sass 3.2.7 → 3.3.0.rc.1
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/MIT-LICENSE +2 -2
- data/README.md +14 -2
- data/Rakefile +25 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/lib/sass/cache_stores/base.rb +4 -2
- data/lib/sass/cache_stores/chain.rb +2 -1
- data/lib/sass/cache_stores/filesystem.rb +2 -6
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +1 -0
- data/lib/sass/css.rb +10 -10
- data/lib/sass/engine.rb +403 -150
- data/lib/sass/environment.rb +136 -57
- data/lib/sass/error.rb +7 -7
- data/lib/sass/exec.rb +123 -39
- data/lib/sass/features.rb +41 -0
- data/lib/sass/importers/base.rb +33 -2
- data/lib/sass/importers/deprecated_path.rb +45 -0
- data/lib/sass/importers/filesystem.rb +25 -14
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +3 -3
- data/lib/sass/logger/log_level.rb +4 -6
- data/lib/sass/media.rb +19 -19
- data/lib/sass/plugin/compiler.rb +141 -101
- data/lib/sass/plugin/configuration.rb +18 -22
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +24 -8
- data/lib/sass/plugin.rb +4 -2
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script/css_lexer.rb +9 -4
- data/lib/sass/script/css_parser.rb +6 -2
- data/lib/sass/script/functions.rb +1343 -590
- data/lib/sass/script/lexer.rb +84 -52
- data/lib/sass/script/parser.rb +217 -97
- data/lib/sass/script/tree/funcall.rb +290 -0
- data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +34 -13
- data/lib/sass/script/tree/list_literal.rb +80 -0
- data/lib/sass/script/tree/literal.rb +47 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +22 -12
- data/lib/sass/script/{operation.rb → tree/operation.rb} +17 -25
- data/lib/sass/script/tree/selector.rb +30 -0
- data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +5 -4
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +14 -9
- data/lib/sass/script/tree/variable.rb +57 -0
- data/lib/sass/script/tree.rb +16 -0
- data/lib/sass/script/{arg_list.rb → value/arg_list.rb} +4 -24
- data/lib/sass/script/value/base.rb +248 -0
- data/lib/sass/script/value/bool.rb +36 -0
- data/lib/sass/script/{color.rb → value/color.rb} +239 -195
- data/lib/sass/script/value/helpers.rb +155 -0
- data/lib/sass/script/value/list.rb +119 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/value/null.rb +45 -0
- data/lib/sass/script/{number.rb → value/number.rb} +91 -65
- data/lib/sass/script/{string.rb → value/string.rb} +9 -11
- data/lib/sass/script/value.rb +11 -0
- data/lib/sass/script.rb +35 -8
- data/lib/sass/scss/css_parser.rb +2 -1
- data/lib/sass/scss/parser.rb +338 -170
- data/lib/sass/scss/rx.rb +5 -6
- data/lib/sass/scss/script_lexer.rb +1 -0
- data/lib/sass/scss/script_parser.rb +1 -0
- data/lib/sass/scss/static_parser.rb +23 -6
- data/lib/sass/selector/abstract_sequence.rb +2 -2
- data/lib/sass/selector/comma_sequence.rb +21 -16
- data/lib/sass/selector/sequence.rb +60 -34
- data/lib/sass/selector/simple.rb +11 -12
- data/lib/sass/selector/simple_sequence.rb +55 -33
- data/lib/sass/selector.rb +52 -48
- data/lib/sass/source/map.rb +211 -0
- data/lib/sass/source/position.rb +39 -0
- data/lib/sass/source/range.rb +41 -0
- data/lib/sass/stack.rb +120 -0
- data/lib/sass/supports.rb +12 -13
- data/lib/sass/tree/at_root_node.rb +82 -0
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +11 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +13 -2
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +13 -6
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +5 -4
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +4 -5
- data/lib/sass/tree/media_node.rb +4 -14
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +21 -8
- data/lib/sass/tree/node.rb +29 -12
- data/lib/sass/tree/prop_node.rb +38 -18
- data/lib/sass/tree/return_node.rb +3 -2
- data/lib/sass/tree/root_node.rb +19 -3
- data/lib/sass/tree/rule_node.rb +25 -17
- data/lib/sass/tree/supports_node.rb +0 -13
- data/lib/sass/tree/trace_node.rb +2 -1
- data/lib/sass/tree/variable_node.rb +9 -3
- data/lib/sass/tree/visitors/base.rb +6 -6
- data/lib/sass/tree/visitors/check_nesting.rb +12 -9
- data/lib/sass/tree/visitors/convert.rb +63 -38
- data/lib/sass/tree/visitors/cssize.rb +63 -23
- data/lib/sass/tree/visitors/deep_copy.rb +6 -5
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +256 -151
- data/lib/sass/tree/visitors/set_options.rb +6 -6
- data/lib/sass/tree/visitors/to_css.rb +231 -81
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util/multibyte_string_scanner.rb +2 -0
- data/lib/sass/util/normalized_map.rb +65 -0
- data/lib/sass/util/ordered_hash.rb +188 -0
- data/lib/sass/util/subset_map.rb +3 -2
- data/lib/sass/util/test.rb +9 -0
- data/lib/sass/util.rb +220 -34
- data/lib/sass/version.rb +9 -9
- data/lib/sass.rb +14 -7
- data/test/sass/compiler_test.rb +213 -0
- data/test/sass/conversion_test.rb +235 -9
- data/test/sass/engine_test.rb +230 -60
- data/test/sass/exec_test.rb +86 -0
- data/test/sass/extend_test.rb +215 -147
- data/test/sass/functions_test.rb +584 -99
- data/test/sass/importer_test.rb +165 -17
- data/test/sass/plugin_test.rb +19 -13
- data/test/sass/script_conversion_test.rb +40 -0
- data/test/sass/script_test.rb +231 -21
- data/test/sass/scss/css_test.rb +14 -5
- data/test/sass/scss/scss_test.rb +1266 -66
- data/test/sass/source_map_test.rb +879 -0
- data/test/sass/templates/bork5.sass +3 -0
- data/test/sass/util/normalized_map_test.rb +30 -0
- data/test/sass/util_test.rb +90 -0
- data/test/sass/value_helpers_test.rb +181 -0
- data/test/test_helper.rb +7 -2
- metadata +316 -291
- data/lib/sass/script/bool.rb +0 -18
- data/lib/sass/script/funcall.rb +0 -231
- data/lib/sass/script/list.rb +0 -84
- data/lib/sass/script/literal.rb +0 -239
- data/lib/sass/script/null.rb +0 -34
- data/lib/sass/script/variable.rb +0 -58
- data/test/Gemfile +0 -3
- data/vendor/listen/CHANGELOG.md +0 -221
- data/vendor/listen/CONTRIBUTING.md +0 -38
- data/vendor/listen/Gemfile +0 -30
- data/vendor/listen/Guardfile +0 -8
- data/vendor/listen/LICENSE +0 -20
- data/vendor/listen/README.md +0 -315
- data/vendor/listen/Rakefile +0 -47
- data/vendor/listen/Vagrantfile +0 -96
- data/vendor/listen/lib/listen/adapter.rb +0 -214
- data/vendor/listen/lib/listen/adapters/bsd.rb +0 -112
- data/vendor/listen/lib/listen/adapters/darwin.rb +0 -85
- data/vendor/listen/lib/listen/adapters/linux.rb +0 -113
- data/vendor/listen/lib/listen/adapters/polling.rb +0 -67
- data/vendor/listen/lib/listen/adapters/windows.rb +0 -87
- data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
- data/vendor/listen/lib/listen/directory_record.rb +0 -371
- data/vendor/listen/lib/listen/listener.rb +0 -225
- data/vendor/listen/lib/listen/multi_listener.rb +0 -143
- data/vendor/listen/lib/listen/turnstile.rb +0 -28
- data/vendor/listen/lib/listen/version.rb +0 -3
- data/vendor/listen/lib/listen.rb +0 -40
- data/vendor/listen/listen.gemspec +0 -22
- data/vendor/listen/spec/listen/adapter_spec.rb +0 -183
- data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
- data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1225
- data/vendor/listen/spec/listen/listener_spec.rb +0 -169
- data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
- data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
- data/vendor/listen/spec/listen_spec.rb +0 -73
- data/vendor/listen/spec/spec_helper.rb +0 -21
- data/vendor/listen/spec/support/adapter_helper.rb +0 -629
- data/vendor/listen/spec/support/directory_record_helper.rb +0 -55
- data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
- data/vendor/listen/spec/support/listeners_helper.rb +0 -156
- data/vendor/listen/spec/support/platform_helper.rb +0 -15
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
|
#
|
|
@@ -12,11 +12,18 @@ module Sass
|
|
|
12
12
|
@lexer.line
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
# The column number of the parser's current position.
|
|
16
|
+
#
|
|
17
|
+
# @return [Fixnum]
|
|
18
|
+
def offset
|
|
19
|
+
@lexer.offset
|
|
20
|
+
end
|
|
21
|
+
|
|
15
22
|
# @param str [String, StringScanner] The source text to parse
|
|
16
23
|
# @param line [Fixnum] The line on which the SassScript appears.
|
|
17
|
-
# Used for error reporting
|
|
18
|
-
# @param offset [Fixnum] The
|
|
19
|
-
# Used for error reporting
|
|
24
|
+
# Used for error reporting and sourcemap building
|
|
25
|
+
# @param offset [Fixnum] The character (not byte) offset where the script starts in the line.
|
|
26
|
+
# Used for error reporting and sourcemap building
|
|
20
27
|
# @param options [{Symbol => Object}] An options hash;
|
|
21
28
|
# see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
|
|
22
29
|
def initialize(str, line, offset, options = {})
|
|
@@ -29,7 +36,7 @@ module Sass
|
|
|
29
36
|
# which signals the end of an interpolated segment,
|
|
30
37
|
# it returns rather than throwing an error.
|
|
31
38
|
#
|
|
32
|
-
# @return [Script::Node] The root node of the parse tree
|
|
39
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
|
33
40
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
|
34
41
|
def parse_interpolated
|
|
35
42
|
expr = assert_expr :expr
|
|
@@ -43,7 +50,7 @@ module Sass
|
|
|
43
50
|
|
|
44
51
|
# Parses a SassScript expression.
|
|
45
52
|
#
|
|
46
|
-
# @return [Script::Node] The root node of the parse tree
|
|
53
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
|
47
54
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
|
48
55
|
def parse
|
|
49
56
|
expr = assert_expr :expr
|
|
@@ -58,8 +65,8 @@ module Sass
|
|
|
58
65
|
# Parses a SassScript expression,
|
|
59
66
|
# ending it when it encounters one of the given identifier tokens.
|
|
60
67
|
#
|
|
61
|
-
# @param [#include?(String)] A set of strings that delimit the expression.
|
|
62
|
-
# @return [Script::Node] The root node of the parse tree
|
|
68
|
+
# @param tokens [#include?(String)] A set of strings that delimit the expression.
|
|
69
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
|
63
70
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
|
64
71
|
def parse_until(tokens)
|
|
65
72
|
@stop_at = tokens
|
|
@@ -74,14 +81,17 @@ module Sass
|
|
|
74
81
|
|
|
75
82
|
# Parses the argument list for a mixin include.
|
|
76
83
|
#
|
|
77
|
-
# @return [(Array<Script::Node>,
|
|
84
|
+
# @return [(Array<Script::Tree::Node>,
|
|
85
|
+
# {String => Script::Tree::Node},
|
|
86
|
+
# Script::Tree::Node,
|
|
87
|
+
# Script::Tree::Node)]
|
|
78
88
|
# The root nodes of the positional arguments, keyword arguments, and
|
|
79
|
-
# splat argument. Keyword arguments are in a hash from names to values.
|
|
89
|
+
# splat argument(s). Keyword arguments are in a hash from names to values.
|
|
80
90
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
|
81
91
|
def parse_mixin_include_arglist
|
|
82
92
|
args, keywords = [], {}
|
|
83
93
|
if try_tok(:lparen)
|
|
84
|
-
args, keywords, splat = mixin_arglist
|
|
94
|
+
args, keywords, splat, kwarg_splat = mixin_arglist
|
|
85
95
|
assert_tok(:rparen)
|
|
86
96
|
end
|
|
87
97
|
assert_done
|
|
@@ -89,7 +99,8 @@ module Sass
|
|
|
89
99
|
args.each {|a| a.options = @options}
|
|
90
100
|
keywords.each {|k, v| v.options = @options}
|
|
91
101
|
splat.options = @options if splat
|
|
92
|
-
|
|
102
|
+
kwarg_splat.options = @options if kwarg_splat
|
|
103
|
+
return args, keywords, splat, kwarg_splat
|
|
93
104
|
rescue Sass::SyntaxError => e
|
|
94
105
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
|
95
106
|
raise e
|
|
@@ -97,7 +108,7 @@ module Sass
|
|
|
97
108
|
|
|
98
109
|
# Parses the argument list for a mixin definition.
|
|
99
110
|
#
|
|
100
|
-
# @return [(Array<Script::Node>, Script::Node)]
|
|
111
|
+
# @return [(Array<Script::Tree::Node>, Script::Tree::Node)]
|
|
101
112
|
# The root nodes of the arguments, and the splat argument.
|
|
102
113
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
|
103
114
|
def parse_mixin_definition_arglist
|
|
@@ -117,7 +128,7 @@ module Sass
|
|
|
117
128
|
|
|
118
129
|
# Parses the argument list for a function definition.
|
|
119
130
|
#
|
|
120
|
-
# @return [(Array<Script::Node>, Script::Node)]
|
|
131
|
+
# @return [(Array<Script::Tree::Node>, Script::Tree::Node)]
|
|
121
132
|
# The root nodes of the arguments, and the splat argument.
|
|
122
133
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
|
123
134
|
def parse_function_definition_arglist
|
|
@@ -138,7 +149,7 @@ module Sass
|
|
|
138
149
|
# Parse a single string value, possibly containing interpolation.
|
|
139
150
|
# Doesn't assert that the scanner is finished after parsing.
|
|
140
151
|
#
|
|
141
|
-
# @return [Script::Node] The root node of the parse tree.
|
|
152
|
+
# @return [Script::Tree::Node] The root node of the parse tree.
|
|
142
153
|
# @raise [Sass::SyntaxError] if the string isn't valid SassScript
|
|
143
154
|
def parse_string
|
|
144
155
|
unless (peek = @lexer.peek) &&
|
|
@@ -159,7 +170,7 @@ module Sass
|
|
|
159
170
|
# Parses a SassScript expression.
|
|
160
171
|
#
|
|
161
172
|
# @overload parse(str, line, offset, filename = nil)
|
|
162
|
-
# @return [Script::Node] The root node of the parse tree
|
|
173
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
|
163
174
|
# @see Parser#initialize
|
|
164
175
|
# @see Parser#parse
|
|
165
176
|
def self.parse(*args)
|
|
@@ -205,17 +216,18 @@ module Sass
|
|
|
205
216
|
def production(name, sub, *ops)
|
|
206
217
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
|
207
218
|
def #{name}
|
|
208
|
-
interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect})
|
|
219
|
+
interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect})
|
|
220
|
+
return interp if interp
|
|
209
221
|
return unless e = #{sub}
|
|
210
222
|
while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
|
|
211
223
|
if interp = try_op_before_interp(tok, e)
|
|
212
|
-
|
|
224
|
+
other_interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}, interp)
|
|
225
|
+
return interp unless other_interp
|
|
213
226
|
return other_interp
|
|
214
227
|
end
|
|
215
228
|
|
|
216
|
-
|
|
217
|
-
e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
|
|
218
|
-
e.line = line
|
|
229
|
+
start_pos = source_position
|
|
230
|
+
e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type), start_pos)
|
|
219
231
|
end
|
|
220
232
|
e
|
|
221
233
|
end
|
|
@@ -226,11 +238,10 @@ RUBY
|
|
|
226
238
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
|
227
239
|
def unary_#{op}
|
|
228
240
|
return #{sub} unless tok = try_tok(:#{op})
|
|
229
|
-
interp = try_op_before_interp(tok)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
op
|
|
233
|
-
op
|
|
241
|
+
interp = try_op_before_interp(tok)
|
|
242
|
+
return interp if interp
|
|
243
|
+
start_pos = source_position
|
|
244
|
+
node(Tree::UnaryOperation.new(assert_expr(:unary_#{op}), :#{op}), start_pos)
|
|
234
245
|
end
|
|
235
246
|
RUBY
|
|
236
247
|
end
|
|
@@ -238,22 +249,61 @@ RUBY
|
|
|
238
249
|
|
|
239
250
|
private
|
|
240
251
|
|
|
252
|
+
def source_position
|
|
253
|
+
Sass::Source::Position.new(line, offset)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def range(start_pos, end_pos = source_position)
|
|
257
|
+
Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
|
|
258
|
+
end
|
|
259
|
+
|
|
241
260
|
# @private
|
|
242
261
|
def lexer_class; Lexer; end
|
|
243
262
|
|
|
263
|
+
def map
|
|
264
|
+
start_pos = source_position
|
|
265
|
+
e = interpolation
|
|
266
|
+
return unless e
|
|
267
|
+
return list e, start_pos unless @lexer.peek && @lexer.peek.type == :colon
|
|
268
|
+
|
|
269
|
+
key, value = map_pair(e)
|
|
270
|
+
map = node(Sass::Script::Tree::MapLiteral.new([[key, value]]), start_pos)
|
|
271
|
+
while try_tok(:comma)
|
|
272
|
+
return map unless (pair = map_pair)
|
|
273
|
+
key, value = pair
|
|
274
|
+
map.pairs << [key, value]
|
|
275
|
+
end
|
|
276
|
+
map
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def map_pair(key = nil)
|
|
280
|
+
return unless key ||= interpolation
|
|
281
|
+
assert_tok :colon
|
|
282
|
+
return key, assert_expr(:interpolation)
|
|
283
|
+
end
|
|
284
|
+
|
|
244
285
|
def expr
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return unless e
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
286
|
+
start_pos = source_position
|
|
287
|
+
e = interpolation
|
|
288
|
+
return unless e
|
|
289
|
+
list e, start_pos
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def list(first, start_pos)
|
|
293
|
+
return first unless @lexer.peek && @lexer.peek.type == :comma
|
|
294
|
+
|
|
295
|
+
list = node(Sass::Script::Tree::ListLiteral.new([first], :comma), start_pos)
|
|
296
|
+
while (tok = try_tok(:comma))
|
|
297
|
+
element_before_interp = list.elements.length == 1 ? list.elements.first : list
|
|
298
|
+
if (interp = try_op_before_interp(tok, element_before_interp))
|
|
299
|
+
other_interp = try_ops_after_interp([:comma], :expr, interp)
|
|
300
|
+
return interp unless other_interp
|
|
252
301
|
return other_interp
|
|
253
302
|
end
|
|
254
|
-
|
|
303
|
+
return list unless (e = interpolation)
|
|
304
|
+
list.elements << e
|
|
255
305
|
end
|
|
256
|
-
|
|
306
|
+
list
|
|
257
307
|
end
|
|
258
308
|
|
|
259
309
|
production :equals, :interpolation, :single_eq
|
|
@@ -261,47 +311,57 @@ RUBY
|
|
|
261
311
|
def try_op_before_interp(op, prev = nil)
|
|
262
312
|
return unless @lexer.peek && @lexer.peek.type == :begin_interpolation
|
|
263
313
|
wb = @lexer.whitespace?(op)
|
|
264
|
-
str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
|
|
265
|
-
|
|
266
|
-
interp =
|
|
267
|
-
|
|
314
|
+
str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
|
|
315
|
+
op.source_range)
|
|
316
|
+
interp = node(
|
|
317
|
+
Script::Tree::Interpolation.new(prev, str, nil, wb, !:wa, :originally_text),
|
|
318
|
+
(prev || str).source_range.start_pos)
|
|
268
319
|
interpolation(interp)
|
|
269
320
|
end
|
|
270
321
|
|
|
271
322
|
def try_ops_after_interp(ops, name, prev = nil)
|
|
272
323
|
return unless @lexer.after_interpolation?
|
|
273
|
-
|
|
274
|
-
|
|
324
|
+
op = try_tok(*ops)
|
|
325
|
+
return unless op
|
|
326
|
+
interp = try_op_before_interp(op, prev)
|
|
327
|
+
return interp if interp
|
|
275
328
|
|
|
276
329
|
wa = @lexer.whitespace?
|
|
277
|
-
str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
|
|
330
|
+
str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
|
|
331
|
+
op.source_range)
|
|
278
332
|
str.line = @lexer.line
|
|
279
|
-
interp =
|
|
280
|
-
|
|
281
|
-
|
|
333
|
+
interp = node(
|
|
334
|
+
Script::Tree::Interpolation.new(prev, str, assert_expr(name), !:wb, wa, :originally_text),
|
|
335
|
+
(prev || str).source_range.start_pos)
|
|
336
|
+
interp
|
|
282
337
|
end
|
|
283
338
|
|
|
284
339
|
def interpolation(first = space)
|
|
285
340
|
e = first
|
|
286
|
-
while interp = try_tok(:begin_interpolation)
|
|
341
|
+
while (interp = try_tok(:begin_interpolation))
|
|
287
342
|
wb = @lexer.whitespace?(interp)
|
|
288
|
-
line = @lexer.line
|
|
289
343
|
mid = parse_interpolated
|
|
290
344
|
wa = @lexer.whitespace?
|
|
291
|
-
e =
|
|
292
|
-
|
|
345
|
+
e = node(
|
|
346
|
+
Script::Tree::Interpolation.new(e, mid, space, wb, wa),
|
|
347
|
+
(e || mid).source_range.start_pos)
|
|
293
348
|
end
|
|
294
349
|
e
|
|
295
350
|
end
|
|
296
351
|
|
|
297
352
|
def space
|
|
298
|
-
|
|
299
|
-
|
|
353
|
+
start_pos = source_position
|
|
354
|
+
e = or_expr
|
|
355
|
+
return unless e
|
|
300
356
|
arr = [e]
|
|
301
|
-
while e = or_expr
|
|
357
|
+
while (e = or_expr)
|
|
302
358
|
arr << e
|
|
303
359
|
end
|
|
304
|
-
arr.size == 1
|
|
360
|
+
if arr.size == 1
|
|
361
|
+
arr.first
|
|
362
|
+
else
|
|
363
|
+
node(Sass::Script::Tree::ListLiteral.new(arr, :space), start_pos)
|
|
364
|
+
end
|
|
305
365
|
end
|
|
306
366
|
|
|
307
367
|
production :or_expr, :and_expr, :or
|
|
@@ -321,17 +381,19 @@ RUBY
|
|
|
321
381
|
return if @stop_at && @stop_at.include?(@lexer.peek.value)
|
|
322
382
|
|
|
323
383
|
name = @lexer.next
|
|
324
|
-
if color = Color::COLOR_NAMES[name.value.downcase]
|
|
325
|
-
return
|
|
384
|
+
if (color = Sass::Script::Value::Color::COLOR_NAMES[name.value.downcase])
|
|
385
|
+
return literal_node(Sass::Script::Value::Color.new(color), name.source_range)
|
|
326
386
|
end
|
|
327
|
-
|
|
387
|
+
literal_node(Script::Value::String.new(name.value, :identifier), name.source_range)
|
|
328
388
|
end
|
|
329
389
|
|
|
330
390
|
def funcall
|
|
331
|
-
|
|
332
|
-
|
|
391
|
+
tok = try_tok(:funcall)
|
|
392
|
+
return raw unless tok
|
|
393
|
+
args, keywords, splat, kwarg_splat = fn_arglist
|
|
333
394
|
assert_tok(:rparen)
|
|
334
|
-
node(Script::Funcall.new(tok.value, args, keywords, splat)
|
|
395
|
+
node(Script::Tree::Funcall.new(tok.value, args, keywords, splat, kwarg_splat),
|
|
396
|
+
tok.source_range.start_pos, source_position)
|
|
335
397
|
end
|
|
336
398
|
|
|
337
399
|
def defn_arglist!(must_have_parens)
|
|
@@ -347,12 +409,13 @@ RUBY
|
|
|
347
409
|
must_have_default = false
|
|
348
410
|
loop do
|
|
349
411
|
c = assert_tok(:const)
|
|
350
|
-
var = Script::Variable.new(c.value)
|
|
412
|
+
var = node(Script::Tree::Variable.new(c.value), c.source_range)
|
|
351
413
|
if try_tok(:colon)
|
|
352
414
|
val = assert_expr(:space)
|
|
353
415
|
must_have_default = true
|
|
354
416
|
elsif must_have_default
|
|
355
|
-
raise SyntaxError.new(
|
|
417
|
+
raise SyntaxError.new(
|
|
418
|
+
"Required argument #{var.inspect} must come before any optional arguments.")
|
|
356
419
|
elsif try_tok(:splat)
|
|
357
420
|
splat = var
|
|
358
421
|
break
|
|
@@ -373,48 +436,65 @@ RUBY
|
|
|
373
436
|
end
|
|
374
437
|
|
|
375
438
|
def arglist(subexpr, description)
|
|
376
|
-
return unless e = send(subexpr)
|
|
377
|
-
|
|
378
439
|
args = []
|
|
379
|
-
keywords =
|
|
440
|
+
keywords = Sass::Util::NormalizedMap.new
|
|
441
|
+
e = send(subexpr)
|
|
442
|
+
|
|
443
|
+
return [args, keywords] unless e
|
|
444
|
+
|
|
445
|
+
splat = nil
|
|
380
446
|
loop do
|
|
381
447
|
if @lexer.peek && @lexer.peek.type == :colon
|
|
382
448
|
name = e
|
|
383
|
-
@lexer.expected!("comma") unless name.is_a?(Variable)
|
|
449
|
+
@lexer.expected!("comma") unless name.is_a?(Tree::Variable)
|
|
384
450
|
assert_tok(:colon)
|
|
385
451
|
value = assert_expr(subexpr, description)
|
|
386
452
|
|
|
387
|
-
if keywords[name.
|
|
453
|
+
if keywords[name.name]
|
|
388
454
|
raise SyntaxError.new("Keyword argument \"#{name.to_sass}\" passed more than once")
|
|
389
455
|
end
|
|
390
456
|
|
|
391
|
-
keywords[name.
|
|
457
|
+
keywords[name.name] = value
|
|
392
458
|
else
|
|
393
|
-
if
|
|
459
|
+
if try_tok(:splat)
|
|
460
|
+
return args, keywords, splat, e if splat
|
|
461
|
+
splat, e = e, nil
|
|
462
|
+
elsif splat
|
|
463
|
+
raise SyntaxError.new("Only keyword arguments may follow variable arguments (...).")
|
|
464
|
+
elsif !keywords.empty?
|
|
394
465
|
raise SyntaxError.new("Positional arguments must come before keyword arguments.")
|
|
395
466
|
end
|
|
396
467
|
|
|
397
|
-
|
|
398
|
-
args << e
|
|
468
|
+
args << e if e
|
|
399
469
|
end
|
|
400
470
|
|
|
401
|
-
return args, keywords unless try_tok(:comma)
|
|
471
|
+
return args, keywords, splat unless try_tok(:comma)
|
|
402
472
|
e = assert_expr(subexpr, description)
|
|
403
473
|
end
|
|
404
474
|
end
|
|
405
475
|
|
|
406
476
|
def raw
|
|
407
|
-
|
|
408
|
-
|
|
477
|
+
tok = try_tok(:raw)
|
|
478
|
+
return special_fun unless tok
|
|
479
|
+
literal_node(Script::Value::String.new(tok.value), tok.source_range)
|
|
409
480
|
end
|
|
410
481
|
|
|
411
482
|
def special_fun
|
|
412
|
-
|
|
413
|
-
|
|
483
|
+
start_pos = source_position
|
|
484
|
+
tok = try_tok(:special_fun)
|
|
485
|
+
return paren unless tok
|
|
486
|
+
first = literal_node(Script::Value::String.new(tok.value.first),
|
|
487
|
+
start_pos, start_pos.after(tok.value.first))
|
|
414
488
|
Sass::Util.enum_slice(tok.value[1..-1], 2).inject(first) do |l, (i, r)|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
489
|
+
end_pos = i.source_range.end_pos
|
|
490
|
+
end_pos = end_pos.after(r) if r
|
|
491
|
+
node(
|
|
492
|
+
Script::Tree::Interpolation.new(
|
|
493
|
+
l, i,
|
|
494
|
+
r && literal_node(Script::Value::String.new(r),
|
|
495
|
+
i.source_range.end_pos, end_pos),
|
|
496
|
+
false, false),
|
|
497
|
+
start_pos, end_pos)
|
|
418
498
|
end
|
|
419
499
|
end
|
|
420
500
|
|
|
@@ -422,39 +502,49 @@ RUBY
|
|
|
422
502
|
return variable unless try_tok(:lparen)
|
|
423
503
|
was_in_parens = @in_parens
|
|
424
504
|
@in_parens = true
|
|
425
|
-
|
|
426
|
-
e =
|
|
505
|
+
start_pos = source_position
|
|
506
|
+
e = map
|
|
507
|
+
end_pos = source_position
|
|
427
508
|
assert_tok(:rparen)
|
|
428
|
-
return e || node(
|
|
509
|
+
return e || node(Sass::Script::Tree::ListLiteral.new([], nil), start_pos, end_pos)
|
|
429
510
|
ensure
|
|
430
511
|
@in_parens = was_in_parens
|
|
431
512
|
end
|
|
432
513
|
|
|
433
514
|
def variable
|
|
434
|
-
|
|
435
|
-
|
|
515
|
+
start_pos = source_position
|
|
516
|
+
c = try_tok(:const)
|
|
517
|
+
return string unless c
|
|
518
|
+
node(Tree::Variable.new(*c.value), start_pos)
|
|
436
519
|
end
|
|
437
520
|
|
|
438
521
|
def string
|
|
439
|
-
|
|
440
|
-
return
|
|
441
|
-
|
|
522
|
+
first = try_tok(:string)
|
|
523
|
+
return number unless first
|
|
524
|
+
str = literal_node(first.value, first.source_range)
|
|
525
|
+
return str unless try_tok(:begin_interpolation)
|
|
442
526
|
mid = parse_interpolated
|
|
443
527
|
last = assert_expr(:string)
|
|
444
|
-
|
|
445
|
-
interp.line = line
|
|
446
|
-
interp
|
|
528
|
+
node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
|
|
447
529
|
end
|
|
448
530
|
|
|
449
531
|
def number
|
|
450
|
-
|
|
532
|
+
tok = try_tok(:number)
|
|
533
|
+
return selector unless tok
|
|
451
534
|
num = tok.value
|
|
452
535
|
num.original = num.to_s unless @in_parens
|
|
453
|
-
num
|
|
536
|
+
literal_node(num, tok.source_range.start_pos)
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
def selector
|
|
540
|
+
tok = try_tok(:selector)
|
|
541
|
+
return literal unless tok
|
|
542
|
+
node(tok.value, tok.source_range.start_pos)
|
|
454
543
|
end
|
|
455
544
|
|
|
456
545
|
def literal
|
|
457
|
-
|
|
546
|
+
t = try_tok(:color, :bool, :null)
|
|
547
|
+
return literal_node(t.value, t.source_range) if t
|
|
458
548
|
end
|
|
459
549
|
|
|
460
550
|
# It would be possible to have unified #assert and #try methods,
|
|
@@ -465,20 +555,23 @@ RUBY
|
|
|
465
555
|
:default => "expression (e.g. 1px, bold)",
|
|
466
556
|
:mixin_arglist => "mixin argument",
|
|
467
557
|
:fn_arglist => "function argument",
|
|
558
|
+
:splat => "...",
|
|
468
559
|
}
|
|
469
560
|
|
|
470
561
|
def assert_expr(name, expected = nil)
|
|
471
|
-
|
|
562
|
+
e = send(name)
|
|
563
|
+
return e if e
|
|
472
564
|
@lexer.expected!(expected || EXPR_NAMES[name] || EXPR_NAMES[:default])
|
|
473
565
|
end
|
|
474
566
|
|
|
475
567
|
def assert_tok(*names)
|
|
476
|
-
|
|
568
|
+
t = try_tok(*names)
|
|
569
|
+
return t if t
|
|
477
570
|
@lexer.expected!(names.map {|tok| Lexer::TOKEN_NAMES[tok] || tok}.join(" or "))
|
|
478
571
|
end
|
|
479
572
|
|
|
480
573
|
def try_tok(*names)
|
|
481
|
-
peeked =
|
|
574
|
+
peeked = @lexer.peek
|
|
482
575
|
peeked && names.include?(peeked.type) && @lexer.next
|
|
483
576
|
end
|
|
484
577
|
|
|
@@ -487,8 +580,35 @@ RUBY
|
|
|
487
580
|
@lexer.expected!(EXPR_NAMES[:default])
|
|
488
581
|
end
|
|
489
582
|
|
|
490
|
-
|
|
491
|
-
|
|
583
|
+
# @overload node(value, source_range)
|
|
584
|
+
# @param value [Sass::Script::Value::Base]
|
|
585
|
+
# @param source_range [Sass::Source::Range]
|
|
586
|
+
# @overload node(value, start_pos, end_pos = source_position)
|
|
587
|
+
# @param value [Sass::Script::Value::Base]
|
|
588
|
+
# @param start_pos [Sass::Source::Position]
|
|
589
|
+
# @param end_pos [Sass::Source::Position]
|
|
590
|
+
def literal_node(value, source_range_or_start_pos, end_pos = source_position)
|
|
591
|
+
node(Sass::Script::Tree::Literal.new(value), source_range_or_start_pos, end_pos)
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
# @overload node(node, source_range)
|
|
595
|
+
# @param node [Sass::Script::Tree::Node]
|
|
596
|
+
# @param source_range [Sass::Source::Range]
|
|
597
|
+
# @overload node(node, start_pos, end_pos = source_position)
|
|
598
|
+
# @param node [Sass::Script::Tree::Node]
|
|
599
|
+
# @param start_pos [Sass::Source::Position]
|
|
600
|
+
# @param end_pos [Sass::Source::Position]
|
|
601
|
+
def node(node, source_range_or_start_pos, end_pos = source_position)
|
|
602
|
+
source_range =
|
|
603
|
+
if source_range_or_start_pos.is_a?(Sass::Source::Range)
|
|
604
|
+
source_range_or_start_pos
|
|
605
|
+
else
|
|
606
|
+
range(source_range_or_start_pos, end_pos)
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
node.line = source_range.start_pos.line
|
|
610
|
+
node.source_range = source_range
|
|
611
|
+
node.filename = @options[:filename]
|
|
492
612
|
node
|
|
493
613
|
end
|
|
494
614
|
end
|