static Result expectAndSkipTrait(IdlModelLoader loader) {
        // "@" shape_id
        IdlInternalTokenizer tokenizer = loader.getTokenizer();
        SourceLocation location = tokenizer.getCurrentTokenLocation();
        tokenizer.expect(IdlToken.AT);
        tokenizer.next();
        CharSequence id = IdlShapeIdParser.expectAndSkipShapeId(tokenizer);

        // No (): it's an annotation trait.
        if (tokenizer.getCurrentToken() != IdlToken.LPAREN) {
            return new Result(id, new NullNode(location), TraitType.ANNOTATION);
        }

        tokenizer.next();
        tokenizer.skipWsAndDocs();

        // (): it's also an annotation trait.
        if (tokenizer.getCurrentToken() == IdlToken.RPAREN) {
            tokenizer.next();
            return new Result(id, new NullNode(location), TraitType.ANNOTATION);
        }

        // The trait has a value between the '(' and ')'.
        Node value = parseTraitValueBody(loader, location);
        tokenizer.skipWsAndDocs();
        tokenizer.expect(IdlToken.RPAREN);
        tokenizer.next();

        return new Result(id, value, TraitType.VALUE);
    }
Parses a single trait: "@" trait-id [(trait-body)].

@param loader   IDL parser.
@return Returns the parsed trait.
smithy-model/src/main/java/software/amazon/smithy/model/loader/IdlTraitParser.java