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 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) } } }
// 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 }
// 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 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") } } }
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 lexObject(l *lex.Lexer) lex.StateFn { r := l.Next() // The object can be an IRI, blank node or a literal. if r == '<' { l.Depth++ return lexUntilClosing(l, itemObject, lexText) } if r == '_' { l.Depth++ r = l.Next() // TODO - Remove this, doesn't conform to the spec. if r == 'u' { return lexUidNode(l, itemObject, lexText) } if r == ':' { return lexBlankNode(l, itemObject, lexText) } } if r == '"' { l.Ignore() return lexLiteral(l) } return l.Errorf("Invalid char: %v at lexObject", r) }
func lexPredicate(l *lex.Lexer) lex.StateFn { r := l.Next() if r != '<' { return l.Errorf("Invalid character in lexPredicate: %v", r) } l.Depth += 1 return lexUntilClosing(l, itemPredicate, lexText) }
func lexPredicate(l *lex.Lexer) lex.StateFn { r := l.Next() // The predicate can only be an IRI according to the spec. if r != '<' { return l.Errorf("Invalid character in lexPredicate: %v", r) } l.Depth++ return lexUntilClosing(l, itemPredicate, lexText) }
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 }
func lexLabel(l *lex.Lexer) lex.StateFn { r := l.Next() if r == '<' { l.Depth += 1 return lexUntilClosing(l, itemLabel, lexText) } if r == '_' { l.Depth += 1 return lexBlankNode(l, itemLabel, lexText) } return l.Errorf("Invalid char: %v at lexLabel", r) }
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 lexSubject(l *lex.Lexer) lex.StateFn { r := l.Next() if r == '<' { l.Depth += 1 return lexUntilClosing(l, itemSubject, lexText) } if r == '_' { l.Depth += 1 return lexBlankNode(l, itemSubject, lexText) } return l.Errorf("Invalid character during lexSubject: %v", r) }
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 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 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 lexObject(l *lex.Lexer) lex.StateFn { r := l.Next() if r == '<' { l.Depth += 1 return lexUntilClosing(l, itemObject, lexText) } if r == '_' { l.Depth += 1 return lexBlankNode(l, itemObject, lexText) } if r == '"' { l.Ignore() return lexLiteral(l) } return l.Errorf("Invalid char: %v at lexObject", r) }
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") } } }
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) }
// 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) } } }
// 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 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 }
// 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 }
// 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 }