blob: f1072f1330efc9db38185357a4ef33d97424a599 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
module CodeRay
module Scanners
class Css < Scanner
register_for :css
module RE
NonASCII = /[\x80-\xFF]/
Hex = /[0-9a-fA-F]/
Unicode = /\\#{Hex}{1,6}(?:\r\n|\s)?/ # differs from standard because it allows uppercase hex too
Escape = /#{Unicode}|\\[^\r\n\f0-9a-fA-F]/
NMChar = /[_a-zA-Z0-9-]|#{NonASCII}|#{Escape}/
NMStart = /[_a-zA-Z]|#{NonASCII}|#{Escape}/
NL = /\r\n|\r|\n|\f/
String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"/
String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'/
String = /#{String1}|#{String2}/
Invalid1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*/
Invalid2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*/
Invalid = /#{Invalid1}|#{Invalid2}/
W = /\s+/
S = W
HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/
Color = /#{HexColor}/
Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/
Name = /#{NMChar}+/
Ident = /-?#{NMStart}#{NMChar}*/
AtKeyword = /@#{Ident}/
Percentage = /#{Num}%/
reldimensions = %w[em ex px]
absdimensions = %w[in cm mm pt pc]
Unit = /#{(reldimensions + absdimensions).join('|')}/
Dimension = /#{Num}#{Unit}/
Comment = %r! /\* (?: .*? \*/ | .* ) !mx
URL = /url\((?:[^)\n\r\f]|\\\))*\)/
Id = /##{Name}/
Class = /\.#{Name}/
end
def scan_tokens tokens, options
states = [:initial]
i = 0
until eos?
kind = nil
match = nil
if states.last == :comment
if scan /(?:[^\n\r\f*]|\*(?!\/))+/
kind = :comment
elsif scan /\*\//
kind = :comment
states.pop
elsif scan RE::S
kind = :space
end
elsif scan RE::S
kind = :space
elsif scan /\/\*/
kind = :comment
states.push :comment
elsif scan RE::String
kind = :string
elsif scan RE::AtKeyword
kind = :reserved
elsif scan RE::Invalid
kind = :error
elsif scan RE::URL
kind = :string
elsif scan RE::Dimension
kind = :float
elsif scan RE::Percentage
kind = :float
elsif scan RE::Num
kind = :float
elsif scan /\{/
kind = :operator
states.push :block
elsif scan /\}/
if states.last == :block
kind = :operator
states.pop
else
kind = :error
end
elsif
case states.last
when :initial
if scan RE::Class
kind = :class
elsif scan RE::Id
kind = :constant
elsif scan RE::Ident
kind = :label
elsif scan RE::Name
kind = :identifier
end
when :block
if scan RE::Color
kind = :color
elsif scan RE::Ident
kind = :definition
elsif scan RE::Name
kind = :symbol
end
else
raise_inspect 'Unknown state', tokens
end
elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) /x)
kind = :operator
else
getch
kind = :error
end
match ||= matched
if $DEBUG and not kind
raise_inspect 'Error token %p in line %d' %
[[match, kind], line], tokens
end
raise_inspect 'Empty token', tokens unless match
tokens << [match, kind]
end
tokens
end
end
end
end
|