sass 3.2.0.alpha.11 → 3.2.0.alpha.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/REVISION +1 -1
  2. data/VERSION +1 -1
  3. data/lib/sass/cache_stores/base.rb +4 -9
  4. data/lib/sass/cache_stores/filesystem.rb +2 -0
  5. data/lib/sass/css.rb +2 -1
  6. data/lib/sass/engine.rb +28 -8
  7. data/lib/sass/environment.rb +26 -0
  8. data/lib/sass/exec.rb +13 -0
  9. data/lib/sass/importers/base.rb +2 -1
  10. data/lib/sass/script/funcall.rb +8 -0
  11. data/lib/sass/script/interpolation.rb +9 -0
  12. data/lib/sass/script/list.rb +7 -0
  13. data/lib/sass/script/literal.rb +5 -0
  14. data/lib/sass/script/node.rb +8 -0
  15. data/lib/sass/script/number.rb +28 -5
  16. data/lib/sass/script/operation.rb +8 -0
  17. data/lib/sass/script/string_interpolation.rb +9 -0
  18. data/lib/sass/script/unary_operation.rb +7 -0
  19. data/lib/sass/script/variable.rb +5 -0
  20. data/lib/sass/scss/parser.rb +26 -13
  21. data/lib/sass/scss/rx.rb +1 -1
  22. data/lib/sass/scss/static_parser.rb +2 -2
  23. data/lib/sass/tree/content_node.rb +9 -0
  24. data/lib/sass/tree/debug_node.rb +1 -6
  25. data/lib/sass/tree/each_node.rb +1 -7
  26. data/lib/sass/tree/extend_node.rb +1 -1
  27. data/lib/sass/tree/for_node.rb +2 -7
  28. data/lib/sass/tree/function_node.rb +1 -6
  29. data/lib/sass/tree/if_node.rb +1 -19
  30. data/lib/sass/tree/mixin_def_node.rb +5 -6
  31. data/lib/sass/tree/mixin_node.rb +2 -7
  32. data/lib/sass/tree/node.rb +4 -19
  33. data/lib/sass/tree/prop_node.rb +0 -5
  34. data/lib/sass/tree/return_node.rb +1 -6
  35. data/lib/sass/tree/rule_node.rb +9 -7
  36. data/lib/sass/tree/trace_node.rb +32 -0
  37. data/lib/sass/tree/variable_node.rb +1 -7
  38. data/lib/sass/tree/visitors/check_nesting.rb +30 -13
  39. data/lib/sass/tree/visitors/convert.rb +5 -1
  40. data/lib/sass/tree/visitors/cssize.rb +3 -3
  41. data/lib/sass/tree/visitors/deep_copy.rb +87 -0
  42. data/lib/sass/tree/visitors/perform.rb +36 -16
  43. data/lib/sass/tree/visitors/set_options.rb +97 -0
  44. data/lib/sass/tree/visitors/to_css.rb +5 -1
  45. data/lib/sass/tree/warn_node.rb +1 -7
  46. data/lib/sass/tree/while_node.rb +1 -7
  47. data/test/sass/cache_test.rb +15 -0
  48. data/test/sass/conversion_test.rb +38 -0
  49. data/test/sass/css2sass_test.rb +9 -0
  50. data/test/sass/engine_test.rb +248 -17
  51. data/test/sass/scss/css_test.rb +4 -2
  52. data/test/sass/scss/scss_test.rb +53 -12
  53. data/vendor/fssm/Gemfile +3 -0
  54. data/vendor/fssm/LICENSE +1 -1
  55. data/vendor/fssm/README.markdown +55 -27
  56. data/vendor/fssm/Rakefile +6 -54
  57. data/vendor/fssm/example.rb +6 -3
  58. data/vendor/fssm/fssm.gemspec +17 -70
  59. data/vendor/fssm/lib/fssm.rb +7 -3
  60. data/vendor/fssm/lib/fssm/backends/fsevents.rb +1 -1
  61. data/vendor/fssm/lib/fssm/backends/inotify.rb +2 -2
  62. data/vendor/fssm/lib/fssm/backends/polling.rb +2 -2
  63. data/vendor/fssm/lib/fssm/backends/rbfsevent.rb +42 -0
  64. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +10 -10
  65. data/vendor/fssm/lib/fssm/monitor.rb +19 -9
  66. data/vendor/fssm/lib/fssm/path.rb +24 -21
  67. data/vendor/fssm/lib/fssm/pathname.rb +13 -479
  68. data/vendor/fssm/lib/fssm/state/directory.rb +29 -11
  69. data/vendor/fssm/lib/fssm/state/file.rb +1 -1
  70. data/vendor/fssm/lib/fssm/support.rb +41 -12
  71. data/vendor/fssm/lib/fssm/tree.rb +6 -6
  72. data/vendor/fssm/lib/fssm/version.rb +3 -0
  73. data/vendor/fssm/profile/prof-cache.rb +3 -3
  74. data/vendor/fssm/profile/prof-pathname-rubinius.rb +35 -0
  75. data/vendor/fssm/profile/prof-pathname.rb +7 -7
  76. data/vendor/fssm/spec/count_down_latch.rb +151 -0
  77. data/vendor/fssm/spec/monitor_spec.rb +202 -0
  78. data/vendor/fssm/spec/path_spec.rb +36 -15
  79. data/vendor/fssm/spec/spec_helper.rb +6 -6
  80. metadata +14 -4
  81. data/vendor/fssm/VERSION.yml +0 -5
data/REVISION CHANGED
@@ -1 +1 @@
1
- bf9eafb0036f01dc23350e0dc1db29b7e5ddf463
1
+ 4ddfd6971c9a04129f3a184c15868ecacf46120f
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.11
1
+ 3.2.0.alpha.21
@@ -42,20 +42,15 @@ module Sass
42
42
  raise "#{self.class} must implement #_retrieve."
43
43
  end
44
44
 
45
- # Store an object to the Sass Cache.
45
+ # Store a {Sass::Tree::RootNode}.
46
46
  #
47
47
  # @param key [String] The key to store it under.
48
48
  # @param sha [String] The checksum for the contents that are being stored.
49
49
  # @param obj [Object] The object to cache.
50
- def store(key, sha, obj)
51
- temp = obj.before_sass_cache_store if obj.respond_to?(:before_sass_cache_store)
52
- begin
53
- _store(key, Sass::VERSION, sha, Marshal.dump(obj))
54
- ensure
55
- obj.after_sass_cache_store(temp) if obj.respond_to?(:after_sass_cache_store)
56
- end
50
+ def store(key, sha, root)
51
+ _store(key, Sass::VERSION, sha, Marshal.dump(root))
57
52
  rescue TypeError, LoadError => e
58
- Sass::Util.sass_warn "Warning. Error encountered while saving a #{obj.class.name} to cache #{path_to(key)}: #{e}"
53
+ Sass::Util.sass_warn "Warning. Error encountered while saving cache #{path_to(key)}: #{e}"
59
54
  end
60
55
 
61
56
  # Retrieve a {Sass::Tree::RootNode}.
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+
1
3
  module Sass
2
4
  module CacheStores
3
5
  # A backend for the Sass cache using the filesystem.
@@ -75,7 +75,7 @@ module Sass
75
75
  #
76
76
  # @return [Tree::Node] The root node of the parsed tree
77
77
  def build_tree
78
- root = Sass::SCSS::CssParser.new(@template).parse
78
+ root = Sass::SCSS::CssParser.new(@template, @options[:filename]).parse
79
79
  expand_commas root
80
80
  parent_ref_rules root
81
81
  remove_parent_refs root
@@ -106,6 +106,7 @@ module Sass
106
106
  next child
107
107
  end
108
108
  child.rule.first.split(',').map do |rule|
109
+ next if rule.strip.empty?
109
110
  node = Tree::RuleNode.new([rule.strip])
110
111
  node.children = child.children
111
112
  node
@@ -12,6 +12,8 @@ require 'sass/tree/media_node'
12
12
  require 'sass/tree/variable_node'
13
13
  require 'sass/tree/mixin_def_node'
14
14
  require 'sass/tree/mixin_node'
15
+ require 'sass/tree/trace_node'
16
+ require 'sass/tree/content_node'
15
17
  require 'sass/tree/function_node'
16
18
  require 'sass/tree/return_node'
17
19
  require 'sass/tree/extend_node'
@@ -28,6 +30,8 @@ require 'sass/tree/visitors/perform'
28
30
  require 'sass/tree/visitors/cssize'
29
31
  require 'sass/tree/visitors/convert'
30
32
  require 'sass/tree/visitors/to_css'
33
+ require 'sass/tree/visitors/deep_copy'
34
+ require 'sass/tree/visitors/set_options'
31
35
  require 'sass/tree/visitors/check_nesting'
32
36
  require 'sass/selector'
33
37
  require 'sass/environment'
@@ -56,7 +60,10 @@ module Sass
56
60
  #
57
61
  # `tree`: `Array<Tree::Node>`
58
62
  # : The parse tree for the mixin/function.
59
- Callable = Struct.new(:name, :args, :environment, :tree)
63
+ #
64
+ # `has_content`: `Boolean`
65
+ # : Whether the callable accepts a content block.
66
+ Callable = Struct.new(:name, :args, :environment, :tree, :has_content)
60
67
 
61
68
  # This class handles the parsing and compilation of the Sass template.
62
69
  # Example usage:
@@ -307,7 +314,6 @@ module Sass
307
314
  sha = Digest::SHA1.hexdigest(@template)
308
315
 
309
316
  if root = @options[:cache_store].retrieve(key, sha)
310
- @options = root.options.merge(@options)
311
317
  root.options = @options
312
318
  return root
313
319
  end
@@ -316,7 +322,7 @@ module Sass
316
322
  check_encoding!
317
323
 
318
324
  if @options[:syntax] == :scss
319
- root = Sass::SCSS::Parser.new(@template).parse
325
+ root = Sass::SCSS::Parser.new(@template, @options[:filename]).parse
320
326
  else
321
327
  root = Tree::RootNode.new(@template)
322
328
  append_children(root, tree(tabulate(@template)).first, true)
@@ -558,7 +564,7 @@ WARNING
558
564
  def parse_property_or_rule(line)
559
565
  scanner = StringScanner.new(line.text)
560
566
  hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
561
- parser = Sass::SCSS::SassParser.new(scanner, @line)
567
+ parser = Sass::SCSS::SassParser.new(scanner, @options[:filename], @line)
562
568
 
563
569
  unless res = parser.parse_interp_ident
564
570
  return Tree::RuleNode.new(parse_interp(line.text))
@@ -619,6 +625,8 @@ WARNING
619
625
  parse_import(line, value)
620
626
  elsif directive == "mixin"
621
627
  parse_mixin_definition(line)
628
+ elsif directive == "content"
629
+ parse_content_directive(line)
622
630
  elsif directive == "include"
623
631
  parse_mixin_include(line, root)
624
632
  elsif directive == "function"
@@ -744,6 +752,11 @@ WARNING
744
752
  break unless scanner.scan(/,\s*/)
745
753
  end
746
754
 
755
+ if scanner.scan(/;/)
756
+ raise SyntaxError.new("Invalid @import: expected end of line, was \";\".",
757
+ :line => @line)
758
+ end
759
+
747
760
  return values
748
761
  end
749
762
 
@@ -751,12 +764,12 @@ WARNING
751
764
  return if scanner.eos?
752
765
  unless (str = scanner.scan(Sass::SCSS::RX::STRING)) ||
753
766
  (uri = scanner.scan(Sass::SCSS::RX::URI))
754
- return Tree::ImportNode.new(scanner.scan(/[^,]+/))
767
+ return Tree::ImportNode.new(scanner.scan(/[^,;]+/))
755
768
  end
756
769
 
757
770
  val = scanner[1] || scanner[2]
758
771
  scanner.scan(/\s*/)
759
- if media = scanner.scan(/[^,].*/)
772
+ if media = scanner.scan(/[^,;].*/)
760
773
  Tree::DirectiveNode.new("@import #{str || uri} #{media}")
761
774
  elsif uri
762
775
  Tree::DirectiveNode.new("@import #{uri}")
@@ -778,6 +791,15 @@ WARNING
778
791
  Tree::MixinDefNode.new(name, args)
779
792
  end
780
793
 
794
+ CONTENT_RE = /^@content\s*(.+)?$/
795
+ def parse_content_directive(line)
796
+ trailing = line.text.scan(CONTENT_RE).first.first
797
+ raise SyntaxError.new("Invalid content directive. Trailing characters found: \"#{trailing}\".") unless trailing.nil?
798
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath @content directives.",
799
+ :line => line.index + 1) unless line.children.empty?
800
+ Tree::ContentNode.new
801
+ end
802
+
781
803
  MIXIN_INCLUDE_RE = /^(?:\+|@include)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
782
804
  def parse_mixin_include(line, root)
783
805
  name, arg_string = line.text.scan(MIXIN_INCLUDE_RE).first
@@ -786,8 +808,6 @@ WARNING
786
808
  offset = line.offset + line.text.size - arg_string.size
787
809
  args, keywords = Script::Parser.new(arg_string.strip, @line, offset, @options).
788
810
  parse_mixin_include_arglist
789
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath mixin directives.",
790
- :line => @line + 1) unless line.children.empty?
791
811
  Tree::MixinNode.new(name, args, keywords)
792
812
  end
793
813
 
@@ -19,6 +19,8 @@ module Sass
19
19
  # @return [Environment]
20
20
  attr_reader :parent
21
21
  attr_writer :options
22
+ attr_writer :caller
23
+ attr_writer :content
22
24
 
23
25
  # @param parent [Environment] See \{#parent}
24
26
  def initialize(parent = nil)
@@ -30,6 +32,19 @@ module Sass
30
32
  end
31
33
  end
32
34
 
35
+ # The environment of the caller of this environment's mixin or function.
36
+ # @return {Environment?}
37
+ def caller
38
+ @caller || (@parent && @parent.caller)
39
+ end
40
+
41
+ # The content passed to this environmnet. This is naturally only set
42
+ # for mixin body environments with content passed in.
43
+ # @return {Environment?}
44
+ def content
45
+ @content || (@parent && @parent.content)
46
+ end
47
+
33
48
  # The options hash.
34
49
  # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
35
50
  #
@@ -93,6 +108,17 @@ module Sass
93
108
  @mixins_in_use ||= @parent.mixins_in_use
94
109
  end
95
110
 
111
+ def stack_trace
112
+ trace = []
113
+ stack.reverse.each_with_index do |entry, i|
114
+ msg = "#{i == 0 ? "on" : "from"} line #{entry[:line]}"
115
+ msg << " of #{entry[:filename] || "an unknown file"}"
116
+ msg << ", in `#{entry[:mixin]}'" if entry[:mixin]
117
+ trace << msg
118
+ end
119
+ trace
120
+ end
121
+
96
122
  private
97
123
 
98
124
  def parent_options
@@ -229,6 +229,10 @@ END
229
229
  'Only meaningful for --watch and --update.') do
230
230
  @options[:stop_on_error] = true
231
231
  end
232
+ opts.on('-f', '--force', 'Recompile all Sass files, even if the CSS file is newer.',
233
+ 'Only meaningful for --update.') do
234
+ @options[:force] = true
235
+ end
232
236
  opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
233
237
  require 'stringio'
234
238
  @options[:check_syntax] = true
@@ -238,6 +242,10 @@ END
238
242
  'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
239
243
  @options[:for_engine][:style] = name.to_sym
240
244
  end
245
+ opts.on('--precision NUMBER_OF_DIGITS', Integer,
246
+ 'How many digits of precision to use when outputting decimal numbers. Defaults to 3.') do |precision|
247
+ ::Sass::Script::Number.precision = precision
248
+ end
241
249
  opts.on('-q', '--quiet', 'Silence warnings and status messages during compilation.') do
242
250
  @options[:for_engine][:quiet] = true
243
251
  end
@@ -350,6 +358,11 @@ END
350
358
  ::Sass::Plugin.options.merge! @options[:for_engine]
351
359
  ::Sass::Plugin.options[:unix_newlines] = @options[:unix_newlines]
352
360
 
361
+ if @options[:force]
362
+ raise "The --force flag may only be used with --update." unless @options[:update]
363
+ ::Sass::Plugin.options[:always_update] = true
364
+ end
365
+
353
366
  raise <<MSG if @args.empty?
354
367
  What files should I watch? Did you mean something like:
355
368
  #{@default_syntax} --watch input.#{@default_syntax}:output.css
@@ -72,7 +72,8 @@ module Sass
72
72
  # If no such files exist, it should return nil.
73
73
  #
74
74
  # The {Sass::Engine} to be returned should be passed `options`,
75
- # with a few modifications. `:filename` and `:syntax` should be set appropriately,
75
+ # with a few modifications. `:syntax` should be set appropriately,
76
+ # `:filename` should be set to `uri`,
76
77
  # and `:importer` should be set to this importer.
77
78
  #
78
79
  # @param uri [String] The URI to import.
@@ -57,6 +57,14 @@ module Sass
57
57
  @args + @keywords.values
58
58
  end
59
59
 
60
+ # @see Node#deep_copy
61
+ def deep_copy
62
+ node = dup
63
+ node.instance_variable_set('@args', args.map {|a| a.deep_copy})
64
+ node.instance_variable_set('@keywords', Hash[keywords.map {|k, v| [k, v.deep_copy]}])
65
+ node
66
+ end
67
+
60
68
  protected
61
69
 
62
70
  # Evaluates the function call.
@@ -50,6 +50,15 @@ module Sass::Script
50
50
  [@before, @mid, @after].compact
51
51
  end
52
52
 
53
+ # @see Node#deep_copy
54
+ def deep_copy
55
+ node = dup
56
+ node.instance_variable_set('@before', @before.deep_copy) if @before
57
+ node.instance_variable_set('@mid', @mid.deep_copy)
58
+ node.instance_variable_set('@after', @after.deep_copy) if @after
59
+ node
60
+ end
61
+
53
62
  protected
54
63
 
55
64
  # Evaluates the interpolation.
@@ -24,6 +24,13 @@ 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
+
27
34
  # @see Node#eq
28
35
  def eq(other)
29
36
  Sass::Script::Bool.new(
@@ -33,6 +33,11 @@ module Sass::Script
33
33
  []
34
34
  end
35
35
 
36
+ # @see Node#deep_copy
37
+ def deep_copy
38
+ dup
39
+ end
40
+
36
41
  # Returns the options hash for this node.
37
42
  #
38
43
  # @return [{Symbol => Object}]
@@ -57,6 +57,14 @@ 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
+
60
68
  protected
61
69
 
62
70
  # Converts underscores to dashes if the :dasherize option is set.
@@ -35,11 +35,34 @@ module Sass::Script
35
35
  # @return [Boolean, nil]
36
36
  attr_accessor :original
37
37
 
38
- # The precision with which numbers will be printed to CSS files.
39
- # For example, if this is `1000.0`,
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`,
40
44
  # `3.1415926` will be printed as `3.142`.
41
- # @api public
42
- PRECISION = 1000.0
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
43
66
 
44
67
  # Used so we don't allocate two new arrays for each new number.
45
68
  NO_UNITS = []
@@ -337,7 +360,7 @@ module Sass::Script
337
360
  elsif num % 1 == 0.0
338
361
  num.to_i
339
362
  else
340
- (num * PRECISION).round / PRECISION
363
+ (num * self.precision_factor).round / self.precision_factor
341
364
  end
342
365
  end
343
366
 
@@ -55,6 +55,14 @@ 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
+
58
66
  protected
59
67
 
60
68
  # Evaluates the operation.
@@ -60,6 +60,15 @@ 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
+
63
72
  protected
64
73
 
65
74
  # Evaluates the interpolation.
@@ -38,6 +38,13 @@ 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
+
41
48
  protected
42
49
 
43
50
  # Evaluates the operation.
@@ -34,6 +34,11 @@ module Sass
34
34
  []
35
35
  end
36
36
 
37
+ # @see Node#deep_copy
38
+ def deep_copy
39
+ dup
40
+ end
41
+
37
42
  protected
38
43
 
39
44
  # Evaluates the variable.
@@ -9,10 +9,12 @@ module Sass
9
9
  # @param str [String, StringScanner] The source document to parse.
10
10
  # Note that `Parser` *won't* raise a nice error message if this isn't properly parsed;
11
11
  # for that, you should use the higher-level {Sass::Engine} or {Sass::CSS}.
12
+ # @param filename [String] The name of the file being parsed. Used for warnings.
12
13
  # @param line [Fixnum] The line on which the source string appeared,
13
- # if it's part of another document
14
- def initialize(str, line = 1)
14
+ # if it's part of another document.
15
+ def initialize(str, filename, line = 1)
15
16
  @template = str
17
+ @filename = filename
16
18
  @line = line
17
19
  @strs = []
18
20
  end
@@ -99,7 +101,7 @@ module Sass
99
101
  end
100
102
 
101
103
  DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
102
- :each, :while, :if, :else, :extend, :import, :media, :charset]
104
+ :each, :while, :if, :else, :extend, :import, :media, :charset, :content]
103
105
 
104
106
  def directive
105
107
  return unless tok(/@/)
@@ -141,7 +143,18 @@ module Sass
141
143
  name = tok! IDENT
142
144
  args, keywords = sass_script(:parse_mixin_include_arglist)
143
145
  ss
144
- node(Sass::Tree::MixinNode.new(name, args, keywords))
146
+ include_node = node(Sass::Tree::MixinNode.new(name, args, keywords))
147
+ if tok?(/\{/)
148
+ include_node.has_children = true
149
+ block(include_node, :directive)
150
+ else
151
+ include_node
152
+ end
153
+ end
154
+
155
+ def content_directive
156
+ ss
157
+ node(Sass::Tree::ContentNode.new)
145
158
  end
146
159
 
147
160
  def function_directive
@@ -487,20 +500,20 @@ module Sass
487
500
  res = [e]
488
501
 
489
502
  # The tok(/\*/) allows the "E*" hack
490
- while v = element_name || id_selector || class_selector ||
491
- attrib || negation || pseudo || interpolation_selector ||
492
- (tok(/\*/) && Selector::Universal.new(nil))
503
+ while v = id_selector || class_selector || attrib || negation || pseudo ||
504
+ interpolation_selector || (tok(/\*/) && Selector::Universal.new(nil))
493
505
  res << v
494
506
  end
495
507
 
496
- if tok?(/&/)
508
+ pos = @scanner.pos
509
+ line = @line
510
+ if sel = str? {simple_selector_sequence}
511
+ @scanner.pos = pos
512
+ @line = line
497
513
  begin
498
514
  expected('"{"')
499
515
  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.
503
- MESSAGE
516
+ e.message << "\n\n\"#{sel}\" may only be used at the beginning of a selector."
504
517
  raise e
505
518
  end
506
519
  end
@@ -613,7 +626,7 @@ MESSAGE
613
626
  end
614
627
 
615
628
  def negation
616
- return unless name = tok(NOT) || tok(MOZ_ANY)
629
+ return unless name = tok(NOT) || tok(ANY)
617
630
  ss
618
631
  @expected = "selector"
619
632
  sel = selector_comma_sequence