synvert-core 1.2.1 → 1.4.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 +16 -0
- data/Gemfile +9 -0
- data/lib/synvert/core/node_query/compiler/attribute.rb +6 -18
- data/lib/synvert/core/node_query/compiler/basic_selector.rb +28 -0
- data/lib/synvert/core/node_query/compiler/comparable.rb +26 -19
- data/lib/synvert/core/node_query/compiler/expression.rb +8 -93
- 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 +91 -34
- 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 +20 -26
- data/lib/synvert/core/node_query/lexer.rex.rb +35 -51
- data/lib/synvert/core/node_query/parser.racc.rb +115 -293
- data/lib/synvert/core/node_query/parser.y +16 -35
- data/lib/synvert/core/node_query.rb +3 -4
- data/lib/synvert/core/rewriter/action/delete_action.rb +4 -2
- data/lib/synvert/core/rewriter/action/remove_action.rb +5 -2
- data/lib/synvert/core/rewriter/instance.rb +8 -4
- data/lib/synvert/core/version.rb +1 -1
- data/spec/synvert/core/node_query/lexer_spec.rb +46 -106
- data/spec/synvert/core/node_query/parser_spec.rb +116 -129
- data/spec/synvert/core/rewriter/instance_spec.rb +12 -7
- data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +9 -2
- data/synvert-core-ruby.gemspec +0 -10
- metadata +3 -128
@@ -20,8 +20,6 @@ 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 = />/
|
25
23
|
OPEN_DYNAMIC_ATTRIBUTE = /{{/
|
26
24
|
CLOSE_DYNAMIC_ATTRIBUTE = /}}/
|
27
25
|
NODE_TYPE = /\.[a-z]+/
|
@@ -35,8 +33,8 @@ class Synvert::Core::NodeQuery::Lexer
|
|
35
33
|
REGEXP = /\/(#{REGEXP_BODY})(?<!\\)\/([imxo]*)/
|
36
34
|
SYMBOL = /:[\w!\?<>=]+/
|
37
35
|
TRUE = /true/
|
38
|
-
SINGLE_QUOTE_STRING = /'
|
39
|
-
DOUBLE_QUOTE_STRING = /"
|
36
|
+
SINGLE_QUOTE_STRING = /'.*?'/
|
37
|
+
DOUBLE_QUOTE_STRING = /".*?"/
|
40
38
|
# :startdoc:
|
41
39
|
# :stopdoc:
|
42
40
|
class LexerError < StandardError ; end
|
@@ -127,76 +125,62 @@ class Synvert::Core::NodeQuery::Lexer
|
|
127
125
|
case
|
128
126
|
when ss.skip(/\s+/) then
|
129
127
|
# do nothing
|
130
|
-
when ss.skip(/:first-child/) then
|
131
|
-
action { [:tINDEX, 0] }
|
132
|
-
when ss.skip(/:last-child/) then
|
133
|
-
action { [:tINDEX, -1] }
|
134
|
-
when text = ss.scan(/:nth-child\(\d+\)/) then
|
135
|
-
action { [:tINDEX, text.sub(':nth-child(', '').to_i - 1] }
|
136
|
-
when text = ss.scan(/:nth-last-child\(\d+\)/) then
|
137
|
-
action { [:tINDEX, -text.sub(':nth-last-child(', '').to_i] }
|
138
128
|
when text = ss.scan(/:has/) then
|
139
129
|
action { [:tPSEUDO_CLASS, text[1..-1]] }
|
140
130
|
when text = ss.scan(/:not_has/) then
|
141
131
|
action { [:tPSEUDO_CLASS, text[1..-1]] }
|
142
132
|
when text = ss.scan(/#{NODE_TYPE}/) then
|
143
133
|
action { [:tNODE_TYPE, text[1..]] }
|
134
|
+
when text = ss.scan(/#{IDENTIFIER}/) then
|
135
|
+
action { [:tGOTO_SCOPE, text] }
|
144
136
|
when text = ss.scan(/>/) then
|
145
|
-
action { [:
|
137
|
+
action { [:tRELATIONSHIP, text] }
|
146
138
|
when text = ss.scan(/~/) then
|
147
|
-
action { [:
|
139
|
+
action { [:tRELATIONSHIP, text] }
|
148
140
|
when text = ss.scan(/\+/) then
|
149
|
-
action { [:
|
141
|
+
action { [:tRELATIONSHIP, text] }
|
150
142
|
when text = ss.scan(/#{OPEN_SELECTOR}/) then
|
151
143
|
action { [:tOPEN_SELECTOR, text] }
|
152
144
|
when text = ss.scan(/#{CLOSE_SELECTOR}/) then
|
153
145
|
action { [:tCLOSE_SELECTOR, text] }
|
154
|
-
when text = ss.scan(/#{OPEN_GOTO_SCOPE}/) then
|
155
|
-
action { @state = :GOTO_SCOPE; [:tOPEN_GOTO_SCOPE, text] }
|
156
146
|
when text = ss.scan(/#{OPEN_ATTRIBUTE}/) then
|
157
147
|
action { @nested_count += 1; @state = :KEY; [:tOPEN_ATTRIBUTE, text] }
|
158
148
|
else
|
159
149
|
text = ss.string[ss.pos .. -1]
|
160
150
|
raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
|
161
151
|
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
|
174
152
|
when :KEY then
|
175
153
|
case
|
176
154
|
when ss.skip(/\s+/) then
|
177
155
|
# do nothing
|
178
|
-
when
|
179
|
-
action { @state = :VALUE; [:
|
180
|
-
when
|
181
|
-
action { @state = :VALUE; [:
|
182
|
-
when
|
183
|
-
action { @state = :VALUE; [:
|
184
|
-
when
|
185
|
-
action { @state = :VALUE; [:
|
186
|
-
when
|
187
|
-
action { @state = :VALUE; [:
|
188
|
-
when
|
189
|
-
action { @state = :VALUE; [:
|
190
|
-
when
|
191
|
-
action { @state = :VALUE; [:
|
192
|
-
when
|
193
|
-
action { @state = :VALUE; [:
|
194
|
-
when
|
195
|
-
action { @state = :VALUE; [:
|
196
|
-
when
|
197
|
-
action { @state = :VALUE; [:
|
198
|
-
when
|
199
|
-
action { @state = :VALUE; [:
|
156
|
+
when ss.skip(/\^=/) then
|
157
|
+
action { @state = :VALUE; [:tOPERATOR, '^='] }
|
158
|
+
when ss.skip(/\$=/) then
|
159
|
+
action { @state = :VALUE; [:tOPERATOR, '$='] }
|
160
|
+
when ss.skip(/\*=/) then
|
161
|
+
action { @state = :VALUE; [:tOPERATOR, '*='] }
|
162
|
+
when ss.skip(/!=/) then
|
163
|
+
action { @state = :VALUE; [:tOPERATOR, '!='] }
|
164
|
+
when ss.skip(/=~/) then
|
165
|
+
action { @state = :VALUE; [:tOPERATOR, '=~'] }
|
166
|
+
when ss.skip(/!~/) then
|
167
|
+
action { @state = :VALUE; [:tOPERATOR, '!~'] }
|
168
|
+
when ss.skip(/>=/) then
|
169
|
+
action { @state = :VALUE; [:tOPERATOR, '>='] }
|
170
|
+
when ss.skip(/<=/) then
|
171
|
+
action { @state = :VALUE; [:tOPERATOR, '<='] }
|
172
|
+
when ss.skip(/>/) then
|
173
|
+
action { @state = :VALUE; [:tOPERATOR, '>'] }
|
174
|
+
when ss.skip(/</) then
|
175
|
+
action { @state = :VALUE; [:tOPERATOR, '<'] }
|
176
|
+
when ss.skip(/=/) then
|
177
|
+
action { @state = :VALUE; [:tOPERATOR, '=='] }
|
178
|
+
when ss.skip(/includes/i) then
|
179
|
+
action { @state = :VALUE; [:tOPERATOR, 'includes'] }
|
180
|
+
when ss.skip(/not in/i) then
|
181
|
+
action { @state = :VALUE; [:tOPERATOR, 'not_in'] }
|
182
|
+
when ss.skip(/in/i) then
|
183
|
+
action { @state = :VALUE; [:tOPERATOR, 'in'] }
|
200
184
|
when text = ss.scan(/#{IDENTIFIER}/) then
|
201
185
|
action { [:tKEY, text] }
|
202
186
|
else
|