oreorenasass 3.4.4 → 3.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +50 -70
- data/Rakefile +5 -26
- data/VERSION +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass.rb +12 -19
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +1 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -1
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +0 -1
- data/lib/sass/css.rb +13 -11
- data/lib/sass/engine.rb +173 -424
- data/lib/sass/environment.rb +58 -148
- data/lib/sass/error.rb +14 -11
- data/lib/sass/exec.rb +703 -5
- data/lib/sass/importers/base.rb +6 -49
- data/lib/sass/importers/filesystem.rb +19 -44
- data/lib/sass/logger.rb +4 -1
- data/lib/sass/logger/base.rb +4 -2
- data/lib/sass/logger/log_level.rb +7 -3
- data/lib/sass/media.rb +23 -20
- data/lib/sass/plugin.rb +7 -7
- data/lib/sass/plugin/compiler.rb +145 -304
- data/lib/sass/plugin/configuration.rb +23 -18
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script.rb +8 -35
- data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
- data/lib/sass/script/bool.rb +18 -0
- data/lib/sass/script/color.rb +606 -0
- data/lib/sass/script/css_lexer.rb +4 -8
- data/lib/sass/script/css_parser.rb +2 -5
- data/lib/sass/script/funcall.rb +245 -0
- data/lib/sass/script/functions.rb +408 -1491
- data/lib/sass/script/interpolation.rb +79 -0
- data/lib/sass/script/lexer.rb +68 -172
- data/lib/sass/script/list.rb +85 -0
- data/lib/sass/script/literal.rb +221 -0
- data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
- data/lib/sass/script/{value/null.rb → null.rb} +7 -14
- data/lib/sass/script/{value/number.rb → number.rb} +75 -152
- data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
- data/lib/sass/script/parser.rb +110 -245
- data/lib/sass/script/string.rb +51 -0
- data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
- data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
- data/lib/sass/script/variable.rb +58 -0
- data/lib/sass/scss/css_parser.rb +3 -9
- data/lib/sass/scss/parser.rb +421 -450
- data/lib/sass/scss/rx.rb +11 -19
- data/lib/sass/scss/static_parser.rb +7 -321
- data/lib/sass/selector.rb +194 -68
- data/lib/sass/selector/abstract_sequence.rb +14 -29
- data/lib/sass/selector/comma_sequence.rb +25 -108
- data/lib/sass/selector/sequence.rb +66 -159
- data/lib/sass/selector/simple.rb +25 -23
- data/lib/sass/selector/simple_sequence.rb +63 -173
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/supports.rb +15 -13
- data/lib/sass/tree/charset_node.rb +1 -1
- 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 +4 -21
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +7 -14
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +4 -9
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +5 -4
- data/lib/sass/tree/media_node.rb +14 -4
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +8 -21
- data/lib/sass/tree/node.rb +12 -54
- data/lib/sass/tree/prop_node.rb +20 -39
- data/lib/sass/tree/return_node.rb +2 -3
- data/lib/sass/tree/root_node.rb +3 -19
- data/lib/sass/tree/rule_node.rb +22 -35
- data/lib/sass/tree/supports_node.rb +13 -0
- data/lib/sass/tree/trace_node.rb +1 -2
- data/lib/sass/tree/variable_node.rb +3 -9
- data/lib/sass/tree/visitors/base.rb +8 -5
- data/lib/sass/tree/visitors/check_nesting.rb +19 -49
- data/lib/sass/tree/visitors/convert.rb +56 -74
- data/lib/sass/tree/visitors/cssize.rb +74 -202
- data/lib/sass/tree/visitors/deep_copy.rb +5 -10
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +185 -278
- data/lib/sass/tree/visitors/set_options.rb +6 -20
- data/lib/sass/tree/visitors/to_css.rb +81 -234
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util.rb +152 -522
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/subset_map.rb +3 -4
- data/lib/sass/util/test.rb +1 -0
- data/lib/sass/version.rb +22 -20
- data/test/Gemfile +3 -0
- data/test/Gemfile.lock +10 -0
- data/test/sass/cache_test.rb +20 -62
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/conversion_test.rb +2 -296
- data/test/sass/css2sass_test.rb +4 -23
- data/test/sass/engine_test.rb +354 -411
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +145 -324
- data/test/sass/functions_test.rb +86 -873
- data/test/sass/importer_test.rb +21 -241
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +26 -16
- 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 +3 -3
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +7 -36
- data/test/sass/script_test.rb +53 -485
- data/test/sass/scss/css_test.rb +28 -143
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +325 -2119
- data/test/sass/templates/scss_import.scss +1 -2
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +1 -86
- data/test/test_helper.rb +8 -37
- metadata +19 -66
- data/lib/sass/exec/base.rb +0 -187
- data/lib/sass/exec/sass_convert.rb +0 -264
- data/lib/sass/exec/sass_scss.rb +0 -424
- data/lib/sass/features.rb +0 -47
- data/lib/sass/script/tree.rb +0 -16
- data/lib/sass/script/tree/funcall.rb +0 -306
- data/lib/sass/script/tree/interpolation.rb +0 -118
- data/lib/sass/script/tree/list_literal.rb +0 -77
- data/lib/sass/script/tree/literal.rb +0 -45
- data/lib/sass/script/tree/map_literal.rb +0 -64
- data/lib/sass/script/tree/selector.rb +0 -26
- data/lib/sass/script/tree/variable.rb +0 -57
- data/lib/sass/script/value.rb +0 -11
- data/lib/sass/script/value/base.rb +0 -240
- data/lib/sass/script/value/bool.rb +0 -35
- data/lib/sass/script/value/color.rb +0 -680
- data/lib/sass/script/value/helpers.rb +0 -262
- data/lib/sass/script/value/list.rb +0 -113
- data/lib/sass/script/value/map.rb +0 -70
- data/lib/sass/script/value/string.rb +0 -97
- data/lib/sass/selector/pseudo.rb +0 -256
- data/lib/sass/source/map.rb +0 -210
- data/lib/sass/source/position.rb +0 -39
- data/lib/sass/source/range.rb +0 -41
- data/lib/sass/stack.rb +0 -120
- data/lib/sass/tree/at_root_node.rb +0 -83
- data/lib/sass/tree/error_node.rb +0 -18
- data/lib/sass/tree/keyframe_rule_node.rb +0 -15
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/normalized_map.rb +0 -130
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/compiler_test.rb +0 -232
- data/test/sass/encoding_test.rb +0 -219
- data/test/sass/source_map_test.rb +0 -977
- data/test/sass/superselector_test.rb +0 -191
- data/test/sass/util/normalized_map_test.rb +0 -51
- data/test/sass/value_helpers_test.rb +0 -179
@@ -1,4 +1,13 @@
|
|
1
|
-
|
1
|
+
require 'set'
|
2
|
+
require 'sass/script/string'
|
3
|
+
require 'sass/script/number'
|
4
|
+
require 'sass/script/color'
|
5
|
+
require 'sass/script/functions'
|
6
|
+
require 'sass/script/unary_operation'
|
7
|
+
require 'sass/script/interpolation'
|
8
|
+
require 'sass/script/string_interpolation'
|
9
|
+
|
10
|
+
module Sass::Script
|
2
11
|
# A SassScript parse node representing a binary operation,
|
3
12
|
# such as `$a + $b` or `"foo" + 1`.
|
4
13
|
class Operation < Node
|
@@ -6,12 +15,12 @@ module Sass::Script::Tree
|
|
6
15
|
attr_reader :operand2
|
7
16
|
attr_reader :operator
|
8
17
|
|
9
|
-
# @param operand1 [
|
18
|
+
# @param operand1 [Script::Node] The parse-tree node
|
10
19
|
# for the right-hand side of the operator
|
11
|
-
# @param operand2 [
|
20
|
+
# @param operand2 [Script::Node] The parse-tree node
|
12
21
|
# for the left-hand side of the operator
|
13
22
|
# @param operator [Symbol] The operator to perform.
|
14
|
-
# This should be one of the binary operator names in {
|
23
|
+
# This should be one of the binary operator names in {Lexer::OPERATORS}
|
15
24
|
def initialize(operand1, operand2, operator)
|
16
25
|
@operand1 = operand1
|
17
26
|
@operand2 = operand2
|
@@ -32,7 +41,7 @@ module Sass::Script::Tree
|
|
32
41
|
case @operator
|
33
42
|
when :comma; ", "
|
34
43
|
when :space; " "
|
35
|
-
else; " #{
|
44
|
+
else; " #{Lexer::OPERATORS_REVERSE[@operator]} "
|
36
45
|
end
|
37
46
|
"#{o1}#{sep}#{o2}"
|
38
47
|
end
|
@@ -58,38 +67,36 @@ module Sass::Script::Tree
|
|
58
67
|
# Evaluates the operation.
|
59
68
|
#
|
60
69
|
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
61
|
-
# @return [
|
70
|
+
# @return [Literal] The SassScript object that is the value of the operation
|
62
71
|
# @raise [Sass::SyntaxError] if the operation is undefined for the operands
|
63
72
|
def _perform(environment)
|
64
|
-
|
73
|
+
literal1 = @operand1.perform(environment)
|
65
74
|
|
66
75
|
# Special-case :and and :or to support short-circuiting.
|
67
76
|
if @operator == :and
|
68
|
-
return
|
77
|
+
return literal1.to_bool ? @operand2.perform(environment) : literal1
|
69
78
|
elsif @operator == :or
|
70
|
-
return
|
79
|
+
return literal1.to_bool ? literal1 : @operand2.perform(environment)
|
71
80
|
end
|
72
81
|
|
73
|
-
|
82
|
+
literal2 = @operand2.perform(environment)
|
74
83
|
|
75
|
-
if (
|
76
|
-
|
77
|
-
raise Sass::SyntaxError.new(
|
78
|
-
"Invalid null operation: \"#{value1.inspect} #{@operator} #{value2.inspect}\".")
|
84
|
+
if (literal1.is_a?(Null) || literal2.is_a?(Null)) && @operator != :eq && @operator != :neq
|
85
|
+
raise Sass::SyntaxError.new("Invalid null operation: \"#{literal1.inspect} #{@operator} #{literal2.inspect}\".")
|
79
86
|
end
|
80
87
|
|
81
88
|
begin
|
82
|
-
opts(
|
89
|
+
opts(literal1.send(@operator, literal2))
|
83
90
|
rescue NoMethodError => e
|
84
91
|
raise e unless e.name.to_s == @operator.to_s
|
85
|
-
raise Sass::SyntaxError.new("Undefined operation: \"#{
|
92
|
+
raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
|
86
93
|
end
|
87
94
|
end
|
88
95
|
|
89
96
|
private
|
90
97
|
|
91
98
|
def operand_to_sass(op, side, opts)
|
92
|
-
return "(#{op.to_sass(opts)})" if op.is_a?(
|
99
|
+
return "(#{op.to_sass(opts)})" if op.is_a?(List)
|
93
100
|
return op.to_sass(opts) unless op.is_a?(Operation)
|
94
101
|
|
95
102
|
pred = Sass::Script::Parser.precedence_of(@operator)
|
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::
|
6
|
+
# It parses a string of code into a tree of {Script::Node}s.
|
7
7
|
class Parser
|
8
8
|
# The line number of the parser's current position.
|
9
9
|
#
|
@@ -12,18 +12,11 @@ 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
|
-
|
22
15
|
# @param str [String, StringScanner] The source text to parse
|
23
16
|
# @param line [Fixnum] The line on which the SassScript appears.
|
24
|
-
# Used for error reporting
|
25
|
-
# @param offset [Fixnum] The
|
26
|
-
# Used for error reporting
|
17
|
+
# Used for error reporting
|
18
|
+
# @param offset [Fixnum] The number of characters in on which the SassScript appears.
|
19
|
+
# Used for error reporting
|
27
20
|
# @param options [{Symbol => Object}] An options hash;
|
28
21
|
# see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
|
29
22
|
def initialize(str, line, offset, options = {})
|
@@ -36,19 +29,13 @@ module Sass
|
|
36
29
|
# which signals the end of an interpolated segment,
|
37
30
|
# it returns rather than throwing an error.
|
38
31
|
#
|
39
|
-
# @
|
40
|
-
# interoplation should cause a warning.
|
41
|
-
# @return [Script::Tree::Node] The root node of the parse tree
|
32
|
+
# @return [Script::Node] The root node of the parse tree
|
42
33
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
43
|
-
def parse_interpolated
|
44
|
-
# Start two characters back to compensate for #{
|
45
|
-
start_pos = Sass::Source::Position.new(line, offset - 2)
|
34
|
+
def parse_interpolated
|
46
35
|
expr = assert_expr :expr
|
47
36
|
assert_tok :end_interpolation
|
48
|
-
expr = Sass::Script::Tree::Interpolation.new(
|
49
|
-
nil, expr, nil, !:wb, !:wa, !:originally_text, warn_for_color)
|
50
37
|
expr.options = @options
|
51
|
-
|
38
|
+
expr
|
52
39
|
rescue Sass::SyntaxError => e
|
53
40
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
54
41
|
raise e
|
@@ -56,7 +43,7 @@ module Sass
|
|
56
43
|
|
57
44
|
# Parses a SassScript expression.
|
58
45
|
#
|
59
|
-
# @return [Script::
|
46
|
+
# @return [Script::Node] The root node of the parse tree
|
60
47
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
61
48
|
def parse
|
62
49
|
expr = assert_expr :expr
|
@@ -71,8 +58,8 @@ module Sass
|
|
71
58
|
# Parses a SassScript expression,
|
72
59
|
# ending it when it encounters one of the given identifier tokens.
|
73
60
|
#
|
74
|
-
# @param
|
75
|
-
# @return [Script::
|
61
|
+
# @param [#include?(String)] A set of strings that delimit the expression.
|
62
|
+
# @return [Script::Node] The root node of the parse tree
|
76
63
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
77
64
|
def parse_until(tokens)
|
78
65
|
@stop_at = tokens
|
@@ -87,17 +74,14 @@ module Sass
|
|
87
74
|
|
88
75
|
# Parses the argument list for a mixin include.
|
89
76
|
#
|
90
|
-
# @return [(Array<Script::
|
91
|
-
# {String => Script::Tree::Node},
|
92
|
-
# Script::Tree::Node,
|
93
|
-
# Script::Tree::Node)]
|
77
|
+
# @return [(Array<Script::Node>, {String => Script::Node}, Script::Node)]
|
94
78
|
# The root nodes of the positional arguments, keyword arguments, and
|
95
|
-
# splat argument
|
79
|
+
# splat argument. Keyword arguments are in a hash from names to values.
|
96
80
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
97
81
|
def parse_mixin_include_arglist
|
98
82
|
args, keywords = [], {}
|
99
83
|
if try_tok(:lparen)
|
100
|
-
args, keywords, splat
|
84
|
+
args, keywords, splat = mixin_arglist || [[], {}]
|
101
85
|
assert_tok(:rparen)
|
102
86
|
end
|
103
87
|
assert_done
|
@@ -105,8 +89,7 @@ module Sass
|
|
105
89
|
args.each {|a| a.options = @options}
|
106
90
|
keywords.each {|k, v| v.options = @options}
|
107
91
|
splat.options = @options if splat
|
108
|
-
|
109
|
-
return args, keywords, splat, kwarg_splat
|
92
|
+
return args, keywords, splat
|
110
93
|
rescue Sass::SyntaxError => e
|
111
94
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
112
95
|
raise e
|
@@ -114,7 +97,7 @@ module Sass
|
|
114
97
|
|
115
98
|
# Parses the argument list for a mixin definition.
|
116
99
|
#
|
117
|
-
# @return [(Array<Script::
|
100
|
+
# @return [(Array<Script::Node>, Script::Node)]
|
118
101
|
# The root nodes of the arguments, and the splat argument.
|
119
102
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
120
103
|
def parse_mixin_definition_arglist
|
@@ -134,7 +117,7 @@ module Sass
|
|
134
117
|
|
135
118
|
# Parses the argument list for a function definition.
|
136
119
|
#
|
137
|
-
# @return [(Array<Script::
|
120
|
+
# @return [(Array<Script::Node>, Script::Node)]
|
138
121
|
# The root nodes of the arguments, and the splat argument.
|
139
122
|
# @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
|
140
123
|
def parse_function_definition_arglist
|
@@ -155,7 +138,7 @@ module Sass
|
|
155
138
|
# Parse a single string value, possibly containing interpolation.
|
156
139
|
# Doesn't assert that the scanner is finished after parsing.
|
157
140
|
#
|
158
|
-
# @return [Script::
|
141
|
+
# @return [Script::Node] The root node of the parse tree.
|
159
142
|
# @raise [Sass::SyntaxError] if the string isn't valid SassScript
|
160
143
|
def parse_string
|
161
144
|
unless (peek = @lexer.peek) &&
|
@@ -176,7 +159,7 @@ module Sass
|
|
176
159
|
# Parses a SassScript expression.
|
177
160
|
#
|
178
161
|
# @overload parse(str, line, offset, filename = nil)
|
179
|
-
# @return [Script::
|
162
|
+
# @return [Script::Node] The root node of the parse tree
|
180
163
|
# @see Parser#initialize
|
181
164
|
# @see Parser#parse
|
182
165
|
def self.parse(*args)
|
@@ -203,7 +186,7 @@ module Sass
|
|
203
186
|
PRECEDENCE.each_with_index do |e, i|
|
204
187
|
return i if Array(e).include?(op)
|
205
188
|
end
|
206
|
-
raise "[BUG] Unknown operator #{op
|
189
|
+
raise "[BUG] Unknown operator #{op}"
|
207
190
|
end
|
208
191
|
|
209
192
|
# Returns whether or not the given operation is associative.
|
@@ -222,18 +205,17 @@ module Sass
|
|
222
205
|
def production(name, sub, *ops)
|
223
206
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
224
207
|
def #{name}
|
225
|
-
interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect})
|
226
|
-
return interp if interp
|
208
|
+
interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}) and return interp
|
227
209
|
return unless e = #{sub}
|
228
|
-
while tok =
|
210
|
+
while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
|
229
211
|
if interp = try_op_before_interp(tok, e)
|
230
|
-
other_interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}, interp)
|
231
|
-
return interp unless other_interp
|
212
|
+
return interp unless other_interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}, interp)
|
232
213
|
return other_interp
|
233
214
|
end
|
234
215
|
|
235
|
-
|
236
|
-
|
216
|
+
line = @lexer.line
|
217
|
+
e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
|
218
|
+
e.line = line
|
237
219
|
end
|
238
220
|
e
|
239
221
|
end
|
@@ -244,10 +226,11 @@ RUBY
|
|
244
226
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
245
227
|
def unary_#{op}
|
246
228
|
return #{sub} unless tok = try_tok(:#{op})
|
247
|
-
interp = try_op_before_interp(tok)
|
248
|
-
|
249
|
-
|
250
|
-
|
229
|
+
interp = try_op_before_interp(tok) and return interp
|
230
|
+
line = @lexer.line
|
231
|
+
op = UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
|
232
|
+
op.line = line
|
233
|
+
op
|
251
234
|
end
|
252
235
|
RUBY
|
253
236
|
end
|
@@ -255,61 +238,21 @@ RUBY
|
|
255
238
|
|
256
239
|
private
|
257
240
|
|
258
|
-
def source_position
|
259
|
-
Sass::Source::Position.new(line, offset)
|
260
|
-
end
|
261
|
-
|
262
|
-
def range(start_pos, end_pos = source_position)
|
263
|
-
Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
|
264
|
-
end
|
265
|
-
|
266
241
|
# @private
|
267
242
|
def lexer_class; Lexer; end
|
268
243
|
|
269
|
-
def map
|
270
|
-
start_pos = source_position
|
271
|
-
e = interpolation
|
272
|
-
return unless e
|
273
|
-
return list e, start_pos unless @lexer.peek && @lexer.peek.type == :colon
|
274
|
-
|
275
|
-
pair = map_pair(e)
|
276
|
-
map = node(Sass::Script::Tree::MapLiteral.new([pair]), start_pos)
|
277
|
-
while try_tok(:comma)
|
278
|
-
pair = map_pair
|
279
|
-
return map unless pair
|
280
|
-
map.pairs << pair
|
281
|
-
end
|
282
|
-
map
|
283
|
-
end
|
284
|
-
|
285
|
-
def map_pair(key = nil)
|
286
|
-
return unless key ||= interpolation
|
287
|
-
assert_tok :colon
|
288
|
-
return key, assert_expr(:interpolation)
|
289
|
-
end
|
290
|
-
|
291
244
|
def expr
|
292
|
-
|
293
|
-
e = interpolation
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
def list(first, start_pos)
|
299
|
-
return first unless @lexer.peek && @lexer.peek.type == :comma
|
300
|
-
|
301
|
-
list = node(Sass::Script::Tree::ListLiteral.new([first], :comma), start_pos)
|
302
|
-
while (tok = try_tok(:comma))
|
303
|
-
element_before_interp = list.elements.length == 1 ? list.elements.first : list
|
304
|
-
if (interp = try_op_before_interp(tok, element_before_interp))
|
305
|
-
other_interp = try_ops_after_interp([:comma], :expr, interp)
|
306
|
-
return interp unless other_interp
|
245
|
+
line = @lexer.line
|
246
|
+
return unless e = interpolation
|
247
|
+
list = node(List.new([e], :comma), line)
|
248
|
+
while tok = try_tok(:comma)
|
249
|
+
if interp = try_op_before_interp(tok, list)
|
250
|
+
return interp unless other_interp = try_ops_after_interp([:comma], :expr, interp)
|
307
251
|
return other_interp
|
308
252
|
end
|
309
|
-
|
310
|
-
list.elements << e
|
253
|
+
list.value << assert_expr(:interpolation)
|
311
254
|
end
|
312
|
-
list
|
255
|
+
list.value.size == 1 ? list.value.first : list
|
313
256
|
end
|
314
257
|
|
315
258
|
production :equals, :interpolation, :single_eq
|
@@ -317,58 +260,47 @@ RUBY
|
|
317
260
|
def try_op_before_interp(op, prev = nil)
|
318
261
|
return unless @lexer.peek && @lexer.peek.type == :begin_interpolation
|
319
262
|
wb = @lexer.whitespace?(op)
|
320
|
-
str =
|
321
|
-
|
322
|
-
interp =
|
323
|
-
|
324
|
-
(prev || str).source_range.start_pos)
|
263
|
+
str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
|
264
|
+
str.line = @lexer.line
|
265
|
+
interp = Script::Interpolation.new(prev, str, nil, wb, !:wa, :originally_text)
|
266
|
+
interp.line = @lexer.line
|
325
267
|
interpolation(interp)
|
326
268
|
end
|
327
269
|
|
328
270
|
def try_ops_after_interp(ops, name, prev = nil)
|
329
271
|
return unless @lexer.after_interpolation?
|
330
|
-
op =
|
331
|
-
|
332
|
-
interp = try_op_before_interp(op, prev)
|
333
|
-
return interp if interp
|
272
|
+
return unless op = try_tok(*ops)
|
273
|
+
interp = try_op_before_interp(op, prev) and return interp
|
334
274
|
|
335
275
|
wa = @lexer.whitespace?
|
336
|
-
str =
|
337
|
-
op.source_range)
|
276
|
+
str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
|
338
277
|
str.line = @lexer.line
|
339
|
-
interp =
|
340
|
-
|
341
|
-
|
342
|
-
interp
|
278
|
+
interp = Script::Interpolation.new(prev, str, assert_expr(name), !:wb, wa, :originally_text)
|
279
|
+
interp.line = @lexer.line
|
280
|
+
return interp
|
343
281
|
end
|
344
282
|
|
345
283
|
def interpolation(first = space)
|
346
284
|
e = first
|
347
|
-
while
|
285
|
+
while interp = try_tok(:begin_interpolation)
|
348
286
|
wb = @lexer.whitespace?(interp)
|
349
|
-
|
350
|
-
|
287
|
+
line = @lexer.line
|
288
|
+
mid = parse_interpolated
|
351
289
|
wa = @lexer.whitespace?
|
352
|
-
e =
|
353
|
-
|
354
|
-
(e || mid).source_range.start_pos)
|
290
|
+
e = Script::Interpolation.new(e, mid, space, wb, wa)
|
291
|
+
e.line = line
|
355
292
|
end
|
356
293
|
e
|
357
294
|
end
|
358
295
|
|
359
296
|
def space
|
360
|
-
|
361
|
-
e = or_expr
|
362
|
-
return unless e
|
297
|
+
line = @lexer.line
|
298
|
+
return unless e = or_expr
|
363
299
|
arr = [e]
|
364
|
-
while
|
300
|
+
while e = or_expr
|
365
301
|
arr << e
|
366
302
|
end
|
367
|
-
|
368
|
-
arr.first
|
369
|
-
else
|
370
|
-
node(Sass::Script::Tree::ListLiteral.new(arr, :space), start_pos)
|
371
|
-
end
|
303
|
+
arr.size == 1 ? arr.first : node(List.new(arr, :space), line)
|
372
304
|
end
|
373
305
|
|
374
306
|
production :or_expr, :and_expr, :or
|
@@ -388,26 +320,24 @@ RUBY
|
|
388
320
|
return if @stop_at && @stop_at.include?(@lexer.peek.value)
|
389
321
|
|
390
322
|
name = @lexer.next
|
391
|
-
if
|
392
|
-
|
323
|
+
if color = Color::COLOR_NAMES[name.value.downcase]
|
324
|
+
node(Color.new(color))
|
393
325
|
elsif name.value == "true"
|
394
|
-
|
326
|
+
node(Script::Bool.new(true))
|
395
327
|
elsif name.value == "false"
|
396
|
-
|
328
|
+
node(Script::Bool.new(false))
|
397
329
|
elsif name.value == "null"
|
398
|
-
|
330
|
+
node(Script::Null.new)
|
399
331
|
else
|
400
|
-
|
332
|
+
node(Script::String.new(name.value, :identifier))
|
401
333
|
end
|
402
334
|
end
|
403
335
|
|
404
336
|
def funcall
|
405
|
-
tok = try_tok(:funcall)
|
406
|
-
|
407
|
-
args, keywords, splat, kwarg_splat = fn_arglist
|
337
|
+
return raw unless tok = try_tok(:funcall)
|
338
|
+
args, keywords, splat = fn_arglist || [[], {}]
|
408
339
|
assert_tok(:rparen)
|
409
|
-
node(Script::
|
410
|
-
tok.source_range.start_pos, source_position)
|
340
|
+
node(Script::Funcall.new(tok.value, args, keywords, splat))
|
411
341
|
end
|
412
342
|
|
413
343
|
def defn_arglist!(must_have_parens)
|
@@ -423,16 +353,15 @@ RUBY
|
|
423
353
|
must_have_default = false
|
424
354
|
loop do
|
425
355
|
c = assert_tok(:const)
|
426
|
-
var =
|
356
|
+
var = Script::Variable.new(c.value)
|
427
357
|
if try_tok(:colon)
|
428
358
|
val = assert_expr(:space)
|
429
359
|
must_have_default = true
|
360
|
+
elsif must_have_default
|
361
|
+
raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.")
|
430
362
|
elsif try_tok(:splat)
|
431
363
|
splat = var
|
432
364
|
break
|
433
|
-
elsif must_have_default
|
434
|
-
raise SyntaxError.new(
|
435
|
-
"Required argument #{var.inspect} must come before any optional arguments.")
|
436
365
|
end
|
437
366
|
res << [var, val]
|
438
367
|
break unless try_tok(:comma)
|
@@ -450,108 +379,88 @@ RUBY
|
|
450
379
|
end
|
451
380
|
|
452
381
|
def arglist(subexpr, description)
|
453
|
-
|
454
|
-
keywords = Sass::Util::NormalizedMap.new
|
455
|
-
e = send(subexpr)
|
382
|
+
return unless e = send(subexpr)
|
456
383
|
|
457
|
-
|
458
|
-
|
459
|
-
splat = nil
|
384
|
+
args = []
|
385
|
+
keywords = {}
|
460
386
|
loop do
|
461
387
|
if @lexer.peek && @lexer.peek.type == :colon
|
462
388
|
name = e
|
463
|
-
@lexer.expected!("comma") unless name.is_a?(
|
389
|
+
@lexer.expected!("comma") unless name.is_a?(Variable)
|
464
390
|
assert_tok(:colon)
|
465
391
|
value = assert_expr(subexpr, description)
|
466
392
|
|
467
|
-
if keywords[name.
|
393
|
+
if keywords[name.underscored_name]
|
468
394
|
raise SyntaxError.new("Keyword argument \"#{name.to_sass}\" passed more than once")
|
469
395
|
end
|
470
396
|
|
471
|
-
keywords[name.
|
397
|
+
keywords[name.underscored_name] = value
|
472
398
|
else
|
473
|
-
if
|
474
|
-
return args, keywords, splat, e if splat
|
475
|
-
splat, e = e, nil
|
476
|
-
elsif splat
|
477
|
-
raise SyntaxError.new("Only keyword arguments may follow variable arguments (...).")
|
478
|
-
elsif !keywords.empty?
|
399
|
+
if !keywords.empty?
|
479
400
|
raise SyntaxError.new("Positional arguments must come before keyword arguments.")
|
480
401
|
end
|
481
402
|
|
482
|
-
args
|
403
|
+
return args, keywords, e if try_tok(:splat)
|
404
|
+
args << e
|
483
405
|
end
|
484
406
|
|
485
|
-
return args, keywords
|
407
|
+
return args, keywords unless try_tok(:comma)
|
486
408
|
e = assert_expr(subexpr, description)
|
487
409
|
end
|
488
410
|
end
|
489
411
|
|
490
412
|
def raw
|
491
|
-
tok = try_tok(:raw)
|
492
|
-
|
493
|
-
literal_node(Script::Value::String.new(tok.value), tok.source_range)
|
413
|
+
return special_fun unless tok = try_tok(:raw)
|
414
|
+
node(Script::String.new(tok.value))
|
494
415
|
end
|
495
416
|
|
496
417
|
def special_fun
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
first.source_range.start_pos)
|
418
|
+
return paren unless tok = try_tok(:special_fun)
|
419
|
+
first = node(Script::String.new(tok.value.first))
|
420
|
+
Sass::Util.enum_slice(tok.value[1..-1], 2).inject(first) do |l, (i, r)|
|
421
|
+
Script::Interpolation.new(
|
422
|
+
l, i, r && node(Script::String.new(r)),
|
423
|
+
false, false)
|
424
|
+
end
|
505
425
|
end
|
506
426
|
|
507
427
|
def paren
|
508
428
|
return variable unless try_tok(:lparen)
|
509
429
|
was_in_parens = @in_parens
|
510
430
|
@in_parens = true
|
511
|
-
|
512
|
-
e =
|
513
|
-
end_pos = source_position
|
431
|
+
line = @lexer.line
|
432
|
+
e = expr
|
514
433
|
assert_tok(:rparen)
|
515
|
-
return e || node(
|
434
|
+
return e || node(List.new([], :space), line)
|
516
435
|
ensure
|
517
436
|
@in_parens = was_in_parens
|
518
437
|
end
|
519
438
|
|
520
439
|
def variable
|
521
|
-
|
522
|
-
c
|
523
|
-
return string unless c
|
524
|
-
node(Tree::Variable.new(*c.value), start_pos)
|
440
|
+
return string unless c = try_tok(:const)
|
441
|
+
node(Variable.new(*c.value))
|
525
442
|
end
|
526
443
|
|
527
444
|
def string
|
528
|
-
first = try_tok(:string)
|
529
|
-
return
|
530
|
-
|
531
|
-
|
532
|
-
mid = assert_expr :expr
|
533
|
-
assert_tok :end_interpolation
|
445
|
+
return number unless first = try_tok(:string)
|
446
|
+
return first.value unless try_tok(:begin_interpolation)
|
447
|
+
line = @lexer.line
|
448
|
+
mid = parse_interpolated
|
534
449
|
last = assert_expr(:string)
|
535
|
-
|
450
|
+
interp = StringInterpolation.new(first.value, mid, last)
|
451
|
+
interp.line = line
|
452
|
+
interp
|
536
453
|
end
|
537
454
|
|
538
455
|
def number
|
539
|
-
tok = try_tok(:number)
|
540
|
-
return selector unless tok
|
456
|
+
return literal unless tok = try_tok(:number)
|
541
457
|
num = tok.value
|
542
458
|
num.original = num.to_s unless @in_parens
|
543
|
-
|
544
|
-
end
|
545
|
-
|
546
|
-
def selector
|
547
|
-
tok = try_tok(:selector)
|
548
|
-
return literal unless tok
|
549
|
-
node(tok.value, tok.source_range.start_pos)
|
459
|
+
num
|
550
460
|
end
|
551
461
|
|
552
462
|
def literal
|
553
|
-
t = try_tok(:color)
|
554
|
-
return literal_node(t.value, t.source_range) if t
|
463
|
+
(t = try_tok(:color)) && (return t.value)
|
555
464
|
end
|
556
465
|
|
557
466
|
# It would be possible to have unified #assert and #try methods,
|
@@ -562,37 +471,20 @@ RUBY
|
|
562
471
|
:default => "expression (e.g. 1px, bold)",
|
563
472
|
:mixin_arglist => "mixin argument",
|
564
473
|
:fn_arglist => "function argument",
|
565
|
-
:splat => "...",
|
566
|
-
:special_fun => '")"',
|
567
474
|
}
|
568
475
|
|
569
476
|
def assert_expr(name, expected = nil)
|
570
|
-
e = send(name)
|
571
|
-
return e if e
|
477
|
+
(e = send(name)) && (return e)
|
572
478
|
@lexer.expected!(expected || EXPR_NAMES[name] || EXPR_NAMES[:default])
|
573
479
|
end
|
574
480
|
|
575
|
-
def assert_tok(
|
576
|
-
|
577
|
-
t = try_tok(name)
|
578
|
-
return t if t
|
579
|
-
@lexer.expected!(Lexer::TOKEN_NAMES[name] || name.to_s)
|
580
|
-
end
|
581
|
-
|
582
|
-
def assert_toks(*names)
|
583
|
-
t = try_toks(*names)
|
584
|
-
return t if t
|
481
|
+
def assert_tok(*names)
|
482
|
+
(t = try_tok(*names)) && (return t)
|
585
483
|
@lexer.expected!(names.map {|tok| Lexer::TOKEN_NAMES[tok] || tok}.join(" or "))
|
586
484
|
end
|
587
485
|
|
588
|
-
def try_tok(
|
589
|
-
|
590
|
-
peeked = @lexer.peek
|
591
|
-
peeked && name == peeked.type && @lexer.next
|
592
|
-
end
|
593
|
-
|
594
|
-
def try_toks(*names)
|
595
|
-
peeked = @lexer.peek
|
486
|
+
def try_tok(*names)
|
487
|
+
peeked = @lexer.peek
|
596
488
|
peeked && names.include?(peeked.type) && @lexer.next
|
597
489
|
end
|
598
490
|
|
@@ -601,35 +493,8 @@ RUBY
|
|
601
493
|
@lexer.expected!(EXPR_NAMES[:default])
|
602
494
|
end
|
603
495
|
|
604
|
-
|
605
|
-
|
606
|
-
# @param source_range [Sass::Source::Range]
|
607
|
-
# @overload node(value, start_pos, end_pos = source_position)
|
608
|
-
# @param value [Sass::Script::Value::Base]
|
609
|
-
# @param start_pos [Sass::Source::Position]
|
610
|
-
# @param end_pos [Sass::Source::Position]
|
611
|
-
def literal_node(value, source_range_or_start_pos, end_pos = source_position)
|
612
|
-
node(Sass::Script::Tree::Literal.new(value), source_range_or_start_pos, end_pos)
|
613
|
-
end
|
614
|
-
|
615
|
-
# @overload node(node, source_range)
|
616
|
-
# @param node [Sass::Script::Tree::Node]
|
617
|
-
# @param source_range [Sass::Source::Range]
|
618
|
-
# @overload node(node, start_pos, end_pos = source_position)
|
619
|
-
# @param node [Sass::Script::Tree::Node]
|
620
|
-
# @param start_pos [Sass::Source::Position]
|
621
|
-
# @param end_pos [Sass::Source::Position]
|
622
|
-
def node(node, source_range_or_start_pos, end_pos = source_position)
|
623
|
-
source_range =
|
624
|
-
if source_range_or_start_pos.is_a?(Sass::Source::Range)
|
625
|
-
source_range_or_start_pos
|
626
|
-
else
|
627
|
-
range(source_range_or_start_pos, end_pos)
|
628
|
-
end
|
629
|
-
|
630
|
-
node.line = source_range.start_pos.line
|
631
|
-
node.source_range = source_range
|
632
|
-
node.filename = @options[:filename]
|
496
|
+
def node(node, line = @lexer.line)
|
497
|
+
node.line = line
|
633
498
|
node
|
634
499
|
end
|
635
500
|
end
|