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..fb52274fbc 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; @@ -681,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() @@ -882,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/ast.hpp b/ast.hpp index bbf70f8f98..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) { } @@ -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..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 }; @@ -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..1543d624ce 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 @@ -227,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; - Contextualize* old_context = eval->contextualize; - Expression* dv = leftover->default_value()->perform(eval->with(env, eval->backtrace)); - eval->env = old_env; - eval->backtrace = old_bt; - eval->contextualize = old_context; - // dv->perform(&to_string); + Expression* dv = leftover->default_value()->perform(eval); env->local_frame()[leftover->name()] = dv; } else { diff --git a/context.cpp b/context.cpp index 5620764072..9ae1e6bb6c 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" @@ -311,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( @@ -319,38 +318,52 @@ 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))); + 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(); 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; + + Env global; // create root environment + // register built-in functions on env + register_built_in_functions(*this, &global); + // 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), ""); - register_built_in_functions(*this, &tge); - 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); - Cssize cssize(*this, &tge, &backtrace); + // 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() { @@ -439,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/contextualize.cpp b/contextualize.cpp deleted file mode 100644 index fca78c41cd..0000000000 --- a/contextualize.cpp +++ /dev/null @@ -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 deleted file mode 100644 index 7efccd1c08..0000000000 --- a/contextualize.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#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 deleted file mode 100644 index ba2b25d1d5..0000000000 --- a/contextualize_eval.cpp +++ /dev/null @@ -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 deleted file mode 100644 index 738b4d606d..0000000000 --- a/contextualize_eval.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#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/cssize.cpp b/cssize.cpp index 5f9dc5243f..12a4f92c3b 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; } @@ -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 1389965393..1e495de6d0 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; @@ -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/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..583b8d531b 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,19 +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() : 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; } @@ -40,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); } + { return local_frame_.find(key) != local_frame_.end(); } T& get_local(const string& key) { return local_frame_[key]; } @@ -117,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 @@ -144,10 +161,16 @@ 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() { - 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 18c98a3475..9c9eb8fcf2 100644 --- a/eval.cpp +++ b/eval.cpp @@ -12,11 +12,15 @@ #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" #include "prelexer.hpp" #include "parser.hpp" +#include "expand.hpp" namespace Sass { using namespace std; @@ -32,24 +36,31 @@ 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(Expand& exp) + : exp(exp), + ctx(exp.ctx), + listize(exp.ctx) + { } Eval::~Eval() { } - Eval* Eval::with(Env* e, Backtrace* bt) // 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; } - Eval* Eval::with(Selector* c, Env* e, Backtrace* bt, Selector* p, Selector* ex) // for setting the env before eval'ing an expression + Env* Eval::environment() { - contextualize = contextualize->with(c, e, bt, p, ex); - env = e; - backtrace = bt; - return this; + return exp.environment(); + } + + Selector* Eval::selector() + { + return exp.selector(); + } + + Backtrace* Eval::stacktrace() + { + return exp.backtrace(); } Expression* Eval::operator()(Block* b) @@ -64,6 +75,7 @@ namespace Sass { Expression* Eval::operator()(Assignment* a) { + Env* env = environment(); string var(a->variable()); if (a->is_global()) { if (a->is_default()) { @@ -124,14 +136,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 @@ -154,11 +170,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); @@ -197,6 +214,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) { @@ -287,6 +305,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]")) { @@ -308,7 +327,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; @@ -319,6 +338,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]")) { @@ -348,6 +368,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]")) { @@ -457,8 +478,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 @@ -535,10 +556,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]"); @@ -547,80 +568,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; - new_env.link(def->environment()); - // 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) { + Env fn_env(def->environment()); + exp.env_stack.push_back(&fn_env); - 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 = 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()); @@ -631,63 +636,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) @@ -697,6 +672,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; } @@ -714,6 +690,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; @@ -750,6 +727,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; @@ -817,12 +797,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) @@ -843,6 +829,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()) { @@ -857,6 +844,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 +885,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 +902,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 +1042,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); @@ -1088,8 +1062,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: { @@ -1366,4 +1343,141 @@ 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 = 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 86e95eee83..42b15ba60c 100644 --- a/eval.hpp +++ b/eval.hpp @@ -2,38 +2,35 @@ #define SASS_EVAL_H #include - #include "context.hpp" -#include "position.hpp" -#include "operation.hpp" -#include "environment.hpp" -#include "contextualize.hpp" #include "listize.hpp" -#include "sass_values.h" +#include "operation.hpp" namespace Sass { using namespace std; - typedef Environment Env; - struct Backtrace; - class Contextualize; + class Expand; + class Context; class Listize; class Eval : public Operation_CRTP { - Context& ctx; - + private: + string interpolation(Expression* s); Expression* fallback_impl(AST_Node* n); - public: - Contextualize* contextualize; - Listize* listize; - Env* env; - Backtrace* backtrace; - Eval(Context&, Contextualize*, Listize*, Env*, Backtrace*); + public: + Expand& exp; + Context& ctx; + Listize listize; + Eval(Expand& exp); 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(); + using Operation::operator(); // for evaluating function bodies @@ -69,14 +66,23 @@ 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); } - private: - string interpolation(Expression* s); - }; Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate = ParserState("[AST]")); diff --git a/expand.cpp b/expand.cpp index 5b18edd713..3db63d889c 100644 --- a/expand.cpp +++ b/expand.cpp @@ -1,10 +1,13 @@ +#ifdef _MSC_VER +#pragma warning(disable : 4503) +#endif + #include #include #include "expand.hpp" #include "bind.hpp" #include "eval.hpp" -#include "contextualize_eval.hpp" #include "to_string.hpp" #include "backtrace.hpp" #include "context.hpp" @@ -12,54 +15,106 @@ 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)), + 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) + { + for (size_t i = 0, L = b->length(); i < L; ++i) { + Statement* ith = (*b)[i]->perform(this); + if (ith) *block_stack.back() << 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); + k->selector(static_cast(r->selector()->perform(&eval))); + 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); + 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 + // At least only re-parse selector schemas Emitter emitter(&ctx); Inspect isp(emitter); sel_ctx->perform(&isp); @@ -67,7 +122,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 +130,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 +139,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; } @@ -107,11 +147,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() @@ -122,13 +160,13 @@ 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 } 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); 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); 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,44 @@ 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); 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); + 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(), 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)); + 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, value, @@ -213,22 +249,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)); } } else { - env->set_global(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_global(var, a->value()->perform(&eval)); } } else { - env->set_global(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_global(var, a->value()->perform(&eval)); } } else if (a->is_default()) { @@ -239,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->with(p, env, backtrace))); + cur->set_local(var, a->value()->perform(&eval)); } } else { @@ -255,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->with(p, env, backtrace))); + env->set_global(var, a->value()->perform(&eval)); } } } 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)); } else { - env->set_local(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_local(var, a->value()->perform(&eval)); } } else { - env->set_lexical(var, a->value()->perform(eval->with(p, env, backtrace))); + env->set_lexical(var, a->value()->perform(&eval)); } return 0; } @@ -276,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->with(env, backtrace))); + result->urls().push_back(imp->urls()[i]->perform(&eval)); } return result; } @@ -290,33 +326,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); 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); 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); 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)), c->is_important()); } Statement* Expand::operator()(If* i) { - if (*i->predicate()->perform(eval->with(env, backtrace))) { + if (*i->predicate()->perform(&eval)) { append_block(i->consequent()); } else { @@ -331,13 +367,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); 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); 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 +382,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 +422,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); List* list = 0; Map* map = 0; if (expr->concrete_type() == Expression::MAP) { @@ -399,6 +436,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 +446,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); + Expression* v = map->at(key)->perform(&eval); if (variables.size() == 1) { List* variable = new (ctx.mem) List(map->pstate(), 2, List::SPACE); @@ -435,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->with(env, backtrace))); + env->set_local(variables[j], (*variable)[j]->perform(&eval)); } else { env->set_local(variables[j], new (ctx.mem) Null(expr->pstate())); @@ -456,7 +494,7 @@ namespace Sass { { Expression* pred = w->predicate(); Block* body = w->block(); - while (*pred->perform(eval->with(env, backtrace))) { + while (*pred->perform(&eval)) { append_block(body); } return 0; @@ -464,7 +502,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 +511,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); 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)); // 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 +537,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,43 +554,42 @@ 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)); + 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(), "@content", new (ctx.mem) Parameters(c->pstate()), c->block(), - &ctx, + // &ctx, Definition::MIXIN); 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); 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(), @@ -557,19 +598,13 @@ namespace Sass { return call->perform(this); } + // produce an error if something is not implemented inline Statement* Expand::fallback_impl(AST_Node* n) { - 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()); + 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()); 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..29b1392260 100644 --- a/expand.hpp +++ b/expand.hpp @@ -9,35 +9,41 @@ #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..c8c78a948d 100644 --- a/extend.cpp +++ b/extend.cpp @@ -1,6 +1,9 @@ +#ifdef _MSC_VER +#pragma warning(disable : 4503) +#endif + #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..5c581003a2 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" @@ -46,7 +47,7 @@ namespace Sass { name, params, func, - &ctx, + // &ctx, false); } @@ -67,7 +68,7 @@ namespace Sass { name, params, c_func, - &ctx, + // &ctx, false, true); } @@ -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/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/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/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..486b1a3a14 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); } @@ -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; } @@ -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<';'> > >()) { @@ -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/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/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 24e02f1e07..d555f65282 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" @@ -226,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())); @@ -272,9 +276,9 @@ 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_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; @@ -290,7 +294,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 +308,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 +322,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 +336,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 +669,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 +784,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); } 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) { 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 @@ - -