rubyjedi-oga 1.0.3

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +13 -0
  3. data/LICENSE +362 -0
  4. data/README.md +317 -0
  5. data/doc/css/common.css +77 -0
  6. data/doc/css_selectors.md +935 -0
  7. data/doc/manually_creating_documents.md +67 -0
  8. data/doc/migrating_from_nokogiri.md +169 -0
  9. data/doc/xml_namespaces.md +63 -0
  10. data/ext/c/extconf.rb +11 -0
  11. data/ext/c/lexer.c +2595 -0
  12. data/ext/c/lexer.h +16 -0
  13. data/ext/c/lexer.rl +198 -0
  14. data/ext/c/liboga.c +6 -0
  15. data/ext/c/liboga.h +11 -0
  16. data/ext/java/Liboga.java +14 -0
  17. data/ext/java/org/liboga/xml/Lexer.java +1363 -0
  18. data/ext/java/org/liboga/xml/Lexer.rl +223 -0
  19. data/ext/ragel/base_lexer.rl +633 -0
  20. data/lib/oga.rb +57 -0
  21. data/lib/oga/blacklist.rb +40 -0
  22. data/lib/oga/css/lexer.rb +743 -0
  23. data/lib/oga/css/parser.rb +976 -0
  24. data/lib/oga/entity_decoder.rb +21 -0
  25. data/lib/oga/html/entities.rb +2150 -0
  26. data/lib/oga/html/parser.rb +25 -0
  27. data/lib/oga/html/sax_parser.rb +18 -0
  28. data/lib/oga/lru.rb +160 -0
  29. data/lib/oga/oga.rb +57 -0
  30. data/lib/oga/version.rb +3 -0
  31. data/lib/oga/whitelist.rb +20 -0
  32. data/lib/oga/xml/attribute.rb +136 -0
  33. data/lib/oga/xml/cdata.rb +17 -0
  34. data/lib/oga/xml/character_node.rb +37 -0
  35. data/lib/oga/xml/comment.rb +17 -0
  36. data/lib/oga/xml/default_namespace.rb +13 -0
  37. data/lib/oga/xml/doctype.rb +82 -0
  38. data/lib/oga/xml/document.rb +108 -0
  39. data/lib/oga/xml/element.rb +428 -0
  40. data/lib/oga/xml/entities.rb +122 -0
  41. data/lib/oga/xml/html_void_elements.rb +15 -0
  42. data/lib/oga/xml/lexer.rb +550 -0
  43. data/lib/oga/xml/namespace.rb +48 -0
  44. data/lib/oga/xml/node.rb +219 -0
  45. data/lib/oga/xml/node_set.rb +333 -0
  46. data/lib/oga/xml/parser.rb +631 -0
  47. data/lib/oga/xml/processing_instruction.rb +37 -0
  48. data/lib/oga/xml/pull_parser.rb +175 -0
  49. data/lib/oga/xml/querying.rb +56 -0
  50. data/lib/oga/xml/sax_parser.rb +192 -0
  51. data/lib/oga/xml/text.rb +66 -0
  52. data/lib/oga/xml/traversal.rb +50 -0
  53. data/lib/oga/xml/xml_declaration.rb +65 -0
  54. data/lib/oga/xpath/evaluator.rb +1798 -0
  55. data/lib/oga/xpath/lexer.rb +1958 -0
  56. data/lib/oga/xpath/parser.rb +622 -0
  57. data/oga.gemspec +45 -0
  58. metadata +227 -0
@@ -0,0 +1,976 @@
1
+ # This file is automatically generated by ruby-ll. Manually changing this file
2
+ # is not recommended as any changes will be lost the next time this parser is
3
+ # re-generated.
4
+ require 'll/setup'
5
+
6
+ module Oga
7
+ module CSS
8
+ ##
9
+ # AST parser for CSS expressions.
10
+ #
11
+ # This parser does _not_ build a CSS specific AST, instead it directly produces
12
+ # an XPath AST. This removes the need to transform the AST or generate
13
+ # corresponding XPath expressions as a String.
14
+ #
15
+ # Similar to {Oga::XPath::Parser} this parser only takes String instances as
16
+ # input.
17
+ #
18
+ # @api private
19
+ #
20
+ class Parser < LL::Driver
21
+ CONFIG = LL::DriverConfig.new
22
+
23
+ CONFIG.terminals = [
24
+ :$EOF, # 0
25
+ :T_IDENT, # 1
26
+ :T_PIPE, # 2
27
+ :T_LBRACK, # 3
28
+ :T_RBRACK, # 4
29
+ :T_COLON, # 5
30
+ :T_SPACE, # 6
31
+ :T_LPAREN, # 7
32
+ :T_RPAREN, # 8
33
+ :T_MINUS, # 9
34
+ :T_EQ, # 10
35
+ :T_SPACE_IN, # 11
36
+ :T_STARTS_WITH, # 12
37
+ :T_ENDS_WITH, # 13
38
+ :T_IN, # 14
39
+ :T_HYPHEN_IN, # 15
40
+ :T_GREATER, # 16
41
+ :T_TILDE, # 17
42
+ :T_PLUS, # 18
43
+ :T_NTH, # 19
44
+ :T_INT, # 20
45
+ :T_STRING, # 21
46
+ :T_ODD, # 22
47
+ :T_EVEN, # 23
48
+ :T_DOT, # 24
49
+ :T_HASH, # 25
50
+ ].freeze
51
+
52
+ CONFIG.rules = [
53
+ [3, 0, 0, 1], # 0
54
+ [3, 1, 2, 0], # 1
55
+ [3, 2, 4, 29, 6, 0, 0, 3], # 2
56
+ [3, 3, 0, 3, 1, 6], # 3
57
+ [3, 4, 8, 30, 0, 4], # 4
58
+ [3, 5, 8, 31, 0, 5], # 5
59
+ [3, 6, 0, 10], # 6
60
+ [3, 7, 0, 7], # 7
61
+ [3, 8, 0, 6, 1, 16], # 8
62
+ [3, 9, 0, 6, 1, 17], # 9
63
+ [3, 10, 0, 6, 1, 18], # 10
64
+ [3, 11, 0, 7], # 11
65
+ [3, 12, 0, 5], # 12
66
+ [3, 13, 0, 8], # 13
67
+ [3, 14, 8, 32, 1, 1], # 14
68
+ [3, 15, 1, 1, 1, 2], # 15
69
+ [3, 16, 4, 33, 6, 0, 0, 11], # 16
70
+ [3, 17, 0, 17], # 17
71
+ [3, 18, 0, 18], # 18
72
+ [3, 19, 0, 19], # 19
73
+ [3, 20, 0, 12], # 20
74
+ [3, 21, 1, 4, 0, 13, 1, 3], # 21
75
+ [3, 22, 0, 15], # 22
76
+ [3, 23, 0, 8], # 23
77
+ [3, 24, 8, 34, 0, 14], # 24
78
+ [3, 25, 1, 10], # 25
79
+ [3, 26, 1, 11], # 26
80
+ [3, 27, 1, 12], # 27
81
+ [3, 28, 1, 13], # 28
82
+ [3, 29, 1, 14], # 29
83
+ [3, 30, 1, 15], # 30
84
+ [3, 31, 1, 1, 1, 24], # 31
85
+ [3, 32, 1, 1, 1, 25], # 32
86
+ [3, 33, 8, 35, 0, 20], # 33
87
+ [3, 34, 1, 1, 1, 5], # 34
88
+ [3, 35, 1, 8, 0, 22, 1, 7], # 35
89
+ [3, 36, 0, 27], # 36
90
+ [3, 37, 0, 28], # 37
91
+ [3, 38, 0, 25], # 38
92
+ [3, 39, 0, 3], # 39
93
+ [3, 40, 1, 21], # 40
94
+ [3, 41, 1, 20], # 41
95
+ [3, 42, 8, 36, 0, 26], # 42
96
+ [3, 43, 8, 37, 0, 26, 1, 9], # 43
97
+ [3, 44, 8, 39, 8, 38, 0, 24], # 44
98
+ [3, 45, 1, 19], # 45
99
+ [3, 46, 1, 22], # 46
100
+ [3, 47, 1, 23], # 47
101
+ [3, 48, 0, 2], # 48
102
+ [3, 49, 0, 10], # 49
103
+ [3, 50, 0, 10], # 50
104
+ [3, 51, 0, 9], # 51
105
+ [3, 52, 0, 11], # 52
106
+ [3, 53, 0, 23, 0, 16], # 53
107
+ [3, 54, 0, 21], # 54
108
+ [3, 55, 0, 24], # 55
109
+ [3, 56, 0, 24], # 56
110
+ [3, 57, 0, 26], # 57
111
+ [3, 58, 0, 24], # 58
112
+ ].freeze
113
+
114
+ CONFIG.table = [
115
+ [1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], # 0
116
+ [-1, 2, -1, 2, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, -1, -1, -1, -1, -1, 2, 2], # 1
117
+ [-1, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 2
118
+ [-1, 4, -1, 6, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, -1, -1, -1, -1, -1, 6, 6], # 3
119
+ [-1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 4
120
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1], # 5
121
+ [-1, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 12, 12, -1, -1, -1, -1, -1, -1, -1], # 6
122
+ [-1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 7
123
+ [-1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 8
124
+ [-1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 9
125
+ [-1, -1, -1, 16, -1, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, 16], # 10
126
+ [-1, -1, -1, 20, -1, 19, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18], # 11
127
+ [-1, -1, -1, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 12
128
+ [-1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 13
129
+ [-1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 14
130
+ [-1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 15
131
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 16
132
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, -1], # 17
133
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32], # 18
134
+ [-1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 19
135
+ [-1, -1, -1, -1, -1, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 20
136
+ [-1, -1, -1, -1, -1, -1, -1, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 21
137
+ [-1, 39, -1, 39, -1, 39, -1, -1, -1, 38, -1, -1, -1, -1, -1, -1, 39, 39, 39, 38, 38, -1, 36, 37, 39, 39], # 22
138
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1], # 23
139
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1], # 24
140
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, 44, -1, -1, -1, -1, -1], # 25
141
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1], # 26
142
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, -1], # 27
143
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1], # 28
144
+ [-1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 29
145
+ [-1, -1, -1, 49, -1, 49, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, 49], # 30
146
+ [-1, -1, -1, 50, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 50, 50], # 31
147
+ [-1, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 32
148
+ [-1, -1, -1, 52, -1, 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, 52], # 33
149
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, 53, 53, 53, 53, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 34
150
+ [-1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], # 35
151
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, -1], # 36
152
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 56, -1, -1, -1, -1, -1], # 37
153
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1], # 38
154
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, -1], # 39
155
+ ].freeze
156
+
157
+ CONFIG.actions = [
158
+ [:_rule_0, 1], # 0
159
+ [:_rule_1, 0], # 1
160
+ [:_rule_2, 2], # 2
161
+ [:_rule_3, 2], # 3
162
+ [:_rule_4, 2], # 4
163
+ [:_rule_5, 2], # 5
164
+ [:_rule_6, 1], # 6
165
+ [:_rule_7, 1], # 7
166
+ [:_rule_8, 2], # 8
167
+ [:_rule_9, 2], # 9
168
+ [:_rule_10, 2], # 10
169
+ [:_rule_11, 1], # 11
170
+ [:_rule_12, 1], # 12
171
+ [:_rule_13, 1], # 13
172
+ [:_rule_14, 2], # 14
173
+ [:_rule_15, 2], # 15
174
+ [:_rule_16, 2], # 16
175
+ [:_rule_17, 1], # 17
176
+ [:_rule_18, 1], # 18
177
+ [:_rule_19, 1], # 19
178
+ [:_rule_20, 1], # 20
179
+ [:_rule_21, 3], # 21
180
+ [:_rule_22, 1], # 22
181
+ [:_rule_23, 1], # 23
182
+ [:_rule_24, 2], # 24
183
+ [:_rule_25, 1], # 25
184
+ [:_rule_26, 1], # 26
185
+ [:_rule_27, 1], # 27
186
+ [:_rule_28, 1], # 28
187
+ [:_rule_29, 1], # 29
188
+ [:_rule_30, 1], # 30
189
+ [:_rule_31, 2], # 31
190
+ [:_rule_32, 2], # 32
191
+ [:_rule_33, 2], # 33
192
+ [:_rule_34, 2], # 34
193
+ [:_rule_35, 3], # 35
194
+ [:_rule_36, 1], # 36
195
+ [:_rule_37, 1], # 37
196
+ [:_rule_38, 1], # 38
197
+ [:_rule_39, 1], # 39
198
+ [:_rule_40, 1], # 40
199
+ [:_rule_41, 1], # 41
200
+ [:_rule_42, 2], # 42
201
+ [:_rule_43, 3], # 43
202
+ [:_rule_44, 3], # 44
203
+ [:_rule_45, 1], # 45
204
+ [:_rule_46, 1], # 46
205
+ [:_rule_47, 1], # 47
206
+ [:_rule_48, 1], # 48
207
+ [:_rule_49, 1], # 49
208
+ [:_rule_50, 1], # 50
209
+ [:_rule_51, 1], # 51
210
+ [:_rule_52, 1], # 52
211
+ [:_rule_53, 2], # 53
212
+ [:_rule_54, 1], # 54
213
+ [:_rule_55, 1], # 55
214
+ [:_rule_56, 1], # 56
215
+ [:_rule_57, 1], # 57
216
+ [:_rule_58, 1], # 58
217
+ ].freeze
218
+
219
+ ##
220
+ # @return [Oga::LRU]
221
+ #
222
+ CACHE = LRU.new
223
+
224
+ ##
225
+ # @param [String] data
226
+ # @return [AST::Node]
227
+ #
228
+ def self.parse_with_cache(data)
229
+ return CACHE.get_or_set(data) { new(data).parse }
230
+ end
231
+
232
+ ##
233
+ # @param [String] data The input to parse.
234
+ #
235
+ def initialize(data)
236
+ @lexer = Lexer.new(data)
237
+ end
238
+
239
+ ##
240
+ # Resets the internal state of the parser.
241
+ #
242
+ def reset
243
+ @current_element = nil
244
+ end
245
+
246
+ ##
247
+ # @param [Symbol] type
248
+ # @param [Array] children
249
+ # @return [AST::Node]
250
+ #
251
+ def s(type, *children)
252
+ return AST::Node.new(type, children)
253
+ end
254
+
255
+ ##
256
+ # Yields the next token from the lexer.
257
+ #
258
+ # @yieldparam [Array]
259
+ #
260
+ def each_token
261
+ @lexer.advance do |*args|
262
+ yield args
263
+ end
264
+
265
+ yield [-1, -1]
266
+ end
267
+
268
+ ##
269
+ # Returns the node test for the current element.
270
+ #
271
+ # @return [AST::Node]
272
+ #
273
+ def current_element
274
+ @current_element ||= s(:test, nil, '*')
275
+ end
276
+
277
+ ##
278
+ # Parses the input and returns the corresponding AST.
279
+ #
280
+ # @example
281
+ # parser = Oga::CSS::Parser.new('foo.bar')
282
+ # ast = parser.parse
283
+ #
284
+ # @return [AST::Node]
285
+ #
286
+ def parse
287
+ reset
288
+
289
+ super
290
+ end
291
+
292
+ ##
293
+ # Generates the AST for a node test.
294
+ #
295
+ # @param [String] namespace
296
+ # @param [String] name
297
+ # @return [AST::Node]
298
+ #
299
+ def on_test(namespace, name)
300
+ @current_element = s(:test, namespace, name)
301
+ end
302
+
303
+ ##
304
+ # @param [String] name
305
+ # @param [AST::Node] arg
306
+ # @return [AST::Node]
307
+ #
308
+ def on_pseudo_class(name, arg = nil)
309
+ handler = "on_pseudo_class_#{name.gsub('-', '_')}"
310
+
311
+ arg ? send(handler, arg) : send(handler)
312
+ end
313
+
314
+ ##
315
+ # Generates the AST for the `root` pseudo class.
316
+ #
317
+ # @return [AST::Node]
318
+ #
319
+ def on_pseudo_class_root
320
+ s(:call, 'not', s(:axis, 'parent', s(:test, nil, '*')))
321
+ end
322
+
323
+ ##
324
+ # Generates the AST for the `nth-child` pseudo class.
325
+ #
326
+ # @param [AST::Node] arg
327
+ # @return [AST::Node]
328
+ #
329
+ def on_pseudo_class_nth_child(arg)
330
+ generate_nth_child('preceding-sibling', arg)
331
+ end
332
+
333
+ ##
334
+ # Generates the AST for the `nth-last-child` pseudo class.
335
+ #
336
+ # @param [AST::Node] arg
337
+ # @return [AST::Node]
338
+ #
339
+ def on_pseudo_class_nth_last_child(arg)
340
+ generate_nth_child('following-sibling', arg)
341
+ end
342
+
343
+ ##
344
+ # Generates the AST for the `nth-of-type` pseudo class.
345
+ #
346
+ # @param [AST::Node] arg
347
+ # @return [AST::Node]
348
+ #
349
+ def on_pseudo_class_nth_of_type(arg)
350
+ generate_nth_child('preceding-sibling', arg, current_element)
351
+ end
352
+
353
+ ##
354
+ # Generates the AST for the `nth-last-of-type` pseudo class.
355
+ #
356
+ # @param [AST::Node] arg
357
+ # @return [AST::Node]
358
+ #
359
+ def on_pseudo_class_nth_last_of_type(arg)
360
+ generate_nth_child('following-sibling', arg, current_element)
361
+ end
362
+
363
+ ##
364
+ # Generates the AST for the `:first-child` selector.
365
+ #
366
+ # @return [AST::Node]
367
+ #
368
+ def on_pseudo_class_first_child
369
+ generate_no_siblings('preceding-sibling')
370
+ end
371
+
372
+ ##
373
+ # Generates the AST for the `:last-child` selector.
374
+ #
375
+ # @return [AST::Node]
376
+ #
377
+ def on_pseudo_class_last_child
378
+ generate_no_siblings('following-sibling')
379
+ end
380
+
381
+ ##
382
+ # Generates the AST for the `:first-of-type` selector.
383
+ #
384
+ # @return [AST::Node]
385
+ #
386
+ def on_pseudo_class_first_of_type
387
+ generate_no_siblings('preceding-sibling', current_element)
388
+ end
389
+
390
+ ##
391
+ # Generates the AST for the `:last-of-type` selector.
392
+ #
393
+ # @return [AST::Node]
394
+ #
395
+ def on_pseudo_class_last_of_type
396
+ generate_no_siblings('following-sibling', current_element)
397
+ end
398
+
399
+ ##
400
+ # Generates the AST for the `:only-child` selector.
401
+ #
402
+ # @return [AST::Node]
403
+ #
404
+ def on_pseudo_class_only_child
405
+ s(:and, on_pseudo_class_first_child, on_pseudo_class_last_child)
406
+ end
407
+
408
+ ##
409
+ # Generates the AST for the `:only-of-type` selector.
410
+ #
411
+ # @return [AST::Node]
412
+ #
413
+ def on_pseudo_class_only_of_type
414
+ s(:and, on_pseudo_class_first_of_type, on_pseudo_class_last_of_type)
415
+ end
416
+
417
+ ##
418
+ # Generates the AST for the `:empty` selector.
419
+ #
420
+ # @return [AST::Node]
421
+ #
422
+ def on_pseudo_class_empty
423
+ s(:call, 'not', s(:axis, 'child', s(:type_test, 'node')))
424
+ end
425
+
426
+ ##
427
+ # Generates the AST for the `=` operator.
428
+ #
429
+ # @param [AST::Node] attr
430
+ # @param [AST::Node] value
431
+ # @return [AST::Node]
432
+ #
433
+ def on_op_eq(attr, value)
434
+ s(:eq, attr, value)
435
+ end
436
+
437
+ ##
438
+ # Generates the AST for the `~=` operator.
439
+ #
440
+ # @param [AST::Node] attr
441
+ # @param [AST::Node] value
442
+ # @return [AST::Node]
443
+ #
444
+ def on_op_space_in(attr, value)
445
+ s(
446
+ :call,
447
+ 'contains',
448
+ s(:call, 'concat', s(:string, ' '), attr, s(:string, ' ')),
449
+ s(:call, 'concat', s(:string, ' '), value, s(:string, ' '))
450
+ )
451
+ end
452
+
453
+ ##
454
+ # Generates the AST for the `^=` operator.
455
+ #
456
+ # @param [AST::Node] attr
457
+ # @param [AST::Node] value
458
+ # @return [AST::Node]
459
+ #
460
+ def on_op_starts_with(attr, value)
461
+ s(:call, 'starts-with', attr, value)
462
+ end
463
+
464
+ ##
465
+ # Generates the AST for the `$=` operator.
466
+ #
467
+ # @param [AST::Node] attr
468
+ # @param [AST::Node] value
469
+ # @return [AST::Node]
470
+ #
471
+ def on_op_ends_with(attr, value)
472
+ s(
473
+ :eq,
474
+ s(
475
+ :call,
476
+ 'substring',
477
+ attr,
478
+ s(
479
+ :add,
480
+ s(
481
+ :sub,
482
+ s(:call, 'string-length', attr),
483
+ s(:call, 'string-length', value)
484
+ ),
485
+ s(:int, 1)
486
+ ),
487
+ s(:call, 'string-length', value)
488
+ ),
489
+ value
490
+ )
491
+ end
492
+
493
+ ##
494
+ # Generates the AST for the `*=` operator.
495
+ #
496
+ # @param [AST::Node] attr
497
+ # @param [AST::Node] value
498
+ # @return [AST::Node]
499
+ #
500
+ def on_op_in(attr, value)
501
+ s(:call, 'contains', attr, value)
502
+ end
503
+
504
+ ##
505
+ # Generates the AST for the `|=` operator.
506
+ #
507
+ # @param [AST::Node] attr
508
+ # @param [AST::Node] value
509
+ # @return [AST::Node]
510
+ #
511
+ def on_op_hyphen_in(attr, value)
512
+ s(
513
+ :or,
514
+ s(:eq, attr, value),
515
+ s(
516
+ :call,
517
+ 'starts-with',
518
+ attr,
519
+ s(:call, 'concat', value, s(:string, '-'))
520
+ )
521
+ )
522
+ end
523
+
524
+ private
525
+
526
+ ##
527
+ # @param [String] count_axis
528
+ # @param [AST::Node] arg
529
+ # @param [AST::Node] count_test
530
+ # @return [AST::Node]
531
+ #
532
+ def generate_nth_child(count_axis, arg, count_test = s(:test, nil, '*'))
533
+ count_call = s(:call, 'count', s(:axis, count_axis, count_test))
534
+
535
+ # literal 2, 4, etc
536
+ if int_node?(arg)
537
+ node = s(:eq, count_call, s(:int, arg.children[0] - 1))
538
+ else
539
+ step, offset = *arg
540
+ before_count = s(:add, count_call, s(:int, 1))
541
+ compare = step_comparison(step)
542
+
543
+ # 2n+2, 2n-4, etc
544
+ if offset
545
+ mod_val = step_modulo_value(step)
546
+ node = s(
547
+ :and,
548
+ s(compare, before_count, offset),
549
+ s(:eq, s(:mod, s(:sub, before_count, offset), mod_val), s(:int, 0))
550
+ )
551
+
552
+ # 2n, n, -2n
553
+ else
554
+ node = s(:eq, s(:mod, before_count, step), s(:int, 0))
555
+ end
556
+ end
557
+
558
+ return node
559
+ end
560
+
561
+ ##
562
+ # @param [String] axis
563
+ # @param [AST::Node] test
564
+ # @return [AST::Node]
565
+ #
566
+ def generate_no_siblings(axis, test = s(:test, nil, '*'))
567
+ s(:eq, s(:call, 'count', s(:axis, axis, test)), s(:int, 0))
568
+ end
569
+
570
+ ##
571
+ # @param [AST::Node] node
572
+ # @return [TrueClass|FalseClass]
573
+ #
574
+ def int_node?(node)
575
+ node.type.equal?(:int)
576
+ end
577
+
578
+ ##
579
+ # @param [AST::Node] node
580
+ # @return [TrueClass|FalseClass]
581
+ #
582
+ def non_positive_number?(node)
583
+ node.children[0] <= 0
584
+ end
585
+
586
+ ##
587
+ # @param [AST::Node] node
588
+ # @return [Symbol]
589
+ #
590
+ def step_comparison(node)
591
+ node.children[0] >= 0 ? :gte : :lte
592
+ end
593
+
594
+ ##
595
+ # @param [AST::Node] step
596
+ # @return [AST::Node]
597
+ #
598
+ def step_modulo_value(step)
599
+ # -2n
600
+ if step and non_positive_number?(step)
601
+ mod_val = s(:int, -step.children[0])
602
+
603
+ # 2n
604
+ elsif step
605
+ mod_val = step
606
+
607
+ else
608
+ mod_val = s(:int, 1)
609
+ end
610
+
611
+ mod_val
612
+ end
613
+
614
+ def _rule_0(val)
615
+ val[0]
616
+ end
617
+
618
+ def _rule_1(val)
619
+ nil
620
+ end
621
+
622
+ def _rule_2(val)
623
+
624
+ # Single selector
625
+ if val[1].empty?
626
+ ret = val[0]
627
+
628
+ if ret.is_a?(Array)
629
+ ret = s(:path, *ret)
630
+ end
631
+
632
+ # Multiple selectors
633
+ else
634
+ steps = [val[0]]
635
+
636
+ val[1].each do |step|
637
+ # "+ foo" is broken up into two steps.
638
+ if step.is_a?(Array)
639
+ # Using Array#+ or Array#| would require allocating an extra Array
640
+ step.each { |sub| steps << sub }
641
+ else
642
+ steps << step
643
+ end
644
+ end
645
+
646
+ ret = s(:path, *steps)
647
+ end
648
+
649
+ ret
650
+
651
+ end
652
+
653
+ def _rule_3(val)
654
+ val[1]
655
+ end
656
+
657
+ def _rule_4(val)
658
+
659
+ val[1] ? s(:predicate, val[0], val[1]) : val[0]
660
+
661
+ end
662
+
663
+ def _rule_5(val)
664
+
665
+ val[1] ? s(:predicate, val[0], val[1]) : val[0]
666
+
667
+ end
668
+
669
+ def _rule_6(val)
670
+
671
+ s(:predicate, s(:axis, 'descendant', on_test(nil, '*')), val[0])
672
+
673
+ end
674
+
675
+ def _rule_7(val)
676
+ s(:axis, 'descendant', val[0])
677
+ end
678
+
679
+ def _rule_8(val)
680
+
681
+ s(:axis, 'child', val[1])
682
+
683
+ end
684
+
685
+ def _rule_9(val)
686
+
687
+ s(:axis, 'following-sibling', val[1])
688
+
689
+ end
690
+
691
+ def _rule_10(val)
692
+
693
+ [
694
+ s(
695
+ :predicate,
696
+ s(:axis, 'following-sibling', on_test(nil, '*')),
697
+ s(:int, 1)
698
+ ),
699
+ s(:axis, 'self', val[1])
700
+ ]
701
+
702
+ end
703
+
704
+ def _rule_11(val)
705
+ val[0]
706
+ end
707
+
708
+ def _rule_12(val)
709
+ val[0]
710
+ end
711
+
712
+ def _rule_13(val)
713
+ on_test(*val[0])
714
+ end
715
+
716
+ def _rule_14(val)
717
+ val[1] ? [val[0], val[1]] : [nil, val[0]]
718
+ end
719
+
720
+ def _rule_15(val)
721
+ val[1]
722
+ end
723
+
724
+ def _rule_16(val)
725
+
726
+ ret = val[0]
727
+
728
+ val[1].each do |pred|
729
+ ret = s(:and, ret, pred)
730
+ end
731
+
732
+ ret
733
+
734
+ end
735
+
736
+ def _rule_17(val)
737
+ val[0]
738
+ end
739
+
740
+ def _rule_18(val)
741
+ val[0]
742
+ end
743
+
744
+ def _rule_19(val)
745
+ val[0]
746
+ end
747
+
748
+ def _rule_20(val)
749
+ val[0]
750
+ end
751
+
752
+ def _rule_21(val)
753
+ val[1]
754
+ end
755
+
756
+ def _rule_22(val)
757
+ val[0]
758
+ end
759
+
760
+ def _rule_23(val)
761
+ s(:axis, 'attribute', on_test(*val[0]))
762
+ end
763
+
764
+ def _rule_24(val)
765
+
766
+ op_type = val[1] ? val[1][0] : nil
767
+
768
+ case op_type
769
+ # a="b"
770
+ when :eq
771
+ on_op_eq(val[0], val[1][1])
772
+
773
+ # a~="b"
774
+ when :space_in
775
+ on_op_space_in(val[0], val[1][1])
776
+
777
+ # a^="b"
778
+ when :starts_with
779
+ on_op_starts_with(val[0], val[1][1])
780
+
781
+ # a$="b"
782
+ when :ends_with
783
+ on_op_ends_with(val[0], val[1][1])
784
+
785
+ # a*="b"
786
+ when :in
787
+ on_op_in(val[0], val[1][1])
788
+
789
+ # a|="b"
790
+ when :hyphen_in
791
+ on_op_hyphen_in(val[0], val[1][1])
792
+
793
+ else
794
+ val[0]
795
+ end
796
+
797
+ end
798
+
799
+ def _rule_25(val)
800
+ :eq
801
+ end
802
+
803
+ def _rule_26(val)
804
+ :space_in
805
+ end
806
+
807
+ def _rule_27(val)
808
+ :starts_with
809
+ end
810
+
811
+ def _rule_28(val)
812
+ :ends_with
813
+ end
814
+
815
+ def _rule_29(val)
816
+ :in
817
+ end
818
+
819
+ def _rule_30(val)
820
+ :hyphen_in
821
+ end
822
+
823
+ def _rule_31(val)
824
+
825
+ axis = s(:axis, 'attribute', s(:test, nil, 'class'))
826
+
827
+ s(
828
+ :call,
829
+ 'contains',
830
+ s(:call, 'concat', s(:string, ' '), axis, s(:string, ' ')),
831
+ s(:string, " #{val[1]} ")
832
+ )
833
+
834
+ end
835
+
836
+ def _rule_32(val)
837
+
838
+ s(
839
+ :eq,
840
+ s(:axis, 'attribute', s(:test, nil, 'id')),
841
+ s(:string, val[1])
842
+ )
843
+
844
+ end
845
+
846
+ def _rule_33(val)
847
+ on_pseudo_class(val[0], val[1])
848
+ end
849
+
850
+ def _rule_34(val)
851
+ val[1]
852
+ end
853
+
854
+ def _rule_35(val)
855
+ val[1]
856
+ end
857
+
858
+ def _rule_36(val)
859
+ val[0]
860
+ end
861
+
862
+ def _rule_37(val)
863
+ val[0]
864
+ end
865
+
866
+ def _rule_38(val)
867
+ val[0]
868
+ end
869
+
870
+ def _rule_39(val)
871
+ val[0]
872
+ end
873
+
874
+ def _rule_40(val)
875
+ s(:string, val[0])
876
+ end
877
+
878
+ def _rule_41(val)
879
+ s(:int, val[0].to_i)
880
+ end
881
+
882
+ def _rule_42(val)
883
+
884
+ val[1] ? s(:nth, s(:int, 1), val[1]) : s(:nth, s(:int, 1))
885
+
886
+ end
887
+
888
+ def _rule_43(val)
889
+
890
+ val[2] ? s(:nth, s(:int, -1), val[2]) : s(:nth, s(:int, 1))
891
+
892
+ end
893
+
894
+ def _rule_44(val)
895
+
896
+ # 2n+1
897
+ if val[1] and val[2]
898
+ a = val[0]
899
+ b = val[2]
900
+
901
+ # 2n-1 gets turned into 2n+1
902
+ if b.children[0] < 0
903
+ b = s(:int, a.children[0] - (b.children[0] % a.children[0]))
904
+ end
905
+
906
+ s(:nth, a, b)
907
+
908
+ # 2n
909
+ elsif val[1]
910
+ s(:nth, val[0])
911
+
912
+ # 2
913
+ else
914
+ val[0]
915
+ end
916
+
917
+ end
918
+
919
+ def _rule_45(val)
920
+ :nth
921
+ end
922
+
923
+ def _rule_46(val)
924
+ s(:nth, s(:int, 2), s(:int, 1))
925
+ end
926
+
927
+ def _rule_47(val)
928
+ s(:nth, s(:int, 2))
929
+ end
930
+
931
+ def _rule_48(val)
932
+ val[0]
933
+ end
934
+
935
+ def _rule_49(val)
936
+ val[0]
937
+ end
938
+
939
+ def _rule_50(val)
940
+ val[0]
941
+ end
942
+
943
+ def _rule_51(val)
944
+ val[0]
945
+ end
946
+
947
+ def _rule_52(val)
948
+ val[0]
949
+ end
950
+
951
+ def _rule_53(val)
952
+ val
953
+ end
954
+
955
+ def _rule_54(val)
956
+ val[0]
957
+ end
958
+
959
+ def _rule_55(val)
960
+ val[0]
961
+ end
962
+
963
+ def _rule_56(val)
964
+ val[0]
965
+ end
966
+
967
+ def _rule_57(val)
968
+ val[0]
969
+ end
970
+
971
+ def _rule_58(val)
972
+ val[0]
973
+ end
974
+ end
975
+ end
976
+ end