123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832 |
- /*
- * Public Domain Software
- *
- * I (Matthias Ladkau) am the author of the source code in this file.
- * I have placed the source code in this file in the public domain.
- *
- * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
- */
- package parser
- import (
- "fmt"
- "devt.de/krotik/common/errorutil"
- )
- // Parser Rules
- // ============
- /*
- Maps of AST nodes corresponding to lexer tokens
- */
- var astNodeMapValues map[string]*ASTNode
- var astNodeMapTokens map[LexTokenID]*ASTNode
- var astNodeMapIgnoredValues map[string]*ASTNode
- func init() {
- astNodeMapValues = map[string]*ASTNode{
- "query": {NodeOperationDefinition, nil, nil, nil, 0, ndOperationDefinition, nil},
- "mutation": {NodeOperationDefinition, nil, nil, nil, 0, ndOperationDefinition, nil},
- "subscription": {NodeOperationDefinition, nil, nil, nil, 0, ndOperationDefinition, nil},
- "fragment": {NodeFragmentDefinition, nil, nil, nil, 0, ndFragmentDefinition, nil},
- "{": {NodeSelectionSet, nil, nil, nil, 0, ndSelectionSet, nil},
- "(": {NodeArguments, nil, nil, nil, 0, ndArgsOrVarDef, nil},
- "@": {NodeDirectives, nil, nil, nil, 0, ndDirectives, nil},
- "$": {NodeVariable, nil, nil, nil, 0, ndVariable, nil},
- "...": {NodeFragmentSpread, nil, nil, nil, 0, ndFragmentSpread, nil},
- "[": {NodeListValue, nil, nil, nil, 0, ndListValue, nil},
- // Tokens which are not part of the AST (can be retrieved by next but not be inserted by run)
- "}": {"", nil, nil, nil, 0, nil, nil},
- ":": {"", nil, nil, nil, 0, nil, nil},
- ")": {"", nil, nil, nil, 0, nil, nil},
- "=": {"", nil, nil, nil, 0, nil, nil},
- "]": {"", nil, nil, nil, 0, nil, nil},
- }
- astNodeMapTokens = map[LexTokenID]*ASTNode{
- TokenName: {NodeName, nil, nil, nil, 0, ndTerm, nil},
- TokenIntValue: {NodeValue, nil, nil, nil, 0, ndTerm, nil},
- TokenStringValue: {NodeValue, nil, nil, nil, 0, ndTerm, nil},
- TokenFloatValue: {NodeValue, nil, nil, nil, 0, ndTerm, nil},
- TokenEOF: {NodeEOF, nil, nil, nil, 0, ndTerm, nil},
- }
- }
- // Parser
- // ======
- /*
- Parser data structure
- */
- type parser struct {
- name string // Name to identify the input
- node *ASTNode // Current ast node
- tokens chan LexToken // Channel which contains lex tokens
- rp RuntimeProvider // Runtime provider which creates runtime components
- // Flags
- isVarDef bool // The next Arguments block is parsed as a VariableDefinition
- isValue bool // The next expression is parsed as a value
- }
- /*
- Parse parses a given input string and returns an AST.
- */
- func Parse(name string, input string) (*ASTNode, error) {
- return ParseWithRuntime(name, input, nil)
- }
- /*
- ParseWithRuntime parses a given input string and returns an AST decorated with
- runtime components.
- */
- func ParseWithRuntime(name string, input string, rp RuntimeProvider) (*ASTNode, error) {
- p := &parser{name, nil, Lex(name, input), rp, false, false}
- node, err := p.next()
- if err != nil {
- return nil, err
- }
- p.node = node
- doc := newAstNode(NodeDocument, p, node.Token)
- for err == nil && p.node.Name != NodeEOF {
- if node, err = p.run(0); err == nil {
- if node != nil && node.Name == NodeSelectionSet {
- // Handle query shorthand
- if len(doc.Children) == 0 {
- ed := newAstNode(NodeExecutableDefinition, p, node.Token)
- doc.Children = append(doc.Children, ed)
- od := newAstNode(NodeOperationDefinition, p, node.Token)
- ed.Children = append(ed.Children, od)
- od.Children = append(od.Children, node)
- } else {
- return nil, p.newParserError(ErrMultipleShorthand,
- node.Token.String(), *node.Token)
- }
- } else {
- ed := newAstNode(NodeExecutableDefinition, p, node.Token)
- doc.Children = append(doc.Children, ed)
- ed.Children = append(ed.Children, node)
- }
- }
- }
- if err == nil {
- return doc, nil
- }
- return nil, err
- }
- /*
- run is the main parser function.
- */
- func (p *parser) run(rightBinding int) (*ASTNode, error) {
- var err error
- var left *ASTNode
- n := p.node
- // Get the next ASTNode
- if p.node, err = p.next(); err == nil {
- // All nodes have a null denotation
- if n.nullDenotation == nil {
- return nil, p.newParserError(ErrImpossibleNullDenotation, p.node.Token.Val, *p.node.Token)
- }
- left, err = n.nullDenotation(p, n)
- }
- if err != nil {
- return nil, err
- }
- // At this point we would normally collect left denotations but this
- // parser has only null denotations
- errorutil.AssertTrue(rightBinding == p.node.binding, "Unexpected right binding")
- return left, nil
- }
- /*
- next retrieves the next lexer token and return it as ASTNode.
- */
- func (p *parser) next() (*ASTNode, error) {
- token, more := <-p.tokens
- if !more {
- // Unexpected end of input - the associated token is an empty error token
- return nil, p.newParserError(ErrUnexpectedEnd, "", token)
- } else if token.ID == TokenError {
- // There was a lexer error wrap it in a parser error
- return nil, p.newParserError(ErrLexicalError, token.Val, token)
- } else if node, ok := astNodeMapValues[token.Val]; ok &&
- (!p.isValue || token.ID == TokenPunctuator) && token.ID != TokenStringValue {
- // Parse complex expressions unless we parse a value (then just deal with punctuators)
- return node.instance(p, &token), nil
- } else if node, ok := astNodeMapTokens[token.ID]; ok {
- return node.instance(p, &token), nil
- }
- return nil, p.newParserError(ErrUnknownToken, fmt.Sprintf("id:%v (%v)", token.ID, token), token)
- }
- // Null denotation functions
- // =========================
- /*
- ndTerm is used for terminals.
- */
- func ndTerm(p *parser, self *ASTNode) (*ASTNode, error) {
- return self, nil
- }
- /*
- ndVariable is used for variables. (@spec 2.10)
- */
- func ndVariable(p *parser, self *ASTNode) (*ASTNode, error) {
- var err error
- if p.node.Token.ID == TokenName {
- // Append the query name and move on
- self.Token = p.node.Token
- p.node, err = p.next()
- }
- return self, err
- }
- /*
- ndListValue parses a list value. (@spec 2.9.7)
- */
- func ndListValue(p *parser, self *ASTNode) (*ASTNode, error) {
- var current *ASTNode
- var err error
- for p.node.Token.ID != TokenEOF && p.node.Token.Val != "]" {
- // Parse list values
- if current, err = parseValue(p); err == nil {
- self.Children = append(self.Children, current)
- } else {
- return nil, err
- }
- }
- return self, skipToken(p, "]")
- }
- /*
- ndInputObject parses an input object literal. (@spec 2.9.8)
- */
- func ndInputObject(p *parser, self *ASTNode) (*ASTNode, error) {
- var current *ASTNode
- var err error
- changeAstNode(self, NodeObjectValue, p)
- for p.node.Token.ID != TokenEOF && p.node.Token.Val != "}" {
- if current, err = p.run(0); err == nil {
- if current.Name != NodeName {
- err = p.newParserError(ErrNameExpected,
- current.Token.String(), *current.Token)
- } else {
- of := newAstNode(NodeObjectField, p, current.Token)
- self.Children = append(self.Children, of)
- if err = skipToken(p, ":"); err == nil {
- // Parse object value
- if current, err = parseValue(p); err == nil {
- of.Children = append(of.Children, current)
- }
- }
- }
- }
- if err != nil {
- return nil, err
- }
- }
- return self, skipToken(p, "}")
- }
- /*
- ndFragmentSpread is used for fragment spreads and inline fragments.
- (@spec 2.8, 2.8.2)
- */
- func ndFragmentSpread(p *parser, self *ASTNode) (*ASTNode, error) {
- var current, expectedNameNode *ASTNode
- var err error
- if p.node.Token.Val == "on" {
- // We might have an inline fragment
- onToken := p.node.Token
- p.node, err = p.next()
- if err == nil && p.node.Name == NodeName {
- // Append the fragment name
- changeAstNode(p.node, NodeTypeCondition, p)
- self.Children = append(self.Children, p.node)
- p.node, err = p.next()
- } else {
- self.Token = onToken
- }
- } else if p.node.Token.ID == TokenName {
- // Append the query name and move on
- self.Token = p.node.Token
- p.node, err = p.next()
- } else {
- expectedNameNode = p.node
- }
- if err == nil && p.node.Token.Val == "@" {
- // Parse directives
- if current, err = p.run(0); err == nil {
- self.Children = append(self.Children, current)
- }
- }
- if err == nil && p.node.Token.Val == "{" {
- // Parse selection set
- if current, err = p.run(0); err == nil {
- self.Children = append(self.Children, current)
- // If there is a selection set we must have an inline fragment
- changeAstNode(self, NodeInlineFragment, p)
- }
- } else if err == nil && expectedNameNode != nil {
- // Using the fragment spread operatior without specifying a name nor
- // a selection set is an error
- err = p.newParserError(ErrNameExpected,
- expectedNameNode.Token.String(), *expectedNameNode.Token)
- }
- return self, err
- }
- /*
- ndOperationDefinition parses an operation definition. Each operation is
- represented by an optional operation name and a selection set. (@spec 2.3)
- */
- func ndOperationDefinition(p *parser, self *ASTNode) (*ASTNode, error) {
- var err error
- var current = p.node
- ot := newAstNode(NodeOperationType, p, self.Token)
- self.Children = append(self.Children, ot)
- if p.node.Token.ID == TokenName {
- // Append the query name and move on
- self.Children = append(self.Children, p.node)
- p.node, err = p.next()
- }
- if err == nil && p.node.Token.Val == "(" {
- // Parse variable definition
- p.isVarDef = true
- if current, err = p.run(0); err == nil {
- self.Children = append(self.Children, current)
- }
- p.isVarDef = false
- }
- if err == nil && p.node.Token.Val == "@" {
- // Parse directive
- if current, err = p.run(0); err == nil {
- self.Children = append(self.Children, current)
- }
- }
- if err == nil && p.node.Token.Val == "{" {
- // Parse selection set
- if current, err = p.run(0); err == nil {
- self.Children = append(self.Children, current)
- }
- } else if err == nil {
- // Selection Set is mandatory
- err = p.newParserError(ErrSelectionSetExpected,
- current.Token.String(), *current.Token)
- }
- return self, err
- }
- /*
- ndFragmentDefinition parses a fragment definition. Each fragment is
- represented by an optional fragment name, a type condition and a selection set.
- (@spec 2.8)
- */
- func ndFragmentDefinition(p *parser, self *ASTNode) (*ASTNode, error) {
- var err error
- var current *ASTNode
- if p.node.Token.ID == TokenName {
- // Append the fragment name and move on
- changeAstNode(p.node, NodeFragmentName, p)
- self.Children = append(self.Children, p.node)
- p.node, err = p.next()
- } else {
- err = p.newParserError(ErrNameExpected,
- p.node.Token.String(), *p.node.Token)
- }
- if err == nil {
- if p.node.Token.Val != "on" {
- // Type conditions must start with on
- err = p.newParserError(ErrOnExpected,
- p.node.Token.String(), *p.node.Token)
- } else {
- p.node, err = p.next()
- if err == nil {
- if p.node.Token.ID == TokenName {
- // Append the fragment name
- changeAstNode(p.node, NodeTypeCondition, p)
- self.Children = append(self.Children, p.node)
- p.node, err = p.next()
- } else {
- err = p.newParserError(ErrNameExpected,
- p.node.Token.String(), *p.node.Token)
- }
- }
- }
- }
- if err == nil && p.node.Token.Val == "@" {
- // Parse directive
- if current, err = p.run(0); err == nil {
- self.Children = append(self.Children, current)
- }
- }
- if err == nil && p.node.Token.Val == "{" {
- // Parse selection set
- if current, err = p.run(0); err == nil {
- self.Children = append(self.Children, current)
- }
- } else if err == nil {
- // Selection Set is mandatory
- err = p.newParserError(ErrSelectionSetExpected,
- p.node.Token.String(), *p.node.Token)
- }
- return self, err
- }
- /*
- ndSelectionSet parses a selection set. An operation selects the set of
- information it needs. (@spec 2.4)
- */
- func ndSelectionSet(p *parser, self *ASTNode) (*ASTNode, error) {
- var current *ASTNode
- var err error
- // Special case if we are parsing an input object literal (@spec 2.9.8)
- if p.isValue {
- return ndInputObject(p, self)
- }
- for p.node.Token.ID != TokenEOF && p.node.Token.Val != "}" {
- if p.node.Token.Val == "..." {
- // Add a simple fragment spread
- if current, err = p.run(0); err == nil {
- self.Children = append(self.Children, current)
- }
- } else {
- err = acceptFieldExpression(p, self)
- }
- if err != nil {
- return nil, err
- }
- }
- return self, skipToken(p, "}")
- }
- /*
- acceptFieldExpression parses a field expression. (@spec 2.5, 2.6, 2.7)
- */
- func acceptFieldExpression(p *parser, self *ASTNode) error {
- var err error
- // Field node gets the first token in the field expression
- fe := newAstNode(NodeField, p, p.node.Token)
- self.Children = append(self.Children, fe)
- current := p.node
- if p.node, err = p.next(); err == nil && p.node.Name != NodeEOF {
- if p.node.Token.Val == ":" {
- // Last node was an Alias not a name
- changeAstNode(current, NodeAlias, p)
- // Append Alias to Field children and move on
- fe.Children = append(fe.Children, current)
- if p.node, err = p.next(); err == nil && p.node.Name != NodeEOF {
- current = p.node
- p.node, err = p.next()
- }
- }
- if err == nil && p.node.Name != NodeEOF {
- // Next node must be a Name
- if current.Name == NodeName {
- // Append Name to Field children and move on
- fe.Children = append(fe.Children, current)
- } else {
- err = p.newParserError(ErrNameExpected,
- current.Token.String(), *current.Token)
- }
- if err == nil && p.node.Token.Val == "(" {
- // Parse arguments
- if current, err = p.run(0); err == nil {
- fe.Children = append(fe.Children, current)
- }
- }
- if err == nil && p.node.Token.Val == "@" {
- // Parse directives
- if current, err = p.run(0); err == nil {
- fe.Children = append(fe.Children, current)
- }
- }
- if err == nil && p.node.Token.Val == "{" {
- // Parse nested selection set
- if current, err = p.run(0); err == nil {
- fe.Children = append(fe.Children, current)
- }
- }
- }
- }
- return err
- }
- /*
- ndArgsOrVarDef parses an argument or variable definition expression. (@spec 2.6, 2.10)
- */
- func ndArgsOrVarDef(p *parser, self *ASTNode) (*ASTNode, error) {
- var err error
- var args, arg, current *ASTNode
- // Create a list token
- if p.isVarDef {
- args = newAstNode(NodeVariableDefinitions, p, p.node.Token)
- } else {
- args = newAstNode(NodeArguments, p, p.node.Token)
- }
- for err == nil && p.node.Token.ID != TokenEOF && p.node.Token.Val != ")" {
- if p.isVarDef {
- arg = newAstNode(NodeVariableDefinition, p, p.node.Token)
- } else {
- arg = newAstNode(NodeArgument, p, p.node.Token)
- }
- args.Children = append(args.Children, arg)
- if current, err = p.run(0); err == nil {
- if !p.isVarDef && current.Name != NodeName {
- err = p.newParserError(ErrNameExpected,
- current.Token.String(), *current.Token)
- } else if p.isVarDef && current.Name != NodeVariable {
- err = p.newParserError(ErrVariableExpected,
- current.Token.String(), *current.Token)
- } else {
- // Add name
- arg.Children = append(arg.Children, current)
- if err = skipToken(p, ":"); err == nil {
- // Add value
- if p.isVarDef {
- if current, err = p.run(0); err == nil {
- changeAstNode(current, NodeType, p)
- arg.Children = append(arg.Children, current)
- }
- } else {
- if current, err = parseValue(p); err == nil {
- arg.Children = append(arg.Children, current)
- }
- }
- if err == nil && p.isVarDef && p.node.Token.Val == "=" {
- skipToken(p, "=")
- // Parse default value
- if current, err = parseValue(p); err == nil {
- changeAstNode(current, NodeDefaultValue, p)
- arg.Children = append(arg.Children, current)
- }
- }
- }
- }
- }
- }
- // Must have a closing bracket
- if err == nil {
- return args, skipToken(p, ")")
- }
- return nil, err
- }
- /*
- parseValue parses a value and returns the result. (@spec 2.9)
- */
- func parseValue(p *parser) (*ASTNode, error) {
- p.isValue = true
- current, err := p.run(0)
- p.isValue = false
- if err == nil {
- if current.Token.Val == "true" ||
- current.Token.Val == "false" ||
- current.Token.Val == "null" ||
- current.Token.ID == TokenIntValue ||
- current.Token.ID == TokenFloatValue ||
- current.Token.ID == TokenStringValue {
- // Simple constant values
- changeAstNode(current, NodeValue, p)
- } else if current.Name == NodeName {
- // Enum values
- changeAstNode(current, NodeEnumValue, p)
- } else {
- // Everything else must be a variable or a complex data type
- errorutil.AssertTrue(current.Name == NodeVariable ||
- current.Name == NodeListValue ||
- current.Name == NodeObjectValue, fmt.Sprint("Unexpected value node:", current))
- }
- if err == nil {
- return current, err
- }
- }
- return nil, err
- }
- /*
- ndDirectives parses a directive expression. (@spec 2.12)
- */
- func ndDirectives(p *parser, self *ASTNode) (*ASTNode, error) {
- var err error
- var current *ASTNode
- dir := newAstNode(NodeDirective, p, p.node.Token)
- if err = acceptChild(p, dir, TokenName); err == nil {
- if current, err = p.run(0); err == nil {
- dir.Children = append(dir.Children, current)
- self.Children = append(self.Children, dir)
- if p.node.Token.Val == "@" {
- if p.node, err = p.next(); err == nil {
- return ndDirectives(p, self)
- }
- }
- }
- }
- return self, err
- }
- // Helper functions
- // ================
- /*
- skipToken skips over a token if it has one of the given valid values.
- */
- func skipToken(p *parser, validValues ...string) error {
- var err error
- canSkip := func(val string) bool {
- for _, i := range validValues {
- if i == val {
- return true
- }
- }
- return false
- }
- if !canSkip(p.node.Token.Val) {
- if p.node.Token.ID == TokenEOF {
- return p.newParserError(ErrUnexpectedEnd, "", *p.node.Token)
- }
- return p.newParserError(ErrUnexpectedToken, p.node.Token.Val, *p.node.Token)
- }
- // This should never return an error unless we skip over EOF or complex tokens
- // like values
- p.node, err = p.next()
- return err
- }
- /*
- acceptChild accepts the current token as a child.
- */
- func acceptChild(p *parser, self *ASTNode, id LexTokenID) error {
- var err error
- current := p.node
- if p.node, err = p.next(); err == nil {
- if current.Token.ID == id {
- self.Children = append(self.Children, current)
- } else {
- err = p.newParserError(ErrUnexpectedToken, current.Token.Val, *current.Token)
- }
- }
- return err
- }
|