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) } } }
// 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 }
// This function inspects the next rune and calls the appropriate stateFn. func lexText(l *lex.Lexer) lex.StateFn { Loop: for { switch r := l.Next(); { case r == '<' || r == '_': if l.Depth == atSubject { l.Backup() l.Emit(itemText) // emit whatever we have so far. return lexSubject } if l.Depth == atPredicate { l.Backup() l.Emit(itemText) return lexPredicate } if l.Depth == atObject { l.Backup() l.Emit(itemText) return lexObject } if l.Depth == atLabel { l.Backup() l.Emit(itemText) return lexLabel } return l.Errorf("Invalid input: %c at lexText", r) case r == '"': if l.Depth != atObject { return l.Errorf("Invalid quote for non-object.") } l.Backup() l.Emit(itemText) return lexObject case r == lex.EOF: break Loop case r == '.': if l.Depth > atObject { l.Emit(itemValidEnd) } break Loop case isSpace(r): continue default: l.Errorf("Invalid input: %c at lexText", r) } } if l.Pos > l.Start { l.Emit(itemText) } l.Emit(lex.ItemEOF) return nil }
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]) } } }
// 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 }
// 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 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 }
func lexFragmentSpread(l *lex.Lexer) lex.StateFn { for { r := l.Next() if isNameSuffix(r) { continue } l.Backup() l.Emit(itemFragmentSpread) break } return lexInside }
func lexText(l *lex.Lexer) lex.StateFn { Loop: for { switch r := l.Next(); { case r == '<' || r == '_': if l.Depth == AT_SUBJECT { l.Backup() l.Emit(itemText) // emit whatever we have so far. return lexSubject } else if l.Depth == AT_PREDICATE { l.Backup() l.Emit(itemText) return lexPredicate } else if l.Depth == AT_OBJECT { l.Backup() l.Emit(itemText) return lexObject } else if l.Depth == AT_LABEL { l.Backup() l.Emit(itemText) return lexLabel } else { return l.Errorf("Invalid input: %v at lexText", r) } case r == '"': if l.Depth != AT_OBJECT { return l.Errorf("Invalid quote for non-object.") } l.Backup() l.Emit(itemText) return lexObject case r == lex.EOF: break Loop case r == '.': if l.Depth > AT_OBJECT { l.Emit(itemValidEnd) } break Loop } } if l.Pos > l.Start { l.Emit(itemText) } l.Emit(lex.ItemEOF) return nil }
// 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 }
// 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 }
// 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 }
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 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 }
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]) } } }
// 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 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 }
func lexLabel(l *lex.Lexer) lex.StateFn { r := l.Next() // Graph label can either be an IRI or a blank node according to spec. if r == '<' { l.Depth++ return lexUntilClosing(l, itemLabel, lexText) } if r == '_' { l.Depth++ r = l.Next() if r != ':' { return l.Errorf("Invalid char: %c at lexLabel", r) } l.Backup() return lexBlankNode(l, itemLabel, lexText) } return l.Errorf("Invalid char: %v at lexLabel", r) }
// 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") } } }
// 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) } } }
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 }
// 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 == 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++ // one level down. l.Emit(itemLeftCurl) if l.Mode == mutationMode { return lexInsideMutation } // Both queryMode and fragmentMode are handled by lexInside. return lexInside case r == rightCurl: return l.Errorf("Too many right characters") case r == lex.EOF: break Loop case r == leftRound: l.Backup() l.Emit(itemText) l.Next() l.Emit(itemLeftRound) return lexVarInside case isNameBegin(r): l.Backup() l.Emit(itemText) return lexOperationType } } if l.Pos > l.Start { l.Emit(itemText) } l.Emit(lex.ItemEOF) return nil }
func lexScalarPair1(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. l.Emit(itemScalarName) 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(itemScalarType) break } // Check for the mention of @index. var isIndexed bool L1: for { switch r := l.Next(); { case isSpace(r): l.Ignore() case isEndOfLine(r): break L1 case r == '@': l.Emit(itemAt) isIndexed = true 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 == "index" { l.Emit(itemIndex) break L1 } else { return l.Errorf("Invalid mention of index") } } break L1 default: return l.Errorf("Invalid schema. Unexpected %s", l.Input[l.Start:l.Pos]) } } if !isIndexed { l.Emit(itemDummy) } return lexScalarBlock }