csspool-st 3.1.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.
Files changed (64) hide show
  1. data/.autotest +16 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.rdoc +87 -0
  4. data/Manifest.txt +62 -0
  5. data/README.rdoc +65 -0
  6. data/Rakefile +50 -0
  7. data/lib/csspool/collection.rb +50 -0
  8. data/lib/csspool/css/charset.rb +13 -0
  9. data/lib/csspool/css/declaration.rb +19 -0
  10. data/lib/csspool/css/document.rb +34 -0
  11. data/lib/csspool/css/document_handler.rb +51 -0
  12. data/lib/csspool/css/import_rule.rb +27 -0
  13. data/lib/csspool/css/media.rb +13 -0
  14. data/lib/csspool/css/parser.rb +1298 -0
  15. data/lib/csspool/css/parser.y +398 -0
  16. data/lib/csspool/css/rule_set.rb +17 -0
  17. data/lib/csspool/css/tokenizer.rb +231 -0
  18. data/lib/csspool/css/tokenizer.rex +97 -0
  19. data/lib/csspool/css.rb +8 -0
  20. data/lib/csspool/node.rb +41 -0
  21. data/lib/csspool/sac/document.rb +35 -0
  22. data/lib/csspool/sac/parser.rb +16 -0
  23. data/lib/csspool/sac.rb +2 -0
  24. data/lib/csspool/selector.rb +36 -0
  25. data/lib/csspool/selectors/additional.rb +6 -0
  26. data/lib/csspool/selectors/attribute.rb +21 -0
  27. data/lib/csspool/selectors/class.rb +11 -0
  28. data/lib/csspool/selectors/id.rb +11 -0
  29. data/lib/csspool/selectors/pseudo_class.rb +13 -0
  30. data/lib/csspool/selectors/simple.rb +22 -0
  31. data/lib/csspool/selectors/type.rb +6 -0
  32. data/lib/csspool/selectors/universal.rb +6 -0
  33. data/lib/csspool/selectors.rb +9 -0
  34. data/lib/csspool/terms/function.rb +17 -0
  35. data/lib/csspool/terms/hash.rb +6 -0
  36. data/lib/csspool/terms/ident.rb +15 -0
  37. data/lib/csspool/terms/number.rb +14 -0
  38. data/lib/csspool/terms/rgb.rb +20 -0
  39. data/lib/csspool/terms/string.rb +6 -0
  40. data/lib/csspool/terms/uri.rb +6 -0
  41. data/lib/csspool/terms.rb +7 -0
  42. data/lib/csspool/visitors/children.rb +50 -0
  43. data/lib/csspool/visitors/comparable.rb +84 -0
  44. data/lib/csspool/visitors/iterator.rb +80 -0
  45. data/lib/csspool/visitors/to_css.rb +248 -0
  46. data/lib/csspool/visitors/visitor.rb +17 -0
  47. data/lib/csspool/visitors.rb +5 -0
  48. data/lib/csspool.rb +21 -0
  49. data/test/css/test_document.rb +13 -0
  50. data/test/css/test_import_rule.rb +42 -0
  51. data/test/css/test_parser.rb +462 -0
  52. data/test/css/test_tokenizer.rb +320 -0
  53. data/test/helper.rb +65 -0
  54. data/test/sac/test_parser.rb +123 -0
  55. data/test/sac/test_properties.rb +43 -0
  56. data/test/sac/test_terms.rb +228 -0
  57. data/test/test_collection.rb +81 -0
  58. data/test/test_parser.rb +91 -0
  59. data/test/test_selector.rb +51 -0
  60. data/test/visitors/test_children.rb +20 -0
  61. data/test/visitors/test_comparable.rb +102 -0
  62. data/test/visitors/test_each.rb +19 -0
  63. data/test/visitors/test_to_css.rb +309 -0
  64. metadata +214 -0
@@ -0,0 +1,398 @@
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 RPAREN FUNCTION GREATER PLUS
5
+ token SLASH NUMBER MINUS LENGTH PERCENTAGE EMS EXS ANGLE TIME FREQ URI
6
+ token IMPORTANT_SYM MEDIA_SYM LPAREN
7
+
8
+ rule
9
+ document
10
+ : { @handler.start_document }
11
+ stylesheet
12
+ { @handler.end_document }
13
+ ;
14
+ stylesheet
15
+ : charset stylesheet
16
+ | import stylesheet
17
+ | charset
18
+ | import
19
+ | body
20
+ ;
21
+ charset
22
+ : CHARSET_SYM STRING SEMI { @handler.charset interpret_string(val[1]), {} }
23
+ ;
24
+ import
25
+ : IMPORT_SYM import_location medium SEMI {
26
+ @handler.import_style val[2], val[1]
27
+ }
28
+ | IMPORT_SYM import_location SEMI {
29
+ @handler.import_style [], val[1]
30
+ }
31
+ ;
32
+ import_location
33
+ : import_location S
34
+ | STRING { result = Terms::String.new interpret_string val.first }
35
+ | URI { result = Terms::URI.new interpret_uri val.first }
36
+ ;
37
+ medium
38
+ : medium COMMA media_query {
39
+ result = val.first + [val.last]
40
+ }
41
+ | media_query {
42
+ result = [val.first]
43
+ }
44
+ ;
45
+ media_query
46
+ : IDENT S IDENT media_expression {
47
+ result = [Terms::Ident.new(interpret_identifier val[0]), Terms::Ident.new(interpret_identifier val[2])] + val.last
48
+ }
49
+ | IDENT S IDENT {
50
+ result = [Terms::Ident.new(interpret_identifier val[0]), Terms::Ident.new(interpret_identifier val.last)]
51
+ }
52
+ | IDENT media_expression {
53
+ result = [Terms::Ident.new(interpret_identifier val.first)] + val.last
54
+ }
55
+ | IDENT {
56
+ result = [Terms::Ident.new(interpret_identifier val.first)]
57
+ }
58
+ | expression media_expression {
59
+ result = [val.first] + val.last
60
+ }
61
+ | expression {
62
+ result = [val.first]
63
+ }
64
+ ;
65
+ media_expression
66
+ : S IDENT expression media_expression {
67
+ result = [Terms::Ident.new(interpret_identifier val[1]), val[2]] + val.last
68
+ }
69
+ | S IDENT expression {
70
+ result = [Terms::Ident.new(interpret_identifier val[1]), val.last]
71
+ }
72
+ ;
73
+ expression_internal
74
+ : property ':' expr
75
+ { result = Selectors::MediaExpression.new val.first, val[2] }
76
+ | property ':' S expr
77
+ { result = Selectors::MediaExpression.new val.first, val[3] }
78
+ | property S ':' expr
79
+ { result = Selectors::MediaExpression.new val.first, val[3] }
80
+ | property S ':' S expr
81
+ { result = Selectors::MediaExpression.new val.first, val[4] }
82
+ ;
83
+ expression
84
+ : LPAREN expression_internal RPAREN {
85
+ result = val[1]
86
+ }
87
+ ;
88
+ body
89
+ : ruleset body
90
+ | media body
91
+ | ruleset
92
+ | media
93
+ ;
94
+ media
95
+ : start_media body RBRACE { @handler.end_media val.first }
96
+ ;
97
+ start_media
98
+ : MEDIA_SYM medium LBRACE {
99
+ @handler.start_media val[1]
100
+ }
101
+ | MEDIA_SYM LBRACE { result = [] }
102
+ ;
103
+ ruleset
104
+ : start_selector declarations RBRACE {
105
+ @handler.end_selector val.first
106
+ }
107
+ | start_selector RBRACE {
108
+ @handler.end_selector val.first
109
+ }
110
+ ;
111
+ start_selector
112
+ : S start_selector { result = val.last }
113
+ | selectors LBRACE {
114
+ @handler.start_selector val.first
115
+ }
116
+ ;
117
+ selectors
118
+ : selector COMMA selectors
119
+ {
120
+ # FIXME: should always garantee array
121
+ sel = Selector.new(val.first, {})
122
+ result = [sel, val[2]].flatten
123
+ }
124
+ | selector
125
+ {
126
+ result = [Selector.new(val.first, {})]
127
+ }
128
+ ;
129
+ selector
130
+ : simple_selector combinator selector
131
+ {
132
+ val = val.flatten
133
+ val[2].combinator = val.delete_at 1
134
+ result = val
135
+ }
136
+ | simple_selector
137
+ ;
138
+ combinator
139
+ : S { result = :s }
140
+ | GREATER { result = :> }
141
+ | PLUS { result = :+ }
142
+ ;
143
+ simple_selector
144
+ : element_name hcap {
145
+ selector = val.first
146
+ selector.additional_selectors = val.last
147
+ result = [selector]
148
+ }
149
+ | element_name { result = val }
150
+ | hcap
151
+ {
152
+ ss = Selectors::Simple.new nil, nil
153
+ ss.additional_selectors = val.flatten
154
+ result = [ss]
155
+ }
156
+ ;
157
+ element_name
158
+ : IDENT { result = Selectors::Type.new interpret_identifier val.first }
159
+ | STAR { result = Selectors::Universal.new val.first }
160
+ ;
161
+ hcap
162
+ : hash { result = val }
163
+ | class { result = val }
164
+ | attrib { result = val }
165
+ | pseudo { result = val }
166
+ | hash hcap { result = val.flatten }
167
+ | class hcap { result = val.flatten }
168
+ | attrib hcap { result = val.flatten }
169
+ | pseudo hcap { result = val.flatten }
170
+ ;
171
+ hash
172
+ : HASH {
173
+ result = Selectors::Id.new interpret_identifier val.first.sub(/^#/, '')
174
+ }
175
+ class
176
+ : '.' IDENT {
177
+ result = Selectors::Class.new interpret_identifier val.last
178
+ }
179
+ ;
180
+ attrib
181
+ : LSQUARE IDENT EQUAL IDENT RSQUARE {
182
+ result = Selectors::Attribute.new(
183
+ interpret_identifier(val[1]),
184
+ interpret_identifier(val[3]),
185
+ Selectors::Attribute::EQUALS
186
+ )
187
+ }
188
+ | LSQUARE IDENT EQUAL STRING RSQUARE {
189
+ result = Selectors::Attribute.new(
190
+ interpret_identifier(val[1]),
191
+ interpret_string(val[3]),
192
+ Selectors::Attribute::EQUALS
193
+ )
194
+ }
195
+ | LSQUARE IDENT INCLUDES STRING RSQUARE {
196
+ result = Selectors::Attribute.new(
197
+ interpret_identifier(val[1]),
198
+ interpret_string(val[3]),
199
+ Selectors::Attribute::INCLUDES
200
+ )
201
+ }
202
+ | LSQUARE IDENT INCLUDES IDENT RSQUARE {
203
+ result = Selectors::Attribute.new(
204
+ interpret_identifier(val[1]),
205
+ interpret_identifier(val[3]),
206
+ Selectors::Attribute::INCLUDES
207
+ )
208
+ }
209
+ | LSQUARE IDENT DASHMATCH IDENT RSQUARE {
210
+ result = Selectors::Attribute.new(
211
+ interpret_identifier(val[1]),
212
+ interpret_identifier(val[3]),
213
+ Selectors::Attribute::DASHMATCH
214
+ )
215
+ }
216
+ | LSQUARE IDENT DASHMATCH STRING RSQUARE {
217
+ result = Selectors::Attribute.new(
218
+ interpret_identifier(val[1]),
219
+ interpret_string(val[3]),
220
+ Selectors::Attribute::DASHMATCH
221
+ )
222
+ }
223
+ | LSQUARE IDENT RSQUARE {
224
+ result = Selectors::Attribute.new(
225
+ interpret_identifier(val[1]),
226
+ nil,
227
+ Selectors::Attribute::SET
228
+ )
229
+ }
230
+ ;
231
+ pseudo
232
+ : ':' IDENT {
233
+ result = Selectors::pseudo interpret_identifier(val[1])
234
+ }
235
+ | ':' ':' IDENT {
236
+ result = Selectors::PseudoElement.new(
237
+ interpret_identifier(val[2])
238
+ )
239
+ }
240
+ | ':' FUNCTION RPAREN {
241
+ result = Selectors::PseudoClass.new(
242
+ interpret_identifier(val[1].sub(/\($/, '')),
243
+ ''
244
+ )
245
+ }
246
+ | ':' FUNCTION IDENT RPAREN {
247
+ result = Selectors::PseudoClass.new(
248
+ interpret_identifier(val[1].sub(/\($/, '')),
249
+ interpret_identifier(val[2])
250
+ )
251
+ }
252
+ ;
253
+ declarations
254
+ : declaration SEMI declarations
255
+ | declaration SEMI
256
+ | declaration
257
+ ;
258
+ declaration
259
+ : property ':' expr prio
260
+ { @handler.property val.first, val[2], val[3] }
261
+ | property ':' S expr prio
262
+ { @handler.property val.first, val[3], val[4] }
263
+ | property S ':' expr prio
264
+ { @handler.property val.first, val[3], val[4] }
265
+ | property S ':' S expr prio
266
+ { @handler.property val.first, val[4], val[5] }
267
+ ;
268
+ prio
269
+ : IMPORTANT_SYM { result = true }
270
+ | { result = false }
271
+ ;
272
+ property
273
+ : IDENT { result = interpret_identifier val[0] }
274
+ | STAR IDENT { result = interpret_identifier val.join }
275
+ ;
276
+ operator
277
+ : COMMA
278
+ | SLASH
279
+ | EQUAL
280
+ ;
281
+ expr
282
+ : term operator expr {
283
+ result = [val.first, val.last].flatten
284
+ val.last.first.operator = val[1]
285
+ }
286
+ | term expr { result = val.flatten }
287
+ | term { result = val }
288
+ ;
289
+ term
290
+ : ident
291
+ | numeric
292
+ | string
293
+ | uri
294
+ | hexcolor
295
+ | function
296
+ ;
297
+ function
298
+ : function S { result = val.first }
299
+ | FUNCTION expr RPAREN {
300
+ name = interpret_identifier val.first.sub(/\($/, '')
301
+ if name == 'rgb'
302
+ result = Terms::Rgb.new(*val[1])
303
+ else
304
+ result = Terms::Function.new name, val[1]
305
+ end
306
+ }
307
+ ;
308
+ hexcolor
309
+ : hexcolor S { result = val.first }
310
+ | HASH { result = Terms::Hash.new val.first.sub(/^#/, '') }
311
+ ;
312
+ uri
313
+ : uri S { result = val.first }
314
+ | URI { result = Terms::URI.new interpret_uri val.first }
315
+ string
316
+ : string S { result = val.first }
317
+ | STRING { result = Terms::String.new interpret_string val.first }
318
+ ;
319
+ numeric
320
+ : unary_operator numeric {
321
+ result = val[1]
322
+ val[1].unary_operator = val.first
323
+ }
324
+ | NUMBER {
325
+ result = Terms::Number.new numeric val.first
326
+ }
327
+ | PERCENTAGE {
328
+ result = Terms::Number.new numeric(val.first), nil, '%'
329
+ }
330
+ | LENGTH {
331
+ unit = val.first.gsub(/[\s\d.]/, '')
332
+ result = Terms::Number.new numeric(val.first), nil, unit
333
+ }
334
+ | EMS {
335
+ result = Terms::Number.new numeric(val.first), nil, 'em'
336
+ }
337
+ | EXS {
338
+ result = Terms::Number.new numeric(val.first), nil, 'ex'
339
+ }
340
+ | ANGLE {
341
+ unit = val.first.gsub(/[\s\d.]/, '')
342
+ result = Terms::Number.new numeric(val.first), nil, unit
343
+ }
344
+ | TIME {
345
+ unit = val.first.gsub(/[\s\d.]/, '')
346
+ result = Terms::Number.new numeric(val.first), nil, unit
347
+ }
348
+ | FREQ {
349
+ unit = val.first.gsub(/[\s\d.]/, '')
350
+ result = Terms::Number.new numeric(val.first), nil, unit
351
+ }
352
+ ;
353
+ unary_operator
354
+ : MINUS { result = :minus }
355
+ | PLUS { result = :plus }
356
+ ;
357
+ ident
358
+ : ident S { result = val.first }
359
+ | IDENT { result = Terms::Ident.new interpret_identifier val.first }
360
+ ;
361
+
362
+ ---- inner
363
+
364
+ def numeric thing
365
+ thing = thing.gsub(/[^\d.]/, '')
366
+ Integer(thing) rescue Float(thing)
367
+ end
368
+
369
+ def interpret_identifier s
370
+ interpret_escapes s
371
+ end
372
+
373
+ def interpret_uri s
374
+ interpret_escapes s.match(/^url\((.*)\)$/mu)[1].strip.match(/^(['"]?)((?:\\.|.)*)\1$/mu)[2]
375
+ end
376
+
377
+ def interpret_string s
378
+ interpret_escapes s.match(/^(['"])((?:\\.|.)*)\1$/mu)[2]
379
+ end
380
+
381
+ def interpret_escapes s
382
+ token_exp = /\\([0-9a-fA-F]{1,6}(?:\r\n|\s)?)|\\(.)|(.)/mu
383
+ characters = s.scan(token_exp).map do |u_escape, i_escape, ident|
384
+ if u_escape
385
+ code = u_escape.chomp.to_i 16
386
+ code = 0xFFFD if code > 0x10FFFF
387
+ [code].pack('U')
388
+ elsif i_escape
389
+ if i_escape == "\n"
390
+ ''
391
+ else
392
+ i_escape
393
+ end
394
+ else
395
+ ident
396
+ end
397
+ end.join ''
398
+ end
@@ -0,0 +1,17 @@
1
+ module CSSPool
2
+ module CSS
3
+ class RuleSet < CSSPool::Node
4
+ attr_accessor :selectors
5
+ attr_accessor :declarations
6
+ attr_accessor :media
7
+
8
+ def initialize selectors, declarations = [], media = []
9
+ @selectors = selectors
10
+ @declarations = declarations
11
+ @media = media
12
+
13
+ selectors.each { |sel| sel.rule_set = self }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,231 @@
1
+ #--
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by rex 1.0.5
4
+ # from lexical definition file "lib/csspool/css/tokenizer.rex".
5
+ #++
6
+
7
+ module CSSPool
8
+ module CSS
9
+ class Tokenizer < Parser
10
+ require 'strscan'
11
+
12
+ class ScanError < StandardError ; end
13
+
14
+ attr_reader :lineno
15
+ attr_reader :filename
16
+ attr_accessor :state
17
+
18
+ def scan_setup(str)
19
+ @ss = StringScanner.new(str)
20
+ @lineno = 1
21
+ @state = nil
22
+ end
23
+
24
+ def action
25
+ yield
26
+ end
27
+
28
+ def scan_str(str)
29
+ scan_setup(str)
30
+ do_parse
31
+ end
32
+ alias :scan :scan_str
33
+
34
+ def load_file( filename )
35
+ @filename = filename
36
+ open(filename, "r") do |f|
37
+ scan_setup(f.read)
38
+ end
39
+ end
40
+
41
+ def scan_file( filename )
42
+ load_file(filename)
43
+ do_parse
44
+ end
45
+
46
+
47
+ def next_token
48
+ return if @ss.eos?
49
+
50
+ # skips empty actions
51
+ until token = _next_token or @ss.eos?; end
52
+ token
53
+ end
54
+
55
+ def _next_token
56
+ text = @ss.peek(1)
57
+ @lineno += 1 if text == "\n"
58
+ token = case @state
59
+ when nil
60
+ case
61
+ when (text = @ss.scan(/url\([\s]*("([^\n\r\f\\"]|\\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*"|'([^\n\r\f\\']|\\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*')[\s]*\)/i))
62
+ action { [:URI, st(text)] }
63
+
64
+ when (text = @ss.scan(/url\([\s]*([!#\$%&*-~]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*[\s]*\)/i))
65
+ action { [:URI, st(text)] }
66
+
67
+ when (text = @ss.scan(/U\+[0-9a-fA-F?]{1,6}(-[0-9a-fA-F]{1,6})?/i))
68
+ action {[:UNICODE_RANGE, st(text)] }
69
+
70
+ when (text = @ss.scan(/[\s]*\/\*(.|[\s]*)*?\*\/[\s]*/i))
71
+ action { next_token }
72
+
73
+ when (text = @ss.scan(/[-@]?([_A-Za-z]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]|[.])*\(\s*/i))
74
+ action { [:FUNCTION, st(text)] }
75
+
76
+ when (text = @ss.scan(/[\s]*@import[\s]*/i))
77
+ action { [:IMPORT_SYM, st(text)] }
78
+
79
+ when (text = @ss.scan(/[\s]*@page[\s]*/i))
80
+ action { [:PAGE_SYM, st(text)] }
81
+
82
+ when (text = @ss.scan(/[\s]*@charset[\s]*/i))
83
+ action { [:CHARSET_SYM, st(text)] }
84
+
85
+ when (text = @ss.scan(/[\s]*@media[\s]*/i))
86
+ action { [:MEDIA_SYM, st(text)] }
87
+
88
+ when (text = @ss.scan(/[\s]*!([\s]*|[\s]*\/\*(.|[\s]*)*?\*\/[\s]*)important[\s]*/i))
89
+ action { [:IMPORTANT_SYM, st(text)] }
90
+
91
+ when (text = @ss.scan(/[-@]?([_A-Za-z]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*/i))
92
+ action { [:IDENT, st(text)] }
93
+
94
+ when (text = @ss.scan(/\#([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])+/i))
95
+ action { [:HASH, st(text)] }
96
+
97
+ when (text = @ss.scan(/[\s]*~=[\s]*/i))
98
+ action { [:INCLUDES, st(text)] }
99
+
100
+ when (text = @ss.scan(/[\s]*\|=[\s]*/i))
101
+ action { [:DASHMATCH, st(text)] }
102
+
103
+ when (text = @ss.scan(/[\s]*\^=[\s]*/i))
104
+ action { [:PREFIXMATCH, st(text)] }
105
+
106
+ when (text = @ss.scan(/[\s]*\$=[\s]*/i))
107
+ action { [:SUFFIXMATCH, st(text)] }
108
+
109
+ when (text = @ss.scan(/[\s]*\*=[\s]*/i))
110
+ action { [:SUBSTRINGMATCH, st(text)] }
111
+
112
+ when (text = @ss.scan(/[\s]*!=[\s]*/i))
113
+ action { [:NOT_EQUAL, st(text)] }
114
+
115
+ when (text = @ss.scan(/[\s]*=[\s]*/i))
116
+ action { [:EQUAL, st(text)] }
117
+
118
+ when (text = @ss.scan(/[\s]*\)/i))
119
+ action { [:RPAREN, st(text)] }
120
+
121
+ when (text = @ss.scan(/[\s]*\([\s]*/i))
122
+ action { [:LPAREN, st(text)] }
123
+
124
+ when (text = @ss.scan(/\[[\s]*/i))
125
+ action { [:LSQUARE, st(text)] }
126
+
127
+ when (text = @ss.scan(/[\s]*\]/i))
128
+ action { [:RSQUARE, st(text)] }
129
+
130
+ when (text = @ss.scan(/[\s]*\+[\s]*/i))
131
+ action { [:PLUS, st(text)] }
132
+
133
+ when (text = @ss.scan(/[\s]*\{[\s]*/i))
134
+ action { [:LBRACE, st(text)] }
135
+
136
+ when (text = @ss.scan(/[\s]*\}[\s]*/i))
137
+ action { [:RBRACE, st(text)] }
138
+
139
+ when (text = @ss.scan(/[\s]*>[\s]*/i))
140
+ action { [:GREATER, st(text)] }
141
+
142
+ when (text = @ss.scan(/[\s]*,[\s]*/i))
143
+ action { [:COMMA, st(',')] }
144
+
145
+ when (text = @ss.scan(/[\s]*;[\s]*/i))
146
+ action { [:SEMI, st(';')] }
147
+
148
+ when (text = @ss.scan(/\*/i))
149
+ action { [:STAR, st(text)] }
150
+
151
+ when (text = @ss.scan(/[\s]*~[\s]*/i))
152
+ action { [:TILDE, st(text)] }
153
+
154
+ when (text = @ss.scan(/\:not\([\s]*/i))
155
+ action { [:NOT, st(text)] }
156
+
157
+ when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)em[\s]*/i))
158
+ action { [:EMS, st(text)] }
159
+
160
+ when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)ex[\s]*/i))
161
+ action { [:EXS, st(text)] }
162
+
163
+ when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(px|cm|mm|in|pt|pc)[\s]*/i))
164
+ action { [:LENGTH, st(text)] }
165
+
166
+ when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(deg|rad|grad)[\s]*/i))
167
+ action { [:ANGLE, st(text)] }
168
+
169
+ when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(ms|s)[\s]*/i))
170
+ action { [:TIME, st(text)] }
171
+
172
+ when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)[k]?hz[\s]*/i))
173
+ action { [:FREQ, st(text)] }
174
+
175
+ when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)%[\s]*/i))
176
+ action { [:PERCENTAGE, st(text)] }
177
+
178
+ when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)[\s]*/i))
179
+ action { [:NUMBER, st(text)] }
180
+
181
+ when (text = @ss.scan(/[\s]*\/\/[\s]*/i))
182
+ action { [:DOUBLESLASH, st(text)] }
183
+
184
+ when (text = @ss.scan(/[\s]*\/[\s]*/i))
185
+ action { [:SLASH, st('/')] }
186
+
187
+ when (text = @ss.scan(/<!--/i))
188
+ action { [:CDO, st(text)] }
189
+
190
+ when (text = @ss.scan(/-->/i))
191
+ action { [:CDC, st(text)] }
192
+
193
+ when (text = @ss.scan(/[\s]*\-(?![-@]?([_A-Za-z]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*)[\s]*/i))
194
+ action { [:MINUS, st(text)] }
195
+
196
+ when (text = @ss.scan(/[\s]*\+[\s]*/i))
197
+ action { [:PLUS, st(text)] }
198
+
199
+ when (text = @ss.scan(/[\s]+/i))
200
+ action { [:S, st(text)] }
201
+
202
+ when (text = @ss.scan(/("([^\n\r\f\\"]|\\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*"|'([^\n\r\f\\']|\\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*')/i))
203
+ action { [:STRING, st(text)] }
204
+
205
+ when (text = @ss.scan(/("([^\n\r\f\\"]|\\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*|'([^\n\r\f\\']|\\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*)/i))
206
+ action { [:INVALID, st(text)] }
207
+
208
+ when (text = @ss.scan(/./i))
209
+ action { [st(text), st(text)] }
210
+
211
+ else
212
+ text = @ss.string[@ss.pos .. -1]
213
+ raise ScanError, "can not match: '" + text + "'"
214
+ end # if
215
+
216
+ else
217
+ raise ScanError, "undefined state: '" + state.to_s + "'"
218
+ end # case state
219
+ token
220
+ end # def _next_token
221
+
222
+ def st o
223
+ @st ||= Hash.new { |h,k| h[k] = k }
224
+ @st[o]
225
+ end # class
226
+
227
+ end
228
+ end
229
+ end
230
+
231
+ # vim: syntax=lex