1package lexer
2
3import (
4	"fmt"
5
6	"github.com/ChrisTrenkamp/goxpath/xconst"
7)
8
9func absLocPathState(l *Lexer) stateFn {
10	l.emit(XItemAbsLocPath)
11	return stepState
12}
13
14func abbrAbsLocPathState(l *Lexer) stateFn {
15	l.emit(XItemAbbrAbsLocPath)
16	return stepState
17}
18
19func relLocPathState(l *Lexer) stateFn {
20	l.emit(XItemRelLocPath)
21	return stepState
22}
23
24func abbrRelLocPathState(l *Lexer) stateFn {
25	l.emit(XItemAbbrRelLocPath)
26	return stepState
27}
28
29func stepState(l *Lexer) stateFn {
30	l.skipWS(true)
31	r := l.next()
32
33	for isElemChar(r) {
34		r = l.next()
35	}
36
37	l.backup()
38	tok := l.input[l.start:l.pos]
39
40	state, err := parseSeparators(l, tok)
41	if err != nil {
42		return l.errorf(err.Error())
43	}
44
45	return getNextPathState(l, state)
46}
47
48func parseSeparators(l *Lexer, tok string) (XItemType, error) {
49	l.skipWS(false)
50	state := XItemType(XItemQName)
51	r := l.peek()
52
53	if string(r) == ":" && string(l.peekAt(2)) == ":" {
54		var err error
55		if state, err = getAxis(l, tok); err != nil {
56			return state, fmt.Errorf(err.Error())
57		}
58	} else if string(r) == ":" {
59		state = XItemNCName
60		l.emitVal(state, tok)
61		l.skip(1)
62		l.skipWS(true)
63	} else if string(r) == "@" {
64		state = XItemAbbrAxis
65		l.emitVal(state, tok)
66		l.skip(1)
67		l.skipWS(true)
68	} else if string(r) == "(" {
69		var err error
70		if state, err = getNT(l, tok); err != nil {
71			return state, fmt.Errorf(err.Error())
72		}
73	} else if len(tok) > 0 {
74		l.emitVal(state, tok)
75	}
76
77	return state, nil
78}
79
80func getAxis(l *Lexer, tok string) (XItemType, error) {
81	var state XItemType
82	for i := range xconst.AxisNames {
83		if tok == xconst.AxisNames[i] {
84			state = XItemAxis
85		}
86	}
87	if state != XItemAxis {
88		return state, fmt.Errorf("Invalid Axis specifier, %s", tok)
89	}
90	l.emitVal(state, tok)
91	l.skip(2)
92	l.skipWS(true)
93	return state, nil
94}
95
96func getNT(l *Lexer, tok string) (XItemType, error) {
97	isNT := false
98	for _, i := range xconst.NodeTypes {
99		if tok == i {
100			isNT = true
101			break
102		}
103	}
104
105	if isNT {
106		return procNT(l, tok)
107	}
108
109	return XItemError, fmt.Errorf("Invalid node-type " + tok)
110}
111
112func procNT(l *Lexer, tok string) (XItemType, error) {
113	state := XItemType(XItemNodeType)
114	l.emitVal(state, tok)
115	l.skip(1)
116	l.skipWS(true)
117	n := l.peek()
118	if tok == xconst.NodeTypeProcInst && (string(n) == `"` || string(n) == `'`) {
119		if err := getStrLit(l, XItemProcLit); err != nil {
120			return state, fmt.Errorf(err.Error())
121		}
122		l.skipWS(true)
123		n = l.next()
124	}
125
126	if string(n) != ")" {
127		return state, fmt.Errorf("Missing ) at end of NodeType declaration.")
128	}
129
130	l.skip(1)
131	return state, nil
132}
133
134func procFunc(l *Lexer, tok string) error {
135	state := XItemType(XItemFunction)
136	l.emitVal(state, tok)
137	l.skip(1)
138	l.skipWS(true)
139	if string(l.peek()) != ")" {
140		l.emit(XItemArgument)
141		for {
142			for state := startState; state != nil; {
143				state = state(l)
144			}
145			l.skipWS(true)
146
147			if string(l.peek()) == "," {
148				l.emit(XItemArgument)
149				l.skip(1)
150			} else if string(l.peek()) == ")" {
151				l.emit(XItemEndFunction)
152				l.skip(1)
153				break
154			} else if l.peek() == eof {
155				return fmt.Errorf("Missing ) at end of function declaration.")
156			}
157		}
158	} else {
159		l.emit(XItemEndFunction)
160		l.skip(1)
161	}
162
163	return nil
164}
165
166func getNextPathState(l *Lexer, state XItemType) stateFn {
167	isMultiPart := state == XItemAxis || state == XItemAbbrAxis || state == XItemNCName
168
169	l.skipWS(true)
170
171	for string(l.peek()) == "[" {
172		if err := getPred(l); err != nil {
173			return l.errorf(err.Error())
174		}
175	}
176
177	if string(l.peek()) == "/" && !isMultiPart {
178		l.skip(1)
179		if string(l.peek()) == "/" {
180			l.skip(1)
181			return abbrRelLocPathState
182		}
183		l.skipWS(true)
184		return relLocPathState
185	} else if isMultiPart && isElemChar(l.peek()) {
186		return stepState
187	}
188
189	if isMultiPart {
190		return l.errorf("Step is not complete")
191	}
192
193	l.emit(XItemEndPath)
194	return findOperatorState
195}
196
197func getPred(l *Lexer) error {
198	l.emit(XItemPredicate)
199	l.skip(1)
200	l.skipWS(true)
201
202	if string(l.peek()) == "]" {
203		return fmt.Errorf("Missing content in predicate.")
204	}
205
206	for state := startState; state != nil; {
207		state = state(l)
208	}
209
210	l.skipWS(true)
211	if string(l.peek()) != "]" {
212		return fmt.Errorf("Missing ] at end of predicate.")
213	}
214	l.skip(1)
215	l.emit(XItemEndPredicate)
216	l.skipWS(true)
217
218	return nil
219}
220