From 167f2a8b22e043ba1d36f28b4ee23a2fb41d3934 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sun, 10 May 2015 15:02:08 +0200 Subject: [PATCH] Improve keyword handling in arglists Fixes https://github.com/sass/libsass/issues/1192 --- ast.cpp | 12 ++++++++++++ ast.hpp | 1 + bind.cpp | 8 +++++++- debugger.hpp | 4 +++- functions.cpp | 14 +++++++------- inspect.cpp | 2 +- 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/ast.cpp b/ast.cpp index dba810f7e5..1477240a5e 100644 --- a/ast.cpp +++ b/ast.cpp @@ -856,6 +856,18 @@ namespace Sass { return operator==(&rhs); } + size_t List::size() const { + if (!is_arglist_) return length(); + // arglist expects a list of arguments + // so we need to break before keywords + for (size_t i = 0, L = length(); i < L; ++i) { + if (Argument* arg = dynamic_cast((*this)[i])) { + if (!arg->name().empty()) return i; + } + } + return length(); + } + Expression* Hashed::at(Expression* k) const { if (elements_.count(k)) diff --git a/ast.hpp b/ast.hpp index bdd5d183a3..8580fa6d77 100644 --- a/ast.hpp +++ b/ast.hpp @@ -757,6 +757,7 @@ namespace Sass { bool is_invisible() { return !length(); } Expression* value_at_index(size_t i); + virtual size_t size() const; virtual bool operator==(Expression& rhs) const; virtual bool operator==(Expression* rhs) const; diff --git a/bind.cpp b/bind.cpp index dda9ff384f..207681fa65 100644 --- a/bind.cpp +++ b/bind.cpp @@ -93,6 +93,7 @@ namespace Sass { (*arglist) << new (ctx.mem) Argument(key->pstate(), argmap->at(key), name, + false, false); } @@ -111,6 +112,7 @@ namespace Sass { (*arglist) << new (ctx.mem) Argument(a->pstate(), a->value(), a->name(), + false, false); // check if we have rest argument if (a->is_rest_argument()) { @@ -144,7 +146,11 @@ namespace Sass { a = static_cast((*arglist)[0]); } else { Expression* a_to_convert = (*arglist)[0]; - a = new (ctx.mem) Argument(a_to_convert->pstate(), a_to_convert, "", false); + a = new (ctx.mem) Argument(a_to_convert->pstate(), + a_to_convert, + "", + false, + false); } arglist->elements().erase(arglist->elements().begin()); if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) { diff --git a/debugger.hpp b/debugger.hpp index aaaa914f8f..f95fdb4196 100644 --- a/debugger.hpp +++ b/debugger.hpp @@ -356,7 +356,9 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast(node)) { Mixin_Call* block = dynamic_cast(node); - cerr << ind << "Mixin_Call " << block << " " << block->tabs() << endl; + cerr << ind << "Mixin_Call " << block << " " << block->tabs(); + cerr << " [" << block->name() << "]" << endl; + debug_ast(block->arguments(), ind + " args: "); if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast(node)) { Ruleset* ruleset = dynamic_cast(node); diff --git a/functions.cpp b/functions.cpp index fd6165c653..204c7dfa56 100644 --- a/functions.cpp +++ b/functions.cpp @@ -1107,7 +1107,7 @@ namespace Sass { List* list = dynamic_cast(env["$list"]); return new (ctx.mem) Number(pstate, - list ? list->length() : 1); + list ? list->size() : 1); } Signature nth_sig = "nth($list, $n)"; @@ -1356,13 +1356,10 @@ namespace Sass { { List* arglist = new (ctx.mem) List(*ARG("$args", List)); Map* result = new (ctx.mem) Map(pstate, 1); - // The parser ensures the ordering of arguments so we can assert this - // isn't keyword argument list the first argument isn't a keyword argument - if (!(arglist->empty() || ((Argument*)(*arglist)[0])->is_keyword_argument())) return result; - for (size_t i = 0, L = arglist->length(); i < L; ++i) { + for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) { string name = string(((Argument*)(*arglist)[i])->name()); - string sanitized_name = string(name, 1); - *result << make_pair(new (ctx.mem) String_Constant(pstate, sanitized_name), + name = name.erase(0, 1); // sanitize name (remove dollar sign) + *result << make_pair(new (ctx.mem) String_Constant(pstate, name), ((Argument*)(*arglist)[i])->value()); } return result; @@ -1551,11 +1548,14 @@ namespace Sass { } else if (v->concrete_type() == Expression::STRING) { return v; } else { + bool parentheses = v->concrete_type() == Expression::MAP || + v->concrete_type() == Expression::LIST; Output_Style old_style; old_style = ctx.output_style; ctx.output_style = NESTED; To_String to_string(&ctx, false); string inspect = v->perform(&to_string); + if (inspect.empty() && parentheses) inspect = "()"; ctx.output_style = old_style; return new (ctx.mem) String_Constant(pstate, inspect); diff --git a/inspect.cpp b/inspect.cpp index c155137a5d..6127f47696 100644 --- a/inspect.cpp +++ b/inspect.cpp @@ -362,7 +362,7 @@ namespace Sass { if (list->separator() == List::SPACE) in_space_array = true; else if (list->separator() == List::COMMA) in_comma_array = true; - for (size_t i = 0, L = list->length(); i < L; ++i) { + for (size_t i = 0, L = list->size(); i < L; ++i) { Expression* list_item = (*list)[i]; if (list_item->is_invisible()) { continue;