racc 1.4.14-java → 1.4.15-java

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 (61) hide show
  1. checksums.yaml +5 -5
  2. data/Manifest.txt +50 -0
  3. data/ext/racc/com/headius/racc/Cparse.java +66 -23
  4. data/ext/racc/cparse.c +1 -1
  5. data/ext/racc/depend +1 -1
  6. data/lib/racc/cparse-jruby.jar +0 -0
  7. data/lib/racc/info.rb +2 -2
  8. data/test/assets/bibtex.y +141 -0
  9. data/test/assets/cadenza.y +170 -0
  10. data/test/assets/cast.y +926 -0
  11. data/test/assets/csspool.y +729 -0
  12. data/test/assets/edtf.y +583 -0
  13. data/test/assets/huia.y +318 -0
  14. data/test/assets/journey.y +47 -0
  15. data/test/assets/liquor.y +313 -0
  16. data/test/assets/machete.y +423 -0
  17. data/test/assets/macruby.y +2197 -0
  18. data/test/assets/mediacloth.y +599 -0
  19. data/test/assets/mof.y +649 -0
  20. data/test/assets/namae.y +302 -0
  21. data/test/assets/nasl.y +626 -0
  22. data/test/assets/nokogiri-css.y +255 -0
  23. data/test/assets/opal.y +1807 -0
  24. data/test/assets/php_serialization.y +98 -0
  25. data/test/assets/rdblockparser.y +576 -0
  26. data/test/assets/rdinlineparser.y +561 -0
  27. data/test/assets/riml.y +665 -0
  28. data/test/assets/ruby18.y +1943 -0
  29. data/test/assets/ruby19.y +2174 -0
  30. data/test/assets/ruby20.y +2350 -0
  31. data/test/assets/ruby21.y +2359 -0
  32. data/test/assets/ruby22.y +2381 -0
  33. data/test/assets/tp_plus.y +622 -0
  34. data/test/assets/twowaysql.y +278 -0
  35. data/test/helper.rb +50 -34
  36. data/test/regress/bibtex +474 -0
  37. data/test/regress/cadenza +796 -0
  38. data/test/regress/cast +3425 -0
  39. data/test/regress/csspool +2318 -0
  40. data/test/regress/edtf +1794 -0
  41. data/test/regress/huia +1392 -0
  42. data/test/regress/journey +222 -0
  43. data/test/regress/liquor +885 -0
  44. data/test/regress/machete +833 -0
  45. data/test/regress/mediacloth +1463 -0
  46. data/test/regress/mof +1368 -0
  47. data/test/regress/namae +634 -0
  48. data/test/regress/nasl +2058 -0
  49. data/test/regress/nokogiri-css +836 -0
  50. data/test/regress/opal +6429 -0
  51. data/test/regress/php_serialization +336 -0
  52. data/test/regress/rdblockparser +1061 -0
  53. data/test/regress/rdinlineparser +1243 -0
  54. data/test/regress/riml +3297 -0
  55. data/test/regress/ruby18 +6351 -0
  56. data/test/regress/ruby22 +7456 -0
  57. data/test/regress/tp_plus +1933 -0
  58. data/test/regress/twowaysql +556 -0
  59. data/test/test_racc_command.rb +177 -0
  60. metadata +80 -25
  61. data/.gemtest +0 -0
@@ -0,0 +1,729 @@
1
+ class CSSPool::CSS::Parser
2
+
3
+ token CHARSET_SYM IMPORT_SYM STRING SEMI IDENT S COMMA LBRACE RBRACE STAR HASH
4
+ token LSQUARE RSQUARE EQUAL INCLUDES DASHMATCH LPAREN RPAREN FUNCTION GREATER PLUS
5
+ token SLASH NUMBER MINUS LENGTH PERCENTAGE ANGLE TIME FREQ URI
6
+ token IMPORTANT_SYM MEDIA_SYM NOT ONLY AND NTH_PSEUDO_CLASS
7
+ token DOCUMENT_QUERY_SYM FUNCTION_NO_QUOTE
8
+ token TILDE
9
+ token PREFIXMATCH SUFFIXMATCH SUBSTRINGMATCH
10
+ token NOT_PSEUDO_CLASS
11
+ token KEYFRAMES_SYM
12
+ token MATCHES_PSEUDO_CLASS
13
+ token NAMESPACE_SYM
14
+ token MOZ_PSEUDO_ELEMENT
15
+ token RESOLUTION
16
+ token COLON
17
+ token SUPPORTS_SYM
18
+ token OR
19
+ token VARIABLE_NAME
20
+ token CALC_SYM
21
+ token FONTFACE_SYM
22
+ token UNICODE_RANGE
23
+ token RATIO
24
+
25
+ rule
26
+ document
27
+ : { @handler.start_document }
28
+ stylesheet
29
+ { @handler.end_document }
30
+ ;
31
+ stylesheet
32
+ : charset stylesheet
33
+ | import stylesheet
34
+ | namespace stylesheet
35
+ | charset
36
+ | import
37
+ | namespace
38
+ | body
39
+ |
40
+ ;
41
+ charset
42
+ : CHARSET_SYM STRING SEMI { @handler.charset interpret_string(val[1]), {} }
43
+ ;
44
+ import
45
+ : IMPORT_SYM import_location medium SEMI {
46
+ @handler.import_style val[2], val[1]
47
+ }
48
+ | IMPORT_SYM import_location SEMI {
49
+ @handler.import_style [], val[1]
50
+ }
51
+ ;
52
+ import_location
53
+ : import_location S
54
+ | STRING { result = Terms::String.new interpret_string val.first }
55
+ | URI { result = Terms::URI.new interpret_uri val.first }
56
+ ;
57
+ namespace
58
+ : NAMESPACE_SYM ident import_location SEMI {
59
+ @handler.namespace val[1], val[2]
60
+ }
61
+ | NAMESPACE_SYM import_location SEMI {
62
+ @handler.namespace nil, val[1]
63
+ }
64
+ ;
65
+ medium
66
+ : medium COMMA IDENT {
67
+ result = val[0] << MediaType.new(val[2])
68
+ }
69
+ | IDENT {
70
+ result = [MediaType.new(val[0])]
71
+ }
72
+ ;
73
+ media_query_list
74
+ : media_query { result = MediaQueryList.new([ val[0] ]) }
75
+ | media_query_list COMMA media_query { result = val[0] << val[2] }
76
+ | { result = MediaQueryList.new }
77
+ ;
78
+ media_query
79
+ : optional_only_or_not media_type optional_and_exprs { result = MediaQuery.new(val[0], val[1], val[2]) }
80
+ | media_expr optional_and_exprs { result = MediaQuery.new(nil, val[0], val[1]) }
81
+ ;
82
+ optional_only_or_not
83
+ : ONLY { result = :only }
84
+ | NOT { result = :not }
85
+ | { result = nil }
86
+ ;
87
+ media_type
88
+ : IDENT { result = MediaType.new(val[0]) }
89
+ ;
90
+ media_expr
91
+ : LPAREN optional_space IDENT optional_space RPAREN { result = MediaType.new(val[2]) }
92
+ | LPAREN optional_space IDENT optional_space COLON optional_space expr RPAREN { result = MediaFeature.new(val[2], val[6][0]) }
93
+ ;
94
+ optional_space
95
+ : S { result = val[0] }
96
+ | { result = nil }
97
+ ;
98
+ optional_and_exprs
99
+ : optional_and_exprs AND media_expr { result = val[0] << val[2] }
100
+ | { result = [] }
101
+ ;
102
+ resolution
103
+ : RESOLUTION {
104
+ unit = val.first.gsub(/[\s\d.]/, '')
105
+ number = numeric(val.first)
106
+ result = Terms::Resolution.new(number, unit)
107
+ }
108
+ ;
109
+ body
110
+ : ruleset body
111
+ | conditional_rule body
112
+ | keyframes_rule body
113
+ | fontface_rule body
114
+ | ruleset
115
+ | conditional_rule
116
+ | keyframes_rule
117
+ | fontface_rule
118
+ ;
119
+ conditional_rule
120
+ : media
121
+ | document_query
122
+ | supports
123
+ ;
124
+ body_in_media
125
+ : body
126
+ | empty_ruleset
127
+ ;
128
+ media
129
+ : start_media body_in_media RBRACE { @handler.end_media val.first }
130
+ ;
131
+ start_media
132
+ : MEDIA_SYM media_query_list LBRACE {
133
+ result = val[1]
134
+ @handler.start_media result
135
+ }
136
+ ;
137
+ document_query
138
+ : start_document_query body RBRACE { @handler.end_document_query(before_pos(val), after_pos(val)) }
139
+ | start_document_query RBRACE { @handler.end_document_query(before_pos(val), after_pos(val)) }
140
+ ;
141
+ start_document_query
142
+ : start_document_query_pos url_match_fns LBRACE {
143
+ @handler.start_document_query(val[1], after_pos(val))
144
+ }
145
+ ;
146
+ start_document_query_pos
147
+ : DOCUMENT_QUERY_SYM {
148
+ @handler.node_start_pos = before_pos(val)
149
+ }
150
+ ;
151
+ url_match_fns
152
+ : url_match_fn COMMA url_match_fns {
153
+ result = [val[0], val[2]].flatten
154
+ }
155
+ | url_match_fn {
156
+ result = val
157
+ }
158
+ ;
159
+ url_match_fn
160
+ : function_no_quote
161
+ | function
162
+ | uri
163
+ ;
164
+ supports
165
+ : start_supports body RBRACE { @handler.end_supports }
166
+ | start_supports RBRACE { @handler.end_supports }
167
+ ;
168
+ start_supports
169
+ : SUPPORTS_SYM supports_condition_root LBRACE {
170
+ @handler.start_supports val[1]
171
+ }
172
+ ;
173
+ supports_condition_root
174
+ : supports_negation { result = val.join('') }
175
+ | supports_conjunction_or_disjunction { result = val.join('') }
176
+ | supports_condition_in_parens { result = val.join('') }
177
+ ;
178
+ supports_condition
179
+ : supports_negation { result = val.join('') }
180
+ | supports_conjunction_or_disjunction { result = val.join('') }
181
+ | supports_condition_in_parens { result = val.join('') }
182
+ ;
183
+ supports_condition_in_parens
184
+ : LPAREN supports_condition RPAREN { result = val.join('') }
185
+ | supports_declaration_condition { result = val.join('') }
186
+ ;
187
+ supports_negation
188
+ : NOT supports_condition_in_parens { result = val.join('') }
189
+ ;
190
+ supports_conjunction_or_disjunction
191
+ : supports_conjunction
192
+ | supports_disjunction
193
+ ;
194
+ supports_conjunction
195
+ : supports_condition_in_parens AND supports_condition_in_parens { result = val.join('') }
196
+ | supports_conjunction_or_disjunction AND supports_condition_in_parens { result = val.join('') }
197
+ ;
198
+ supports_disjunction
199
+ : supports_condition_in_parens OR supports_condition_in_parens { result = val.join('') }
200
+ | supports_conjunction_or_disjunction OR supports_condition_in_parens { result = val.join('') }
201
+ ;
202
+ supports_declaration_condition
203
+ : LPAREN declaration_internal RPAREN { result = val.join('') }
204
+ | LPAREN S declaration_internal RPAREN { result = val.join('') }
205
+ ;
206
+ keyframes_rule
207
+ : start_keyframes_rule keyframes_blocks RBRACE
208
+ | start_keyframes_rule RBRACE
209
+ ;
210
+ start_keyframes_rule
211
+ : KEYFRAMES_SYM IDENT LBRACE {
212
+ @handler.start_keyframes_rule val[1]
213
+ }
214
+ ;
215
+ keyframes_blocks
216
+ : keyframes_block keyframes_blocks
217
+ | keyframes_block
218
+ ;
219
+ keyframes_block
220
+ : start_keyframes_block declarations RBRACE { @handler.end_keyframes_block }
221
+ | start_keyframes_block RBRACE { @handler.end_keyframes_block }
222
+ ;
223
+ start_keyframes_block
224
+ : keyframes_selectors LBRACE {
225
+ @handler.start_keyframes_block val[0]
226
+ }
227
+ ;
228
+ keyframes_selectors
229
+ | keyframes_selector COMMA keyframes_selectors {
230
+ result = val[0] + ', ' + val[2]
231
+ }
232
+ | keyframes_selector
233
+ ;
234
+ keyframes_selector
235
+ : IDENT
236
+ | PERCENTAGE { result = val[0].strip }
237
+ ;
238
+ fontface_rule
239
+ : start_fontface_rule declarations RBRACE { @handler.end_fontface_rule }
240
+ | start_fontface_rule RBRACE { @handler.end_fontface_rule }
241
+ ;
242
+ start_fontface_rule
243
+ : FONTFACE_SYM LBRACE {
244
+ @handler.start_fontface_rule
245
+ }
246
+ ;
247
+ ruleset
248
+ : start_selector declarations RBRACE {
249
+ @handler.end_selector val.first
250
+ }
251
+ | start_selector RBRACE {
252
+ @handler.end_selector val.first
253
+ }
254
+ ;
255
+ empty_ruleset
256
+ : optional_space {
257
+ start = @handler.start_selector([])
258
+ @handler.end_selector(start)
259
+ }
260
+ ;
261
+ start_selector
262
+ : S start_selector { result = val.last }
263
+ | selectors LBRACE {
264
+ @handler.start_selector val.first
265
+ }
266
+ ;
267
+ selectors
268
+ : selector COMMA selectors
269
+ {
270
+ sel = Selector.new(val.first, {})
271
+ result = [sel].concat(val[2])
272
+ }
273
+ | selector
274
+ {
275
+ result = [Selector.new(val.first, {})]
276
+ }
277
+ ;
278
+ selector
279
+ : simple_selector combinator selector
280
+ {
281
+ val.flatten!
282
+ val[2].combinator = val.delete_at 1
283
+ result = val
284
+ }
285
+ | simple_selector
286
+ ;
287
+ combinator
288
+ : S { result = :s }
289
+ | GREATER { result = :> }
290
+ | PLUS { result = :+ }
291
+ | TILDE { result = :~ }
292
+ ;
293
+ simple_selector
294
+ : element_name hcap {
295
+ selector = val.first
296
+ selector.additional_selectors = val.last
297
+ result = [selector]
298
+ }
299
+ | element_name { result = val }
300
+ | hcap
301
+ {
302
+ ss = Selectors::Simple.new nil, nil
303
+ ss.additional_selectors = val.flatten
304
+ result = [ss]
305
+ }
306
+ ;
307
+ simple_selectors
308
+ : simple_selector COMMA simple_selectors { result = [val[0], val[2]].flatten }
309
+ | simple_selector
310
+ ;
311
+ ident_with_namespace
312
+ : IDENT { result = [interpret_identifier(val[0]), nil] }
313
+ | IDENT '|' IDENT { result = [interpret_identifier(val[2]), interpret_identifier(val[0])] }
314
+ | '|' IDENT { result = [interpret_identifier(val[1]), nil] }
315
+ | STAR '|' IDENT { result = [interpret_identifier(val[2]), '*'] }
316
+ ;
317
+ element_name
318
+ : ident_with_namespace { result = Selectors::Type.new val.first[0], nil, val.first[1] }
319
+ | STAR { result = Selectors::Universal.new val.first }
320
+ | '|' STAR { result = Selectors::Universal.new val[1] }
321
+ | STAR '|' STAR { result = Selectors::Universal.new val[2], nil, val[0] }
322
+ | IDENT '|' STAR { result = Selectors::Universal.new val[2], nil, interpret_identifier(val[0]) }
323
+ ;
324
+ hcap
325
+ : hash { result = val }
326
+ | class { result = val }
327
+ | attrib { result = val }
328
+ | pseudo { result = val }
329
+ | hash hcap { result = val.flatten }
330
+ | class hcap { result = val.flatten }
331
+ | attrib hcap { result = val.flatten }
332
+ | pseudo hcap { result = val.flatten }
333
+ ;
334
+ hash
335
+ : HASH {
336
+ result = Selectors::Id.new interpret_identifier val.first.sub(/^#/, '')
337
+ }
338
+ class
339
+ : '.' IDENT {
340
+ result = Selectors::Class.new interpret_identifier val.last
341
+ }
342
+ ;
343
+ attrib
344
+ : LSQUARE ident_with_namespace EQUAL IDENT RSQUARE {
345
+ result = Selectors::Attribute.new(
346
+ val[1][0],
347
+ interpret_identifier(val[3]),
348
+ Selectors::Attribute::EQUALS,
349
+ val[1][1]
350
+ )
351
+ }
352
+ | LSQUARE ident_with_namespace EQUAL STRING RSQUARE {
353
+ result = Selectors::Attribute.new(
354
+ val[1][0],
355
+ interpret_string(val[3]),
356
+ Selectors::Attribute::EQUALS,
357
+ val[1][1]
358
+ )
359
+ }
360
+ | LSQUARE ident_with_namespace INCLUDES STRING RSQUARE {
361
+ result = Selectors::Attribute.new(
362
+ val[1][0],
363
+ interpret_string(val[3]),
364
+ Selectors::Attribute::INCLUDES,
365
+ val[1][1]
366
+ )
367
+ }
368
+ | LSQUARE ident_with_namespace INCLUDES IDENT RSQUARE {
369
+ result = Selectors::Attribute.new(
370
+ val[1][0],
371
+ interpret_identifier(val[3]),
372
+ Selectors::Attribute::INCLUDES,
373
+ val[1][1]
374
+ )
375
+ }
376
+ | LSQUARE ident_with_namespace DASHMATCH IDENT RSQUARE {
377
+ result = Selectors::Attribute.new(
378
+ val[1][0],
379
+ interpret_identifier(val[3]),
380
+ Selectors::Attribute::DASHMATCH,
381
+ val[1][1]
382
+ )
383
+ }
384
+ | LSQUARE ident_with_namespace DASHMATCH STRING RSQUARE {
385
+ result = Selectors::Attribute.new(
386
+ val[1][0],
387
+ interpret_string(val[3]),
388
+ Selectors::Attribute::DASHMATCH,
389
+ val[1][1]
390
+ )
391
+ }
392
+ | LSQUARE ident_with_namespace PREFIXMATCH IDENT RSQUARE {
393
+ result = Selectors::Attribute.new(
394
+ val[1][0],
395
+ interpret_identifier(val[3]),
396
+ Selectors::Attribute::PREFIXMATCH,
397
+ val[1][1]
398
+ )
399
+ }
400
+ | LSQUARE ident_with_namespace PREFIXMATCH STRING RSQUARE {
401
+ result = Selectors::Attribute.new(
402
+ val[1][0],
403
+ interpret_string(val[3]),
404
+ Selectors::Attribute::PREFIXMATCH,
405
+ val[1][1]
406
+ )
407
+ }
408
+ | LSQUARE ident_with_namespace SUFFIXMATCH IDENT RSQUARE {
409
+ result = Selectors::Attribute.new(
410
+ val[1][0],
411
+ interpret_identifier(val[3]),
412
+ Selectors::Attribute::SUFFIXMATCH,
413
+ val[1][1]
414
+ )
415
+ }
416
+ | LSQUARE ident_with_namespace SUFFIXMATCH STRING RSQUARE {
417
+ result = Selectors::Attribute.new(
418
+ val[1][0],
419
+ interpret_string(val[3]),
420
+ Selectors::Attribute::SUFFIXMATCH,
421
+ val[1][1]
422
+ )
423
+ }
424
+ | LSQUARE ident_with_namespace SUBSTRINGMATCH IDENT RSQUARE {
425
+ result = Selectors::Attribute.new(
426
+ val[1][0],
427
+ interpret_identifier(val[3]),
428
+ Selectors::Attribute::SUBSTRINGMATCH,
429
+ val[1][1]
430
+ )
431
+ }
432
+ | LSQUARE ident_with_namespace SUBSTRINGMATCH STRING RSQUARE {
433
+ result = Selectors::Attribute.new(
434
+ val[1][0],
435
+ interpret_string(val[3]),
436
+ Selectors::Attribute::SUBSTRINGMATCH,
437
+ val[1][1]
438
+ )
439
+ }
440
+ | LSQUARE ident_with_namespace RSQUARE {
441
+ result = Selectors::Attribute.new(
442
+ val[1][0],
443
+ nil,
444
+ Selectors::Attribute::SET,
445
+ val[1][1]
446
+ )
447
+ }
448
+ ;
449
+ pseudo
450
+ : COLON IDENT {
451
+ result = Selectors::pseudo interpret_identifier(val[1])
452
+ }
453
+ | COLON COLON IDENT {
454
+ result = Selectors::PseudoElement.new(
455
+ interpret_identifier(val[2])
456
+ )
457
+ }
458
+ | COLON FUNCTION RPAREN {
459
+ result = Selectors::PseudoClass.new(
460
+ interpret_identifier(val[1].sub(/\($/, '')),
461
+ ''
462
+ )
463
+ }
464
+ | COLON FUNCTION IDENT RPAREN {
465
+ result = Selectors::PseudoClass.new(
466
+ interpret_identifier(val[1].sub(/\($/, '')),
467
+ interpret_identifier(val[2])
468
+ )
469
+ }
470
+ | COLON NOT_PSEUDO_CLASS simple_selector RPAREN {
471
+ result = Selectors::PseudoClass.new(
472
+ 'not',
473
+ val[2].first.to_s
474
+ )
475
+ }
476
+ | COLON NTH_PSEUDO_CLASS {
477
+ result = Selectors::PseudoClass.new(
478
+ interpret_identifier(val[1].sub(/\(.*/, '')),
479
+ interpret_identifier(val[1].sub(/.*\(/, '').sub(/\).*/, ''))
480
+ )
481
+ }
482
+ | COLON MATCHES_PSEUDO_CLASS simple_selectors RPAREN {
483
+ result = Selectors::PseudoClass.new(
484
+ val[1].split('(').first.strip,
485
+ val[2].join(', ')
486
+ )
487
+ }
488
+ | COLON MOZ_PSEUDO_ELEMENT optional_space any_number_of_idents optional_space RPAREN {
489
+ result = Selectors::PseudoElement.new(
490
+ interpret_identifier(val[1].sub(/\($/, ''))
491
+ )
492
+ }
493
+ | COLON COLON MOZ_PSEUDO_ELEMENT optional_space any_number_of_idents optional_space RPAREN {
494
+ result = Selectors::PseudoElement.new(
495
+ interpret_identifier(val[2].sub(/\($/, ''))
496
+ )
497
+ }
498
+ ;
499
+ any_number_of_idents
500
+ :
501
+ | multiple_idents
502
+ ;
503
+ multiple_idents
504
+ : IDENT
505
+ | IDENT COMMA multiple_idents
506
+ ;
507
+ # declarations can be separated by one *or more* semicolons. semi-colons at the start or end of a ruleset are also allowed
508
+ one_or_more_semis
509
+ : SEMI
510
+ | SEMI one_or_more_semis
511
+ ;
512
+ declarations
513
+ : declaration one_or_more_semis declarations
514
+ | one_or_more_semis declarations
515
+ | declaration one_or_more_semis
516
+ | declaration
517
+ | one_or_more_semis
518
+ ;
519
+ declaration
520
+ : declaration_internal { @handler.property val.first }
521
+ ;
522
+ declaration_internal
523
+ : property COLON expr prio
524
+ { result = Declaration.new(val.first, val[2], val[3]) }
525
+ | property COLON S expr prio
526
+ { result = Declaration.new(val.first, val[3], val[4]) }
527
+ | property S COLON expr prio
528
+ { result = Declaration.new(val.first, val[3], val[4]) }
529
+ | property S COLON S expr prio
530
+ { result = Declaration.new(val.first, val[4], val[5]) }
531
+ ;
532
+ prio
533
+ : IMPORTANT_SYM { result = true }
534
+ | { result = false }
535
+ ;
536
+ property
537
+ : IDENT { result = interpret_identifier val[0] }
538
+ | STAR IDENT { result = interpret_identifier val.join }
539
+ | VARIABLE_NAME { result = interpret_identifier val[0] }
540
+ ;
541
+ operator
542
+ : COMMA
543
+ | SLASH
544
+ | EQUAL
545
+ ;
546
+ expr
547
+ : term operator expr {
548
+ result = [val.first, val.last].flatten
549
+ val.last.first.operator = val[1]
550
+ }
551
+ | term expr { result = val.flatten }
552
+ | term { result = val }
553
+ ;
554
+ term
555
+ : ident
556
+ | ratio
557
+ | numeric
558
+ | string
559
+ | uri
560
+ | hexcolor
561
+ | calc
562
+ | function
563
+ | resolution
564
+ | VARIABLE_NAME
565
+ | uranges
566
+ ;
567
+ function
568
+ : function S { result = val.first }
569
+ | FUNCTION expr RPAREN {
570
+ name = interpret_identifier val.first.sub(/\($/, '')
571
+ if name == 'rgb'
572
+ result = Terms::Rgb.new(*val[1])
573
+ else
574
+ result = Terms::Function.new name, val[1]
575
+ end
576
+ }
577
+ | FUNCTION RPAREN {
578
+ name = interpret_identifier val.first.sub(/\($/, '')
579
+ result = Terms::Function.new name
580
+ }
581
+ ;
582
+ function_no_quote
583
+ : function_no_quote S { result = val.first }
584
+ | FUNCTION_NO_QUOTE {
585
+ parts = val.first.split('(')
586
+ name = interpret_identifier parts.first
587
+ result = Terms::Function.new(name, [Terms::String.new(interpret_string_no_quote(parts.last))])
588
+ }
589
+ ;
590
+ uranges
591
+ : UNICODE_RANGE COMMA uranges
592
+ | UNICODE_RANGE
593
+ ;
594
+ calc
595
+ : CALC_SYM calc_sum RPAREN optional_space {
596
+ result = Terms::Math.new(val.first.split('(').first, val[1])
597
+ }
598
+ ;
599
+ # plus and minus are supposed to have whitespace around them, per http://dev.w3.org/csswg/css-values/#calc-syntax, but the numbers are eating trailing whitespace, so we inject it back in
600
+ calc_sum
601
+ : calc_product
602
+ | calc_product PLUS calc_sum { val.insert(1, ' '); result = val.join('') }
603
+ | calc_product MINUS calc_sum { val.insert(1, ' '); result = val.join('') }
604
+ ;
605
+ calc_product
606
+ : calc_value
607
+ | calc_value optional_space STAR calc_value { result = val.join('') }
608
+ | calc_value optional_space SLASH calc_value { result = val.join('') }
609
+ ;
610
+ calc_value
611
+ : numeric { result = val.join('') }
612
+ | function { result = val.join('') } # for var() variable references
613
+ | LPAREN calc_sum RPAREN { result = val.join('') }
614
+ ;
615
+ hexcolor
616
+ : hexcolor S { result = val.first }
617
+ | HASH { result = Terms::Hash.new val.first.sub(/^#/, '') }
618
+ ;
619
+ uri
620
+ : uri S { result = val.first }
621
+ | URI { result = Terms::URI.new interpret_uri val.first }
622
+ ;
623
+ string
624
+ : string S { result = val.first }
625
+ | STRING { result = Terms::String.new interpret_string val.first }
626
+ ;
627
+ numeric
628
+ : unary_operator numeric {
629
+ result = val[1]
630
+ val[1].unary_operator = val.first
631
+ }
632
+ | NUMBER {
633
+ result = Terms::Number.new numeric val.first
634
+ }
635
+ | PERCENTAGE {
636
+ result = Terms::Number.new numeric(val.first), nil, '%'
637
+ }
638
+ | LENGTH {
639
+ unit = val.first.gsub(/[\s\d.]/, '')
640
+ result = Terms::Number.new numeric(val.first), nil, unit
641
+ }
642
+ | ANGLE {
643
+ unit = val.first.gsub(/[\s\d.]/, '')
644
+ result = Terms::Number.new numeric(val.first), nil, unit
645
+ }
646
+ | TIME {
647
+ unit = val.first.gsub(/[\s\d.]/, '')
648
+ result = Terms::Number.new numeric(val.first), nil, unit
649
+ }
650
+ | FREQ {
651
+ unit = val.first.gsub(/[\s\d.]/, '')
652
+ result = Terms::Number.new numeric(val.first), nil, unit
653
+ }
654
+ ;
655
+ ratio
656
+ : RATIO {
657
+ result = Terms::Ratio.new(val[0], val[1])
658
+ }
659
+ ;
660
+ unary_operator
661
+ : MINUS { result = :minus }
662
+ | PLUS { result = :plus }
663
+ ;
664
+ ident
665
+ : ident S { result = val.first }
666
+ | IDENT { result = Terms::Ident.new interpret_identifier val.first }
667
+ ;
668
+
669
+ ---- inner
670
+
671
+ def numeric thing
672
+ thing = thing.gsub(/[^\d.]/, '')
673
+ Integer(thing) rescue Float(thing)
674
+ end
675
+
676
+ def interpret_identifier s
677
+ interpret_escapes s
678
+ end
679
+
680
+ def interpret_uri s
681
+ interpret_escapes s.match(/^url\((.*)\)$/mui)[1].strip.match(/^(['"]?)((?:\\.|.)*)\1$/mu)[2]
682
+ end
683
+
684
+ def interpret_string_no_quote s
685
+ interpret_escapes s.match(/^(.*)\)$/mu)[1].strip.match(/^(['"]?)((?:\\.|.)*)\1$/mu)[2]
686
+ end
687
+
688
+ def interpret_string s
689
+ interpret_escapes s.match(/^(['"])((?:\\.|.)*)\1$/mu)[2]
690
+ end
691
+
692
+ def interpret_escapes s
693
+ token_exp = /\\(?:([0-9a-fA-F]{1,6}(?:\r\n|\s)?)|(.))/mu
694
+ return s.gsub(token_exp) do |escape_sequence|
695
+ if !$1.nil?
696
+ code = $1.chomp.to_i 16
697
+ code = 0xFFFD if code > 0x10FFFF
698
+ next [code].pack('U')
699
+ end
700
+ next '' if $2 == "\n"
701
+ next $2
702
+ end
703
+ end
704
+
705
+ # override racc's on_error so we can have context in our error messages
706
+ def on_error(t, val, vstack)
707
+ errcontext = (@ss.pre_match[-10..-1] || @ss.pre_match) +
708
+ @ss.matched + @ss.post_match[0..9]
709
+ line_number = @ss.pre_match.lines.count
710
+ raise ParseError, sprintf("parse error on value %s (%s) " +
711
+ "on line %s around \"%s\"",
712
+ val.inspect, token_to_str(t) || '?',
713
+ line_number, errcontext)
714
+ end
715
+
716
+ def before_pos(val)
717
+ # don't include leading whitespace
718
+ return current_pos - val.last.length + val.last[/\A\s*/].size
719
+ end
720
+
721
+ def after_pos(val)
722
+ # don't include trailing whitespace
723
+ return current_pos - val.last[/\s*\z/].size
724
+ end
725
+
726
+ # charpos will work with multibyte strings but is not available until ruby 2
727
+ def current_pos
728
+ @ss.respond_to?('charpos') ? @ss.charpos : @ss.pos
729
+ end