Commit 12ff626b by Aaron Leung

No longer doing single-pass parsing/expansion. Building up a queue of pending…

No longer doing single-pass parsing/expansion. Building up a queue of pending expansions/evaluations, then performing them after parse. Should combine the efficiency of single-pass with the ease of multi-pass. Small bug that needs fixing.
parent 53096e97
...@@ -3,15 +3,15 @@ namespace Sass { ...@@ -3,15 +3,15 @@ namespace Sass {
struct Context { struct Context {
map<Token, Node> environment; map<Token, Node> environment;
map<Token, Node> mixins; // map<Token, Node> mixins;
vector<Node*> pending; vector<Node> pending;
vector<char*> source_refs; vector<char*> source_refs;
size_t ref_count; size_t ref_count;
Context() Context()
: environment(map<Token, Node>()), : environment(map<Token, Node>()),
mixins(map<Token, Node>()), // mixins(map<Token, Node>()),
pending(vector<Node*>()), pending(vector<Node>()),
source_refs(vector<char*>()), source_refs(vector<char*>()),
ref_count(0) ref_count(0)
{ } { }
......
...@@ -112,11 +112,11 @@ namespace Sass { ...@@ -112,11 +112,11 @@ namespace Sass {
void parse_scss(); void parse_scss();
Node parse_import(); Node parse_import();
Node parse_include(); Node parse_include();
void parse_mixin_def(); Node parse_mixin_def();
Node parse_parameter(); Node parse_parameter();
Node parse_arguments(); Node parse_arguments();
Node parse_mixin_params(); Node parse_mixin_params();
void parse_assignment(); Node parse_assignment();
Node parse_ruleset(); Node parse_ruleset();
Node parse_selector_group(); Node parse_selector_group();
Node parse_selector(); Node parse_selector();
...@@ -145,6 +145,7 @@ namespace Sass { ...@@ -145,6 +145,7 @@ namespace Sass {
const char* look_for_pseudo(const char* start = 0); const char* look_for_pseudo(const char* start = 0);
const char* look_for_attrib(const char* start = 0); const char* look_for_attrib(const char* start = 0);
void eval_pending();
string emit_css(CSS_Style style); string emit_css(CSS_Style style);
}; };
......
#include "document.hpp"
#include "evaluator.hpp"
namespace Sass {
void Document::eval_pending()
{
for (int i = 0; i < context.pending.size(); ++i) {
Node n(context.pending[i]);
switch (n.type)
{
case Node::assignment:
context.environment[n[0].token] = eval(n[1], context.environment);
break;
case Node::rule:
n[1] = eval(n[1], context.environment);
break;
}
}
}
}
\ No newline at end of file
...@@ -28,7 +28,7 @@ namespace Sass { ...@@ -28,7 +28,7 @@ namespace Sass {
// parse_mixin_def(); // parse_mixin_def();
// } // }
else if (peek< variable >(position)) { else if (peek< variable >(position)) {
parse_assignment(); context.pending.push_back(parse_assignment());
lex< exactly<';'> >(); lex< exactly<';'> >();
} }
else { else {
...@@ -128,20 +128,22 @@ namespace Sass { ...@@ -128,20 +128,22 @@ namespace Sass {
// } // }
// } // }
void Document::parse_assignment() Node Document::parse_assignment()
{ {
lex< variable >(); lex< variable >();
Token key(lexed); Node var(line_number, Node::variable, lexed);
lex< exactly<':'> >(); lex< exactly<':'> >();
// context.environment[key] = parse_values();
Node val(parse_list()); Node val(parse_list());
val.from_variable = true; // val.from_variable = true;
val.eval_me = true; // val.eval_me = true;
Node assn(line_number, Node::assignment, 2);
assn << var << val;
return assn;
Node evaled(eval(val)); // Node evaled(eval(val));
evaled.from_variable = true; // evaled.from_variable = true;
val.eval_me = true; // val.eval_me = true;
context.environment[key] = evaled; // context.environment[key] = evaled;
} }
Node Document::parse_ruleset() Node Document::parse_ruleset()
...@@ -325,7 +327,7 @@ namespace Sass { ...@@ -325,7 +327,7 @@ namespace Sass {
// semicolon = true; // semicolon = true;
// } // }
else if (lex< variable >()) { else if (lex< variable >()) {
parse_assignment(); context.pending.push_back(parse_assignment());
semicolon = true; semicolon = true;
} }
// else if (look_for_rule(position)) { // else if (look_for_rule(position)) {
...@@ -358,23 +360,23 @@ namespace Sass { ...@@ -358,23 +360,23 @@ namespace Sass {
lex< exactly<':'> >(); lex< exactly<':'> >();
// rule << parse_values(); // rule << parse_values();
rule << parse_list(); rule << parse_list();
if (rule[1].eval_me) context.pending.push_back(rule);
return rule; return rule;
} }
Node Document::parse_list() Node Document::parse_list()
{ {
Node val(parse_comma_list()); Node val(parse_comma_list());
if (val.type != Node::comma_list && val.type != Node::space_list && val.eval_me) { // if (val.type != Node::comma_list && val.type != Node::space_list && val.eval_me) {
return eval(val); // return eval(val);
} // }
else if (val.type == Node::comma_list || val.type == Node::space_list) { // else if (val.type == Node::comma_list || val.type == Node::space_list) {
for (int i = 0; i < val.children->size(); ++i) { // for (int i = 0; i < val.children->size(); ++i) {
if (val.children->at(i).eval_me) { // if (val.children->at(i).eval_me) {
val.children->at(i) = eval(val.children->at(i)); // val.children->at(i) = eval(val.children->at(i));
} // }
} // }
} // }
return val; return val;
} }
...@@ -391,9 +393,14 @@ namespace Sass { ...@@ -391,9 +393,14 @@ namespace Sass {
Node comma_list(line_number, Node::comma_list, 2); Node comma_list(line_number, Node::comma_list, 2);
comma_list << list1; comma_list << list1;
comma_list.eval_me |= list1.eval_me;
while (lex< exactly<','> >()) while (lex< exactly<','> >())
{ comma_list << parse_space_list(); } {
Node list(parse_space_list());
comma_list << list;
comma_list.eval_me |= list.eval_me;
}
return comma_list; return comma_list;
} }
...@@ -406,20 +413,21 @@ namespace Sass { ...@@ -406,20 +413,21 @@ namespace Sass {
peek< exactly<'}'> >(position) || peek< exactly<'}'> >(position) ||
peek< exactly<')'> >(position) || peek< exactly<')'> >(position) ||
peek< exactly<','> >(position)) peek< exactly<','> >(position))
// { return expr1.eval_me ? eval(expr1) : expr1; }
{ return expr1; } { return 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); space_list.eval_me |= expr1.eval_me;
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)))
// { Node expr(parse_expression()); {
// space_list << (expr.eval_me ? eval(expr) : expr); } Node expr(parse_expression());
{ space_list << parse_expression(); } space_list << expr;
space_list.eval_me |= expr.eval_me;
}
return space_list; return space_list;
} }
...@@ -473,7 +481,7 @@ namespace Sass { ...@@ -473,7 +481,7 @@ namespace Sass {
Node term(line_number, Node::term, 3); Node term(line_number, Node::term, 3);
term << fact1; term << fact1;
if (fact1.from_variable || fact1.eval_me) term.eval_me = true; if (fact1.eval_me) term.eval_me = true;
while (lex< exactly<'*'> >() || lex< exactly<'/'> >()) { while (lex< exactly<'*'> >() || lex< exactly<'/'> >()) {
if (lexed.begin[0] == '*') { if (lexed.begin[0] == '*') {
...@@ -484,7 +492,7 @@ namespace Sass { ...@@ -484,7 +492,7 @@ namespace Sass {
term << Node(line_number, Node::div, lexed); term << Node(line_number, Node::div, lexed);
} }
Node fact(parse_factor()); Node fact(parse_factor());
if (fact.from_variable || fact.eval_me) term.eval_me = true; if (fact.eval_me) term.eval_me = true;
term << fact; term << fact;
} }
...@@ -556,8 +564,11 @@ namespace Sass { ...@@ -556,8 +564,11 @@ namespace Sass {
if (lex< string_constant >()) if (lex< string_constant >())
{ return Node(line_number, Node::string_constant, lexed); } { return Node(line_number, Node::string_constant, lexed); }
if (lex< variable >()) { if (lex< variable >())
return context.environment[lexed]; {
Node var(line_number, Node::variable, lexed);
var.eval_me = true;
return var;
} }
} }
......
...@@ -5,39 +5,40 @@ ...@@ -5,39 +5,40 @@
namespace Sass { namespace Sass {
using std::cerr; using std::endl; using std::cerr; using std::endl;
Node eval(const Node& expr) Node eval(const Node& expr, map<Token, Node>& g_env)
{ {
switch (expr.type) switch (expr.type)
{ {
case Node::comma_list: case Node::comma_list:
case Node::space_list: { case Node::space_list: {
if (expr.eval_me) { if (expr.eval_me) {
*(expr.children->begin()) = eval(expr.children->front()); // *(expr.children->begin()) = eval(expr[0], g_env);
expr[0] = eval(expr[0], g_env);
} }
return expr; return expr;
} break; } break;
case Node::expression: { case Node::expression: {
Node acc(expr.line_number, Node::expression, eval(expr.children->at(0))); Node acc(expr.line_number, Node::expression, eval(expr[0], g_env));
Node rhs(eval(expr.children->at(2))); Node rhs(eval(expr[2], g_env));
accumulate(expr.children->at(1).type, acc, rhs); accumulate(expr[1].type, acc, rhs);
for (int i = 3; i < expr.children->size(); i += 2) { for (int i = 3; i < expr.size(); i += 2) {
Node rhs(eval(expr.children->at(i+1))); Node rhs(eval(expr[i+1], g_env));
accumulate(expr.children->at(i).type, acc, rhs); accumulate(expr[i].type, acc, rhs);
} }
return acc.children->size() == 1 ? acc.children->front() : acc; return acc.size() == 1 ? acc[0] : acc;
} break; } break;
case Node::term: { case Node::term: {
if (expr.eval_me) { if (expr.eval_me) {
Node acc(expr.line_number, Node::expression, eval(expr.children->at(0))); Node acc(expr.line_number, Node::expression, eval(expr[0], g_env));
Node rhs(eval(expr.children->at(2))); Node rhs(eval(expr[2], g_env));
accumulate(expr.children->at(1).type, acc, rhs); accumulate(expr[1].type, acc, rhs);
for (int i = 3; i < expr.children->size(); i += 2) { for (int i = 3; i < expr.size(); i += 2) {
Node rhs(eval(expr.children->at(i+1))); Node rhs(eval(expr[i+1], g_env));
accumulate(expr.children->at(i).type, acc, rhs); accumulate(expr[i].type, acc, rhs);
} }
return acc.children->size() == 1 ? acc.children->front() : acc; return acc.size() == 1 ? acc[0] : acc;
} }
else { else {
return expr; return expr;
...@@ -73,6 +74,10 @@ namespace Sass { ...@@ -73,6 +74,10 @@ namespace Sass {
return triple; return triple;
} break; } break;
case Node::variable: {
return g_env[expr.token];
} break;
default: { default: {
return expr; return expr;
} }
......
#include <map>
#ifndef SASS_NODE_INCLUDED #ifndef SASS_NODE_INCLUDED
#include "node.hpp" #include "node.hpp"
#endif #endif
namespace Sass { namespace Sass {
Node eval(const Node& expr); using std::map;
Node eval(const Node& expr, map<Token, Node>& g_env);
Node accumulate(const Node::Type op, Node& acc, Node& rhs); Node accumulate(const Node::Type op, Node& acc, Node& rhs);
double operate(const Node::Type op, double lhs, double rhs); double operate(const Node::Type op, double lhs, double rhs);
} }
\ No newline at end of file
...@@ -30,6 +30,7 @@ int main(int argc, char* argv[]) { ...@@ -30,6 +30,7 @@ int main(int argc, char* argv[]) {
Document doc(path, 0); Document doc(path, 0);
doc.parse_scss(); doc.parse_scss();
cerr << "successfully parsed document" << endl; cerr << "successfully parsed document" << endl;
doc.eval_pending();
string output = doc.emit_css(style); string output = doc.emit_css(style);
cout << output; cout << output;
......
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