synvert-core 1.1.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/Gemfile +9 -0
- data/lib/synvert/core/array_ext.rb +9 -2
- data/lib/synvert/core/node_ext.rb +14 -2
- data/lib/synvert/core/node_query/compiler/array.rb +1 -1
- data/lib/synvert/core/node_query/compiler/attribute.rb +6 -18
- data/lib/synvert/core/node_query/compiler/comparable.rb +26 -19
- data/lib/synvert/core/node_query/compiler/expression.rb +22 -52
- data/lib/synvert/core/node_query/compiler/identifier.rb +1 -1
- data/lib/synvert/core/node_query/compiler/regexp.rb +2 -2
- data/lib/synvert/core/node_query/compiler/selector.rb +116 -31
- data/lib/synvert/core/node_query/compiler/simple_selector.rb +29 -0
- data/lib/synvert/core/node_query/compiler/string.rb +1 -1
- data/lib/synvert/core/node_query/compiler.rb +1 -0
- data/lib/synvert/core/node_query/lexer.rex +27 -17
- data/lib/synvert/core/node_query/lexer.rex.rb +53 -29
- data/lib/synvert/core/node_query/parser.racc.rb +119 -315
- data/lib/synvert/core/node_query/parser.y +20 -42
- data/lib/synvert/core/node_query.rb +7 -7
- data/lib/synvert/core/version.rb +1 -1
- data/spec/synvert/core/node_ext_spec.rb +7 -5
- data/spec/synvert/core/node_query/lexer_spec.rb +76 -50
- data/spec/synvert/core/node_query/parser_spec.rb +181 -114
- data/spec/synvert/core/rewriter/instance_spec.rb +3 -3
- data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +3 -3
- data/synvert-core-ruby.gemspec +0 -10
- metadata +3 -128
@@ -7,6 +7,8 @@ macros
|
|
7
7
|
CLOSE_ARRAY /\)/
|
8
8
|
OPEN_SELECTOR /\(/
|
9
9
|
CLOSE_SELECTOR /\)/
|
10
|
+
OPEN_GOTO_SCOPE /</
|
11
|
+
CLOSE_GOTO_SCOPE />/
|
10
12
|
OPEN_DYNAMIC_ATTRIBUTE /{{/
|
11
13
|
CLOSE_DYNAMIC_ATTRIBUTE /}}/
|
12
14
|
NODE_TYPE /\.[a-z]+/
|
@@ -20,8 +22,8 @@ macros
|
|
20
22
|
REGEXP /\/(#{REGEXP_BODY})(?<!\\)\/([imxo]*)/
|
21
23
|
SYMBOL /:[\w!\?<>=]+/
|
22
24
|
TRUE /true/
|
23
|
-
SINGLE_QUOTE_STRING /'
|
24
|
-
DOUBLE_QUOTE_STRING /"
|
25
|
+
SINGLE_QUOTE_STRING /'.*?'/
|
26
|
+
DOUBLE_QUOTE_STRING /".*?"/
|
25
27
|
|
26
28
|
rules
|
27
29
|
|
@@ -34,24 +36,31 @@ rules
|
|
34
36
|
/:has/ { [:tPSEUDO_CLASS, text[1..-1]] }
|
35
37
|
/:not_has/ { [:tPSEUDO_CLASS, text[1..-1]] }
|
36
38
|
/#{NODE_TYPE}/ { [:tNODE_TYPE, text[1..]] }
|
37
|
-
/>/ { [:
|
38
|
-
/~/ { [:
|
39
|
-
/\+/ { [:
|
39
|
+
/>/ { [:tRELATIONSHIP, text] }
|
40
|
+
/~/ { [:tRELATIONSHIP, text] }
|
41
|
+
/\+/ { [:tRELATIONSHIP, text] }
|
40
42
|
/#{OPEN_SELECTOR}/ { [:tOPEN_SELECTOR, text] }
|
41
43
|
/#{CLOSE_SELECTOR}/ { [:tCLOSE_SELECTOR, text] }
|
44
|
+
/#{OPEN_GOTO_SCOPE}/ { @state = :GOTO_SCOPE; [:tOPEN_GOTO_SCOPE, text] }
|
42
45
|
/#{OPEN_ATTRIBUTE}/ { @nested_count += 1; @state = :KEY; [:tOPEN_ATTRIBUTE, text] }
|
46
|
+
:GOTO_SCOPE /\s+/
|
47
|
+
:GOTO_SCOPE /#{IDENTIFIER}/ { [:tIDENTIFIER, text] }
|
48
|
+
:GOTO_SCOPE /#{CLOSE_GOTO_SCOPE}/ { @state = nil; [:tCLOSE_GOTO_SCOPE, text] }
|
43
49
|
:KEY /\s+/
|
44
|
-
:KEY
|
45
|
-
:KEY
|
46
|
-
:KEY
|
47
|
-
:KEY
|
48
|
-
:KEY
|
49
|
-
:KEY
|
50
|
-
:KEY
|
51
|
-
:KEY
|
52
|
-
:KEY
|
53
|
-
:KEY
|
54
|
-
:KEY
|
50
|
+
:KEY /\^=/ { @state = :VALUE; [:tOPERATOR, '^='] }
|
51
|
+
:KEY /\$=/ { @state = :VALUE; [:tOPERATOR, '$='] }
|
52
|
+
:KEY /\*=/ { @state = :VALUE; [:tOPERATOR, '*='] }
|
53
|
+
:KEY /!=/ { @state = :VALUE; [:tOPERATOR, '!='] }
|
54
|
+
:KEY /=~/ { @state = :VALUE; [:tOPERATOR, '=~'] }
|
55
|
+
:KEY /!~/ { @state = :VALUE; [:tOPERATOR, '!~'] }
|
56
|
+
:KEY />=/ { @state = :VALUE; [:tOPERATOR, '>='] }
|
57
|
+
:KEY /<=/ { @state = :VALUE; [:tOPERATOR, '<='] }
|
58
|
+
:KEY />/ { @state = :VALUE; [:tOPERATOR, '>'] }
|
59
|
+
:KEY /</ { @state = :VALUE; [:tOPERATOR, '<'] }
|
60
|
+
:KEY /=/ { @state = :VALUE; [:tOPERATOR, '=='] }
|
61
|
+
:KEY /includes/i { @state = :VALUE; [:tOPERATOR, 'includes'] }
|
62
|
+
:KEY /not in/i { @state = :VALUE; [:tOPERATOR, 'not_in'] }
|
63
|
+
:KEY /in/i { @state = :VALUE; [:tOPERATOR, 'in'] }
|
55
64
|
:KEY /#{IDENTIFIER}/ { [:tKEY, text] }
|
56
65
|
:VALUE /\s+/
|
57
66
|
:VALUE /\[\]=/ { [:tIDENTIFIER_VALUE, text] }
|
@@ -61,6 +70,7 @@ rules
|
|
61
70
|
:VALUE /#{OPEN_DYNAMIC_ATTRIBUTE}/ { @state = :DYNAMIC_ATTRIBUTE; [:tOPEN_DYNAMIC_ATTRIBUTE, text] }
|
62
71
|
:VALUE /#{OPEN_ARRAY}/ { @state = :ARRAY_VALUE; [:tOPEN_ARRAY, text] }
|
63
72
|
:VALUE /#{CLOSE_ATTRIBUTE}/ { @nested_count -= 1; @state = @nested_count == 0 ? nil : :VALUE; [:tCLOSE_ATTRIBUTE, text] }
|
73
|
+
:VALUE /#{NIL}\?/ { [:tIDENTIFIER_VALUE, text] }
|
64
74
|
:VALUE /#{NIL}/ { [:tNIL, nil] }
|
65
75
|
:VALUE /#{TRUE}/ { [:tBOOLEAN, true] }
|
66
76
|
:VALUE /#{FALSE}/ { [:tBOOLEAN, false] }
|
@@ -76,8 +86,8 @@ rules
|
|
76
86
|
:DYNAMIC_ATTRIBUTE /#{CLOSE_DYNAMIC_ATTRIBUTE}/ { @state = :VALUE; [:tCLOSE_DYNAMIC_ATTRIBUTE, text] }
|
77
87
|
:DYNAMIC_ATTRIBUTE /#{IDENTIFIER}/ { [:tDYNAMIC_ATTRIBUTE, text] }
|
78
88
|
:ARRAY_VALUE /\s+/
|
79
|
-
:ARRAY_VALUE /,/ { [:tCOMMA, text] }
|
80
89
|
:ARRAY_VALUE /#{CLOSE_ARRAY}/ { @state = :VALUE; [:tCLOSE_ARRAY, text] }
|
90
|
+
:ARRAY_VALUE /#{NIL}\?/ { [:tIDENTIFIER_VALUE, text] }
|
81
91
|
:ARRAY_VALUE /#{NIL}/ { [:tNIL, nil] }
|
82
92
|
:ARRAY_VALUE /#{TRUE}/ { [:tBOOLEAN, true] }
|
83
93
|
:ARRAY_VALUE /#{FALSE}/ { [:tBOOLEAN, false] }
|
@@ -20,6 +20,8 @@ class Synvert::Core::NodeQuery::Lexer
|
|
20
20
|
CLOSE_ARRAY = /\)/
|
21
21
|
OPEN_SELECTOR = /\(/
|
22
22
|
CLOSE_SELECTOR = /\)/
|
23
|
+
OPEN_GOTO_SCOPE = /</
|
24
|
+
CLOSE_GOTO_SCOPE = />/
|
23
25
|
OPEN_DYNAMIC_ATTRIBUTE = /{{/
|
24
26
|
CLOSE_DYNAMIC_ATTRIBUTE = /}}/
|
25
27
|
NODE_TYPE = /\.[a-z]+/
|
@@ -33,8 +35,8 @@ class Synvert::Core::NodeQuery::Lexer
|
|
33
35
|
REGEXP = /\/(#{REGEXP_BODY})(?<!\\)\/([imxo]*)/
|
34
36
|
SYMBOL = /:[\w!\?<>=]+/
|
35
37
|
TRUE = /true/
|
36
|
-
SINGLE_QUOTE_STRING = /'
|
37
|
-
DOUBLE_QUOTE_STRING = /"
|
38
|
+
SINGLE_QUOTE_STRING = /'.*?'/
|
39
|
+
DOUBLE_QUOTE_STRING = /".*?"/
|
38
40
|
# :startdoc:
|
39
41
|
# :stopdoc:
|
40
42
|
class LexerError < StandardError ; end
|
@@ -140,47 +142,67 @@ class Synvert::Core::NodeQuery::Lexer
|
|
140
142
|
when text = ss.scan(/#{NODE_TYPE}/) then
|
141
143
|
action { [:tNODE_TYPE, text[1..]] }
|
142
144
|
when text = ss.scan(/>/) then
|
143
|
-
action { [:
|
145
|
+
action { [:tRELATIONSHIP, text] }
|
144
146
|
when text = ss.scan(/~/) then
|
145
|
-
action { [:
|
147
|
+
action { [:tRELATIONSHIP, text] }
|
146
148
|
when text = ss.scan(/\+/) then
|
147
|
-
action { [:
|
149
|
+
action { [:tRELATIONSHIP, text] }
|
148
150
|
when text = ss.scan(/#{OPEN_SELECTOR}/) then
|
149
151
|
action { [:tOPEN_SELECTOR, text] }
|
150
152
|
when text = ss.scan(/#{CLOSE_SELECTOR}/) then
|
151
153
|
action { [:tCLOSE_SELECTOR, text] }
|
154
|
+
when text = ss.scan(/#{OPEN_GOTO_SCOPE}/) then
|
155
|
+
action { @state = :GOTO_SCOPE; [:tOPEN_GOTO_SCOPE, text] }
|
152
156
|
when text = ss.scan(/#{OPEN_ATTRIBUTE}/) then
|
153
157
|
action { @nested_count += 1; @state = :KEY; [:tOPEN_ATTRIBUTE, text] }
|
154
158
|
else
|
155
159
|
text = ss.string[ss.pos .. -1]
|
156
160
|
raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
|
157
161
|
end
|
162
|
+
when :GOTO_SCOPE then
|
163
|
+
case
|
164
|
+
when ss.skip(/\s+/) then
|
165
|
+
# do nothing
|
166
|
+
when text = ss.scan(/#{IDENTIFIER}/) then
|
167
|
+
action { [:tIDENTIFIER, text] }
|
168
|
+
when text = ss.scan(/#{CLOSE_GOTO_SCOPE}/) then
|
169
|
+
action { @state = nil; [:tCLOSE_GOTO_SCOPE, text] }
|
170
|
+
else
|
171
|
+
text = ss.string[ss.pos .. -1]
|
172
|
+
raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
|
173
|
+
end
|
158
174
|
when :KEY then
|
159
175
|
case
|
160
176
|
when ss.skip(/\s+/) then
|
161
177
|
# do nothing
|
162
|
-
when
|
163
|
-
action { @state = :VALUE; [:
|
164
|
-
when
|
165
|
-
action { @state = :VALUE; [:
|
166
|
-
when
|
167
|
-
action { @state = :VALUE; [:
|
168
|
-
when
|
169
|
-
action { @state = :VALUE; [:
|
170
|
-
when
|
171
|
-
action { @state = :VALUE; [:
|
172
|
-
when
|
173
|
-
action { @state = :VALUE; [:
|
174
|
-
when
|
175
|
-
action { @state = :VALUE; [:
|
176
|
-
when
|
177
|
-
action { @state = :VALUE; [:
|
178
|
-
when
|
179
|
-
action { @state = :VALUE; [:
|
180
|
-
when
|
181
|
-
action { @state = :VALUE; [:
|
182
|
-
when
|
183
|
-
action { @state = :VALUE; [:
|
178
|
+
when ss.skip(/\^=/) then
|
179
|
+
action { @state = :VALUE; [:tOPERATOR, '^='] }
|
180
|
+
when ss.skip(/\$=/) then
|
181
|
+
action { @state = :VALUE; [:tOPERATOR, '$='] }
|
182
|
+
when ss.skip(/\*=/) then
|
183
|
+
action { @state = :VALUE; [:tOPERATOR, '*='] }
|
184
|
+
when ss.skip(/!=/) then
|
185
|
+
action { @state = :VALUE; [:tOPERATOR, '!='] }
|
186
|
+
when ss.skip(/=~/) then
|
187
|
+
action { @state = :VALUE; [:tOPERATOR, '=~'] }
|
188
|
+
when ss.skip(/!~/) then
|
189
|
+
action { @state = :VALUE; [:tOPERATOR, '!~'] }
|
190
|
+
when ss.skip(/>=/) then
|
191
|
+
action { @state = :VALUE; [:tOPERATOR, '>='] }
|
192
|
+
when ss.skip(/<=/) then
|
193
|
+
action { @state = :VALUE; [:tOPERATOR, '<='] }
|
194
|
+
when ss.skip(/>/) then
|
195
|
+
action { @state = :VALUE; [:tOPERATOR, '>'] }
|
196
|
+
when ss.skip(/</) then
|
197
|
+
action { @state = :VALUE; [:tOPERATOR, '<'] }
|
198
|
+
when ss.skip(/=/) then
|
199
|
+
action { @state = :VALUE; [:tOPERATOR, '=='] }
|
200
|
+
when ss.skip(/includes/i) then
|
201
|
+
action { @state = :VALUE; [:tOPERATOR, 'includes'] }
|
202
|
+
when ss.skip(/not in/i) then
|
203
|
+
action { @state = :VALUE; [:tOPERATOR, 'not_in'] }
|
204
|
+
when ss.skip(/in/i) then
|
205
|
+
action { @state = :VALUE; [:tOPERATOR, 'in'] }
|
184
206
|
when text = ss.scan(/#{IDENTIFIER}/) then
|
185
207
|
action { [:tKEY, text] }
|
186
208
|
else
|
@@ -205,6 +227,8 @@ class Synvert::Core::NodeQuery::Lexer
|
|
205
227
|
action { @state = :ARRAY_VALUE; [:tOPEN_ARRAY, text] }
|
206
228
|
when text = ss.scan(/#{CLOSE_ATTRIBUTE}/) then
|
207
229
|
action { @nested_count -= 1; @state = @nested_count == 0 ? nil : :VALUE; [:tCLOSE_ATTRIBUTE, text] }
|
230
|
+
when text = ss.scan(/#{NIL}\?/) then
|
231
|
+
action { [:tIDENTIFIER_VALUE, text] }
|
208
232
|
when ss.skip(/#{NIL}/) then
|
209
233
|
action { [:tNIL, nil] }
|
210
234
|
when ss.skip(/#{TRUE}/) then
|
@@ -247,10 +271,10 @@ class Synvert::Core::NodeQuery::Lexer
|
|
247
271
|
case
|
248
272
|
when ss.skip(/\s+/) then
|
249
273
|
# do nothing
|
250
|
-
when text = ss.scan(/,/) then
|
251
|
-
action { [:tCOMMA, text] }
|
252
274
|
when text = ss.scan(/#{CLOSE_ARRAY}/) then
|
253
275
|
action { @state = :VALUE; [:tCLOSE_ARRAY, text] }
|
276
|
+
when text = ss.scan(/#{NIL}\?/) then
|
277
|
+
action { [:tIDENTIFIER_VALUE, text] }
|
254
278
|
when ss.skip(/#{NIL}/) then
|
255
279
|
action { [:tNIL, nil] }
|
256
280
|
when ss.skip(/#{TRUE}/) then
|