Skip to content

Commit

Permalink
Enable full evaluation before logical operators
Browse files Browse the repository at this point in the history
  • Loading branch information
mgreter committed Apr 30, 2015
1 parent 060c498 commit b5ac186
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 26 deletions.
39 changes: 33 additions & 6 deletions ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,19 +813,46 @@ 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
{
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))
Expand Down
60 changes: 43 additions & 17 deletions ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
};
}
Expand Down Expand Up @@ -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()
{
Expand All @@ -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();
};

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
58 changes: 57 additions & 1 deletion debugger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -374,35 +375,54 @@ 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;
string name(expression->name());
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;
debug_ast(expression->name(), ind + "name: ", env);
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() << "]";
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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()) << "]" <<
Expand All @@ -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}" : "") <<
Expand All @@ -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() <<
Expand All @@ -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() <<
Expand Down
19 changes: 17 additions & 2 deletions eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit b5ac186

Please sign in to comment.