sass 3.1.21 → 3.2.0.alpha.3

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 (180) hide show
  1. data/README.md +5 -4
  2. data/REVISION +1 -1
  3. data/Rakefile +6 -15
  4. data/VERSION +1 -1
  5. data/VERSION_NAME +1 -1
  6. data/lib/sass.rb +0 -1
  7. data/lib/sass/cache_stores/base.rb +1 -3
  8. data/lib/sass/cache_stores/filesystem.rb +0 -3
  9. data/lib/sass/css.rb +49 -145
  10. data/lib/sass/engine.rb +23 -47
  11. data/lib/sass/environment.rb +5 -30
  12. data/lib/sass/exec.rb +7 -30
  13. data/lib/sass/importers/base.rb +1 -2
  14. data/lib/sass/importers/filesystem.rb +13 -18
  15. data/lib/sass/less.rb +1 -1
  16. data/lib/sass/plugin.rb +8 -4
  17. data/lib/sass/plugin/compiler.rb +67 -93
  18. data/lib/sass/plugin/configuration.rb +2 -0
  19. data/lib/sass/plugin/staleness_checker.rb +4 -14
  20. data/lib/sass/repl.rb +3 -2
  21. data/lib/sass/script.rb +1 -0
  22. data/lib/sass/script/color.rb +9 -4
  23. data/lib/sass/script/funcall.rb +3 -16
  24. data/lib/sass/script/functions.rb +55 -98
  25. data/lib/sass/script/interpolation.rb +0 -9
  26. data/lib/sass/script/lexer.rb +4 -2
  27. data/lib/sass/script/list.rb +0 -8
  28. data/lib/sass/script/literal.rb +20 -5
  29. data/lib/sass/script/node.rb +0 -8
  30. data/lib/sass/script/number.rb +11 -35
  31. data/lib/sass/script/operation.rb +0 -16
  32. data/lib/sass/script/parser.rb +5 -12
  33. data/lib/sass/script/string_interpolation.rb +0 -9
  34. data/lib/sass/script/unary_operation.rb +0 -7
  35. data/lib/sass/script/variable.rb +1 -5
  36. data/lib/sass/scss/parser.rb +54 -191
  37. data/lib/sass/scss/rx.rb +3 -15
  38. data/lib/sass/scss/static_parser.rb +3 -3
  39. data/lib/sass/selector.rb +3 -15
  40. data/lib/sass/selector/abstract_sequence.rb +2 -11
  41. data/lib/sass/selector/comma_sequence.rb +3 -8
  42. data/lib/sass/selector/sequence.rb +11 -74
  43. data/lib/sass/selector/simple.rb +1 -7
  44. data/lib/sass/selector/simple_sequence.rb +8 -28
  45. data/lib/sass/shared.rb +5 -3
  46. data/lib/sass/tree/comment_node.rb +12 -25
  47. data/lib/sass/tree/debug_node.rb +1 -1
  48. data/lib/sass/tree/directive_node.rb +0 -5
  49. data/lib/sass/tree/each_node.rb +1 -1
  50. data/lib/sass/tree/extend_node.rb +1 -1
  51. data/lib/sass/tree/for_node.rb +2 -2
  52. data/lib/sass/tree/function_node.rb +1 -1
  53. data/lib/sass/tree/if_node.rb +14 -1
  54. data/lib/sass/tree/media_node.rb +4 -4
  55. data/lib/sass/tree/mixin_def_node.rb +1 -1
  56. data/lib/sass/tree/mixin_node.rb +2 -2
  57. data/lib/sass/tree/node.rb +26 -10
  58. data/lib/sass/tree/return_node.rb +1 -1
  59. data/lib/sass/tree/root_node.rb +1 -1
  60. data/lib/sass/tree/rule_node.rb +11 -9
  61. data/lib/sass/tree/variable_node.rb +1 -1
  62. data/lib/sass/tree/visitors/base.rb +1 -1
  63. data/lib/sass/tree/visitors/check_nesting.rb +36 -29
  64. data/lib/sass/tree/visitors/convert.rb +9 -16
  65. data/lib/sass/tree/visitors/cssize.rb +9 -40
  66. data/lib/sass/tree/visitors/perform.rb +23 -79
  67. data/lib/sass/tree/visitors/to_css.rb +21 -23
  68. data/lib/sass/tree/warn_node.rb +1 -1
  69. data/lib/sass/tree/while_node.rb +1 -1
  70. data/lib/sass/util.rb +9 -147
  71. data/lib/sass/version.rb +0 -14
  72. data/test/sass/cache_test.rb +0 -15
  73. data/test/sass/conversion_test.rb +8 -50
  74. data/test/sass/css2sass_test.rb +0 -33
  75. data/test/sass/engine_test.rb +32 -283
  76. data/test/sass/extend_test.rb +0 -315
  77. data/test/sass/functions_test.rb +23 -60
  78. data/test/sass/importer_test.rb +0 -110
  79. data/test/sass/more_results/more_import.css +2 -2
  80. data/test/sass/plugin_test.rb +13 -40
  81. data/test/sass/results/import.css +2 -2
  82. data/test/sass/results/import_charset.css +0 -1
  83. data/test/sass/results/import_charset_1_8.css +0 -1
  84. data/test/sass/results/import_charset_ibm866.css +0 -1
  85. data/test/sass/results/scss_import.css +2 -2
  86. data/test/sass/results/units.css +1 -1
  87. data/test/sass/script_conversion_test.rb +0 -2
  88. data/test/sass/script_test.rb +4 -28
  89. data/test/sass/scss/css_test.rb +1 -79
  90. data/test/sass/scss/scss_test.rb +16 -96
  91. data/test/sass/templates/import_charset.sass +0 -2
  92. data/test/sass/templates/import_charset_1_8.sass +0 -2
  93. data/test/sass/templates/import_charset_ibm866.sass +0 -2
  94. data/test/sass/test_helper.rb +1 -1
  95. data/test/sass/util_test.rb +0 -28
  96. data/test/test_helper.rb +0 -2
  97. data/vendor/{listen → fssm}/LICENSE +1 -1
  98. data/vendor/fssm/README.markdown +55 -0
  99. data/vendor/fssm/Rakefile +59 -0
  100. data/vendor/fssm/VERSION.yml +5 -0
  101. data/vendor/fssm/example.rb +9 -0
  102. data/vendor/fssm/fssm.gemspec +77 -0
  103. data/vendor/fssm/lib/fssm.rb +33 -0
  104. data/vendor/fssm/lib/fssm/backends/fsevents.rb +36 -0
  105. data/vendor/fssm/lib/fssm/backends/inotify.rb +26 -0
  106. data/vendor/fssm/lib/fssm/backends/polling.rb +25 -0
  107. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +131 -0
  108. data/vendor/fssm/lib/fssm/monitor.rb +26 -0
  109. data/vendor/fssm/lib/fssm/path.rb +91 -0
  110. data/vendor/fssm/lib/fssm/pathname.rb +502 -0
  111. data/vendor/fssm/lib/fssm/state/directory.rb +57 -0
  112. data/vendor/fssm/lib/fssm/state/file.rb +24 -0
  113. data/vendor/fssm/lib/fssm/support.rb +63 -0
  114. data/vendor/fssm/lib/fssm/tree.rb +176 -0
  115. data/vendor/fssm/profile/prof-cache.rb +40 -0
  116. data/vendor/fssm/profile/prof-fssm-pathname.html +1231 -0
  117. data/vendor/fssm/profile/prof-pathname.rb +68 -0
  118. data/vendor/fssm/profile/prof-plain-pathname.html +988 -0
  119. data/vendor/fssm/profile/prof.html +2379 -0
  120. data/vendor/fssm/spec/path_spec.rb +75 -0
  121. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  122. data/vendor/fssm/spec/root/file.css +0 -0
  123. data/vendor/fssm/spec/root/file.rb +0 -0
  124. data/vendor/fssm/spec/root/file.yml +0 -0
  125. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  126. data/vendor/fssm/spec/spec_helper.rb +14 -0
  127. metadata +246 -281
  128. data/VERSION_DATE +0 -1
  129. data/lib/sass/logger.rb +0 -15
  130. data/lib/sass/logger/base.rb +0 -32
  131. data/lib/sass/logger/log_level.rb +0 -49
  132. data/lib/sass/tree/visitors/deep_copy.rb +0 -87
  133. data/lib/sass/tree/visitors/extend.rb +0 -42
  134. data/lib/sass/tree/visitors/set_options.rb +0 -97
  135. data/lib/sass/util/multibyte_string_scanner.rb +0 -134
  136. data/test/Gemfile +0 -4
  137. data/test/Gemfile.lock +0 -19
  138. data/test/sass/fixtures/test_staleness_check_across_importers.css +0 -1
  139. data/test/sass/fixtures/test_staleness_check_across_importers.scss +0 -1
  140. data/test/sass/logger_test.rb +0 -58
  141. data/test/sass/templates/_double_import_loop2.sass +0 -1
  142. data/test/sass/templates/bork5.sass +0 -3
  143. data/test/sass/templates/double_import_loop1.sass +0 -1
  144. data/test/sass/templates/nested_bork5.sass +0 -2
  145. data/test/sass/templates/single_import_loop.sass +0 -1
  146. data/test/sass/util/multibyte_string_scanner_test.rb +0 -147
  147. data/vendor/listen/CHANGELOG.md +0 -147
  148. data/vendor/listen/Gemfile +0 -23
  149. data/vendor/listen/Guardfile +0 -8
  150. data/vendor/listen/README.md +0 -312
  151. data/vendor/listen/Rakefile +0 -47
  152. data/vendor/listen/Vagrantfile +0 -96
  153. data/vendor/listen/lib/listen.rb +0 -38
  154. data/vendor/listen/lib/listen/adapter.rb +0 -167
  155. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -84
  156. data/vendor/listen/lib/listen/adapters/linux.rb +0 -110
  157. data/vendor/listen/lib/listen/adapters/polling.rb +0 -66
  158. data/vendor/listen/lib/listen/adapters/windows.rb +0 -81
  159. data/vendor/listen/lib/listen/directory_record.rb +0 -318
  160. data/vendor/listen/lib/listen/listener.rb +0 -203
  161. data/vendor/listen/lib/listen/multi_listener.rb +0 -121
  162. data/vendor/listen/lib/listen/turnstile.rb +0 -28
  163. data/vendor/listen/lib/listen/version.rb +0 -3
  164. data/vendor/listen/listen.gemspec +0 -26
  165. data/vendor/listen/spec/listen/adapter_spec.rb +0 -142
  166. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -31
  167. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -41
  168. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  169. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -24
  170. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1138
  171. data/vendor/listen/spec/listen/listener_spec.rb +0 -155
  172. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -156
  173. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  174. data/vendor/listen/spec/listen_spec.rb +0 -73
  175. data/vendor/listen/spec/spec_helper.rb +0 -18
  176. data/vendor/listen/spec/support/adapter_helper.rb +0 -716
  177. data/vendor/listen/spec/support/directory_record_helper.rb +0 -55
  178. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  179. data/vendor/listen/spec/support/listeners_helper.rb +0 -144
  180. data/vendor/listen/spec/support/platform_helper.rb +0 -11
@@ -24,13 +24,6 @@ module Sass::Script
24
24
  @separator = separator
25
25
  end
26
26
 
27
- # @see Node#deep_copy
28
- def deep_copy
29
- node = dup
30
- node.instance_variable_set('@value', value.map {|c| c.deep_copy})
31
- node
32
- end
33
-
34
27
  # @see Node#eq
35
28
  def eq(other)
36
29
  Sass::Script::Bool.new(
@@ -46,7 +39,6 @@ module Sass::Script
46
39
 
47
40
  # @see Node#to_sass
48
41
  def to_sass(opts = {})
49
- return "()" if value.empty?
50
42
  precedence = Sass::Script::Parser.precedence_of(separator)
51
43
  value.map do |v|
52
44
  if v.is_a?(List) && Sass::Script::Parser.precedence_of(v.separator) <= precedence
@@ -33,11 +33,6 @@ module Sass::Script
33
33
  []
34
34
  end
35
35
 
36
- # @see Node#deep_copy
37
- def deep_copy
38
- dup
39
- end
40
-
41
36
  # Returns the options hash for this node.
42
37
  #
43
38
  # @return [{Symbol => Object}]
@@ -55,6 +50,26 @@ The #options attribute is not set on this #{self.class}.
55
50
  MSG
56
51
  end
57
52
 
53
+ # The SassScript `and` operation.
54
+ #
55
+ # @param other [Literal] The right-hand side of the operator
56
+ # @return [Literal] The result of a logical and:
57
+ # `other` if this literal isn't a false {Bool},
58
+ # and this literal otherwise
59
+ def and(other)
60
+ to_bool ? other : self
61
+ end
62
+
63
+ # The SassScript `or` operation.
64
+ #
65
+ # @param other [Literal] The right-hand side of the operator
66
+ # @return [Literal] The result of the logical or:
67
+ # this literal if it isn't a false {Bool},
68
+ # and `other` otherwise
69
+ def or(other)
70
+ to_bool ? self : other
71
+ end
72
+
58
73
  # The SassScript `==` operation.
59
74
  # **Note that this returns a {Sass::Script::Bool} object,
60
75
  # not a Ruby boolean**.
@@ -57,14 +57,6 @@ module Sass::Script
57
57
  Sass::Util.abstract(self)
58
58
  end
59
59
 
60
- # Returns a deep clone of this node.
61
- # The child nodes are cloned, but options are not.
62
- #
63
- # @return [Node]
64
- def deep_copy
65
- Sass::Util.abstract(self)
66
- end
67
-
68
60
  protected
69
61
 
70
62
  # Converts underscores to dashes if the :dasherize option is set.
@@ -35,34 +35,11 @@ module Sass::Script
35
35
  # @return [Boolean, nil]
36
36
  attr_accessor :original
37
37
 
38
- def self.precision
39
- @precision ||= 3
40
- end
41
-
42
- # Sets the number of digits of precision
43
- # For example, if this is `3`,
38
+ # The precision with which numbers will be printed to CSS files.
39
+ # For example, if this is `1000.0`,
44
40
  # `3.1415926` will be printed as `3.142`.
45
- def self.precision=(digits)
46
- @precision = digits.round
47
- @precision_factor = 10.0**@precision
48
- end
49
-
50
- # the precision factor used in numeric output
51
- # it is derived from the `precision` method.
52
- def self.precision_factor
53
- @precision_factor ||= 10.0**precision
54
- end
55
-
56
- # Handles the deprecation warning for the PRECISION constant
57
- # This can be removed in 3.2.
58
- def self.const_missing(const)
59
- if const == :PRECISION
60
- Sass::Util.sass_warn("Sass::Script::Number::PRECISION is deprecated and will be removed in a future release. Use Sass::Script::Number.precision_factor instead.")
61
- const_set(:PRECISION, self.precision_factor)
62
- else
63
- super
64
- end
65
- end
41
+ # @api public
42
+ PRECISION = 1000.0
66
43
 
67
44
  # Used so we don't allocate two new arrays for each new number.
68
45
  NO_UNITS = []
@@ -360,7 +337,7 @@ module Sass::Script
360
337
  elsif num % 1 == 0.0
361
338
  num.to_i
362
339
  else
363
- ((num * self.precision_factor).round / self.precision_factor).to_f
340
+ (num * PRECISION).round / PRECISION
364
341
  end
365
342
  end
366
343
 
@@ -422,13 +399,12 @@ module Sass::Script
422
399
  end
423
400
 
424
401
  # A hash of unit names to their index in the conversion table
425
- CONVERTABLE_UNITS = {"in" => 0, "cm" => 1, "pc" => 2, "mm" => 3, "pt" => 4, "px" => 5 }
426
- CONVERSION_TABLE = [[ 1, 2.54, 6, 25.4, 72 , 96 ], # in
427
- [ nil, 1, 2.36220473, 10, 28.3464567, 37.795275591], # cm
428
- [ nil, nil, 1, 4.23333333, 12 , 16 ], # pc
429
- [ nil, nil, nil, 1, 2.83464567, 3.7795275591], # mm
430
- [ nil, nil, nil, nil, 1 , 1.3333333333], # pt
431
- [ nil, nil, nil, nil, nil , 1 ]] # px
402
+ CONVERTABLE_UNITS = {"in" => 0, "cm" => 1, "pc" => 2, "mm" => 3, "pt" => 4}
403
+ CONVERSION_TABLE = [[ 1, 2.54, 6, 25.4, 72 ], # in
404
+ [ nil, 1, 2.36220473, 10, 28.3464567], # cm
405
+ [ nil, nil, 1, 4.23333333, 12 ], # pc
406
+ [ nil, nil, nil, 1, 2.83464567], # mm
407
+ [ nil, nil, nil, nil, 1 ]] # pt
432
408
 
433
409
  def conversion_factor(from_unit, to_unit)
434
410
  res = CONVERSION_TABLE[CONVERTABLE_UNITS[from_unit]][CONVERTABLE_UNITS[to_unit]]
@@ -55,14 +55,6 @@ module Sass::Script
55
55
  [@operand1, @operand2]
56
56
  end
57
57
 
58
- # @see Node#deep_copy
59
- def deep_copy
60
- node = dup
61
- node.instance_variable_set('@operand1', @operand1.deep_copy)
62
- node.instance_variable_set('@operand2', @operand2.deep_copy)
63
- node
64
- end
65
-
66
58
  protected
67
59
 
68
60
  # Evaluates the operation.
@@ -72,14 +64,6 @@ module Sass::Script
72
64
  # @raise [Sass::SyntaxError] if the operation is undefined for the operands
73
65
  def _perform(environment)
74
66
  literal1 = @operand1.perform(environment)
75
-
76
- # Special-case :and and :or to support short-circuiting.
77
- if @operator == :and
78
- return literal1.to_bool ? @operand2.perform(environment) : literal1
79
- elsif @operator == :or
80
- return literal1.to_bool ? literal1 : @operand2.perform(environment)
81
- end
82
-
83
67
  literal2 = @operand2.perform(environment)
84
68
 
85
69
  begin
@@ -182,11 +182,7 @@ module Sass
182
182
  interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}) and return interp
183
183
  return unless e = #{sub}
184
184
  while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
185
- if interp = try_op_before_interp(tok, e)
186
- return interp unless other_interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}, interp)
187
- return other_interp
188
- end
189
-
185
+ interp = try_op_before_interp(tok, e) and return interp
190
186
  line = @lexer.line
191
187
  e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
192
188
  e.line = line
@@ -221,10 +217,7 @@ RUBY
221
217
  return unless e = interpolation
222
218
  arr = [e]
223
219
  while tok = try_tok(:comma)
224
- if interp = try_op_before_interp(tok, e)
225
- return interp unless other_interp = try_ops_after_interp([:comma], :expr, interp)
226
- return other_interp
227
- end
220
+ interp = try_op_before_interp(tok, e) and return interp
228
221
  arr << assert_expr(:interpolation)
229
222
  end
230
223
  arr.size == 1 ? arr.first : node(List.new(arr, :comma), line)
@@ -242,15 +235,15 @@ RUBY
242
235
  interpolation(interp)
243
236
  end
244
237
 
245
- def try_ops_after_interp(ops, name, prev = nil)
238
+ def try_ops_after_interp(ops, name)
246
239
  return unless @lexer.after_interpolation?
247
240
  return unless op = try_tok(*ops)
248
- interp = try_op_before_interp(op, prev) and return interp
241
+ interp = try_op_before_interp(op) and return interp
249
242
 
250
243
  wa = @lexer.whitespace?
251
244
  str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
252
245
  str.line = @lexer.line
253
- interp = Script::Interpolation.new(prev, str, assert_expr(name), !:wb, wa, :originally_text)
246
+ interp = Script::Interpolation.new(nil, str, assert_expr(name), !:wb, wa, :originally_text)
254
247
  interp.line = @lexer.line
255
248
  return interp
256
249
  end
@@ -60,15 +60,6 @@ module Sass::Script
60
60
  [@before, @mid, @after].compact
61
61
  end
62
62
 
63
- # @see Node#deep_copy
64
- def deep_copy
65
- node = dup
66
- node.instance_variable_set('@before', @before.deep_copy) if @before
67
- node.instance_variable_set('@mid', @mid.deep_copy)
68
- node.instance_variable_set('@after', @after.deep_copy) if @after
69
- node
70
- end
71
-
72
63
  protected
73
64
 
74
65
  # Evaluates the interpolation.
@@ -38,13 +38,6 @@ module Sass::Script
38
38
  [@operand]
39
39
  end
40
40
 
41
- # @see Node#deep_copy
42
- def deep_copy
43
- node = dup
44
- node.instance_variable_set('@operand', @operand.deep_copy)
45
- node
46
- end
47
-
48
41
  protected
49
42
 
50
43
  # Evaluates the operation.
@@ -21,6 +21,7 @@ module Sass
21
21
 
22
22
  # @return [String] A string representation of the variable
23
23
  def inspect(opts = {})
24
+ return "!important" if name == "important"
24
25
  "$#{dasherize(name, opts)}"
25
26
  end
26
27
  alias_method :to_sass, :inspect
@@ -33,11 +34,6 @@ module Sass
33
34
  []
34
35
  end
35
36
 
36
- # @see Node#deep_copy
37
- def deep_copy
38
- dup
39
- end
40
-
41
37
  protected
42
38
 
43
39
  # Evaluates the variable.
@@ -1,3 +1,4 @@
1
+ require 'strscan'
1
2
  require 'set'
2
3
 
3
4
  module Sass
@@ -8,12 +9,10 @@ module Sass
8
9
  # @param str [String, StringScanner] The source document to parse.
9
10
  # Note that `Parser` *won't* raise a nice error message if this isn't properly parsed;
10
11
  # for that, you should use the higher-level {Sass::Engine} or {Sass::CSS}.
11
- # @param filename [String] The name of the file being parsed. Used for warnings.
12
12
  # @param line [Fixnum] The line on which the source string appeared,
13
- # if it's part of another document.
14
- def initialize(str, filename, line = 1)
13
+ # if it's part of another document
14
+ def initialize(str, line = 1)
15
15
  @template = str
16
- @filename = filename
17
16
  @line = line
18
17
  @strs = []
19
18
  end
@@ -49,7 +48,7 @@ module Sass
49
48
  if @template.is_a?(StringScanner)
50
49
  @template
51
50
  else
52
- Sass::Util::MultibyteStringScanner.new(@template.gsub("\r", ""))
51
+ StringScanner.new(@template.gsub("\r", ""))
53
52
  end
54
53
  end
55
54
 
@@ -88,35 +87,19 @@ module Sass
88
87
  end
89
88
 
90
89
  def process_comment(text, node)
91
- silent = text =~ /^\/\//
92
- line = @line - text.count("\n")
93
- if loud = text =~ %r{^/[/*]!}
94
- value = Sass::Engine.parse_interp(text, line, @scanner.pos - text.size, :filename => @filename)
95
- value[0].slice!(2) # get rid of the "!"
96
- else
97
- value = [text]
98
- end
99
-
100
- if silent
101
- value = Sass::Util.with_extracted_values(value) do |str|
102
- str.sub(/^\s*\/\//, '/*').gsub(/^\s*\/\//, ' *') + ' */'
103
- end
104
- else
105
- value.unshift(@scanner.
106
- string[0...@scanner.pos].
107
- reverse[/.*?\*\/(.*?)($|\Z)/, 1].
108
- reverse.gsub(/[^\s]/, ' '))
109
- end
110
-
111
- comment = Sass::Tree::CommentNode.new(value, silent, loud)
112
- comment.line = line
90
+ single_line = text =~ /^\/\//
91
+ pre_str = single_line ? "" : @scanner.
92
+ string[0...@scanner.pos].
93
+ reverse[/.*?\*\/(.*?)($|\Z)/, 1].
94
+ reverse.gsub(/[^\s]/, ' ')
95
+ text = text.sub(/^\s*\/\//, '/*').gsub(/^\s*\/\//, ' *') + ' */' if single_line
96
+ comment = Sass::Tree::CommentNode.new(pre_str + text, single_line)
97
+ comment.line = @line - text.count("\n")
113
98
  node << comment
114
99
  end
115
100
 
116
101
  DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
117
- :each, :while, :if, :else, :extend, :import, :media, :charset, :_moz_document]
118
-
119
- PREFIXED_DIRECTIVES = Set[:supports]
102
+ :each, :while, :if, :else, :extend, :import, :media, :charset]
120
103
 
121
104
  def directive
122
105
  return unless tok(/@/)
@@ -125,19 +108,13 @@ module Sass
125
108
 
126
109
  if dir = special_directive(name)
127
110
  return dir
128
- elsif dir = prefixed_directive(name)
129
- return dir
130
111
  end
131
112
 
132
113
  # Most at-rules take expressions (e.g. @import),
133
114
  # but some (e.g. @page) take selector-like arguments
134
115
  val = str {break unless expr}
135
116
  val ||= CssParser.new(@scanner, @line).parse_selector_string
136
- directive_body("@#{name} #{val}")
137
- end
138
-
139
- def directive_body(value)
140
- node = node(Sass::Tree::DirectiveNode.new(value.strip))
117
+ node = node(Sass::Tree::DirectiveNode.new("@#{name} #{val}".strip))
141
118
 
142
119
  if tok(/\{/)
143
120
  node.has_children = true
@@ -153,11 +130,6 @@ module Sass
153
130
  DIRECTIVES.include?(sym) && send("#{sym}_directive")
154
131
  end
155
132
 
156
- def prefixed_directive(name)
157
- sym = name.gsub(/^-[a-z0-9]+-/i, '').gsub('-', '_').to_sym
158
- PREFIXED_DIRECTIVES.include?(sym) && send("#{sym}_directive", name)
159
- end
160
-
161
133
  def mixin_directive
162
134
  name = tok! IDENT
163
135
  args = sass_script(:parse_mixin_definition_arglist)
@@ -268,7 +240,7 @@ module Sass
268
240
  end
269
241
 
270
242
  def extend_directive
271
- node(Sass::Tree::ExtendNode.new(expr!(:selector_sequence)))
243
+ node(Sass::Tree::ExtendNode.new(expr!(:selector)))
272
244
  end
273
245
 
274
246
  def import_directive
@@ -299,23 +271,20 @@ module Sass
299
271
  def use_css_import?; false; end
300
272
 
301
273
  def media_directive
302
- block(node(Sass::Tree::MediaNode.new(media_query_list)), :directive)
274
+ val = str {media_query_list}.strip
275
+ block(node(Sass::Tree::MediaNode.new(val)), :directive)
303
276
  end
304
277
 
305
278
  # http://www.w3.org/TR/css3-mediaqueries/#syntax
306
279
  def media_query_list
307
- has_q = false
308
- q = str {has_q = media_query}
309
-
310
- return unless has_q
311
- queries = [q.strip]
280
+ return unless media_query
312
281
 
313
282
  ss
314
283
  while tok(/,/)
315
- ss; queries << str {expr!(:media_query)}.strip; ss
284
+ ss; expr!(:media_query); ss
316
285
  end
317
286
 
318
- queries
287
+ true
319
288
  end
320
289
 
321
290
  def media_query
@@ -359,76 +328,6 @@ module Sass
359
328
  node(Sass::Tree::CharsetNode.new(name))
360
329
  end
361
330
 
362
- # The document directive is specified in
363
- # http://www.w3.org/TR/css3-conditional/, but Gecko allows the
364
- # `url-prefix` and `domain` functions to omit quotation marks, contrary to
365
- # the standard.
366
- #
367
- # We could parse all document directives according to Mozilla's syntax,
368
- # but if someone's using e.g. @-webkit-document we don't want them to
369
- # think WebKit works sans quotes.
370
- def _moz_document_directive
371
- value = str do
372
- begin
373
- ss
374
- expr!(:moz_document_function)
375
- end while tok(/,/)
376
- end
377
- directive_body("@-moz-document #{value}")
378
- end
379
-
380
- def moz_document_function
381
- return unless tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function
382
- ss
383
- end
384
-
385
- # http://www.w3.org/TR/css3-conditional/
386
- def supports_directive(name)
387
- value = str {expr!(:supports_condition)}
388
- directive_body("@#{name} #{value}")
389
- end
390
-
391
- def supports_condition
392
- supports_negation || supports_operator || supports_declaration_condition
393
- end
394
-
395
- def supports_negation
396
- return unless tok(/not/i)
397
- ss
398
- expr!(:supports_condition_in_parens)
399
- end
400
-
401
- def supports_operator
402
- return unless supports_condition_in_parens
403
- tok!(/and|or/i)
404
- begin
405
- ss
406
- expr!(:supports_condition_in_parens)
407
- end while tok(/and|or/i)
408
- true
409
- end
410
-
411
- def supports_condition_in_parens
412
- return unless tok(/\(/); ss
413
- if supports_condition
414
- tok!(/\)/); ss
415
- else
416
- supports_declaration_body
417
- end
418
- end
419
-
420
- def supports_declaration_condition
421
- return unless tok(/\(/); ss
422
- supports_declaration_body
423
- end
424
-
425
- def supports_declaration_body
426
- tok!(IDENT); ss
427
- tok!(/:/); ss
428
- expr!(:expr); ss
429
- tok!(/\)/); ss
430
- end
431
-
432
331
  def variable
433
332
  return unless tok(/\$/)
434
333
  name = tok!(IDENT)
@@ -522,7 +421,7 @@ module Sass
522
421
  end
523
422
 
524
423
  def selector_sequence
525
- if sel = tok(STATIC_SELECTOR, true)
424
+ if sel = tok(STATIC_SELECTOR)
526
425
  return [sel]
527
426
  end
528
427
 
@@ -588,30 +487,21 @@ module Sass
588
487
  res = [e]
589
488
 
590
489
  # The tok(/\*/) allows the "E*" hack
591
- while v = id_selector || class_selector || attrib || negation || pseudo ||
592
- interpolation_selector || (tok(/\*/) && Selector::Universal.new(nil))
490
+ while v = element_name || id_selector || class_selector ||
491
+ attrib || negation || pseudo || interpolation_selector ||
492
+ (tok(/\*/) && Selector::Universal.new(nil))
593
493
  res << v
594
494
  end
595
495
 
596
- pos = @scanner.pos
597
- line = @line
598
- if sel = str? {simple_selector_sequence}
599
- @scanner.pos = pos
600
- @line = line
601
-
602
- if sel =~ /^&/
603
- begin
604
- throw_error {expected('"{"')}
605
- rescue Sass::SyntaxError => e
606
- e.message << "\n\n\"#{sel}\" may only be used at the beginning of a selector."
607
- raise e
608
- end
609
- else
610
- Sass::Util.sass_warn(<<MESSAGE)
611
- DEPRECATION WARNING:
612
- On line #{@line}#{" of \"#{@filename}\"" if @filename}, after "#{self.class.prior_snippet(@scanner)}"
613
- Starting in Sass 3.2, "#{sel}" may only be used at the beginning of a selector.
496
+ if tok?(/&/)
497
+ begin
498
+ expected('"{"')
499
+ rescue Sass::SyntaxError => e
500
+ e.message << "\n\n" << <<MESSAGE
501
+ In Sass 3, the parent selector & can only be used where element names are valid,
502
+ since it could potentially be replaced by an element name.
614
503
  MESSAGE
504
+ raise e
615
505
  end
616
506
  end
617
507
 
@@ -669,10 +559,14 @@ MESSAGE
669
559
  tok(SUBSTRINGMATCH)
670
560
  @expected = "identifier or string"
671
561
  ss
672
- val = interp_ident || expr!(:interp_string)
562
+ if val = tok(IDENT)
563
+ val = [val]
564
+ else
565
+ val = expr!(:interp_string)
566
+ end
673
567
  ss
674
568
  end
675
- tok!(/\]/)
569
+ tok(/\]/)
676
570
 
677
571
  Selector::Attribute.new(merge(name), merge(ns), op, merge(val))
678
572
  end
@@ -762,7 +656,7 @@ MESSAGE
762
656
  # we don't parse it at all, and instead return a plain old string
763
657
  # containing the value.
764
658
  # This results in a dramatic speed increase.
765
- if val = tok(STATIC_VALUE, true)
659
+ if val = tok(STATIC_VALUE)
766
660
  return space, Sass::Script::String.new(val.strip)
767
661
  end
768
662
  return space, sass_script(:parse)
@@ -851,7 +745,7 @@ MESSAGE
851
745
  end
852
746
 
853
747
  def interp_ident(start = IDENT)
854
- return unless val = tok(start) || interpolation || tok(IDENT_HYPHEN_INTERP, true)
748
+ return unless val = tok(start) || interpolation
855
749
  res = [val]
856
750
  while val = tok(NAME) || interpolation
857
751
  res << val
@@ -872,14 +766,8 @@ MESSAGE
872
766
  end
873
767
 
874
768
  def str?
875
- pos = @scanner.pos
876
- line = @line
877
769
  @strs.push ""
878
- throw_error {yield} && @strs.last
879
- rescue Sass::SyntaxError => e
880
- @scanner.pos = pos
881
- @line = line
882
- nil
770
+ yield && @strs.last
883
771
  ensure
884
772
  @strs.pop
885
773
  end
@@ -920,9 +808,6 @@ MESSAGE
920
808
  :selector_comma_sequence => "selector",
921
809
  :simple_selector_sequence => "selector",
922
810
  :import_arg => "file to import (string or url())",
923
- :moz_document_function => "matching function (e.g. url-prefix(), domain())",
924
- :supports_condition => "@supports condition (e.g. (display: flexbox))",
925
- :supports_condition_in_parens => "@supports condition (e.g. (display: flexbox))",
926
811
  }
927
812
 
928
813
  TOK_NAMES = Sass::Util.to_hash(
@@ -961,13 +846,6 @@ MESSAGE
961
846
  raise Sass::SyntaxError.new(msg, :line => @line)
962
847
  end
963
848
 
964
- def throw_error
965
- old_throw_error, @throw_error = @throw_error, false
966
- yield
967
- ensure
968
- @throw_error = old_throw_error
969
- end
970
-
971
849
  def catch_error(&block)
972
850
  old_throw_error, @throw_error = @throw_error, true
973
851
  pos = @scanner.pos
@@ -987,7 +865,7 @@ MESSAGE
987
865
  if @throw_err
988
866
  throw :_sass_parser_error, err
989
867
  else
990
- @scanner = Sass::Util::MultibyteStringScanner.new(@scanner.string)
868
+ @scanner = StringScanner.new(@scanner.string)
991
869
  @scanner.pos = err[:pos]
992
870
  @line = err[:line]
993
871
  @expected = err[:expected]
@@ -997,6 +875,16 @@ MESSAGE
997
875
 
998
876
  # @private
999
877
  def self.expected(scanner, expected, line)
878
+ pos = scanner.pos
879
+
880
+ after = scanner.string[0...pos]
881
+ # Get rid of whitespace between pos and the last token,
882
+ # but only if there's a newline in there
883
+ after.gsub!(/\s*\n\s*$/, '')
884
+ # Also get rid of stuff before the last newline
885
+ after.gsub!(/.*\n/, '')
886
+ after = "..." + after[-15..-1] if after.size > 18
887
+
1000
888
  was = scanner.rest.dup
1001
889
  # Get rid of whitespace between pos and the next token,
1002
890
  # but only if there's a newline in there
@@ -1006,42 +894,17 @@ MESSAGE
1006
894
  was = was[0...15] + "..." if was.size > 18
1007
895
 
1008
896
  raise Sass::SyntaxError.new(
1009
- "Invalid CSS after \"#{prior_snippet(scanner)}\": expected #{expected}, was \"#{was}\"",
897
+ "Invalid CSS after \"#{after}\": expected #{expected}, was \"#{was}\"",
1010
898
  :line => line)
1011
899
  end
1012
900
 
1013
- # @private
1014
- def self.prior_snippet(scanner)
1015
- pos = scanner.pos
1016
-
1017
- after = scanner.string[0...pos]
1018
- # Get rid of whitespace between pos and the last token,
1019
- # but only if there's a newline in there
1020
- after.gsub!(/\s*\n\s*$/, '')
1021
- # Also get rid of stuff before the last newline
1022
- after.gsub!(/.*\n/, '')
1023
- after = "..." + after[-15..-1] if after.size > 18
1024
- after
1025
- end
1026
-
1027
901
  # Avoid allocating lots of new strings for `#tok`.
1028
902
  # This is important because `#tok` is called all the time.
1029
903
  NEWLINE = "\n"
1030
904
 
1031
- def tok(rx, last_group_lookahead = false)
905
+ def tok(rx)
1032
906
  res = @scanner.scan(rx)
1033
907
  if res
1034
- # This fixes https://github.com/nex3/sass/issues/104, which affects
1035
- # Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
1036
- # positive lookahead operator in the Regexp (which matches without
1037
- # consuming the matched group), with a match that does consume the
1038
- # group, but then rewinds the scanner and removes the group from the
1039
- # end of the matched string. This fix makes the assumption that the
1040
- # matched group will always occur at the end of the match.
1041
- if last_group_lookahead && @scanner[-1]
1042
- @scanner.pos -= @scanner[-1].length
1043
- res.slice!(-@scanner[-1].length..-1)
1044
- end
1045
908
  @line += res.count(NEWLINE)
1046
909
  @expected = nil
1047
910
  if !@strs.empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT