Commit 9e8b930e by Aaron Leung

Finished the node refactor. Required more debugging than I expected.

parent 42a50269
build: sassc.cpp document.cpp node.cpp token.cpp prelexer.cpp
build: sassc.cpp document.cpp node.cpp values.cpp prelexer.cpp
g++ -o bin/sassc sassc.cpp document.cpp document_parser.cpp eval_apply.cpp node.cpp values.cpp prelexer.cpp
test: build
......
......@@ -39,8 +39,7 @@ namespace Sass {
size_t ref_count;
Context()
: pending(vector<Node>()),
source_refs(vector<char*>()),
: source_refs(vector<char*>()),
ref_count(0)
{ }
......
......@@ -9,8 +9,8 @@ namespace Sass {
: path(path), source(source),
line_number(1), own_source(false),
context(*(new Context())),
root(Node(1, Node::root)),
lexed(Token())
root(Node(Node::root, 1)),
lexed(Token::make())
{
if (!source) {
std::FILE *f;
......@@ -35,8 +35,8 @@ namespace Sass {
: path(path), source(0),
line_number(1), own_source(false),
context(context),
root(Node(1, Node::root)),
lexed(Token())
root(Node(Node::root, 1)),
lexed(Token::make())
{
std::FILE *f;
// TO DO: CHECK f AGAINST NULL/0
......@@ -59,12 +59,12 @@ namespace Sass {
if (context.ref_count == 0) delete &context;
}
void Document::eval_pending()
{
for (int i = 0; i < context.pending.size(); ++i) {
eval(context.pending[i], context.global_env);
}
}
// void Document::eval_pending()
// {
// for (int i = 0; i < context.pending.size(); ++i) {
// eval(context.pending[i], context.global_env);
// }
// }
using std::string;
using std::stringstream;
......
......@@ -85,7 +85,7 @@ namespace Sass {
after_whitespace = spaces(position);
if (after_whitespace) {
line_number += count_interval<'\n'>(position, after_whitespace);
lexed = Token(position, after_whitespace);
lexed = Token::make(position, after_whitespace);
return position = after_whitespace;
}
else {
......@@ -101,7 +101,7 @@ namespace Sass {
const char* after_token = mx(after_whitespace);
if (after_token) {
line_number += count_interval<'\n'>(position, after_token);
lexed = Token(after_whitespace, after_token);
lexed = Token::make(after_whitespace, after_token);
return position = after_token;
}
else {
......
......@@ -26,8 +26,8 @@ namespace Sass {
lex< exactly<';'> >();
}
else if (peek< variable >(position)) {
lex< exactly<';'> >();
root << parse_assignment();
lex< exactly<';'> >();
}
else {
root << parse_ruleset();
......@@ -152,7 +152,7 @@ namespace Sass {
Node Document::parse_selector_group()
{
Node group(line_number, Node::selector_group, 1);
Node group(Node::selector_group, line_number, 1);
group << parse_selector();
while (lex< exactly<','> >()) group << parse_selector();
return group;
......@@ -266,7 +266,7 @@ namespace Sass {
Node Document::parse_attribute_selector()
{
Node attr_sel(line_number, Node::attribute_selector, 3);
Node attr_sel(Node::attribute_selector, line_number, 3);
lex< exactly<'['> >();
lex< type_selector >();
attr_sel << Node(Node::value, line_number, lexed);
......@@ -316,8 +316,8 @@ namespace Sass {
block[0].has_expansions = true;
}
else if (lex< variable >()) {
semicolon = true;
block << parse_assignment();
semicolon = true;
}
// else if (look_for_rule(position)) {
// block << parse_rule();
......@@ -498,7 +498,7 @@ namespace Sass {
if (lex< rgb_prefix >())
{
Node result(Node::color, line_number, 3);
Node result(Node::numeric_color, line_number, 3);
lex< number >();
result << Node(line_number, std::atof(lexed.begin));
lex< exactly<','> >();
......@@ -644,7 +644,7 @@ namespace Sass {
(q = peek< id_name >(p)) || (q = peek< class_name >(p)) ||
(q = look_for_pseudo(p)) || (q = look_for_attrib(p));
// cerr << "looking for simple selector; found:" << endl;
// cerr << (q ? string(Token(q,q+8)) : "nothing") << endl;
// cerr << (q ? string(Token::make(q,q+8)) : "nothing") << endl;
return q;
}
......
......@@ -10,19 +10,18 @@ namespace Sass {
switch (expr.type)
{
case Node::mixin: {
env[expr[0].token] = expr;
// cerr << "DEFINED MIXIN: " << string(expr[0].token) << endl << endl;
env[expr[0].content.token] = expr;
return expr;
} break;
case Node::expansion: {
Token name(expr[0].token);
Token name(expr[0].content.token);
// cerr << "EVALUATING EXPANSION: " << string(name) << endl;
Node args(expr[1]);
Node mixin(env[name]);
Node expansion(apply(mixin, args, env));
expr.children->pop_back();
expr.children->pop_back();
expr.content.children->pop_back();
expr.content.children->pop_back();
expr += expansion;
// expr[0].has_rules_or_comments |= expansion[0].has_rules_or_comments;
// expr[0].has_rulesets |= expansion[0].has_rulesets;
......@@ -63,11 +62,11 @@ namespace Sass {
val = eval(val, env);
}
Node var(expr[0]);
if (env.query(var.token)) {
env[var.token] = val;
if (env.query(var.content.token)) {
env[var.content.token] = val;
}
else {
env.current_frame[var.token] = val;
env.current_frame[var.content.token] = val;
}
return expr;
} break;
......@@ -95,7 +94,8 @@ namespace Sass {
} break;
case Node::expression: {
Node acc(expr.line_number, Node::expression, eval(expr[0], env));
Node acc(Node::expression, expr.line_number, 1);
acc << eval(expr[0], env);
Node rhs(eval(expr[2], env));
accumulate(expr[1].type, acc, rhs);
for (int i = 3; i < expr.size(); i += 2) {
......@@ -107,7 +107,8 @@ namespace Sass {
case Node::term: {
if (expr.eval_me) {
Node acc(expr.line_number, Node::expression, eval(expr[0], env));
Node acc(Node::expression, expr.line_number, 1);
acc << eval(expr[0], env);
Node rhs(eval(expr[2], env));
accumulate(expr[1].type, acc, rhs);
for (int i = 3; i < expr.size(); i += 2) {
......@@ -123,22 +124,22 @@ namespace Sass {
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);
return Node(expr.line_number,
std::atof(expr.content.token.begin),
Token::make(Prelexer::number(expr.content.token.begin),
expr.content.token.end));
} break;
case Node::textual_number: {
double numval = std::atof(expr.token.begin);
return Node(expr.line_number, numval);
return Node(expr.line_number, std::atof(expr.content.token.begin));
} break;
case Node::textual_hex: {
Node triple(expr.line_number, Node::hex_triple, 3);
Token hext(expr.token.begin+1, expr.token.end);
Node triple(Node::numeric_color, expr.line_number, 3);
Token hext(Token::make(expr.content.token.begin+1, expr.content.token.end));
if (hext.length() == 6) {
for (int i = 0; i < 6; i += 2) {
Node thing(expr.line_number, static_cast<double>(std::strtol(string(hext.begin+i, 2).c_str(), NULL, 16)));
// Node thing(expr.line_number, static_cast<double>(std::strtol(string(hext.begin+i, 2).c_str(), NULL, 16)));
triple << Node(expr.line_number, static_cast<double>(std::strtol(string(hext.begin+i, 2).c_str(), NULL, 16)));
}
}
......@@ -151,7 +152,7 @@ namespace Sass {
} break;
case Node::variable: {
return env[expr.token];
return env[expr.content.token];
} break;
default: {
......@@ -162,26 +163,26 @@ namespace Sass {
Node accumulate(Node::Type op, Node& acc, Node& rhs)
{
Node lhs(acc.children->back());
double lnum = lhs.numeric_value;
double rnum = rhs.numeric_value;
Node lhs(acc.content.children->back());
double lnum = lhs.content.numeric_value;
double rnum = rhs.content.numeric_value;
if (lhs.type == Node::number && rhs.type == Node::number) {
Node result(acc.line_number, operate(op, lnum, rnum));
acc.children->pop_back();
acc.children->push_back(result);
acc.content.children->pop_back();
acc.content.children->push_back(result);
}
// TO DO: find a way to merge the following two clauses
else if (lhs.type == Node::number && rhs.type == Node::numeric_dimension) {
// TO DO: disallow division
Node result(acc.line_number, operate(op, lnum, rnum), rhs.token);
acc.children->pop_back();
acc.children->push_back(result);
Node result(acc.line_number, operate(op, lnum, rnum), Token::make(rhs.content.dimension.unit, Prelexer::identifier(rhs.content.dimension.unit)));
acc.content.children->pop_back();
acc.content.children->push_back(result);
}
else if (lhs.type == Node::numeric_dimension && rhs.type == Node::number) {
Node result(acc.line_number, operate(op, lnum, rnum), lhs.token);
acc.children->pop_back();
acc.children->push_back(result);
Node result(acc.line_number, operate(op, lnum, rnum), Token::make(lhs.content.dimension.unit, Prelexer::identifier(rhs.content.dimension.unit)));
acc.content.children->pop_back();
acc.content.children->push_back(result);
}
else if (lhs.type == Node::numeric_dimension && rhs.type == Node::numeric_dimension) {
// TO DO: CHECK FOR MISMATCHED UNITS HERE
......@@ -189,49 +190,49 @@ namespace Sass {
if (op == Node::div)
{ result = Node(acc.line_number, operate(op, lnum, rnum)); }
else
{ result = Node(acc.line_number, operate(op, lnum, rnum), lhs.token); }
acc.children->pop_back();
acc.children->push_back(result);
{ result = Node(acc.line_number, operate(op, lnum, rnum), Token::make(lhs.content.dimension.unit, Prelexer::identifier(rhs.content.dimension.unit))); }
acc.content.children->pop_back();
acc.content.children->push_back(result);
}
// TO DO: find a way to merge the following two clauses
else if (lhs.type == Node::number && rhs.type == Node::hex_triple) {
else if (lhs.type == Node::number && rhs.type == Node::numeric_color) {
if (op != Node::sub && op != Node::div) {
double h1 = operate(op, lhs.numeric_value, rhs[0].numeric_value);
double h2 = operate(op, lhs.numeric_value, rhs[1].numeric_value);
double h3 = operate(op, lhs.numeric_value, rhs[2].numeric_value);
acc.children->pop_back();
double h1 = operate(op, lhs.content.numeric_value, rhs[0].content.numeric_value);
double h2 = operate(op, lhs.content.numeric_value, rhs[1].content.numeric_value);
double h3 = operate(op, lhs.content.numeric_value, rhs[2].content.numeric_value);
acc.content.children->pop_back();
acc << Node(acc.line_number, h1, h2, h3);
}
// trying to handle weird edge cases ... not sure if it's worth it
else if (op == Node::div) {
acc << Node(acc.line_number, Node::div);
acc << Node(Node::div);
acc << rhs;
}
else if (op == Node::sub) {
acc << Node(acc.line_number, Node::sub);
acc << Node(Node::sub);
acc << rhs;
}
else {
acc << rhs;
}
}
else if (lhs.type == Node::hex_triple && rhs.type == Node::number) {
double h1 = operate(op, lhs[0].numeric_value, rhs.numeric_value);
double h2 = operate(op, lhs[1].numeric_value, rhs.numeric_value);
double h3 = operate(op, lhs[2].numeric_value, rhs.numeric_value);
acc.children->pop_back();
else if (lhs.type == Node::numeric_color && rhs.type == Node::number) {
double h1 = operate(op, lhs[0].content.numeric_value, rhs.content.numeric_value);
double h2 = operate(op, lhs[1].content.numeric_value, rhs.content.numeric_value);
double h3 = operate(op, lhs[2].content.numeric_value, rhs.content.numeric_value);
acc.content.children->pop_back();
acc << Node(acc.line_number, h1, h2, h3);
}
else if (lhs.type == Node::hex_triple && rhs.type == Node::hex_triple) {
double h1 = operate(op, lhs[0].numeric_value, rhs[0].numeric_value);
double h2 = operate(op, lhs[1].numeric_value, rhs[1].numeric_value);
double h3 = operate(op, lhs[2].numeric_value, rhs[2].numeric_value);
acc.children->pop_back();
else if (lhs.type == Node::numeric_color && rhs.type == Node::numeric_color) {
double h1 = operate(op, lhs[0].content.numeric_value, rhs[0].content.numeric_value);
double h2 = operate(op, lhs[1].content.numeric_value, rhs[1].content.numeric_value);
double h3 = operate(op, lhs[2].content.numeric_value, rhs[2].content.numeric_value);
acc.content.children->pop_back();
acc << Node(acc.line_number, h1, h2, h3);
}
else {
// TO DO: disallow division and multiplication on lists
acc.children->push_back(rhs);
acc.content.children->push_back(rhs);
}
return acc;
......@@ -256,12 +257,11 @@ namespace Sass {
Node params(mixin[1]);
Node body(mixin[2].clone());
Environment m_env;
// cerr << "CLONED BODY" << endl;
// bind arguments
for (int i = 0, j = 0; i < args.size(); ++i) {
if (args[i].type == Node::assignment) {
Node arg(args[i]);
Token name(arg[0].token);
Token name(arg[0].content.token);
if (!m_env.query(name)) {
m_env[name] = eval(arg[1], env);
}
......@@ -269,7 +269,7 @@ namespace Sass {
else {
// TO DO: ensure (j < params.size())
Node param(params[j]);
Token name(param.type == Node::variable ? param.token : param[0].token);
Token name(param.type == Node::variable ? param.content.token : param[0].content.token);
m_env[name] = eval(args[i], env);
++j;
}
......@@ -279,7 +279,7 @@ namespace Sass {
for (int i = 0; i < params.size(); ++i) {
if (params[i].type == Node::assignment) {
Node param(params[i]);
Token name(param[0].token);
Token name(param[0].content.token);
if (!m_env.query(name)) {
m_env[name] = eval(param[1], env);
}
......
......@@ -48,7 +48,7 @@ namespace Sass {
result += ' ';
}
if (at(0).type == selector_combinator) {
result += string(at(0).content.token);
result += at(0).content.token.to_string();
result += ' ';
}
else {
......@@ -122,10 +122,6 @@ namespace Sass {
case expression:
case term: {
string result(at(0).to_string(prefix));
// for (int i = 2; i < size(); i += 2) {
// // result += " ";
// result += at(i).to_string(prefix);
// }
for (int i = 1; i < size(); ++i) {
if (!(at(i).type == add ||
// at(i).type == sub || // another edge case -- consider uncommenting
......@@ -147,21 +143,16 @@ namespace Sass {
case numeric_dimension: {
stringstream ss;
// ss.setf(std::ios::fixed, std::ios::floatfield);
// ss.precision(3);
ss << content.dimension.numeric_value;
Token unit;
unit.begin = content.dimension.unit;
unit.end = Prelexer::identifier(content.dimension.unit);
ss << string(unit);
// << string(Token(content.dimension.unit, Prelexer::identifier(content.dimension.unit)));
ss << string(content.dimension.unit, 2);
// << string(content.dimension.unit, Prelexer::identifier(content.dimension.unit) - content.dimension.unit);
// cerr << Token::make(content.dimension.unit, content.dimension.unit + 2).to_string();
// << Token::make(content.dimension.unit, Prelexer::identifier(content.dimension.unit)).to_string();
return ss.str();
} break;
case number: {
stringstream ss;
// ss.setf(std::ios::fixed, std::ios::floatfield);
// ss.precision(3);
ss << content.numeric_value;
return ss.str();
} break;
......@@ -213,7 +204,9 @@ namespace Sass {
// } break;
default: {
return string(content.token);
// return content.token.to_string();
if (!has_children && type != flags) return content.token.to_string();
else return "";
} break;
}
}
......
......@@ -3,11 +3,13 @@
#include <vector>
#include <sstream>
#include "values.hpp"
#include <iostream>
namespace Sass {
using std::string;
using std::vector;
using std::stringstream;
using std::cerr; using std::endl;
struct Node {
enum Type {
......@@ -96,7 +98,7 @@ namespace Sass {
void clear()
{
type = none; line_number = 0;
type = none; line_number = 0; has_children = false;
has_statements = false; has_blocks = false; has_expansions = false;
has_backref = false; from_variable = false; eval_me = false;
}
......@@ -174,6 +176,7 @@ namespace Sass {
clear();
type = numeric_dimension;
line_number = ln;
content.dimension = Dimension();
content.dimension.numeric_value = val;
content.dimension.unit = tok.begin;
}
......@@ -192,86 +195,4 @@ namespace Sass {
++allocations;
}
};
struct Orig_Node {
enum Type {
root,
ruleset,
propset,
selector_group,
selector,
selector_combinator,
simple_selector_sequence,
backref,
simple_selector,
type_selector,
class_selector,
id_selector,
pseudo,
pseudo_negation,
functional_pseudo,
attribute_selector,
block,
rule,
property,
nil,
comma_list,
space_list,
expression,
add,
sub,
term,
mul,
div,
factor,
values,
value,
identifier,
uri,
textual_percentage,
textual_dimension,
textual_number,
textual_hex,
string_constant,
numeric_percentage,
numeric_dimension,
number,
hex_triple,
mixin,
parameters,
expansion,
arguments,
variable,
assignment,
comment,
none,
flags
};
string to_string(const string& prefix) const;
Node clone() const;
void echo(stringstream& buf, size_t depth = 0);
void emit_nested_css(stringstream& buf,
size_t depth,
const vector<string>& prefixes);
void emit_nested_css(stringstream& buf, size_t depth);
void emit_expanded_css(stringstream& buf, const string& prefix);
void flatten();
};
}
\ No newline at end of file
......@@ -29,6 +29,7 @@ int main(int argc, char* argv[]) {
}
Document doc(path, 0);
cerr << "PREPARING TO PARSE DOCUMENT" << endl;
doc.parse_scss();
cerr << "SUCCESSFULLY PARSED DOCUMENT" << endl;
// doc.eval_pending();
......@@ -36,8 +37,8 @@ int main(int argc, char* argv[]) {
cerr << "SUCCESSFULLY EVALED DOCUMENT" << endl;
string output = doc.emit_css(style);
cerr << "Fresh nodes:\t" << Node::fresh << endl;
cerr << "Copied nodes:\t" << Node::copied << endl;
// cerr << "Fresh nodes:\t" << Node::fresh << endl;
// cerr << "Copied nodes:\t" << Node::copied << endl;
cerr << "Allocations:\t" << Node::allocations << endl;
cout << output;
......
......@@ -23,8 +23,8 @@ div {
l: 15 / 5 / $three;
m: 1/2, $stuff url("www.foo.com/blah.png") blah blah;
n: 1 2 3, $stuff 4 5 (6, 7 8 9);
o: 3px + 3px;
p: 4 + 1em;
o: 3px + 3px + 3px;
p: 4 + 1px;
q: (20pt / 10pt);
r: 16em * 4;
s: (5em / 2);
......
......@@ -19,8 +19,8 @@ div {
l: 1;
m: 1/2, 1 2 3 url("www.foo.com/blah.png") blah blah;
n: 1 2 3, 1 2 3 4 5 6, 7 8 9;
o: 6px;
p: 5em;
o: 9px;
p: 5px;
q: 2;
r: 64em;
s: 2.5em;
......
#include "token.hpp"
#include "values.hpp"
namespace Sass {
Token::Token() : begin(0), end(0) { }
Token::Token(const char* begin, const char* end)
: begin(begin), end(end) { }
// Token::Token() : begin(0), end(0) { }
// Token::Token(const char* begin, const char* end)
// : begin(begin), end(end) { }
string Token::unquote() const {
string result;
......
......@@ -18,6 +18,9 @@ namespace Sass {
inline operator string() const
{ return string(begin, end - begin); }
string to_string() const
{ return string(begin, end - begin); }
string unquote() const;
void unquote_to_stream(std::stringstream& buf) const;
......@@ -26,6 +29,22 @@ namespace Sass {
operator bool()
{ return begin && end && begin >= end; }
// static Token make()
// {
// Token t;
// t.begin = 0;
// t.end = 0;
// return t;
// }
//
static Token make(const char* b = 0, const char* e = 0)
{
Token t;
t.begin = b;
t.end = e;
return t;
}
};
struct Dimension {
......
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