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 {
struct Context {
map<Token, Node> environment;
map<Token, Node> mixins;
vector<Node*> pending;
// map<Token, Node> mixins;
vector<Node> pending;
vector<char*> source_refs;
size_t ref_count;
Context()
: environment(map<Token, Node>()),
mixins(map<Token, Node>()),
pending(vector<Node*>()),
// mixins(map<Token, Node>()),
pending(vector<Node>()),
source_refs(vector<char*>()),
ref_count(0)
{ }
......
......@@ -112,11 +112,11 @@ namespace Sass {
void parse_scss();
Node parse_import();
Node parse_include();
void parse_mixin_def();
Node parse_mixin_def();
Node parse_parameter();
Node parse_arguments();
Node parse_mixin_params();
void parse_assignment();
Node parse_assignment();
Node parse_ruleset();
Node parse_selector_group();
Node parse_selector();
......@@ -145,6 +145,7 @@ namespace Sass {
const char* look_for_pseudo(const char* start = 0);
const char* look_for_attrib(const char* start = 0);
void eval_pending();
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 {
// parse_mixin_def();
// }
else if (peek< variable >(position)) {
parse_assignment();
context.pending.push_back(parse_assignment());
lex< exactly<';'> >();
}
else {
......@@ -128,20 +128,22 @@ namespace Sass {
// }
// }
void Document::parse_assignment()
Node Document::parse_assignment()
{
lex< variable >();
Token key(lexed);
Node var(line_number, Node::variable, lexed);
lex< exactly<':'> >();
// context.environment[key] = parse_values();
Node val(parse_list());
val.from_variable = true;
val.eval_me = true;
// val.from_variable = true;
// val.eval_me = true;
Node assn(line_number, Node::assignment, 2);
assn << var << val;
return assn;
Node evaled(eval(val));
evaled.from_variable = true;
val.eval_me = true;
context.environment[key] = evaled;
// Node evaled(eval(val));
// evaled.from_variable = true;
// val.eval_me = true;
// context.environment[key] = evaled;
}
Node Document::parse_ruleset()
......@@ -325,7 +327,7 @@ namespace Sass {
// semicolon = true;
// }
else if (lex< variable >()) {
parse_assignment();
context.pending.push_back(parse_assignment());
semicolon = true;
}
// else if (look_for_rule(position)) {
......@@ -358,23 +360,23 @@ namespace Sass {
lex< exactly<':'> >();
// rule << parse_values();
rule << parse_list();
if (rule[1].eval_me) context.pending.push_back(rule);
return rule;
}
Node Document::parse_list()
{
Node val(parse_comma_list());
if (val.type != Node::comma_list && val.type != Node::space_list && val.eval_me) {
return eval(val);
}
else if (val.type == Node::comma_list || val.type == Node::space_list) {
for (int i = 0; i < val.children->size(); ++i) {
if (val.children->at(i).eval_me) {
val.children->at(i) = eval(val.children->at(i));
}
}
}
// if (val.type != Node::comma_list && val.type != Node::space_list && val.eval_me) {
// return eval(val);
// }
// else if (val.type == Node::comma_list || val.type == Node::space_list) {
// for (int i = 0; i < val.children->size(); ++i) {
// if (val.children->at(i).eval_me) {
// val.children->at(i) = eval(val.children->at(i));
// }
// }
// }
return val;
}
......@@ -391,9 +393,14 @@ namespace Sass {
Node comma_list(line_number, Node::comma_list, 2);
comma_list << list1;
comma_list.eval_me |= list1.eval_me;
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;
}
......@@ -406,20 +413,21 @@ namespace Sass {
peek< exactly<'}'> >(position) ||
peek< exactly<')'> >(position) ||
peek< exactly<','> >(position))
// { return expr1.eval_me ? eval(expr1) : expr1; }
{ return expr1; }
Node space_list(line_number, Node::space_list, 2);
space_list << expr1;
// space_list << (expr1.eval_me ? eval(expr1) : expr1);
space_list.eval_me |= expr1.eval_me;
while (!(peek< exactly<';'> >(position) ||
peek< exactly<'}'> >(position) ||
peek< exactly<')'> >(position) ||
peek< exactly<','> >(position)))
// { Node expr(parse_expression());
// space_list << (expr.eval_me ? eval(expr) : expr); }
{ space_list << parse_expression(); }
{
Node expr(parse_expression());
space_list << expr;
space_list.eval_me |= expr.eval_me;
}
return space_list;
}
......@@ -473,7 +481,7 @@ namespace Sass {
Node term(line_number, Node::term, 3);
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<'/'> >()) {
if (lexed.begin[0] == '*') {
......@@ -484,7 +492,7 @@ namespace Sass {
term << Node(line_number, Node::div, lexed);
}
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;
}
......@@ -556,8 +564,11 @@ namespace Sass {
if (lex< string_constant >())
{ return Node(line_number, Node::string_constant, lexed); }
if (lex< variable >()) {
return context.environment[lexed];
if (lex< variable >())
{
Node var(line_number, Node::variable, lexed);
var.eval_me = true;
return var;
}
}
......
......@@ -5,39 +5,40 @@
namespace Sass {
using std::cerr; using std::endl;
Node eval(const Node& expr)
Node eval(const Node& expr, map<Token, Node>& g_env)
{
switch (expr.type)
{
case Node::comma_list:
case Node::space_list: {
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;
} break;
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);
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;
Node acc(expr.line_number, Node::expression, eval(expr[0], g_env));
Node rhs(eval(expr[2], g_env));
accumulate(expr[1].type, acc, rhs);
for (int i = 3; i < expr.size(); i += 2) {
Node rhs(eval(expr[i+1], g_env));
accumulate(expr[i].type, acc, rhs);
}
return acc.size() == 1 ? acc[0] : 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);
Node acc(expr.line_number, Node::expression, eval(expr[0], g_env));
Node rhs(eval(expr[2], g_env));
accumulate(expr[1].type, acc, rhs);
for (int i = 3; i < expr.size(); i += 2) {
Node rhs(eval(expr[i+1], g_env));
accumulate(expr[i].type, acc, rhs);
}
return acc.children->size() == 1 ? acc.children->front() : acc;
return acc.size() == 1 ? acc[0] : acc;
}
else {
return expr;
......@@ -73,6 +74,10 @@ namespace Sass {
return triple;
} break;
case Node::variable: {
return g_env[expr.token];
} break;
default: {
return expr;
}
......
#include <map>
#ifndef SASS_NODE_INCLUDED
#include "node.hpp"
#endif
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);
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[]) {
Document doc(path, 0);
doc.parse_scss();
cerr << "successfully parsed document" << endl;
doc.eval_pending();
string output = doc.emit_css(style);
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