Skip to content

Commit d39ab81

Browse files
committed
implementing new selector engine, cuz pegs didnt work well on compile time
1 parent 87f9a62 commit d39ab81

File tree

3 files changed

+55
-30
lines changed

3 files changed

+55
-30
lines changed

src/xml.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ iterator tokens*(input: string): XmlToken {.inline.} =
111111
inc(pos)
112112
var next_ch = input.find(ch, pos)
113113
if next_ch == -1:
114-
error(fmt"unable to find matching string quote last found {pos}")
114+
error(fmt"unable to find matching string quote last found {pos}")
115115
yield token(STRING, input[pos..<next_ch])
116116
pos = next_ch+1
117117
of '>':

src/xml/selector.nim

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
import pegs, strutils, ../xml
1+
import strutils, ../xml
22
from streams import newStringStream
33
from strtabs import hasKey
44

5-
6-
let
7-
attribute = r"[a-zA-Z][a-zA-Z0-9_\-]*"
8-
classes = r"{\.[a-zA-Z0-9_][a-zA-Z0-9_\-]*}"
9-
attributes = r"{\[" & attribute & r"\s*([\*\^\$\~]?\=\s*[\'""]?(\s*\ident\s*)+[\'""]?)?\]}"
10-
pselectors = peg(r"\s*{\ident}?({'#'\ident})? (" & classes & ")* " & attributes & "*")
11-
pattributes = peg(r"{\[{" & attribute & r"}\s*({[\*\^\$\~]?}\=\s*[\'""]?{(\s*\ident\s*)+}[\'""]?)?\]}")
12-
135
type
6+
TokenKind = enum
7+
TAG
8+
ID
9+
CLASS
10+
ATTR
1411
Attribute = object
1512
name: string
1613
operator: char
@@ -26,7 +23,18 @@ type
2623
QueryContext = object
2724
root: seq[XmlNode]
2825

29-
proc newSelector(tag, id = "", classes: seq[string] = @[], attributes: seq[Attribute] = @[]): Selector =
26+
proc push(s: var Selector, kind: TokenKind, name: string) =
27+
case kind
28+
of TAG:
29+
s.tag = name
30+
of ID:
31+
s.id = name
32+
of CLASS:
33+
s.classes.add(name)
34+
else:
35+
echo "parse attribute"
36+
37+
proc newSelector*(tag, id = "", classes: seq[string] = @[], attributes: seq[Attribute] = @[]): Selector =
3038
result.combinator = ' '
3139
result.tag = tag
3240
result.id = id
@@ -140,32 +148,45 @@ proc searchCombined(parents: var seq[XmlNode], selectors: seq[Selector]) =
140148

141149
parents = found
142150

143-
proc parseSelector(token: string): Selector =
151+
proc parseSelector*(token: string): Selector =
144152
result = newSelector()
145153
# Universal selector
146154
if token == "*":
147155
result.tag = "*"
148156
# Type selector
149-
elif token =~ pselectors:
150-
for i in 0..matches.len-1:
151-
if matches[i].isNil:
157+
else:
158+
var
159+
pos: int
160+
length = token.len
161+
kind = TAG
162+
name = ""
163+
ch: char
164+
165+
while pos < length:
166+
ch = token[pos]
167+
if ch in Whitespace:
168+
inc(pos)
152169
continue
153-
154-
let ch = matches[i][0]
155-
case ch:
156-
of '#':
157-
matches[i].delete(0, 0)
158-
result.id = matches[i]
159-
of '.':
160-
matches[i].delete(0, 0)
161-
result.classes.add(matches[i])
162-
of '[':
163-
if matches[i] =~ pattributes:
164-
result.attributes.add(newAttribute(matches[1], matches[2], matches[3]))
170+
if ch in {'#', '.', '[', '=', ']'}:
171+
result.push(kind, name)
172+
if ch == '#':
173+
kind = ID
174+
elif ch == '.':
175+
kind = CLASS
176+
elif ch == '[':
177+
kind = ATTR
178+
name = ""
179+
#echo "next ", kind
165180
else:
166-
result.tag = matches[i]
167-
else:
168-
discard
181+
#if name.len == 0:
182+
# assert ch in IdentStartChars
183+
name.add(ch)
184+
185+
if pos == length-1:
186+
result.push(kind, name)
187+
break
188+
189+
inc(pos)
169190

170191
proc select*(q: QueryContext, s: string = ""): seq[XmlNode] =
171192
## Return list of nodes matched by CSS selector

tests/test.nim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import ../src/xml/selector
2+
3+
4+
echo parseSelector("object.GtkLabel.clas[type='aa']")

0 commit comments

Comments
 (0)