oreorenasass 3.4.4 → 3.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +50 -70
  4. data/Rakefile +5 -26
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +12 -19
  10. data/lib/sass/cache_stores/base.rb +2 -2
  11. data/lib/sass/cache_stores/chain.rb +1 -2
  12. data/lib/sass/cache_stores/filesystem.rb +5 -1
  13. data/lib/sass/cache_stores/memory.rb +1 -1
  14. data/lib/sass/cache_stores/null.rb +2 -2
  15. data/lib/sass/callbacks.rb +0 -1
  16. data/lib/sass/css.rb +13 -11
  17. data/lib/sass/engine.rb +173 -424
  18. data/lib/sass/environment.rb +58 -148
  19. data/lib/sass/error.rb +14 -11
  20. data/lib/sass/exec.rb +703 -5
  21. data/lib/sass/importers/base.rb +6 -49
  22. data/lib/sass/importers/filesystem.rb +19 -44
  23. data/lib/sass/logger.rb +4 -1
  24. data/lib/sass/logger/base.rb +4 -2
  25. data/lib/sass/logger/log_level.rb +7 -3
  26. data/lib/sass/media.rb +23 -20
  27. data/lib/sass/plugin.rb +7 -7
  28. data/lib/sass/plugin/compiler.rb +145 -304
  29. data/lib/sass/plugin/configuration.rb +23 -18
  30. data/lib/sass/plugin/merb.rb +1 -1
  31. data/lib/sass/plugin/staleness_checker.rb +3 -3
  32. data/lib/sass/repl.rb +3 -3
  33. data/lib/sass/script.rb +8 -35
  34. data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
  35. data/lib/sass/script/bool.rb +18 -0
  36. data/lib/sass/script/color.rb +606 -0
  37. data/lib/sass/script/css_lexer.rb +4 -8
  38. data/lib/sass/script/css_parser.rb +2 -5
  39. data/lib/sass/script/funcall.rb +245 -0
  40. data/lib/sass/script/functions.rb +408 -1491
  41. data/lib/sass/script/interpolation.rb +79 -0
  42. data/lib/sass/script/lexer.rb +68 -172
  43. data/lib/sass/script/list.rb +85 -0
  44. data/lib/sass/script/literal.rb +221 -0
  45. data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
  46. data/lib/sass/script/{value/null.rb → null.rb} +7 -14
  47. data/lib/sass/script/{value/number.rb → number.rb} +75 -152
  48. data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
  49. data/lib/sass/script/parser.rb +110 -245
  50. data/lib/sass/script/string.rb +51 -0
  51. data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
  52. data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
  53. data/lib/sass/script/variable.rb +58 -0
  54. data/lib/sass/scss/css_parser.rb +3 -9
  55. data/lib/sass/scss/parser.rb +421 -450
  56. data/lib/sass/scss/rx.rb +11 -19
  57. data/lib/sass/scss/static_parser.rb +7 -321
  58. data/lib/sass/selector.rb +194 -68
  59. data/lib/sass/selector/abstract_sequence.rb +14 -29
  60. data/lib/sass/selector/comma_sequence.rb +25 -108
  61. data/lib/sass/selector/sequence.rb +66 -159
  62. data/lib/sass/selector/simple.rb +25 -23
  63. data/lib/sass/selector/simple_sequence.rb +63 -173
  64. data/lib/sass/shared.rb +1 -1
  65. data/lib/sass/supports.rb +15 -13
  66. data/lib/sass/tree/charset_node.rb +1 -1
  67. data/lib/sass/tree/comment_node.rb +3 -3
  68. data/lib/sass/tree/css_import_node.rb +11 -11
  69. data/lib/sass/tree/debug_node.rb +2 -2
  70. data/lib/sass/tree/directive_node.rb +4 -21
  71. data/lib/sass/tree/each_node.rb +8 -8
  72. data/lib/sass/tree/extend_node.rb +7 -14
  73. data/lib/sass/tree/for_node.rb +4 -4
  74. data/lib/sass/tree/function_node.rb +4 -9
  75. data/lib/sass/tree/if_node.rb +1 -1
  76. data/lib/sass/tree/import_node.rb +5 -4
  77. data/lib/sass/tree/media_node.rb +14 -4
  78. data/lib/sass/tree/mixin_def_node.rb +4 -4
  79. data/lib/sass/tree/mixin_node.rb +8 -21
  80. data/lib/sass/tree/node.rb +12 -54
  81. data/lib/sass/tree/prop_node.rb +20 -39
  82. data/lib/sass/tree/return_node.rb +2 -3
  83. data/lib/sass/tree/root_node.rb +3 -19
  84. data/lib/sass/tree/rule_node.rb +22 -35
  85. data/lib/sass/tree/supports_node.rb +13 -0
  86. data/lib/sass/tree/trace_node.rb +1 -2
  87. data/lib/sass/tree/variable_node.rb +3 -9
  88. data/lib/sass/tree/visitors/base.rb +8 -5
  89. data/lib/sass/tree/visitors/check_nesting.rb +19 -49
  90. data/lib/sass/tree/visitors/convert.rb +56 -74
  91. data/lib/sass/tree/visitors/cssize.rb +74 -202
  92. data/lib/sass/tree/visitors/deep_copy.rb +5 -10
  93. data/lib/sass/tree/visitors/extend.rb +7 -7
  94. data/lib/sass/tree/visitors/perform.rb +185 -278
  95. data/lib/sass/tree/visitors/set_options.rb +6 -20
  96. data/lib/sass/tree/visitors/to_css.rb +81 -234
  97. data/lib/sass/tree/warn_node.rb +2 -2
  98. data/lib/sass/tree/while_node.rb +2 -2
  99. data/lib/sass/util.rb +152 -522
  100. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  101. data/lib/sass/util/subset_map.rb +3 -4
  102. data/lib/sass/util/test.rb +1 -0
  103. data/lib/sass/version.rb +22 -20
  104. data/test/Gemfile +3 -0
  105. data/test/Gemfile.lock +10 -0
  106. data/test/sass/cache_test.rb +20 -62
  107. data/test/sass/callbacks_test.rb +1 -1
  108. data/test/sass/conversion_test.rb +2 -296
  109. data/test/sass/css2sass_test.rb +4 -23
  110. data/test/sass/engine_test.rb +354 -411
  111. data/test/sass/exec_test.rb +2 -2
  112. data/test/sass/extend_test.rb +145 -324
  113. data/test/sass/functions_test.rb +86 -873
  114. data/test/sass/importer_test.rb +21 -241
  115. data/test/sass/logger_test.rb +1 -1
  116. data/test/sass/more_results/more_import.css +1 -1
  117. data/test/sass/plugin_test.rb +26 -16
  118. data/test/sass/results/compact.css +1 -1
  119. data/test/sass/results/complex.css +4 -4
  120. data/test/sass/results/expanded.css +1 -1
  121. data/test/sass/results/import.css +1 -1
  122. data/test/sass/results/import_charset_ibm866.css +2 -2
  123. data/test/sass/results/mixins.css +17 -17
  124. data/test/sass/results/nested.css +1 -1
  125. data/test/sass/results/parent_ref.css +2 -2
  126. data/test/sass/results/script.css +3 -3
  127. data/test/sass/results/scss_import.css +1 -1
  128. data/test/sass/script_conversion_test.rb +7 -36
  129. data/test/sass/script_test.rb +53 -485
  130. data/test/sass/scss/css_test.rb +28 -143
  131. data/test/sass/scss/rx_test.rb +4 -4
  132. data/test/sass/scss/scss_test.rb +325 -2119
  133. data/test/sass/templates/scss_import.scss +1 -2
  134. data/test/sass/test_helper.rb +1 -1
  135. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  136. data/test/sass/util/subset_map_test.rb +2 -2
  137. data/test/sass/util_test.rb +1 -86
  138. data/test/test_helper.rb +8 -37
  139. metadata +19 -66
  140. data/lib/sass/exec/base.rb +0 -187
  141. data/lib/sass/exec/sass_convert.rb +0 -264
  142. data/lib/sass/exec/sass_scss.rb +0 -424
  143. data/lib/sass/features.rb +0 -47
  144. data/lib/sass/script/tree.rb +0 -16
  145. data/lib/sass/script/tree/funcall.rb +0 -306
  146. data/lib/sass/script/tree/interpolation.rb +0 -118
  147. data/lib/sass/script/tree/list_literal.rb +0 -77
  148. data/lib/sass/script/tree/literal.rb +0 -45
  149. data/lib/sass/script/tree/map_literal.rb +0 -64
  150. data/lib/sass/script/tree/selector.rb +0 -26
  151. data/lib/sass/script/tree/variable.rb +0 -57
  152. data/lib/sass/script/value.rb +0 -11
  153. data/lib/sass/script/value/base.rb +0 -240
  154. data/lib/sass/script/value/bool.rb +0 -35
  155. data/lib/sass/script/value/color.rb +0 -680
  156. data/lib/sass/script/value/helpers.rb +0 -262
  157. data/lib/sass/script/value/list.rb +0 -113
  158. data/lib/sass/script/value/map.rb +0 -70
  159. data/lib/sass/script/value/string.rb +0 -97
  160. data/lib/sass/selector/pseudo.rb +0 -256
  161. data/lib/sass/source/map.rb +0 -210
  162. data/lib/sass/source/position.rb +0 -39
  163. data/lib/sass/source/range.rb +0 -41
  164. data/lib/sass/stack.rb +0 -120
  165. data/lib/sass/tree/at_root_node.rb +0 -83
  166. data/lib/sass/tree/error_node.rb +0 -18
  167. data/lib/sass/tree/keyframe_rule_node.rb +0 -15
  168. data/lib/sass/util/cross_platform_random.rb +0 -19
  169. data/lib/sass/util/normalized_map.rb +0 -130
  170. data/lib/sass/util/ordered_hash.rb +0 -192
  171. data/test/sass/compiler_test.rb +0 -232
  172. data/test/sass/encoding_test.rb +0 -219
  173. data/test/sass/source_map_test.rb +0 -977
  174. data/test/sass/superselector_test.rb +0 -191
  175. data/test/sass/util/normalized_map_test.rb +0 -51
  176. data/test/sass/value_helpers_test.rb +0 -179
@@ -1,4 +1,13 @@
1
- module Sass::Script::Tree
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 [Sass::Script::Tree::Node] The parse-tree node
18
+ # @param operand1 [Script::Node] The parse-tree node
10
19
  # for the right-hand side of the operator
11
- # @param operand2 [Sass::Script::Tree::Node] The parse-tree node
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 {Sass::Script::Lexer::OPERATORS}
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; " #{Sass::Script::Lexer::OPERATORS_REVERSE[@operator]} "
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 [Sass::Script::Value] The SassScript object that is the value of the operation
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
- value1 = @operand1.perform(environment)
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 value1.to_bool ? @operand2.perform(environment) : value1
77
+ return literal1.to_bool ? @operand2.perform(environment) : literal1
69
78
  elsif @operator == :or
70
- return value1.to_bool ? value1 : @operand2.perform(environment)
79
+ return literal1.to_bool ? literal1 : @operand2.perform(environment)
71
80
  end
72
81
 
73
- value2 = @operand2.perform(environment)
82
+ literal2 = @operand2.perform(environment)
74
83
 
75
- if (value1.is_a?(Sass::Script::Value::Null) || value2.is_a?(Sass::Script::Value::Null)) &&
76
- @operator != :eq && @operator != :neq
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(value1.send(@operator, value2))
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: \"#{value1} #{@operator} #{value2}\".")
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?(Sass::Script::Tree::ListLiteral)
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)
@@ -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::Tree::Node}s.
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 and sourcemap building
25
- # @param offset [Fixnum] The character (not byte) offset where the script starts in the line.
26
- # Used for error reporting and sourcemap building
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
- # @param warn_for_color [Boolean] Whether raw color values passed to
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(warn_for_color = false)
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
- node(expr, start_pos)
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::Tree::Node] The root node of the parse tree
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 tokens [#include?(String)] A set of strings that delimit the expression.
75
- # @return [Script::Tree::Node] The root node of the parse tree
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::Tree::Node>,
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(s). Keyword arguments are in a hash from names to values.
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, kwarg_splat = mixin_arglist
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
- kwarg_splat.options = @options if kwarg_splat
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::Tree::Node>, Script::Tree::Node)]
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::Tree::Node>, Script::Tree::Node)]
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::Tree::Node] The root node of the parse tree.
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::Tree::Node] The root node of the parse tree
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.inspect}"
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 = try_toks(#{ops.map {|o| o.inspect}.join(', ')})
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
- e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type),
236
- e.source_range.start_pos)
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
- return interp if interp
249
- start_pos = source_position
250
- node(Tree::UnaryOperation.new(assert_expr(:unary_#{op}), :#{op}), start_pos)
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
- start_pos = source_position
293
- e = interpolation
294
- return unless e
295
- list e, start_pos
296
- end
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
- return list unless (e = interpolation)
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 = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
321
- op.source_range)
322
- interp = node(
323
- Script::Tree::Interpolation.new(prev, str, nil, wb, !:wa, :originally_text),
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 = try_toks(*ops)
331
- return unless op
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 = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
337
- op.source_range)
276
+ str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
338
277
  str.line = @lexer.line
339
- interp = node(
340
- Script::Tree::Interpolation.new(prev, str, assert_expr(name), !:wb, wa, :originally_text),
341
- (prev || str).source_range.start_pos)
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 (interp = try_tok(:begin_interpolation))
285
+ while interp = try_tok(:begin_interpolation)
348
286
  wb = @lexer.whitespace?(interp)
349
- mid = assert_expr :expr
350
- assert_tok :end_interpolation
287
+ line = @lexer.line
288
+ mid = parse_interpolated
351
289
  wa = @lexer.whitespace?
352
- e = node(
353
- Script::Tree::Interpolation.new(e, mid, space, wb, wa),
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
- start_pos = source_position
361
- e = or_expr
362
- return unless e
297
+ line = @lexer.line
298
+ return unless e = or_expr
363
299
  arr = [e]
364
- while (e = or_expr)
300
+ while e = or_expr
365
301
  arr << e
366
302
  end
367
- if arr.size == 1
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 (color = Sass::Script::Value::Color::COLOR_NAMES[name.value.downcase])
392
- literal_node(Sass::Script::Value::Color.new(color, name.value), name.source_range)
323
+ if color = Color::COLOR_NAMES[name.value.downcase]
324
+ node(Color.new(color))
393
325
  elsif name.value == "true"
394
- literal_node(Sass::Script::Value::Bool.new(true), name.source_range)
326
+ node(Script::Bool.new(true))
395
327
  elsif name.value == "false"
396
- literal_node(Sass::Script::Value::Bool.new(false), name.source_range)
328
+ node(Script::Bool.new(false))
397
329
  elsif name.value == "null"
398
- literal_node(Sass::Script::Value::Null.new, name.source_range)
330
+ node(Script::Null.new)
399
331
  else
400
- literal_node(Sass::Script::Value::String.new(name.value, :identifier), name.source_range)
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
- return raw unless tok
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::Tree::Funcall.new(tok.value, args, keywords, splat, kwarg_splat),
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 = node(Script::Tree::Variable.new(c.value), c.source_range)
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
- args = []
454
- keywords = Sass::Util::NormalizedMap.new
455
- e = send(subexpr)
382
+ return unless e = send(subexpr)
456
383
 
457
- return [args, keywords] unless e
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?(Tree::Variable)
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.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.name] = value
397
+ keywords[name.underscored_name] = value
472
398
  else
473
- if try_tok(:splat)
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 << e if e
403
+ return args, keywords, e if try_tok(:splat)
404
+ args << e
483
405
  end
484
406
 
485
- return args, keywords, splat unless try_tok(:comma)
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
- return special_fun unless tok
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
- first = try_tok(:special_fun)
498
- return paren unless first
499
- str = literal_node(first.value, first.source_range)
500
- return str unless try_tok(:begin_interpolation)
501
- mid = parse_interpolated
502
- last = assert_expr(:special_fun)
503
- node(Tree::Interpolation.new(str, mid, last, false, false),
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
- start_pos = source_position
512
- e = map
513
- end_pos = source_position
431
+ line = @lexer.line
432
+ e = expr
514
433
  assert_tok(:rparen)
515
- return e || node(Sass::Script::Tree::ListLiteral.new([], nil), start_pos, end_pos)
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
- start_pos = source_position
522
- c = try_tok(:const)
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 number unless first
530
- str = literal_node(first.value, first.source_range)
531
- return str unless try_tok(:begin_interpolation)
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
- node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
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
- literal_node(num, tok.source_range.start_pos)
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(name)
576
- # Avoids an array allocation caused by argument globbing in assert_toks.
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(name)
589
- # Avoids an array allocation caused by argument globbing in the try_toks method.
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
- # @overload node(value, source_range)
605
- # @param value [Sass::Script::Value::Base]
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