diff --git a/ast.cpp b/ast.cpp index 74d2127c67..0bf8339f55 100644 --- a/ast.cpp +++ b/ast.cpp @@ -813,12 +813,18 @@ namespace Sass { bool Number::operator== (Expression* rhs) const { - Number l(pstate_, value_, unit()); - Number& r = dynamic_cast<Number&>(*rhs); - l.normalize(find_convertible_unit()); - r.normalize(find_convertible_unit()); - return l.unit() == r.unit() && - l.value() == r.value(); + try + { + Number l(pstate_, value_, unit()); + Number& r = dynamic_cast<Number&>(*rhs); + l.normalize(find_convertible_unit()); + r.normalize(find_convertible_unit()); + return l.unit() == r.unit() && + l.value() == r.value(); + } + catch (std::bad_cast&) {} + catch (...) { throw; } + return false; } bool Number::operator== (Expression& rhs) const @@ -826,6 +832,27 @@ namespace Sass { return operator==(&rhs); } + bool List::operator==(Expression* rhs) const + { + try + { + List* r = dynamic_cast<List*>(rhs); + if (!r || length() != r->length()) return false; + if (separator() != r->separator()) return false; + for (size_t i = 0, L = r->length(); i < L; ++i) + if (*elements()[i] != *(*r)[i]) return false; + return true; + } + catch (std::bad_cast&) {} + catch (...) { throw; } + return false; + } + + bool List::operator== (Expression& rhs) const + { + return operator==(&rhs); + } + Expression* Hashed::at(Expression* k) const { if (elements_.count(k)) diff --git a/ast.hpp b/ast.hpp index 2c99adc826..bdd5d183a3 100644 --- a/ast.hpp +++ b/ast.hpp @@ -113,6 +113,7 @@ namespace Sass { static string type_name() { return ""; } virtual bool is_false() { return false; } virtual bool operator==( Expression& rhs) const { return false; } + virtual void set_delayed(bool delayed) { is_delayed(delayed); } virtual size_t hash() { return 0; } }; } @@ -756,23 +757,8 @@ namespace Sass { bool is_invisible() { return !length(); } Expression* value_at_index(size_t i); - virtual bool operator==(Expression& rhs) const - { - try - { - List& l = dynamic_cast<List&>(rhs); - if (!(l && length() == l.length() && separator() == l.separator())) return false; - for (size_t i = 0, L = l.length(); i < L; ++i) - if (!(*(elements()[i]) == *(l[i]))) return false; - return true; - } - catch (std::bad_cast&) - { - return false; - } - catch (...) { throw; } - - } + virtual bool operator==(Expression& rhs) const; + virtual bool operator==(Expression* rhs) const; virtual size_t hash() { @@ -786,6 +772,13 @@ namespace Sass { return hash_; } + virtual void set_delayed(bool delayed) + { + for (size_t i = 0, L = length(); i < L; ++i) + (elements()[i])->set_delayed(delayed); + is_delayed(delayed); + } + ATTACH_OPERATIONS(); }; @@ -857,6 +850,31 @@ namespace Sass { Type t, Expression* lhs, Expression* rhs) : Expression(pstate), type_(t), left_(lhs), right_(rhs), hash_(0) { } + const string type_name() { + switch (type_) { + case AND: return "and"; break; + case OR: return "or"; break; + case EQ: return "eq"; break; + case NEQ: return "neq"; break; + case GT: return "gt"; break; + case GTE: return "gte"; break; + case LT: return "lt"; break; + case LTE: return "lte"; break; + case ADD: return "add"; break; + case SUB: return "sub"; break; + case MUL: return "mul"; break; + case DIV: return "div"; break; + case MOD: return "mod"; break; + case NUM_OPS: return "num_ops"; break; + default: return "invalid"; break; + } + } + virtual void set_delayed(bool delayed) + { + right()->set_delayed(delayed); + left()->set_delayed(delayed); + is_delayed(delayed); + } virtual bool operator==(Expression& rhs) const { try @@ -896,6 +914,14 @@ namespace Sass { Unary_Expression(ParserState pstate, Type t, Expression* o) : Expression(pstate), type_(t), operand_(o), hash_(0) { } + const string type_name() { + switch (type_) { + case PLUS: return "plus"; break; + case MINUS: return "minus"; break; + case NOT: return "not"; break; + default: return "invalid"; break; + } + } virtual bool operator==(Expression& rhs) const { try diff --git a/debugger.hpp b/debugger.hpp index dafcc06240..5e7bee38b2 100644 --- a/debugger.hpp +++ b/debugger.hpp @@ -290,6 +290,7 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) cerr << ind << "Import " << block; cerr << " (" << pstate_source_position(node) << ")"; cerr << " " << block->tabs() << endl; + debug_ast(block->media_queries(), ind + " @ "); // vector<string> files_; for (auto imp : block->urls()) debug_ast(imp, "@ ", env); } else if (dynamic_cast<Assignment*>(node)) { @@ -374,9 +375,14 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) else if (expression->type() == Textual::PERCENTAGE) cerr << " [PERCENTAGE]"; else if (expression->type() == Textual::DIMENSION) cerr << " [DIMENSION]"; else if (expression->type() == Textual::HEX) cerr << " [HEX]"; - cerr << expression << " [" << expression->value() << "]" << endl; + cerr << expression << " [" << expression->value() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; } else if (dynamic_cast<Variable*>(node)) { Variable* expression = dynamic_cast<Variable*>(node); + cerr << ind << "Variable " << expression << " [" << expression->name() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Variable " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << expression->name() << "]" << endl; @@ -384,6 +390,9 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) if (env && env->has(name)) debug_ast(static_cast<Expression*>((*env)[name]), ind + " -> ", env); } else if (dynamic_cast<Function_Call_Schema*>(node)) { Function_Call_Schema* expression = dynamic_cast<Function_Call_Schema*>(node); + cerr << ind << "Function_Call_Schema " << expression << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Function_Call_Schema " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << "" << endl; @@ -391,18 +400,29 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) debug_ast(expression->arguments(), ind + " args: ", env); } else if (dynamic_cast<Function_Call*>(node)) { Function_Call* expression = dynamic_cast<Function_Call*>(node); + cerr << ind << "Function_Call " << expression << " [" << expression->name() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Function_Call " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << expression->name() << "]" << endl; debug_ast(expression->arguments(), ind + " args: ", env); } else if (dynamic_cast<Arguments*>(node)) { Arguments* expression = dynamic_cast<Arguments*>(node); + cerr << ind << "Arguments " << expression << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Arguments " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << endl; for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Argument*>(node)) { Argument* expression = dynamic_cast<Argument*>(node); + cerr << ind << "Argument " << expression << " [" << expression->value() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + if (expression->is_rest_argument()) cerr << " [is_rest_argument]"; + if (expression->is_keyword_argument()) cerr << " [is_keyword_argument]"; + cerr << endl; cerr << ind << "Argument " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << expression->value() << "]"; @@ -427,12 +447,18 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) cerr << " [rest: " << expression->is_rest_parameter() << "] " << endl; } else if (dynamic_cast<Unary_Expression*>(node)) { Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node); + cerr << ind << "Unary_Expression " << expression << " [" << expression->type_name() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Unary_Expression " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << expression->type() << "]" << endl; debug_ast(expression->operand(), ind + " operand: ", env); } else if (dynamic_cast<Binary_Expression*>(node)) { Binary_Expression* expression = dynamic_cast<Binary_Expression*>(node); + cerr << ind << "Binary_Expression " << expression << " [" << expression->type_name() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Binary_Expression " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << expression->type() << "]" << endl; @@ -450,6 +476,9 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) cerr << " (" << expression->length() << ") " << (expression->separator() == Sass::List::Separator::COMMA ? "Comma " : "Space ") << " [delayed: " << expression->is_delayed() << "] " << + " [interpolant: " << expression->is_interpolant() << "]"; + if (expression->is_arglist()) cerr << " [is_arglist]"; + cerr << endl; " [interpolant: " << expression->is_interpolant() << "] " << " [arglist: " << expression->is_arglist() << "] " << endl; @@ -461,21 +490,36 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) cerr << " [Statement]" << endl; } else if (dynamic_cast<Boolean*>(node)) { Boolean* expression = dynamic_cast<Boolean*>(node); + cerr << ind << "Boolean " << expression << " [" << expression->value() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Boolean " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << expression->value() << "]" << endl; } else if (dynamic_cast<Color*>(node)) { Color* expression = dynamic_cast<Color*>(node); + cerr << ind << "Color " << expression << " [" << expression->r() << ":" << expression->g() << ":" << expression->b() << "@" << expression->a() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Color " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << expression->r() << ":" << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << endl; } else if (dynamic_cast<Number*>(node)) { Number* expression = dynamic_cast<Number*>(node); + cerr << ind << "Number " << expression << " [" << expression->value() << expression->unit() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + cerr << endl; cerr << ind << "Number " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << expression->value() << expression->unit() << "]" << endl; } else if (dynamic_cast<String_Quoted*>(node)) { String_Quoted* expression = dynamic_cast<String_Quoted*>(node); + cerr << ind << "String_Quoted : " << expression << " ["; + cerr << prettyprint(expression->value()) << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]"; + if (expression->quote_mark()) cerr << " [quote_mark]"; + cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl; cerr << ind << "String_Quoted : " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << prettyprint(expression->value()) << "]" << @@ -486,6 +530,11 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) } else if (dynamic_cast<String_Constant*>(node)) { String_Constant* expression = dynamic_cast<String_Constant*>(node); cerr << ind << "String_Constant : " << expression; + cerr << " [" << prettyprint(expression->value()) << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]"; + cerr " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl; + cerr << ind << "String_Constant : " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " [" << prettyprint(expression->value()) << "]" << (expression->is_delayed() ? " {delayed}" : "") << @@ -494,6 +543,10 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl; } else if (dynamic_cast<String_Schema*>(node)) { String_Schema* expression = dynamic_cast<String_Schema*>(node); + cerr << ind << "String_Schema " << expression << " [" << expression->concrete_type() << "]"; + if (expression->is_delayed()) cerr << " [delayed]"; + if (expression->has_interpolants()) cerr << " [has_interpolants]"; + cerr " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl; cerr << ind << "String_Schema " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << " " << expression->concrete_type() << @@ -502,6 +555,9 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0) for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<String*>(node)) { String* expression = dynamic_cast<String*>(node); + cerr << ind << "String " << expression << expression->concrete_type(); + if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]"; + cerr " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl; cerr << ind << "String " << expression; cerr << " (" << pstate_source_position(node) << ")"; cerr << expression->concrete_type() << diff --git a/eval.cpp b/eval.cpp index ff936a9cde..0da927c599 100644 --- a/eval.cpp +++ b/eval.cpp @@ -435,8 +435,23 @@ namespace Sass { } // not a logical connective, so go ahead and eval the rhs Expression* rhs = b->right()->perform(this); - rhs->is_delayed(false); - while (typeid(*rhs) == typeid(Binary_Expression)) rhs = rhs->perform(this); + // maybe fully evaluate structure + if (op_type == Binary_Expression::EQ || + op_type == Binary_Expression::NEQ || + op_type == Binary_Expression::GT || + op_type == Binary_Expression::GTE || + op_type == Binary_Expression::LT || + op_type == Binary_Expression::LTE) + { + rhs->is_expanded(false); + rhs->set_delayed(false); + rhs = rhs->perform(this); + } + else + { + rhs->is_delayed(false); + rhs = rhs->perform(this); + } // see if it's a relational expression switch(op_type) {