lib/sass/script/parser.rb in sass-3.2.0.alpha.278 vs lib/sass/script/parser.rb in sass-3.2.0.alpha.291

- old
+ new

@@ -72,61 +72,66 @@ raise e end # Parses the argument list for a mixin include. # - # @return [(Array<Script::Node>, {String => Script::Note})] - # The root nodes of the arguments. - # Keyword arguments are in a hash from names to values. + # @return [(Array<Script::Node>, {String => Script::Node}, Script::Node)] + # The root nodes of the positional arguments, keyword arguments, and + # splat argument. Keyword arguments are in a hash from names to values. # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript def parse_mixin_include_arglist args, keywords = [], {} if try_tok(:lparen) - args, keywords = mixin_arglist || [[], {}] + args, keywords, splat = mixin_arglist || [[], {}] assert_tok(:rparen) end assert_done args.each {|a| a.options = @options} keywords.each {|k, v| v.options = @options} - return args, keywords + splat.options = @options if splat + return args, keywords, splat rescue Sass::SyntaxError => e e.modify_backtrace :line => @lexer.line, :filename => @options[:filename] raise e end # Parses the argument list for a mixin definition. # - # @return [Array<Script::Node>] The root nodes of the arguments. + # @return [(Array<Script::Node>, Script::Node)] + # The root nodes of the arguments, and the splat argument. # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript def parse_mixin_definition_arglist - args = defn_arglist!(false) + args, splat = defn_arglist!(false) assert_done args.each do |k, v| k.options = @options v.options = @options if v end - args + splat.options = @options if splat + return args, splat rescue Sass::SyntaxError => e e.modify_backtrace :line => @lexer.line, :filename => @options[:filename] raise e end # Parses the argument list for a function definition. # - # @return [Array<Script::Node>] The root nodes of the arguments. + # @return [(Array<Script::Node>, Script::Node)] + # The root nodes of the arguments, and the splat argument. # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript def parse_function_definition_arglist - args = defn_arglist!(true) + args, splat = defn_arglist!(true) assert_done args.each do |k, v| k.options = @options v.options = @options if v end - args + splat.options = @options if splat + return args, splat rescue Sass::SyntaxError => e e.modify_backtrace :line => @lexer.line, :filename => @options[:filename] raise e end @@ -322,41 +327,45 @@ node(Script::String.new(name.value, :identifier)) end def funcall return raw unless tok = try_tok(:funcall) - args, keywords = fn_arglist || [[], {}] + args, keywords, splat = fn_arglist || [[], {}] assert_tok(:rparen) - node(Script::Funcall.new(tok.value, args, keywords)) + node(Script::Funcall.new(tok.value, args, keywords, splat)) end def defn_arglist!(must_have_parens) if must_have_parens assert_tok(:lparen) else - return [] unless try_tok(:lparen) + return [], nil unless try_tok(:lparen) end - return [] if try_tok(:rparen) + return [], nil if try_tok(:rparen) res = [] + splat = nil must_have_default = false loop do line = @lexer.line offset = @lexer.offset + 1 c = assert_tok(:const) var = Script::Variable.new(c.value) - if tok = try_tok(:colon) + if try_tok(:colon) val = assert_expr(:space) must_have_default = true elsif must_have_default raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.") + elsif try_tok(:splat) + splat = var + break end res << [var, val] break unless try_tok(:comma) end assert_tok(:rparen) - res + return res, splat end def fn_arglist arglist(:fn_arglist, :equals) end @@ -374,35 +383,24 @@ keywords = {name.underscored_name => assert_expr(subexpr, EXPR_NAMES[type])} end unless try_tok(:comma) return [], keywords if keywords + return [], {}, e if try_tok(:splat) return [e], {} end - other_args, other_keywords = assert_expr(type) + other_args, other_keywords, splat = assert_expr(type) if keywords - if !other_args.empty? - raise SyntaxError.new("Positional arguments must come before keyword arguments") + if !other_args.empty? || splat + raise SyntaxError.new("Positional arguments must come before keyword arguments.") elsif other_keywords[name.underscored_name] raise SyntaxError.new("Keyword argument \"#{name.to_sass}\" passed more than once") end - return other_args, keywords.merge(other_keywords) + return other_args, keywords.merge(other_keywords), splat else - return [e, *other_args], other_keywords + return [e, *other_args], other_keywords, splat end - end - - def keyword_arglist - return unless var = try_tok(:const) - unless try_tok(:colon) - return_tok! - return - end - name = var[1] - value = interpolation - return {name => value} unless try_tok(:comma) - {name => value}.merge(assert_expr(:keyword_arglist)) end def raw return special_fun unless tok = try_tok(:raw) node(Script::String.new(tok.value))