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