Commit 3238f08b by Aaron Leung

Evaluator is mostly working. Ironing out some intermittent bugs.

parent 53ac5d5f
build: sassc.cpp document.cpp node.cpp token.cpp prelexer.cpp build: sassc.cpp document.cpp node.cpp token.cpp prelexer.cpp
g++ -o bin/sassc sassc.cpp document.cpp document_parser.cpp document_emitter.cpp node.cpp token.cpp prelexer.cpp g++ -o bin/sassc sassc.cpp document.cpp document_parser.cpp evaluator.cpp document_emitter.cpp node.cpp token.cpp prelexer.cpp
test: build test: build
ruby spec.rb spec/basic/ ruby spec.rb spec/basic/
......
#include <map> #include <map>
#ifndef SASS_NODE_INCLUDED
#include "node.hpp" #include "node.hpp"
#endif
#include "context.hpp" #include "context.hpp"
namespace Sass { namespace Sass {
......
#include "document.hpp" #include "document.hpp"
#include "evaluator.hpp"
#include <iostream> #include <iostream>
namespace Sass { namespace Sass {
...@@ -50,8 +51,8 @@ namespace Sass { ...@@ -50,8 +51,8 @@ namespace Sass {
val.from_variable = true; val.from_variable = true;
val.eval_me = true; val.eval_me = true;
// context.environment[key] = eval(val); context.environment[key] = eval(val);
context.environment[key] = val; // context.environment[key] = val;
} }
Node Document::parse_ruleset() Node Document::parse_ruleset()
...@@ -311,17 +312,19 @@ namespace Sass { ...@@ -311,17 +312,19 @@ namespace Sass {
peek< exactly<'}'> >(position) || peek< exactly<'}'> >(position) ||
peek< exactly<')'> >(position) || peek< exactly<')'> >(position) ||
peek< exactly<','> >(position)) peek< exactly<','> >(position))
{ return expr1; } { return expr1.eval_me ? eval(expr1) : expr1; }
Node space_list(line_number, Node::space_list, 2); Node space_list(line_number, Node::space_list, 2);
space_list << expr1; // space_list << expr1;
space_list << (expr1.eval_me ? eval(expr1) : expr1);
while (!(peek< exactly<';'> >(position) || while (!(peek< exactly<';'> >(position) ||
peek< exactly<'}'> >(position) || peek< exactly<'}'> >(position) ||
peek< exactly<')'> >(position) || peek< exactly<')'> >(position) ||
peek< exactly<','> >(position))) peek< exactly<','> >(position)))
// { space_list << eval(parse_expression()); { Node expr(parse_expression());
{ space_list << parse_expression(); } space_list << (expr.eval_me ? eval(expr) : expr); }
// { space_list << parse_expression(); }
return space_list; return space_list;
} }
...@@ -336,6 +339,7 @@ namespace Sass { ...@@ -336,6 +339,7 @@ namespace Sass {
Node expression(line_number, Node::expression, 3); Node expression(line_number, Node::expression, 3);
term1.eval_me = true; term1.eval_me = true;
cerr << "Parsed an initial term: " << term1.to_string("") << endl;
expression << term1; expression << term1;
while (lex< exactly<'+'> >() || lex< exactly<'-'> >()) { while (lex< exactly<'+'> >() || lex< exactly<'-'> >()) {
...@@ -350,6 +354,8 @@ namespace Sass { ...@@ -350,6 +354,8 @@ namespace Sass {
expression << term; expression << term;
} }
expression.eval_me = true;
cerr << "parsed an expression: " << expression.to_string("") << endl;
return expression; return expression;
} }
...@@ -378,6 +384,11 @@ namespace Sass { ...@@ -378,6 +384,11 @@ namespace Sass {
term << fact; term << fact;
} }
// if (term.eval_me) {
// for (int i = 0; i < term.children->size(); i += 2) {
// term.children->at(i).eval_me = true;
// }
// }
return term; return term;
} }
...@@ -386,6 +397,9 @@ namespace Sass { ...@@ -386,6 +397,9 @@ namespace Sass {
if (lex< exactly<'('> >()) { if (lex< exactly<'('> >()) {
Node value(parse_list()); Node value(parse_list());
value.eval_me = true; value.eval_me = true;
if (value.type == Node::comma_list || value.type == Node::space_list) {
value.children->front().eval_me = true;
}
lex< exactly<')'> >(); lex< exactly<')'> >();
return value; return value;
} }
...@@ -396,17 +410,26 @@ namespace Sass { ...@@ -396,17 +410,26 @@ namespace Sass {
Node Document::parse_value() Node Document::parse_value()
{ {
lex< identifier >() || lex < dimension >() || if (lex< identifier >())
lex< percentage >() || lex < number >() || { return Node(line_number, Node::identifier, lexed); }
lex< hex >() || lex < string_constant >() ||
lex< variable >();
if (lexed.begin[0] == '$') { if (lex< percentage >())
return context.environment[lexed]; { return Node(line_number, Node::textual_percentage, lexed); }
}
else { if (lex< dimension >())
return Node(line_number, Node::value, lexed); { return Node(line_number, Node::textual_dimension, lexed); }
}
if (lex< number >())
{ return Node(line_number, Node::textual_number, lexed); }
if (lex< hex >())
{ return Node(line_number, Node::textual_hex, lexed); }
if (lex< string_constant >())
{ return Node(line_number, Node::string_constant, lexed); }
if (lex< variable >())
{ return context.environment[lexed]; }
} }
// const char* Document::look_for_rule(const char* start) // const char* Document::look_for_rule(const char* start)
......
#include "document.hpp" #include "evaluator.hpp"
#include <iostream> #include <iostream>
#include <cstdlib>
Node eval(const Node& expr) namespace Sass {
{ using std::cerr; using std::endl;
switch (expr.type)
Node eval(const Node& expr)
{ {
case expression: { cerr << "evaluating type " << expr.type << ": " << expr.to_string("") << endl;
Node acc(expr.line_number, Node::expression, eval(expr.children->at(0))); switch (expr.type)
Node rhs(eval(expr.children->at(2))); {
accumulate(expr.children->at(1).type, acc, rhs); case Node::comma_list:
for (int i = 3; i < expr.children->size(); i += 2) { case Node::space_list: {
Node rhs(eval(expr.children->at(i+1))); if (expr.eval_me) {
accumulate(expr.children->at(i), acc, rhs); *(expr.children->begin()) = eval(expr.children->front());
} }
return acc; return expr;
} break; } break;
case term: { case Node::expression: {
Node acc(expr.line_number, Node::expression, eval(expr.children->at(0)));
Node rhs(eval(expr.children->at(2)));
accumulate(expr.children->at(1).type, acc, rhs);
cerr << "blah" << endl;
for (int i = 3; i < expr.children->size(); i += 2) {
Node rhs(eval(expr.children->at(i+1)));
accumulate(expr.children->at(i).type, acc, rhs);
}
return acc.children->size() == 1 ? acc.children->front() : acc;
} break;
case Node::term: {
if (expr.eval_me) {
Node acc(expr.line_number, Node::expression, eval(expr.children->at(0)));
Node rhs(eval(expr.children->at(2)));
accumulate(expr.children->at(1).type, acc, rhs);
for (int i = 3; i < expr.children->size(); i += 2) {
Node rhs(eval(expr.children->at(i+1)));
accumulate(expr.children->at(i).type, acc, rhs);
}
return acc.children->size() == 1 ? acc.children->front() : acc;
}
else {
return expr;
}
} break;
case Node::textual_percentage:
case Node::textual_dimension: {
double numval = std::atof(expr.token.begin);
Token unit(Prelexer::number(expr.token.begin), expr.token.end);
return Node(expr.line_number, numval, unit);
} break;
case Node::textual_number: {
double numval = std::atof(expr.token.begin);
return Node(expr.line_number, numval);
} break;
case Node::textual_hex: {
long numval = std::strtol(expr.token.begin + 1, NULL, 16);
Node result(expr.line_number, numval);
result.is_hex = true;
return result;
} break;
} break; default: {
return expr;
}
}
} }
}
Node accumulate(const Node::Type op, Node& acc, const Node& rhs) Node accumulate(const Node::Type op, Node& acc, Node& rhs)
{ {
Node lhs(acc.children->back()); Node lhs(acc.children->back());
double lnum = lhs.numeric_value;
if (lhs.type == Node::number && rhs.type == Node::number) { double rnum = rhs.numeric_value;
Node result(acc.line_number, Node::number, operate(op, lhs, rhs));
acc.children->pop_back(); // cerr << "accumulate's args: " << lhs.to_string("") << "\t" << rhs.to_string("") << endl;
acc.children->push_back(result); // cerr << "accumulate's arg types: " << lhs.type << "\t" << rhs.type << endl;
} // cerr << endl;
else if (lhs.type == Node::number && rhs.type == Node::numeric_dimension) {
Node result(acc.line_number, Node::numeric_dimension, operate(op, lhs, rhs), rhs.token); if (lhs.type == Node::number && rhs.type == Node::number) {
acc.children->pop_back(); Node result(acc.line_number, operate(op, lnum, rnum));
acc.children->push_back(result); // cerr << "accumulate just made a node: " << result.to_string("") << "\t" << result.type << endl;
} acc.children->pop_back();
else if (lhs.type == Node::numeric_dimension && rhs.type == Node::number) { acc.children->push_back(result);
Node result(acc.line_number, Node::numeric_dimension, operate(op, lhs, rhs), lhs.token); }
acc.children->pop_back(); else if (lhs.type == Node::number && rhs.type == Node::numeric_dimension) {
acc.children->push_back(result); Node result(acc.line_number, operate(op, lnum, rnum), rhs.token);
} acc.children->pop_back();
else if (lhs.type == Node::numeric_dimension && rhs.type == Node::numeric_dimension) { acc.children->push_back(result);
// CHECK FOR MISMATCHED UNITS HERE }
Node result(acc.line_number, Node::numeric_dimension, operate(op, lhs, rhs), lhs.token); else if (lhs.type == Node::numeric_dimension && rhs.type == Node::number) {
acc.children->pop_back(); Node result(acc.line_number, operate(op, lnum, rnum), lhs.token);
acc.children->push_back(result); acc.children->pop_back();
} acc.children->push_back(result);
else { }
acc.children->push_back(rhs); else if (lhs.type == Node::numeric_dimension && rhs.type == Node::numeric_dimension) {
// TO DO: CHECK FOR MISMATCHED UNITS HERE
Node result(acc.line_number, operate(op, lnum, rnum), lhs.token);
acc.children->pop_back();
acc.children->push_back(result);
}
else {
// cerr << "accumulate: didn't do anything" << endl;
acc.children->push_back(rhs);
}
return acc;
} }
return acc;
}
double operate(const Node::Type op, double lhs, double rhs) double operate(const Node::Type op, double lhs, double rhs)
{
switch (op)
{ {
case Node::add: return lhs + rhs; break; switch (op)
case Node::sub: return lhs - rhs; break; {
case Node::mul: return lhs * rhs; break; case Node::add: return lhs + rhs; break;
case Node::div: return lhs / rhs; break; case Node::sub: return lhs - rhs; break;
default: return 0; break; case Node::mul: return lhs * rhs; break;
case Node::div: return lhs / rhs; break;
default: return 0; break;
}
} }
} }
\ No newline at end of file
$x: 1 2 3;
$y: 3;
$z: 2;
$w: 10/2;
div { div {
a: b c d; /* a: 1 + 2;
b: a $x b; b: 3 + 2/3;
c: 1 (2 3) 4; c: 1/2 + 1/2;*/
d: 1, 2 3, 4, (5 6, 7 8) 9, 10; /* shouldn't eval the following "300" */
e: 1 + (2 3) + 3 + 4; /* d: 300; */
f: 1 + 2 + (3 4) + 5 + 6; /* e: 1 + (5/10 2 3);*/
g: 2 / 3, (3/4); f: 1 + ((2+(3 4) 5) 6);
h: 1 + 2/3; /* f: 1 + ((1+(14/7 8) 9) 6);*/
i: 2/3 + 1;
j: 2/3 + 1 2;
k: 1 2 + 3/4;
l: (1 2) + 3/4;
m: 2 3/4;
n: $y / 2;
o: ($y) / 2;
p: 12 / 3 / $z;
q: 12 / 3 / 2;
r: 12 / (3 / 2);
s: (12 / 3) / 2;
t: 5 / (1 + (3 - 2) + 4 / (1 * $z));
t: 5 / (2 + 3);
t: 5 / (2);
t: 5 / 2;
u: 6 / 2 + 4 / $z;
v: 3-2;
w: (5 / #{$w});
x: "#{$w}";
// t: 12 (/ 3 / 2);
y: 5 + (4/2 4/2 4/2);
z: 2px + 2px, 2px + 2 //, 2px + 2em;
} }
\ No newline at end of file
...@@ -14,7 +14,7 @@ namespace Sass { ...@@ -14,7 +14,7 @@ namespace Sass {
size_t Node::fresh = 0; size_t Node::fresh = 0;
size_t Node::copied = 0; size_t Node::copied = 0;
string Node::to_string(const string& prefix) string Node::to_string(const string& prefix) const
{ {
switch (type) switch (type)
{ {
...@@ -109,21 +109,32 @@ namespace Sass { ...@@ -109,21 +109,32 @@ namespace Sass {
case expression: case expression:
case term: { case term: {
string result(children->at(0).to_string(prefix)); string result(children->at(0).to_string(prefix));
for (int i = 2; i < children->size(); i += 2) { // for (int i = 2; i < children->size(); i += 2) {
// result += " "; // // result += " ";
result += children->at(i).to_string(prefix); // result += children->at(i).to_string(prefix);
// }
for (int i = 1; i < children->size(); ++i) {
if (!(children->at(i).type == add ||
children->at(i).type == sub ||
children->at(i).type == mul)) {
result += children->at(i).to_string(prefix);
}
} }
return result; return result;
} break; } break;
case numeric_dimension: { case numeric_dimension: {
stringstream ss; stringstream ss;
// ss.setf(std::ios::fixed, std::ios::floatfield);
// ss.precision(3);
ss << numeric_value << string(token); ss << numeric_value << string(token);
return ss.str(); return ss.str();
} break; } break;
case number: { case number: {
stringstream ss; stringstream ss;
// ss.setf(std::ios::fixed, std::ios::floatfield);
// ss.precision(3);
ss << numeric_value; ss << numeric_value;
return ss.str(); return ss.str();
} break; } break;
......
#define SASS_NODE_INCLUDED
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include "token.hpp" #include "token.hpp"
...@@ -46,10 +48,17 @@ namespace Sass { ...@@ -46,10 +48,17 @@ namespace Sass {
factor, factor,
values, values,
value, value,
dimension, identifier,
uri,
textual_percentage,
textual_dimension,
textual_number,
textual_hex,
string_constant,
numeric_percentage,
numeric_dimension, numeric_dimension,
number, number,
comment comment
}; };
...@@ -67,6 +76,7 @@ namespace Sass { ...@@ -67,6 +76,7 @@ namespace Sass {
bool has_backref; bool has_backref;
bool from_variable; bool from_variable;
bool eval_me; bool eval_me;
bool is_hex;
Node() : type(nil), children(0) { ++fresh; } Node() : type(nil), children(0) { ++fresh; }
...@@ -81,7 +91,8 @@ namespace Sass { ...@@ -81,7 +91,8 @@ namespace Sass {
has_propsets(n.has_propsets), has_propsets(n.has_propsets),
has_backref(n.has_backref), has_backref(n.has_backref),
from_variable(n.from_variable), from_variable(n.from_variable),
eval_me(n.eval_me) eval_me(n.eval_me),
is_hex(n.is_hex)
{ /*n.release();*/ ++copied; } // No joint custody. { /*n.release();*/ ++copied; } // No joint custody.
Node(size_t line_number, Type type, size_t length = 0) Node(size_t line_number, Type type, size_t length = 0)
...@@ -95,7 +106,8 @@ namespace Sass { ...@@ -95,7 +106,8 @@ namespace Sass {
has_propsets(false), has_propsets(false),
has_backref(false), has_backref(false),
from_variable(false), from_variable(false),
eval_me(false) eval_me(false),
is_hex(false)
{ children->reserve(length); ++fresh; } { children->reserve(length); ++fresh; }
Node(size_t line_number, Type type, const Node& n) Node(size_t line_number, Type type, const Node& n)
...@@ -109,7 +121,8 @@ namespace Sass { ...@@ -109,7 +121,8 @@ namespace Sass {
has_propsets(false), has_propsets(false),
has_backref(false), has_backref(false),
from_variable(false), from_variable(false),
eval_me(false) eval_me(false),
is_hex(false)
{ ++fresh; } { ++fresh; }
Node(size_t line_number, Type type, const Node& n, const Node& m) Node(size_t line_number, Type type, const Node& n, const Node& m)
...@@ -123,7 +136,8 @@ namespace Sass { ...@@ -123,7 +136,8 @@ namespace Sass {
has_propsets(false), has_propsets(false),
has_backref(false), has_backref(false),
from_variable(false), from_variable(false),
eval_me(false) eval_me(false),
is_hex(false)
{ {
children->reserve(2); children->reserve(2);
children->push_back(n); children->push_back(n);
...@@ -142,7 +156,8 @@ namespace Sass { ...@@ -142,7 +156,8 @@ namespace Sass {
has_propsets(false), has_propsets(false),
has_backref(false), has_backref(false),
from_variable(false), from_variable(false),
eval_me(false) eval_me(false),
is_hex(false)
{ ++fresh; } { ++fresh; }
Node(size_t line_number, double d) Node(size_t line_number, double d)
...@@ -156,7 +171,8 @@ namespace Sass { ...@@ -156,7 +171,8 @@ namespace Sass {
has_propsets(false), has_propsets(false),
has_backref(false), has_backref(false),
from_variable(false), from_variable(false),
eval_me(false) eval_me(false),
is_hex(false)
{ ++fresh; } { ++fresh; }
Node(size_t line_number, double d, Token& token) Node(size_t line_number, double d, Token& token)
...@@ -170,7 +186,8 @@ namespace Sass { ...@@ -170,7 +186,8 @@ namespace Sass {
has_propsets(false), has_propsets(false),
has_backref(false), has_backref(false),
from_variable(false), from_variable(false),
eval_me(false) eval_me(false),
is_hex(false)
{ ++fresh; } { ++fresh; }
//~Node() { delete children; } //~Node() { delete children; }
...@@ -189,6 +206,7 @@ namespace Sass { ...@@ -189,6 +206,7 @@ namespace Sass {
has_backref = n.has_backref; has_backref = n.has_backref;
from_variable = n.from_variable; from_variable = n.from_variable;
eval_me = n.eval_me; eval_me = n.eval_me;
is_hex = n.is_hex;
++copied; ++copied;
return *this; return *this;
} }
...@@ -207,7 +225,7 @@ namespace Sass { ...@@ -207,7 +225,7 @@ namespace Sass {
return *this; return *this;
} }
string to_string(const string& prefix); string to_string(const string& prefix) const;
void release() const { children = 0; } void release() const { children = 0; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment