sass 3.2.19 → 3.4.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +1 -1
- data/README.md +87 -61
- data/Rakefile +119 -15
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/extra/sass-spec-ref.sh +32 -0
- data/extra/update_watch.rb +1 -1
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +2 -1
- data/lib/sass/cache_stores/filesystem.rb +8 -12
- data/lib/sass/cache_stores/memory.rb +5 -6
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +3 -2
- data/lib/sass/css.rb +22 -23
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +487 -191
- data/lib/sass/environment.rb +172 -58
- data/lib/sass/error.rb +21 -24
- data/lib/sass/exec/base.rb +199 -0
- data/lib/sass/exec/sass_convert.rb +283 -0
- data/lib/sass/exec/sass_scss.rb +440 -0
- data/lib/sass/exec.rb +5 -703
- data/lib/sass/features.rb +47 -0
- data/lib/sass/importers/base.rb +50 -7
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +54 -21
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +9 -5
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger/log_level.rb +3 -7
- data/lib/sass/logger.rb +9 -7
- data/lib/sass/media.rb +20 -23
- data/lib/sass/plugin/compiler.rb +321 -145
- data/lib/sass/plugin/configuration.rb +45 -34
- data/lib/sass/plugin/merb.rb +3 -3
- data/lib/sass/plugin/rack.rb +3 -3
- data/lib/sass/plugin/rails.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +6 -6
- data/lib/sass/plugin.rb +9 -8
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script/css_lexer.rb +8 -4
- data/lib/sass/script/css_parser.rb +4 -2
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +1583 -433
- data/lib/sass/script/lexer.rb +198 -79
- data/lib/sass/script/parser.rb +463 -133
- data/lib/sass/script/tree/funcall.rb +313 -0
- data/lib/sass/script/tree/interpolation.rb +223 -0
- data/lib/sass/script/tree/list_literal.rb +104 -0
- data/lib/sass/script/tree/literal.rb +49 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +42 -14
- data/lib/sass/script/tree/operation.rb +156 -0
- data/lib/sass/script/tree/selector.rb +26 -0
- data/lib/sass/script/tree/string_interpolation.rb +125 -0
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +6 -6
- 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} +9 -25
- data/lib/sass/script/value/base.rb +241 -0
- data/lib/sass/script/value/bool.rb +35 -0
- data/lib/sass/script/value/color.rb +698 -0
- data/lib/sass/script/value/helpers.rb +272 -0
- data/lib/sass/script/value/list.rb +113 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/{null.rb → value/null.rb} +14 -7
- data/lib/sass/script/{number.rb → value/number.rb} +196 -86
- data/lib/sass/script/value/string.rb +138 -0
- data/lib/sass/script/value.rb +11 -0
- data/lib/sass/script.rb +38 -11
- data/lib/sass/scss/css_parser.rb +25 -5
- data/lib/sass/scss/parser.rb +532 -458
- data/lib/sass/scss/rx.rb +21 -14
- data/lib/sass/scss/static_parser.rb +328 -9
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/selector/abstract_sequence.rb +36 -19
- data/lib/sass/selector/comma_sequence.rb +125 -26
- data/lib/sass/selector/pseudo.rb +266 -0
- data/lib/sass/selector/sequence.rb +200 -71
- data/lib/sass/selector/simple.rb +30 -32
- data/lib/sass/selector/simple_sequence.rb +193 -64
- data/lib/sass/selector.rb +65 -194
- data/lib/sass/shared.rb +2 -2
- data/lib/sass/source/map.rb +213 -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 +19 -23
- data/lib/sass/tree/at_root_node.rb +83 -0
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +4 -4
- data/lib/sass/tree/css_import_node.rb +19 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +21 -4
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/error_node.rb +18 -0
- data/lib/sass/tree/extend_node.rb +14 -7
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +14 -4
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +10 -10
- data/lib/sass/tree/keyframe_rule_node.rb +15 -0
- 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 +59 -15
- data/lib/sass/tree/prop_node.rb +42 -24
- 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 +49 -26
- 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 +5 -8
- data/lib/sass/tree/visitors/check_nesting.rb +62 -36
- data/lib/sass/tree/visitors/convert.rb +111 -76
- data/lib/sass/tree/visitors/cssize.rb +206 -74
- data/lib/sass/tree/visitors/deep_copy.rb +11 -6
- data/lib/sass/tree/visitors/extend.rb +19 -17
- data/lib/sass/tree/visitors/perform.rb +308 -190
- data/lib/sass/tree/visitors/set_options.rb +21 -7
- data/lib/sass/tree/visitors/to_css.rb +273 -92
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util/cross_platform_random.rb +19 -0
- data/lib/sass/util/normalized_map.rb +129 -0
- data/lib/sass/util/ordered_hash.rb +192 -0
- data/lib/sass/util/subset_map.rb +5 -5
- data/lib/sass/util/test.rb +0 -1
- data/lib/sass/util.rb +620 -193
- data/lib/sass/version.rb +22 -24
- data/lib/sass.rb +27 -13
- data/test/sass/cache_test.rb +62 -20
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/compiler_test.rb +236 -0
- data/test/sass/conversion_test.rb +472 -44
- data/test/sass/css2sass_test.rb +73 -5
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/encoding_test.rb +219 -0
- data/test/sass/engine_test.rb +618 -415
- data/test/sass/exec_test.rb +12 -2
- data/test/sass/extend_test.rb +419 -168
- data/test/sass/functions_test.rb +931 -93
- data/test/sass/importer_test.rb +250 -21
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/more_templates/more1.sass +10 -10
- data/test/sass/more_templates/more_import.sass +2 -2
- data/test/sass/plugin_test.rb +26 -34
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +4 -4
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +1 -1
- data/test/sass/results/import_charset_ibm866.css +2 -2
- data/test/sass/results/mixins.css +17 -17
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/parent_ref.css +2 -2
- data/test/sass/results/script.css +5 -5
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +97 -39
- data/test/sass/script_test.rb +911 -102
- data/test/sass/scss/css_test.rb +215 -34
- data/test/sass/scss/rx_test.rb +8 -4
- data/test/sass/scss/scss_test.rb +2424 -325
- data/test/sass/source_map_test.rb +1055 -0
- data/test/sass/superselector_test.rb +210 -0
- data/test/sass/templates/_partial.sass +1 -1
- data/test/sass/templates/basic.sass +10 -10
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/bork5.sass +1 -1
- data/test/sass/templates/compact.sass +10 -10
- data/test/sass/templates/complex.sass +187 -187
- data/test/sass/templates/compressed.sass +10 -10
- data/test/sass/templates/expanded.sass +10 -10
- data/test/sass/templates/import.sass +2 -2
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/mixins.sass +22 -22
- data/test/sass/templates/multiline.sass +4 -4
- data/test/sass/templates/nested.sass +13 -13
- data/test/sass/templates/parent_ref.sass +12 -12
- data/test/sass/templates/script.sass +70 -70
- data/test/sass/templates/scss_import.scss +2 -1
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
- data/test/sass/templates/subdir/subdir.sass +3 -3
- data/test/sass/templates/units.sass +10 -10
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
- data/test/sass/util/normalized_map_test.rb +51 -0
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +99 -43
- data/test/sass/value_helpers_test.rb +179 -0
- data/test/sass-spec.yml +3 -0
- data/test/test_helper.rb +42 -12
- data/vendor/listen/CHANGELOG.md +1 -228
- data/vendor/listen/Gemfile +5 -15
- data/vendor/listen/README.md +111 -77
- data/vendor/listen/Rakefile +0 -42
- data/vendor/listen/lib/listen/adapter.rb +195 -82
- data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
- data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
- data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
- data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
- data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
- data/vendor/listen/lib/listen/directory_record.rb +96 -61
- data/vendor/listen/lib/listen/listener.rb +135 -37
- data/vendor/listen/lib/listen/turnstile.rb +9 -5
- data/vendor/listen/lib/listen/version.rb +1 -1
- data/vendor/listen/lib/listen.rb +33 -19
- data/vendor/listen/listen.gemspec +6 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
- data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
- data/vendor/listen/spec/listen/listener_spec.rb +128 -39
- data/vendor/listen/spec/listen_spec.rb +15 -21
- data/vendor/listen/spec/spec_helper.rb +4 -0
- data/vendor/listen/spec/support/adapter_helper.rb +52 -15
- data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
- data/vendor/listen/spec/support/listeners_helper.rb +30 -7
- metadata +161 -111
- data/CONTRIBUTING +0 -3
- data/lib/sass/script/bool.rb +0 -18
- data/lib/sass/script/color.rb +0 -606
- data/lib/sass/script/funcall.rb +0 -245
- data/lib/sass/script/interpolation.rb +0 -79
- data/lib/sass/script/list.rb +0 -85
- data/lib/sass/script/literal.rb +0 -221
- data/lib/sass/script/operation.rb +0 -110
- data/lib/sass/script/string.rb +0 -51
- data/lib/sass/script/string_interpolation.rb +0 -103
- data/lib/sass/script/variable.rb +0 -58
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
- data/test/Gemfile +0 -3
- data/test/Gemfile.lock +0 -10
- data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
- data/vendor/listen/lib/listen/multi_listener.rb +0 -143
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
- data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
data/lib/sass/script/parser.rb
CHANGED
@@ -1,27 +1,41 @@
|
|
1
1
|
require 'sass/script/lexer'
|
2
|
+
require 'sass/script/css_variable_warning'
|
2
3
|
|
3
4
|
module Sass
|
4
5
|
module Script
|
5
6
|
# The parser for SassScript.
|
6
|
-
# It parses a string of code into a tree of {Script::Node}s.
|
7
|
+
# It parses a string of code into a tree of {Script::Tree::Node}s.
|
7
8
|
class Parser
|
8
9
|
# The line number of the parser's current position.
|
9
10
|
#
|
10
|
-
# @return [
|
11
|
+
# @return [Integer]
|
11
12
|
def line
|
12
13
|
@lexer.line
|
13
14
|
end
|
14
15
|
|
16
|
+
# The column number of the parser's current position.
|
17
|
+
#
|
18
|
+
# @return [Integer]
|
19
|
+
def offset
|
20
|
+
@lexer.offset
|
21
|
+
end
|
22
|
+
|
15
23
|
# @param str [String, StringScanner] The source text to parse
|
16
|
-
# @param line [
|
17
|
-
# Used for error reporting
|
18
|
-
# @param offset [
|
19
|
-
# Used for error reporting
|
20
|
-
# @param options [{Symbol => Object}] An options hash;
|
21
|
-
#
|
24
|
+
# @param line [Integer] The line on which the SassScript appears.
|
25
|
+
# Used for error reporting and sourcemap building
|
26
|
+
# @param offset [Integer] The character (not byte) offset where the script starts in the line.
|
27
|
+
# Used for error reporting and sourcemap building
|
28
|
+
# @param options [{Symbol => Object}] An options hash; see
|
29
|
+
# {file:SASS_REFERENCE.md#Options the Sass options documentation}.
|
30
|
+
# This supports an additional `:allow_extra_text` option that controls
|
31
|
+
# whether the parser throws an error when extra text is encountered
|
32
|
+
# after the parsed construct.
|
22
33
|
def initialize(str, line, offset, options = {})
|
23
34
|
@options = options
|
35
|
+
@allow_extra_text = options.delete(:allow_extra_text)
|
24
36
|
@lexer = lexer_class.new(str, line, offset, options)
|
37
|
+
@stop_at = nil
|
38
|
+
@css_variable_warning = nil
|
25
39
|
end
|
26
40
|
|
27
41
|
# Parses a SassScript expression within an interpolated segment (`#{}`).
|
@@ -29,13 +43,20 @@ module Sass
|
|
29
43
|
# which signals the end of an interpolated segment,
|
30
44
|
# it returns rather than throwing an error.
|
31
45
|
#
|
32
|
-
# @
|
46
|
+
# @param warn_for_color [Boolean] Whether raw color values passed to
|
47
|
+
# interoplation should cause a warning.
|
48
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
33
49
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
34
|
-
def parse_interpolated
|
50
|
+
def parse_interpolated(warn_for_color = false)
|
51
|
+
# Start two characters back to compensate for #{
|
52
|
+
start_pos = Sass::Source::Position.new(line, offset - 2)
|
35
53
|
expr = assert_expr :expr
|
36
54
|
assert_tok :end_interpolation
|
55
|
+
expr = Sass::Script::Tree::Interpolation.new(
|
56
|
+
nil, expr, nil, false, false, :warn_for_color => warn_for_color)
|
57
|
+
check_for_interpolation expr
|
37
58
|
expr.options = @options
|
38
|
-
expr
|
59
|
+
node(expr, start_pos)
|
39
60
|
rescue Sass::SyntaxError => e
|
40
61
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
41
62
|
raise e
|
@@ -43,12 +64,23 @@ module Sass
|
|
43
64
|
|
44
65
|
# Parses a SassScript expression.
|
45
66
|
#
|
46
|
-
# @
|
67
|
+
# @param css_variable [Boolean] Whether this is the value of a CSS variable.
|
68
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
47
69
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
48
|
-
def parse
|
70
|
+
def parse(css_variable = false)
|
71
|
+
if css_variable
|
72
|
+
@css_variable_warning = CssVariableWarning.new
|
73
|
+
end
|
74
|
+
|
49
75
|
expr = assert_expr :expr
|
50
76
|
assert_done
|
51
77
|
expr.options = @options
|
78
|
+
check_for_interpolation expr
|
79
|
+
|
80
|
+
if css_variable
|
81
|
+
@css_variable_warning.value = expr
|
82
|
+
end
|
83
|
+
|
52
84
|
expr
|
53
85
|
rescue Sass::SyntaxError => e
|
54
86
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -58,14 +90,15 @@ module Sass
|
|
58
90
|
# Parses a SassScript expression,
|
59
91
|
# ending it when it encounters one of the given identifier tokens.
|
60
92
|
#
|
61
|
-
# @param [#include?(String)] A set of strings that delimit the expression.
|
62
|
-
# @return [Script::Node] The root node of the parse tree
|
93
|
+
# @param tokens [#include?(String)] A set of strings that delimit the expression.
|
94
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
63
95
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
64
96
|
def parse_until(tokens)
|
65
97
|
@stop_at = tokens
|
66
98
|
expr = assert_expr :expr
|
67
99
|
assert_done
|
68
100
|
expr.options = @options
|
101
|
+
check_for_interpolation expr
|
69
102
|
expr
|
70
103
|
rescue Sass::SyntaxError => e
|
71
104
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -74,22 +107,42 @@ module Sass
|
|
74
107
|
|
75
108
|
# Parses the argument list for a mixin include.
|
76
109
|
#
|
77
|
-
# @return [(Array<Script::Node>,
|
110
|
+
# @return [(Array<Script::Tree::Node>,
|
111
|
+
# {String => Script::Tree::Node},
|
112
|
+
# Script::Tree::Node,
|
113
|
+
# Script::Tree::Node)]
|
78
114
|
# The root nodes of the positional arguments, keyword arguments, and
|
79
|
-
# splat argument. Keyword arguments are in a hash from names to values.
|
115
|
+
# splat argument(s). Keyword arguments are in a hash from names to values.
|
80
116
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
81
117
|
def parse_mixin_include_arglist
|
82
118
|
args, keywords = [], {}
|
83
119
|
if try_tok(:lparen)
|
84
|
-
args, keywords, splat = mixin_arglist
|
120
|
+
args, keywords, splat, kwarg_splat = mixin_arglist
|
85
121
|
assert_tok(:rparen)
|
86
122
|
end
|
87
123
|
assert_done
|
88
124
|
|
89
|
-
args.each
|
90
|
-
|
91
|
-
|
92
|
-
|
125
|
+
args.each do |a|
|
126
|
+
check_for_interpolation a
|
127
|
+
a.options = @options
|
128
|
+
end
|
129
|
+
|
130
|
+
keywords.each do |_k, v|
|
131
|
+
check_for_interpolation v
|
132
|
+
v.options = @options
|
133
|
+
end
|
134
|
+
|
135
|
+
if splat
|
136
|
+
check_for_interpolation splat
|
137
|
+
splat.options = @options
|
138
|
+
end
|
139
|
+
|
140
|
+
if kwarg_splat
|
141
|
+
check_for_interpolation kwarg_splat
|
142
|
+
kwarg_splat.options = @options
|
143
|
+
end
|
144
|
+
|
145
|
+
return args, keywords, splat, kwarg_splat
|
93
146
|
rescue Sass::SyntaxError => e
|
94
147
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
95
148
|
raise e
|
@@ -97,7 +150,7 @@ module Sass
|
|
97
150
|
|
98
151
|
# Parses the argument list for a mixin definition.
|
99
152
|
#
|
100
|
-
# @return [(Array<Script::Node>, Script::Node)]
|
153
|
+
# @return [(Array<Script::Tree::Node>, Script::Tree::Node)]
|
101
154
|
# The root nodes of the arguments, and the splat argument.
|
102
155
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
103
156
|
def parse_mixin_definition_arglist
|
@@ -105,10 +158,20 @@ module Sass
|
|
105
158
|
assert_done
|
106
159
|
|
107
160
|
args.each do |k, v|
|
161
|
+
check_for_interpolation k
|
108
162
|
k.options = @options
|
109
|
-
|
163
|
+
|
164
|
+
if v
|
165
|
+
check_for_interpolation v
|
166
|
+
v.options = @options
|
167
|
+
end
|
110
168
|
end
|
111
|
-
|
169
|
+
|
170
|
+
if splat
|
171
|
+
check_for_interpolation splat
|
172
|
+
splat.options = @options
|
173
|
+
end
|
174
|
+
|
112
175
|
return args, splat
|
113
176
|
rescue Sass::SyntaxError => e
|
114
177
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -117,7 +180,7 @@ module Sass
|
|
117
180
|
|
118
181
|
# Parses the argument list for a function definition.
|
119
182
|
#
|
120
|
-
# @return [(Array<Script::Node>, Script::Node)]
|
183
|
+
# @return [(Array<Script::Tree::Node>, Script::Tree::Node)]
|
121
184
|
# The root nodes of the arguments, and the splat argument.
|
122
185
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
123
186
|
def parse_function_definition_arglist
|
@@ -125,10 +188,20 @@ module Sass
|
|
125
188
|
assert_done
|
126
189
|
|
127
190
|
args.each do |k, v|
|
191
|
+
check_for_interpolation k
|
128
192
|
k.options = @options
|
129
|
-
|
193
|
+
|
194
|
+
if v
|
195
|
+
check_for_interpolation v
|
196
|
+
v.options = @options
|
197
|
+
end
|
130
198
|
end
|
131
|
-
|
199
|
+
|
200
|
+
if splat
|
201
|
+
check_for_interpolation splat
|
202
|
+
splat.options = @options
|
203
|
+
end
|
204
|
+
|
132
205
|
return args, splat
|
133
206
|
rescue Sass::SyntaxError => e
|
134
207
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
@@ -138,7 +211,7 @@ module Sass
|
|
138
211
|
# Parse a single string value, possibly containing interpolation.
|
139
212
|
# Doesn't assert that the scanner is finished after parsing.
|
140
213
|
#
|
141
|
-
# @return [Script::Node] The root node of the parse tree.
|
214
|
+
# @return [Script::Tree::Node] The root node of the parse tree.
|
142
215
|
# @raise [Sass::SyntaxError] if the string isn't valid SassScript
|
143
216
|
def parse_string
|
144
217
|
unless (peek = @lexer.peek) &&
|
@@ -148,6 +221,7 @@ module Sass
|
|
148
221
|
end
|
149
222
|
|
150
223
|
expr = assert_expr :funcall
|
224
|
+
check_for_interpolation expr
|
151
225
|
expr.options = @options
|
152
226
|
@lexer.unpeek!
|
153
227
|
expr
|
@@ -158,12 +232,12 @@ module Sass
|
|
158
232
|
|
159
233
|
# Parses a SassScript expression.
|
160
234
|
#
|
161
|
-
# @
|
162
|
-
# @return [Script::Node] The root node of the parse tree
|
235
|
+
# @return [Script::Tree::Node] The root node of the parse tree
|
163
236
|
# @see Parser#initialize
|
164
237
|
# @see Parser#parse
|
165
|
-
def self.parse(
|
166
|
-
|
238
|
+
def self.parse(value, line, offset, options = {})
|
239
|
+
css_variable = options.delete :css_variable
|
240
|
+
new(value, line, offset, options).parse(css_variable)
|
167
241
|
end
|
168
242
|
|
169
243
|
PRECEDENCE = [
|
@@ -176,6 +250,8 @@ module Sass
|
|
176
250
|
|
177
251
|
ASSOCIATIVE = [:plus, :times]
|
178
252
|
|
253
|
+
VALID_CSS_OPS = [:comma, :single_eq, :space, :div]
|
254
|
+
|
179
255
|
class << self
|
180
256
|
# Returns an integer representing the precedence
|
181
257
|
# of the given operator.
|
@@ -186,7 +262,7 @@ module Sass
|
|
186
262
|
PRECEDENCE.each_with_index do |e, i|
|
187
263
|
return i if Array(e).include?(op)
|
188
264
|
end
|
189
|
-
raise "[BUG] Unknown operator #{op}"
|
265
|
+
raise "[BUG] Unknown operator #{op.inspect}"
|
190
266
|
end
|
191
267
|
|
192
268
|
# Returns whether or not the given operation is associative.
|
@@ -205,17 +281,22 @@ module Sass
|
|
205
281
|
def production(name, sub, *ops)
|
206
282
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
207
283
|
def #{name}
|
208
|
-
interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect})
|
284
|
+
interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect})
|
285
|
+
return interp if interp
|
209
286
|
return unless e = #{sub}
|
210
|
-
while tok =
|
287
|
+
while tok = try_toks(#{ops.map {|o| o.inspect}.join(', ')})
|
211
288
|
if interp = try_op_before_interp(tok, e)
|
212
|
-
|
289
|
+
other_interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}, interp)
|
290
|
+
return interp unless other_interp
|
213
291
|
return other_interp
|
214
292
|
end
|
215
293
|
|
216
|
-
|
217
|
-
|
218
|
-
|
294
|
+
if @css_variable_warning && !VALID_CSS_OPS.include?(tok.type)
|
295
|
+
@css_variable_warning.warn!
|
296
|
+
end
|
297
|
+
|
298
|
+
e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type),
|
299
|
+
e.source_range.start_pos)
|
219
300
|
end
|
220
301
|
e
|
221
302
|
end
|
@@ -226,11 +307,12 @@ RUBY
|
|
226
307
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
227
308
|
def unary_#{op}
|
228
309
|
return #{sub} unless tok = try_tok(:#{op})
|
229
|
-
interp = try_op_before_interp(tok)
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
310
|
+
interp = try_op_before_interp(tok)
|
311
|
+
return interp if interp
|
312
|
+
start_pos = source_position
|
313
|
+
|
314
|
+
@css_variable_warning.warn! if @css_variable_warning
|
315
|
+
node(Tree::UnaryOperation.new(assert_expr(:unary_#{op}), :#{op}), start_pos)
|
234
316
|
end
|
235
317
|
RUBY
|
236
318
|
end
|
@@ -238,69 +320,188 @@ RUBY
|
|
238
320
|
|
239
321
|
private
|
240
322
|
|
323
|
+
def source_position
|
324
|
+
Sass::Source::Position.new(line, offset)
|
325
|
+
end
|
326
|
+
|
327
|
+
def range(start_pos, end_pos = source_position)
|
328
|
+
Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
|
329
|
+
end
|
330
|
+
|
241
331
|
# @private
|
242
332
|
def lexer_class; Lexer; end
|
243
333
|
|
334
|
+
def map
|
335
|
+
start_pos = source_position
|
336
|
+
e = interpolation
|
337
|
+
return unless e
|
338
|
+
return list e, start_pos unless @lexer.peek && @lexer.peek.type == :colon
|
339
|
+
|
340
|
+
pair = map_pair(e)
|
341
|
+
@css_variable_warning.warn! if @css_variable_warning
|
342
|
+
map = node(Sass::Script::Tree::MapLiteral.new([pair]), start_pos)
|
343
|
+
while try_tok(:comma)
|
344
|
+
pair = map_pair
|
345
|
+
return map unless pair
|
346
|
+
map.pairs << pair
|
347
|
+
end
|
348
|
+
map
|
349
|
+
end
|
350
|
+
|
351
|
+
def map_pair(key = nil)
|
352
|
+
return unless key ||= interpolation
|
353
|
+
assert_tok :colon
|
354
|
+
return key, assert_expr(:interpolation)
|
355
|
+
end
|
356
|
+
|
244
357
|
def expr
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
358
|
+
start_pos = source_position
|
359
|
+
e = interpolation
|
360
|
+
return unless e
|
361
|
+
list e, start_pos
|
362
|
+
end
|
363
|
+
|
364
|
+
def list(first, start_pos)
|
365
|
+
return first unless @lexer.peek && @lexer.peek.type == :comma
|
366
|
+
|
367
|
+
list = node(Sass::Script::Tree::ListLiteral.new([first], :comma), start_pos)
|
368
|
+
while (tok = try_tok(:comma))
|
369
|
+
element_before_interp = list.elements.length == 1 ? list.elements.first : list
|
370
|
+
if (interp = try_op_before_interp(tok, element_before_interp))
|
371
|
+
other_interp = try_ops_after_interp([:comma], :expr, interp)
|
372
|
+
return interp unless other_interp
|
251
373
|
return other_interp
|
252
374
|
end
|
253
|
-
list
|
375
|
+
return list unless (e = interpolation)
|
376
|
+
list.elements << e
|
377
|
+
list.source_range.end_pos = list.elements.last.source_range.end_pos
|
254
378
|
end
|
255
|
-
list
|
379
|
+
list
|
256
380
|
end
|
257
381
|
|
258
382
|
production :equals, :interpolation, :single_eq
|
259
383
|
|
260
|
-
def try_op_before_interp(op, prev = nil)
|
384
|
+
def try_op_before_interp(op, prev = nil, after_interp = false)
|
261
385
|
return unless @lexer.peek && @lexer.peek.type == :begin_interpolation
|
386
|
+
unary = !prev && !after_interp
|
262
387
|
wb = @lexer.whitespace?(op)
|
263
|
-
str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
|
264
|
-
|
265
|
-
|
266
|
-
|
388
|
+
str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
|
389
|
+
op.source_range)
|
390
|
+
|
391
|
+
deprecation =
|
392
|
+
case op.type
|
393
|
+
when :comma; :potential
|
394
|
+
when :div, :single_eq; :none
|
395
|
+
when :plus; unary ? :none : :immediate
|
396
|
+
when :minus; @lexer.whitespace?(@lexer.peek) ? :immediate : :none
|
397
|
+
else; :immediate
|
398
|
+
end
|
399
|
+
|
400
|
+
interp = node(
|
401
|
+
Script::Tree::Interpolation.new(
|
402
|
+
prev, str, nil, wb, false, :originally_text => true, :deprecation => deprecation),
|
403
|
+
(prev || str).source_range.start_pos)
|
267
404
|
interpolation(interp)
|
268
405
|
end
|
269
406
|
|
270
407
|
def try_ops_after_interp(ops, name, prev = nil)
|
271
408
|
return unless @lexer.after_interpolation?
|
272
|
-
|
273
|
-
|
409
|
+
op = try_toks(*ops)
|
410
|
+
return unless op
|
411
|
+
interp = try_op_before_interp(op, prev, :after_interp)
|
412
|
+
return interp if interp
|
274
413
|
|
275
414
|
wa = @lexer.whitespace?
|
276
|
-
str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
|
415
|
+
str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
|
416
|
+
op.source_range)
|
277
417
|
str.line = @lexer.line
|
278
|
-
|
279
|
-
|
280
|
-
|
418
|
+
|
419
|
+
deprecation =
|
420
|
+
case op.type
|
421
|
+
when :comma; :potential
|
422
|
+
when :div, :single_eq; :none
|
423
|
+
when :minus; @lexer.whitespace?(op) ? :immediate : :none
|
424
|
+
else; :immediate
|
425
|
+
end
|
426
|
+
interp = node(
|
427
|
+
Script::Tree::Interpolation.new(
|
428
|
+
prev, str, assert_expr(name), false, wa,
|
429
|
+
:originally_text => true, :deprecation => deprecation),
|
430
|
+
(prev || str).source_range.start_pos)
|
431
|
+
interp
|
281
432
|
end
|
282
433
|
|
283
434
|
def interpolation(first = space)
|
284
435
|
e = first
|
285
|
-
while interp = try_tok(:begin_interpolation)
|
436
|
+
while (interp = try_tok(:begin_interpolation))
|
286
437
|
wb = @lexer.whitespace?(interp)
|
287
|
-
|
288
|
-
mid =
|
438
|
+
char_before = @lexer.char(interp.pos - 1)
|
439
|
+
mid = without_css_variable_warning {assert_expr :expr}
|
440
|
+
assert_tok :end_interpolation
|
289
441
|
wa = @lexer.whitespace?
|
290
|
-
|
291
|
-
|
442
|
+
char_after = @lexer.char
|
443
|
+
|
444
|
+
after = space
|
445
|
+
before_deprecation = e.is_a?(Script::Tree::Interpolation) ? e.deprecation : :none
|
446
|
+
after_deprecation = after.is_a?(Script::Tree::Interpolation) ? after.deprecation : :none
|
447
|
+
|
448
|
+
deprecation =
|
449
|
+
if before_deprecation == :immediate || after_deprecation == :immediate ||
|
450
|
+
# Warn for #{foo}$var and #{foo}(1) but not #{$foo}1.
|
451
|
+
(after && !wa && char_after =~ /[$(]/) ||
|
452
|
+
# Warn for $var#{foo} and (a)#{foo} but not a#{foo}.
|
453
|
+
(e && !wb && is_unsafe_before?(e, char_before))
|
454
|
+
:immediate
|
455
|
+
else
|
456
|
+
:potential
|
457
|
+
end
|
458
|
+
|
459
|
+
e = node(
|
460
|
+
Script::Tree::Interpolation.new(e, mid, after, wb, wa, :deprecation => deprecation),
|
461
|
+
(e || interp).source_range.start_pos)
|
292
462
|
end
|
293
463
|
e
|
294
464
|
end
|
295
465
|
|
466
|
+
# Returns whether `expr` is unsafe to include before an interpolation.
|
467
|
+
#
|
468
|
+
# @param expr [Node] The expression to check.
|
469
|
+
# @param char_before [String] The character immediately before the
|
470
|
+
# interpolation being checked (and presumably the last character of
|
471
|
+
# `expr`).
|
472
|
+
# @return [Boolean]
|
473
|
+
def is_unsafe_before?(expr, char_before)
|
474
|
+
return char_before == ')' if is_safe_value?(expr)
|
475
|
+
|
476
|
+
# Otherwise, it's only safe if it was another interpolation.
|
477
|
+
!expr.is_a?(Script::Tree::Interpolation)
|
478
|
+
end
|
479
|
+
|
480
|
+
# Returns whether `expr` is safe as the value immediately before an
|
481
|
+
# interpolation.
|
482
|
+
#
|
483
|
+
# It's safe as long as the previous expression is an identifier or number,
|
484
|
+
# or a list whose last element is also safe.
|
485
|
+
def is_safe_value?(expr)
|
486
|
+
return is_safe_value?(expr.elements.last) if expr.is_a?(Script::Tree::ListLiteral)
|
487
|
+
return false unless expr.is_a?(Script::Tree::Literal)
|
488
|
+
expr.value.is_a?(Script::Value::Number) ||
|
489
|
+
(expr.value.is_a?(Script::Value::String) && expr.value.type == :identifier)
|
490
|
+
end
|
491
|
+
|
296
492
|
def space
|
297
|
-
|
298
|
-
|
493
|
+
start_pos = source_position
|
494
|
+
e = or_expr
|
495
|
+
return unless e
|
299
496
|
arr = [e]
|
300
|
-
while e = or_expr
|
497
|
+
while (e = or_expr)
|
301
498
|
arr << e
|
302
499
|
end
|
303
|
-
arr.size == 1
|
500
|
+
if arr.size == 1
|
501
|
+
arr.first
|
502
|
+
else
|
503
|
+
node(Sass::Script::Tree::ListLiteral.new(arr, :space), start_pos)
|
504
|
+
end
|
304
505
|
end
|
305
506
|
|
306
507
|
production :or_expr, :and_expr, :or
|
@@ -320,24 +521,26 @@ RUBY
|
|
320
521
|
return if @stop_at && @stop_at.include?(@lexer.peek.value)
|
321
522
|
|
322
523
|
name = @lexer.next
|
323
|
-
if color = Color::COLOR_NAMES[name.value.downcase]
|
324
|
-
|
524
|
+
if (color = Sass::Script::Value::Color::COLOR_NAMES[name.value.downcase])
|
525
|
+
literal_node(Sass::Script::Value::Color.new(color, name.value), name.source_range)
|
325
526
|
elsif name.value == "true"
|
326
|
-
|
527
|
+
literal_node(Sass::Script::Value::Bool.new(true), name.source_range)
|
327
528
|
elsif name.value == "false"
|
328
|
-
|
529
|
+
literal_node(Sass::Script::Value::Bool.new(false), name.source_range)
|
329
530
|
elsif name.value == "null"
|
330
|
-
|
531
|
+
literal_node(Sass::Script::Value::Null.new, name.source_range)
|
331
532
|
else
|
332
|
-
|
533
|
+
literal_node(Sass::Script::Value::String.new(name.value, :identifier), name.source_range)
|
333
534
|
end
|
334
535
|
end
|
335
536
|
|
336
537
|
def funcall
|
337
|
-
|
338
|
-
|
538
|
+
tok = try_tok(:funcall)
|
539
|
+
return raw unless tok
|
540
|
+
args, keywords, splat, kwarg_splat = fn_arglist
|
339
541
|
assert_tok(:rparen)
|
340
|
-
node(Script::Funcall.new(tok.value, args, keywords, splat)
|
542
|
+
node(Script::Tree::Funcall.new(tok.value, args, keywords, splat, kwarg_splat),
|
543
|
+
tok.source_range.start_pos, source_position)
|
341
544
|
end
|
342
545
|
|
343
546
|
def defn_arglist!(must_have_parens)
|
@@ -353,15 +556,16 @@ RUBY
|
|
353
556
|
must_have_default = false
|
354
557
|
loop do
|
355
558
|
c = assert_tok(:const)
|
356
|
-
var = Script::Variable.new(c.value)
|
559
|
+
var = node(Script::Tree::Variable.new(c.value), c.source_range)
|
357
560
|
if try_tok(:colon)
|
358
561
|
val = assert_expr(:space)
|
359
562
|
must_have_default = true
|
360
|
-
elsif must_have_default
|
361
|
-
raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.")
|
362
563
|
elsif try_tok(:splat)
|
363
564
|
splat = var
|
364
565
|
break
|
566
|
+
elsif must_have_default
|
567
|
+
raise SyntaxError.new(
|
568
|
+
"Required argument #{var.inspect} must come before any optional arguments.")
|
365
569
|
end
|
366
570
|
res << [var, val]
|
367
571
|
break unless try_tok(:comma)
|
@@ -379,88 +583,113 @@ RUBY
|
|
379
583
|
end
|
380
584
|
|
381
585
|
def arglist(subexpr, description)
|
382
|
-
return unless e = send(subexpr)
|
383
|
-
|
384
586
|
args = []
|
385
|
-
keywords =
|
587
|
+
keywords = Sass::Util::NormalizedMap.new
|
588
|
+
e = send(subexpr)
|
589
|
+
|
590
|
+
return [args, keywords] unless e
|
591
|
+
|
592
|
+
splat = nil
|
386
593
|
loop do
|
387
594
|
if @lexer.peek && @lexer.peek.type == :colon
|
388
595
|
name = e
|
389
|
-
@lexer.expected!("comma") unless name.is_a?(Variable)
|
596
|
+
@lexer.expected!("comma") unless name.is_a?(Tree::Variable)
|
390
597
|
assert_tok(:colon)
|
391
598
|
value = assert_expr(subexpr, description)
|
392
599
|
|
393
|
-
if keywords[name.
|
600
|
+
if keywords[name.name]
|
394
601
|
raise SyntaxError.new("Keyword argument \"#{name.to_sass}\" passed more than once")
|
395
602
|
end
|
396
603
|
|
397
|
-
keywords[name.
|
604
|
+
keywords[name.name] = value
|
398
605
|
else
|
399
|
-
if
|
606
|
+
if try_tok(:splat)
|
607
|
+
return args, keywords, splat, e if splat
|
608
|
+
splat, e = e, nil
|
609
|
+
elsif splat
|
610
|
+
raise SyntaxError.new("Only keyword arguments may follow variable arguments (...).")
|
611
|
+
elsif !keywords.empty?
|
400
612
|
raise SyntaxError.new("Positional arguments must come before keyword arguments.")
|
401
613
|
end
|
402
614
|
|
403
|
-
|
404
|
-
args << e
|
615
|
+
args << e if e
|
405
616
|
end
|
406
617
|
|
407
|
-
return args, keywords unless try_tok(:comma)
|
618
|
+
return args, keywords, splat unless try_tok(:comma)
|
408
619
|
e = assert_expr(subexpr, description)
|
409
620
|
end
|
410
621
|
end
|
411
622
|
|
412
623
|
def raw
|
413
|
-
|
414
|
-
|
624
|
+
tok = try_tok(:raw)
|
625
|
+
return special_fun unless tok
|
626
|
+
literal_node(Script::Value::String.new(tok.value), tok.source_range)
|
415
627
|
end
|
416
628
|
|
417
629
|
def special_fun
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
630
|
+
first = try_tok(:special_fun)
|
631
|
+
return paren unless first
|
632
|
+
str = literal_node(first.value, first.source_range)
|
633
|
+
return str unless try_tok(:string_interpolation)
|
634
|
+
mid = without_css_variable_warning {assert_expr :expr}
|
635
|
+
assert_tok :end_interpolation
|
636
|
+
last = assert_expr(:special_fun)
|
637
|
+
node(
|
638
|
+
Tree::Interpolation.new(str, mid, last, false, false),
|
639
|
+
first.source_range.start_pos)
|
425
640
|
end
|
426
641
|
|
427
642
|
def paren
|
428
643
|
return variable unless try_tok(:lparen)
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
644
|
+
start_pos = source_position
|
645
|
+
e = map
|
646
|
+
e.force_division! if e
|
647
|
+
end_pos = source_position
|
433
648
|
assert_tok(:rparen)
|
434
|
-
|
435
|
-
|
436
|
-
|
649
|
+
|
650
|
+
@css_variable_warning.warn! if @css_variable_warning
|
651
|
+
e || node(Sass::Script::Tree::ListLiteral.new([], nil), start_pos, end_pos)
|
437
652
|
end
|
438
653
|
|
439
654
|
def variable
|
440
|
-
|
441
|
-
|
655
|
+
start_pos = source_position
|
656
|
+
c = try_tok(:const)
|
657
|
+
return string unless c
|
658
|
+
|
659
|
+
@css_variable_warning.warn! if @css_variable_warning
|
660
|
+
node(Tree::Variable.new(*c.value), start_pos)
|
442
661
|
end
|
443
662
|
|
444
663
|
def string
|
445
|
-
|
446
|
-
return
|
447
|
-
|
448
|
-
|
664
|
+
first = try_tok(:string)
|
665
|
+
return number unless first
|
666
|
+
str = literal_node(first.value, first.source_range)
|
667
|
+
return str unless try_tok(:string_interpolation)
|
668
|
+
mid = without_css_variable_warning {assert_expr :expr}
|
669
|
+
assert_tok :end_interpolation
|
449
670
|
last = assert_expr(:string)
|
450
|
-
|
451
|
-
interp.line = line
|
452
|
-
interp
|
671
|
+
node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
|
453
672
|
end
|
454
673
|
|
455
674
|
def number
|
456
|
-
|
675
|
+
tok = try_tok(:number)
|
676
|
+
return selector unless tok
|
457
677
|
num = tok.value
|
458
|
-
num.
|
459
|
-
num
|
678
|
+
num.options = @options
|
679
|
+
num.original = num.to_s
|
680
|
+
literal_node(num, tok.source_range.start_pos)
|
681
|
+
end
|
682
|
+
|
683
|
+
def selector
|
684
|
+
tok = try_tok(:selector)
|
685
|
+
return literal unless tok
|
686
|
+
@css_variable_warning.warn! if @css_variable_warning
|
687
|
+
node(tok.value, tok.source_range.start_pos)
|
460
688
|
end
|
461
689
|
|
462
690
|
def literal
|
463
|
-
|
691
|
+
t = try_tok(:color)
|
692
|
+
return literal_node(t.value, t.source_range) if t
|
464
693
|
end
|
465
694
|
|
466
695
|
# It would be possible to have unified #assert and #try methods,
|
@@ -471,32 +700,133 @@ RUBY
|
|
471
700
|
:default => "expression (e.g. 1px, bold)",
|
472
701
|
:mixin_arglist => "mixin argument",
|
473
702
|
:fn_arglist => "function argument",
|
703
|
+
:splat => "...",
|
704
|
+
:special_fun => '")"',
|
474
705
|
}
|
475
706
|
|
476
707
|
def assert_expr(name, expected = nil)
|
477
|
-
|
708
|
+
e = send(name)
|
709
|
+
return e if e
|
478
710
|
@lexer.expected!(expected || EXPR_NAMES[name] || EXPR_NAMES[:default])
|
479
711
|
end
|
480
712
|
|
481
|
-
def assert_tok(
|
482
|
-
|
713
|
+
def assert_tok(name)
|
714
|
+
# Avoids an array allocation caused by argument globbing in assert_toks.
|
715
|
+
t = try_tok(name)
|
716
|
+
return t if t
|
717
|
+
@lexer.expected!(Lexer::TOKEN_NAMES[name] || name.to_s)
|
718
|
+
end
|
719
|
+
|
720
|
+
def assert_toks(*names)
|
721
|
+
t = try_toks(*names)
|
722
|
+
return t if t
|
483
723
|
@lexer.expected!(names.map {|tok| Lexer::TOKEN_NAMES[tok] || tok}.join(" or "))
|
484
724
|
end
|
485
725
|
|
486
|
-
def try_tok(
|
487
|
-
|
726
|
+
def try_tok(name)
|
727
|
+
# Avoids an array allocation caused by argument globbing in the try_toks method.
|
728
|
+
peeked = @lexer.peek
|
729
|
+
peeked && name == peeked.type && @lexer.next
|
730
|
+
end
|
731
|
+
|
732
|
+
def try_toks(*names)
|
733
|
+
peeked = @lexer.peek
|
488
734
|
peeked && names.include?(peeked.type) && @lexer.next
|
489
735
|
end
|
490
736
|
|
491
737
|
def assert_done
|
492
|
-
|
493
|
-
|
738
|
+
if @allow_extra_text
|
739
|
+
# If extra text is allowed, just rewind the lexer so that the
|
740
|
+
# StringScanner is pointing to the end of the parsed text.
|
741
|
+
@lexer.unpeek!
|
742
|
+
else
|
743
|
+
return if @lexer.done?
|
744
|
+
@lexer.expected!(EXPR_NAMES[:default])
|
745
|
+
end
|
494
746
|
end
|
495
747
|
|
496
|
-
|
497
|
-
|
748
|
+
# @overload node(value, source_range)
|
749
|
+
# @param value [Sass::Script::Value::Base]
|
750
|
+
# @param source_range [Sass::Source::Range]
|
751
|
+
# @overload node(value, start_pos, end_pos = source_position)
|
752
|
+
# @param value [Sass::Script::Value::Base]
|
753
|
+
# @param start_pos [Sass::Source::Position]
|
754
|
+
# @param end_pos [Sass::Source::Position]
|
755
|
+
def literal_node(value, source_range_or_start_pos, end_pos = source_position)
|
756
|
+
node(Sass::Script::Tree::Literal.new(value), source_range_or_start_pos, end_pos)
|
757
|
+
end
|
758
|
+
|
759
|
+
# @overload node(node, source_range)
|
760
|
+
# @param node [Sass::Script::Tree::Node]
|
761
|
+
# @param source_range [Sass::Source::Range]
|
762
|
+
# @overload node(node, start_pos, end_pos = source_position)
|
763
|
+
# @param node [Sass::Script::Tree::Node]
|
764
|
+
# @param start_pos [Sass::Source::Position]
|
765
|
+
# @param end_pos [Sass::Source::Position]
|
766
|
+
def node(node, source_range_or_start_pos, end_pos = source_position)
|
767
|
+
source_range =
|
768
|
+
if source_range_or_start_pos.is_a?(Sass::Source::Range)
|
769
|
+
source_range_or_start_pos
|
770
|
+
else
|
771
|
+
range(source_range_or_start_pos, end_pos)
|
772
|
+
end
|
773
|
+
|
774
|
+
node.css_variable_warning = @css_variable_warning
|
775
|
+
node.line = source_range.start_pos.line
|
776
|
+
node.source_range = source_range
|
777
|
+
node.filename = @options[:filename]
|
498
778
|
node
|
499
779
|
end
|
780
|
+
|
781
|
+
# Runs the given block without CSS variable warnings enabled.
|
782
|
+
#
|
783
|
+
# CSS warnings don't apply within interpolation, so this is used to
|
784
|
+
# disable them.
|
785
|
+
#
|
786
|
+
# @yield []
|
787
|
+
def without_css_variable_warning
|
788
|
+
old_css_variable_warning = @css_variable_warning
|
789
|
+
@css_variable_warning = nil
|
790
|
+
yield
|
791
|
+
ensure
|
792
|
+
@css_variable_warning = old_css_variable_warning
|
793
|
+
end
|
794
|
+
|
795
|
+
# Checks a script node for any immediately-deprecated interpolations, and
|
796
|
+
# emits warnings for them.
|
797
|
+
#
|
798
|
+
# @param node [Sass::Script::Tree::Node]
|
799
|
+
def check_for_interpolation(node)
|
800
|
+
nodes = [node]
|
801
|
+
until nodes.empty?
|
802
|
+
node = nodes.pop
|
803
|
+
unless node.is_a?(Sass::Script::Tree::Interpolation) &&
|
804
|
+
node.deprecation == :immediate
|
805
|
+
nodes.concat node.children
|
806
|
+
next
|
807
|
+
end
|
808
|
+
|
809
|
+
interpolation_deprecation(node)
|
810
|
+
end
|
811
|
+
end
|
812
|
+
|
813
|
+
# Emits a deprecation warning for an interpolation node.
|
814
|
+
#
|
815
|
+
# @param node [Sass::Script::Tree::Node]
|
816
|
+
def interpolation_deprecation(interpolation)
|
817
|
+
return if @options[:_convert]
|
818
|
+
location = "on line #{interpolation.line}"
|
819
|
+
location << " of #{interpolation.filename}" if interpolation.filename
|
820
|
+
Sass::Util.sass_warn <<WARNING
|
821
|
+
DEPRECATION WARNING #{location}:
|
822
|
+
\#{} interpolation near operators will be simplified in a future version of Sass.
|
823
|
+
To preserve the current behavior, use quotes:
|
824
|
+
|
825
|
+
#{interpolation.to_quoted_equivalent.to_sass}
|
826
|
+
|
827
|
+
You can use the sass-convert command to automatically fix most cases.
|
828
|
+
WARNING
|
829
|
+
end
|
500
830
|
end
|
501
831
|
end
|
502
832
|
end
|