vendor/sass/lib/sass/scss/parser.rb in haml-3.1.0 vs vendor/sass/lib/sass/scss/parser.rb in haml-3.1.1
- old
+ new
@@ -96,12 +96,12 @@
comment = Sass::Tree::CommentNode.new(pre_str + text, single_line)
comment.line = @line - text.count("\n")
node << comment
end
- DIRECTIVES = Set[:mixin, :include, :debug, :warn, :for, :each, :while, :if,
- :else, :extend, :import, :media, :charset]
+ DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
+ :each, :while, :if, :else, :extend, :import, :media, :charset]
def directive
return unless tok(/@/)
name = tok!(IDENT)
ss
@@ -142,10 +142,21 @@
args, keywords = sass_script(:parse_mixin_include_arglist)
ss
node(Sass::Tree::MixinNode.new(name, args, keywords))
end
+ def function_directive
+ name = tok! IDENT
+ args = sass_script(:parse_function_definition_arglist)
+ ss
+ block(node(Sass::Tree::FunctionNode.new(name, args)), :function)
+ end
+
+ def return_directive
+ node(Sass::Tree::ReturnNode.new(sass_script(:parse)))
+ end
+
def debug_directive
node(Sass::Tree::DebugNode.new(sass_script(:parse)))
end
def warn_directive
@@ -223,12 +234,11 @@
node
end
end
def else_directive
- raise Sass::SyntaxError.new(
- "Invalid CSS: @else must come after @if", :line => @line)
+ err("Invalid CSS: @else must come after @if")
end
def extend_directive
node(Sass::Tree::ExtendNode.new(expr!(:selector)))
end
@@ -363,10 +373,11 @@
end
node
end
def block_child(context)
+ return variable || directive if context == :function
return variable || directive || ruleset if context == :stylesheet
variable || directive || declaration_or_ruleset
end
def has_children?(child_or_array)
@@ -389,33 +400,24 @@
# We could eke some more efficiency out of this
# by handling some easy cases (first token isn't an identifier,
# no colon after the identifier, whitespace after the colon),
# but I'm not sure the gains would be worth the added complexity.
def declaration_or_ruleset
- pos = @scanner.pos
- line = @line
old_use_property_exception, @use_property_exception =
@use_property_exception, false
- begin
+ decl_err = catch_error do
decl = declaration
unless decl && decl.has_children
# We want an exception if it's not there,
# but we don't want to consume if it is
tok!(/[;}]/) unless tok?(/[;}]/)
end
return decl
- rescue Sass::SyntaxError => decl_err
end
- @line = line
- @scanner.pos = pos
-
- begin
- return ruleset
- rescue Sass::SyntaxError => ruleset_err
- raise @use_property_exception ? decl_err : ruleset_err
- end
+ ruleset_err = catch_error {return ruleset}
+ rethrow(@use_property_exception ? decl_err : ruleset_err)
ensure
@use_property_exception = old_use_property_exception
end
def selector_sequence
@@ -634,13 +636,15 @@
ss
tok!(/:/)
space, value = value!
ss
+ important = tok(IMPORTANT)
+ ss
require_block = tok?(/\{/)
- node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new))
+ node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, !!important, :new))
return node unless require_block
nested_properties! node, space
end
@@ -670,11 +674,11 @@
# expression, space, value
return expression, space, expression || [""]
end
def nested_properties!(node, space)
- raise Sass::SyntaxError.new(<<MESSAGE, :line => @line) unless space
+ err(<<MESSAGE) unless space
Invalid CSS: a space is required between a property and its definition
when it has other properties nested beneath it.
MESSAGE
@use_property_exception = true
@@ -784,10 +788,13 @@
parser = self.class.sass_script_parser.new(@scanner, @line,
@scanner.pos - (@scanner.string[0...@scanner.pos].rindex("\n") || 0))
result = parser.send(*args)
@line = parser.line
result
+ rescue Sass::SyntaxError => e
+ throw(:_sass_parser_error, true) if @throw_error
+ raise e
end
def merge(arr)
arr && Sass::Util.merge_adjacent_strings([arr].flatten)
end
@@ -830,10 +837,43 @@
expected(name)
end
def expected(name)
+ throw(:_sass_parser_error, true) if @throw_error
self.class.expected(@scanner, @expected || name, @line)
+ end
+
+ def err(msg)
+ throw(:_sass_parser_error, true) if @throw_error
+ raise Sass::SyntaxError.new(msg, :line => @line)
+ end
+
+ def catch_error(&block)
+ old_throw_error, @throw_error = @throw_error, true
+ pos = @scanner.pos
+ line = @line
+ expected = @expected
+ if catch(:_sass_parser_error, &block)
+ @scanner.pos = pos
+ @line = line
+ @expected = expected
+ {:pos => pos, :line => line, :expected => @expected, :block => block}
+ end
+ ensure
+ @throw_error = old_throw_error
+ end
+
+ def rethrow(err)
+ if @throw_err
+ throw :_sass_parser_error, err
+ else
+ @scanner = StringScanner.new(@scanner.string)
+ @scanner.pos = err[:pos]
+ @line = err[:line]
+ @expected = err[:expected]
+ err[:block].call
+ end
end
# @private
def self.expected(scanner, expected, line)
pos = scanner.pos