diff options
Diffstat (limited to 'vendor/github.com/graphql-go/graphql/language/parser/parser.go')
-rw-r--r-- | vendor/github.com/graphql-go/graphql/language/parser/parser.go | 1636 |
1 files changed, 1636 insertions, 0 deletions
diff --git a/vendor/github.com/graphql-go/graphql/language/parser/parser.go b/vendor/github.com/graphql-go/graphql/language/parser/parser.go new file mode 100644 index 00000000..32beef37 --- /dev/null +++ b/vendor/github.com/graphql-go/graphql/language/parser/parser.go @@ -0,0 +1,1636 @@ +package parser + +import ( + "fmt" + + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/language/ast" + "github.com/graphql-go/graphql/language/lexer" + "github.com/graphql-go/graphql/language/source" +) + +type parseFn func(parser *Parser) (interface{}, error) + +type ParseOptions struct { + NoLocation bool + NoSource bool +} + +type ParseParams struct { + Source interface{} + Options ParseOptions +} + +type Parser struct { + LexToken lexer.Lexer + Source *source.Source + Options ParseOptions + PrevEnd int + Token lexer.Token +} + +func Parse(p ParseParams) (*ast.Document, error) { + var sourceObj *source.Source + switch p.Source.(type) { + case *source.Source: + sourceObj = p.Source.(*source.Source) + default: + body, _ := p.Source.(string) + sourceObj = source.NewSource(&source.Source{Body: []byte(body)}) + } + parser, err := makeParser(sourceObj, p.Options) + if err != nil { + return nil, err + } + doc, err := parseDocument(parser) + if err != nil { + return nil, err + } + return doc, nil +} + +// TODO: test and expose parseValue as a public +func parseValue(p ParseParams) (ast.Value, error) { + var value ast.Value + var sourceObj *source.Source + switch p.Source.(type) { + case *source.Source: + sourceObj = p.Source.(*source.Source) + default: + body, _ := p.Source.(string) + sourceObj = source.NewSource(&source.Source{Body: []byte(body)}) + } + parser, err := makeParser(sourceObj, p.Options) + if err != nil { + return value, err + } + value, err = parseValueLiteral(parser, false) + if err != nil { + return value, err + } + return value, nil +} + +// Converts a name lex token into a name parse node. +func parseName(parser *Parser) (*ast.Name, error) { + token, err := expect(parser, lexer.TokenKind[lexer.NAME]) + if err != nil { + return nil, err + } + return ast.NewName(&ast.Name{ + Value: token.Value, + Loc: loc(parser, token.Start), + }), nil +} + +func makeParser(s *source.Source, opts ParseOptions) (*Parser, error) { + lexToken := lexer.Lex(s) + token, err := lexToken(0) + if err != nil { + return &Parser{}, err + } + return &Parser{ + LexToken: lexToken, + Source: s, + Options: opts, + PrevEnd: 0, + Token: token, + }, nil +} + +/* Implements the parsing rules in the Document section. */ + +func parseDocument(parser *Parser) (*ast.Document, error) { + start := parser.Token.Start + var nodes []ast.Node + for { + if skp, err := skip(parser, lexer.TokenKind[lexer.EOF]); err != nil { + return nil, err + } else if skp { + break + } + if peek(parser, lexer.TokenKind[lexer.BRACE_L]) { + node, err := parseOperationDefinition(parser) + if err != nil { + return nil, err + } + nodes = append(nodes, node) + } else if peek(parser, lexer.TokenKind[lexer.NAME]) { + switch parser.Token.Value { + case "query": + fallthrough + case "mutation": + fallthrough + case "subscription": // Note: subscription is an experimental non-spec addition. + node, err := parseOperationDefinition(parser) + if err != nil { + return nil, err + } + nodes = append(nodes, node) + case "fragment": + node, err := parseFragmentDefinition(parser) + if err != nil { + return nil, err + } + nodes = append(nodes, node) + + // Note: the Type System IDL is an experimental non-spec addition. + case "schema": + fallthrough + case "scalar": + fallthrough + case "type": + fallthrough + case "interface": + fallthrough + case "union": + fallthrough + case "enum": + fallthrough + case "input": + fallthrough + case "extend": + fallthrough + case "directive": + node, err := parseTypeSystemDefinition(parser) + if err != nil { + return nil, err + } + nodes = append(nodes, node) + default: + if err := unexpected(parser, lexer.Token{}); err != nil { + return nil, err + } + } + } else if peekDescription(parser) { + node, err := parseTypeSystemDefinition(parser) + if err != nil { + return nil, err + } + nodes = append(nodes, node) + } else { + if err := unexpected(parser, lexer.Token{}); err != nil { + return nil, err + } + } + } + return ast.NewDocument(&ast.Document{ + Loc: loc(parser, start), + Definitions: nodes, + }), nil +} + +/* Implements the parsing rules in the Operations section. */ + +/** + * OperationDefinition : + * - SelectionSet + * - OperationType Name? VariableDefinitions? Directives? SelectionSet + */ +func parseOperationDefinition(parser *Parser) (*ast.OperationDefinition, error) { + start := parser.Token.Start + if peek(parser, lexer.TokenKind[lexer.BRACE_L]) { + selectionSet, err := parseSelectionSet(parser) + if err != nil { + return nil, err + } + return ast.NewOperationDefinition(&ast.OperationDefinition{ + Operation: ast.OperationTypeQuery, + Directives: []*ast.Directive{}, + SelectionSet: selectionSet, + Loc: loc(parser, start), + }), nil + } + operation, err := parseOperationType(parser) + if err != nil { + return nil, err + } + + var name *ast.Name + if peek(parser, lexer.TokenKind[lexer.NAME]) { + name, err = parseName(parser) + } + variableDefinitions, err := parseVariableDefinitions(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + selectionSet, err := parseSelectionSet(parser) + if err != nil { + return nil, err + } + return ast.NewOperationDefinition(&ast.OperationDefinition{ + Operation: operation, + Name: name, + VariableDefinitions: variableDefinitions, + Directives: directives, + SelectionSet: selectionSet, + Loc: loc(parser, start), + }), nil +} + +/** + * OperationType : one of query mutation subscription + */ +func parseOperationType(parser *Parser) (string, error) { + operationToken, err := expect(parser, lexer.TokenKind[lexer.NAME]) + if err != nil { + return "", err + } + switch operationToken.Value { + case ast.OperationTypeQuery: + return operationToken.Value, nil + case ast.OperationTypeMutation: + return operationToken.Value, nil + case ast.OperationTypeSubscription: + return operationToken.Value, nil + default: + return "", unexpected(parser, operationToken) + } +} + +/** + * VariableDefinitions : ( VariableDefinition+ ) + */ +func parseVariableDefinitions(parser *Parser) ([]*ast.VariableDefinition, error) { + variableDefinitions := []*ast.VariableDefinition{} + if peek(parser, lexer.TokenKind[lexer.PAREN_L]) { + vdefs, err := many(parser, lexer.TokenKind[lexer.PAREN_L], parseVariableDefinition, lexer.TokenKind[lexer.PAREN_R]) + for _, vdef := range vdefs { + if vdef != nil { + variableDefinitions = append(variableDefinitions, vdef.(*ast.VariableDefinition)) + } + } + if err != nil { + return variableDefinitions, err + } + return variableDefinitions, nil + } + return variableDefinitions, nil +} + +/** + * VariableDefinition : Variable : Type DefaultValue? + */ +func parseVariableDefinition(parser *Parser) (interface{}, error) { + start := parser.Token.Start + variable, err := parseVariable(parser) + if err != nil { + return nil, err + } + _, err = expect(parser, lexer.TokenKind[lexer.COLON]) + if err != nil { + return nil, err + } + ttype, err := parseType(parser) + if err != nil { + return nil, err + } + var defaultValue ast.Value + if skp, err := skip(parser, lexer.TokenKind[lexer.EQUALS]); err != nil { + return nil, err + } else if skp { + dv, err := parseValueLiteral(parser, true) + if err != nil { + return nil, err + } + defaultValue = dv + } + return ast.NewVariableDefinition(&ast.VariableDefinition{ + Variable: variable, + Type: ttype, + DefaultValue: defaultValue, + Loc: loc(parser, start), + }), nil +} + +/** + * Variable : $ Name + */ +func parseVariable(parser *Parser) (*ast.Variable, error) { + start := parser.Token.Start + _, err := expect(parser, lexer.TokenKind[lexer.DOLLAR]) + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + return ast.NewVariable(&ast.Variable{ + Name: name, + Loc: loc(parser, start), + }), nil +} + +/** + * SelectionSet : { Selection+ } + */ +func parseSelectionSet(parser *Parser) (*ast.SelectionSet, error) { + start := parser.Token.Start + iSelections, err := many(parser, lexer.TokenKind[lexer.BRACE_L], parseSelection, lexer.TokenKind[lexer.BRACE_R]) + if err != nil { + return nil, err + } + selections := []ast.Selection{} + for _, iSelection := range iSelections { + if iSelection != nil { + // type assert interface{} into Selection interface + selections = append(selections, iSelection.(ast.Selection)) + } + } + + return ast.NewSelectionSet(&ast.SelectionSet{ + Selections: selections, + Loc: loc(parser, start), + }), nil +} + +/** + * Selection : + * - Field + * - FragmentSpread + * - InlineFragment + */ +func parseSelection(parser *Parser) (interface{}, error) { + if peek(parser, lexer.TokenKind[lexer.SPREAD]) { + r, err := parseFragment(parser) + return r, err + } + return parseField(parser) +} + +/** + * Field : Alias? Name Arguments? Directives? SelectionSet? + * + * Alias : Name : + */ +func parseField(parser *Parser) (*ast.Field, error) { + start := parser.Token.Start + nameOrAlias, err := parseName(parser) + if err != nil { + return nil, err + } + var ( + name *ast.Name + alias *ast.Name + ) + if skp, err := skip(parser, lexer.TokenKind[lexer.COLON]); err != nil { + return nil, err + } else if skp { + alias = nameOrAlias + n, err := parseName(parser) + if err != nil { + return nil, err + } + name = n + } else { + name = nameOrAlias + } + arguments, err := parseArguments(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + var selectionSet *ast.SelectionSet + if peek(parser, lexer.TokenKind[lexer.BRACE_L]) { + sSet, err := parseSelectionSet(parser) + if err != nil { + return nil, err + } + selectionSet = sSet + } + return ast.NewField(&ast.Field{ + Alias: alias, + Name: name, + Arguments: arguments, + Directives: directives, + SelectionSet: selectionSet, + Loc: loc(parser, start), + }), nil +} + +/** + * Arguments : ( Argument+ ) + */ +func parseArguments(parser *Parser) ([]*ast.Argument, error) { + arguments := []*ast.Argument{} + if peek(parser, lexer.TokenKind[lexer.PAREN_L]) { + iArguments, err := many(parser, lexer.TokenKind[lexer.PAREN_L], parseArgument, lexer.TokenKind[lexer.PAREN_R]) + if err != nil { + return arguments, err + } + for _, iArgument := range iArguments { + if iArgument != nil { + arguments = append(arguments, iArgument.(*ast.Argument)) + } + } + return arguments, nil + } + return arguments, nil +} + +/** + * Argument : Name : Value + */ +func parseArgument(parser *Parser) (interface{}, error) { + start := parser.Token.Start + name, err := parseName(parser) + if err != nil { + return nil, err + } + _, err = expect(parser, lexer.TokenKind[lexer.COLON]) + if err != nil { + return nil, err + } + value, err := parseValueLiteral(parser, false) + if err != nil { + return nil, err + } + return ast.NewArgument(&ast.Argument{ + Name: name, + Value: value, + Loc: loc(parser, start), + }), nil +} + +/* Implements the parsing rules in the Fragments section. */ + +/** + * Corresponds to both FragmentSpread and InlineFragment in the spec. + * + * FragmentSpread : ... FragmentName Directives? + * + * InlineFragment : ... TypeCondition? Directives? SelectionSet + */ +func parseFragment(parser *Parser) (interface{}, error) { + start := parser.Token.Start + _, err := expect(parser, lexer.TokenKind[lexer.SPREAD]) + if err != nil { + return nil, err + } + if peek(parser, lexer.TokenKind[lexer.NAME]) && parser.Token.Value != "on" { + name, err := parseFragmentName(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + return ast.NewFragmentSpread(&ast.FragmentSpread{ + Name: name, + Directives: directives, + Loc: loc(parser, start), + }), nil + } + var typeCondition *ast.Named + if parser.Token.Value == "on" { + if err := advance(parser); err != nil { + return nil, err + } + name, err := parseNamed(parser) + if err != nil { + return nil, err + } + typeCondition = name + + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + selectionSet, err := parseSelectionSet(parser) + if err != nil { + return nil, err + } + return ast.NewInlineFragment(&ast.InlineFragment{ + TypeCondition: typeCondition, + Directives: directives, + SelectionSet: selectionSet, + Loc: loc(parser, start), + }), nil +} + +/** + * FragmentDefinition : + * - fragment FragmentName on TypeCondition Directives? SelectionSet + * + * TypeCondition : NamedType + */ +func parseFragmentDefinition(parser *Parser) (*ast.FragmentDefinition, error) { + start := parser.Token.Start + _, err := expectKeyWord(parser, "fragment") + if err != nil { + return nil, err + } + name, err := parseFragmentName(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "on") + if err != nil { + return nil, err + } + typeCondition, err := parseNamed(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + selectionSet, err := parseSelectionSet(parser) + if err != nil { + return nil, err + } + return ast.NewFragmentDefinition(&ast.FragmentDefinition{ + Name: name, + TypeCondition: typeCondition, + Directives: directives, + SelectionSet: selectionSet, + Loc: loc(parser, start), + }), nil +} + +/** + * FragmentName : Name but not `on` + */ +func parseFragmentName(parser *Parser) (*ast.Name, error) { + if parser.Token.Value == "on" { + return nil, unexpected(parser, lexer.Token{}) + } + return parseName(parser) +} + +/* Implements the parsing rules in the Values section. */ + +/** + * Value[Const] : + * - [~Const] Variable + * - IntValue + * - FloatValue + * - StringValue + * - BooleanValue + * - EnumValue + * - ListValue[?Const] + * - ObjectValue[?Const] + * + * BooleanValue : one of `true` `false` + * + * EnumValue : Name but not `true`, `false` or `null` + */ +func parseValueLiteral(parser *Parser, isConst bool) (ast.Value, error) { + token := parser.Token + switch token.Kind { + case lexer.TokenKind[lexer.BRACKET_L]: + return parseList(parser, isConst) + case lexer.TokenKind[lexer.BRACE_L]: + return parseObject(parser, isConst) + case lexer.TokenKind[lexer.INT]: + if err := advance(parser); err != nil { + return nil, err + } + return ast.NewIntValue(&ast.IntValue{ + Value: token.Value, + Loc: loc(parser, token.Start), + }), nil + case lexer.TokenKind[lexer.FLOAT]: + if err := advance(parser); err != nil { + return nil, err + } + return ast.NewFloatValue(&ast.FloatValue{ + Value: token.Value, + Loc: loc(parser, token.Start), + }), nil + case lexer.TokenKind[lexer.BLOCK_STRING]: + fallthrough + case lexer.TokenKind[lexer.STRING]: + return parseStringLiteral(parser) + case lexer.TokenKind[lexer.NAME]: + if token.Value == "true" || token.Value == "false" { + if err := advance(parser); err != nil { + return nil, err + } + value := true + if token.Value == "false" { + value = false + } + return ast.NewBooleanValue(&ast.BooleanValue{ + Value: value, + Loc: loc(parser, token.Start), + }), nil + } else if token.Value != "null" { + if err := advance(parser); err != nil { + return nil, err + } + return ast.NewEnumValue(&ast.EnumValue{ + Value: token.Value, + Loc: loc(parser, token.Start), + }), nil + } + case lexer.TokenKind[lexer.DOLLAR]: + if !isConst { + return parseVariable(parser) + } + } + if err := unexpected(parser, lexer.Token{}); err != nil { + return nil, err + } + return nil, nil +} + +func parseConstValue(parser *Parser) (interface{}, error) { + value, err := parseValueLiteral(parser, true) + if err != nil { + return value, err + } + return value, nil +} + +func parseValueValue(parser *Parser) (interface{}, error) { + return parseValueLiteral(parser, false) +} + +/** + * ListValue[Const] : + * - [ ] + * - [ Value[?Const]+ ] + */ +func parseList(parser *Parser, isConst bool) (*ast.ListValue, error) { + start := parser.Token.Start + var item parseFn + if isConst { + item = parseConstValue + } else { + item = parseValueValue + } + iValues, err := any(parser, lexer.TokenKind[lexer.BRACKET_L], item, lexer.TokenKind[lexer.BRACKET_R]) + if err != nil { + return nil, err + } + values := []ast.Value{} + for _, iValue := range iValues { + values = append(values, iValue.(ast.Value)) + } + return ast.NewListValue(&ast.ListValue{ + Values: values, + Loc: loc(parser, start), + }), nil +} + +/** + * ObjectValue[Const] : + * - { } + * - { ObjectField[?Const]+ } + */ +func parseObject(parser *Parser, isConst bool) (*ast.ObjectValue, error) { + start := parser.Token.Start + _, err := expect(parser, lexer.TokenKind[lexer.BRACE_L]) + if err != nil { + return nil, err + } + fields := []*ast.ObjectField{} + for { + if skp, err := skip(parser, lexer.TokenKind[lexer.BRACE_R]); err != nil { + return nil, err + } else if skp { + break + } + field, err := parseObjectField(parser, isConst) + if err != nil { + return nil, err + } + fields = append(fields, field) + } + return ast.NewObjectValue(&ast.ObjectValue{ + Fields: fields, + Loc: loc(parser, start), + }), nil +} + +/** + * ObjectField[Const] : Name : Value[?Const] + */ +func parseObjectField(parser *Parser, isConst bool) (*ast.ObjectField, error) { + start := parser.Token.Start + name, err := parseName(parser) + if err != nil { + return nil, err + } + _, err = expect(parser, lexer.TokenKind[lexer.COLON]) + if err != nil { + return nil, err + } + value, err := parseValueLiteral(parser, isConst) + if err != nil { + return nil, err + } + return ast.NewObjectField(&ast.ObjectField{ + Name: name, + Value: value, + Loc: loc(parser, start), + }), nil +} + +/* Implements the parsing rules in the Directives section. */ + +/** + * Directives : Directive+ + */ +func parseDirectives(parser *Parser) ([]*ast.Directive, error) { + directives := []*ast.Directive{} + for { + if !peek(parser, lexer.TokenKind[lexer.AT]) { + break + } + directive, err := parseDirective(parser) + if err != nil { + return directives, err + } + directives = append(directives, directive) + } + return directives, nil +} + +/** + * Directive : @ Name Arguments? + */ +func parseDirective(parser *Parser) (*ast.Directive, error) { + start := parser.Token.Start + _, err := expect(parser, lexer.TokenKind[lexer.AT]) + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + args, err := parseArguments(parser) + if err != nil { + return nil, err + } + return ast.NewDirective(&ast.Directive{ + Name: name, + Arguments: args, + Loc: loc(parser, start), + }), nil +} + +/* Implements the parsing rules in the Types section. */ + +/** + * Type : + * - NamedType + * - ListType + * - NonNullType + */ +func parseType(parser *Parser) (ast.Type, error) { + start := parser.Token.Start + var ttype ast.Type + if skp, err := skip(parser, lexer.TokenKind[lexer.BRACKET_L]); err != nil { + return nil, err + } else if skp { + t, err := parseType(parser) + if err != nil { + return t, err + } + ttype = t + _, err = expect(parser, lexer.TokenKind[lexer.BRACKET_R]) + if err != nil { + return ttype, err + } + ttype = ast.NewList(&ast.List{ + Type: ttype, + Loc: loc(parser, start), + }) + } else { + name, err := parseNamed(parser) + if err != nil { + return ttype, err + } + ttype = name + } + if skp, err := skip(parser, lexer.TokenKind[lexer.BANG]); err != nil { + return nil, err + } else if skp { + ttype = ast.NewNonNull(&ast.NonNull{ + Type: ttype, + Loc: loc(parser, start), + }) + return ttype, nil + } + return ttype, nil +} + +/** + * NamedType : Name + */ +func parseNamed(parser *Parser) (*ast.Named, error) { + start := parser.Token.Start + name, err := parseName(parser) + if err != nil { + return nil, err + } + return ast.NewNamed(&ast.Named{ + Name: name, + Loc: loc(parser, start), + }), nil +} + +/* Implements the parsing rules in the Type Definition section. */ + +/** + * TypeSystemDefinition : + * - SchemaDefinition + * - TypeDefinition + * - TypeExtension + * - DirectiveDefinition + * + * TypeDefinition : + * - ScalarTypeDefinition + * - ObjectTypeDefinition + * - InterfaceTypeDefinition + * - UnionTypeDefinition + * - EnumTypeDefinition + * - InputObjectTypeDefinition + */ +func parseTypeSystemDefinition(parser *Parser) (ast.Node, error) { + var err error + + // Many definitions begin with a description and require a lookahead. + keywordToken := parser.Token + if peekDescription(parser) { + keywordToken, err = lookahead(parser) + if err != nil { + return nil, err + } + } + + if keywordToken.Kind == lexer.NAME { + switch keywordToken.Value { + case "schema": + return parseSchemaDefinition(parser) + case "scalar": + return parseScalarTypeDefinition(parser) + case "type": + return parseObjectTypeDefinition(parser) + case "interface": + return parseInterfaceTypeDefinition(parser) + case "union": + return parseUnionTypeDefinition(parser) + case "enum": + return parseEnumTypeDefinition(parser) + case "input": + return parseInputObjectTypeDefinition(parser) + case "extend": + return parseTypeExtensionDefinition(parser) + case "directive": + return parseDirectiveDefinition(parser) + } + } + + return nil, unexpected(parser, keywordToken) +} + +/** + * SchemaDefinition : schema Directives? { OperationTypeDefinition+ } + * + * OperationTypeDefinition : OperationType : NamedType + */ +func parseSchemaDefinition(parser *Parser) (*ast.SchemaDefinition, error) { + start := parser.Token.Start + _, err := expectKeyWord(parser, "schema") + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + operationTypesI, err := many( + parser, + lexer.TokenKind[lexer.BRACE_L], + parseOperationTypeDefinition, + lexer.TokenKind[lexer.BRACE_R], + ) + if err != nil { + return nil, err + } + operationTypes := []*ast.OperationTypeDefinition{} + for _, op := range operationTypesI { + if op, ok := op.(*ast.OperationTypeDefinition); ok { + operationTypes = append(operationTypes, op) + } + } + return ast.NewSchemaDefinition(&ast.SchemaDefinition{ + OperationTypes: operationTypes, + Directives: directives, + Loc: loc(parser, start), + }), nil +} + +func parseOperationTypeDefinition(parser *Parser) (interface{}, error) { + start := parser.Token.Start + operation, err := parseOperationType(parser) + if err != nil { + return nil, err + } + _, err = expect(parser, lexer.TokenKind[lexer.COLON]) + if err != nil { + return nil, err + } + ttype, err := parseNamed(parser) + if err != nil { + return nil, err + } + return ast.NewOperationTypeDefinition(&ast.OperationTypeDefinition{ + Operation: operation, + Type: ttype, + Loc: loc(parser, start), + }), nil +} + +/** + * ScalarTypeDefinition : Description? scalar Name Directives? + */ +func parseScalarTypeDefinition(parser *Parser) (*ast.ScalarDefinition, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "scalar") + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + def := ast.NewScalarDefinition(&ast.ScalarDefinition{ + Name: name, + Description: description, + Directives: directives, + Loc: loc(parser, start), + }) + return def, nil +} + +/** + * ObjectTypeDefinition : + * Description? + * type Name ImplementsInterfaces? Directives? { FieldDefinition+ } + */ +func parseObjectTypeDefinition(parser *Parser) (*ast.ObjectDefinition, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "type") + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + interfaces, err := parseImplementsInterfaces(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + iFields, err := any(parser, lexer.TokenKind[lexer.BRACE_L], parseFieldDefinition, lexer.TokenKind[lexer.BRACE_R]) + if err != nil { + return nil, err + } + fields := []*ast.FieldDefinition{} + for _, iField := range iFields { + if iField != nil { + fields = append(fields, iField.(*ast.FieldDefinition)) + } + } + return ast.NewObjectDefinition(&ast.ObjectDefinition{ + Name: name, + Description: description, + Loc: loc(parser, start), + Interfaces: interfaces, + Directives: directives, + Fields: fields, + }), nil +} + +/** + * ImplementsInterfaces : implements NamedType+ + */ +func parseImplementsInterfaces(parser *Parser) ([]*ast.Named, error) { + types := []*ast.Named{} + if parser.Token.Value == "implements" { + if err := advance(parser); err != nil { + return nil, err + } + for { + ttype, err := parseNamed(parser) + if err != nil { + return types, err + } + types = append(types, ttype) + if !peek(parser, lexer.TokenKind[lexer.NAME]) { + break + } + } + } + return types, nil +} + +/** + * FieldDefinition : Description? Name ArgumentsDefinition? : Type Directives? + */ +func parseFieldDefinition(parser *Parser) (interface{}, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + args, err := parseArgumentDefs(parser) + if err != nil { + return nil, err + } + _, err = expect(parser, lexer.TokenKind[lexer.COLON]) + if err != nil { + return nil, err + } + ttype, err := parseType(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + return ast.NewFieldDefinition(&ast.FieldDefinition{ + Name: name, + Description: description, + Arguments: args, + Type: ttype, + Directives: directives, + Loc: loc(parser, start), + }), nil +} + +/** + * ArgumentsDefinition : ( InputValueDefinition+ ) + */ +func parseArgumentDefs(parser *Parser) ([]*ast.InputValueDefinition, error) { + inputValueDefinitions := []*ast.InputValueDefinition{} + + if !peek(parser, lexer.TokenKind[lexer.PAREN_L]) { + return inputValueDefinitions, nil + } + iInputValueDefinitions, err := many(parser, lexer.TokenKind[lexer.PAREN_L], parseInputValueDef, lexer.TokenKind[lexer.PAREN_R]) + if err != nil { + return inputValueDefinitions, err + } + for _, iInputValueDefinition := range iInputValueDefinitions { + if iInputValueDefinition != nil { + inputValueDefinitions = append(inputValueDefinitions, iInputValueDefinition.(*ast.InputValueDefinition)) + } + } + return inputValueDefinitions, err +} + +/** + * InputValueDefinition : Description? Name : Type DefaultValue? Directives? + */ +func parseInputValueDef(parser *Parser) (interface{}, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + _, err = expect(parser, lexer.TokenKind[lexer.COLON]) + if err != nil { + return nil, err + } + ttype, err := parseType(parser) + if err != nil { + return nil, err + } + var defaultValue ast.Value + if skp, err := skip(parser, lexer.TokenKind[lexer.EQUALS]); err != nil { + return nil, err + } else if skp { + val, err := parseConstValue(parser) + if err != nil { + return nil, err + } + if val, ok := val.(ast.Value); ok { + defaultValue = val + } + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + return ast.NewInputValueDefinition(&ast.InputValueDefinition{ + Name: name, + Description: description, + Type: ttype, + DefaultValue: defaultValue, + Directives: directives, + Loc: loc(parser, start), + }), nil +} + +/** + * InterfaceTypeDefinition : + * Description? + * interface Name Directives? { FieldDefinition+ } + */ +func parseInterfaceTypeDefinition(parser *Parser) (*ast.InterfaceDefinition, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "interface") + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + iFields, err := any(parser, lexer.TokenKind[lexer.BRACE_L], parseFieldDefinition, lexer.TokenKind[lexer.BRACE_R]) + if err != nil { + return nil, err + } + fields := []*ast.FieldDefinition{} + for _, iField := range iFields { + if iField != nil { + fields = append(fields, iField.(*ast.FieldDefinition)) + } + } + return ast.NewInterfaceDefinition(&ast.InterfaceDefinition{ + Name: name, + Description: description, + Directives: directives, + Loc: loc(parser, start), + Fields: fields, + }), nil +} + +/** + * UnionTypeDefinition : Description? union Name Directives? = UnionMembers + */ +func parseUnionTypeDefinition(parser *Parser) (*ast.UnionDefinition, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "union") + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + _, err = expect(parser, lexer.TokenKind[lexer.EQUALS]) + if err != nil { + return nil, err + } + types, err := parseUnionMembers(parser) + if err != nil { + return nil, err + } + return ast.NewUnionDefinition(&ast.UnionDefinition{ + Name: name, + Description: description, + Directives: directives, + Loc: loc(parser, start), + Types: types, + }), nil +} + +/** + * UnionMembers : + * - NamedType + * - UnionMembers | NamedType + */ +func parseUnionMembers(parser *Parser) ([]*ast.Named, error) { + members := []*ast.Named{} + for { + member, err := parseNamed(parser) + if err != nil { + return members, err + } + members = append(members, member) + if skp, err := skip(parser, lexer.TokenKind[lexer.PIPE]); err != nil { + return nil, err + } else if !skp { + break + } + } + return members, nil +} + +/** + * EnumTypeDefinition : Description? enum Name Directives? { EnumValueDefinition+ } + */ +func parseEnumTypeDefinition(parser *Parser) (*ast.EnumDefinition, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "enum") + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + iEnumValueDefs, err := any(parser, lexer.TokenKind[lexer.BRACE_L], parseEnumValueDefinition, lexer.TokenKind[lexer.BRACE_R]) + if err != nil { + return nil, err + } + values := []*ast.EnumValueDefinition{} + for _, iEnumValueDef := range iEnumValueDefs { + if iEnumValueDef != nil { + values = append(values, iEnumValueDef.(*ast.EnumValueDefinition)) + } + } + return ast.NewEnumDefinition(&ast.EnumDefinition{ + Name: name, + Description: description, + Directives: directives, + Loc: loc(parser, start), + Values: values, + }), nil +} + +/** + * EnumValueDefinition : Description? EnumValue Directives? + * + * EnumValue : Name + */ +func parseEnumValueDefinition(parser *Parser) (interface{}, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + return ast.NewEnumValueDefinition(&ast.EnumValueDefinition{ + Name: name, + Description: description, + Directives: directives, + Loc: loc(parser, start), + }), nil +} + +/** + * InputObjectTypeDefinition : + * - Description? input Name Directives? { InputValueDefinition+ } + */ +func parseInputObjectTypeDefinition(parser *Parser) (*ast.InputObjectDefinition, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "input") + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + directives, err := parseDirectives(parser) + if err != nil { + return nil, err + } + iInputValueDefinitions, err := any(parser, lexer.TokenKind[lexer.BRACE_L], parseInputValueDef, lexer.TokenKind[lexer.BRACE_R]) + if err != nil { + return nil, err + } + fields := []*ast.InputValueDefinition{} + for _, iInputValueDefinition := range iInputValueDefinitions { + if iInputValueDefinition != nil { + fields = append(fields, iInputValueDefinition.(*ast.InputValueDefinition)) + } + } + return ast.NewInputObjectDefinition(&ast.InputObjectDefinition{ + Name: name, + Description: description, + Directives: directives, + Loc: loc(parser, start), + Fields: fields, + }), nil +} + +/** + * TypeExtensionDefinition : extend ObjectTypeDefinition + */ +func parseTypeExtensionDefinition(parser *Parser) (*ast.TypeExtensionDefinition, error) { + start := parser.Token.Start + _, err := expectKeyWord(parser, "extend") + if err != nil { + return nil, err + } + + definition, err := parseObjectTypeDefinition(parser) + if err != nil { + return nil, err + } + return ast.NewTypeExtensionDefinition(&ast.TypeExtensionDefinition{ + Loc: loc(parser, start), + Definition: definition, + }), nil +} + +/** + * DirectiveDefinition : + * - directive @ Name ArgumentsDefinition? on DirectiveLocations + */ +func parseDirectiveDefinition(parser *Parser) (*ast.DirectiveDefinition, error) { + start := parser.Token.Start + description, err := parseDescription(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "directive") + if err != nil { + return nil, err + } + _, err = expect(parser, lexer.TokenKind[lexer.AT]) + if err != nil { + return nil, err + } + name, err := parseName(parser) + if err != nil { + return nil, err + } + args, err := parseArgumentDefs(parser) + if err != nil { + return nil, err + } + _, err = expectKeyWord(parser, "on") + if err != nil { + return nil, err + } + locations, err := parseDirectiveLocations(parser) + if err != nil { + return nil, err + } + + return ast.NewDirectiveDefinition(&ast.DirectiveDefinition{ + Loc: loc(parser, start), + Name: name, + Description: description, + Arguments: args, + Locations: locations, + }), nil +} + +/** + * DirectiveLocations : + * - Name + * - DirectiveLocations | Name + */ +func parseDirectiveLocations(parser *Parser) ([]*ast.Name, error) { + locations := []*ast.Name{} + for { + name, err := parseName(parser) + if err != nil { + return locations, err + } + locations = append(locations, name) + + hasPipe, err := skip(parser, lexer.TokenKind[lexer.PIPE]) + if err != nil { + return locations, err + } + if !hasPipe { + break + } + } + return locations, nil +} + +func parseStringLiteral(parser *Parser) (*ast.StringValue, error) { + token := parser.Token + if err := advance(parser); err != nil { + return nil, err + } + return ast.NewStringValue(&ast.StringValue{ + Value: token.Value, + Loc: loc(parser, token.Start), + }), nil +} + +/** + * Description : StringValue + */ +func parseDescription(parser *Parser) (*ast.StringValue, error) { + if peekDescription(parser) { + return parseStringLiteral(parser) + } + return nil, nil +} + +/* Core parsing utility functions */ + +// Returns a location object, used to identify the place in +// the source that created a given parsed object. +func loc(parser *Parser, start int) *ast.Location { + if parser.Options.NoLocation { + return nil + } + if parser.Options.NoSource { + return ast.NewLocation(&ast.Location{ + Start: start, + End: parser.PrevEnd, + }) + } + return ast.NewLocation(&ast.Location{ + Start: start, + End: parser.PrevEnd, + Source: parser.Source, + }) +} + +// Moves the internal parser object to the next lexed token. +func advance(parser *Parser) error { + prevEnd := parser.Token.End + parser.PrevEnd = prevEnd + token, err := parser.LexToken(prevEnd) + if err != nil { + return err + } + parser.Token = token + return nil +} + +// lookahead retrieves the next token +func lookahead(parser *Parser) (lexer.Token, error) { + prevEnd := parser.Token.End + return parser.LexToken(prevEnd) +} + +// Determines if the next token is of a given kind +func peek(parser *Parser, Kind int) bool { + return parser.Token.Kind == Kind +} + +// peekDescription determines if the next token is a string value +func peekDescription(parser *Parser) bool { + return peek(parser, lexer.STRING) || peek(parser, lexer.BLOCK_STRING) +} + +// If the next token is of the given kind, return true after advancing +// the parser. Otherwise, do not change the parser state and return false. +func skip(parser *Parser, Kind int) (bool, error) { + if parser.Token.Kind == Kind { + err := advance(parser) + return true, err + } + return false, nil +} + +// If the next token is of the given kind, return that token after advancing +// the parser. Otherwise, do not change the parser state and return error. +func expect(parser *Parser, kind int) (lexer.Token, error) { + token := parser.Token + if token.Kind == kind { + err := advance(parser) + return token, err + } + descp := fmt.Sprintf("Expected %s, found %s", lexer.GetTokenKindDesc(kind), lexer.GetTokenDesc(token)) + return token, gqlerrors.NewSyntaxError(parser.Source, token.Start, descp) +} + +// If the next token is a keyword with the given value, return that token after +// advancing the parser. Otherwise, do not change the parser state and return false. +func expectKeyWord(parser *Parser, value string) (lexer.Token, error) { + token := parser.Token + if token.Kind == lexer.TokenKind[lexer.NAME] && token.Value == value { + err := advance(parser) + return token, err + } + descp := fmt.Sprintf("Expected \"%s\", found %s", value, lexer.GetTokenDesc(token)) + return token, gqlerrors.NewSyntaxError(parser.Source, token.Start, descp) +} + +// Helper function for creating an error when an unexpected lexed token +// is encountered. +func unexpected(parser *Parser, atToken lexer.Token) error { + var token lexer.Token + if (atToken == lexer.Token{}) { + token = parser.Token + } else { + token = parser.Token + } + description := fmt.Sprintf("Unexpected %v", lexer.GetTokenDesc(token)) + return gqlerrors.NewSyntaxError(parser.Source, token.Start, description) +} + +// Returns a possibly empty list of parse nodes, determined by +// the parseFn. This list begins with a lex token of openKind +// and ends with a lex token of closeKind. Advances the parser +// to the next lex token after the closing token. +func any(parser *Parser, openKind int, parseFn parseFn, closeKind int) ([]interface{}, error) { + var nodes []interface{} + _, err := expect(parser, openKind) + if err != nil { + return nodes, nil + } + for { + if skp, err := skip(parser, closeKind); err != nil { + return nil, err + } else if skp { + break + } + n, err := parseFn(parser) + if err != nil { + return nodes, err + } + nodes = append(nodes, n) + } + return nodes, nil +} + +// Returns a non-empty list of parse nodes, determined by +// the parseFn. This list begins with a lex token of openKind +// and ends with a lex token of closeKind. Advances the parser +// to the next lex token after the closing token. +func many(parser *Parser, openKind int, parseFn parseFn, closeKind int) ([]interface{}, error) { + _, err := expect(parser, openKind) + if err != nil { + return nil, err + } + var nodes []interface{} + node, err := parseFn(parser) + if err != nil { + return nodes, err + } + nodes = append(nodes, node) + for { + if skp, err := skip(parser, closeKind); err != nil { + return nil, err + } else if skp { + break + } + node, err := parseFn(parser) + if err != nil { + return nodes, err + } + nodes = append(nodes, node) + } + return nodes, nil +} |