func lexText(l *lex.Lexer) lex.StateFn { Loop: for { switch r := l.Next(); { case r == leftCurl: l.Backup() l.Emit(itemText) // emit whatever we have so far. l.Next() // advance one to get back to where we saw leftCurl. l.Depth += 1 // one level down. l.Emit(itemLeftCurl) return lexInside // we're in. case r == rightCurl: return l.Errorf("Too many right characters") case r == lex.EOF: break Loop case isNameBegin(r): l.Backup() l.Emit(itemText) return lexOperationType } } if l.Pos > l.Start { l.Emit(itemText) } l.Emit(lex.ItemEOF) return nil }
// lexInsideMutation lexes the text inside a mutation block. func lexInsideMutation(l *lex.Lexer) lex.StateFn { for { switch r := l.Next(); { case r == rightCurl: l.Depth-- l.Emit(itemRightCurl) if l.Depth == 0 { return lexText } case r == leftCurl: l.Depth++ l.Emit(itemLeftCurl) if l.Depth >= 2 { return lexTextMutation } case r == lex.EOF: return l.Errorf("Unclosed mutation action") case isSpace(r) || isEndOfLine(r): l.Ignore() case isNameBegin(r): return lexNameMutation default: return l.Errorf("Unrecognized character in lexInsideMutation: %#U", r) } } }
// lexDirective is called right after we see a @. func lexDirective(l *lex.Lexer) lex.StateFn { r := l.Next() if !isNameBegin(r) { return l.Errorf("Unrecognized character in lexDirective: %#U", r) } l.Backup() // This gives our buffer an initial capacity. Its length is zero though. The // buffer can grow beyond this initial capacity. buf := bytes.NewBuffer(make([]byte, 0, 15)) for { // The caller already checked isNameBegin, and absorbed one rune. r = l.Next() buf.WriteRune(r) if isNameSuffix(r) { continue } l.Backup() l.Emit(itemDirectiveName) directive := buf.Bytes()[:buf.Len()-1] // The lexer may behave differently for different directives. Hence, we need // to check the directive here and go into the right state. if string(directive) == "filter" { return lexFilterInside } return l.Errorf("Unhandled directive %s", directive) } return lexInside }
// Assumes '"' has already been encountered. func lexLiteral(l *lex.Lexer) lex.StateFn { for { r := l.Next() if r == '\u005c' { // backslash r = l.Next() continue // This would skip over the escaped rune. } if r == lex.EOF || isEndLiteral(r) { break } } l.Backup() l.Emit(itemLiteral) l.Next() // Move to end literal. l.Ignore() // Ignore end literal. l.Depth++ r := l.Peek() if r == '@' { return lexLanguage(l) } if r == '^' { return lexObjectType(l) } return lexText }
// lexTextMutation lexes and absorbs the text inside a mutation operation block. func lexTextMutation(l *lex.Lexer) lex.StateFn { for { r := l.Next() if r == lex.EOF { return l.Errorf("Unclosed mutation text") } if r == quote { return lexMutationValue } if r == leftCurl { l.Depth++ } if r == rightCurl { if l.Depth > 2 { l.Depth-- continue } } if r != rightCurl { // Absorb everything until we find '}'. continue } l.Backup() l.Emit(itemMutationContent) break } return lexInsideMutation }
func lexObject(l *lex.Lexer) lex.StateFn { for { switch r := l.Next(); { case r == rightCurl: return lexText case isSpace(r) || isEndOfLine(r): l.Ignore() case isNameBegin(r): { for { r := l.Next() if isNameSuffix(r) { continue // absorb } l.Backup() l.Emit(itemObject) break } return lexObjectBlock } default: return l.Errorf("Invalid schema. Unexpected %s", l.Input[l.Start:l.Pos]) } } }
func lexFragmentSpread(l *lex.Lexer) lex.StateFn { for { r := l.Next() if isNameSuffix(r) { continue } l.Backup() l.Emit(itemFragmentSpread) break } return lexInside }
// lexArgName lexes and emits the name part of an argument. func lexArgName(l *lex.Lexer) lex.StateFn { for { r := l.Next() if isNameSuffix(r) { continue } l.Backup() l.Emit(itemArgName) break } return lexArgInside }
// lexInside lexes the content inside a query block. func lexInside(l *lex.Lexer) lex.StateFn { for { switch r := l.Next(); { case r == period: if l.Next() == period && l.Next() == period { return lexFragmentSpread } // We do not expect a period at all. If you do, you may want to // backup the two extra periods we try to read. return l.Errorf("Unrecognized character in lexInside: %#U", r) case r == rightCurl: l.Depth-- l.Emit(itemRightCurl) if l.Depth == 0 { return lexText } case r == leftCurl: l.Depth++ l.Emit(itemLeftCurl) case r == lex.EOF: return l.Errorf("Unclosed action") case isSpace(r) || isEndOfLine(r) || r == comma: l.Ignore() case isNameBegin(r): return lexName case r == '#': l.Backup() return lexComment case r == leftRound: l.Emit(itemLeftRound) l.AcceptRun(isSpace) l.Ignore() k := l.Next() if k == '_' || l.Depth != 1 || l.Mode == fragmentMode { l.Backup() l.Emit(itemArgument) return lexArgInside } // This is a generator function. l.Backup() l.Emit(itemGenerator) l.FilterDepth++ return lexFilterInside case r == ':': return lexAlias case r == '@': return lexDirective default: return l.Errorf("Unrecognized character in lexInside: %#U", r) } } }
// lexFilterFuncName expects input to look like equal("...", "..."). func lexFilterFuncName(l *lex.Lexer) lex.StateFn { for { // The caller already checked isNameBegin, and absorbed one rune. r := l.Next() if isNameSuffix(r) { continue } l.Backup() l.Emit(itemFilterFunc) break } return lexFilterFuncInside }
// lexNameMutation lexes the itemMutationOp, which could be set or delete. func lexNameMutation(l *lex.Lexer) lex.StateFn { for { // The caller already checked isNameBegin, and absorbed one rune. r := l.Next() if isNameBegin(r) { continue } l.Backup() l.Emit(itemMutationOp) break } return lexInsideMutation }
func lexAlias(l *lex.Lexer) lex.StateFn { l.AcceptRun(isSpace) l.Ignore() // Any spaces encountered. for { r := l.Next() if isNameSuffix(r) { continue } l.Backup() l.Emit(itemAlias) break } return lexInside }
func lexLanguage(l *lex.Lexer) lex.StateFn { r := l.Next() if r != '@' { return l.Errorf("Expected @ prefix for lexLanguage") } l.Ignore() r = l.Next() if !isLangTagPrefix(r) { return l.Errorf("Invalid language tag prefix: %v", r) } l.AcceptRun(isLangTag) l.Emit(itemLanguage) return lexText }
func lexUntilClosing(l *lex.Lexer, styp lex.ItemType, sfn lex.StateFn) lex.StateFn { l.AcceptUntil(isClosingBracket) r := l.Next() if r == lex.EOF { return l.Errorf("Unexpected end of subject") } if r == '>' { l.Emit(styp) return sfn } return l.Errorf("Invalid character %v found for itemType: %v", r, styp) }
func lexOperationType(l *lex.Lexer) lex.StateFn { for { r := l.Next() if isNameSuffix(r) { continue // absorb } l.Backup() word := l.Input[l.Start:l.Pos] if word == "query" || word == "mutation" { l.Emit(itemOpType) } break } return lexText }
// lexArgVal lexes and emits the value part of an argument. func lexArgVal(l *lex.Lexer) lex.StateFn { l.AcceptRun(isSpace) l.Ignore() // Any spaces encountered. for { r := l.Next() if isSpace(r) || isEndOfLine(r) || r == rightRound || r == comma { l.Backup() l.Emit(itemArgVal) return lexArgInside } if r == lex.EOF { return l.Errorf("Reached lex.EOF while reading var value: %v", l.Input[l.Start:l.Pos]) } } }
func lexScalarBlock(l *lex.Lexer) lex.StateFn { for { switch r := l.Next(); { case r == ')': l.Emit(itemRightRound) return lexText case isNameBegin(r): l.Backup() return lexScalarPair1 case isSpace(r) || isEndOfLine(r): l.Ignore() default: return l.Errorf("Invalid schema. Unexpected %s", l.Input[l.Start:l.Pos]) } } }
func lexObjectBlock(l *lex.Lexer) lex.StateFn { for { switch r := l.Next(); { case r == leftCurl: l.Emit(itemLeftCurl) case isSpace(r) || isEndOfLine(r): l.Ignore() case r == rightCurl: l.Emit(itemRightCurl) return lexText case isNameBegin(r): return lexObjectPair default: return l.Errorf("Invalid schema. Unexpected %s", l.Input[l.Start:l.Pos]) } } }
func lexArgVal(l *lex.Lexer) lex.StateFn { l.AcceptRun(isSpace) l.Ignore() // Any spaces encountered. for { r := l.Next() if isSpace(r) || isEndOfLine(r) || r == ')' || r == ',' { l.Backup() l.Emit(itemArgVal) return lexArgInside } if r == lex.EOF { return l.Errorf("Reached lex.EOF while reading var value: %v", l.Input[l.Start:l.Pos]) } } glog.Fatal("This shouldn't be reached.") return nil }
// Assumes that the current rune is '_'. func lexBlankNode(l *lex.Lexer, styp lex.ItemType, sfn lex.StateFn) lex.StateFn { // RDF Blank Node. // TODO: At some point do checkings based on the guidelines. For now, // just accept everything until space. l.AcceptUntil(isSpace) r := l.Peek() if r == lex.EOF { return l.Errorf("Unexpected end of subject") } if isSpace(r) { l.Emit(styp) return sfn } return l.Errorf("Invalid character %v found for itemType: %v", r, styp) }
// lexArgInside is used to lex the arguments inside (). func lexArgInside(l *lex.Lexer) lex.StateFn { for { switch r := l.Next(); { case r == lex.EOF: return l.Errorf("unclosed argument") case isSpace(r) || isEndOfLine(r) || r == comma: l.Ignore() case isNameBegin(r): return lexArgName case r == ':': l.Ignore() return lexArgVal case r == rightRound: l.Emit(itemRightRound) return lexInside default: return l.Errorf("argument list invalid") } } }
// lexText lexes the input string and calls other lex functions. func lexText(l *lex.Lexer) lex.StateFn { Loop: for { switch r := l.Next(); { case r == lex.EOF: break Loop case isNameBegin(r): l.Backup() return lexStart case isSpace(r) || isEndOfLine(r): l.Ignore() default: return l.Errorf("Invalid schema. Unexpected %s", l.Input[l.Start:l.Pos]) } } if l.Pos > l.Start { l.Emit(itemText) } l.Emit(lex.ItemEOF) return nil }
func lexStart(l *lex.Lexer) lex.StateFn { for { r := l.Next() if isNameSuffix(r) { continue // absorb } l.Backup() // l.Pos would be index of the end of operation type + 1. word := l.Input[l.Start:l.Pos] if word == "scalar" { l.Emit(itemScalar) return lexScalar } else if word == "type" { l.Emit(itemType) return lexObject } else { return l.Errorf("Invalid schema") } } }
func lexVarInside(l *lex.Lexer) lex.StateFn { for { switch r := l.Next(); { case r == lex.EOF: return l.Errorf("unclosed argument") case isSpace(r) || isEndOfLine(r): l.Ignore() case isDollar(r): return lexVarName case r == ':': l.Ignore() return lexVarType case r == equal: l.Emit(itemEqual) l.Ignore() return lexVarDefault case r == rightRound: l.Emit(itemRightRound) return lexText case r == comma: l.Emit(itemComma) l.Ignore() default: return l.Errorf("variable list invalid") } } }
// lexOperationType lexes a query or mutation operation type. func lexOperationType(l *lex.Lexer) lex.StateFn { for { r := l.Next() if isNameSuffix(r) { continue // absorb } l.Backup() // l.Pos would be index of the end of operation type + 1. word := l.Input[l.Start:l.Pos] if word == "mutation" { l.Emit(itemOpType) l.Mode = mutationMode } else if word == "fragment" { l.Emit(itemOpType) l.Mode = fragmentMode } else if word == "query" { l.Emit(itemOpType) l.Mode = queryMode } else { if l.Mode == 0 { l.Errorf("Invalid operation type") } } break } return lexText }
func lexInside(l *lex.Lexer) lex.StateFn { for { switch r := l.Next(); { case r == rightCurl: l.Depth -= 1 l.Emit(itemRightCurl) if l.Depth == 0 { return lexText } case r == leftCurl: l.Depth += 1 l.Emit(itemLeftCurl) case r == lex.EOF: return l.Errorf("unclosed action") case isSpace(r) || isEndOfLine(r) || r == ',': l.Ignore() case isNameBegin(r): return lexName case r == '#': l.Backup() return lexComment case r == '(': l.Emit(itemLeftRound) return lexArgInside default: return l.Errorf("Unrecognized character in lexInside: %#U", r) } } }
func lexUidNode(l *lex.Lexer, styp lex.ItemType, sfn lex.StateFn) lex.StateFn { l.AcceptUntil(isSpace) r := l.Peek() if r == lex.EOF { return l.Errorf("Unexpected end of uid subject") } in := l.Input[l.Start:l.Pos] if !strings.HasPrefix(in, "_uid_:") { return l.Errorf("Expected _uid_: Found: %v", l.Input[l.Start:l.Pos]) } if _, err := strconv.ParseUint(in[6:], 0, 64); err != nil { return l.Errorf("Unable to convert '%v' to UID", in[6:]) } if isSpace(r) { l.Emit(styp) return sfn } return l.Errorf("Invalid character %v found for UID node itemType: %v", r, styp) }
// lexFilterInside expects input like ( (equal(...) && f(...)) || g(...) ). func lexFilterInside(l *lex.Lexer) lex.StateFn { for { r := l.Next() switch { case r == leftRound: l.Emit(itemLeftRound) l.FilterDepth++ case r == rightRound: if l.FilterDepth == 0 { return l.Errorf("Unexpected right round bracket") } l.FilterDepth-- l.Emit(itemRightRound) if l.FilterDepth == 0 { return lexInside // Filter directive is done. } case r == lex.EOF: return l.Errorf("Unclosed directive") case isSpace(r) || isEndOfLine(r): l.Ignore() case isNameBegin(r): return lexFilterFuncName case r == '&': r2 := l.Next() if r2 == '&' { l.Emit(itemFilterAnd) return lexFilterInside } return l.Errorf("Expected & but got %v", r2) case r == '|': r2 := l.Next() if r2 == '|' { l.Emit(itemFilterOr) return lexFilterInside } return l.Errorf("Expected | but got %v", r2) default: return l.Errorf("Unrecognized character in lexInside: %#U", r) } } }
// lexComment lexes a comment text. func lexComment(l *lex.Lexer) lex.StateFn { for { r := l.Next() if isEndOfLine(r) { l.Emit(itemComment) return lexInside } if r == lex.EOF { break } } if l.Pos > l.Start { l.Emit(itemComment) } l.Emit(lex.ItemEOF) return nil // Stop the run loop. }
func lexObjectPair(l *lex.Lexer) lex.StateFn { for { r := l.Next() if isNameSuffix(r) { continue // absorb } l.Backup() l.Emit(itemObjectName) break } L: for { switch r := l.Next(); { case isSpace(r) || isEndOfLine(r): l.Ignore() case r == ':': l.Emit(itemCollon) break case isNameBegin(r): l.Backup() break L default: return l.Errorf("Invalid schema. Unexpected %s", l.Input[l.Start:l.Pos]) } } for { r := l.Next() if isNameSuffix(r) { continue // absorb } l.Backup() l.Emit(itemObjectType) break } return lexObjectBlock }