Commit 414e8f5f by Aaron Leung

Refactoring the node data structure. Should reduce the size from 56 bytes down to 32 bytes.

parent bd7f9014
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 eval_apply.cpp node.cpp token.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 test: build
ruby spec.rb spec/basic/ ruby spec.rb spec/basic/
......
...@@ -12,32 +12,19 @@ using std::cerr; ...@@ -12,32 +12,19 @@ using std::cerr;
using std::endl; using std::endl;
namespace Sass { namespace Sass {
size_t Node::fresh = 0;
size_t Node::copied = 0;
size_t Node::allocations = 0; size_t Node::allocations = 0;
Node Node::clone() const Node Node::clone() const
{ {
Node n; Node n(*this);
n.line_number = line_number; if (has_children) {
n.token = token; n.contents.children = new vector<Node>;
n.numeric_value = numeric_value; ++allocations;
n.type = type; n.contents.children->reserve(size());
n.has_rules_or_comments = has_rules_or_comments;
n.has_rulesets = has_rulesets;
n.has_propsets = has_propsets;
n.has_expansions = has_expansions;
n.has_backref = has_backref;
n.from_variable = from_variable;
n.eval_me = eval_me;
if (children) {
n.children = new vector<Node>();
n.children->reserve(size());
for (int i = 0; i < size(); ++i) { for (int i = 0; i < size(); ++i) {
n << at(i).clone(); n << at(i).clone();
} }
} }
++fresh;
return n; return n;
} }
...@@ -60,43 +47,43 @@ namespace Sass { ...@@ -60,43 +47,43 @@ namespace Sass {
result += prefix; result += prefix;
result += ' '; result += ' ';
} }
if (children->at(0).type == selector_combinator) { if (at(0).type == selector_combinator) {
result += string(children->at(0).token); result += string(at(0).content.token);
result += ' '; result += ' ';
} }
else { else {
result += children->at(0).to_string(prefix); result += at(0).to_string(prefix);
} }
for (int i = 1; i < children->size(); ++i) { for (int i = 1; i < size(); ++i) {
result += children->at(i).to_string(prefix); result += at(i).to_string(prefix);
} }
return result; return result;
} break; } break;
case selector_combinator: { case selector_combinator: {
if (std::isspace(token.begin[0])) return string(" "); if (std::isspace(content.token.begin[0])) return string(" ");
else return string(" ") += string(token) += string(" "); else return string(" ") += string(content.token) += string(" ");
} break; } break;
case simple_selector_sequence: { case simple_selector_sequence: {
string result; string result;
for (int i = 0; i < children->size(); ++i) { for (int i = 0; i < size(); ++i) {
result += children->at(i).to_string(prefix); result += at(i).to_string(prefix);
} }
return result; return result;
} break; } break;
case pseudo_negation: { case pseudo_negation: {
string result(children->at(0).to_string(prefix)); string result(at(0).to_string(prefix));
result += children->at(1).to_string(prefix); result += at(1).to_string(prefix);
result += ')'; result += ')';
return result; return result;
} break; } break;
case functional_pseudo: { case functional_pseudo: {
string result(children->at(0).to_string(prefix)); string result(at(0).to_string(prefix));
for (int i = 1; i < children->size(); ++i) { for (int i = 1; i < size(); ++i) {
result += children->at(i).to_string(prefix); result += at(i).to_string(prefix);
} }
result += ')'; result += ')';
return result; return result;
...@@ -105,7 +92,7 @@ namespace Sass { ...@@ -105,7 +92,7 @@ namespace Sass {
case attribute_selector: { case attribute_selector: {
string result("["); string result("[");
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
{ result += children->at(i).to_string(prefix); } { result += at(i).to_string(prefix); }
result += ']'; result += ']';
return result; return result;
} break; } break;
...@@ -115,35 +102,35 @@ namespace Sass { ...@@ -115,35 +102,35 @@ namespace Sass {
} break; } break;
case comma_list: { case comma_list: {
string result(children->at(0).to_string(prefix)); string result(at(0).to_string(prefix));
for (int i = 1; i < children->size(); ++i) { for (int i = 1; i < size(); ++i) {
result += ", "; result += ", ";
result += children->at(i).to_string(prefix); result += at(i).to_string(prefix);
} }
return result; return result;
} break; } break;
case space_list: { case space_list: {
string result(children->at(0).to_string(prefix)); string result(at(0).to_string(prefix));
for (int i = 1; i < children->size(); ++i) { for (int i = 1; i < size(); ++i) {
result += " "; result += " ";
result += children->at(i).to_string(prefix); result += at(i).to_string(prefix);
} }
return result; return result;
} break; } break;
case expression: case expression:
case term: { case term: {
string result(children->at(0).to_string(prefix)); string result(at(0).to_string(prefix));
// for (int i = 2; i < children->size(); i += 2) { // for (int i = 2; i < size(); i += 2) {
// // result += " "; // // result += " ";
// result += children->at(i).to_string(prefix); // result += at(i).to_string(prefix);
// } // }
for (int i = 1; i < children->size(); ++i) { for (int i = 1; i < size(); ++i) {
if (!(children->at(i).type == add || if (!(at(i).type == add ||
// children->at(i).type == sub || // another edge case -- consider uncommenting // at(i).type == sub || // another edge case -- consider uncommenting
children->at(i).type == mul)) { at(i).type == mul)) {
result += children->at(i).to_string(prefix); result += at(i).to_string(prefix);
} }
} }
return result; return result;
...@@ -162,7 +149,8 @@ namespace Sass { ...@@ -162,7 +149,8 @@ namespace Sass {
stringstream ss; stringstream ss;
// ss.setf(std::ios::fixed, std::ios::floatfield); // ss.setf(std::ios::fixed, std::ios::floatfield);
// ss.precision(3); // ss.precision(3);
ss << numeric_value << string(token); ss << content.dimension.numeric_value
<< string(Token(content.dimension.unit, identifier(content.dimension.unit)));
return ss.str(); return ss.str();
} break; } break;
...@@ -170,14 +158,14 @@ namespace Sass { ...@@ -170,14 +158,14 @@ namespace Sass {
stringstream ss; stringstream ss;
// ss.setf(std::ios::fixed, std::ios::floatfield); // ss.setf(std::ios::fixed, std::ios::floatfield);
// ss.precision(3); // ss.precision(3);
ss << numeric_value; ss << content.numeric_value;
return ss.str(); return ss.str();
} break; } break;
case hex_triple: { case numeric_color: {
double a = children->at(0).numeric_value; double a = at(0).content.numeric_value;
double b = children->at(1).numeric_value; double b = at(1).content.numeric_value;
double c = children->at(2).numeric_value; double c = at(2).content.numeric_value;
if (a >= 0xff && b >= 0xff && c >= 0xff) if (a >= 0xff && b >= 0xff && c >= 0xff)
{ return "white"; } { return "white"; }
else if (a >= 0xff && b >= 0xff && c == 0) else if (a >= 0xff && b >= 0xff && c == 0)
...@@ -199,7 +187,7 @@ namespace Sass { ...@@ -199,7 +187,7 @@ namespace Sass {
stringstream ss; stringstream ss;
ss << '#' << std::setw(2) << std::setfill('0') << std::hex; ss << '#' << std::setw(2) << std::setfill('0') << std::hex;
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
double x = children->at(i).numeric_value; double x = at(i).content.numeric_value;
if (x > 0xff) x = 0xff; if (x > 0xff) x = 0xff;
else if (x < 0) x = 0; else if (x < 0) x = 0;
ss << std::hex << std::setw(2) << static_cast<unsigned long>(x); ss << std::hex << std::setw(2) << static_cast<unsigned long>(x);
...@@ -210,7 +198,7 @@ namespace Sass { ...@@ -210,7 +198,7 @@ namespace Sass {
case uri: { case uri: {
string result("url("); string result("url(");
result += string(token); result += string(content.token);
result += ")"; result += ")";
return result; return result;
} break; } break;
...@@ -221,7 +209,7 @@ namespace Sass { ...@@ -221,7 +209,7 @@ namespace Sass {
// } break; // } break;
default: { default: {
return string(token); return string(content.token);
} break; } break;
} }
} }
...@@ -234,19 +222,19 @@ namespace Sass { ...@@ -234,19 +222,19 @@ namespace Sass {
break; break;
case ruleset: case ruleset:
buf << indentation; buf << indentation;
children->at(0).echo(buf, depth); at(0).echo(buf, depth);
children->at(1).echo(buf, depth); at(1).echo(buf, depth);
break; break;
case selector_group: case selector_group:
children->at(0).echo(buf, depth); at(0).echo(buf, depth);
for (int i = 1; i < children->size(); ++i) { for (int i = 1; i < size(); ++i) {
buf << ", "; buf << ", ";
children->at(i).echo(buf, depth); at(i).echo(buf, depth);
} }
break; break;
case selector: case selector:
for (int i = 0; i < children->size(); ++i) { for (int i = 0; i < size(); ++i) {
children->at(i).echo(buf, depth); at(i).echo(buf, depth);
} }
break; break;
case selector_combinator: case selector_combinator:
...@@ -254,8 +242,8 @@ namespace Sass { ...@@ -254,8 +242,8 @@ namespace Sass {
else buf << ' ' << string(token) << ' '; else buf << ' ' << string(token) << ' ';
break; break;
case simple_selector_sequence: case simple_selector_sequence:
for (int i = 0; i < children->size(); ++i) { for (int i = 0; i < size(); ++i) {
buf << children->at(i).to_string(string()); buf << at(i).to_string(string());
} }
break; break;
case simple_selector: case simple_selector:
...@@ -263,21 +251,21 @@ namespace Sass { ...@@ -263,21 +251,21 @@ namespace Sass {
break; break;
case block: case block:
buf << " {" << endl; buf << " {" << endl;
for (int i = 0; i < children->size(); children->at(i++).echo(buf, depth+1)) ; for (int i = 0; i < size(); at(i++).echo(buf, depth+1)) ;
buf << indentation << "}" << endl; buf << indentation << "}" << endl;
break; break;
case rule: case rule:
buf << indentation; buf << indentation;
children->at(0).echo(buf, depth); at(0).echo(buf, depth);
buf << ": "; buf << ": ";
children->at(1).echo(buf, depth); at(1).echo(buf, depth);
buf << ';' << endl; buf << ';' << endl;
break; break;
case property: case property:
buf << string(token); buf << string(token);
break; break;
case values: case values:
for (int i = 0; i < children->size(); children->at(i++).echo(buf, depth)) ; for (int i = 0; i < size(); at(i++).echo(buf, depth)) ;
break; break;
case value: case value:
buf << ' ' << string(token); buf << ' ' << string(token);
...@@ -295,8 +283,8 @@ namespace Sass { ...@@ -295,8 +283,8 @@ namespace Sass {
if (at(0).has_expansions) { if (at(0).has_expansions) {
flatten(); flatten();
} }
for (int i = 0; i < children->size(); ++i) { for (int i = 0; i < size(); ++i) {
children->at(i).emit_nested_css(buf, depth, prefixes); at(i).emit_nested_css(buf, depth, prefixes);
} }
break; break;
...@@ -320,7 +308,7 @@ namespace Sass { ...@@ -320,7 +308,7 @@ namespace Sass {
} }
} }
if (block[0].has_expansions) block.flatten(); if (block[0].has_expansions) block.flatten();
if (block[0].has_rules_or_comments) { if (block[0].has_statements) {
buf << string(2*depth, ' ') << new_prefixes[0]; buf << string(2*depth, ' ') << new_prefixes[0];
for (int i = 1; i < new_prefixes.size(); ++i) { for (int i = 1; i < new_prefixes.size(); ++i) {
buf << ", " << new_prefixes[i]; buf << ", " << new_prefixes[i];
...@@ -341,14 +329,14 @@ namespace Sass { ...@@ -341,14 +329,14 @@ namespace Sass {
buf << " }" << endl; buf << " }" << endl;
++depth; // if we printed content at this level, we need to indent any nested rulesets ++depth; // if we printed content at this level, we need to indent any nested rulesets
} }
if (block[0].has_rulesets) { if (block[0].has_blocks) {
for (int i = 0; i < block.size(); ++i) { for (int i = 0; i < block.size(); ++i) {
if (block[i].type == ruleset) { if (block[i].type == ruleset) {
block[i].emit_nested_css(buf, depth, new_prefixes); block[i].emit_nested_css(buf, depth, new_prefixes);
} }
} }
} }
if (block[0].has_rules_or_comments) --depth; if (block[0].has_statements) --depth;
if (depth == 0 && prefixes.empty()) buf << endl; if (depth == 0 && prefixes.empty()) buf << endl;
} break; } break;
...@@ -364,24 +352,24 @@ namespace Sass { ...@@ -364,24 +352,24 @@ namespace Sass {
{ {
case rule: case rule:
buf << endl << string(2*depth, ' '); buf << endl << string(2*depth, ' ');
children->at(0).emit_nested_css(buf, depth); // property at(0).emit_nested_css(buf, depth); // property
children->at(1).emit_nested_css(buf, depth); // values at(1).emit_nested_css(buf, depth); // values
buf << ";"; buf << ";";
break; break;
case property: case property:
buf << string(token) << ": "; buf << string(content.token) << ": ";
break; break;
case values: case values:
for (int i = 0; i < children->size(); ++i) { for (int i = 0; i < size(); ++i) {
buf << " " << string(children->at(i).token); buf << " " << string(at(i).content.token);
} }
break; break;
case comment: case comment:
if (depth != 0) buf << endl; if (depth != 0) buf << endl;
buf << string(2*depth, ' ') << string(token); buf << string(2*depth, ' ') << string(content.token);
if (depth == 0) buf << endl; if (depth == 0) buf << endl;
break; break;
...@@ -451,7 +439,8 @@ namespace Sass { ...@@ -451,7 +439,8 @@ namespace Sass {
at(0).has_propsets |= expn[0].has_propsets; at(0).has_propsets |= expn[0].has_propsets;
at(0).has_expansions |= expn[0].has_expansions; at(0).has_expansions |= expn[0].has_expansions;
at(i).type = none; at(i).type = none;
children->insert(children->begin() + i, expn.children->begin(), expn.children->end()); children->insert(children->begin() + i,
expn.children->begin(), expn.children->end());
} }
} }
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include "token.hpp" #include "values.hpp"
namespace Sass { namespace Sass {
using std::string; using std::string;
...@@ -54,231 +54,214 @@ namespace Sass { ...@@ -54,231 +54,214 @@ namespace Sass {
textual_dimension, textual_dimension,
textual_number, textual_number,
textual_hex, textual_hex,
color_name;
string_constant, string_constant,
numeric_percentage, numeric_percentage,
numeric_dimension, numeric_dimension,
number, number,
hex_triple, numeric_color,
mixin, mixin,
parameters, parameters,
expansion, expansion,
arguments, arguments,
variable, variable,
assignment, assignment,
comment, comment,
none, none,
flags flags
}; };
static size_t fresh;
static size_t copied;
static size_t allocations;
size_t line_number;
mutable vector<Node>* children;
Token token;
double numeric_value;
Type type; Type type;
bool has_rules_or_comments; unsigned int line_number;
bool has_rulesets;
bool has_propsets; bool has_children;
bool has_statements;
bool has_blocks;
bool has_expansions; bool has_expansions;
bool has_backref; bool has_backref;
bool from_variable; bool from_variable;
bool eval_me; bool eval_me;
union {
Token token;
mutable vector<Node>* children;
Dimension dimension;
double numeric_value;
} content;
Node() : type(none), children(0) { ++fresh; } static size_t allocations;
Node(Node::Type type)
: type(type),
children(0),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false)
{ ++fresh; }
Node(const Node& n)
: line_number(n.line_number),
children(n.children),
token(n.token),
numeric_value(n.numeric_value),
type(n.type),
has_rules_or_comments(n.has_rules_or_comments),
has_rulesets(n.has_rulesets),
has_propsets(n.has_propsets),
has_expansions(n.has_expansions),
has_backref(n.has_backref),
from_variable(n.from_variable),
eval_me(n.eval_me)
{ ++copied; }
Node(size_t line_number, Type type, size_t length = 0)
: line_number(line_number),
children(new vector<Node>),
token(Token()),
numeric_value(0),
type(type),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false),
has_backref(false),
from_variable(false),
eval_me(false)
{ children->reserve(length); ++fresh; ++allocations; }
Node(size_t line_number, Type type, const Node& n)
: line_number(line_number),
children(new vector<Node>(1, n)),
token(Token()),
numeric_value(0),
type(type),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false),
has_backref(false),
from_variable(false),
eval_me(false)
{ ++fresh; ++allocations; }
Node(size_t line_number, Type type, const Node& n, const Node& m)
: line_number(line_number),
children(new vector<Node>),
token(Token()),
numeric_value(0),
type(type),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false),
has_backref(false),
from_variable(false),
eval_me(false)
{
children->reserve(2);
children->push_back(n);
children->push_back(m);
++fresh;
++allocations;
}
Node(size_t line_number, Type type, Token& token)
: line_number(line_number),
children(0),
token(token),
numeric_value(0),
type(type),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false),
has_backref(false),
from_variable(false),
eval_me(false)
{ ++fresh; }
Node(size_t line_number, double d)
: line_number(line_number),
children(0),
token(Token()),
numeric_value(d),
type(number),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false),
has_backref(false),
from_variable(false),
eval_me(false)
{ ++fresh; }
Node(size_t line_number, double d, Token& token)
: line_number(line_number),
children(0),
token(token),
numeric_value(d),
type(numeric_dimension),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false),
has_backref(false),
from_variable(false),
eval_me(false)
{ ++fresh; }
Node(size_t line_number, double a, double b, double c) void clear()
: line_number(line_number),
children(new vector<Node>()),
token(Token()),
numeric_value(0),
type(hex_triple),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false),
has_backref(false),
from_variable(false),
eval_me(false)
{ {
children->reserve(3); type = none; line_number = 0;
children->push_back(Node(line_number, a)); has_statements = false; has_blocks = false; has_expansions = false;
children->push_back(Node(line_number, b)); has_backref = false; from_variable = false; eval_me = false;
children->push_back(Node(line_number, c));
++fresh;
++allocations;
} }
//~Node() { delete children; }
size_t size() const size_t size() const
{ return children->size(); } { return content.children->size(); }
Node& operator[](const size_t i) const Node& operator[](const size_t i) const
{ return children->at(i); } { return content.children->at(i); }
Node& at(const size_t i) const Node& at(const size_t i) const
{ return children->at(i); } { return content.children->at(i); }
Node& operator=(const Node& n)
{
line_number = n.line_number;
children = n.children;
token = n.token;
numeric_value = n.numeric_value;
type = n.type;
has_rules_or_comments = n.has_rules_or_comments;
has_rulesets = n.has_rulesets;
has_propsets = n.has_propsets;
has_backref = n.has_backref;
from_variable = n.from_variable;
eval_me = n.eval_me;
++copied;
return *this;
}
Node& operator<<(const Node& n) Node& operator<<(const Node& n)
{ {
children->push_back(n); content.children->push_back(n);
return *this; return *this;
} }
Node& operator+=(const Node& n) Node& operator+=(const Node& n)
{ {
for (int i = 0; i < n.children->size(); ++i) { for (int i = 0; i < n.size(); ++i) {
children->push_back(n.children->at(i)); content.children->push_back(n[i]);
} }
return *this; return *this;
} }
string to_string(const string& prefix) const; string to_string(const string& prefix) 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);
Node clone() const;
void flatten();
Node()
{ clear(); }
Node(Type t) // flags
{ clear(); type = t; }
Node(Type t, unsigned int ln, size_t s = 0) // nodes with children
{
clear();
type = t;
line_number = ln;
content.children = new vector<Node>;
content.children->reserve(s);
has_children = true;
++allocations;
}
Node(Type t, unsigned int ln, const Token& tok) // nodes with a single token
{
clear();
type = t;
line_number = ln;
content.token = tok;
}
Node(unsigned int ln, double val) // numeric values
{
clear();
type = number;
line_number = ln;
content.numeric_value = val;
}
Node(unsigned int ln, double val, const Token& tok) // dimensions
{
clear();
type = numeric_dimension;
line_number = ln;
content.dimension.numeric_value = val;
content.dimension.unit = tok.begin;
}
Node(unsigned int ln, double r, double g, double b) // colors
{
clear();
type = numeric_color;
line_number = ln;
content.children = new vector<Node>;
content.children->reserve(3);
content.children->push_back(Node(ln, r));
content.children->push_back(Node(ln, g));
content.children->push_back(Node(ln, b));
has_children = true;
++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
};
void release() const { children = 0; } string to_string(const string& prefix) const;
Node clone() const; Node clone() const;
......
...@@ -25,7 +25,11 @@ namespace Sass { ...@@ -25,7 +25,11 @@ namespace Sass {
bool operator==(const Token& rhs) const; bool operator==(const Token& rhs) const;
operator bool() operator bool()
{ return begin && end && begin >= end; } { return begin && end && begin >= end; }
};
struct Dimension {
const double numeric_value;
const char* unit;
}; };
} }
\ No newline at end of file
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