sass 3.7.4 → 4.0.0.alpha.1

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 (257) hide show
  1. checksums.yaml +13 -5
  2. data/.yardopts +1 -1
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/CONTRIBUTING.md +1 -146
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +25 -39
  7. data/Rakefile +274 -0
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/lib/sass.rb +3 -3
  11. data/lib/sass/cache_stores/filesystem.rb +2 -2
  12. data/lib/sass/cache_stores/memory.rb +5 -4
  13. data/lib/sass/callbacks.rb +2 -2
  14. data/lib/sass/css.rb +12 -12
  15. data/lib/sass/engine.rb +44 -62
  16. data/lib/sass/environment.rb +7 -35
  17. data/lib/sass/error.rb +14 -14
  18. data/lib/sass/exec/base.rb +14 -3
  19. data/lib/sass/exec/sass_convert.rb +6 -20
  20. data/lib/sass/exec/sass_scss.rb +29 -5
  21. data/lib/sass/features.rb +2 -3
  22. data/lib/sass/importers/filesystem.rb +6 -11
  23. data/lib/sass/logger.rb +3 -8
  24. data/lib/sass/logger/base.rb +2 -19
  25. data/lib/sass/plugin.rb +2 -3
  26. data/lib/sass/plugin/compiler.rb +67 -48
  27. data/lib/sass/plugin/configuration.rb +3 -3
  28. data/lib/sass/plugin/merb.rb +1 -1
  29. data/lib/sass/plugin/rack.rb +3 -3
  30. data/lib/sass/plugin/staleness_checker.rb +3 -3
  31. data/lib/sass/railtie.rb +1 -1
  32. data/lib/sass/script.rb +3 -3
  33. data/lib/sass/script/css_parser.rb +15 -5
  34. data/lib/sass/script/functions.rb +121 -337
  35. data/lib/sass/script/lexer.rb +36 -102
  36. data/lib/sass/script/parser.rb +153 -529
  37. data/lib/sass/script/tree/funcall.rb +34 -42
  38. data/lib/sass/script/tree/interpolation.rb +26 -171
  39. data/lib/sass/script/tree/list_literal.rb +8 -23
  40. data/lib/sass/script/tree/map_literal.rb +2 -2
  41. data/lib/sass/script/tree/node.rb +3 -3
  42. data/lib/sass/script/tree/operation.rb +16 -43
  43. data/lib/sass/script/tree/string_interpolation.rb +43 -64
  44. data/lib/sass/script/tree/variable.rb +1 -1
  45. data/lib/sass/script/value.rb +0 -2
  46. data/lib/sass/script/value/arg_list.rb +1 -1
  47. data/lib/sass/script/value/base.rb +9 -27
  48. data/lib/sass/script/value/color.rb +18 -26
  49. data/lib/sass/script/value/helpers.rb +18 -44
  50. data/lib/sass/script/value/list.rb +14 -35
  51. data/lib/sass/script/value/map.rb +2 -2
  52. data/lib/sass/script/value/number.rb +16 -26
  53. data/lib/sass/script/value/string.rb +1 -30
  54. data/lib/sass/scss.rb +2 -0
  55. data/lib/sass/scss/css_parser.rb +3 -7
  56. data/lib/sass/scss/parser.rb +78 -196
  57. data/lib/sass/scss/rx.rb +14 -7
  58. data/lib/sass/scss/script_lexer.rb +15 -0
  59. data/lib/sass/scss/script_parser.rb +25 -0
  60. data/lib/sass/scss/static_parser.rb +55 -38
  61. data/lib/sass/selector.rb +10 -7
  62. data/lib/sass/selector/abstract_sequence.rb +12 -15
  63. data/lib/sass/selector/comma_sequence.rb +6 -24
  64. data/lib/sass/selector/pseudo.rb +6 -19
  65. data/lib/sass/selector/sequence.rb +16 -14
  66. data/lib/sass/selector/simple.rb +7 -9
  67. data/lib/sass/selector/simple_sequence.rb +12 -16
  68. data/lib/sass/shared.rb +1 -1
  69. data/lib/sass/source/map.rb +9 -7
  70. data/lib/sass/source/position.rb +4 -4
  71. data/lib/sass/stack.rb +3 -23
  72. data/lib/sass/tree/charset_node.rb +1 -1
  73. data/lib/sass/tree/comment_node.rb +1 -1
  74. data/lib/sass/tree/function_node.rb +3 -2
  75. data/lib/sass/tree/node.rb +3 -5
  76. data/lib/sass/tree/prop_node.rb +58 -49
  77. data/lib/sass/tree/rule_node.rb +8 -15
  78. data/lib/sass/tree/visitors/check_nesting.rb +23 -19
  79. data/lib/sass/tree/visitors/convert.rb +13 -15
  80. data/lib/sass/tree/visitors/cssize.rb +15 -4
  81. data/lib/sass/tree/visitors/deep_copy.rb +2 -2
  82. data/lib/sass/tree/visitors/extend.rb +14 -10
  83. data/lib/sass/tree/visitors/perform.rb +18 -29
  84. data/lib/sass/tree/visitors/set_options.rb +2 -2
  85. data/lib/sass/tree/visitors/to_css.rb +47 -77
  86. data/lib/sass/util.rb +311 -98
  87. data/lib/sass/util/cross_platform_random.rb +19 -0
  88. data/lib/sass/util/multibyte_string_scanner.rb +133 -127
  89. data/lib/sass/util/normalized_map.rb +8 -1
  90. data/lib/sass/util/ordered_hash.rb +192 -0
  91. data/lib/sass/version.rb +6 -2
  92. data/test/sass/cache_test.rb +131 -0
  93. data/test/sass/callbacks_test.rb +61 -0
  94. data/test/sass/compiler_test.rb +236 -0
  95. data/test/sass/conversion_test.rb +2171 -0
  96. data/test/sass/css2sass_test.rb +526 -0
  97. data/test/sass/data/hsl-rgb.txt +319 -0
  98. data/test/sass/encoding_test.rb +219 -0
  99. data/test/sass/engine_test.rb +3400 -0
  100. data/test/sass/exec_test.rb +86 -0
  101. data/test/sass/extend_test.rb +1719 -0
  102. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  103. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  104. data/test/sass/functions_test.rb +1984 -0
  105. data/test/sass/importer_test.rb +421 -0
  106. data/test/sass/logger_test.rb +58 -0
  107. data/test/sass/mock_importer.rb +49 -0
  108. data/test/sass/more_results/more1.css +9 -0
  109. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  110. data/test/sass/more_results/more_import.css +29 -0
  111. data/test/sass/more_templates/_more_partial.sass +2 -0
  112. data/test/sass/more_templates/more1.sass +23 -0
  113. data/test/sass/more_templates/more_import.sass +11 -0
  114. data/test/sass/plugin_test.rb +556 -0
  115. data/test/sass/results/alt.css +4 -0
  116. data/test/sass/results/basic.css +9 -0
  117. data/test/sass/results/cached_import_option.css +3 -0
  118. data/test/sass/results/compact.css +5 -0
  119. data/test/sass/results/complex.css +86 -0
  120. data/test/sass/results/compressed.css +1 -0
  121. data/test/sass/results/expanded.css +19 -0
  122. data/test/sass/results/filename_fn.css +3 -0
  123. data/test/sass/results/if.css +3 -0
  124. data/test/sass/results/import.css +31 -0
  125. data/test/sass/results/import_charset.css +5 -0
  126. data/test/sass/results/import_charset_1_8.css +5 -0
  127. data/test/sass/results/import_charset_ibm866.css +5 -0
  128. data/test/sass/results/import_content.css +1 -0
  129. data/test/sass/results/line_numbers.css +49 -0
  130. data/test/sass/results/mixins.css +95 -0
  131. data/test/sass/results/multiline.css +24 -0
  132. data/test/sass/results/nested.css +22 -0
  133. data/test/sass/results/options.css +1 -0
  134. data/test/sass/results/parent_ref.css +13 -0
  135. data/test/sass/results/script.css +16 -0
  136. data/test/sass/results/scss_import.css +31 -0
  137. data/test/sass/results/scss_importee.css +2 -0
  138. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  139. data/test/sass/results/subdir/subdir.css +3 -0
  140. data/test/sass/results/units.css +11 -0
  141. data/test/sass/results/warn.css +0 -0
  142. data/test/sass/results/warn_imported.css +0 -0
  143. data/test/sass/script_conversion_test.rb +306 -0
  144. data/test/sass/script_test.rb +1206 -0
  145. data/test/sass/scss/css_test.rb +1281 -0
  146. data/test/sass/scss/rx_test.rb +160 -0
  147. data/test/sass/scss/scss_test.rb +4147 -0
  148. data/test/sass/scss/test_helper.rb +37 -0
  149. data/test/sass/source_map_test.rb +1055 -0
  150. data/test/sass/superselector_test.rb +210 -0
  151. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  152. data/test/sass/templates/_double_import_loop2.sass +1 -0
  153. data/test/sass/templates/_filename_fn_import.scss +11 -0
  154. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  155. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  156. data/test/sass/templates/_imported_content.sass +3 -0
  157. data/test/sass/templates/_partial.sass +2 -0
  158. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  159. data/test/sass/templates/alt.sass +16 -0
  160. data/test/sass/templates/basic.sass +23 -0
  161. data/test/sass/templates/bork1.sass +2 -0
  162. data/test/sass/templates/bork2.sass +2 -0
  163. data/test/sass/templates/bork3.sass +2 -0
  164. data/test/sass/templates/bork4.sass +2 -0
  165. data/test/sass/templates/bork5.sass +3 -0
  166. data/test/sass/templates/cached_import_option.scss +3 -0
  167. data/test/sass/templates/compact.sass +17 -0
  168. data/test/sass/templates/complex.sass +305 -0
  169. data/test/sass/templates/compressed.sass +15 -0
  170. data/test/sass/templates/double_import_loop1.sass +1 -0
  171. data/test/sass/templates/expanded.sass +17 -0
  172. data/test/sass/templates/filename_fn.scss +18 -0
  173. data/test/sass/templates/if.sass +11 -0
  174. data/test/sass/templates/import.sass +12 -0
  175. data/test/sass/templates/import_charset.sass +9 -0
  176. data/test/sass/templates/import_charset_1_8.sass +6 -0
  177. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  178. data/test/sass/templates/import_content.sass +4 -0
  179. data/test/sass/templates/importee.less +2 -0
  180. data/test/sass/templates/importee.sass +19 -0
  181. data/test/sass/templates/line_numbers.sass +13 -0
  182. data/test/sass/templates/mixin_bork.sass +5 -0
  183. data/test/sass/templates/mixins.sass +76 -0
  184. data/test/sass/templates/multiline.sass +20 -0
  185. data/test/sass/templates/nested.sass +25 -0
  186. data/test/sass/templates/nested_bork1.sass +2 -0
  187. data/test/sass/templates/nested_bork2.sass +2 -0
  188. data/test/sass/templates/nested_bork3.sass +2 -0
  189. data/test/sass/templates/nested_bork4.sass +2 -0
  190. data/test/sass/templates/nested_import.sass +2 -0
  191. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  192. data/test/sass/templates/options.sass +2 -0
  193. data/test/sass/templates/parent_ref.sass +25 -0
  194. data/test/sass/templates/same_name_different_ext.sass +2 -0
  195. data/test/sass/templates/same_name_different_ext.scss +1 -0
  196. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  197. data/test/sass/templates/script.sass +101 -0
  198. data/test/sass/templates/scss_import.scss +12 -0
  199. data/test/sass/templates/scss_importee.scss +1 -0
  200. data/test/sass/templates/single_import_loop.sass +1 -0
  201. data/test/sass/templates/subdir/import_up1.scss +1 -0
  202. data/test/sass/templates/subdir/import_up2.scss +1 -0
  203. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  204. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  205. data/test/sass/templates/subdir/subdir.sass +6 -0
  206. data/test/sass/templates/units.sass +11 -0
  207. data/test/sass/templates/warn.sass +3 -0
  208. data/test/sass/templates/warn_imported.sass +4 -0
  209. data/test/sass/test_helper.rb +8 -0
  210. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  211. data/test/sass/util/normalized_map_test.rb +51 -0
  212. data/test/sass/util/subset_map_test.rb +91 -0
  213. data/test/sass/util_test.rb +438 -0
  214. data/test/sass/value_helpers_test.rb +179 -0
  215. data/test/test_helper.rb +110 -0
  216. data/vendor/listen/CHANGELOG.md +1 -0
  217. data/vendor/listen/CONTRIBUTING.md +38 -0
  218. data/vendor/listen/Gemfile +20 -0
  219. data/vendor/listen/Guardfile +8 -0
  220. data/vendor/listen/LICENSE +20 -0
  221. data/vendor/listen/README.md +349 -0
  222. data/vendor/listen/Rakefile +5 -0
  223. data/vendor/listen/Vagrantfile +96 -0
  224. data/vendor/listen/lib/listen.rb +54 -0
  225. data/vendor/listen/lib/listen/adapter.rb +327 -0
  226. data/vendor/listen/lib/listen/adapters/bsd.rb +75 -0
  227. data/vendor/listen/lib/listen/adapters/darwin.rb +48 -0
  228. data/vendor/listen/lib/listen/adapters/linux.rb +81 -0
  229. data/vendor/listen/lib/listen/adapters/polling.rb +58 -0
  230. data/vendor/listen/lib/listen/adapters/windows.rb +91 -0
  231. data/vendor/listen/lib/listen/directory_record.rb +406 -0
  232. data/vendor/listen/lib/listen/listener.rb +323 -0
  233. data/vendor/listen/lib/listen/turnstile.rb +32 -0
  234. data/vendor/listen/lib/listen/version.rb +3 -0
  235. data/vendor/listen/listen.gemspec +28 -0
  236. data/vendor/listen/spec/listen/adapter_spec.rb +149 -0
  237. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  238. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  239. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  240. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  241. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  242. data/vendor/listen/spec/listen/directory_record_spec.rb +1250 -0
  243. data/vendor/listen/spec/listen/listener_spec.rb +258 -0
  244. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  245. data/vendor/listen/spec/listen_spec.rb +67 -0
  246. data/vendor/listen/spec/spec_helper.rb +25 -0
  247. data/vendor/listen/spec/support/adapter_helper.rb +666 -0
  248. data/vendor/listen/spec/support/directory_record_helper.rb +57 -0
  249. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  250. data/vendor/listen/spec/support/listeners_helper.rb +179 -0
  251. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  252. metadata +217 -76
  253. data/extra/sass-spec-ref.sh +0 -40
  254. data/lib/sass/deprecation.rb +0 -55
  255. data/lib/sass/logger/delayed.rb +0 -50
  256. data/lib/sass/script/value/callable.rb +0 -25
  257. data/lib/sass/script/value/function.rb +0 -19
@@ -66,35 +66,26 @@ module Sass::Script::Value
66
66
  Number.new(number, *parse_unit_string(unit_string))
67
67
  end
68
68
 
69
- # @overload list(*elements, separator:, bracketed: false)
69
+ # @overload list(*elements, separator)
70
70
  # Create a space-separated list from the arguments given.
71
71
  # @param elements [Array<Sass::Script::Value::Base>] Each argument will be a list element.
72
72
  # @param separator [Symbol] Either :space or :comma.
73
- # @param bracketed [Boolean] Whether the list uses square brackets.
74
73
  # @return [Sass::Script::Value::List] The space separated list.
75
74
  #
76
- # @overload list(array, separator:, bracketed: false)
75
+ # @overload list(array, separator)
77
76
  # Create a space-separated list from the array given.
78
77
  # @param array [Array<Sass::Script::Value::Base>] A ruby array of Sass values
79
78
  # to make into a list.
80
- # @param separator [Symbol] Either :space or :comma.
81
- # @param bracketed [Boolean] Whether the list uses square brackets.
82
79
  # @return [Sass::Script::Value::List] The space separated list.
83
- def list(*elements, separator: nil, bracketed: false)
84
- # Support passing separator as the last value in elements for
85
- # backwards-compatibility.
86
- if separator.nil?
87
- if elements.last.is_a?(Symbol)
88
- separator = elements.pop
89
- else
90
- raise ArgumentError.new("A separator of :space or :comma must be specified.")
91
- end
80
+ def list(*elements)
81
+ unless elements.last.is_a?(Symbol)
82
+ raise ArgumentError.new("A list type of :space or :comma must be specified.")
92
83
  end
93
-
84
+ separator = elements.pop
94
85
  if elements.size == 1 && elements.first.is_a?(Array)
95
86
  elements = elements.first
96
87
  end
97
- Sass::Script::Value::List.new(elements, separator: separator, bracketed: bracketed)
88
+ Sass::Script::Value::List.new(elements, separator)
98
89
  end
99
90
 
100
91
  # Construct a Sass map.
@@ -148,7 +139,7 @@ module Sass::Script::Value
148
139
  Sass::SCSS::StaticParser.new(str, nil, nil, 1, 1, allow_parent_ref).parse_selector
149
140
  rescue Sass::SyntaxError => e
150
141
  err = "#{value.inspect} is not a valid selector: #{e}"
151
- err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
142
+ err = "$#{name.to_s.gsub('_', '-')}: #{err}" if name
152
143
  raise ArgumentError.new(err)
153
144
  end
154
145
  end
@@ -172,7 +163,7 @@ module Sass::Script::Value
172
163
  return seq if selector.members.length == 1
173
164
 
174
165
  err = "#{value.inspect} is not a complex selector"
175
- err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
166
+ err = "$#{name.to_s.gsub('_', '-')}: #{err}" if name
176
167
  raise ArgumentError.new(err)
177
168
  end
178
169
 
@@ -199,35 +190,18 @@ module Sass::Script::Value
199
190
  end
200
191
 
201
192
  err = "#{value.inspect} is not a compound selector"
202
- err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
193
+ err = "$#{name.to_s.gsub('_', '-')}: #{err}" if name
203
194
  raise ArgumentError.new(err)
204
195
  end
205
196
 
206
- # Returns true when the literal is a string containing a calc().
207
- #
208
- # Use \{#special_number?} in preference to this.
197
+ # Returns true when the literal is a string containing a calc()
209
198
  #
210
199
  # @param literal [Sass::Script::Value::Base] The value to check
211
- # @return Boolean
200
+ # @return boolean
212
201
  def calc?(literal)
213
- literal.is_a?(Sass::Script::Value::String) && literal.value =~ /calc\(/
214
- end
215
-
216
- # Returns true when the literal is a string containing a var().
217
- #
218
- # @param literal [Sass::Script::Value::Base] The value to check
219
- # @return Boolean
220
- def var?(literal)
221
- literal.is_a?(Sass::Script::Value::String) && literal.value =~ /var\(/
222
- end
223
-
224
- # Returns whether the literal is a special CSS value that may evaluate to a
225
- # number, such as `calc()` or `var()`.
226
- #
227
- # @param literal [Sass::Script::Value::Base] The value to check
228
- # @return Boolean
229
- def special_number?(literal)
230
- literal.is_a?(Sass::Script::Value::String) && literal.value =~ /(calc|var)\(/
202
+ if literal.is_a?(Sass::Script::Value::String)
203
+ literal.value =~ /calc\(/
204
+ end
231
205
  end
232
206
 
233
207
  private
@@ -241,7 +215,7 @@ module Sass::Script::Value
241
215
 
242
216
  err = "#{value.inspect} is not a valid selector: it must be a string,\n" +
243
217
  "a list of strings, or a list of lists of strings"
244
- err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
218
+ err = "$#{name.to_s.gsub('_', '-')}: #{err}" if name
245
219
  raise ArgumentError.new(err)
246
220
  end
247
221
 
@@ -278,14 +252,14 @@ module Sass::Script::Value
278
252
  def parse_unit_string(unit_string)
279
253
  denominator_units = numerator_units = Sass::Script::Value::Number::NO_UNITS
280
254
  return numerator_units, denominator_units unless unit_string && unit_string.length > 0
281
- num_over_denominator = unit_string.split(%r{ */ *})
255
+ num_over_denominator = unit_string.split(/ *\/ */)
282
256
  unless (1..2).include?(num_over_denominator.size)
283
257
  raise ArgumentError.new("Malformed unit string: #{unit_string}")
284
258
  end
285
259
  numerator_units = num_over_denominator[0].split(/ *\* */)
286
260
  denominator_units = (num_over_denominator[1] || "").split(/ *\* */)
287
261
  [[numerator_units, "numerator"], [denominator_units, "denominator"]].each do |units, name|
288
- if unit_string =~ %r{/} && units.size == 0
262
+ if unit_string =~ /\// && units.size == 0
289
263
  raise ArgumentError.new("Malformed unit string: #{unit_string}")
290
264
  end
291
265
  if units.any? {|unit| unit !~ VALID_UNIT}
@@ -14,20 +14,13 @@ module Sass::Script::Value
14
14
  # @return [Symbol]
15
15
  attr_reader :separator
16
16
 
17
- # Whether the list is surrounded by square brackets.
18
- #
19
- # @return [Boolean]
20
- attr_reader :bracketed
21
-
22
17
  # Creates a new list.
23
18
  #
24
19
  # @param value [Array<Value>] See \{#value}
25
20
  # @param separator [Symbol] See \{#separator}
26
- # @param bracketed [Boolean] See \{#bracketed}
27
- def initialize(value, separator: nil, bracketed: false)
21
+ def initialize(value, separator)
28
22
  super(value)
29
23
  @separator = separator
30
- @bracketed = bracketed
31
24
  end
32
25
 
33
26
  # @see Value#options=
@@ -40,30 +33,24 @@ module Sass::Script::Value
40
33
  def eq(other)
41
34
  Sass::Script::Value::Bool.new(
42
35
  other.is_a?(List) && value == other.value &&
43
- separator == other.separator && bracketed == other.bracketed)
36
+ separator == other.separator)
44
37
  end
45
38
 
46
39
  def hash
47
- @hash ||= [value, separator, bracketed].hash
40
+ @hash ||= [value, separator].hash
48
41
  end
49
42
 
50
43
  # @see Value#to_s
51
44
  def to_s(opts = {})
52
- if !bracketed && value.empty?
53
- raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
54
- end
55
-
56
- members = value.
45
+ raise Sass::SyntaxError.new("() isn't a valid CSS value.") if value.empty?
46
+ value.
57
47
  reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.
58
- map {|e| e.to_s(opts)}
59
-
60
- contents = members.join(sep_str)
61
- bracketed ? "[#{contents}]" : contents
48
+ map {|e| e.to_s(opts)}.join(sep_str)
62
49
  end
63
50
 
64
51
  # @see Value#to_sass
65
52
  def to_sass(opts = {})
66
- return bracketed ? "[]" : "()" if value.empty?
53
+ return "()" if value.empty?
67
54
  members = value.map do |v|
68
55
  if element_needs_parens?(v)
69
56
  "(#{v.to_sass(opts)})"
@@ -71,26 +58,19 @@ module Sass::Script::Value
71
58
  v.to_sass(opts)
72
59
  end
73
60
  end
74
-
75
- if separator == :comma && members.length == 1
76
- return "#{bracketed ? '[' : '('}#{members.first},#{bracketed ? ']' : ')'}"
77
- end
78
-
79
- contents = members.join(sep_str(nil))
80
- bracketed ? "[#{contents}]" : contents
61
+ return "(#{members.first},)" if members.length == 1 && separator == :comma
62
+ members.join(sep_str(nil))
81
63
  end
82
64
 
83
65
  # @see Value#to_h
84
66
  def to_h
85
- return {} if value.empty?
67
+ return Sass::Util.ordered_hash if value.empty?
86
68
  super
87
69
  end
88
70
 
89
71
  # @see Value#inspect
90
72
  def inspect
91
- (bracketed ? '[' : '(') +
92
- value.map {|e| e.inspect}.join(sep_str(nil)) +
93
- (bracketed ? ']' : ')')
73
+ "(#{value.map {|e| e.inspect}.join(sep_str(nil))})"
94
74
  end
95
75
 
96
76
  # Asserts an index is within the list.
@@ -114,10 +94,9 @@ module Sass::Script::Value
114
94
 
115
95
  def element_needs_parens?(element)
116
96
  if element.is_a?(List)
117
- return false if element.value.length < 2
118
- return false if element.bracketed
119
- precedence = Sass::Script::Parser.precedence_of(separator || :space)
120
- return Sass::Script::Parser.precedence_of(element.separator || :space) <= precedence
97
+ return false if element.value.empty?
98
+ precedence = Sass::Script::Parser.precedence_of(separator)
99
+ return Sass::Script::Parser.precedence_of(element.separator) <= precedence
121
100
  end
122
101
 
123
102
  return false unless separator == :space
@@ -12,7 +12,7 @@ module Sass::Script::Value
12
12
  #
13
13
  # @param hash [Hash<Node, Node>]
14
14
  def initialize(hash)
15
- super(hash)
15
+ super(Sass::Util.ordered_hash(hash))
16
16
  end
17
17
 
18
18
  # @see Value#options=
@@ -32,7 +32,7 @@ module Sass::Script::Value
32
32
  # @see Value#to_a
33
33
  def to_a
34
34
  value.map do |k, v|
35
- list = List.new([k, v], separator: :space)
35
+ list = List.new([k, v], :space)
36
36
  list.options = options
37
37
  list
38
38
  end
@@ -34,35 +34,33 @@ module Sass::Script::Value
34
34
  attr_accessor :original
35
35
 
36
36
  def self.precision
37
- Thread.current[:sass_numeric_precision] || Thread.main[:sass_numeric_precision] || 10
37
+ @precision ||= 5
38
38
  end
39
39
 
40
40
  # Sets the number of digits of precision
41
41
  # For example, if this is `3`,
42
42
  # `3.1415926` will be printed as `3.142`.
43
- # The numeric precision is stored as a thread local for thread safety reasons.
44
- # To set for all threads, be sure to set the precision on the main thread.
45
43
  def self.precision=(digits)
46
- Thread.current[:sass_numeric_precision] = digits.round
47
- Thread.current[:sass_numeric_precision_factor] = nil
48
- Thread.current[:sass_numeric_epsilon] = nil
44
+ @precision = digits.round
45
+ @precision_factor = 10.0**@precision
46
+ @epsilon = 1 / (@precision_factor * 10)
49
47
  end
50
48
 
51
49
  # the precision factor used in numeric output
52
50
  # it is derived from the `precision` method.
53
51
  def self.precision_factor
54
- Thread.current[:sass_numeric_precision_factor] ||= 10.0**precision
52
+ @precision_factor ||= 10.0**precision
55
53
  end
56
54
 
57
55
  # Used in checking equality of floating point numbers. Any
58
56
  # numbers within an `epsilon` of each other are considered functionally equal.
59
57
  # The value for epsilon is one tenth of the current numeric precision.
60
58
  def self.epsilon
61
- Thread.current[:sass_numeric_epsilon] ||= 1 / (precision_factor * 10)
59
+ @epsilon ||= 1 / (precision_factor * 10)
62
60
  end
63
61
 
64
62
  # Used so we don't allocate two new arrays for each new number.
65
- NO_UNITS = []
63
+ NO_UNITS = []
66
64
 
67
65
  # @param value [Numeric] The value of the number
68
66
  # @param numerator_units [::String, Array<::String>] See \{#numerator\_units}
@@ -73,7 +71,6 @@ module Sass::Script::Value
73
71
  super(value)
74
72
  @numerator_units = numerator_units
75
73
  @denominator_units = denominator_units
76
- @options = nil
77
74
  normalize!
78
75
  end
79
76
 
@@ -189,7 +186,6 @@ module Sass::Script::Value
189
186
  # @raise [Sass::UnitConversionError] if `other` has incompatible units
190
187
  def mod(other)
191
188
  if other.is_a?(Number)
192
- return Number.new(Float::NAN) if other.value == 0
193
189
  operate(other, :%)
194
190
  else
195
191
  raise NoMethodError.new(nil, :mod)
@@ -293,21 +289,14 @@ module Sass::Script::Value
293
289
  # and confusing.
294
290
  str = ("%0.#{self.class.precision}f" % value).gsub(/0*$/, '') if str.include?('e')
295
291
 
296
- # Sometimes numeric formatting will result in a decimal number with a trailing zero (x.0)
297
- if str =~ /(.*)\.0$/
298
- str = $1
299
- end
300
-
301
- # We omit a leading zero before the decimal point in compressed mode.
302
292
  if @options && options[:style] == :compressed
303
293
  str.sub!(/^(-)?0\./, '\1.')
304
294
  end
305
-
306
295
  unitless? ? str : "#{str}#{unit_str}"
307
296
  end
308
297
  alias_method :to_sass, :inspect
309
298
 
310
- # @return [Integer] The integer value of the number
299
+ # @return [Fixnum] The integer value of the number
311
300
  # @raise [Sass::SyntaxError] if the number isn't an integer
312
301
  def to_i
313
302
  super unless int?
@@ -414,7 +403,7 @@ module Sass::Script::Value
414
403
  if num.is_a?(Float) && (num.infinite? || num.nan?)
415
404
  num
416
405
  elsif basically_equal?(num % 1, 0.0)
417
- num.round
406
+ num.to_i
418
407
  else
419
408
  ((num * precision_factor).round / precision_factor).to_f
420
409
  end
@@ -473,10 +462,11 @@ module Sass::Script::Value
473
462
  sans_common_units(@numerator_units, @denominator_units)
474
463
 
475
464
  @denominator_units.each_with_index do |d, i|
476
- next unless convertable?(d) && (u = @numerator_units.find {|n| convertable?([n, d])})
477
- @value /= conversion_factor(d, u)
478
- @denominator_units.delete_at(i)
479
- @numerator_units.delete_at(@numerator_units.index(u))
465
+ if convertable?(d) && (u = @numerator_units.find(&method(:convertable?)))
466
+ @value /= conversion_factor(d, u)
467
+ @denominator_units.delete_at(i)
468
+ @numerator_units.delete_at(@numerator_units.index(u))
469
+ end
480
470
  end
481
471
  end
482
472
 
@@ -511,8 +501,8 @@ module Sass::Script::Value
511
501
  },
512
502
  {
513
503
  'dpi' => Rational(1),
514
- 'dpcm' => Rational(254, 100),
515
- 'dppx' => Rational(96)
504
+ 'dpcm' => Rational(1, 2.54),
505
+ 'dppx' => Rational(1, 96)
516
506
  }
517
507
  ]
518
508
 
@@ -2,8 +2,6 @@
2
2
  module Sass::Script::Value
3
3
  # A SassScript object representing a CSS string *or* a CSS identifier.
4
4
  class String < Base
5
- @@interpolation_deprecation = Sass::Deprecation.new
6
-
7
5
  # The Ruby value of the string.
8
6
  #
9
7
  # @return [String]
@@ -78,13 +76,9 @@ module Sass::Script::Value
78
76
  #
79
77
  # @param value [String] See \{#value}
80
78
  # @param type [Symbol] See \{#type}
81
- # @param deprecated_interp_equivalent [String?]
82
- # If this was created via a potentially-deprecated string interpolation,
83
- # this is the replacement expression that should be suggested to the user.
84
- def initialize(value, type = :identifier, deprecated_interp_equivalent = nil)
79
+ def initialize(value, type = :identifier)
85
80
  super(value)
86
81
  @type = type
87
- @deprecated_interp_equivalent = deprecated_interp_equivalent
88
82
  end
89
83
 
90
84
  # @see Value#plus
@@ -108,29 +102,6 @@ module Sass::Script::Value
108
102
  to_s(opts.merge(:sass => true))
109
103
  end
110
104
 
111
- def separator
112
- check_deprecated_interp
113
- super
114
- end
115
-
116
- def to_a
117
- check_deprecated_interp
118
- super
119
- end
120
-
121
- # Prints a warning if this string was created using potentially-deprecated
122
- # interpolation.
123
- def check_deprecated_interp
124
- return unless @deprecated_interp_equivalent
125
-
126
- @@interpolation_deprecation.warn(source_range.file, source_range.start_pos.line, <<WARNING)
127
- \#{} interpolation near operators will be simplified in a future version of Sass.
128
- To preserve the current behavior, use quotes:
129
-
130
- #{@deprecated_interp_equivalent}
131
- WARNING
132
- end
133
-
134
105
  def inspect
135
106
  String.quote(value)
136
107
  end
@@ -1,4 +1,6 @@
1
1
  require 'sass/scss/rx'
2
+ require 'sass/scss/script_lexer'
3
+ require 'sass/scss/script_parser'
2
4
  require 'sass/scss/parser'
3
5
  require 'sass/scss/static_parser'
4
6
  require 'sass/scss/css_parser'
@@ -47,15 +47,11 @@ module Sass
47
47
  def keyframes_ruleset
48
48
  start_pos = source_position
49
49
  return unless (selector = keyframes_selector)
50
- block(
51
- node(
52
- Sass::Tree::KeyframeRuleNode.new(
53
- Sass::Util.strip_except_escapes(selector)),
54
- start_pos),
55
- :ruleset)
50
+ block(node(Sass::Tree::KeyframeRuleNode.new(selector.strip), start_pos), :ruleset)
56
51
  end
57
52
 
58
- @sass_script_parser = Sass::Script::CssParser
53
+ @sass_script_parser = Class.new(Sass::Script::CssParser)
54
+ @sass_script_parser.send(:include, ScriptParser)
59
55
  end
60
56
  end
61
57
  end
@@ -16,20 +16,21 @@ module Sass
16
16
  # warnings and source maps.
17
17
  # @param importer [Sass::Importers::Base] The importer used to import the
18
18
  # file being parsed. Used for source maps.
19
- # @param line [Integer] The 1-based line on which the source string appeared,
19
+ # @param line [Fixnum] The 1-based line on which the source string appeared,
20
20
  # if it's part of another document.
21
- # @param offset [Integer] The 1-based character (not byte) offset in the line on
21
+ # @param offset [Fixnum] The 1-based character (not byte) offset in the line on
22
22
  # which the source string starts. Used for error reporting and sourcemap
23
23
  # building.
24
+ # @comment
25
+ # rubocop:disable ParameterLists
24
26
  def initialize(str, filename, importer, line = 1, offset = 1)
27
+ # rubocop:enable ParameterLists
25
28
  @template = str
26
29
  @filename = filename
27
30
  @importer = importer
28
31
  @line = line
29
32
  @offset = offset
30
33
  @strs = []
31
- @expected = nil
32
- @throw_error = false
33
34
  end
34
35
 
35
36
  # Parses an SCSS document.
@@ -99,18 +100,6 @@ module Sass
99
100
  condition
100
101
  end
101
102
 
102
- # Parses a custom property value.
103
- #
104
- # @return [Array<String, Sass::Script;:Tree::Node>] The interpolated value.
105
- # @raise [Sass::SyntaxError] if there's a syntax error in the value,
106
- # or if it doesn't take up the entire input string.
107
- def parse_declaration_value
108
- init_scanner!
109
- value = declaration_value
110
- expected('"}"') unless value && @scanner.eos?
111
- value
112
- end
113
-
114
103
  private
115
104
 
116
105
  include Sass::SCSS::RX
@@ -128,7 +117,7 @@ module Sass
128
117
  if @template.is_a?(StringScanner)
129
118
  @template
130
119
  else
131
- Sass::Util::MultibyteStringScanner.new(@template.tr("\r", ""))
120
+ Sass::Util::MultibyteStringScanner.new(@template.gsub("\r", ""))
132
121
  end
133
122
  end
134
123
 
@@ -203,7 +192,7 @@ module Sass
203
192
  def directive
204
193
  start_pos = source_position
205
194
  return unless tok(/@/)
206
- name = ident!
195
+ name = tok!(IDENT)
207
196
  ss
208
197
 
209
198
  if (dir = special_directive(name, start_pos))
@@ -240,14 +229,14 @@ module Sass
240
229
  end
241
230
 
242
231
  def mixin_directive(start_pos)
243
- name = ident!
232
+ name = tok! IDENT
244
233
  args, splat = sass_script(:parse_mixin_definition_arglist)
245
234
  ss
246
235
  block(node(Sass::Tree::MixinDefNode.new(name, args, splat), start_pos), :directive)
247
236
  end
248
237
 
249
238
  def include_directive(start_pos)
250
- name = ident!
239
+ name = tok! IDENT
251
240
  args, keywords, splat, kwarg_splat = sass_script(:parse_mixin_include_arglist)
252
241
  ss
253
242
  include_node = node(
@@ -266,7 +255,7 @@ module Sass
266
255
  end
267
256
 
268
257
  def function_directive(start_pos)
269
- name = ident!
258
+ name = tok! IDENT
270
259
  args, splat = sass_script(:parse_function_definition_arglist)
271
260
  ss
272
261
  block(node(Sass::Tree::FunctionNode.new(name, args, splat), start_pos), :function)
@@ -286,7 +275,7 @@ module Sass
286
275
 
287
276
  def for_directive(start_pos)
288
277
  tok!(/\$/)
289
- var = ident!
278
+ var = tok! IDENT
290
279
  ss
291
280
 
292
281
  tok!(/from/)
@@ -303,12 +292,12 @@ module Sass
303
292
 
304
293
  def each_directive(start_pos)
305
294
  tok!(/\$/)
306
- vars = [ident!]
295
+ vars = [tok!(IDENT)]
307
296
  ss
308
297
  while tok(/,/)
309
298
  ss
310
299
  tok!(/\$/)
311
- vars << ident!
300
+ vars << tok!(IDENT)
312
301
  ss
313
302
  end
314
303
 
@@ -407,8 +396,7 @@ module Sass
407
396
  ss
408
397
  media = media_query_list
409
398
  if str =~ %r{^(https?:)?//} || media || supports || use_css_import?
410
- return node(
411
- Sass::Tree::CssImportNode.new(
399
+ return node(Sass::Tree::CssImportNode.new(
412
400
  Sass::Script::Value::String.quote(str), media.to_a, supports), start_pos)
413
401
  end
414
402
 
@@ -477,23 +465,12 @@ module Sass
477
465
  return unless tok(/\(/)
478
466
  res = ['(']
479
467
  ss
480
- stop_at = Set[:single_eq, :lt, :lte, :gt, :gte]
481
- res << sass_script(:parse_until, stop_at)
468
+ res << sass_script(:parse)
482
469
 
483
470
  if tok(/:/)
484
471
  res << ': '
485
472
  ss
486
473
  res << sass_script(:parse)
487
- elsif comparison1 = tok(/=|[<>]=?/)
488
- res << ' ' << comparison1 << ' '
489
- ss
490
- res << sass_script(:parse_until, stop_at)
491
- if ((comparison1 == ">" || comparison1 == ">=") && comparison2 = tok(/>=?/)) ||
492
- ((comparison1 == "<" || comparison1 == "<=") && comparison2 = tok(/<=?/))
493
- res << ' ' << comparison2 << ' '
494
- ss
495
- res << sass_script(:parse_until, stop_at)
496
- end
497
474
  end
498
475
  res << tok!(/\)/)
499
476
  ss
@@ -534,7 +511,7 @@ module Sass
534
511
 
535
512
  def moz_document_function
536
513
  val = interp_uri || _interp_string(:url_prefix) ||
537
- _interp_string(:domain) || function(false) || interpolation
514
+ _interp_string(:domain) || function(!:allow_var) || interpolation
538
515
  return unless val
539
516
  ss
540
517
  val
@@ -553,10 +530,10 @@ module Sass
553
530
  end
554
531
 
555
532
  def at_root_directive_list
556
- return unless (first = ident)
533
+ return unless (first = tok(IDENT))
557
534
  arr = [first]
558
535
  ss
559
- while (e = ident)
536
+ while (e = tok(IDENT))
560
537
  arr << e
561
538
  ss
562
539
  end
@@ -583,7 +560,7 @@ module Sass
583
560
  def supports_clause
584
561
  return unless tok(/supports\(/i)
585
562
  ss
586
- supports = import_supports_condition
563
+ supports = supports_condition
587
564
  ss
588
565
  tok!(/\)/)
589
566
  supports
@@ -593,10 +570,6 @@ module Sass
593
570
  supports_negation || supports_operator || supports_interpolation
594
571
  end
595
572
 
596
- def import_supports_condition
597
- supports_condition || supports_declaration
598
- end
599
-
600
573
  def supports_negation
601
574
  return unless tok(/not/i)
602
575
  ss
@@ -616,13 +589,6 @@ module Sass
616
589
  cond
617
590
  end
618
591
 
619
- def supports_declaration
620
- name = sass_script(:parse)
621
- tok!(/:/); ss
622
- value = sass_script(:parse)
623
- Sass::Supports::Declaration.new(name, value)
624
- end
625
-
626
592
  def supports_condition_in_parens
627
593
  interp = supports_interpolation
628
594
  return interp if interp
@@ -631,9 +597,11 @@ module Sass
631
597
  tok!(/\)/); ss
632
598
  cond
633
599
  else
634
- decl = supports_declaration
600
+ name = sass_script(:parse)
601
+ tok!(/:/); ss
602
+ value = sass_script(:parse)
635
603
  tok!(/\)/); ss
636
- decl
604
+ Sass::Supports::Declaration.new(name, value)
637
605
  end
638
606
  end
639
607
 
@@ -647,12 +615,12 @@ module Sass
647
615
  def variable
648
616
  return unless tok(/\$/)
649
617
  start_pos = source_position
650
- name = ident!
618
+ name = tok!(IDENT)
651
619
  ss; tok!(/:/); ss
652
620
 
653
621
  expr = sass_script(:parse)
654
622
  while tok(/!/)
655
- flag_name = ident!
623
+ flag_name = tok!(IDENT)
656
624
  if flag_name == 'default'
657
625
  guarded ||= true
658
626
  elsif flag_name == 'global'
@@ -672,15 +640,14 @@ module Sass
672
640
  # are disallowed by the CSS spec,
673
641
  # but they're included here for compatibility
674
642
  # with some proprietary MS properties
675
- str {ss if tok(%r{[/,:.=]})}
643
+ str {ss if tok(/[\/,:.=]/)}
676
644
  end
677
645
 
678
646
  def ruleset
679
647
  start_pos = source_position
680
648
  return unless (rules = almost_any_value)
681
- block(
682
- node(
683
- Sass::Tree::RuleNode.new(rules, range(start_pos)), start_pos), :ruleset)
649
+ block(node(
650
+ Sass::Tree::RuleNode.new(rules, range(start_pos)), start_pos), :ruleset)
684
651
  end
685
652
 
686
653
  def block(node, context)
@@ -755,9 +722,8 @@ module Sass
755
722
  selector << additional_selector
756
723
  end
757
724
 
758
- block(
759
- node(
760
- Sass::Tree::RuleNode.new(merge(selector), range(start_pos)), start_pos), :ruleset)
725
+ block(node(
726
+ Sass::Tree::RuleNode.new(merge(selector), range(start_pos)), start_pos), :ruleset)
761
727
  end
762
728
 
763
729
  # Tries to parse a declaration, and returns the value parsed so far if it
@@ -790,12 +756,6 @@ module Sass
790
756
  mid = [str {ss}]
791
757
  return name + mid unless tok(/:/)
792
758
  mid << ':'
793
-
794
- # If this is a CSS variable, parse it as a property no matter what.
795
- if name.first.is_a?(String) && name.first.start_with?("--")
796
- return css_variable_declaration(name, name_start_pos, name_end_pos)
797
- end
798
-
799
759
  return name + mid + [':'] if tok(/:/)
800
760
  mid << str {ss}
801
761
  post_colon_whitespace = !mid.last.empty?
@@ -831,7 +791,7 @@ module Sass
831
791
  ss
832
792
  require_block = tok?(/\{/)
833
793
 
834
- node = node(Sass::Tree::PropNode.new(name.flatten.compact, [value], :new),
794
+ node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
835
795
  name_start_pos, value_end_pos)
836
796
  node.name_source_range = range(name_start_pos, name_end_pos)
837
797
  node.value_source_range = range(value_start_pos, value_end_pos)
@@ -840,21 +800,13 @@ module Sass
840
800
  nested_properties! node
841
801
  end
842
802
 
843
- def css_variable_declaration(name, name_start_pos, name_end_pos)
844
- value_start_pos = source_position
845
- value = declaration_value
846
- value_end_pos = source_position
847
-
848
- node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
849
- name_start_pos, value_end_pos)
850
- node.name_source_range = range(name_start_pos, name_end_pos)
851
- node.value_source_range = range(value_start_pos, value_end_pos)
852
- node
853
- end
854
-
855
- # This production consumes values that could be a selector, an expression,
856
- # or a combination of both. It respects strings and comments and supports
857
- # interpolation. It will consume up to "{", "}", ";", or "!".
803
+ # This production is similar to the CSS [`<any-value>`][any-value]
804
+ # production, but as the name implies, not quite the same. It's meant to
805
+ # consume values that could be a selector, an expression, or a combination
806
+ # of both. It respects strings and comments and supports interpolation. It
807
+ # will consume up to "{", "}", ";", or "!".
808
+ #
809
+ # [any-value]: http://dev.w3.org/csswg/css-variables/#typedef-any-value
858
810
  #
859
811
  # Values consumed by this production will usually be parsed more
860
812
  # thoroughly once interpolation has been resolved.
@@ -874,9 +826,6 @@ module Sass
874
826
  |
875
827
  (?!url\()
876
828
  [^"'/\#!;\{\}] # "
877
- |
878
- # interp_uri will handle most url() calls, but not ones that take strings
879
- url\(#{W}(?=")
880
829
  |
881
830
  /(?![/*])
882
831
  |
@@ -888,60 +837,6 @@ module Sass
888
837
  interpolation(:warn_for_color)
889
838
  end
890
839
 
891
- def declaration_value(top_level: true)
892
- return unless (tok = declaration_value_token(top_level))
893
- value = [tok]
894
- while (tok = declaration_value_token(top_level))
895
- value << tok
896
- end
897
- merge(value)
898
- end
899
-
900
- def declaration_value_token(top_level)
901
- # This comes, more or less, from the [token consumption algorithm][].
902
- # However, since we don't have to worry about the token semantics, we
903
- # just consume everything until we come across a token with special
904
- # semantics.
905
- #
906
- # [token consumption algorithm]: https://drafts.csswg.org/css-syntax-3/#consume-token.
907
- result = tok(%r{
908
- (
909
- (?!
910
- url\(
911
- )
912
- [^()\[\]{}"'#/ \t\r\n\f#{top_level ? ";" : ""}]
913
- |
914
- \#(?!\{)
915
- |
916
- /(?!\*)
917
- )+
918
- }xi) || interp_string || interp_uri || interpolation || tok(COMMENT)
919
- return result if result
920
-
921
- # Fold together multiple characters of whitespace that don't include
922
- # newlines. The value only cares about the tokenization, so this is safe
923
- # as long as we don't delete whitespace entirely. It's important that we
924
- # fold here rather than post-processing, since we aren't allowed to fold
925
- # whitespace within strings and we lose that context later on.
926
- if (ws = tok(S))
927
- return ws.include?("\n") ? ws.gsub(/\A[^\n]*/, '') : ' '
928
- end
929
-
930
- if tok(/\(/)
931
- value = declaration_value(top_level: false)
932
- tok!(/\)/)
933
- ['(', *value, ')']
934
- elsif tok(/\[/)
935
- value = declaration_value(top_level: false)
936
- tok!(/\]/)
937
- ['[', *value, ']']
938
- elsif tok(/\{/)
939
- value = declaration_value(top_level: false)
940
- tok!(/\}/)
941
- ['{', *value, '}']
942
- end
943
- end
944
-
945
840
  def declaration
946
841
  # This allows the "*prop: val", ":prop: val", "#prop: val", and ".prop:
947
842
  # val" hacks.
@@ -967,7 +862,7 @@ module Sass
967
862
  ss
968
863
  require_block = tok?(/\{/)
969
864
 
970
- node = node(Sass::Tree::PropNode.new(name.flatten.compact, [value], :new),
865
+ node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
971
866
  name_start_pos, value_end_pos)
972
867
  node.name_source_range = range(name_start_pos, name_end_pos)
973
868
  node.value_source_range = range(value_start_pos, value_end_pos)
@@ -990,11 +885,8 @@ module Sass
990
885
  # we don't parse it at all, and instead return a plain old string
991
886
  # containing the value.
992
887
  # This results in a dramatic speed increase.
993
- if (val = tok(STATIC_VALUE))
994
- # If val ends with escaped whitespace, leave it be.
995
- str = Sass::Script::Tree::Literal.new(
996
- Sass::Script::Value::String.new(
997
- Sass::Util.strip_except_escapes(val)))
888
+ if (val = tok(STATIC_VALUE, true))
889
+ str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(val.strip))
998
890
  str.line = start_pos.line
999
891
  str.source_range = range(start_pos)
1000
892
  return str
@@ -1051,7 +943,7 @@ module Sass
1051
943
  def var_expr
1052
944
  return unless tok(/\$/)
1053
945
  line = @line
1054
- var = Sass::Script::Tree::Variable.new(ident!)
946
+ var = Sass::Script::Tree::Variable.new(tok!(IDENT))
1055
947
  var.line = line
1056
948
  var
1057
949
  end
@@ -1089,27 +981,11 @@ module Sass
1089
981
  res
1090
982
  end
1091
983
 
1092
- def ident
1093
- (ident = tok(IDENT)) && Sass::Util.normalize_ident_escapes(ident)
1094
- end
1095
-
1096
- def ident!
1097
- Sass::Util.normalize_ident_escapes(tok!(IDENT))
1098
- end
1099
-
1100
- def name
1101
- (name = tok(NAME)) && Sass::Util.normalize_ident_escapes(name)
1102
- end
1103
-
1104
- def name!
1105
- Sass::Util.normalize_ident_escapes(tok!(NAME))
1106
- end
1107
-
1108
- def interp_ident
1109
- val = ident || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP)
984
+ def interp_ident(start = IDENT)
985
+ val = tok(start) || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP, true)
1110
986
  return unless val
1111
987
  res = [val]
1112
- while (val = name || interpolation(:warn_for_color))
988
+ while (val = tok(NAME) || interpolation(:warn_for_color))
1113
989
  res << val
1114
990
  end
1115
991
  res
@@ -1123,7 +999,7 @@ module Sass
1123
999
  end
1124
1000
 
1125
1001
  def str
1126
- @strs.push String.new("")
1002
+ @strs.push ""
1127
1003
  yield
1128
1004
  @strs.last
1129
1005
  ensure
@@ -1151,7 +1027,8 @@ module Sass
1151
1027
  node
1152
1028
  end
1153
1029
 
1154
- @sass_script_parser = Sass::Script::Parser
1030
+ @sass_script_parser = Class.new(Sass::Script::Parser)
1031
+ @sass_script_parser.send(:include, ScriptParser)
1155
1032
 
1156
1033
  class << self
1157
1034
  # @private
@@ -1160,7 +1037,7 @@ module Sass
1160
1037
 
1161
1038
  def sass_script(*args)
1162
1039
  parser = self.class.sass_script_parser.new(@scanner, @line, @offset,
1163
- :filename => @filename, :importer => @importer, :allow_extra_text => true)
1040
+ :filename => @filename, :importer => @importer)
1164
1041
  result = parser.send(*args)
1165
1042
  unless @strs.empty?
1166
1043
  # Convert to CSS manually so that comments are ignored.
@@ -1185,7 +1062,7 @@ module Sass
1185
1062
  :media_expr => "media expression (e.g. (min-device-width: 800px))",
1186
1063
  :at_root_query => "@at-root query (e.g. (without: media))",
1187
1064
  :at_root_directive_list => '* or identifier',
1188
- :declaration_value => "expression (e.g. fr, 2n+1)",
1065
+ :pseudo_args => "expression (e.g. fr, 2n+1)",
1189
1066
  :interp_ident => "identifier",
1190
1067
  :qualified_name => "identifier",
1191
1068
  :expr => "expression (e.g. 1px, bold)",
@@ -1200,9 +1077,9 @@ module Sass
1200
1077
  :keyframes_selector => "keyframes selector (e.g. 10%)"
1201
1078
  }
1202
1079
 
1203
- TOK_NAMES = Hash[Sass::SCSS::RX.constants.map do |c|
1080
+ TOK_NAMES = Sass::Util.to_hash(Sass::SCSS::RX.constants.map do |c|
1204
1081
  [Sass::SCSS::RX.const_get(c), c.downcase]
1205
- end].merge(
1082
+ end).merge(
1206
1083
  IDENT => "identifier",
1207
1084
  /[;{}]/ => '";"',
1208
1085
  /\b(without|with)\b/ => '"with" or "without"'
@@ -1225,7 +1102,7 @@ module Sass
1225
1102
 
1226
1103
  unless name
1227
1104
  # Display basic regexps as plain old strings
1228
- source = rx.source.gsub(%r{\\/}, '/')
1105
+ source = rx.source.gsub(/\\\//, '/')
1229
1106
  string = rx.source.gsub(/\\(.)/, '\1')
1230
1107
  name = source == Regexp.escape(string) ? string.inspect : rx.inspect
1231
1108
  end
@@ -1256,20 +1133,14 @@ module Sass
1256
1133
  line = @line
1257
1134
  offset = @offset
1258
1135
  expected = @expected
1259
-
1260
- logger = Sass::Logger::Delayed.install!
1261
1136
  if catch(:_sass_parser_error) {yield; false}
1262
1137
  @scanner.pos = pos
1263
1138
  @line = line
1264
1139
  @offset = offset
1265
1140
  @expected = expected
1266
1141
  {:pos => pos, :line => line, :expected => @expected, :block => block}
1267
- else
1268
- logger.flush
1269
- nil
1270
1142
  end
1271
1143
  ensure
1272
- logger.uninstall! if logger
1273
1144
  @throw_error = old_throw_error
1274
1145
  end
1275
1146
 
@@ -1314,24 +1185,35 @@ module Sass
1314
1185
  # This is important because `#tok` is called all the time.
1315
1186
  NEWLINE = "\n"
1316
1187
 
1317
- def tok(rx)
1188
+ def tok(rx, last_group_lookahead = false)
1318
1189
  res = @scanner.scan(rx)
1190
+ if res
1191
+ # This fixes https://github.com/nex3/sass/issues/104, which affects
1192
+ # Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
1193
+ # positive lookahead operator in the Regexp (which matches without
1194
+ # consuming the matched group), with a match that does consume the
1195
+ # group, but then rewinds the scanner and removes the group from the
1196
+ # end of the matched string. This fix makes the assumption that the
1197
+ # matched group will always occur at the end of the match.
1198
+ if last_group_lookahead && @scanner[-1]
1199
+ @scanner.pos -= @scanner[-1].length
1200
+ res.slice!(-@scanner[-1].length..-1)
1201
+ end
1319
1202
 
1320
- return unless res
1321
-
1322
- newline_count = res.count(NEWLINE)
1323
- if newline_count > 0
1324
- @line += newline_count
1325
- @offset = res[res.rindex(NEWLINE)..-1].size
1326
- else
1327
- @offset += res.size
1328
- end
1203
+ newline_count = res.count(NEWLINE)
1204
+ if newline_count > 0
1205
+ @line += newline_count
1206
+ @offset = res[res.rindex(NEWLINE)..-1].size
1207
+ else
1208
+ @offset += res.size
1209
+ end
1329
1210
 
1330
- @expected = nil
1331
- if !@strs.empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT
1332
- @strs.each {|s| s << res}
1211
+ @expected = nil
1212
+ if !@strs.empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT
1213
+ @strs.each {|s| s << res}
1214
+ end
1215
+ res
1333
1216
  end
1334
- res
1335
1217
  end
1336
1218
 
1337
1219
  # Remove a vendor prefix from `str`.