racc 1.4.14 → 1.4.15-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) 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 +88 -32
@@ -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