package lexer import ( "fmt" "github.com/ChrisTrenkamp/goxpath/internal/xconst" ) func absLocPathState(l *Lexer) stateFn { l.emit(XItemAbsLocPath) return stepState } func abbrAbsLocPathState(l *Lexer) stateFn { l.emit(XItemAbbrAbsLocPath) return stepState } func relLocPathState(l *Lexer) stateFn { l.emit(XItemRelLocPath) return stepState } func abbrRelLocPathState(l *Lexer) stateFn { l.emit(XItemAbbrRelLocPath) return stepState } func stepState(l *Lexer) stateFn { l.skipWS(true) r := l.next() for isElemChar(r) { r = l.next() } l.backup() tok := l.input[l.start:l.pos] state, err := parseSeparators(l, tok) if err != nil { return l.errorf(err.Error()) } return getNextPathState(l, state) } func parseSeparators(l *Lexer, tok string) (XItemType, error) { l.skipWS(false) state := XItemType(XItemQName) r := l.peek() if string(r) == ":" && string(l.peekAt(2)) == ":" { var err error if state, err = getAxis(l, tok); err != nil { return state, fmt.Errorf(err.Error()) } } else if string(r) == ":" { state = XItemNCName l.emitVal(state, tok) l.skip(1) l.skipWS(true) } else if string(r) == "@" { state = XItemAbbrAxis l.emitVal(state, tok) l.skip(1) l.skipWS(true) } else if string(r) == "(" { var err error if state, err = getNT(l, tok); err != nil { return state, fmt.Errorf(err.Error()) } } else if len(tok) > 0 { l.emitVal(state, tok) } return state, nil } func getAxis(l *Lexer, tok string) (XItemType, error) { var state XItemType for i := range xconst.AxisNames { if tok == xconst.AxisNames[i] { state = XItemAxis } } if state != XItemAxis { return state, fmt.Errorf("Invalid Axis specifier, %s", tok) } l.emitVal(state, tok) l.skip(2) l.skipWS(true) return state, nil } func getNT(l *Lexer, tok string) (XItemType, error) { isNT := false for _, i := range xconst.NodeTypes { if tok == i { isNT = true break } } if isNT { return procNT(l, tok) } return XItemError, fmt.Errorf("Invalid node-type " + tok) } func procNT(l *Lexer, tok string) (XItemType, error) { state := XItemType(XItemNodeType) l.emitVal(state, tok) l.skip(1) l.skipWS(true) n := l.peek() if tok == xconst.NodeTypeProcInst && (string(n) == `"` || string(n) == `'`) { if err := getStrLit(l, XItemProcLit); err != nil { return state, fmt.Errorf(err.Error()) } l.skipWS(true) n = l.next() } if string(n) != ")" { return state, fmt.Errorf("Missing ) at end of NodeType declaration.") } l.skip(1) return state, nil } func procFunc(l *Lexer, tok string) error { state := XItemType(XItemFunction) l.emitVal(state, tok) l.skip(1) l.skipWS(true) if string(l.peek()) != ")" { l.emit(XItemArgument) for { for state := startState; state != nil; { state = state(l) } l.skipWS(true) if string(l.peek()) == "," { l.emit(XItemArgument) l.skip(1) } else if string(l.peek()) == ")" { l.emit(XItemEndFunction) l.skip(1) break } else if l.peek() == eof { return fmt.Errorf("Missing ) at end of function declaration.") } } } else { l.emit(XItemEndFunction) l.skip(1) } return nil } func getNextPathState(l *Lexer, state XItemType) stateFn { isMultiPart := state == XItemAxis || state == XItemAbbrAxis || state == XItemNCName l.skipWS(true) for string(l.peek()) == "[" { if err := getPred(l); err != nil { return l.errorf(err.Error()) } } if string(l.peek()) == "/" && !isMultiPart { l.skip(1) if string(l.peek()) == "/" { l.skip(1) return abbrRelLocPathState } l.skipWS(true) return relLocPathState } else if isMultiPart && isElemChar(l.peek()) { return stepState } if isMultiPart { return l.errorf("Step is not complete") } l.emit(XItemEndPath) return findOperatorState } func getPred(l *Lexer) error { l.emit(XItemPredicate) l.skip(1) l.skipWS(true) if string(l.peek()) == "]" { return fmt.Errorf("Missing content in predicate.") } for state := startState; state != nil; { state = state(l) } l.skipWS(true) if string(l.peek()) != "]" { return fmt.Errorf("Missing ] at end of predicate.") } l.skip(1) l.emit(XItemEndPredicate) l.skipWS(true) return nil }