haml-edge 2.3.179 → 2.3.180

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/EDGE_GEM_VERSION +1 -1
  2. data/README.md +88 -149
  3. data/VERSION +1 -1
  4. data/bin/css2sass +7 -1
  5. data/bin/sass-convert +7 -0
  6. data/lib/haml/exec.rb +95 -22
  7. data/lib/haml/template.rb +1 -1
  8. data/lib/haml/util.rb +50 -0
  9. data/lib/sass.rb +1 -1
  10. data/lib/sass/css.rb +38 -210
  11. data/lib/sass/engine.rb +121 -47
  12. data/lib/sass/files.rb +28 -19
  13. data/lib/sass/plugin.rb +32 -43
  14. data/lib/sass/repl.rb +1 -1
  15. data/lib/sass/script.rb +25 -6
  16. data/lib/sass/script/bool.rb +1 -0
  17. data/lib/sass/script/color.rb +2 -2
  18. data/lib/sass/script/css_lexer.rb +22 -0
  19. data/lib/sass/script/css_parser.rb +28 -0
  20. data/lib/sass/script/funcall.rb +17 -9
  21. data/lib/sass/script/functions.rb +46 -1
  22. data/lib/sass/script/interpolation.rb +42 -0
  23. data/lib/sass/script/lexer.rb +142 -34
  24. data/lib/sass/script/literal.rb +28 -12
  25. data/lib/sass/script/node.rb +57 -1
  26. data/lib/sass/script/number.rb +18 -3
  27. data/lib/sass/script/operation.rb +44 -8
  28. data/lib/sass/script/parser.rb +149 -24
  29. data/lib/sass/script/string.rb +50 -2
  30. data/lib/sass/script/unary_operation.rb +25 -10
  31. data/lib/sass/script/variable.rb +20 -11
  32. data/lib/sass/scss.rb +14 -0
  33. data/lib/sass/scss/css_parser.rb +39 -0
  34. data/lib/sass/scss/parser.rb +683 -0
  35. data/lib/sass/scss/rx.rb +112 -0
  36. data/lib/sass/scss/script_lexer.rb +13 -0
  37. data/lib/sass/scss/script_parser.rb +25 -0
  38. data/lib/sass/tree/comment_node.rb +58 -16
  39. data/lib/sass/tree/debug_node.rb +7 -2
  40. data/lib/sass/tree/directive_node.rb +38 -34
  41. data/lib/sass/tree/for_node.rb +6 -0
  42. data/lib/sass/tree/if_node.rb +13 -0
  43. data/lib/sass/tree/import_node.rb +26 -7
  44. data/lib/sass/tree/mixin_def_node.rb +18 -0
  45. data/lib/sass/tree/mixin_node.rb +16 -1
  46. data/lib/sass/tree/node.rb +98 -27
  47. data/lib/sass/tree/prop_node.rb +97 -20
  48. data/lib/sass/tree/root_node.rb +37 -0
  49. data/lib/sass/tree/rule_node.rb +88 -60
  50. data/lib/sass/tree/variable_node.rb +9 -5
  51. data/lib/sass/tree/while_node.rb +4 -0
  52. data/test/haml/results/filters.xhtml +1 -1
  53. data/test/haml/util_test.rb +28 -0
  54. data/test/sass/conversion_test.rb +884 -0
  55. data/test/sass/css2sass_test.rb +46 -21
  56. data/test/sass/engine_test.rb +680 -160
  57. data/test/sass/functions_test.rb +27 -0
  58. data/test/sass/more_results/more_import.css +1 -1
  59. data/test/sass/more_templates/more_import.sass +3 -3
  60. data/test/sass/plugin_test.rb +28 -8
  61. data/test/sass/results/compact.css +1 -1
  62. data/test/sass/results/complex.css +5 -5
  63. data/test/sass/results/compressed.css +1 -1
  64. data/test/sass/results/expanded.css +1 -1
  65. data/test/sass/results/import.css +3 -1
  66. data/test/sass/results/mixins.css +12 -12
  67. data/test/sass/results/nested.css +1 -1
  68. data/test/sass/results/parent_ref.css +4 -4
  69. data/test/sass/results/script.css +3 -3
  70. data/test/sass/results/scss_import.css +15 -0
  71. data/test/sass/results/scss_importee.css +2 -0
  72. data/test/sass/script_conversion_test.rb +153 -0
  73. data/test/sass/script_test.rb +44 -54
  74. data/test/sass/scss/css_test.rb +811 -0
  75. data/test/sass/scss/rx_test.rb +156 -0
  76. data/test/sass/scss/scss_test.rb +871 -0
  77. data/test/sass/scss/test_helper.rb +37 -0
  78. data/test/sass/templates/alt.sass +2 -2
  79. data/test/sass/templates/bork1.sass +1 -1
  80. data/test/sass/templates/import.sass +4 -4
  81. data/test/sass/templates/importee.sass +3 -3
  82. data/test/sass/templates/line_numbers.sass +1 -1
  83. data/test/sass/templates/mixins.sass +2 -2
  84. data/test/sass/templates/nested_mixin_bork.sass +1 -1
  85. data/test/sass/templates/options.sass +1 -1
  86. data/test/sass/templates/parent_ref.sass +2 -2
  87. data/test/sass/templates/script.sass +69 -69
  88. data/test/sass/templates/scss_import.scss +10 -0
  89. data/test/sass/templates/scss_importee.scss +1 -0
  90. data/test/sass/templates/units.sass +10 -10
  91. data/test/test_helper.rb +4 -4
  92. metadata +27 -2
@@ -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
- raise NotImplementedError.new("All subclasses of Sass::Script::Node must override #perform.")
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
@@ -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. `!a - !b`).
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 `-` operation (e.g. `-!a`).
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 `!a + !b` or `"foo" + 1`.
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 perform(environment)
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
- # Returns the operands for this operation.
48
- #
49
- # @return [Array<Node>]
50
- # @see Node#children
51
- def children
52
- [@operand1, @operand2]
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
@@ -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 = Lexer.new(str, line, offset, options)
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
- UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
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
- production :expr, :concat, :comma
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, :unary_minus, :times, :div, :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 paren unless name = try_tok(:ident)
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
- filename = @options[:filename]
149
- warn(<<END)
150
- DEPRECATION WARNING:
151
- On line #{name.line}, character #{name.offset}#{" of '#{filename}'" if filename}
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 = concat
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 literal unless first = try_tok(:string)
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(:number, :color, :bool)) && (return t.value)
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
- raise Sass::SyntaxError.new("Expected expression, was #{@lexer.done? ? 'end of text' : "#{@lexer.peek.type} token"}.")
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
- raise Sass::SyntaxError.new("Expected #{names.join(' or ')} token, was #{@lexer.done? ? 'end of text' : "#{@lexer.peek.type} token"}.")
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
- raise Sass::SyntaxError.new("Unexpected #{@lexer.peek.type} token.")
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