From 666ff97e49e19a8eb3ba10ab4ab66f50fba3f80d Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 19 Jul 2016 22:14:49 +0200 Subject: [PATCH 1/2] Fix parent selector evaluation for if function For some reason arguments for if functions are not evaluated before calling the function. The function then creates a new expand/eval context, which will not inherit the correct selector stack. Fixes https://github.com/sass/libsass/issues/2124 --- src/eval.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/eval.cpp b/src/eval.cpp index 70a5a73dbc..c43b071445 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -801,6 +801,14 @@ namespace Sass { } if (full_name != "if[f]") { args = static_cast(args->perform(this)); + } else { + // make sure parent selectors are evaluated + for (size_t i = 0; i < args->length(); ++i) { + Argument* arg = args->at(i); + if (arg && dynamic_cast(arg->value())) { + (*args)[i]->value((*args)[i]->value()->perform(this)); + } + } } Definition* def = static_cast((*env)[full_name]); From 2f42bd585f6e508d7747836ec2679a400c07143c Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 19 Jul 2016 23:55:53 +0200 Subject: [PATCH 2/2] Pass selector stack when calling functions Fixes https://github.com/sass/libsass/issues/2116 --- src/ast.hpp | 2 +- src/eval.cpp | 10 +--------- src/expand.cpp | 5 +++-- src/expand.hpp | 2 +- src/functions.cpp | 4 ++-- src/functions.hpp | 4 ++-- 6 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/ast.hpp b/src/ast.hpp index 9ffca4a43f..0005f8a1f5 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -775,7 +775,7 @@ namespace Sass { struct Backtrace; typedef Environment Env; typedef const char* Signature; - typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*); + typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*, std::vector); typedef const char* Signature; class Definition : public Has_Block { public: diff --git a/src/eval.cpp b/src/eval.cpp index c43b071445..60f3410730 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -801,14 +801,6 @@ namespace Sass { } if (full_name != "if[f]") { args = static_cast(args->perform(this)); - } else { - // make sure parent selectors are evaluated - for (size_t i = 0; i < args->length(); ++i) { - Argument* arg = args->at(i); - if (arg && dynamic_cast(arg->value())) { - (*args)[i]->value((*args)[i]->value()->perform(this)); - } - } } Definition* def = static_cast((*env)[full_name]); @@ -837,7 +829,7 @@ namespace Sass { exp.backtrace_stack.push_back(&here); // eval the body if user-defined or special, invoke underlying CPP function if native if (body && !Prelexer::re_special_fun(name.c_str())) { result = body->perform(this); } - else if (func) { result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace()); } + else if (func) { result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace(), exp.selector_stack); } if (!result) error(std::string("Function ") + c->name() + " did not return a value", c->pstate()); exp.backtrace_stack.pop_back(); } diff --git a/src/expand.cpp b/src/expand.cpp index ab8a85f712..7b8fba9fbc 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -11,7 +11,7 @@ namespace Sass { - Expand::Expand(Context& ctx, Env* env, Backtrace* bt) + Expand::Expand(Context& ctx, Env* env, Backtrace* bt, std::vector* stack) : ctx(ctx), eval(Eval(*this)), env_stack(std::vector()), @@ -31,7 +31,8 @@ namespace Sass { call_stack.push_back(0); // import_stack.push_back(0); property_stack.push_back(0); - selector_stack.push_back(0); + if (stack == NULL) { selector_stack.push_back(0); } + else { selector_stack.insert(selector_stack.end(), stack->begin(), stack->end()); } media_block_stack.push_back(0); backtrace_stack.push_back(0); backtrace_stack.push_back(bt); diff --git a/src/expand.hpp b/src/expand.hpp index 6f2a6113ea..571fac326a 100644 --- a/src/expand.hpp +++ b/src/expand.hpp @@ -45,7 +45,7 @@ namespace Sass { void expand_selector_list(Selector*, CommaSequence_Selector* extender); public: - Expand(Context&, Env*, Backtrace*); + Expand(Context&, Env*, Backtrace*, std::vector* stack = NULL); ~Expand() { } Statement* operator()(Block*); diff --git a/src/functions.cpp b/src/functions.cpp index a203b6c77f..3b1c45678a 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -1637,7 +1637,7 @@ namespace Sass { } } Function_Call* func = SASS_MEMORY_NEW(ctx.mem, Function_Call, pstate, name, args); - Expand expand(ctx, &d_env, backtrace); + Expand expand(ctx, &d_env, backtrace, &selector_stack); return func->perform(&expand.eval); } @@ -1655,7 +1655,7 @@ namespace Sass { // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); } BUILT_IN(sass_if) { - Expand expand(ctx, &d_env, backtrace); + Expand expand(ctx, &d_env, backtrace, &selector_stack); bool is_true = !ARG("$condition", Expression)->perform(&expand.eval)->is_false(); Expression* res = ARG(is_true ? "$if-true" : "$if-false", Expression); res = res->perform(&expand.eval); diff --git a/src/functions.hpp b/src/functions.hpp index 66c6b7bca0..4279a5b17e 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -7,7 +7,7 @@ #include "sass/functions.h" #define BUILT_IN(name) Expression*\ -name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtrace* backtrace) +name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtrace* backtrace, std::vector selector_stack) namespace Sass { class Context; @@ -17,7 +17,7 @@ namespace Sass { class Definition; typedef Environment Env; typedef const char* Signature; - typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*); + typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*, std::vector); Definition* make_native_function(Signature, Native_Function, Context& ctx); Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx);