oreorenasass 3.4.4 → 3.4.5

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.
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