haml-edge 2.3.179 → 2.3.180
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/EDGE_GEM_VERSION +1 -1
- data/README.md +88 -149
- data/VERSION +1 -1
- data/bin/css2sass +7 -1
- data/bin/sass-convert +7 -0
- data/lib/haml/exec.rb +95 -22
- data/lib/haml/template.rb +1 -1
- data/lib/haml/util.rb +50 -0
- data/lib/sass.rb +1 -1
- data/lib/sass/css.rb +38 -210
- data/lib/sass/engine.rb +121 -47
- data/lib/sass/files.rb +28 -19
- data/lib/sass/plugin.rb +32 -43
- data/lib/sass/repl.rb +1 -1
- data/lib/sass/script.rb +25 -6
- data/lib/sass/script/bool.rb +1 -0
- data/lib/sass/script/color.rb +2 -2
- data/lib/sass/script/css_lexer.rb +22 -0
- data/lib/sass/script/css_parser.rb +28 -0
- data/lib/sass/script/funcall.rb +17 -9
- data/lib/sass/script/functions.rb +46 -1
- data/lib/sass/script/interpolation.rb +42 -0
- data/lib/sass/script/lexer.rb +142 -34
- data/lib/sass/script/literal.rb +28 -12
- data/lib/sass/script/node.rb +57 -1
- data/lib/sass/script/number.rb +18 -3
- data/lib/sass/script/operation.rb +44 -8
- data/lib/sass/script/parser.rb +149 -24
- data/lib/sass/script/string.rb +50 -2
- data/lib/sass/script/unary_operation.rb +25 -10
- data/lib/sass/script/variable.rb +20 -11
- data/lib/sass/scss.rb +14 -0
- data/lib/sass/scss/css_parser.rb +39 -0
- data/lib/sass/scss/parser.rb +683 -0
- data/lib/sass/scss/rx.rb +112 -0
- data/lib/sass/scss/script_lexer.rb +13 -0
- data/lib/sass/scss/script_parser.rb +25 -0
- data/lib/sass/tree/comment_node.rb +58 -16
- data/lib/sass/tree/debug_node.rb +7 -2
- data/lib/sass/tree/directive_node.rb +38 -34
- data/lib/sass/tree/for_node.rb +6 -0
- data/lib/sass/tree/if_node.rb +13 -0
- data/lib/sass/tree/import_node.rb +26 -7
- data/lib/sass/tree/mixin_def_node.rb +18 -0
- data/lib/sass/tree/mixin_node.rb +16 -1
- data/lib/sass/tree/node.rb +98 -27
- data/lib/sass/tree/prop_node.rb +97 -20
- data/lib/sass/tree/root_node.rb +37 -0
- data/lib/sass/tree/rule_node.rb +88 -60
- data/lib/sass/tree/variable_node.rb +9 -5
- data/lib/sass/tree/while_node.rb +4 -0
- data/test/haml/results/filters.xhtml +1 -1
- data/test/haml/util_test.rb +28 -0
- data/test/sass/conversion_test.rb +884 -0
- data/test/sass/css2sass_test.rb +46 -21
- data/test/sass/engine_test.rb +680 -160
- data/test/sass/functions_test.rb +27 -0
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/more_templates/more_import.sass +3 -3
- data/test/sass/plugin_test.rb +28 -8
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +5 -5
- data/test/sass/results/compressed.css +1 -1
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +3 -1
- data/test/sass/results/mixins.css +12 -12
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/parent_ref.css +4 -4
- data/test/sass/results/script.css +3 -3
- data/test/sass/results/scss_import.css +15 -0
- data/test/sass/results/scss_importee.css +2 -0
- data/test/sass/script_conversion_test.rb +153 -0
- data/test/sass/script_test.rb +44 -54
- data/test/sass/scss/css_test.rb +811 -0
- data/test/sass/scss/rx_test.rb +156 -0
- data/test/sass/scss/scss_test.rb +871 -0
- data/test/sass/scss/test_helper.rb +37 -0
- data/test/sass/templates/alt.sass +2 -2
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/import.sass +4 -4
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/line_numbers.sass +1 -1
- data/test/sass/templates/mixins.sass +2 -2
- data/test/sass/templates/nested_mixin_bork.sass +1 -1
- data/test/sass/templates/options.sass +1 -1
- data/test/sass/templates/parent_ref.sass +2 -2
- data/test/sass/templates/script.sass +69 -69
- data/test/sass/templates/scss_import.scss +10 -0
- data/test/sass/templates/scss_importee.scss +1 -0
- data/test/sass/templates/units.sass +10 -10
- data/test/test_helper.rb +4 -4
- metadata +27 -2
data/lib/sass/script/node.rb
CHANGED
@@ -8,6 +8,23 @@ module Sass::Script
|
|
8
8
|
# @return [{Symbol => Object}]
|
9
9
|
attr_reader :options
|
10
10
|
|
11
|
+
# The context in which this node was parsed,
|
12
|
+
# which determines how some operations are performed.
|
13
|
+
#
|
14
|
+
# Can be `:equals`, which means it's part of a `$var = val` or `prop = val` assignment,
|
15
|
+
# or `:default`, which means it's anywhere else
|
16
|
+
# (including `$var: val` and `prop: val` assignments,
|
17
|
+
# `#{}`-interpolations,
|
18
|
+
# and other script contexts such as `@if` conditions).
|
19
|
+
#
|
20
|
+
# @return [Symbol]
|
21
|
+
attr_reader :context
|
22
|
+
|
23
|
+
# The line of the document on which this node appeared.
|
24
|
+
#
|
25
|
+
# @return [Fixnum]
|
26
|
+
attr_accessor :line
|
27
|
+
|
11
28
|
# Sets the options hash for this node,
|
12
29
|
# as well as for all child nodes.
|
13
30
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
@@ -18,12 +35,33 @@ module Sass::Script
|
|
18
35
|
children.each {|c| c.options = options}
|
19
36
|
end
|
20
37
|
|
38
|
+
# Sets the options hash for this node,
|
39
|
+
# as well as for all child nodes.
|
40
|
+
#
|
41
|
+
# @param context [Symbol]
|
42
|
+
# @see #context
|
43
|
+
def context=(context)
|
44
|
+
@context = context
|
45
|
+
children.each {|c| c.context = context}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates a new script node.
|
49
|
+
def initialize
|
50
|
+
@context = :default
|
51
|
+
end
|
52
|
+
|
21
53
|
# Evaluates the node.
|
22
54
|
#
|
55
|
+
# \{#perform} shouldn't be overridden directly;
|
56
|
+
# instead, override \{#\_perform}.
|
57
|
+
#
|
23
58
|
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
24
59
|
# @return [Literal] The SassScript object that is the value of the SassScript
|
25
60
|
def perform(environment)
|
26
|
-
|
61
|
+
_perform(environment)
|
62
|
+
rescue Sass::SyntaxError => e
|
63
|
+
e.modify_backtrace(:line => line)
|
64
|
+
raise e
|
27
65
|
end
|
28
66
|
|
29
67
|
# Returns all child nodes of this node.
|
@@ -32,5 +70,23 @@ module Sass::Script
|
|
32
70
|
def children
|
33
71
|
raise NotImplementedError.new("All subclasses of Sass::Script::Node must override #children.")
|
34
72
|
end
|
73
|
+
|
74
|
+
# Returns the text of this SassScript expression.
|
75
|
+
#
|
76
|
+
# @return [String]
|
77
|
+
def to_sass
|
78
|
+
raise NotImplementedError.new("All subclasses of Sass::Script::Node must override #to_sass.")
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
# Evaluates this node.
|
84
|
+
#
|
85
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
86
|
+
# @return [Literal] The SassScript object that is the value of the SassScript
|
87
|
+
# @see #perform
|
88
|
+
def _perform(environment)
|
89
|
+
raise NotImplementedError.new("All subclasses of Sass::Script::Node must override #_perform.")
|
90
|
+
end
|
35
91
|
end
|
36
92
|
end
|
data/lib/sass/script/number.rb
CHANGED
@@ -25,6 +25,8 @@ module Sass::Script
|
|
25
25
|
# @return [Array<String>]
|
26
26
|
attr_reader :denominator_units
|
27
27
|
|
28
|
+
attr_accessor :original
|
29
|
+
|
28
30
|
# The precision with which numbers will be printed to CSS files.
|
29
31
|
# For example, if this is `1000.0`,
|
30
32
|
# `3.1415926` will be printed as `3.142`.
|
@@ -65,7 +67,7 @@ module Sass::Script
|
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
68
|
-
# The SassScript binary `-` operation (e.g.
|
70
|
+
# The SassScript binary `-` operation (e.g. `$a - $b`).
|
69
71
|
# Its functionality depends on the type of its argument:
|
70
72
|
#
|
71
73
|
# {Number}
|
@@ -85,7 +87,14 @@ module Sass::Script
|
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
88
|
-
# The SassScript unary
|
90
|
+
# The SassScript unary `+` operation (e.g. `+$a`).
|
91
|
+
#
|
92
|
+
# @return [Number] The value of this number
|
93
|
+
def unary_plus
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# The SassScript unary `-` operation (e.g. `-$a`).
|
89
98
|
#
|
90
99
|
# @return [Number] The negative value of this number
|
91
100
|
def unary_minus
|
@@ -127,7 +136,11 @@ module Sass::Script
|
|
127
136
|
# @return [Literal] The result of the operation
|
128
137
|
def div(other)
|
129
138
|
if other.is_a? Number
|
130
|
-
operate(other, :/)
|
139
|
+
res = operate(other, :/)
|
140
|
+
if self.original && other.original && context != :equals
|
141
|
+
res.original = "#{self.original}/#{other.original}"
|
142
|
+
end
|
143
|
+
res
|
131
144
|
else
|
132
145
|
super
|
133
146
|
end
|
@@ -214,6 +227,7 @@ module Sass::Script
|
|
214
227
|
# @raise [Sass::SyntaxError] if this number has units that can't be used in CSS
|
215
228
|
# (e.g. `px*in`)
|
216
229
|
def to_s
|
230
|
+
return original if original
|
217
231
|
raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.") unless legal_units?
|
218
232
|
inspect
|
219
233
|
end
|
@@ -235,6 +249,7 @@ module Sass::Script
|
|
235
249
|
end
|
236
250
|
"#{value}#{unit_str}"
|
237
251
|
end
|
252
|
+
alias_method :to_sass, :inspect
|
238
253
|
|
239
254
|
# @return [Fixnum] The integer value of the number
|
240
255
|
# @raise [Sass::SyntaxError] if the number isn't an integer
|
@@ -4,11 +4,16 @@ require 'sass/script/number'
|
|
4
4
|
require 'sass/script/color'
|
5
5
|
require 'sass/script/functions'
|
6
6
|
require 'sass/script/unary_operation'
|
7
|
+
require 'sass/script/interpolation'
|
7
8
|
|
8
9
|
module Sass::Script
|
9
10
|
# A SassScript parse node representing a binary operation,
|
10
|
-
# such as
|
11
|
+
# such as `$a + $b` or `"foo" + 1`.
|
11
12
|
class Operation < Node
|
13
|
+
attr_reader :operand1
|
14
|
+
attr_reader :operand2
|
15
|
+
attr_reader :operator
|
16
|
+
|
12
17
|
# @param operand1 [Script::Node] The parse-tree node
|
13
18
|
# for the right-hand side of the operator
|
14
19
|
# @param operand2 [Script::Node] The parse-tree node
|
@@ -19,6 +24,7 @@ module Sass::Script
|
|
19
24
|
@operand1 = operand1
|
20
25
|
@operand2 = operand2
|
21
26
|
@operator = operator
|
27
|
+
super()
|
22
28
|
end
|
23
29
|
|
24
30
|
# @return [String] A human-readable s-expression representation of the operation
|
@@ -26,14 +32,44 @@ module Sass::Script
|
|
26
32
|
"(#{@operator.inspect} #{@operand1.inspect} #{@operand2.inspect})"
|
27
33
|
end
|
28
34
|
|
35
|
+
# @see Node#to_sass
|
36
|
+
def to_sass
|
37
|
+
pred = Sass::Script::Parser.precedence_of(@operator)
|
38
|
+
o1 = operand_to_sass pred, @operand1
|
39
|
+
o2 = operand_to_sass pred, @operand2
|
40
|
+
sep =
|
41
|
+
case @operator
|
42
|
+
when :comma; ", "
|
43
|
+
when :concat; " "
|
44
|
+
else; " #{Lexer::OPERATORS_REVERSE[@operator]} "
|
45
|
+
end
|
46
|
+
"#{o1}#{sep}#{o2}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns the operands for this operation.
|
50
|
+
#
|
51
|
+
# @return [Array<Node>]
|
52
|
+
# @see Node#children
|
53
|
+
def children
|
54
|
+
[@operand1, @operand2]
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
29
59
|
# Evaluates the operation.
|
30
60
|
#
|
31
61
|
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
32
62
|
# @return [Literal] The SassScript object that is the value of the operation
|
33
63
|
# @raise [Sass::SyntaxError] if the operation is undefined for the operands
|
34
|
-
def
|
64
|
+
def _perform(environment)
|
35
65
|
literal1 = @operand1.perform(environment)
|
36
66
|
literal2 = @operand2.perform(environment)
|
67
|
+
|
68
|
+
if @operator == :concat && context == :equals
|
69
|
+
literal1 = Sass::Script::String.new(literal1.value) if literal1.is_a?(Sass::Script::String)
|
70
|
+
literal2 = Sass::Script::String.new(literal2.value) if literal2.is_a?(Sass::Script::String)
|
71
|
+
end
|
72
|
+
|
37
73
|
begin
|
38
74
|
res = literal1.send(@operator, literal2)
|
39
75
|
res.options = environment.options
|
@@ -44,12 +80,12 @@ module Sass::Script
|
|
44
80
|
end
|
45
81
|
end
|
46
82
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
83
|
+
private
|
84
|
+
|
85
|
+
def operand_to_sass(pred, op)
|
86
|
+
return "(#{op.to_sass})" if op.is_a?(Operation) &&
|
87
|
+
Sass::Script::Parser.precedence_of(op.operator) < pred
|
88
|
+
op.to_sass
|
53
89
|
end
|
54
90
|
end
|
55
91
|
end
|
data/lib/sass/script/parser.rb
CHANGED
@@ -5,6 +5,13 @@ module Sass
|
|
5
5
|
# The parser for SassScript.
|
6
6
|
# It parses a string of code into a tree of {Script::Node}s.
|
7
7
|
class Parser
|
8
|
+
# The line number of the parser's current position.
|
9
|
+
#
|
10
|
+
# @return [Fixnum]
|
11
|
+
def line
|
12
|
+
@lexer.line
|
13
|
+
end
|
14
|
+
|
8
15
|
# @param str [String, StringScanner] The source text to parse
|
9
16
|
# @param line [Fixnum] The line on which the SassScript appears.
|
10
17
|
# Used for error reporting
|
@@ -14,7 +21,7 @@ module Sass
|
|
14
21
|
# see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
|
15
22
|
def initialize(str, line, offset, options = {})
|
16
23
|
@options = options
|
17
|
-
@lexer =
|
24
|
+
@lexer = lexer_class.new(str, line, offset, options)
|
18
25
|
end
|
19
26
|
|
20
27
|
# Parses a SassScript expression within an interpolated segment (`#{}`).
|
@@ -29,6 +36,9 @@ module Sass
|
|
29
36
|
assert_tok :end_interpolation
|
30
37
|
expr.options = @options
|
31
38
|
expr
|
39
|
+
rescue Sass::SyntaxError => e
|
40
|
+
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
41
|
+
raise e
|
32
42
|
end
|
33
43
|
|
34
44
|
# Parses a SassScript expression.
|
@@ -40,6 +50,26 @@ module Sass
|
|
40
50
|
assert_done
|
41
51
|
expr.options = @options
|
42
52
|
expr
|
53
|
+
rescue Sass::SyntaxError => e
|
54
|
+
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
55
|
+
raise e
|
56
|
+
end
|
57
|
+
|
58
|
+
# Parses a SassScript expression,
|
59
|
+
# ending it when it encounters one of the given identifier tokens.
|
60
|
+
#
|
61
|
+
# @param [#include?(String)] A set of strings that delimit the expression.
|
62
|
+
# @return [Script::Node] The root node of the parse tree
|
63
|
+
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
64
|
+
def parse_until(tokens)
|
65
|
+
@stop_at = tokens
|
66
|
+
expr = assert_expr :expr
|
67
|
+
assert_done
|
68
|
+
expr.options = @options
|
69
|
+
expr
|
70
|
+
rescue Sass::SyntaxError => e
|
71
|
+
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
72
|
+
raise e
|
43
73
|
end
|
44
74
|
|
45
75
|
# Parses the argument list for a mixin include.
|
@@ -57,6 +87,9 @@ module Sass
|
|
57
87
|
|
58
88
|
args.each {|a| a.options = @options}
|
59
89
|
args
|
90
|
+
rescue Sass::SyntaxError => e
|
91
|
+
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
92
|
+
raise e
|
60
93
|
end
|
61
94
|
|
62
95
|
# Parses the argument list for a mixin definition.
|
@@ -77,6 +110,9 @@ module Sass
|
|
77
110
|
v.options = @options if v
|
78
111
|
end
|
79
112
|
args
|
113
|
+
rescue Sass::SyntaxError => e
|
114
|
+
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
115
|
+
raise e
|
80
116
|
end
|
81
117
|
|
82
118
|
# Parses a SassScript expression.
|
@@ -89,7 +125,28 @@ module Sass
|
|
89
125
|
new(*args).parse
|
90
126
|
end
|
91
127
|
|
128
|
+
# @private
|
129
|
+
PRECEDENCE = [
|
130
|
+
:comma, :concat, :or, :and,
|
131
|
+
[:eq, :neq],
|
132
|
+
[:gt, :gte, :lt, :lte],
|
133
|
+
[:plus, :minus],
|
134
|
+
[:times, :div, :mod],
|
135
|
+
]
|
136
|
+
|
92
137
|
class << self
|
138
|
+
# Returns an integer representing the precedence
|
139
|
+
# of the given operator.
|
140
|
+
# A lower integer indicates a looser binding.
|
141
|
+
#
|
142
|
+
# @private
|
143
|
+
def precedence_of(op)
|
144
|
+
PRECEDENCE.each_with_index do |e, i|
|
145
|
+
return i if Array(e).include?(op)
|
146
|
+
end
|
147
|
+
raise "[BUG] Unknown operator #{op}"
|
148
|
+
end
|
149
|
+
|
93
150
|
private
|
94
151
|
|
95
152
|
# Defines a simple left-associative production.
|
@@ -101,7 +158,9 @@ module Sass
|
|
101
158
|
def #{name}
|
102
159
|
return unless e = #{sub}
|
103
160
|
while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
|
161
|
+
line = @lexer.line
|
104
162
|
e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
|
163
|
+
e.line = line
|
105
164
|
end
|
106
165
|
e
|
107
166
|
end
|
@@ -112,7 +171,10 @@ RUBY
|
|
112
171
|
class_eval <<RUBY
|
113
172
|
def unary_#{op}
|
114
173
|
return #{sub} unless try_tok(:#{op})
|
115
|
-
|
174
|
+
line = @lexer.line
|
175
|
+
op = UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
|
176
|
+
op.line = line
|
177
|
+
op
|
116
178
|
end
|
117
179
|
RUBY
|
118
180
|
end
|
@@ -120,12 +182,28 @@ RUBY
|
|
120
182
|
|
121
183
|
private
|
122
184
|
|
123
|
-
|
185
|
+
# @private
|
186
|
+
def lexer_class; Lexer; end
|
187
|
+
|
188
|
+
production :expr, :interpolation, :comma
|
189
|
+
|
190
|
+
def interpolation
|
191
|
+
e = concat
|
192
|
+
while interp = try_tok(:begin_interpolation)
|
193
|
+
wb = @lexer.whitespace?(interp)
|
194
|
+
line = @lexer.line
|
195
|
+
mid = parse_interpolated
|
196
|
+
wa = @lexer.whitespace?
|
197
|
+
e = Script::Interpolation.new(e, mid, concat, wb, wa)
|
198
|
+
e.line = line
|
199
|
+
end
|
200
|
+
e
|
201
|
+
end
|
124
202
|
|
125
203
|
def concat
|
126
204
|
return unless e = or_expr
|
127
205
|
while sub = or_expr
|
128
|
-
e = Operation.new(e, sub, :concat)
|
206
|
+
e = node(Operation.new(e, sub, :concat))
|
129
207
|
end
|
130
208
|
e
|
131
209
|
end
|
@@ -135,36 +213,44 @@ RUBY
|
|
135
213
|
production :eq_or_neq, :relational, :eq, :neq
|
136
214
|
production :relational, :plus_or_minus, :gt, :gte, :lt, :lte
|
137
215
|
production :plus_or_minus, :times_div_or_mod, :plus, :minus
|
138
|
-
production :times_div_or_mod, :
|
216
|
+
production :times_div_or_mod, :unary_plus, :times, :div, :mod
|
139
217
|
|
218
|
+
unary :plus, :unary_minus
|
140
219
|
unary :minus, :unary_div
|
141
220
|
unary :div, :unary_not # For strings, so /foo/bar works
|
142
221
|
unary :not, :funcall
|
143
222
|
|
144
223
|
def funcall
|
145
|
-
return
|
224
|
+
return raw unless @lexer.peek && @lexer.peek.type == :ident
|
225
|
+
return if @stop_at && @stop_at.include?(@lexer.peek.value)
|
226
|
+
|
227
|
+
name = @lexer.next
|
146
228
|
# An identifier without arguments is just a string
|
147
229
|
unless try_tok(:lparen)
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
Implicit strings have been deprecated and will be removed in version 3.0.
|
153
|
-
'#{name.value}' was not quoted. Please add double quotes (e.g. "#{name.value}").
|
154
|
-
END
|
155
|
-
Script::String.new(name.value)
|
230
|
+
if color = Color::HTML4_COLORS[name.value]
|
231
|
+
return node(Color.new(color))
|
232
|
+
end
|
233
|
+
node(Script::String.new(name.value, :identifier))
|
156
234
|
else
|
157
235
|
args = arglist || []
|
158
236
|
assert_tok(:rparen)
|
159
|
-
Script::Funcall.new(name.value, args)
|
237
|
+
node(Script::Funcall.new(name.value, args))
|
160
238
|
end
|
161
239
|
end
|
162
240
|
|
163
241
|
def defn_arglist(must_have_default)
|
242
|
+
line = @lexer.line
|
243
|
+
offset = @lexer.offset + 1
|
164
244
|
return unless c = try_tok(:const)
|
165
245
|
var = Script::Variable.new(c.value)
|
166
|
-
if try_tok(:single_eq)
|
246
|
+
if tok = (try_tok(:colon) || try_tok(:single_eq))
|
167
247
|
val = assert_expr(:concat)
|
248
|
+
|
249
|
+
if tok.type == :single_eq
|
250
|
+
val.context = :equals
|
251
|
+
Script.equals_warning("mixin argument defaults", "$#{c.value}",
|
252
|
+
val.to_sass, false, line, offset, @options[:filename])
|
253
|
+
end
|
168
254
|
elsif must_have_default
|
169
255
|
raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.")
|
170
256
|
end
|
@@ -174,46 +260,80 @@ END
|
|
174
260
|
end
|
175
261
|
|
176
262
|
def arglist
|
177
|
-
return unless e =
|
263
|
+
return unless e = interpolation
|
178
264
|
return [e] unless try_tok(:comma)
|
179
265
|
[e, *arglist]
|
180
266
|
end
|
181
267
|
|
268
|
+
def raw
|
269
|
+
return special_fun unless tok = try_tok(:raw)
|
270
|
+
node(Script::String.new(tok.value))
|
271
|
+
end
|
272
|
+
|
273
|
+
def special_fun
|
274
|
+
return paren unless tok = try_tok(:special_fun)
|
275
|
+
first = node(Script::String.new(tok.value.first))
|
276
|
+
Haml::Util.enum_slice(tok.value[1..-1], 2).inject(first) do |l, (i, r)|
|
277
|
+
Script::Interpolation.new(
|
278
|
+
l, i, r && node(Script::String.new(r)),
|
279
|
+
false, false)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
182
283
|
def paren
|
183
284
|
return variable unless try_tok(:lparen)
|
285
|
+
was_in_parens = @in_parens
|
286
|
+
@in_parens = true
|
184
287
|
e = assert_expr(:expr)
|
185
288
|
assert_tok(:rparen)
|
186
289
|
return e
|
290
|
+
ensure
|
291
|
+
@in_parens = was_in_parens
|
187
292
|
end
|
188
293
|
|
189
294
|
def variable
|
190
295
|
return string unless c = try_tok(:const)
|
191
|
-
Variable.new(c.value)
|
296
|
+
node(Variable.new(*c.value))
|
192
297
|
end
|
193
298
|
|
194
299
|
def string
|
195
|
-
return
|
300
|
+
return number unless first = try_tok(:string)
|
196
301
|
return first.value unless try_tok(:begin_interpolation)
|
302
|
+
line = @lexer.line
|
197
303
|
mid = parse_interpolated
|
198
304
|
last = assert_expr(:string)
|
199
|
-
Operation.new(first.value, Operation.new(mid, last, :plus), :plus)
|
305
|
+
op = Operation.new(first.value, node(Operation.new(mid, last, :plus)), :plus)
|
306
|
+
op.line = line
|
307
|
+
op
|
308
|
+
end
|
309
|
+
|
310
|
+
def number
|
311
|
+
return literal unless tok = try_tok(:number)
|
312
|
+
num = tok.value
|
313
|
+
num.original = num.to_s unless @in_parens
|
314
|
+
num
|
200
315
|
end
|
201
316
|
|
202
317
|
def literal
|
203
|
-
(t = try_tok(:
|
318
|
+
(t = try_tok(:color, :bool)) && (return t.value)
|
204
319
|
end
|
205
320
|
|
206
321
|
# It would be possible to have unified #assert and #try methods,
|
207
322
|
# but detecting the method/token difference turns out to be quite expensive.
|
208
323
|
|
324
|
+
EXPR_NAMES = {
|
325
|
+
:string => "string",
|
326
|
+
:default => "expression (e.g. 1px, bold)",
|
327
|
+
}
|
328
|
+
|
209
329
|
def assert_expr(name)
|
210
330
|
(e = send(name)) && (return e)
|
211
|
-
|
331
|
+
@lexer.expected!(EXPR_NAMES[name] || EXPR_NAMES[:default])
|
212
332
|
end
|
213
333
|
|
214
334
|
def assert_tok(*names)
|
215
335
|
(t = try_tok(*names)) && (return t)
|
216
|
-
|
336
|
+
@lexer.expected!(names.map {|tok| Lexer::TOKEN_NAMES[tok] || tok}.join(" or "))
|
217
337
|
end
|
218
338
|
|
219
339
|
def try_tok(*names)
|
@@ -223,7 +343,12 @@ END
|
|
223
343
|
|
224
344
|
def assert_done
|
225
345
|
return if @lexer.done?
|
226
|
-
|
346
|
+
@lexer.expected!(EXPR_NAMES[:default])
|
347
|
+
end
|
348
|
+
|
349
|
+
def node(node)
|
350
|
+
node.line = @lexer.line
|
351
|
+
node
|
227
352
|
end
|
228
353
|
end
|
229
354
|
end
|