synvert-core 1.1.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|