From f982f832f58063739ed25b3a05cc36c8c0752bef Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Thu, 14 May 2015 15:03:58 +0200 Subject: [PATCH 1/9] Refactor contextualize into eval [WIP] --- Makefile | 2 - Makefile.am | 2 - ast.cpp | 40 ------- ast.hpp | 49 +++----- ast_def_macros.hpp | 24 ++++ ast_fwd_decl.hpp | 1 - bind.cpp | 6 +- context.cpp | 8 +- contextualize.cpp | 148 ------------------------ contextualize.hpp | 39 ------- contextualize_eval.cpp | 93 --------------- contextualize_eval.hpp | 35 ------ debugger.hpp | 9 +- environment.hpp | 2 + eval.cpp | 230 +++++++++++++++++++++++++++++++----- eval.hpp | 33 ++++-- expand.cpp | 256 +++++++++++++++++++++++------------------ expand.hpp | 23 ++-- extend.cpp | 1 - functions.cpp | 17 ++- inspect.cpp | 16 +-- inspect.hpp | 1 - listize.cpp | 4 +- listize.hpp | 2 +- node.cpp | 2 +- operation.hpp | 2 - parser.cpp | 4 +- win/libsass.filters | 6 - win/libsass.vcxproj | 4 - 29 files changed, 451 insertions(+), 608 deletions(-) diff --git a/Makefile b/Makefile index 5187e5744d..55fe41b01d 100644 --- a/Makefile +++ b/Makefile @@ -117,8 +117,6 @@ SOURCES = \ bind.cpp \ constants.cpp \ context.cpp \ - contextualize.cpp \ - contextualize_eval.cpp \ cssize.cpp \ listize.cpp \ error_handling.cpp \ diff --git a/Makefile.am b/Makefile.am index e59d2f8603..22822295a1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,8 +46,6 @@ libsass_la_SOURCES = \ bind.cpp bind.hpp \ constants.cpp constants.hpp \ context.cpp context.hpp \ - contextualize.cpp contextualize.hpp \ - contextualize_eval.cpp contextualize_eval.hpp \ error_handling.cpp error_handling.hpp \ eval.cpp eval.hpp \ expand.cpp expand.hpp \ diff --git a/ast.cpp b/ast.cpp index 7f7091e9fc..1f39c4360b 100644 --- a/ast.cpp +++ b/ast.cpp @@ -507,7 +507,6 @@ namespace Sass { void Selector_List::adjust_after_pushing(Complex_Selector* c) { if (c->has_reference()) has_reference(true); - if (c->has_placeholder()) has_placeholder(true); #ifdef DEBUG To_String to_string; @@ -559,45 +558,6 @@ namespace Sass { return false; } - /* not used anymore - remove? - Selector_Placeholder* Selector_List::find_placeholder() - { - if (has_placeholder()) { - for (size_t i = 0, L = length(); i < L; ++i) { - if ((*this)[i]->has_placeholder()) return (*this)[i]->find_placeholder(); - } - } - return 0; - }*/ - - /* not used anymore - remove? - Selector_Placeholder* Complex_Selector::find_placeholder() - { - if (has_placeholder()) { - if (head() && head()->has_placeholder()) return head()->find_placeholder(); - else if (tail() && tail()->has_placeholder()) return tail()->find_placeholder(); - } - return 0; - }*/ - - /* not used anymore - remove? - Selector_Placeholder* Compound_Selector::find_placeholder() - { - if (has_placeholder()) { - for (size_t i = 0, L = length(); i < L; ++i) { - if ((*this)[i]->has_placeholder()) return (*this)[i]->find_placeholder(); - } - // return this; - } - return 0; - }*/ - - /* not used anymore - remove? - Selector_Placeholder* Selector_Placeholder::find_placeholder() - { - return this; - }*/ - vector Compound_Selector::to_str_vec() { To_String to_string; diff --git a/ast.hpp b/ast.hpp index bbf70f8f98..af7506532c 100644 --- a/ast.hpp +++ b/ast.hpp @@ -1666,26 +1666,10 @@ namespace Sass { ////////////////////////////////////////////////////////////////////////////////////////// inline Expression* List::value_at_index(size_t i) { return is_arglist_ ? ((Argument*)(*this)[i])->value() : (*this)[i]; } - //////////// - // The Parent Selector Expression. - //////////// - class Parent_Selector : public Expression { - ADD_PROPERTY(Selector*, selector); - public: - Parent_Selector(ParserState pstate, Selector* r = 0) - : Expression(pstate), selector_(r) - { concrete_type(SELECTOR); } - virtual Selector* selector() { return selector_; } - string type() { return "selector"; } - static string type_name() { return "selector"; } - - ATTACH_OPERATIONS(); - }; - ///////////////////////////////////////// // Abstract base class for CSS selectors. ///////////////////////////////////////// - class Selector : public AST_Node { + class Selector : public Expression { ADD_PROPERTY(bool, has_reference); ADD_PROPERTY(bool, has_placeholder); // line break before list separator @@ -1699,14 +1683,14 @@ namespace Sass { ADD_PROPERTY(Media_Block*, media_block); public: Selector(ParserState pstate, bool r = false, bool h = false) - : AST_Node(pstate), + : Expression(pstate), has_reference_(r), has_placeholder_(h), has_line_feed_(false), has_line_break_(false), is_optional_(false), media_block_(0) - { } + { concrete_type(SELECTOR); } virtual ~Selector() = 0; // virtual Selector_Placeholder* find_placeholder(); virtual unsigned long specificity() { @@ -1748,20 +1732,26 @@ namespace Sass { }; inline Simple_Selector::~Simple_Selector() { } - ///////////////////////////////////// - // Parent references (i.e., the "&"). - ///////////////////////////////////// - class Selector_Reference : public Simple_Selector { - ADD_PROPERTY(Selector*, selector); + + ////////////////////////////////// + // The Parent Selector Expression. + ////////////////////////////////// + class Parent_Selector : public Simple_Selector { + // ADD_PROPERTY(Selector*, selector); public: - Selector_Reference(ParserState pstate, Selector* r = 0) - : Simple_Selector(pstate), selector_(r) + Parent_Selector(ParserState pstate, Selector* r = 0) + : Simple_Selector(pstate)// , selector_(r) { has_reference(true); } virtual unsigned long specificity() { - if (!selector()) return 0; - return selector()->specificity(); + return 0; + // if (!selector()) return 0; + // return selector()->specificity(); } + // virtual Selector* selector() { return selector_; } + string type() { return "selector"; } + static string type_name() { return "selector"; } + ATTACH_OPERATIONS(); }; @@ -1956,8 +1946,7 @@ namespace Sass { bool is_empty_reference() { return length() == 1 && - typeid(*(*this)[0]) == typeid(Selector_Reference) && - !static_cast((*this)[0])->selector(); + typeid(*(*this)[0]) == typeid(Parent_Selector); } vector to_str_vec(); // sometimes need to convert to a flat "by-value" data structure diff --git a/ast_def_macros.hpp b/ast_def_macros.hpp index b240d430e4..d0fb8e911e 100644 --- a/ast_def_macros.hpp +++ b/ast_def_macros.hpp @@ -1,6 +1,30 @@ #ifndef SASS_AST_DEF_MACROS_H #define SASS_AST_DEF_MACROS_H +template +class LocalOption { + private: + T* var; // pointer to original variable + T orig; // copy of the original option + public: + LocalOption(T& var) + { + this->var = &var; + this->orig = var; + } + LocalOption(T& var, T orig) + { + this->var = &var; + this->orig = var; + *(this->var) = orig; + } + ~LocalOption() { + *(this->var) = this->orig; + } +}; + +#define LOCAL_FLAG(name,opt) LocalOption flag_##name(name, opt) + #define ATTACH_OPERATIONS()\ virtual void perform(Operation* op) { (*op)(this); }\ virtual AST_Node* perform(Operation* op) { return (*op)(this); }\ diff --git a/ast_fwd_decl.hpp b/ast_fwd_decl.hpp index 7da1fa7012..d3a9114142 100644 --- a/ast_fwd_decl.hpp +++ b/ast_fwd_decl.hpp @@ -69,7 +69,6 @@ namespace Sass { // selectors class Selector; class Selector_Schema; - class Selector_Reference; class Selector_Placeholder; class Type_Selector; class Selector_Qualifier; diff --git a/bind.cpp b/bind.cpp index 207681fa65..3af0eb85f7 100644 --- a/bind.cpp +++ b/bind.cpp @@ -230,11 +230,11 @@ namespace Sass { // make sure to eval the default value in the env that we've been populating Env* old_env = eval->env; Backtrace* old_bt = eval->backtrace; - Contextualize* old_context = eval->contextualize; - Expression* dv = leftover->default_value()->perform(eval->with(env, eval->backtrace)); + Eval* snapshot = eval->snapshot(); + snapshot->env = env; + Expression* dv = leftover->default_value()->perform(snapshot); eval->env = old_env; eval->backtrace = old_bt; - eval->contextualize = old_context; // dv->perform(&to_string); env->local_frame()[leftover->name()] = dv; } diff --git a/context.cpp b/context.cpp index 5620764072..6e6cc7bab1 100644 --- a/context.cpp +++ b/context.cpp @@ -23,8 +23,6 @@ #include "output.hpp" #include "expand.hpp" #include "eval.hpp" -#include "contextualize.hpp" -#include "contextualize_eval.hpp" #include "cssize.hpp" #include "listize.hpp" #include "extend.hpp" @@ -333,11 +331,7 @@ namespace Sass { for (size_t i = 0, S = c_functions.size(); i < S; ++i) { register_c_function(*this, &tge, c_functions[i]); } - Contextualize contextualize(*this, &tge, &backtrace); - Listize listize(*this); - Eval eval(*this, &contextualize, &listize, &tge, &backtrace); - Contextualize_Eval contextualize_eval(*this, &eval, &tge, &backtrace); - Expand expand(*this, &eval, &contextualize_eval, &tge, &backtrace); + Expand expand(*this, &tge, &backtrace); Cssize cssize(*this, &tge, &backtrace); root = root->perform(&expand)->block(); root = root->perform(&cssize)->block(); diff --git a/contextualize.cpp b/contextualize.cpp index fca78c41cd..e69de29bb2 100644 --- a/contextualize.cpp +++ b/contextualize.cpp @@ -1,148 +0,0 @@ -#include "contextualize.hpp" -#include "ast.hpp" -#include "eval.hpp" -#include "backtrace.hpp" -#include "to_string.hpp" -#include "parser.hpp" - -namespace Sass { - - Contextualize::Contextualize(Context& ctx, Env* env, Backtrace* bt, Selector* placeholder, Selector* extender) - : ctx(ctx), env(env), backtrace(bt), parent(0), placeholder(placeholder), extender(extender) - { } - - Contextualize::~Contextualize() { } - - Selector* Contextualize::fallback_impl(AST_Node* n) - { return parent; } - - Contextualize* Contextualize::with(Selector* s, Env* e, Backtrace* bt, Selector* p, Selector* ex) - { - parent = s; - env = e; - backtrace = bt; - placeholder = p; - extender = ex; - return this; - } - - Selector* Contextualize::operator()(Selector_List* s) - { - Selector_List* p = static_cast(parent); - Selector_List* ss = 0; - if (p) { - ss = new (ctx.mem) Selector_List(s->pstate(), p->length() * s->length()); - if (s->length() == 0) { - Complex_Selector* comb = static_cast(parent->perform(this)); - if (parent->has_line_feed()) comb->has_line_feed(true); - if (comb) *ss << comb; - else cerr << "Warning: contextualize returned null" << endl; - } - for (size_t i = 0, L = p->length(); i < L; ++i) { - for (size_t j = 0, L = s->length(); j < L; ++j) { - parent = (*p)[i]; - Complex_Selector* comb = static_cast((*s)[j]->perform(this)); - if (parent->has_line_feed()) comb->has_line_feed(true); - if (comb) *ss << comb; - else cerr << "Warning: contextualize returned null" << endl; - } - } - } - else { - ss = new (ctx.mem) Selector_List(s->pstate(), s->length()); - for (size_t j = 0, L = s->length(); j < L; ++j) { - Complex_Selector* comb = static_cast((*s)[j]->perform(this)); - if (comb) *ss << comb; - } - } - return ss->length() ? ss : 0; - } - - Selector* Contextualize::operator()(Complex_Selector* s) - { - To_String to_string(&ctx); - Complex_Selector* ss = new (ctx.mem) Complex_Selector(*s); - // ss->last_block(s->last_block()); - // ss->media_block(s->media_block()); - Compound_Selector* new_head = 0; - Complex_Selector* new_tail = 0; - if (ss->head()) { - new_head = static_cast(s->head()->perform(this)); - ss->head(new_head); - } - if (ss->tail()) { - new_tail = static_cast(s->tail()->perform(this)); - // new_tail->last_block(s->last_block()); - // new_tail->media_block(s->media_block()); - ss->tail(new_tail); - } - if ((new_head && new_head->has_placeholder()) || (new_tail && new_tail->has_placeholder())) { - ss->has_placeholder(true); - } - else { - ss->has_placeholder(false); - } - if (!ss->head() && ss->combinator() == Complex_Selector::ANCESTOR_OF) { - return ss->tail(); - } - else { - return ss; - } - } - - Selector* Contextualize::operator()(Compound_Selector* s) - { - To_String to_string(&ctx); - if (placeholder && extender && s->perform(&to_string) == placeholder->perform(&to_string)) { - return extender; - } - Compound_Selector* ss = new (ctx.mem) Compound_Selector(s->pstate(), s->length()); - ss->last_block(s->last_block()); - ss->media_block(s->media_block()); - ss->has_line_break(s->has_line_break()); - for (size_t i = 0, L = s->length(); i < L; ++i) { - Simple_Selector* simp = static_cast((*s)[i]->perform(this)); - if (simp) *ss << simp; - } - return ss->length() ? ss : 0; - } - - Selector* Contextualize::operator()(Wrapped_Selector* s) - { - Selector* old_parent = parent; - parent = 0; - Wrapped_Selector* neg = new (ctx.mem) Wrapped_Selector(s->pstate(), - s->name(), - s->selector()->perform(this)); - parent = old_parent; - return neg; - } - - Selector* Contextualize::operator()(Pseudo_Selector* s) - { return s; } - - Selector* Contextualize::operator()(Selector_Qualifier* s) - { return s; } - - Selector* Contextualize::operator()(Type_Selector* s) - { return s; } - - Selector* Contextualize::operator()(Selector_Placeholder* p) - { - To_String to_string(&ctx); - if (placeholder && extender && p->perform(&to_string) == placeholder->perform(&to_string)) { - return extender; - } - else { - return p; - } - } - - Selector* Contextualize::operator()(Selector_Reference* s) - { - if (!parent) return 0; - Selector_Reference* ss = new (ctx.mem) Selector_Reference(*s); - ss->selector(parent); - return ss; - } -} diff --git a/contextualize.hpp b/contextualize.hpp index 7efccd1c08..1c647caadb 100644 --- a/contextualize.hpp +++ b/contextualize.hpp @@ -1,46 +1,7 @@ #ifndef SASS_CONTEXTUALIZE_H #define SASS_CONTEXTUALIZE_H -#include "context.hpp" -#include "operation.hpp" -#include "environment.hpp" -#include "ast_fwd_decl.hpp" - namespace Sass { - struct Backtrace; - - typedef Environment Env; - - class Contextualize : public Operation_CRTP { - - - public: - Context& ctx; - Env* env; - Backtrace* backtrace; - Selector* parent; - Selector* placeholder; - Selector* extender; - - Selector* fallback_impl(AST_Node* n); - Contextualize(Context&, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0); - virtual ~Contextualize(); - Contextualize* with(Selector*, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0); - using Operation::operator(); - - Selector* operator()(Selector_List*); - Selector* operator()(Complex_Selector*); - Selector* operator()(Compound_Selector*); - Selector* operator()(Wrapped_Selector*); - Selector* operator()(Pseudo_Selector*); - Selector* operator()(Selector_Qualifier*); - Selector* operator()(Type_Selector*); - Selector* operator()(Selector_Placeholder*); - Selector* operator()(Selector_Reference*); - - template - Selector* fallback(U x) { return fallback_impl(x); } - }; } #endif diff --git a/contextualize_eval.cpp b/contextualize_eval.cpp index ba2b25d1d5..e69de29bb2 100644 --- a/contextualize_eval.cpp +++ b/contextualize_eval.cpp @@ -1,93 +0,0 @@ -#include "contextualize_eval.hpp" -#include "ast.hpp" -#include "eval.hpp" -#include "backtrace.hpp" -#include "to_string.hpp" -#include "parser.hpp" - -namespace Sass { - - Contextualize_Eval::Contextualize_Eval(Context& ctx, Eval* eval, Env* env, Backtrace* bt) - : Contextualize(ctx, env, bt), eval(eval) - { } - - Contextualize_Eval::~Contextualize_Eval() { } - - Selector* Contextualize_Eval::fallback_impl(AST_Node* n) - { - return Contextualize::fallback_impl(n); - } - - Contextualize_Eval* Contextualize_Eval::with(Selector* s, Env* e, Backtrace* bt, Selector* p, Selector* ex) - { - Contextualize::with(s, e, bt, p, ex); - eval = eval->with(s, e, bt, p, ex); - return this; - } - - Selector* Contextualize_Eval::operator()(Selector_Schema* s) - { - To_String to_string; - string result_str(s->contents()->perform(eval)->perform(&to_string)); - result_str += '{'; // the parser looks for a brace to end the selector - Selector* result_sel = Parser::from_c_str(result_str.c_str(), ctx, s->pstate()).parse_selector_group(); - return result_sel->perform(this); - } - - Selector* Contextualize_Eval::operator()(Selector_List* s) - { - return Contextualize::operator ()(s); - } - - Selector* Contextualize_Eval::operator()(Complex_Selector* s) - { - return Contextualize::operator ()(s); - } - - Selector* Contextualize_Eval::operator()(Compound_Selector* s) - { - return Contextualize::operator ()(s); - } - - Selector* Contextualize_Eval::operator()(Wrapped_Selector* s) - { - return Contextualize::operator ()(s); - } - - Selector* Contextualize_Eval::operator()(Pseudo_Selector* s) - { - return Contextualize::operator ()(s); - } - - Selector* Contextualize_Eval::operator()(Attribute_Selector* s) - { - // the value might be interpolated; evaluate it - String* v = s->value(); - if (v && eval) { - Eval* eval_with = eval->with(parent, env, backtrace); - v = static_cast(v->perform(eval_with)); - } - To_String toString; - Attribute_Selector* ss = new (ctx.mem) Attribute_Selector(*s); - ss->value(v); - return ss; - } - - Selector* Contextualize_Eval::operator()(Selector_Qualifier* s) - { return Contextualize::operator ()(s); - } - - Selector* Contextualize_Eval::operator()(Type_Selector* s) - { return Contextualize::operator ()(s); - } - - Selector* Contextualize_Eval::operator()(Selector_Placeholder* p) - { - return Contextualize::operator ()(p); - } - - Selector* Contextualize_Eval::operator()(Selector_Reference* s) - { - return Contextualize::operator ()(s); - } -} diff --git a/contextualize_eval.hpp b/contextualize_eval.hpp index 738b4d606d..5ae747e42b 100644 --- a/contextualize_eval.hpp +++ b/contextualize_eval.hpp @@ -1,44 +1,9 @@ #ifndef SASS_CONTEXTUALIZE_EVAL_H #define SASS_CONTEXTUALIZE_EVAL_H -#include "eval.hpp" -#include "context.hpp" -#include "operation.hpp" -#include "environment.hpp" #include "ast_fwd_decl.hpp" namespace Sass { - struct Backtrace; - - typedef Environment Env; - - class Contextualize_Eval : public Contextualize { - - Eval* eval; - - Selector* fallback_impl(AST_Node* n); - - public: - Contextualize_Eval(Context&, Eval*, Env*, Backtrace*); - virtual ~Contextualize_Eval(); - Contextualize_Eval* with(Selector*, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0); - using Operation::operator(); - - Selector* operator()(Selector_Schema*); - Selector* operator()(Selector_List*); - Selector* operator()(Complex_Selector*); - Selector* operator()(Compound_Selector*); - Selector* operator()(Wrapped_Selector*); - Selector* operator()(Pseudo_Selector*); - Selector* operator()(Attribute_Selector*); - Selector* operator()(Selector_Qualifier*); - Selector* operator()(Type_Selector*); - Selector* operator()(Selector_Placeholder*); - Selector* operator()(Selector_Reference*); - - template - Selector* fallback(U x) { return fallback_impl(x); } - }; } #endif diff --git a/debugger.hpp b/debugger.hpp index 996e71bbfe..511ba8f6f3 100644 --- a/debugger.hpp +++ b/debugger.hpp @@ -65,7 +65,7 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) cerr << ind << "Selector_List " << selector; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [block:" << selector->last_block() << "]"; - cerr << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : ""); + // cerr << ((selector->last_block() && selector->last_block()->is_root()) ? " [root]" : ""); cerr << " [@media:" << selector->media_block() << "]"; cerr << (selector->is_optional() ? " [is_optional]": " -"); cerr << (selector->has_line_break() ? " [line-break]": " -"); @@ -83,7 +83,7 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) cerr << ind << "Parent_Selector " << selector; cerr << " (" << pstate_source_position(node) << ")"; cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl; - debug_ast(selector->selector(), ind + "->", env); +// debug_ast(selector->selector(), ind + "->", env); } else if (dynamic_cast(node)) { Complex_Selector* selector = dynamic_cast(node); @@ -164,11 +164,6 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) << (selector->has_line_feed() ? " [line-feed]": " -") << endl; - } else if (dynamic_cast(node)) { - Selector_Reference* selector = dynamic_cast(node); - cerr << ind << "Selector_Reference " << selector; - cerr << " (" << pstate_source_position(node) << ")"; - cerr << " @ref " << selector->selector() << endl; } else if (dynamic_cast(node)) { Simple_Selector* selector = dynamic_cast(node); cerr << ind << "Simple_Selector " << selector; diff --git a/environment.hpp b/environment.hpp index 60aa0f80cd..d8179633aa 100644 --- a/environment.hpp +++ b/environment.hpp @@ -24,6 +24,8 @@ namespace Sass { public: Memory_Manager mem; Environment() : local_frame_(map()), parent_(0) { } + Environment(Environment* env) : local_frame_(map()), parent_(env) { } + Environment(Environment& env) : local_frame_(map()), parent_(&env) { } // link parent to create a stack void link(Environment& env) { parent_ = &env; } diff --git a/eval.cpp b/eval.cpp index 18c98a3475..988b421f2a 100644 --- a/eval.cpp +++ b/eval.cpp @@ -17,6 +17,7 @@ #include "backtrace.hpp" #include "prelexer.hpp" #include "parser.hpp" +#include "expand.hpp" namespace Sass { using namespace std; @@ -32,23 +33,54 @@ namespace Sass { add, sub, mul, div, fmod }; - Eval::Eval(Context& ctx, Contextualize* contextualize, Listize* listize, Env* env, Backtrace* bt) - : ctx(ctx), contextualize(contextualize), listize(listize), env(env), backtrace(bt) { } + Eval::Eval(Eval* eval) + : ctx(eval->ctx), + listize(eval->listize), + env(eval->env), + exp(eval->exp), + backtrace(eval->backtrace) + { } + + Eval::Eval(Expand* exp, Context& ctx, Env* env, Backtrace* bt) + : + ctx(ctx), + listize(new (ctx.mem) Listize(ctx)), + env(env), + exp(exp), + backtrace(bt) + { } Eval::~Eval() { } - Eval* Eval::with(Env* e, Backtrace* bt) // for setting the env before eval'ing an expression + // for setting the env before eval'ing an expression + + Context& Eval::context() { - contextualize = contextualize->with(0, e, bt); - env = e; - backtrace = bt; - return this; + return ctx; + } + + Env* Eval::environment() + { + return exp ? exp->environment() : 0; } - Eval* Eval::with(Selector* c, Env* e, Backtrace* bt, Selector* p, Selector* ex) // for setting the env before eval'ing an expression + Selector* Eval::selector() { - contextualize = contextualize->with(c, e, bt, p, ex); - env = e; - backtrace = bt; + return exp ? exp->selector() : 0; + } + + Backtrace* Eval::stacktrace() + { + return exp ? exp->backtrace() : 0; + } + + + + // for setting the env before eval'ing an expression + // gets the env and other stuff from expander scope + Eval* Eval::snapshot() + { + this->env = environment(); + this->backtrace = stacktrace(); return this; } @@ -750,6 +782,9 @@ namespace Sass { else if (value->concrete_type() == Expression::NULL_VAL) { value = new (ctx.mem) Null(value->pstate()); } + else if (value->concrete_type() == Expression::SELECTOR) { + value = value->perform(this)->perform(listize); + } // cerr << "\ttype is now: " << typeid(*value).name() << endl << endl; return value; @@ -857,6 +892,12 @@ namespace Sass { string str = str_constant->value(); if (!str_constant->quote_mark()) str = unquote(str); return evacuate_escapes(str); + } else if (dynamic_cast(s)) { + To_String to_string(&ctx); + return evacuate_quotes(s->perform(listize)->perform(this)->perform(listize)->perform(this)->perform(&to_string)); + } else if (Selector_List* sel = dynamic_cast(s)) { + To_String to_string(&ctx); + return evacuate_quotes(sel->perform(listize)->perform(this)->perform(&to_string)); } else if (String_Schema* str_schema = dynamic_cast(s)) { string res = ""; for(auto i : str_schema->elements()) @@ -892,9 +933,6 @@ namespace Sass { } else if (Function_Call* var = dynamic_cast(s)) { Expression* ex = var->perform(this); return evacuate_quotes(interpolation(ex)); - } else if (Parent_Selector* var = dynamic_cast(s)) { - Expression* ex = var->perform(this); - return evacuate_quotes(interpolation(ex)); } else if (Unary_Expression* var = dynamic_cast(s)) { Expression* ex = var->perform(this); return evacuate_quotes(interpolation(ex)); @@ -912,10 +950,7 @@ namespace Sass { { string acc; for (size_t i = 0, L = s->length(); i < L; ++i) { - // if (String_Quoted* str_quoted = dynamic_cast((*s)[i])) { - // if (!str_quoted->is_delayed()) str_quoted->value(string_eval_escapes(str_quoted->value())); - // } - acc += interpolation((*s)[i]); + if ((*s)[i]) acc += interpolation((*s)[i]); } String_Quoted* str = new (ctx.mem) String_Quoted(s->pstate(), acc); if (!str->quote_mark()) { @@ -1055,19 +1090,6 @@ namespace Sass { return 0; } - Expression* Eval::operator()(Parent_Selector* p) - { - // no idea why both calls are needed - Selector* s = p->perform(contextualize); - if (!s) s = p->selector()->perform(contextualize); - // access to parent selector may return 0 - Selector_List* l = static_cast(s); - // some spec tests cause this (might be a valid case!) - // if (!s) { cerr << "Parent Selector eval error" << endl; } - if (!s) { l = new (ctx.mem) Selector_List(p->pstate()); } - return l->perform(listize); - } - inline Expression* Eval::fallback_impl(AST_Node* n) { return static_cast(n); @@ -1366,4 +1388,150 @@ namespace Sass { return e; } + + // these should return selectors + Expression* Eval::operator()(Selector_List* s) + { + + int LL = exp->selector_stack.size(); + Selector* parent = exp->selector_stack[LL - 1]; + Selector_List* p = static_cast(parent); + Selector_List* ss = 0; + if (p) { + ss = new (ctx.mem) Selector_List(s->pstate(), p->length() * s->length()); + if (s->length() == 0) { + exit (77); + Complex_Selector* comb = static_cast(parent->perform(this)); + if (parent->has_line_feed()) comb->has_line_feed(true); + if (comb) *ss << comb; + else cerr << "Warning: eval returned null" << endl; + } + // debug_ast(p, "p: "); + // debug_ast(s, "s: "); + for (size_t i = 0, L = p->length(); i < L; ++i) { + for (size_t j = 0, L = s->length(); j < L; ++j) { + parent = (*p)[i]->tail(); + exp->selector_stack.push_back(0); + exp->selector_stack.push_back((*p)[i]); + Complex_Selector* comb = static_cast((*s)[j]->perform(this)); + exp->selector_stack.pop_back(); + exp->selector_stack.pop_back(); + if ((*p)[i]->has_line_feed()) comb->has_line_feed(true); + if (comb) *ss << comb; + else cerr << "Warning: eval returned null" << endl; + } + } + } + else { + ss = new (ctx.mem) Selector_List(s->pstate()); + ss->last_block(s->last_block()); + ss->media_block(s->media_block()); + for (size_t j = 0, L = s->length(); j < L; ++j) { + Complex_Selector* comb = static_cast((*s)[j]->perform(this)); + if (comb) *ss << comb; + } + // debug_ast(ss); + } + return ss->length() ? ss : 0; + } + + Expression* Eval::operator()(Complex_Selector* s) + { + To_String to_string(&ctx); + Complex_Selector* ss = new (ctx.mem) Complex_Selector(*s); + ss->last_block(s->last_block()); + ss->media_block(s->media_block()); + Compound_Selector* new_head = 0; + Complex_Selector* new_tail = 0; + if (ss->head()) { + new_head = static_cast(s->head()->perform(this)); + ss->head(new_head); + } + if (ss->tail()) { + new_tail = static_cast(s->tail()->perform(this)); + new_tail->last_block(s->last_block()); + new_tail->media_block(s->media_block()); + ss->tail(new_tail); + } + if (!ss->head() && ss->combinator() == Complex_Selector::ANCESTOR_OF) { + return ss->tail(); + } + else { + return ss; + } + } + + Expression* Eval::operator()(Compound_Selector* s) + { + Compound_Selector* ss = new (ctx.mem) Compound_Selector(s->pstate(), s->length()); + ss->last_block(s->last_block()); + ss->media_block(s->media_block()); + ss->has_line_break(s->has_line_break()); + for (size_t i = 0, L = s->length(); i < L; ++i) { + Simple_Selector* simp = static_cast((*s)[i]->perform(this)); + if (simp) *ss << simp; + } + return ss->length() ? ss : 0; + } + + Expression* Eval::operator()(Attribute_Selector* s) + { + String* sel = s->value(); + if (sel) { sel = static_cast(sel->perform(this)); } + Attribute_Selector* ss = new (ctx.mem) Attribute_Selector(*s); + ss->value(sel); + return ss; + } + + Expression* Eval::operator()(Wrapped_Selector* s) + { + return s; + } + Expression* Eval::operator()(Pseudo_Selector* s) + { + return s; + } + Expression* Eval::operator()(Selector_Qualifier* s) + { + return s; + } + Expression* Eval::operator()(Type_Selector* s) + { + return s; + } + Expression* Eval::operator()(Selector_Placeholder* s) + { + return s; + } + Expression* Eval::operator()(Selector_Schema* s) + { + To_String to_string; + string result_str(s->contents()->perform(this)->perform(&to_string)); + result_str += '{'; // the parser looks for a brace to end the selector + Selector* result_sel = Parser::from_c_str(result_str.c_str(), ctx, s->pstate()).parse_selector_group(); + return result_sel->perform(this); + } + + Expression* Eval::operator()(Parent_Selector* p) + { + Selector* pr = exp->selector_stack.back(); + if (dynamic_cast(pr)) { + exp->selector_stack.pop_back(); + exp->selector_stack.push_back(0); + // I cannot listize here (would help) + auto rv = pr ? pr->perform(this)->perform(listize) : 0; + exp->selector_stack.pop_back(); + exp->selector_stack.push_back(pr); + return rv; + } else { + exp->selector_stack.pop_back(); + exp->selector_stack.push_back(0); + // I cannot listize here (would help) + auto rv = pr ? pr->perform(this) : 0; + exp->selector_stack.pop_back(); + exp->selector_stack.push_back(pr); + return rv; + } + } + } diff --git a/eval.hpp b/eval.hpp index 86e95eee83..17f3b6918b 100644 --- a/eval.hpp +++ b/eval.hpp @@ -7,17 +7,17 @@ #include "position.hpp" #include "operation.hpp" #include "environment.hpp" -#include "contextualize.hpp" #include "listize.hpp" #include "sass_values.h" + namespace Sass { using namespace std; typedef Environment Env; struct Backtrace; - class Contextualize; class Listize; + class Expand; class Eval : public Operation_CRTP { @@ -26,14 +26,20 @@ namespace Sass { Expression* fallback_impl(AST_Node* n); public: - Contextualize* contextualize; Listize* listize; Env* env; + Expand* exp; Backtrace* backtrace; - Eval(Context&, Contextualize*, Listize*, Env*, Backtrace*); + Eval(Eval* eval); + Eval(Expand* exp, Context&, Env*, Backtrace*); virtual ~Eval(); - Eval* with(Env* e, Backtrace* bt); // for setting the env before eval'ing an expression - Eval* with(Selector* c, Env* e, Backtrace* bt, Selector* placeholder = 0, Selector* extender = 0); // for setting the env before eval'ing an expression + + Env* environment(); + Context& context(); + Selector* selector(); + Backtrace* stacktrace(); + + Eval* snapshot(); // for setting the env before eval'ing an expression using Operation::operator(); // for evaluating function bodies @@ -69,7 +75,20 @@ namespace Sass { Expression* operator()(Argument*); Expression* operator()(Arguments*); Expression* operator()(Comment*); - Expression* operator()(Parent_Selector* p); + + // these should return selectors + Expression* operator()(Selector_List*); + Expression* operator()(Complex_Selector*); + Expression* operator()(Compound_Selector*); + Expression* operator()(Wrapped_Selector*); + Expression* operator()(Pseudo_Selector*); + Expression* operator()(Selector_Qualifier*); + Expression* operator()(Type_Selector*); + Expression* operator()(Selector_Placeholder*); + Expression* operator()(Selector_Schema*); + Expression* operator()(Parent_Selector*); + Expression* operator()(Attribute_Selector*); + template Expression* fallback(U x) { return fallback_impl(x); } diff --git a/expand.cpp b/expand.cpp index 5b18edd713..1651255401 100644 --- a/expand.cpp +++ b/expand.cpp @@ -4,62 +4,115 @@ #include "expand.hpp" #include "bind.hpp" #include "eval.hpp" -#include "contextualize_eval.hpp" #include "to_string.hpp" #include "backtrace.hpp" #include "context.hpp" #include "parser.hpp" +#include "debugger.hpp" namespace Sass { - Expand::Expand(Context& ctx, Eval* eval, Contextualize_Eval* contextualize_eval, Env* env, Backtrace* bt) + Expand::Expand(Context& ctx, Env* env, Backtrace* bt) : ctx(ctx), - eval(eval), - contextualize_eval(contextualize_eval), - env(env), + eval(Eval(this, ctx, env, bt)), + env_stack(vector()), block_stack(vector()), property_stack(vector()), selector_stack(vector()), - at_root_selector_stack(vector()), + backtrace_stack(vector()), in_at_root(false), - in_keyframes(false), - backtrace(bt) - { selector_stack.push_back(0); } + in_keyframes(false) + { + env_stack.push_back(0); + env_stack.push_back(env); + block_stack.push_back(0); + property_stack.push_back(0); + selector_stack.push_back(0); + backtrace_stack.push_back(0); + backtrace_stack.push_back(bt); + } + + + Context& Expand::context() + { + return ctx; + } + Env* Expand::environment() + { + if (env_stack.size()) + return env_stack.back(); + return 0; + } + + Selector* Expand::selector() + { + if (selector_stack.size()) + return selector_stack.back(); + return 0; + } + + Backtrace* Expand::backtrace() + { + if (backtrace_stack.size()) + return backtrace_stack.back(); + return 0; + } + + // blocks create new variable scopes Statement* Expand::operator()(Block* b) { - Env new_env; - new_env.link(*env); - env = &new_env; - Block* bb = new (ctx.mem) Block(b->pstate(), b->length(), b->is_root()); - block_stack.push_back(bb); - append_block(b); - block_stack.pop_back(); - env = env->parent(); + // create new local environment + // set the current env as parent + Env env(environment()); + // copy the block object (add items later) + Block* bb = new (ctx.mem) Block(b->pstate(), + b->length(), + b->is_root()); + // setup block and env stack + this->block_stack.push_back(bb); + this->env_stack.push_back(&env); + // operate on block + this->append_block(b); + // revert block and env stack + this->block_stack.pop_back(); + this->env_stack.pop_back(); + // return copy return bb; } + // process and add to last block on stack + inline void Expand::append_block(Block* b) + { + Block* current_block = block_stack.back(); + for (size_t i = 0, L = b->length(); i < L; ++i) { + Statement* ith = (*b)[i]->perform(this); + if (ith) *current_block << ith; + } + } + Statement* Expand::operator()(Ruleset* r) { - bool old_in_at_root = in_at_root; - in_at_root = false; + // automatically reset on exit + LOCAL_FLAG(in_at_root, false); if (in_keyframes) { - To_String to_string; Keyframe_Rule* k = new (ctx.mem) Keyframe_Rule(r->pstate(), r->block()->perform(this)->block()); - if (r->selector()) k->selector(r->selector()->perform(contextualize_eval->with(0, env, backtrace))); - in_at_root = old_in_at_root; - old_in_at_root = false; + if (r->selector()) { + selector_stack.push_back(0); + // Contextualize contextual(eval.snapshot()); + k->selector(static_cast(r->selector()->perform(eval.snapshot()))); + selector_stack.pop_back(); + } return k; } - - Contextualize_Eval* contextual = contextualize_eval->with(selector_stack.back(), env, backtrace); - // if (old_in_at_root && !r->selector()->has_reference()) - // contextual = contextualize_eval->with(selector_stack.back(), env, backtrace); - - Selector* sel_ctx = r->selector()->perform(contextual); + // debug_ast(r->selector()); + // Contextualize contextual(eval.snapshot()); + Selector* sel_ctx = static_cast(r->selector()->perform(eval.snapshot())); if (sel_ctx == 0) throw "Cannot expand null selector"; + // ToDo: Check if we can do this different + // At least only re-parse selector schemas Emitter emitter(&ctx); Inspect isp(emitter); sel_ctx->perform(&isp); @@ -67,7 +120,7 @@ namespace Sass { str += ";"; Parser p(ctx, r->pstate()); - p.block_stack.push_back(r->selector() ? r->selector()->last_block() : 0); + p.block_stack.push_back(block_stack.back()); p.last_media_block = r->selector() ? r->selector()->media_block() : 0; p.source = str.c_str(); p.position = str.c_str(); @@ -75,19 +128,6 @@ namespace Sass { Selector_List* sel_lst = p.parse_selector_group(); // sel_lst->pstate(isp.remap(sel_lst->pstate())); - for(size_t i = 0; i < sel_lst->length(); i++) { - - Complex_Selector* pIter = (*sel_lst)[i]; - while (pIter) { - Compound_Selector* pHead = pIter->head(); - // pIter->pstate(isp.remap(pIter->pstate())); - if (pHead) { - // pHead->pstate(isp.remap(pHead->pstate())); - // (*pHead)[0]->pstate(isp.remap((*pHead)[0]->pstate())); - } - pIter = pIter->tail(); - } - } sel_ctx = sel_lst; selector_stack.push_back(sel_ctx); @@ -97,8 +137,6 @@ namespace Sass { blk); rr->tabs(r->tabs()); selector_stack.pop_back(); - in_at_root = old_in_at_root; - old_in_at_root = false; return rr; } @@ -128,7 +166,7 @@ namespace Sass { // drop comments in propsets } else { - error("contents of namespaced properties must result in style declarations only", stm->pstate(), backtrace); + error("contents of namespaced properties must result in style declarations only", stm->pstate(), backtrace()); } } @@ -139,7 +177,7 @@ namespace Sass { Statement* Expand::operator()(Feature_Block* f) { - Expression* feature_queries = f->feature_queries()->perform(eval->with(env, backtrace)); + Expression* feature_queries = f->feature_queries()->perform(eval.snapshot()); Feature_Block* ff = new (ctx.mem) Feature_Block(f->pstate(), static_cast(feature_queries), f->block()->perform(this)->block()); @@ -150,7 +188,7 @@ namespace Sass { Statement* Expand::operator()(Media_Block* m) { To_String to_string(&ctx); - Expression* mq = m->media_queries()->perform(eval->with(env, backtrace)); + Expression* mq = m->media_queries()->perform(eval.snapshot()); mq = Parser::from_c_str(mq->perform(&to_string).c_str(), ctx, mq->pstate()).parse_media_queries(); Media_Block* mm = new (ctx.mem) Media_Block(m->pstate(), static_cast(mq), @@ -163,46 +201,45 @@ namespace Sass { Statement* Expand::operator()(At_Root_Block* a) { in_at_root = true; - at_root_selector_stack.push_back(0); Block* ab = a->block(); Expression* ae = a->expression(); - if (ae) ae = ae->perform(eval->with(env, backtrace)); + if (ae) ae = ae->perform(eval.snapshot()); else ae = new (ctx.mem) At_Root_Expression(a->pstate()); Block* bb = ab ? ab->perform(this)->block() : 0; At_Root_Block* aa = new (ctx.mem) At_Root_Block(a->pstate(), bb, static_cast(ae)); - at_root_selector_stack.pop_back(); in_at_root = false; return aa; } Statement* Expand::operator()(At_Rule* a) { - bool old_in_keyframes = in_keyframes; - in_keyframes = a->is_keyframes(); + LOCAL_FLAG(in_keyframes, a->is_keyframes()); Block* ab = a->block(); Selector* as = a->selector(); Expression* av = a->value(); - if (as) as = as->perform(contextualize_eval->with(0, env, backtrace)); - else if (av) av = av->perform(eval->with(env, backtrace)); + selector_stack.push_back(0); + // Contextualize contextual(eval.snapshot()); + if (as) as = static_cast(as->perform(eval.snapshot())); + else if (av) av = av->perform(eval.snapshot()); + selector_stack.pop_back(); Block* bb = ab ? ab->perform(this)->block() : 0; At_Rule* aa = new (ctx.mem) At_Rule(a->pstate(), a->keyword(), as, bb); if (av) aa->value(av); - in_keyframes = old_in_keyframes; return aa; } Statement* Expand::operator()(Declaration* d) { String* old_p = d->property(); - String* new_p = static_cast(old_p->perform(eval->with(env, backtrace))); - Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back(); - Expression* value = d->value()->perform(eval->with(p, env, backtrace)); - if (value->is_invisible() && !d->is_important()) return 0; + String* new_p = static_cast(old_p->perform(eval.snapshot())); + Expression* value = d->value()->perform(eval.snapshot()); + if (!value) debug_ast(d->value()); + if (!value || (value->is_invisible() && !d->is_important())) return 0; Declaration* decl = new (ctx.mem) Declaration(d->pstate(), new_p, value, @@ -213,22 +250,22 @@ namespace Sass { Statement* Expand::operator()(Assignment* a) { + Env* env = environment(); string var(a->variable()); - Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back(); if (a->is_global()) { if (a->is_default()) { if (env->has_global(var)) { Expression* e = dynamic_cast(env->get_global(var)); if (!e || e->concrete_type() == Expression::NULL_VAL) { - env->set_global(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_global(var, a->value()->perform(eval.snapshot())); } } else { - env->set_global(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_global(var, a->value()->perform(eval.snapshot())); } } else { - env->set_global(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_global(var, a->value()->perform(eval.snapshot())); } } else if (a->is_default()) { @@ -239,7 +276,7 @@ namespace Sass { if (AST_Node* node = cur->get_local(var)) { Expression* e = dynamic_cast(node); if (!e || e->concrete_type() == Expression::NULL_VAL) { - cur->set_local(var, a->value()->perform(eval->with(p, env, backtrace))); + cur->set_local(var, a->value()->perform(eval.snapshot())); } } else { @@ -255,19 +292,19 @@ namespace Sass { if (AST_Node* node = env->get_global(var)) { Expression* e = dynamic_cast(node); if (!e || e->concrete_type() == Expression::NULL_VAL) { - env->set_global(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_global(var, a->value()->perform(eval.snapshot())); } } } else if (env->is_lexical()) { - env->set_local(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_local(var, a->value()->perform(eval.snapshot())); } else { - env->set_local(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_local(var, a->value()->perform(eval.snapshot())); } } else { - env->set_lexical(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_lexical(var, a->value()->perform(eval.snapshot())); } return 0; } @@ -276,7 +313,7 @@ namespace Sass { { Import* result = new (ctx.mem) Import(imp->pstate()); for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) { - result->urls().push_back(imp->urls()[i]->perform(eval->with(env, backtrace))); + result->urls().push_back(imp->urls()[i]->perform(eval.snapshot())); } return result; } @@ -290,33 +327,33 @@ namespace Sass { Statement* Expand::operator()(Warning* w) { // eval handles this too, because warnings may occur in functions - w->perform(eval->with(env, backtrace)); + w->perform(eval.snapshot()); return 0; } Statement* Expand::operator()(Error* e) { // eval handles this too, because errors may occur in functions - e->perform(eval->with(env, backtrace)); + e->perform(eval.snapshot()); return 0; } Statement* Expand::operator()(Debug* d) { // eval handles this too, because warnings may occur in functions - d->perform(eval->with(env, backtrace)); + d->perform(eval.snapshot()); return 0; } Statement* Expand::operator()(Comment* c) { // TODO: eval the text, once we're parsing/storing it as a String_Schema - return new (ctx.mem) Comment(c->pstate(), static_cast(c->text()->perform(eval->with(env, backtrace))), c->is_important()); + return new (ctx.mem) Comment(c->pstate(), static_cast(c->text()->perform(eval.snapshot())), c->is_important()); } Statement* Expand::operator()(If* i) { - if (*i->predicate()->perform(eval->with(env, backtrace))) { + if (*i->predicate()->perform(eval.snapshot())) { append_block(i->consequent()); } else { @@ -331,13 +368,13 @@ namespace Sass { Statement* Expand::operator()(For* f) { string variable(f->variable()); - Expression* low = f->lower_bound()->perform(eval->with(env, backtrace)); + Expression* low = f->lower_bound()->perform(eval.snapshot()); if (low->concrete_type() != Expression::NUMBER) { - error("lower bound of `@for` directive must be numeric", low->pstate(), backtrace); + error("lower bound of `@for` directive must be numeric", low->pstate(), backtrace()); } - Expression* high = f->upper_bound()->perform(eval->with(env, backtrace)); + Expression* high = f->upper_bound()->perform(eval.snapshot()); if (high->concrete_type() != Expression::NUMBER) { - error("upper bound of `@for` directive must be numeric", high->pstate(), backtrace); + error("upper bound of `@for` directive must be numeric", high->pstate(), backtrace()); } Number* sass_start = static_cast(low); Number* sass_end = static_cast(high); @@ -346,11 +383,12 @@ namespace Sass { stringstream msg; msg << "Incompatible units: '" << sass_start->unit() << "' and '" << sass_end->unit() << "'."; - error(msg.str(), low->pstate(), backtrace); + error(msg.str(), low->pstate(), backtrace()); } double start = sass_start->value(); double end = sass_end->value(); // only create iterator once in this environment + Env* env = environment(); Number* it = new (env->mem) Number(low->pstate(), start, sass_end->unit()); AST_Node* old_var = env->has_local(variable) ? env->get_local(variable) : 0; env->set_local(variable, it); @@ -385,7 +423,7 @@ namespace Sass { Statement* Expand::operator()(Each* e) { vector variables(e->variables()); - Expression* expr = e->list()->perform(eval->with(env, backtrace)); + Expression* expr = e->list()->perform(eval.snapshot()); List* list = 0; Map* map = 0; if (expr->concrete_type() == Expression::MAP) { @@ -399,6 +437,7 @@ namespace Sass { list = static_cast(expr); } // remember variables and then reset them + Env* env = environment(); vector old_vars(variables.size()); for (size_t i = 0, L = variables.size(); i < L; ++i) { old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0; @@ -408,8 +447,8 @@ namespace Sass { if (map) { for (auto key : map->keys()) { - Expression* k = key->perform(eval->with(env, backtrace)); - Expression* v = map->at(key)->perform(eval->with(env, backtrace)); + Expression* k = key->perform(eval.snapshot()); + Expression* v = map->at(key)->perform(eval.snapshot()); if (variables.size() == 1) { List* variable = new (ctx.mem) List(map->pstate(), 2, List::SPACE); @@ -435,7 +474,7 @@ namespace Sass { } for (size_t j = 0, K = variables.size(); j < K; ++j) { if (j < variable->length()) { - env->set_local(variables[j], (*variable)[j]->perform(eval->with(env, backtrace))); + env->set_local(variables[j], (*variable)[j]->perform(eval.snapshot())); } else { env->set_local(variables[j], new (ctx.mem) Null(expr->pstate())); @@ -456,7 +495,7 @@ namespace Sass { { Expression* pred = w->predicate(); Block* body = w->block(); - while (*pred->perform(eval->with(env, backtrace))) { + while (*pred->perform(eval.snapshot())) { append_block(body); } return 0; @@ -464,7 +503,7 @@ namespace Sass { Statement* Expand::operator()(Return* r) { - error("@return may only be used within a function", r->pstate(), backtrace); + error("@return may only be used within a function", r->pstate(), backtrace()); return 0; } @@ -473,17 +512,19 @@ namespace Sass { To_String to_string(&ctx); Selector_List* extender = static_cast(selector_stack.back()); if (!extender) return 0; - Contextualize_Eval* eval = contextualize_eval->with(0, env, backtrace); + selector_stack.push_back(0); + + // Contextualize contextual(eval.snapshot()); Selector_List* selector_list = static_cast(e->selector()); - Selector_List* contextualized = static_cast(selector_list->perform(eval)); + Selector_List* contextualized = static_cast(selector_list->perform(eval.snapshot())); // ToDo: remove once feature proves stable! // if (contextualized->length() != 1) { - // error("selector groups may not be extended", extendee->pstate(), backtrace); + // error("selector groups may not be extended", extendee->pstate(), backtrace()); // } for (auto complex_sel : contextualized->elements()) { Complex_Selector* c = complex_sel; if (!c->head() || c->tail()) { - error("nested selectors may not be extended", c->pstate(), backtrace); + error("nested selectors may not be extended", c->pstate(), backtrace()); } Compound_Selector* compound_sel = c->head(); compound_sel->is_optional(selector_list->is_optional()); @@ -497,11 +538,13 @@ namespace Sass { ctx.subset_map.put(compound_sel->to_str_vec(), make_pair((*extender)[i], compound_sel)); } } + selector_stack.pop_back(); return 0; } Statement* Expand::operator()(Definition* d) { + Env* env = environment(); Definition* dd = new (ctx.mem) Definition(*d); env->local_frame()[d->name() + (d->type() == Definition::MIXIN ? "[m]" : "[f]")] = dd; @@ -512,21 +555,21 @@ namespace Sass { Statement* Expand::operator()(Mixin_Call* c) { + Env* env = environment(); string full_name(c->name() + "[m]"); if (!env->has(full_name)) { - error("no mixin named " + c->name(), c->pstate(), backtrace); + error("no mixin named " + c->name(), c->pstate(), backtrace()); } Definition* def = static_cast((*env)[full_name]); Block* body = def->block(); Parameters* params = def->parameters(); - Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back(); Arguments* args = static_cast(c->arguments() - ->perform(eval->with(p, env, backtrace))); - Backtrace here(backtrace, c->pstate(), ", in mixin `" + c->name() + "`"); - backtrace = &here; - Env new_env; - new_env.link(def->environment()); + ->perform(eval.snapshot())); + Backtrace new_bt(backtrace(), c->pstate(), ", in mixin `" + c->name() + "`"); + backtrace_stack.push_back(&new_bt); + Env new_env(def->environment()); + env_stack.push_back(&new_env); if (c->block()) { // represent mixin content blocks as thunks/closures Definition* thunk = new (ctx.mem) Definition(c->pstate(), @@ -538,17 +581,16 @@ namespace Sass { thunk->environment(env); new_env.local_frame()["@content[m]"] = thunk; } - bind("mixin " + c->name(), params, args, ctx, &new_env, eval); - Env* old_env = env; - env = &new_env; + bind("mixin " + c->name(), params, args, ctx, &new_env, eval.snapshot()); append_block(body); - env = old_env; - backtrace = here.parent; + backtrace_stack.pop_back(); + env_stack.pop_back(); return 0; } Statement* Expand::operator()(Content* c) { + Env* env = environment(); // convert @content directives into mixin calls to the underlying thunk if (!env->has("@content[m]")) return 0; Mixin_Call* call = new (ctx.mem) Mixin_Call(c->pstate(), @@ -559,17 +601,9 @@ namespace Sass { inline Statement* Expand::fallback_impl(AST_Node* n) { - error("unknown internal error; please contact the LibSass maintainers", n->pstate(), backtrace); + error("unknown internal error; please contact the LibSass maintainers", n->pstate(), backtrace()); String_Constant* msg = new (ctx.mem) String_Constant(ParserState("[WARN]"), string("`Expand` doesn't handle ") + typeid(*n).name()); return new (ctx.mem) Warning(ParserState("[WARN]"), msg); } - inline void Expand::append_block(Block* b) - { - Block* current_block = block_stack.back(); - for (size_t i = 0, L = b->length(); i < L; ++i) { - Statement* ith = (*b)[i]->perform(this); - if (ith) *current_block << ith; - } - } } diff --git a/expand.hpp b/expand.hpp index 58c6d4ea02..481f5a22fa 100644 --- a/expand.hpp +++ b/expand.hpp @@ -9,35 +9,42 @@ #include "eval.hpp" #include "operation.hpp" #include "environment.hpp" -#include "contextualize.hpp" namespace Sass { using namespace std; + class Listize; class Context; class Eval; - class Contextualize_Eval; typedef Environment Env; struct Backtrace; class Expand : public Operation_CRTP { + public: + + Env* environment(); + Context& context(); + Selector* selector(); + Backtrace* backtrace(); + Context& ctx; - Eval* eval; - Contextualize_Eval* contextualize_eval; - Env* env; + Eval eval; + + // it's easier to work with vectors + vector env_stack; vector block_stack; vector property_stack; vector selector_stack; - vector at_root_selector_stack; + vectorbacktrace_stack; + bool in_at_root; bool in_keyframes; - Backtrace* backtrace; Statement* fallback_impl(AST_Node* n); public: - Expand(Context&, Eval*, Contextualize_Eval*, Env*, Backtrace*); + Expand(Context&, Env*, Backtrace*); virtual ~Expand() { } using Operation::operator(); diff --git a/extend.cpp b/extend.cpp index ede8e8d73c..bbfe384504 100644 --- a/extend.cpp +++ b/extend.cpp @@ -1,6 +1,5 @@ #include "extend.hpp" #include "context.hpp" -#include "contextualize.hpp" #include "to_string.hpp" #include "backtrace.hpp" #include "paths.hpp" diff --git a/functions.cpp b/functions.cpp index 2563bf1f62..ff7aa7ebda 100644 --- a/functions.cpp +++ b/functions.cpp @@ -8,6 +8,7 @@ #include "inspect.hpp" #include "eval.hpp" #include "util.hpp" +#include "expand.hpp" #include "utf8_string.hpp" #include "utf8.h" @@ -1490,10 +1491,8 @@ namespace Sass { } } Function_Call* func = new (ctx.mem) Function_Call(pstate, name, args); - Contextualize contextualize(ctx, &d_env, backtrace); - Listize listize(ctx); - Eval eval(ctx, &contextualize, &listize, &d_env, backtrace); - return func->perform(&eval); + Expand expand(ctx, &d_env, backtrace); + return func->perform(&expand.eval); } @@ -1510,15 +1509,13 @@ namespace Sass { // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); } BUILT_IN(sass_if) { - Contextualize contextualize(ctx, &d_env, backtrace); - Listize listize(ctx); - Eval eval(ctx, &contextualize, &listize, &d_env, backtrace); - bool is_true = !ARG("$condition", Expression)->perform(&eval)->is_false(); + Expand expand(ctx, &d_env, backtrace); + bool is_true = !ARG("$condition", Expression)->perform(&expand.eval)->is_false(); if (is_true) { - return ARG("$if-true", Expression)->perform(&eval); + return ARG("$if-true", Expression)->perform(&expand.eval); } else { - return ARG("$if-false", Expression)->perform(&eval); + return ARG("$if-false", Expression)->perform(&expand.eval); } } diff --git a/inspect.cpp b/inspect.cpp index f14db8cc4f..a701fe18dd 100644 --- a/inspect.cpp +++ b/inspect.cpp @@ -739,17 +739,6 @@ namespace Sass { append_token("null", n); } - void Inspect::operator()(Parent_Selector* p) - { - if (p->selector()) { - p->selector()->perform(this); - append_delimiter(); - } - else { - append_string("&"); - } - } - // parameters and arguments void Inspect::operator()(Parameter* p) { @@ -814,10 +803,9 @@ namespace Sass { s->contents()->perform(this); } - void Inspect::operator()(Selector_Reference* ref) + void Inspect::operator()(Parent_Selector* p) { - if (ref->selector()) ref->selector()->perform(this); - else append_string("&"); + append_string("&"); } void Inspect::operator()(Selector_Placeholder* s) diff --git a/inspect.hpp b/inspect.hpp index 7cd0f51c18..3df027aecc 100644 --- a/inspect.hpp +++ b/inspect.hpp @@ -79,7 +79,6 @@ namespace Sass { virtual void operator()(Arguments*); // selectors virtual void operator()(Selector_Schema*); - virtual void operator()(Selector_Reference*); virtual void operator()(Selector_Placeholder*); virtual void operator()(Type_Selector*); virtual void operator()(Selector_Qualifier*); diff --git a/listize.cpp b/listize.cpp index 3e27803904..2faf366f81 100644 --- a/listize.cpp +++ b/listize.cpp @@ -71,9 +71,9 @@ namespace Sass { return l; } - Expression* Listize::operator()(Selector_Reference* sel) + Expression* Listize::operator()(Parent_Selector* sel) { - return 0; + return sel; } Expression* Listize::fallback_impl(AST_Node* n) diff --git a/listize.hpp b/listize.hpp index 68f060c356..a77ce675d5 100644 --- a/listize.hpp +++ b/listize.hpp @@ -30,7 +30,7 @@ namespace Sass { Expression* operator()(Selector_List*); Expression* operator()(Complex_Selector*); Expression* operator()(Compound_Selector*); - Expression* operator()(Selector_Reference*); + Expression* operator()(Parent_Selector*); template Expression* fallback(U x) { return fallback_impl(x); } diff --git a/node.cpp b/node.cpp index 7ed2d55505..68da89d20b 100644 --- a/node.cpp +++ b/node.cpp @@ -239,7 +239,7 @@ namespace Sass { // Put the dummy Compound_Selector in the first position, for consistency with the rest of libsass Compound_Selector* fakeHead = new (ctx.mem) Compound_Selector(ParserState("[NODE]"), 1); - Selector_Reference* selectorRef = new (ctx.mem) Selector_Reference(ParserState("[NODE]"), NULL); + Parent_Selector* selectorRef = new (ctx.mem) Parent_Selector(ParserState("[NODE]")); fakeHead->elements().push_back(selectorRef); pFirst->head(fakeHead); pFirst->has_line_feed(pFirst->has_line_feed() || pFirst->tail()->has_line_feed() || toConvert.got_line_feed); diff --git a/operation.hpp b/operation.hpp index b470fe8ad8..4bd9ca5397 100644 --- a/operation.hpp +++ b/operation.hpp @@ -69,7 +69,6 @@ namespace Sass { virtual T operator()(Arguments* x) = 0; // selectors virtual T operator()(Selector_Schema* x) = 0; - virtual T operator()(Selector_Reference* x) = 0; virtual T operator()(Selector_Placeholder* x) = 0; virtual T operator()(Type_Selector* x) = 0; virtual T operator()(Selector_Qualifier* x) = 0; @@ -144,7 +143,6 @@ namespace Sass { virtual T operator()(Arguments* x) { return static_cast(this)->fallback(x); } // selectors virtual T operator()(Selector_Schema* x) { return static_cast(this)->fallback(x); } - virtual T operator()(Selector_Reference* x) { return static_cast(this)->fallback(x); } virtual T operator()(Selector_Placeholder* x) { return static_cast(this)->fallback(x); } virtual T operator()(Type_Selector* x) { return static_cast(this)->fallback(x); } virtual T operator()(Selector_Qualifier* x) { return static_cast(this)->fallback(x); } diff --git a/parser.cpp b/parser.cpp index 5eaffc6ce6..3ebf9262a5 100644 --- a/parser.cpp +++ b/parser.cpp @@ -547,7 +547,7 @@ namespace Sass { Complex_Selector* comb = parse_selector_combination(); if (!comb->has_reference() && !in_at_root) { ParserState sel_source_position = pstate; - Selector_Reference* ref = new (ctx.mem) Selector_Reference(sel_source_position); + Parent_Selector* ref = new (ctx.mem) Parent_Selector(sel_source_position); Compound_Selector* ref_wrap = new (ctx.mem) Compound_Selector(sel_source_position); ref_wrap->media_block(last_media_block); ref_wrap->last_block(block_stack.back()); @@ -641,7 +641,7 @@ namespace Sass { if (block_stack.back() && block_stack.back()->is_root()) { //error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate); } - (*seq) << new (ctx.mem) Selector_Reference(pstate); + (*seq) << new (ctx.mem) Parent_Selector(pstate); sawsomething = true; // if you see a space after a &, then you're done if(peek< spaces >() || peek< alternatives < spaces, exactly<';'> > >()) { diff --git a/win/libsass.filters b/win/libsass.filters index 4e1838931d..c6851d7ab8 100644 --- a/win/libsass.filters +++ b/win/libsass.filters @@ -36,9 +36,6 @@ Source Files - - Source Files - Source Files @@ -179,9 +176,6 @@ Header Files - - Header Files - Header Files diff --git a/win/libsass.vcxproj b/win/libsass.vcxproj index a6cb1cb4bc..ea08df82f0 100644 --- a/win/libsass.vcxproj +++ b/win/libsass.vcxproj @@ -167,8 +167,6 @@ - - @@ -214,8 +212,6 @@ - - From 91892026c99f9f92b72aef81cb04ad9456a29f41 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 16 May 2015 02:06:36 +0200 Subject: [PATCH 2/9] Cleaning up [WIP] --- ast_fwd_decl.hpp | 2 +- bind.cpp | 2 ++ context.cpp | 30 ++++++++++++++++++++++------ contextualize.cpp | 0 contextualize.hpp | 7 ------- contextualize_eval.cpp | 0 contextualize_eval.hpp | 9 --------- environment.hpp | 2 +- eval.cpp | 44 +++++++++++++++--------------------------- eval.hpp | 2 +- expand.cpp | 15 ++++++-------- sass_context.cpp | 18 ++++++++--------- 12 files changed, 60 insertions(+), 71 deletions(-) delete mode 100644 contextualize.cpp delete mode 100644 contextualize.hpp delete mode 100644 contextualize_eval.cpp delete mode 100644 contextualize_eval.hpp diff --git a/ast_fwd_decl.hpp b/ast_fwd_decl.hpp index d3a9114142..2348d578dd 100644 --- a/ast_fwd_decl.hpp +++ b/ast_fwd_decl.hpp @@ -1,9 +1,9 @@ #ifndef SASS_AST_FWD_DECL_H #define SASS_AST_FWD_DECL_H + ///////////////////////////////////////////// // Forward declarations for the AST visitors. -///////////////////////////////////////////// namespace Sass { enum Output_Style { NESTED, EXPANDED, COMPACT, COMPRESSED, FORMATTED }; diff --git a/bind.cpp b/bind.cpp index 3af0eb85f7..520c897862 100644 --- a/bind.cpp +++ b/bind.cpp @@ -12,6 +12,8 @@ namespace Sass { void bind(string callee, Parameters* ps, Arguments* as, Context& ctx, Env* env, Eval* eval) { + + // Context& ctx = eval->context(); map param_map; // Set up a map to ensure named arguments refer to actual parameters. Also diff --git a/context.cpp b/context.cpp index 6e6cc7bab1..12e7f6e888 100644 --- a/context.cpp +++ b/context.cpp @@ -309,6 +309,7 @@ namespace Sass { Block* Context::parse_file() { + Block* root = 0; for (size_t i = 0; i < queue.size(); ++i) { Sass_Import_Entry import = sass_make_import( @@ -322,29 +323,46 @@ namespace Sass { sass_delete_import(import_stack.back()); import_stack.pop_back(); if (i == 0) root = ast; + // ToDo: we store by load_path, which can lead + // to duplicates if importer reports the same path + // Maybe we should add an error for duplicates!? style_sheets[queue[i].load_path] = ast; } if (root == 0) return 0; - Env tge; - Backtrace backtrace(0, ParserState("", 0), ""); - register_built_in_functions(*this, &tge); + + Env global; // create root environment + // register built-in functions on env + register_built_in_functions(*this, &global); for (size_t i = 0, S = c_functions.size(); i < S; ++i) { - register_c_function(*this, &tge, c_functions[i]); + register_c_function(*this, &global, c_functions[i]); } - Expand expand(*this, &tge, &backtrace); - Cssize cssize(*this, &tge, &backtrace); + // create initial backtrace entry + Backtrace backtrace(0, ParserState("", 0), ""); + // create crtp visitor objects + Expand expand(*this, &global, &backtrace); + Cssize cssize(*this, &global, &backtrace); + // expand and eval the tree root = root->perform(&expand)->block(); + // merge and bubble certain rules root = root->perform(&cssize)->block(); + // should we extend something? if (!subset_map.empty()) { + // create crtp visitor object Extend extend(*this, subset_map); + // extend tree nodes root->perform(&extend); } + // clean up by removing empty placeholders + // ToDo: maybe we can do this somewhere else? Remove_Placeholders remove_placeholders(*this); root->perform(&remove_placeholders); + // return processed tree return root; + } + // EO parse_file Block* Context::parse_string() { diff --git a/contextualize.cpp b/contextualize.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/contextualize.hpp b/contextualize.hpp deleted file mode 100644 index 1c647caadb..0000000000 --- a/contextualize.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef SASS_CONTEXTUALIZE_H -#define SASS_CONTEXTUALIZE_H - -namespace Sass { -} - -#endif diff --git a/contextualize_eval.cpp b/contextualize_eval.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/contextualize_eval.hpp b/contextualize_eval.hpp deleted file mode 100644 index 5ae747e42b..0000000000 --- a/contextualize_eval.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef SASS_CONTEXTUALIZE_EVAL_H -#define SASS_CONTEXTUALIZE_EVAL_H - -#include "ast_fwd_decl.hpp" - -namespace Sass { -} - -#endif diff --git a/environment.hpp b/environment.hpp index d8179633aa..3c7a2e2ff2 100644 --- a/environment.hpp +++ b/environment.hpp @@ -54,7 +54,7 @@ namespace Sass { } bool has_local(const string& key) const - { return local_frame_.count(key); } + { return local_frame_.count(key) != 0; } T& get_local(const string& key) { return local_frame_[key]; } diff --git a/eval.cpp b/eval.cpp index 988b421f2a..fb7b3fece4 100644 --- a/eval.cpp +++ b/eval.cpp @@ -44,15 +44,13 @@ namespace Sass { Eval::Eval(Expand* exp, Context& ctx, Env* env, Backtrace* bt) : ctx(ctx), - listize(new (ctx.mem) Listize(ctx)), + listize(ctx), env(env), exp(exp), backtrace(bt) { } Eval::~Eval() { } - // for setting the env before eval'ing an expression - Context& Eval::context() { return ctx; @@ -73,8 +71,6 @@ namespace Sass { return exp ? exp->backtrace() : 0; } - - // for setting the env before eval'ing an expression // gets the env and other stuff from expander scope Eval* Eval::snapshot() @@ -609,8 +605,8 @@ namespace Sass { } Parameters* params = def->parameters(); - Env new_env; - new_env.link(def->environment()); + Env new_env(def->environment()); + exp->env_stack.push_back(&new_env); // bind("function " + c->name(), params, args, ctx, &new_env, this); // Env* old_env = env; // env = &new_env; @@ -729,6 +725,7 @@ namespace Sass { result->is_delayed(result->concrete_type() == Expression::STRING); result = result->perform(this); } while (result->concrete_type() == Expression::NONE); + exp->env_stack.pop_back(); return result; } @@ -783,7 +780,7 @@ namespace Sass { value = new (ctx.mem) Null(value->pstate()); } else if (value->concrete_type() == Expression::SELECTOR) { - value = value->perform(this)->perform(listize); + value = value->perform(this)->perform(&listize); } // cerr << "\ttype is now: " << typeid(*value).name() << endl << endl; @@ -894,10 +891,10 @@ namespace Sass { return evacuate_escapes(str); } else if (dynamic_cast(s)) { To_String to_string(&ctx); - return evacuate_quotes(s->perform(listize)->perform(this)->perform(listize)->perform(this)->perform(&to_string)); + return evacuate_quotes(s->perform(&listize)->perform(this)->perform(&listize)->perform(this)->perform(&to_string)); } else if (Selector_List* sel = dynamic_cast(s)) { To_String to_string(&ctx); - return evacuate_quotes(sel->perform(listize)->perform(this)->perform(&to_string)); + return evacuate_quotes(sel->perform(&listize)->perform(this)->perform(&to_string)); } else if (String_Schema* str_schema = dynamic_cast(s)) { string res = ""; for(auto i : str_schema->elements()) @@ -1514,24 +1511,15 @@ namespace Sass { Expression* Eval::operator()(Parent_Selector* p) { - Selector* pr = exp->selector_stack.back(); - if (dynamic_cast(pr)) { - exp->selector_stack.pop_back(); - exp->selector_stack.push_back(0); - // I cannot listize here (would help) - auto rv = pr ? pr->perform(this)->perform(listize) : 0; - exp->selector_stack.pop_back(); - exp->selector_stack.push_back(pr); - return rv; - } else { - exp->selector_stack.pop_back(); - exp->selector_stack.push_back(0); - // I cannot listize here (would help) - auto rv = pr ? pr->perform(this) : 0; - exp->selector_stack.pop_back(); - exp->selector_stack.push_back(pr); - return rv; - } + Selector* pr = selector(); + exp->selector_stack.pop_back(); + exp->selector_stack.push_back(0); + auto rv = pr ? pr->perform(this) : 0; + if (dynamic_cast(pr)) + rv = rv->perform(&listize); + exp->selector_stack.pop_back(); + exp->selector_stack.push_back(pr); + return rv; } } diff --git a/eval.hpp b/eval.hpp index 17f3b6918b..6f764fdfd8 100644 --- a/eval.hpp +++ b/eval.hpp @@ -26,7 +26,7 @@ namespace Sass { Expression* fallback_impl(AST_Node* n); public: - Listize* listize; + Listize listize; Env* env; Expand* exp; Backtrace* backtrace; diff --git a/expand.cpp b/expand.cpp index 1651255401..1efeea12e4 100644 --- a/expand.cpp +++ b/expand.cpp @@ -8,7 +8,6 @@ #include "backtrace.hpp" #include "context.hpp" #include "parser.hpp" -#include "debugger.hpp" namespace Sass { @@ -84,10 +83,9 @@ namespace Sass { // process and add to last block on stack inline void Expand::append_block(Block* b) { - Block* current_block = block_stack.back(); for (size_t i = 0, L = b->length(); i < L; ++i) { Statement* ith = (*b)[i]->perform(this); - if (ith) *current_block << ith; + if (ith) *block_stack.back() << ith; } } @@ -145,11 +143,9 @@ namespace Sass { property_stack.push_back(p->property_fragment()); Block* expanded_block = p->block()->perform(this)->block(); - Block* current_block = block_stack.back(); for (size_t i = 0, L = expanded_block->length(); i < L; ++i) { Statement* stm = (*expanded_block)[i]; - if (typeid(*stm) == typeid(Declaration)) { - Declaration* dec = static_cast(stm); + if (Declaration* dec = static_cast(stm)) { String_Schema* combined_prop = new (ctx.mem) String_Schema(p->pstate()); if (!property_stack.empty()) { *combined_prop << property_stack.back() @@ -160,7 +156,7 @@ namespace Sass { *combined_prop << dec->property(); } dec->property(combined_prop); - *current_block << dec; + *block_stack.back() << dec; } else if (typeid(*stm) == typeid(Comment)) { // drop comments in propsets @@ -238,7 +234,6 @@ namespace Sass { String* old_p = d->property(); String* new_p = static_cast(old_p->perform(eval.snapshot())); Expression* value = d->value()->perform(eval.snapshot()); - if (!value) debug_ast(d->value()); if (!value || (value->is_invisible() && !d->is_important())) return 0; Declaration* decl = new (ctx.mem) Declaration(d->pstate(), new_p, @@ -599,10 +594,12 @@ namespace Sass { return call->perform(this); } + // produce an error if something is not implemented inline Statement* Expand::fallback_impl(AST_Node* n) { + string err = string("`Expand` doesn't handle ") + typeid(*n).name(); + String_Constant* msg = new (ctx.mem) String_Constant(ParserState("[WARN]"), err); error("unknown internal error; please contact the LibSass maintainers", n->pstate(), backtrace()); - String_Constant* msg = new (ctx.mem) String_Constant(ParserState("[WARN]"), string("`Expand` doesn't handle ") + typeid(*n).name()); return new (ctx.mem) Warning(ParserState("[WARN]"), msg); } diff --git a/sass_context.cpp b/sass_context.cpp index 24e02f1e07..2d1d594e5d 100644 --- a/sass_context.cpp +++ b/sass_context.cpp @@ -272,7 +272,7 @@ extern "C" { c_ctx->error_json = json_stringify(json_err, " ");; c_ctx->error_message = sass_strdup(msg_stream.str().c_str()); - c_ctx->error_text = strdup(e.message.c_str()); + c_ctx->error_text = sass_strdup(e.message.c_str()); c_ctx->error_status = 1; c_ctx->error_file = sass_strdup(e.pstate.path.c_str()); c_ctx->error_line = e.pstate.line+1; @@ -290,7 +290,7 @@ extern "C" { json_append_member(json_err, "message", json_mkstring(ba.what())); c_ctx->error_json = json_stringify(json_err, " ");; c_ctx->error_message = sass_strdup(msg_stream.str().c_str()); - c_ctx->error_text = strdup(ba.what()); + c_ctx->error_text = sass_strdup(ba.what()); c_ctx->error_status = 2; c_ctx->output_string = 0; c_ctx->source_map_string = 0; @@ -304,7 +304,7 @@ extern "C" { json_append_member(json_err, "message", json_mkstring(e.what())); c_ctx->error_json = json_stringify(json_err, " ");; c_ctx->error_message = sass_strdup(msg_stream.str().c_str()); - c_ctx->error_text = strdup(e.what()); + c_ctx->error_text = sass_strdup(e.what()); c_ctx->error_status = 3; c_ctx->output_string = 0; c_ctx->source_map_string = 0; @@ -318,7 +318,7 @@ extern "C" { json_append_member(json_err, "message", json_mkstring(e.c_str())); c_ctx->error_json = json_stringify(json_err, " ");; c_ctx->error_message = sass_strdup(msg_stream.str().c_str()); - c_ctx->error_text = strdup(e.c_str()); + c_ctx->error_text = sass_strdup(e.c_str()); c_ctx->error_status = 4; c_ctx->output_string = 0; c_ctx->source_map_string = 0; @@ -332,7 +332,7 @@ extern "C" { json_append_member(json_err, "message", json_mkstring("unknown")); c_ctx->error_json = json_stringify(json_err, " ");; c_ctx->error_message = sass_strdup(msg_stream.str().c_str()); - c_ctx->error_text = strdup("unknown"); + c_ctx->error_text = sass_strdup("unknown"); c_ctx->error_status = 5; c_ctx->output_string = 0; c_ctx->source_map_string = 0; @@ -665,8 +665,8 @@ extern "C" { if (compiler->c_ctx->error_status) return compiler->c_ctx->error_status; compiler->state = SASS_COMPILER_EXECUTED; - Context* cpp_ctx = (Context*) compiler->cpp_ctx; - Block* root = (Block*) compiler->root; + Context* cpp_ctx = compiler->cpp_ctx; + Block* root = compiler->root; // compile the parsed root block try { compiler->c_ctx->output_string = cpp_ctx->compile_block(root); } // pass catched errors to generic error handler @@ -780,9 +780,9 @@ extern "C" { void ADDCALL sass_delete_compiler (struct Sass_Compiler* compiler) { if (compiler == 0) return; - Context* cpp_ctx = (Context*) compiler->cpp_ctx; + Context* cpp_ctx = compiler->cpp_ctx; + if (cpp_ctx) delete(cpp_ctx); compiler->cpp_ctx = 0; - delete cpp_ctx; free(compiler); } From 521c3cc35ee809f1316205f9ba8804f4b95359e3 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sun, 17 May 2015 21:35:35 +0200 Subject: [PATCH 3/9] Make more sense of functions and environments [WIP] --- bind.cpp | 10 +--- cssize.cpp | 10 ++-- cssize.hpp | 2 +- eval.cpp | 170 ++++++++++++++++++++--------------------------------- eval.hpp | 4 +- 5 files changed, 72 insertions(+), 124 deletions(-) diff --git a/bind.cpp b/bind.cpp index 520c897862..1543d624ce 100644 --- a/bind.cpp +++ b/bind.cpp @@ -229,15 +229,7 @@ namespace Sass { true); } else if (leftover->default_value()) { - // make sure to eval the default value in the env that we've been populating - Env* old_env = eval->env; - Backtrace* old_bt = eval->backtrace; - Eval* snapshot = eval->snapshot(); - snapshot->env = env; - Expression* dv = leftover->default_value()->perform(snapshot); - eval->env = old_env; - eval->backtrace = old_bt; - // dv->perform(&to_string); + Expression* dv = leftover->default_value()->perform(eval); env->local_frame()[leftover->name()] = dv; } else { diff --git a/cssize.cpp b/cssize.cpp index 5f9dc5243f..2a93fde993 100644 --- a/cssize.cpp +++ b/cssize.cpp @@ -10,7 +10,7 @@ namespace Sass { Cssize::Cssize(Context& ctx, Env* env, Backtrace* bt) : ctx(ctx), - env(env), + // env(env), block_stack(vector()), p_stack(vector()), backtrace(bt) @@ -23,15 +23,15 @@ namespace Sass { Statement* Cssize::operator()(Block* b) { - Env new_env; - new_env.link(*env); - env = &new_env; + // Env new_env; + // new_env.link(*env); + // env = &new_env; Block* bb = new (ctx.mem) Block(b->pstate(), b->length(), b->is_root()); // bb->tabs(b->tabs()); block_stack.push_back(bb); append_block(b); block_stack.pop_back(); - env = env->parent(); + // env = env->parent(); return bb; } diff --git a/cssize.hpp b/cssize.hpp index 1389965393..93034fd27e 100644 --- a/cssize.hpp +++ b/cssize.hpp @@ -18,7 +18,7 @@ namespace Sass { class Cssize : public Operation_CRTP { Context& ctx; - Env* env; + // Env* env; vector block_stack; vector p_stack; Backtrace* backtrace; diff --git a/eval.cpp b/eval.cpp index fb7b3fece4..512fd4f742 100644 --- a/eval.cpp +++ b/eval.cpp @@ -36,18 +36,14 @@ namespace Sass { Eval::Eval(Eval* eval) : ctx(eval->ctx), listize(eval->listize), - env(eval->env), - exp(eval->exp), - backtrace(eval->backtrace) + exp(eval->exp) { } Eval::Eval(Expand* exp, Context& ctx, Env* env, Backtrace* bt) : ctx(ctx), listize(ctx), - env(env), - exp(exp), - backtrace(bt) + exp(exp) { } Eval::~Eval() { } @@ -75,8 +71,8 @@ namespace Sass { // gets the env and other stuff from expander scope Eval* Eval::snapshot() { - this->env = environment(); - this->backtrace = stacktrace(); + // this->env = environment(); + // this->backtrace = stacktrace(); return this; } @@ -92,6 +88,7 @@ namespace Sass { Expression* Eval::operator()(Assignment* a) { + Env* env = environment(); string var(a->variable()); if (a->is_global()) { if (a->is_default()) { @@ -182,11 +179,12 @@ namespace Sass { stringstream msg; msg << "Incompatible units: '" << sass_start->unit() << "' and '" << sass_end->unit() << "'."; - error(msg.str(), low->pstate(), backtrace); + error(msg.str(), low->pstate(), stacktrace()); } double start = sass_start->value(); double end = sass_end->value(); // only create iterator once in this environment + Env* env = environment(); Number* it = new (env->mem) Number(low->pstate(), start, sass_end->unit()); AST_Node* old_var = env->has_local(variable) ? env->get_local(variable) : 0; env->set_local(variable, it); @@ -225,6 +223,7 @@ namespace Sass { { vector variables(e->variables()); Expression* expr = e->list()->perform(this); + Env* env = environment(); List* list = 0; Map* map = 0; if (expr->concrete_type() == Expression::MAP) { @@ -315,6 +314,7 @@ namespace Sass { { Expression* message = w->message()->perform(this); To_String to_string(&ctx); + Env* env = environment(); // try to use generic function if (env->has("@warn[f]")) { @@ -336,7 +336,7 @@ namespace Sass { } string result(unquote(message->perform(&to_string))); - Backtrace top(backtrace, w->pstate(), ""); + Backtrace top(stacktrace(), w->pstate(), ""); cerr << "WARNING: " << result; cerr << top.to_string(true); cerr << endl << endl; @@ -347,6 +347,7 @@ namespace Sass { { Expression* message = e->message()->perform(this); To_String to_string(&ctx); + Env* env = environment(); // try to use generic function if (env->has("@error[f]")) { @@ -376,6 +377,7 @@ namespace Sass { { Expression* message = d->value()->perform(this); To_String to_string(&ctx); + Env* env = environment(); // try to use generic function if (env->has("@debug[f]")) { @@ -563,10 +565,10 @@ namespace Sass { Expression* Eval::operator()(Function_Call* c) { - if (backtrace->parent != NULL && backtrace->depth() > Constants::MaxCallStack) { + if (stacktrace()->parent != NULL && stacktrace()->depth() > Constants::MaxCallStack) { ostringstream stm; stm << "Stack depth exceeded max of " << Constants::MaxCallStack; - error(stm.str(), c->pstate(), backtrace); + error(stm.str(), c->pstate(), stacktrace()); } string name(Util::normalize_underscores(c->name())); string full_name(name + "[f]"); @@ -575,80 +577,64 @@ namespace Sass { args = static_cast(args->perform(this)); } - // try to use generic function + Env* env = environment(); if (!env->has(full_name)) { - if (env->has("*[f]")) { + if (!env->has("*[f]")) { + // just pass it through as a literal + Function_Call* lit = new (ctx.mem) Function_Call(c->pstate(), + c->name(), + args); + To_String to_string(&ctx); + return new (ctx.mem) String_Constant(c->pstate(), + lit->perform(&to_string)); + } else { + // call generic function full_name = "*[f]"; } } - // if it doesn't exist, just pass it through as a literal - if (!env->has(full_name)) { - Function_Call* lit = new (ctx.mem) Function_Call(c->pstate(), - c->name(), - args); - To_String to_string(&ctx); - return new (ctx.mem) String_Constant(c->pstate(), - lit->perform(&to_string)); + Definition* def = static_cast((*env)[full_name]); + + if (def->is_overload_stub()) { + stringstream ss; + ss << full_name + << args->length(); + full_name = ss.str(); + string resolved_name(full_name); + if (!env->has(resolved_name)) error("overloaded function `" + string(c->name()) + "` given wrong number of arguments", c->pstate()); + def = static_cast((*env)[resolved_name]); } Expression* result = c; - Definition* def = static_cast((*env)[full_name]); Block* body = def->block(); Native_Function func = def->native_function(); Sass_Function_Entry c_function = def->c_function(); - if (full_name != "if[f]") { - for (size_t i = 0, L = args->length(); i < L; ++i) { - (*args)[i]->value((*args)[i]->value()->perform(this)); - } - } + // if (full_name != "if[f]") { + // for (size_t i = 0, L = args->length(); i < L; ++i) { + // (*args)[i]->value((*args)[i]->value()->perform(this)); + // } + // } Parameters* params = def->parameters(); - Env new_env(def->environment()); - exp->env_stack.push_back(&new_env); - // bind("function " + c->name(), params, args, ctx, &new_env, this); - // Env* old_env = env; - // env = &new_env; - - // Backtrace here(backtrace, c->path(), c->line(), ", in function `" + c->name() + "`"); - // backtrace = &here; - - // if it's user-defined, eval the body - if (body) { - - bind("function " + c->name(), params, args, ctx, &new_env, this); - Env* old_env = env; - env = &new_env; - - Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`"); - backtrace = &here; + Env fn_env(def->environment()); + exp->env_stack.push_back(&fn_env); - result = body->perform(this); - if (!result) { - error(string("function ") + c->name() + " did not return a value", c->pstate()); - } - backtrace = here.parent; - env = old_env; + if (func || body) { + bind("function " + c->name(), params, args, ctx, &fn_env, this); + Backtrace here(stacktrace(), c->pstate(), ", in function `" + c->name() + "`"); + exp->backtrace_stack.push_back(&here); + // if it's user-defined, eval the body + if (body) result = body->perform(this); + // if it's native, invoke the underlying CPP function + else result = func(fn_env, *env, ctx, def->signature(), c->pstate(), stacktrace()); + if (!result) error(string("function ") + c->name() + " did not return a value", c->pstate()); + exp->backtrace_stack.pop_back(); } - // if it's native, invoke the underlying CPP function - else if (func) { - - bind("function " + c->name(), params, args, ctx, &new_env, this); - Env* old_env = env; - env = &new_env; - - Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`"); - backtrace = &here; - - result = func(*env, *old_env, ctx, def->signature(), c->pstate(), backtrace); - backtrace = here.parent; - env = old_env; - } // else if it's a user-defined c function + // convert call into C-API compatible form else if (c_function) { - Sass_Function_Fn c_func = sass_function_get_function(c_function); if (full_name == "*[f]") { String_Constant *str = new (ctx.mem) String_Constant(c->pstate(), c->name()); @@ -659,63 +645,33 @@ namespace Sass { } // populates env with default values for params - bind("function " + c->name(), params, args, ctx, &new_env, this); - Env* old_env = env; - env = &new_env; + bind("function " + c->name(), params, args, ctx, &fn_env, this); - Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`"); - backtrace = &here; + Backtrace here(stacktrace(), c->pstate(), ", in function `" + c->name() + "`"); + exp->backtrace_stack.push_back(&here); To_C to_c; - union Sass_Value* c_args = sass_make_list(env->local_frame().size(), SASS_COMMA); + union Sass_Value* c_args = sass_make_list(params[0].length(), SASS_COMMA); for(size_t i = 0; i < params[0].length(); i++) { string key = params[0][i]->name(); - AST_Node* node = env->local_frame().at(key); + AST_Node* node = fn_env.get_local(key); Expression* arg = static_cast(node); sass_list_set_value(c_args, i, arg->perform(&to_c)); } Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options); if (sass_value_get_tag(c_val) == SASS_ERROR) { - error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), backtrace); + error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), stacktrace()); } else if (sass_value_get_tag(c_val) == SASS_WARNING) { - error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), backtrace); + error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), stacktrace()); } - result = cval_to_astnode(c_val, ctx, backtrace, c->pstate()); + result = cval_to_astnode(c_val, ctx, stacktrace(), c->pstate()); - backtrace = here.parent; + exp->backtrace_stack.pop_back(); sass_delete_value(c_args); if (c_val != c_args) sass_delete_value(c_val); - env = old_env; - } - // else it's an overloaded native function; resolve it - else if (def->is_overload_stub()) { - size_t arity = args->length(); - stringstream ss; - ss << full_name << arity; - string resolved_name(ss.str()); - if (!env->has(resolved_name)) error("overloaded function `" + string(c->name()) + "` given wrong number of arguments", c->pstate()); - Definition* resolved_def = static_cast((*env)[resolved_name]); - params = resolved_def->parameters(); - Env newer_env; - newer_env.link(resolved_def->environment()); - bind("function " + c->name(), params, args, ctx, &newer_env, this); - Env* old_env = env; - env = &newer_env; - - Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`"); - backtrace = &here; - - result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->pstate(), backtrace); - - backtrace = here.parent; - env = old_env; } - // backtrace = here.parent; - // env = old_env; - - // link back to function definition // only do this for custom functions if (result->pstate().file == string::npos) @@ -743,6 +699,7 @@ namespace Sass { To_String to_string(&ctx); string name(v->name()); Expression* value = 0; + Env* env = environment(); if (env->has(name)) value = static_cast((*env)[name]); else error("Undefined variable: \"" + v->name() + "\".", v->pstate()); // cerr << "name: " << v->name() << "; type: " << typeid(*value).name() << "; value: " << value->perform(&to_string) << endl; @@ -875,6 +832,7 @@ namespace Sass { } string Eval::interpolation(Expression* s) { + Env* env = environment(); if (String_Quoted* str_quoted = dynamic_cast(s)) { if (str_quoted->quote_mark()) { if (str_quoted->quote_mark() == '*' || str_quoted->is_delayed()) { diff --git a/eval.hpp b/eval.hpp index 6f764fdfd8..416f1ab562 100644 --- a/eval.hpp +++ b/eval.hpp @@ -21,15 +21,13 @@ namespace Sass { class Eval : public Operation_CRTP { - Context& ctx; Expression* fallback_impl(AST_Node* n); public: + Context& ctx; Listize listize; - Env* env; Expand* exp; - Backtrace* backtrace; Eval(Eval* eval); Eval(Expand* exp, Context&, Env*, Backtrace*); virtual ~Eval(); From dc6e7b290d37dc7f7db83d39485c83dd7fb04144 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sun, 17 May 2015 22:16:31 +0200 Subject: [PATCH 4/9] Clean up some constructor arguments [WIP] --- eval.cpp | 63 ++++++++++++++++++++++++++++-------------------------- eval.hpp | 4 ++-- expand.cpp | 2 +- expand.hpp | 1 - 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/eval.cpp b/eval.cpp index 512fd4f742..fd59f07248 100644 --- a/eval.cpp +++ b/eval.cpp @@ -34,16 +34,15 @@ namespace Sass { }; Eval::Eval(Eval* eval) - : ctx(eval->ctx), - listize(eval->listize), - exp(eval->exp) + : exp(eval->exp), + ctx(eval->ctx), + listize(eval->listize) { } - Eval::Eval(Expand* exp, Context& ctx, Env* env, Backtrace* bt) - : - ctx(ctx), - listize(ctx), - exp(exp) + Eval::Eval(Expand& exp) + : exp(exp), + ctx(exp.ctx), + listize(exp.ctx) { } Eval::~Eval() { } @@ -54,17 +53,17 @@ namespace Sass { Env* Eval::environment() { - return exp ? exp->environment() : 0; + return exp.environment(); } Selector* Eval::selector() { - return exp ? exp->selector() : 0; + return exp.selector(); } Backtrace* Eval::stacktrace() { - return exp ? exp->backtrace() : 0; + return exp.backtrace(); } // for setting the env before eval'ing an expression @@ -149,14 +148,18 @@ namespace Sass { Expression* Eval::operator()(If* i) { + Expression* rv = 0; + Env env(environment()); + exp.env_stack.push_back(&env); if (*i->predicate()->perform(this)) { - return i->consequent()->perform(this); + rv = i->consequent()->perform(this); } else { Block* alt = i->alternative(); - if (alt) return alt->perform(this); + if (alt) rv = alt->perform(this); } - return 0; + exp.env_stack.pop_back(); + return rv; } // For does not create a new env scope @@ -618,18 +621,18 @@ namespace Sass { Parameters* params = def->parameters(); Env fn_env(def->environment()); - exp->env_stack.push_back(&fn_env); + exp.env_stack.push_back(&fn_env); if (func || body) { bind("function " + c->name(), params, args, ctx, &fn_env, this); Backtrace here(stacktrace(), c->pstate(), ", in function `" + c->name() + "`"); - exp->backtrace_stack.push_back(&here); + exp.backtrace_stack.push_back(&here); // if it's user-defined, eval the body if (body) result = body->perform(this); // if it's native, invoke the underlying CPP function else result = func(fn_env, *env, ctx, def->signature(), c->pstate(), stacktrace()); if (!result) error(string("function ") + c->name() + " did not return a value", c->pstate()); - exp->backtrace_stack.pop_back(); + exp.backtrace_stack.pop_back(); } // else if it's a user-defined c function @@ -648,7 +651,7 @@ namespace Sass { bind("function " + c->name(), params, args, ctx, &fn_env, this); Backtrace here(stacktrace(), c->pstate(), ", in function `" + c->name() + "`"); - exp->backtrace_stack.push_back(&here); + exp.backtrace_stack.push_back(&here); To_C to_c; union Sass_Value* c_args = sass_make_list(params[0].length(), SASS_COMMA); @@ -666,7 +669,7 @@ namespace Sass { } result = cval_to_astnode(c_val, ctx, stacktrace(), c->pstate()); - exp->backtrace_stack.pop_back(); + exp.backtrace_stack.pop_back(); sass_delete_value(c_args); if (c_val != c_args) sass_delete_value(c_val); @@ -681,7 +684,7 @@ namespace Sass { result->is_delayed(result->concrete_type() == Expression::STRING); result = result->perform(this); } while (result->concrete_type() == Expression::NONE); - exp->env_stack.pop_back(); + exp.env_stack.pop_back(); return result; } @@ -1348,8 +1351,8 @@ namespace Sass { Expression* Eval::operator()(Selector_List* s) { - int LL = exp->selector_stack.size(); - Selector* parent = exp->selector_stack[LL - 1]; + int LL = exp.selector_stack.size(); + Selector* parent = exp.selector_stack[LL - 1]; Selector_List* p = static_cast(parent); Selector_List* ss = 0; if (p) { @@ -1366,11 +1369,11 @@ namespace Sass { for (size_t i = 0, L = p->length(); i < L; ++i) { for (size_t j = 0, L = s->length(); j < L; ++j) { parent = (*p)[i]->tail(); - exp->selector_stack.push_back(0); - exp->selector_stack.push_back((*p)[i]); + exp.selector_stack.push_back(0); + exp.selector_stack.push_back((*p)[i]); Complex_Selector* comb = static_cast((*s)[j]->perform(this)); - exp->selector_stack.pop_back(); - exp->selector_stack.pop_back(); + exp.selector_stack.pop_back(); + exp.selector_stack.pop_back(); if ((*p)[i]->has_line_feed()) comb->has_line_feed(true); if (comb) *ss << comb; else cerr << "Warning: eval returned null" << endl; @@ -1470,13 +1473,13 @@ namespace Sass { Expression* Eval::operator()(Parent_Selector* p) { Selector* pr = selector(); - exp->selector_stack.pop_back(); - exp->selector_stack.push_back(0); + exp.selector_stack.pop_back(); + exp.selector_stack.push_back(0); auto rv = pr ? pr->perform(this) : 0; if (dynamic_cast(pr)) rv = rv->perform(&listize); - exp->selector_stack.pop_back(); - exp->selector_stack.push_back(pr); + exp.selector_stack.pop_back(); + exp.selector_stack.push_back(pr); return rv; } diff --git a/eval.hpp b/eval.hpp index 416f1ab562..4b35b039e7 100644 --- a/eval.hpp +++ b/eval.hpp @@ -25,11 +25,11 @@ namespace Sass { Expression* fallback_impl(AST_Node* n); public: + Expand& exp; Context& ctx; Listize listize; - Expand* exp; Eval(Eval* eval); - Eval(Expand* exp, Context&, Env*, Backtrace*); + Eval(Expand& exp); virtual ~Eval(); Env* environment(); diff --git a/expand.cpp b/expand.cpp index 1efeea12e4..6522cc4842 100644 --- a/expand.cpp +++ b/expand.cpp @@ -13,7 +13,7 @@ namespace Sass { Expand::Expand(Context& ctx, Env* env, Backtrace* bt) : ctx(ctx), - eval(Eval(this, ctx, env, bt)), + eval(Eval(*this)), env_stack(vector()), block_stack(vector()), property_stack(vector()), diff --git a/expand.hpp b/expand.hpp index 481f5a22fa..29b1392260 100644 --- a/expand.hpp +++ b/expand.hpp @@ -27,7 +27,6 @@ namespace Sass { Selector* selector(); Backtrace* backtrace(); - Context& ctx; Eval eval; From a89f0a216888d8086398bf479af71404aeead184 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sun, 17 May 2015 23:02:20 +0200 Subject: [PATCH 5/9] Fix some MSVC warnings (and mute some others) --- expand.cpp | 4 ++++ extend.cpp | 4 ++++ json.cpp | 5 +++++ parser.cpp | 4 ++-- posix/getopt.c | 5 +++++ sass2scss.cpp | 5 +++++ sass_context.cpp | 4 ++++ sass_functions.cpp | 2 +- sass_interface.cpp | 4 ++++ util.cpp | 9 +++++++-- 10 files changed, 41 insertions(+), 5 deletions(-) diff --git a/expand.cpp b/expand.cpp index 6522cc4842..1cb421df00 100644 --- a/expand.cpp +++ b/expand.cpp @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#pragma warning(disable : 4503) +#endif + #include #include diff --git a/extend.cpp b/extend.cpp index bbfe384504..c8c78a948d 100644 --- a/extend.cpp +++ b/extend.cpp @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#pragma warning(disable : 4503) +#endif + #include "extend.hpp" #include "context.hpp" #include "to_string.hpp" diff --git a/json.cpp b/json.cpp index f92f096a24..32fda7bc98 100644 --- a/json.cpp +++ b/json.cpp @@ -21,6 +21,11 @@ THE SOFTWARE. */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_NONSTDC_NO_DEPRECATE +#endif + #include "json.hpp" #include diff --git a/parser.cpp b/parser.cpp index 3ebf9262a5..655dbf6906 100644 --- a/parser.cpp +++ b/parser.cpp @@ -281,7 +281,7 @@ namespace Sass { Expression* the_url = parse_string(); *args << new (ctx.mem) Argument(the_url->pstate(), the_url); } - else if (lex < uri_value >(position)) { // chunk seems to work too! + else if (lex < uri_value >(position != 0)) { // chunk seems to work too! String* the_url = parse_interpolated_chunk(lexed); *args << new (ctx.mem) Argument(the_url->pstate(), the_url); } @@ -732,7 +732,7 @@ namespace Sass { if (lex< alternatives< even, odd > >()) { expr = new (ctx.mem) String_Quoted(p, lexed); } - else if (lex< binomial >(position)) { + else if (lex< binomial >(position != 0)) { expr = new (ctx.mem) String_Constant(p, lexed); ((String_Constant*)expr)->can_compress_whitespace(true); } diff --git a/posix/getopt.c b/posix/getopt.c index ac1fda426e..e65eb0d57d 100644 --- a/posix/getopt.c +++ b/posix/getopt.c @@ -49,6 +49,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_NONSTDC_NO_DEPRECATE +#endif + #include #include #include diff --git a/sass2scss.cpp b/sass2scss.cpp index 54e65382d9..6477c2575a 100644 --- a/sass2scss.cpp +++ b/sass2scss.cpp @@ -1,3 +1,8 @@ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_NONSTDC_NO_DEPRECATE +#endif + // include library #include #include diff --git a/sass_context.cpp b/sass_context.cpp index 2d1d594e5d..e5e9f33334 100644 --- a/sass_context.cpp +++ b/sass_context.cpp @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#endif + #ifdef _WIN32 #include #define LFEED "\n" diff --git a/sass_functions.cpp b/sass_functions.cpp index 3905fd66d3..8463f5dfad 100644 --- a/sass_functions.cpp +++ b/sass_functions.cpp @@ -121,7 +121,7 @@ extern "C" { { if (import == 0) return 0; if (import->error) free(import->error); - import->error = error ? strdup(error) : 0; + import->error = error ? sass_strdup(error) : 0; import->line = line ? line : -1; import->column = col ? col : -1; return import; diff --git a/sass_interface.cpp b/sass_interface.cpp index 78cd4bcf67..274f8d3d58 100644 --- a/sass_interface.cpp +++ b/sass_interface.cpp @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#endif + #ifdef _WIN32 #include #define LFEED "\n" diff --git a/util.cpp b/util.cpp index 831a4b7cd9..c0346e5886 100644 --- a/util.cpp +++ b/util.cpp @@ -1,4 +1,9 @@ -#include +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_NONSTDC_NO_DEPRECATE +#endif + +#include #include "ast.hpp" #include "util.hpp" #include "prelexer.hpp" @@ -562,7 +567,7 @@ namespace Sass { } bool isPrintable(Expression* e, Output_Style style) { - return isPrintable(e, style); + return false; // isPrintable(e, style); } bool isPrintable(Feature_Block* f, Output_Style style) { From a81dad6ae1199b084c4d61613d0ae744ec001906 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sun, 17 May 2015 23:31:01 +0200 Subject: [PATCH 6/9] Remove eval snapshot feature [WIP] --- eval.cpp | 9 ------- expand.cpp | 74 +++++++++++++++++++++++++++--------------------------- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/eval.cpp b/eval.cpp index fd59f07248..6511fdc93b 100644 --- a/eval.cpp +++ b/eval.cpp @@ -66,15 +66,6 @@ namespace Sass { return exp.backtrace(); } - // for setting the env before eval'ing an expression - // gets the env and other stuff from expander scope - Eval* Eval::snapshot() - { - // this->env = environment(); - // this->backtrace = stacktrace(); - return this; - } - Expression* Eval::operator()(Block* b) { Expression* val = 0; diff --git a/expand.cpp b/expand.cpp index 1cb421df00..91e089996b 100644 --- a/expand.cpp +++ b/expand.cpp @@ -102,15 +102,15 @@ namespace Sass { Keyframe_Rule* k = new (ctx.mem) Keyframe_Rule(r->pstate(), r->block()->perform(this)->block()); if (r->selector()) { selector_stack.push_back(0); - // Contextualize contextual(eval.snapshot()); - k->selector(static_cast(r->selector()->perform(eval.snapshot()))); + // Contextualize contextual(&eval); + k->selector(static_cast(r->selector()->perform(&eval))); selector_stack.pop_back(); } return k; } // debug_ast(r->selector()); - // Contextualize contextual(eval.snapshot()); - Selector* sel_ctx = static_cast(r->selector()->perform(eval.snapshot())); + // Contextualize contextual(&eval); + Selector* sel_ctx = static_cast(r->selector()->perform(&eval)); if (sel_ctx == 0) throw "Cannot expand null selector"; // ToDo: Check if we can do this different @@ -177,7 +177,7 @@ namespace Sass { Statement* Expand::operator()(Feature_Block* f) { - Expression* feature_queries = f->feature_queries()->perform(eval.snapshot()); + Expression* feature_queries = f->feature_queries()->perform(&eval); Feature_Block* ff = new (ctx.mem) Feature_Block(f->pstate(), static_cast(feature_queries), f->block()->perform(this)->block()); @@ -188,7 +188,7 @@ namespace Sass { Statement* Expand::operator()(Media_Block* m) { To_String to_string(&ctx); - Expression* mq = m->media_queries()->perform(eval.snapshot()); + Expression* mq = m->media_queries()->perform(&eval); mq = Parser::from_c_str(mq->perform(&to_string).c_str(), ctx, mq->pstate()).parse_media_queries(); Media_Block* mm = new (ctx.mem) Media_Block(m->pstate(), static_cast(mq), @@ -203,7 +203,7 @@ namespace Sass { in_at_root = true; Block* ab = a->block(); Expression* ae = a->expression(); - if (ae) ae = ae->perform(eval.snapshot()); + if (ae) ae = ae->perform(&eval); else ae = new (ctx.mem) At_Root_Expression(a->pstate()); Block* bb = ab ? ab->perform(this)->block() : 0; At_Root_Block* aa = new (ctx.mem) At_Root_Block(a->pstate(), @@ -220,9 +220,9 @@ namespace Sass { Selector* as = a->selector(); Expression* av = a->value(); selector_stack.push_back(0); - // Contextualize contextual(eval.snapshot()); - if (as) as = static_cast(as->perform(eval.snapshot())); - else if (av) av = av->perform(eval.snapshot()); + // Contextualize contextual(&eval); + if (as) as = static_cast(as->perform(&eval)); + else if (av) av = av->perform(&eval); selector_stack.pop_back(); Block* bb = ab ? ab->perform(this)->block() : 0; At_Rule* aa = new (ctx.mem) At_Rule(a->pstate(), @@ -236,8 +236,8 @@ namespace Sass { Statement* Expand::operator()(Declaration* d) { String* old_p = d->property(); - String* new_p = static_cast(old_p->perform(eval.snapshot())); - Expression* value = d->value()->perform(eval.snapshot()); + String* new_p = static_cast(old_p->perform(&eval)); + Expression* value = d->value()->perform(&eval); if (!value || (value->is_invisible() && !d->is_important())) return 0; Declaration* decl = new (ctx.mem) Declaration(d->pstate(), new_p, @@ -256,15 +256,15 @@ namespace Sass { if (env->has_global(var)) { Expression* e = dynamic_cast(env->get_global(var)); if (!e || e->concrete_type() == Expression::NULL_VAL) { - env->set_global(var, a->value()->perform(eval.snapshot())); + env->set_global(var, a->value()->perform(&eval)); } } else { - env->set_global(var, a->value()->perform(eval.snapshot())); + env->set_global(var, a->value()->perform(&eval)); } } else { - env->set_global(var, a->value()->perform(eval.snapshot())); + env->set_global(var, a->value()->perform(&eval)); } } else if (a->is_default()) { @@ -275,7 +275,7 @@ namespace Sass { if (AST_Node* node = cur->get_local(var)) { Expression* e = dynamic_cast(node); if (!e || e->concrete_type() == Expression::NULL_VAL) { - cur->set_local(var, a->value()->perform(eval.snapshot())); + cur->set_local(var, a->value()->perform(&eval)); } } else { @@ -291,19 +291,19 @@ namespace Sass { if (AST_Node* node = env->get_global(var)) { Expression* e = dynamic_cast(node); if (!e || e->concrete_type() == Expression::NULL_VAL) { - env->set_global(var, a->value()->perform(eval.snapshot())); + env->set_global(var, a->value()->perform(&eval)); } } } else if (env->is_lexical()) { - env->set_local(var, a->value()->perform(eval.snapshot())); + env->set_local(var, a->value()->perform(&eval)); } else { - env->set_local(var, a->value()->perform(eval.snapshot())); + env->set_local(var, a->value()->perform(&eval)); } } else { - env->set_lexical(var, a->value()->perform(eval.snapshot())); + env->set_lexical(var, a->value()->perform(&eval)); } return 0; } @@ -312,7 +312,7 @@ namespace Sass { { Import* result = new (ctx.mem) Import(imp->pstate()); for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) { - result->urls().push_back(imp->urls()[i]->perform(eval.snapshot())); + result->urls().push_back(imp->urls()[i]->perform(&eval)); } return result; } @@ -326,33 +326,33 @@ namespace Sass { Statement* Expand::operator()(Warning* w) { // eval handles this too, because warnings may occur in functions - w->perform(eval.snapshot()); + w->perform(&eval); return 0; } Statement* Expand::operator()(Error* e) { // eval handles this too, because errors may occur in functions - e->perform(eval.snapshot()); + e->perform(&eval); return 0; } Statement* Expand::operator()(Debug* d) { // eval handles this too, because warnings may occur in functions - d->perform(eval.snapshot()); + d->perform(&eval); return 0; } Statement* Expand::operator()(Comment* c) { // TODO: eval the text, once we're parsing/storing it as a String_Schema - return new (ctx.mem) Comment(c->pstate(), static_cast(c->text()->perform(eval.snapshot())), c->is_important()); + return new (ctx.mem) Comment(c->pstate(), static_cast(c->text()->perform(&eval)), c->is_important()); } Statement* Expand::operator()(If* i) { - if (*i->predicate()->perform(eval.snapshot())) { + if (*i->predicate()->perform(&eval)) { append_block(i->consequent()); } else { @@ -367,11 +367,11 @@ namespace Sass { Statement* Expand::operator()(For* f) { string variable(f->variable()); - Expression* low = f->lower_bound()->perform(eval.snapshot()); + Expression* low = f->lower_bound()->perform(&eval); if (low->concrete_type() != Expression::NUMBER) { error("lower bound of `@for` directive must be numeric", low->pstate(), backtrace()); } - Expression* high = f->upper_bound()->perform(eval.snapshot()); + Expression* high = f->upper_bound()->perform(&eval); if (high->concrete_type() != Expression::NUMBER) { error("upper bound of `@for` directive must be numeric", high->pstate(), backtrace()); } @@ -422,7 +422,7 @@ namespace Sass { Statement* Expand::operator()(Each* e) { vector variables(e->variables()); - Expression* expr = e->list()->perform(eval.snapshot()); + Expression* expr = e->list()->perform(&eval); List* list = 0; Map* map = 0; if (expr->concrete_type() == Expression::MAP) { @@ -446,8 +446,8 @@ namespace Sass { if (map) { for (auto key : map->keys()) { - Expression* k = key->perform(eval.snapshot()); - Expression* v = map->at(key)->perform(eval.snapshot()); + Expression* k = key->perform(&eval); + Expression* v = map->at(key)->perform(&eval); if (variables.size() == 1) { List* variable = new (ctx.mem) List(map->pstate(), 2, List::SPACE); @@ -473,7 +473,7 @@ namespace Sass { } for (size_t j = 0, K = variables.size(); j < K; ++j) { if (j < variable->length()) { - env->set_local(variables[j], (*variable)[j]->perform(eval.snapshot())); + env->set_local(variables[j], (*variable)[j]->perform(&eval)); } else { env->set_local(variables[j], new (ctx.mem) Null(expr->pstate())); @@ -494,7 +494,7 @@ namespace Sass { { Expression* pred = w->predicate(); Block* body = w->block(); - while (*pred->perform(eval.snapshot())) { + while (*pred->perform(&eval)) { append_block(body); } return 0; @@ -513,9 +513,9 @@ namespace Sass { if (!extender) return 0; selector_stack.push_back(0); - // Contextualize contextual(eval.snapshot()); + // Contextualize contextual(&eval); Selector_List* selector_list = static_cast(e->selector()); - Selector_List* contextualized = static_cast(selector_list->perform(eval.snapshot())); + Selector_List* contextualized = static_cast(selector_list->perform(&eval)); // ToDo: remove once feature proves stable! // if (contextualized->length() != 1) { // error("selector groups may not be extended", extendee->pstate(), backtrace()); @@ -564,7 +564,7 @@ namespace Sass { Parameters* params = def->parameters(); Arguments* args = static_cast(c->arguments() - ->perform(eval.snapshot())); + ->perform(&eval)); Backtrace new_bt(backtrace(), c->pstate(), ", in mixin `" + c->name() + "`"); backtrace_stack.push_back(&new_bt); Env new_env(def->environment()); @@ -580,7 +580,7 @@ namespace Sass { thunk->environment(env); new_env.local_frame()["@content[m]"] = thunk; } - bind("mixin " + c->name(), params, args, ctx, &new_env, eval.snapshot()); + bind("mixin " + c->name(), params, args, ctx, &new_env, &eval); append_block(body); backtrace_stack.pop_back(); env_stack.pop_back(); From a9f2ca658d33f4b56d8e3de068680edb62cf8e90 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Mon, 18 May 2015 00:48:01 +0200 Subject: [PATCH 7/9] More clean ups [WIP] --- eval.cpp | 9 +++------ eval.hpp | 29 +++++++++-------------------- sass.cpp | 4 ++++ 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/eval.cpp b/eval.cpp index 6511fdc93b..bd728739e6 100644 --- a/eval.cpp +++ b/eval.cpp @@ -12,6 +12,9 @@ #include "util.hpp" #include "to_string.hpp" #include "inspect.hpp" +#include "environment.hpp" +#include "position.hpp" +#include "sass_values.h" #include "to_c.hpp" #include "context.hpp" #include "backtrace.hpp" @@ -33,12 +36,6 @@ namespace Sass { add, sub, mul, div, fmod }; - Eval::Eval(Eval* eval) - : exp(eval->exp), - ctx(eval->ctx), - listize(eval->listize) - { } - Eval::Eval(Expand& exp) : exp(exp), ctx(exp.ctx), diff --git a/eval.hpp b/eval.hpp index 4b35b039e7..42b15ba60c 100644 --- a/eval.hpp +++ b/eval.hpp @@ -2,33 +2,27 @@ #define SASS_EVAL_H #include - #include "context.hpp" -#include "position.hpp" -#include "operation.hpp" -#include "environment.hpp" #include "listize.hpp" -#include "sass_values.h" - +#include "operation.hpp" namespace Sass { using namespace std; - typedef Environment Env; - struct Backtrace; - class Listize; class Expand; + class Context; + class Listize; class Eval : public Operation_CRTP { - + private: + string interpolation(Expression* s); Expression* fallback_impl(AST_Node* n); - public: - Expand& exp; - Context& ctx; - Listize listize; - Eval(Eval* eval); + public: + Expand& exp; + Context& ctx; + Listize listize; Eval(Expand& exp); virtual ~Eval(); @@ -37,7 +31,6 @@ namespace Sass { Selector* selector(); Backtrace* stacktrace(); - Eval* snapshot(); // for setting the env before eval'ing an expression using Operation::operator(); // for evaluating function bodies @@ -87,13 +80,9 @@ namespace Sass { Expression* operator()(Parent_Selector*); Expression* operator()(Attribute_Selector*); - template Expression* fallback(U x) { return fallback_impl(x); } - private: - string interpolation(Expression* s); - }; Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate = ParserState("[AST]")); diff --git a/sass.cpp b/sass.cpp index dbec8dacad..bc73a99aa2 100644 --- a/sass.cpp +++ b/sass.cpp @@ -7,6 +7,10 @@ #include "file.hpp" #include "util.hpp" +#ifdef _MSC_VER +#define LIBSASS_VERSION "1.0.0" +#endif + extern "C" { using namespace std; using namespace Sass; From dd7e37e44ba2e2b5cdbdc4dd154765a8ebbc33ea Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Mon, 18 May 2015 04:18:03 +0200 Subject: [PATCH 8/9] Add performance improvements [WIP] --- ast.cpp | 28 +++++++++-------------- context.cpp | 2 +- environment.hpp | 35 ++++++++++++++++++++-------- eval.cpp | 30 ++++++++++++++++-------- expand.cpp | 1 + expand.hpp | 1 + functions.cpp | 3 ++- lexer.hpp | 59 +++++++++++++++++++++++++++++++++++++++++------- position.cpp | 6 ++--- position.hpp | 8 +++---- sass.cpp | 4 ---- sass_context.cpp | 4 ++-- 12 files changed, 121 insertions(+), 60 deletions(-) diff --git a/ast.cpp b/ast.cpp index 1f39c4360b..fb52274fbc 100644 --- a/ast.cpp +++ b/ast.cpp @@ -641,17 +641,17 @@ namespace Sass { string Number::unit() const { - stringstream u; + string u; for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) { - if (i) u << '*'; - u << numerator_units_[i]; + if (i) u += '*'; + u += numerator_units_[i]; } - if (!denominator_units_.empty()) u << '/'; + if (!denominator_units_.empty()) u += '/'; for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) { - if (i) u << '*'; - u << denominator_units_[i]; + if (i) u += '*'; + u += denominator_units_[i]; } - return u.str(); + return u; } bool Number::is_unitless() @@ -842,17 +842,11 @@ namespace Sass { bool Number::operator== (Expression* rhs) const { - try - { - Number l(pstate_, value_, unit()); - Number& r = dynamic_cast(*rhs); - l.normalize(find_convertible_unit()); - r.normalize(find_convertible_unit()); - return l.unit() == r.unit() && - l.value() == r.value(); + if (Number* r = static_cast(rhs)) { + return (value() == r->value()) && + (numerator_units_ == r->numerator_units_) && + (denominator_units_ == r->denominator_units_); } - catch (std::bad_cast&) {} - catch (...) { throw; } return false; } diff --git a/context.cpp b/context.cpp index 12e7f6e888..9653b166fb 100644 --- a/context.cpp +++ b/context.cpp @@ -318,7 +318,7 @@ namespace Sass { 0, 0 ); import_stack.push_back(import); - Parser p(Parser::from_c_str(queue[i].source, *this, ParserState(queue[i].abs_path, queue[i].source, i))); + Parser p(Parser::from_c_str(queue[i].source, *this, ParserState(queue[i].abs_path.c_str(), queue[i].source, i))); Block* ast = p.parse(); sass_delete_import(import_stack.back()); import_stack.pop_back(); diff --git a/environment.hpp b/environment.hpp index 3c7a2e2ff2..48a850e654 100644 --- a/environment.hpp +++ b/environment.hpp @@ -1,9 +1,9 @@ #ifndef SASS_ENVIRONMENT_H #define SASS_ENVIRONMENT_H -#include #include #include +#include #include "ast_fwd_decl.hpp" #include "ast_def_macros.hpp" @@ -11,21 +11,21 @@ namespace Sass { using std::string; - using std::map; + using std::unordered_map; using std::cerr; using std::endl; template class Environment { // TODO: test with unordered_map - map local_frame_; + unordered_map local_frame_; ADD_PROPERTY(Environment*, parent); public: Memory_Manager mem; - Environment() : local_frame_(map()), parent_(0) { } - Environment(Environment* env) : local_frame_(map()), parent_(env) { } - Environment(Environment& env) : local_frame_(map()), parent_(&env) { } + Environment() : local_frame_(unordered_map()), parent_(0) { } + Environment(Environment* env) : local_frame_(unordered_map()), parent_(env) { } + Environment(Environment& env) : local_frame_(unordered_map()), parent_(&env) { } // link parent to create a stack void link(Environment& env) { parent_ = &env; } @@ -42,19 +42,19 @@ namespace Sass { // there is still a parent around // not sure what it is actually use for // I guess we store functions etc. there - bool is_root_scope() const + bool is_global() const { return parent_ && ! parent_->parent_; } // scope operates on the current frame - map& local_frame() { + unordered_map& local_frame() { return local_frame_; } bool has_local(const string& key) const - { return local_frame_.count(key) != 0; } + { return local_frame_.find(key) != local_frame_.end(); } T& get_local(const string& key) { return local_frame_[key]; } @@ -119,6 +119,21 @@ namespace Sass { set_local(key, val); } + // see if we have a lexical we could update + // either update already existing lexical value + // or if flag is set, we create one if no lexical found + T& get_lexical(const string& key) + { + auto cur = this; + while (cur) { + if (cur->has_local(key)) { + return cur->get_local(key); + } + cur = cur->parent_; + } + return get_local(key); + } + // look on the full stack for key // include all scopes available bool has(const string& key) const @@ -149,7 +164,7 @@ namespace Sass { #ifdef DEBUG void print() { - for (typename map::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) { + for (typename unordered_map::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) { cerr << i->first << endl; } if (parent_) { diff --git a/eval.cpp b/eval.cpp index bd728739e6..1a5a44dd79 100644 --- a/eval.cpp +++ b/eval.cpp @@ -448,6 +448,7 @@ namespace Sass { // if one of the operands is a '/' then make sure it's evaluated Expression* lhs = b->left()->perform(this); lhs->is_delayed(false); + while (typeid(*lhs) == typeid(Binary_Expression)) lhs = lhs->perform(this); switch (op_type) { @@ -478,8 +479,8 @@ namespace Sass { } else { - rhs->is_delayed(false); - rhs = rhs->perform(this); + // rhs->set_delayed(false); + // rhs = rhs->perform(this); } // see if it's a relational expression @@ -797,12 +798,18 @@ namespace Sass { Expression* Eval::operator()(Number* n) { - n->normalize(); - // behave according to as ruby sass (add leading zero) - return new (ctx.mem) Number(n->pstate(), - n->value(), - n->unit(), - true); + return n; + // we may not even need a copy after all + // we do not copy string constants either + /* + if (n->is_expanded()) return n; + Number* nn = new (ctx.mem) Number(n->pstate(), + n->value(), + n->unit(), + true); + nn->is_expanded(true); + return nn; + */ } Expression* Eval::operator()(Boolean* b) @@ -1056,8 +1063,11 @@ namespace Sass { } break; case Expression::NUMBER: { - return *static_cast(lhs) == - *static_cast(rhs); + Number* l = static_cast(lhs); + Number* r = static_cast(rhs); + return (l->value() == r->value()) && + (l->numerator_units() == r->numerator_units()) && + (l->denominator_units() == r->denominator_units()); } break; case Expression::COLOR: { diff --git a/expand.cpp b/expand.cpp index 91e089996b..349a8a697a 100644 --- a/expand.cpp +++ b/expand.cpp @@ -18,6 +18,7 @@ namespace Sass { Expand::Expand(Context& ctx, Env* env, Backtrace* bt) : ctx(ctx), eval(Eval(*this)), + com_stack(vector()), env_stack(vector()), block_stack(vector()), property_stack(vector()), diff --git a/expand.hpp b/expand.hpp index 29b1392260..9f138601b8 100644 --- a/expand.hpp +++ b/expand.hpp @@ -31,6 +31,7 @@ namespace Sass { Eval eval; // it's easier to work with vectors + vector com_stack; vector env_stack; vector block_stack; vector property_stack; diff --git a/functions.cpp b/functions.cpp index ff7aa7ebda..7b5181e789 100644 --- a/functions.cpp +++ b/functions.cpp @@ -1207,7 +1207,8 @@ namespace Sass { { List* l = dynamic_cast(env["$list"]); Expression* v = ARG("$val", Expression); - String_Constant* sep = ARG("$separator", String_Constant); + // return v; + String_Constant* sep = ARG("$separator", String_Constant); if (!l) { l = new (ctx.mem) List(pstate, 1); *l << ARG("$list", Expression); diff --git a/lexer.hpp b/lexer.hpp index 36121a5f24..008bbd18d1 100644 --- a/lexer.hpp +++ b/lexer.hpp @@ -142,26 +142,69 @@ namespace Sass { // Tries supplied matchers in order. // Succeeds if one of them succeeds. // Regex equivalent: /(?:FOO|BAR)/ - template + template const char* alternatives(const char* src) { const char* rslt; - for (prelexer mx : { mxs... }) { - if ((rslt = mx(src))) return rslt; - } + if ((rslt = mx(src))) return rslt; return 0; } + template + const char* alternatives(const char* src) { + const char* rslt; + if ((rslt = mx1(src))) return rslt; + if ((rslt = mx2(src))) return rslt; + return 0; + } + template + const char* alternatives(const char* src) { + const char* rslt; + if ((rslt = mx1(src))) return rslt; + if ((rslt = mx2(src))) return rslt; + if ((rslt = mx3(src))) return rslt; + return 0; + } + template + const char* alternatives(const char* src) { + const char* rslt; + if ((rslt = mx1(src))) return rslt; + if ((rslt = mx2(src))) return rslt; + if ((rslt = mx3(src))) return rslt; + return alternatives(src); + } // Tries supplied matchers in order. // Succeeds if all of them succeeds. // Regex equivalent: /(?:FOO)(?:BAR)/ - template + template const char* sequence(const char* src) { const char* rslt = src; - for (prelexer mx : { mxs... }) { - if (!(rslt = mx(rslt))) return 0; - } + if (!(rslt = mx1(rslt))) return 0; return rslt; } + template + const char* sequence(const char* src) { + const char* rslt = src; + if (!(rslt = mx1(rslt))) return 0; + if (!(rslt = mx2(rslt))) return 0; + return rslt; + } + template + const char* sequence(const char* src) { + const char* rslt = src; + if (!(rslt = mx1(rslt))) return 0; + if (!(rslt = mx2(rslt))) return 0; + if (!(rslt = mx3(rslt))) return 0; + return rslt; + } + template + const char* sequence(const char* src) { + const char* rslt = src; + if (!(rslt = mx1(rslt))) return 0; + if (!(rslt = mx2(rslt))) return 0; + if (!(rslt = mx3(rslt))) return 0; + return sequence(rslt); + } + // Match a pattern or not. Always succeeds. // Regex equivalent: /(?:literal)?/ diff --git a/position.cpp b/position.cpp index 31b7a733e1..fae784c557 100644 --- a/position.cpp +++ b/position.cpp @@ -96,13 +96,13 @@ namespace Sass { : Offset(line, column), file(file) { } - ParserState::ParserState(string path, const char* src, const size_t file) + ParserState::ParserState(const char* path, const char* src, const size_t file) : Position(file, 0, 0), path(path), src(src), offset(0, 0), token() { } - ParserState::ParserState(string path, const char* src, Position position, Offset offset) + ParserState::ParserState(const char* path, const char* src, const Position& position, Offset offset) : Position(position), path(path), src(src), offset(offset), token() { } - ParserState::ParserState(string path, const char* src, Token token, Position position, Offset offset) + ParserState::ParserState(const char* path, const char* src, const Token& token, const Position& position, Offset offset) : Position(position), path(path), src(src), offset(offset), token(token) { } Position Position::add(const char* begin, const char* end) diff --git a/position.hpp b/position.hpp index 829ae6e6b2..5477cb4648 100644 --- a/position.hpp +++ b/position.hpp @@ -104,9 +104,9 @@ namespace Sass { class ParserState : public Position { public: // c-tor - ParserState(string path, const char* src = 0, const size_t file = string::npos); - ParserState(string path, const char* src, Position position, Offset offset = Offset(0, 0)); - ParserState(string path, const char* src, Token token, Position position, Offset offset = Offset(0, 0)); + ParserState(const char* path, const char* src = 0, const size_t file = string::npos); + ParserState(const char* path, const char* src, const Position& position, Offset offset = Offset(0, 0)); + ParserState(const char* path, const char* src, const Token& token, const Position& position, Offset offset = Offset(0, 0)); public: // down casts Offset off() { return *this; }; @@ -114,7 +114,7 @@ namespace Sass { ParserState pstate() { return *this; }; public: - string path; + const char* path; const char* src; Offset offset; Token token; diff --git a/sass.cpp b/sass.cpp index bc73a99aa2..dbec8dacad 100644 --- a/sass.cpp +++ b/sass.cpp @@ -7,10 +7,6 @@ #include "file.hpp" #include "util.hpp" -#ifdef _MSC_VER -#define LIBSASS_VERSION "1.0.0" -#endif - extern "C" { using namespace std; using namespace Sass; diff --git a/sass_context.cpp b/sass_context.cpp index e5e9f33334..d555f65282 100644 --- a/sass_context.cpp +++ b/sass_context.cpp @@ -230,7 +230,7 @@ extern "C" { string cwd(Sass::File::get_cwd()); JsonNode* json_err = json_mkobject(); json_append_member(json_err, "status", json_mknumber(1)); - json_append_member(json_err, "file", json_mkstring(e.pstate.path.c_str())); + json_append_member(json_err, "file", json_mkstring(e.pstate.path)); json_append_member(json_err, "line", json_mknumber(e.pstate.line+1)); json_append_member(json_err, "column", json_mknumber(e.pstate.column+1)); json_append_member(json_err, "message", json_mkstring(e.message.c_str())); @@ -278,7 +278,7 @@ extern "C" { c_ctx->error_message = sass_strdup(msg_stream.str().c_str()); c_ctx->error_text = sass_strdup(e.message.c_str()); c_ctx->error_status = 1; - c_ctx->error_file = sass_strdup(e.pstate.path.c_str()); + c_ctx->error_file = sass_strdup(e.pstate.path); c_ctx->error_line = e.pstate.line+1; c_ctx->error_column = e.pstate.column+1; c_ctx->error_src = e.pstate.src; From 8671263f0bf0f945f85d6298f9f6dc8f33945212 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Mon, 18 May 2015 18:29:25 +0200 Subject: [PATCH 9/9] Fix windows build (leaks memory) [WIP] --- ast.hpp | 14 +++++++------- context.cpp | 21 +++++++++++---------- cssize.cpp | 5 +++++ cssize.hpp | 1 + environment.hpp | 6 ++++++ eval.cpp | 1 - expand.cpp | 3 +-- expand.hpp | 1 - functions.cpp | 7 +++---- parser.cpp | 2 +- 10 files changed, 35 insertions(+), 26 deletions(-) diff --git a/ast.hpp b/ast.hpp index af7506532c..1176fcc766 100644 --- a/ast.hpp +++ b/ast.hpp @@ -648,7 +648,7 @@ namespace Sass { ADD_PROPERTY(Native_Function, native_function); ADD_PROPERTY(Sass_Function_Entry, c_function); ADD_PROPERTY(void*, cookie); - ADD_PROPERTY(Context*, ctx); + // ADD_PROPERTY(Context*, ctx); ADD_PROPERTY(bool, is_overload_stub); ADD_PROPERTY(Signature, signature); public: @@ -656,7 +656,7 @@ namespace Sass { string n, Parameters* params, Block* b, - Context* ctx, + // Context* ctx, Type t) : Has_Block(pstate, b), name_(n), @@ -666,7 +666,7 @@ namespace Sass { native_function_(0), c_function_(0), cookie_(0), - ctx_(ctx), + // ctx_(ctx), is_overload_stub_(false), signature_(0) { } @@ -675,7 +675,7 @@ namespace Sass { string n, Parameters* params, Native_Function func_ptr, - Context* ctx, + // Context* ctx, bool overload_stub = false) : Has_Block(pstate, 0), name_(n), @@ -685,7 +685,7 @@ namespace Sass { native_function_(func_ptr), c_function_(0), cookie_(0), - ctx_(ctx), + // ctx_(ctx), is_overload_stub_(overload_stub), signature_(sig) { } @@ -694,7 +694,7 @@ namespace Sass { string n, Parameters* params, Sass_Function_Entry c_func, - Context* ctx, + // Context* ctx, bool whatever, bool whatever2) : Has_Block(pstate, 0), @@ -705,7 +705,7 @@ namespace Sass { native_function_(0), c_function_(c_func), cookie_(sass_function_get_cookie(c_func)), - ctx_(ctx), + // ctx_(ctx), is_overload_stub_(false), signature_(sig) { } diff --git a/context.cpp b/context.cpp index 9653b166fb..9ae1e6bb6c 100644 --- a/context.cpp +++ b/context.cpp @@ -318,7 +318,8 @@ namespace Sass { 0, 0 ); import_stack.push_back(import); - Parser p(Parser::from_c_str(queue[i].source, *this, ParserState(queue[i].abs_path.c_str(), queue[i].source, i))); + const char* path = sass_strdup(queue[i].abs_path.c_str()); + Parser p(Parser::from_c_str(queue[i].source, *this, ParserState(path, queue[i].source, i))); Block* ast = p.parse(); sass_delete_import(import_stack.back()); import_stack.pop_back(); @@ -333,9 +334,9 @@ namespace Sass { Env global; // create root environment // register built-in functions on env register_built_in_functions(*this, &global); - for (size_t i = 0, S = c_functions.size(); i < S; ++i) { - register_c_function(*this, &global, c_functions[i]); - } + // register custom functions (defined via C-API) + for (size_t i = 0, S = c_functions.size(); i < S; ++i) + { register_c_function(*this, &global, c_functions[i]); } // create initial backtrace entry Backtrace backtrace(0, ParserState("", 0), ""); // create crtp visitor objects @@ -451,12 +452,12 @@ namespace Sass { void register_overload_stub(Context& ctx, string name, Env* env) { Definition* stub = new (ctx.mem) Definition(ParserState("[built-in function]"), - 0, - name, - 0, - 0, - &ctx, - true); + 0, + name, + 0, + 0, + // &ctx, + true); (*env)[name + "[f]"] = stub; } diff --git a/cssize.cpp b/cssize.cpp index 2a93fde993..12a4f92c3b 100644 --- a/cssize.cpp +++ b/cssize.cpp @@ -136,6 +136,11 @@ namespace Sass { return rules; } + Statement* Cssize::operator()(Null* m) + { + return 0; + } + Statement* Cssize::operator()(Media_Block* m) { if (parent()->statement_type() == Statement::RULESET) diff --git a/cssize.hpp b/cssize.hpp index 93034fd27e..1e495de6d0 100644 --- a/cssize.hpp +++ b/cssize.hpp @@ -56,6 +56,7 @@ namespace Sass { // Statement* operator()(Definition*); // Statement* operator()(Mixin_Call*); // Statement* operator()(Content*); + Statement* operator()(Null*); Statement* parent(); vector> slice_by_bubble(Statement*); diff --git a/environment.hpp b/environment.hpp index 48a850e654..583b8d531b 100644 --- a/environment.hpp +++ b/environment.hpp @@ -161,6 +161,12 @@ namespace Sass { return get_local(key); } + // copy everything from environment + void assign(const Environment& env) + { + // copy the complete local environment frame into our own local frame + local_frame_.insert(env.local_frame_.begin(), env.local_frame_.end()); + } #ifdef DEBUG void print() { diff --git a/eval.cpp b/eval.cpp index 1a5a44dd79..9c9eb8fcf2 100644 --- a/eval.cpp +++ b/eval.cpp @@ -448,7 +448,6 @@ namespace Sass { // if one of the operands is a '/' then make sure it's evaluated Expression* lhs = b->left()->perform(this); lhs->is_delayed(false); - while (typeid(*lhs) == typeid(Binary_Expression)) lhs = lhs->perform(this); switch (op_type) { diff --git a/expand.cpp b/expand.cpp index 349a8a697a..3db63d889c 100644 --- a/expand.cpp +++ b/expand.cpp @@ -18,7 +18,6 @@ namespace Sass { Expand::Expand(Context& ctx, Env* env, Backtrace* bt) : ctx(ctx), eval(Eval(*this)), - com_stack(vector()), env_stack(vector()), block_stack(vector()), property_stack(vector()), @@ -576,7 +575,7 @@ namespace Sass { "@content", new (ctx.mem) Parameters(c->pstate()), c->block(), - &ctx, + // &ctx, Definition::MIXIN); thunk->environment(env); new_env.local_frame()["@content[m]"] = thunk; diff --git a/expand.hpp b/expand.hpp index 9f138601b8..29b1392260 100644 --- a/expand.hpp +++ b/expand.hpp @@ -31,7 +31,6 @@ namespace Sass { Eval eval; // it's easier to work with vectors - vector com_stack; vector env_stack; vector block_stack; vector property_stack; diff --git a/functions.cpp b/functions.cpp index 7b5181e789..5c581003a2 100644 --- a/functions.cpp +++ b/functions.cpp @@ -47,7 +47,7 @@ namespace Sass { name, params, func, - &ctx, + // &ctx, false); } @@ -68,7 +68,7 @@ namespace Sass { name, params, c_func, - &ctx, + // &ctx, false, true); } @@ -1207,8 +1207,7 @@ namespace Sass { { List* l = dynamic_cast(env["$list"]); Expression* v = ARG("$val", Expression); - // return v; - String_Constant* sep = ARG("$separator", String_Constant); + String_Constant* sep = ARG("$separator", String_Constant); if (!l) { l = new (ctx.mem) List(pstate, 1); *l << ARG("$list", Expression); diff --git a/parser.cpp b/parser.cpp index 655dbf6906..486b1a3a14 100644 --- a/parser.cpp +++ b/parser.cpp @@ -321,7 +321,7 @@ namespace Sass { else stack.push_back(function_def); Block* body = parse_block(); stack.pop_back(); - Definition* def = new (ctx.mem) Definition(source_position_of_def, name, params, body, &ctx, which_type); + Definition* def = new (ctx.mem) Definition(source_position_of_def, name, params, body, which_type); return def; }