sass 3.3.0.alpha.149 → 3.3.0.alpha.162
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.
- data/REVISION +1 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass/css.rb +1 -1
- data/lib/sass/engine.rb +4 -4
- data/lib/sass/environment.rb +1 -1
- data/lib/sass/exec.rb +1 -1
- data/lib/sass/media.rb +15 -15
- data/lib/sass/script.rb +32 -7
- data/lib/sass/script/css_lexer.rb +2 -2
- data/lib/sass/script/css_parser.rb +1 -1
- data/lib/sass/script/functions.rb +246 -232
- data/lib/sass/script/lexer.rb +24 -32
- data/lib/sass/script/parser.rb +84 -65
- data/lib/sass/script/tree.rb +14 -0
- data/lib/sass/script/tree/funcall.rb +242 -0
- data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +30 -13
- data/lib/sass/script/tree/list_literal.rb +65 -0
- data/lib/sass/script/tree/literal.rb +46 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +10 -10
- data/lib/sass/script/{operation.rb → tree/operation.rb} +16 -27
- data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +4 -4
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +7 -8
- data/lib/sass/script/tree/variable.rb +56 -0
- data/lib/sass/script/value.rb +10 -0
- data/lib/sass/script/{arg_list.rb → value/arg_list.rb} +5 -20
- data/lib/sass/script/value/base.rb +222 -0
- data/lib/sass/script/{bool.rb → value/bool.rb} +2 -2
- data/lib/sass/script/{color.rb → value/color.rb} +22 -20
- data/lib/sass/script/{list.rb → value/list.rb} +15 -28
- data/lib/sass/script/{null.rb → value/null.rb} +3 -3
- data/lib/sass/script/{number.rb → value/number.rb} +19 -19
- data/lib/sass/script/{string.rb → value/string.rb} +7 -7
- data/lib/sass/scss/parser.rb +14 -4
- data/lib/sass/selector.rb +26 -26
- data/lib/sass/selector/abstract_sequence.rb +1 -1
- data/lib/sass/selector/simple.rb +6 -7
- data/lib/sass/source/position.rb +13 -0
- data/lib/sass/supports.rb +4 -4
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +7 -7
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +2 -2
- data/lib/sass/tree/each_node.rb +2 -2
- data/lib/sass/tree/extend_node.rb +4 -4
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +4 -4
- data/lib/sass/tree/media_node.rb +3 -3
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +6 -6
- data/lib/sass/tree/prop_node.rb +23 -15
- data/lib/sass/tree/return_node.rb +2 -2
- data/lib/sass/tree/rule_node.rb +3 -3
- data/lib/sass/tree/variable_node.rb +2 -2
- data/lib/sass/tree/visitors/convert.rb +2 -2
- data/lib/sass/tree/visitors/deep_copy.rb +5 -5
- data/lib/sass/tree/visitors/perform.rb +7 -7
- data/lib/sass/tree/visitors/set_options.rb +6 -6
- data/lib/sass/tree/visitors/to_css.rb +1 -1
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util.rb +2 -2
- data/test/sass/engine_test.rb +6 -6
- data/test/sass/functions_test.rb +20 -20
- data/test/sass/plugin_test.rb +2 -2
- data/test/sass/script_test.rb +38 -29
- data/test/test_helper.rb +1 -1
- metadata +23 -19
- data/lib/sass/script/funcall.rb +0 -238
- data/lib/sass/script/literal.rb +0 -221
- data/lib/sass/script/variable.rb +0 -58
data/lib/sass/script/lexer.rb
CHANGED
@@ -16,26 +16,29 @@ module Sass
|
|
16
16
|
# `value`: \[`Object`\]
|
17
17
|
# : The Ruby object corresponding to the value of the token.
|
18
18
|
#
|
19
|
-
# `
|
20
|
-
# : The
|
21
|
-
#
|
22
|
-
# `offset`: \[`Fixnum`\]
|
23
|
-
# : The number of characters into the line the SassScript token appeared (1-based).
|
19
|
+
# `source_range`: [`Sass::Source::Range`\]
|
20
|
+
# : The range in the source file in which the token appeared.
|
24
21
|
#
|
25
22
|
# `pos`: \[`Fixnum`\]
|
26
23
|
# : The scanner position at which the SassScript token appeared.
|
27
|
-
Token = Struct.new(:type, :value, :
|
24
|
+
Token = Struct.new(:type, :value, :source_range, :pos)
|
28
25
|
|
29
26
|
# The line number of the lexer's current position.
|
30
27
|
#
|
31
28
|
# @return [Fixnum]
|
32
|
-
|
29
|
+
def line
|
30
|
+
return @line unless @tok
|
31
|
+
@tok.source_range.start_pos.line
|
32
|
+
end
|
33
33
|
|
34
34
|
# The number of bytes into the current line
|
35
35
|
# of the lexer's current position (1-based).
|
36
36
|
#
|
37
37
|
# @return [Fixnum]
|
38
|
-
|
38
|
+
def offset
|
39
|
+
return @offset unless @tok
|
40
|
+
@tok.source_range.start_pos.offset
|
41
|
+
end
|
39
42
|
|
40
43
|
# A hash from operator strings to the corresponding token types.
|
41
44
|
OPERATORS = {
|
@@ -174,8 +177,8 @@ module Sass
|
|
174
177
|
def unpeek!
|
175
178
|
if @tok
|
176
179
|
@scanner.pos = @tok.pos
|
177
|
-
@line = @tok.line
|
178
|
-
@offset = @tok.offset
|
180
|
+
@line = @tok.source_range.start_pos.line
|
181
|
+
@offset = @tok.source_range.start_pos.offset
|
179
182
|
end
|
180
183
|
end
|
181
184
|
|
@@ -219,12 +222,11 @@ module Sass
|
|
219
222
|
|
220
223
|
def read_token
|
221
224
|
return if done?
|
225
|
+
start_pos = source_position
|
226
|
+
start_index = @scanner.pos
|
222
227
|
return unless value = token
|
223
|
-
type, val
|
224
|
-
|
225
|
-
|
226
|
-
val.line = @line if val.is_a?(Script::Node)
|
227
|
-
Token.new(type, val, @line, @offset - size, @scanner.pos - size)
|
228
|
+
type, val = value
|
229
|
+
Token.new(type, val, range(start_pos), @scanner.pos - @scanner.matched_size)
|
228
230
|
end
|
229
231
|
|
230
232
|
def whitespace
|
@@ -259,7 +261,6 @@ module Sass
|
|
259
261
|
end
|
260
262
|
|
261
263
|
def string(re, open)
|
262
|
-
start_pos = source_position
|
263
264
|
return unless scan(STRING_REGULAR_EXPRESSIONS[[re, open]])
|
264
265
|
if @scanner[2] == '#{' #'
|
265
266
|
@scanner.pos -= 2 # Don't actually consume the #{
|
@@ -268,50 +269,41 @@ module Sass
|
|
268
269
|
end
|
269
270
|
str =
|
270
271
|
if re == :uri
|
271
|
-
Script::String.new("#{'url(' unless open}#{@scanner[1]}#{')' unless @scanner[2] == '#{'}")
|
272
|
+
Script::Value::String.new("#{'url(' unless open}#{@scanner[1]}#{')' unless @scanner[2] == '#{'}")
|
272
273
|
else
|
273
|
-
Script::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string)
|
274
|
+
Script::Value::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string)
|
274
275
|
end
|
275
|
-
str.source_range = range(start_pos)
|
276
276
|
[:string, str]
|
277
277
|
end
|
278
278
|
|
279
279
|
def number
|
280
|
-
start_pos = source_position
|
281
280
|
return unless scan(REGULAR_EXPRESSIONS[:number])
|
282
281
|
value = @scanner[2] ? @scanner[2].to_f : @scanner[3].to_i
|
283
282
|
value = -value if @scanner[1]
|
284
|
-
script_number = Script::Number.new(value, Array(@scanner[4]))
|
285
|
-
script_number.source_range = range(start_pos)
|
283
|
+
script_number = Script::Value::Number.new(value, Array(@scanner[4]))
|
286
284
|
[:number, script_number]
|
287
285
|
end
|
288
286
|
|
289
287
|
def color
|
290
|
-
start_pos = source_position
|
291
288
|
return unless s = scan(REGULAR_EXPRESSIONS[:color])
|
292
289
|
raise Sass::SyntaxError.new(<<MESSAGE.rstrip) unless s.size == 4 || s.size == 7
|
293
290
|
Colors must have either three or six digits: '#{s}'
|
294
291
|
MESSAGE
|
295
292
|
value = s.scan(/^#(..?)(..?)(..?)$/).first.
|
296
293
|
map {|num| num.ljust(2, num).to_i(16)}
|
297
|
-
script_color = Script::Color.new(value)
|
298
|
-
script_color.source_range = range(start_pos)
|
294
|
+
script_color = Script::Value::Color.new(value)
|
299
295
|
[:color, script_color]
|
300
296
|
end
|
301
297
|
|
302
298
|
def bool
|
303
|
-
start_pos = source_position
|
304
299
|
return unless s = scan(REGULAR_EXPRESSIONS[:bool])
|
305
|
-
script_bool = Script::Bool.new(s == 'true')
|
306
|
-
script_bool.source_range = range(start_pos)
|
300
|
+
script_bool = Script::Value::Bool.new(s == 'true')
|
307
301
|
[:bool, script_bool]
|
308
302
|
end
|
309
303
|
|
310
304
|
def null
|
311
|
-
start_pos = source_position
|
312
305
|
return unless scan(REGULAR_EXPRESSIONS[:null])
|
313
|
-
script_null = Script::Null.new
|
314
|
-
script_null.source_range = range(start_pos)
|
306
|
+
script_null = Script::Value::Null.new
|
315
307
|
[:null, script_null]
|
316
308
|
end
|
317
309
|
|
@@ -331,7 +323,7 @@ MESSAGE
|
|
331
323
|
|
332
324
|
def special_val
|
333
325
|
return unless scan(/!important/i)
|
334
|
-
[:string, Script::String.new("!important")]
|
326
|
+
[:string, Script::Value::String.new("!important")]
|
335
327
|
end
|
336
328
|
|
337
329
|
def ident_op
|
data/lib/sass/script/parser.rb
CHANGED
@@ -3,7 +3,7 @@ require 'sass/script/lexer'
|
|
3
3
|
module Sass
|
4
4
|
module Script
|
5
5
|
# The parser for SassScript.
|
6
|
-
# It parses a string of code into a tree of {Script::Node}s.
|
6
|
+
# It parses a string of code into a tree of {Script::Tree::Node}s.
|
7
7
|
class Parser
|
8
8
|
# The line number of the parser's current position.
|
9
9
|
#
|
@@ -36,14 +36,12 @@ module Sass
|
|
36
36
|
# which signals the end of an interpolated segment,
|
37
37
|
# it returns rather than throwing an error.
|
38
38
|
#
|
39
|
-
# @return [Script::Node] The root node of the parse tree
|
39
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
40
40
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
41
41
|
def parse_interpolated
|
42
|
-
start_pos = source_position
|
43
42
|
expr = assert_expr :expr
|
44
43
|
assert_tok :end_interpolation
|
45
44
|
expr.options = @options
|
46
|
-
expr.source_range = range(start_pos)
|
47
45
|
expr
|
48
46
|
rescue Sass::SyntaxError => e
|
49
47
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -52,14 +50,12 @@ module Sass
|
|
52
50
|
|
53
51
|
# Parses a SassScript expression.
|
54
52
|
#
|
55
|
-
# @return [Script::Node] The root node of the parse tree
|
53
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
56
54
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
57
55
|
def parse
|
58
|
-
start_pos = source_position
|
59
56
|
expr = assert_expr :expr
|
60
57
|
assert_done
|
61
58
|
expr.options = @options
|
62
|
-
expr.source_range = range(start_pos)
|
63
59
|
expr
|
64
60
|
rescue Sass::SyntaxError => e
|
65
61
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -70,7 +66,7 @@ module Sass
|
|
70
66
|
# ending it when it encounters one of the given identifier tokens.
|
71
67
|
#
|
72
68
|
# @param [#include?(String)] A set of strings that delimit the expression.
|
73
|
-
# @return [Script::Node] The root node of the parse tree
|
69
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
74
70
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
75
71
|
def parse_until(tokens)
|
76
72
|
@stop_at = tokens
|
@@ -85,7 +81,7 @@ module Sass
|
|
85
81
|
|
86
82
|
# Parses the argument list for a mixin include.
|
87
83
|
#
|
88
|
-
# @return [(Array<Script::Node>, {String => Script::Node}, Script::Node)]
|
84
|
+
# @return [(Array<Script::Tree::Node>, {String => Script::Tree::Node}, Script::Tree::Node)]
|
89
85
|
# The root nodes of the positional arguments, keyword arguments, and
|
90
86
|
# splat argument. Keyword arguments are in a hash from names to values.
|
91
87
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
@@ -108,7 +104,7 @@ module Sass
|
|
108
104
|
|
109
105
|
# Parses the argument list for a mixin definition.
|
110
106
|
#
|
111
|
-
# @return [(Array<Script::Node>, Script::Node)]
|
107
|
+
# @return [(Array<Script::Tree::Node>, Script::Tree::Node)]
|
112
108
|
# The root nodes of the arguments, and the splat argument.
|
113
109
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
114
110
|
def parse_mixin_definition_arglist
|
@@ -128,7 +124,7 @@ module Sass
|
|
128
124
|
|
129
125
|
# Parses the argument list for a function definition.
|
130
126
|
#
|
131
|
-
# @return [(Array<Script::Node>, Script::Node)]
|
127
|
+
# @return [(Array<Script::Tree::Node>, Script::Tree::Node)]
|
132
128
|
# The root nodes of the arguments, and the splat argument.
|
133
129
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
134
130
|
def parse_function_definition_arglist
|
@@ -149,7 +145,7 @@ module Sass
|
|
149
145
|
# Parse a single string value, possibly containing interpolation.
|
150
146
|
# Doesn't assert that the scanner is finished after parsing.
|
151
147
|
#
|
152
|
-
# @return [Script::Node] The root node of the parse tree.
|
148
|
+
# @return [Script::Tree::Node] The root node of the parse tree.
|
153
149
|
# @raise [Sass::SyntaxError] if the string isn't valid SassScript
|
154
150
|
def parse_string
|
155
151
|
unless (peek = @lexer.peek) &&
|
@@ -170,7 +166,7 @@ module Sass
|
|
170
166
|
# Parses a SassScript expression.
|
171
167
|
#
|
172
168
|
# @overload parse(str, line, offset, filename = nil)
|
173
|
-
# @return [Script::Node] The root node of the parse tree
|
169
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
174
170
|
# @see Parser#initialize
|
175
171
|
# @see Parser#parse
|
176
172
|
def self.parse(*args)
|
@@ -225,9 +221,7 @@ module Sass
|
|
225
221
|
end
|
226
222
|
|
227
223
|
start_pos = source_position
|
228
|
-
e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
|
229
|
-
e.line = start_pos.line
|
230
|
-
e.source_range = range(start_pos)
|
224
|
+
e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type), start_pos)
|
231
225
|
end
|
232
226
|
e
|
233
227
|
end
|
@@ -239,10 +233,8 @@ RUBY
|
|
239
233
|
def unary_#{op}
|
240
234
|
return #{sub} unless tok = try_tok(:#{op})
|
241
235
|
interp = try_op_before_interp(tok) and return interp
|
242
|
-
|
243
|
-
|
244
|
-
op.line = line
|
245
|
-
op
|
236
|
+
start_pos = source_position
|
237
|
+
node(Tree::UnaryOperation.new(assert_expr(:unary_#{op}), :#{op}), start_pos)
|
246
238
|
end
|
247
239
|
RUBY
|
248
240
|
end
|
@@ -254,10 +246,6 @@ RUBY
|
|
254
246
|
Sass::Source::Position.new(line, offset)
|
255
247
|
end
|
256
248
|
|
257
|
-
def token_start_position(token)
|
258
|
-
Sass::Source::Position.new(token.line, token.offset)
|
259
|
-
end
|
260
|
-
|
261
249
|
def range(start_pos, end_pos=source_position)
|
262
250
|
Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
|
263
251
|
end
|
@@ -269,15 +257,15 @@ RUBY
|
|
269
257
|
interp = try_ops_after_interp([:comma], :expr) and return interp
|
270
258
|
start_pos = source_position
|
271
259
|
return unless e = interpolation
|
272
|
-
list = node(
|
260
|
+
list = node(Sass::Script::Tree::ListLiteral.new([e], :comma), start_pos)
|
273
261
|
while tok = try_tok(:comma)
|
274
262
|
if interp = try_op_before_interp(tok, list)
|
275
263
|
return interp unless other_interp = try_ops_after_interp([:comma], :expr, interp)
|
276
264
|
return other_interp
|
277
265
|
end
|
278
|
-
list.
|
266
|
+
list.elements << assert_expr(:interpolation)
|
279
267
|
end
|
280
|
-
list.
|
268
|
+
list.elements.size == 1 ? list.elements.first : list
|
281
269
|
end
|
282
270
|
|
283
271
|
production :equals, :interpolation, :single_eq
|
@@ -285,10 +273,10 @@ RUBY
|
|
285
273
|
def try_op_before_interp(op, prev = nil)
|
286
274
|
return unless @lexer.peek && @lexer.peek.type == :begin_interpolation
|
287
275
|
wb = @lexer.whitespace?(op)
|
288
|
-
str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
|
289
|
-
|
290
|
-
|
291
|
-
|
276
|
+
str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]), op.source_range)
|
277
|
+
interp = node(
|
278
|
+
Script::Tree::Interpolation.new(prev, str, nil, wb, !:wa, :originally_text),
|
279
|
+
(prev || str).source_range.start_pos)
|
292
280
|
interpolation(interp)
|
293
281
|
end
|
294
282
|
|
@@ -298,12 +286,11 @@ RUBY
|
|
298
286
|
interp = try_op_before_interp(op, prev) and return interp
|
299
287
|
|
300
288
|
wa = @lexer.whitespace?
|
301
|
-
str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
|
289
|
+
str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]), op.source_range)
|
302
290
|
str.line = @lexer.line
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
interp.source_range = range(start_pos)
|
291
|
+
interp = node(
|
292
|
+
Script::Tree::Interpolation.new(prev, str, assert_expr(name), !:wb, wa, :originally_text),
|
293
|
+
(prev || str).source_range.start_pos)
|
307
294
|
return interp
|
308
295
|
end
|
309
296
|
|
@@ -314,8 +301,9 @@ RUBY
|
|
314
301
|
line = @lexer.line
|
315
302
|
mid = parse_interpolated
|
316
303
|
wa = @lexer.whitespace?
|
317
|
-
e =
|
318
|
-
|
304
|
+
e = node(
|
305
|
+
Script::Tree::Interpolation.new(e, mid, space, wb, wa),
|
306
|
+
(e || mid).source_range.start_pos)
|
319
307
|
end
|
320
308
|
e
|
321
309
|
end
|
@@ -327,7 +315,7 @@ RUBY
|
|
327
315
|
while e = or_expr
|
328
316
|
arr << e
|
329
317
|
end
|
330
|
-
arr.size == 1 ? arr.first : node(
|
318
|
+
arr.size == 1 ? arr.first : node(Sass::Script::Tree::ListLiteral.new(arr, :space), start_pos)
|
331
319
|
end
|
332
320
|
|
333
321
|
production :or_expr, :and_expr, :or
|
@@ -347,17 +335,18 @@ RUBY
|
|
347
335
|
return if @stop_at && @stop_at.include?(@lexer.peek.value)
|
348
336
|
|
349
337
|
name = @lexer.next
|
350
|
-
if color = Color::COLOR_NAMES[name.value.downcase]
|
351
|
-
return
|
338
|
+
if color = Sass::Script::Value::Color::COLOR_NAMES[name.value.downcase]
|
339
|
+
return literal_node(Sass::Script::Value::Color.new(color), name.source_range)
|
352
340
|
end
|
353
|
-
|
341
|
+
literal_node(Script::Value::String.new(name.value, :identifier), name.source_range)
|
354
342
|
end
|
355
343
|
|
356
344
|
def funcall
|
357
345
|
return raw unless tok = try_tok(:funcall)
|
358
346
|
args, keywords, splat = fn_arglist || [[], {}]
|
359
347
|
assert_tok(:rparen)
|
360
|
-
node(Script::Funcall.new(tok.value, args, keywords, splat),
|
348
|
+
node(Script::Tree::Funcall.new(tok.value, args, keywords, splat),
|
349
|
+
tok.source_range.start_pos, source_position)
|
361
350
|
end
|
362
351
|
|
363
352
|
def defn_arglist!(must_have_parens)
|
@@ -373,8 +362,7 @@ RUBY
|
|
373
362
|
must_have_default = false
|
374
363
|
loop do
|
375
364
|
c = assert_tok(:const)
|
376
|
-
var = Script::Variable.new(c.value)
|
377
|
-
var.source_range = range(c.offset)
|
365
|
+
var = node(Script::Tree::Variable.new(c.value), c.source_range)
|
378
366
|
if try_tok(:colon)
|
379
367
|
val = assert_expr(:space)
|
380
368
|
must_have_default = true
|
@@ -407,7 +395,7 @@ RUBY
|
|
407
395
|
loop do
|
408
396
|
if @lexer.peek && @lexer.peek.type == :colon
|
409
397
|
name = e
|
410
|
-
@lexer.expected!("comma") unless name.is_a?(Variable)
|
398
|
+
@lexer.expected!("comma") unless name.is_a?(Tree::Variable)
|
411
399
|
assert_tok(:colon)
|
412
400
|
value = assert_expr(subexpr, description)
|
413
401
|
|
@@ -431,17 +419,26 @@ RUBY
|
|
431
419
|
end
|
432
420
|
|
433
421
|
def raw
|
422
|
+
start_pos = source_position
|
434
423
|
return special_fun unless tok = try_tok(:raw)
|
435
|
-
|
424
|
+
literal_node(Script::Value::String.new(tok.value), tok.source_range)
|
436
425
|
end
|
437
426
|
|
438
427
|
def special_fun
|
428
|
+
start_pos = source_position
|
439
429
|
return paren unless tok = try_tok(:special_fun)
|
440
|
-
first =
|
430
|
+
first = literal_node(Script::Value::String.new(tok.value.first),
|
431
|
+
start_pos, start_pos.after(tok.value.first))
|
441
432
|
Sass::Util.enum_slice(tok.value[1..-1], 2).inject(first) do |l, (i, r)|
|
442
|
-
|
443
|
-
|
444
|
-
|
433
|
+
end_pos = i.source_range.end_pos
|
434
|
+
end_pos = end_pos.after(r) if r
|
435
|
+
node(
|
436
|
+
Script::Tree::Interpolation.new(
|
437
|
+
l, i,
|
438
|
+
r && literal_node(Script::Value::String.new(r),
|
439
|
+
i.source_range.end_pos, end_pos),
|
440
|
+
false, false),
|
441
|
+
start_pos, end_pos)
|
445
442
|
end
|
446
443
|
end
|
447
444
|
|
@@ -451,8 +448,9 @@ RUBY
|
|
451
448
|
@in_parens = true
|
452
449
|
start_pos = source_position
|
453
450
|
e = expr
|
451
|
+
end_pos = source_position
|
454
452
|
assert_tok(:rparen)
|
455
|
-
return e || node(
|
453
|
+
return e || node(Sass::Script::Tree::ListLiteral.new([], :space), start_pos, end_pos)
|
456
454
|
ensure
|
457
455
|
@in_parens = was_in_parens
|
458
456
|
end
|
@@ -460,31 +458,27 @@ RUBY
|
|
460
458
|
def variable
|
461
459
|
start_pos = source_position
|
462
460
|
return string unless c = try_tok(:const)
|
463
|
-
node(Variable.new(*c.value), start_pos
|
461
|
+
node(Tree::Variable.new(*c.value), start_pos)
|
464
462
|
end
|
465
463
|
|
466
464
|
def string
|
467
465
|
return number unless first = try_tok(:string)
|
468
|
-
|
469
|
-
|
470
|
-
line = @lexer.line
|
466
|
+
str = literal_node(first.value, first.source_range)
|
467
|
+
return str unless try_tok(:begin_interpolation)
|
471
468
|
mid = parse_interpolated
|
472
469
|
last = assert_expr(:string)
|
473
|
-
|
474
|
-
interp.line = line
|
475
|
-
interp.source_range = range(start_pos)
|
476
|
-
interp
|
470
|
+
node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
|
477
471
|
end
|
478
472
|
|
479
473
|
def number
|
480
474
|
return literal unless tok = try_tok(:number)
|
481
475
|
num = tok.value
|
482
476
|
num.original = num.to_s unless @in_parens
|
483
|
-
num
|
477
|
+
literal_node(num, tok.source_range.start_pos)
|
484
478
|
end
|
485
479
|
|
486
480
|
def literal
|
487
|
-
(t = try_tok(:color, :bool, :null)) && (return t.value)
|
481
|
+
(t = try_tok(:color, :bool, :null)) && (return literal_node(t.value, t.source_range))
|
488
482
|
end
|
489
483
|
|
490
484
|
# It would be possible to have unified #assert and #try methods,
|
@@ -517,10 +511,35 @@ RUBY
|
|
517
511
|
@lexer.expected!(EXPR_NAMES[:default])
|
518
512
|
end
|
519
513
|
|
520
|
-
|
521
|
-
|
514
|
+
# @overload node(value, source_range)
|
515
|
+
# @param value [Sass::Script::Value::Base]
|
516
|
+
# @param source_range [Sass::Source::Range]
|
517
|
+
# @overload node(value, start_pos, end_pos = source_position)
|
518
|
+
# @param value [Sass::Script::Value::Base]
|
519
|
+
# @param start_pos [Sass::Source::Position]
|
520
|
+
# @param end_pos [Sass::Source::Position]
|
521
|
+
def literal_node(value, source_range_or_start_pos, end_pos = source_position)
|
522
|
+
node(Sass::Script::Tree::Literal.new(value), source_range_or_start_pos, end_pos)
|
523
|
+
end
|
524
|
+
|
525
|
+
# @overload node(node, source_range)
|
526
|
+
# @param node [Sass::Script::Tree::Node]
|
527
|
+
# @param source_range [Sass::Source::Range]
|
528
|
+
# @overload node(node, start_pos, end_pos = source_position)
|
529
|
+
# @param node [Sass::Script::Tree::Node]
|
530
|
+
# @param start_pos [Sass::Source::Position]
|
531
|
+
# @param end_pos [Sass::Source::Position]
|
532
|
+
def node(node, source_range_or_start_pos, end_pos = source_position)
|
533
|
+
source_range =
|
534
|
+
if source_range_or_start_pos.is_a?(Sass::Source::Range)
|
535
|
+
source_range_or_start_pos
|
536
|
+
else
|
537
|
+
range(source_range_or_start_pos, end_pos)
|
538
|
+
end
|
539
|
+
|
540
|
+
node.line = source_range.start_pos.line
|
541
|
+
node.source_range = source_range
|
522
542
|
node.filename = @options[:filename]
|
523
|
-
node.source_range = range(start_pos, end_pos) if end_pos
|
524
543
|
node
|
525
544
|
end
|
526
545
|
end
|