Commit 71c31368 by Aaron Leung

Improving the node struct, and working on new parsing functionaity.

parent 9a893f9d
...@@ -12,10 +12,10 @@ namespace Sass { ...@@ -12,10 +12,10 @@ namespace Sass {
char* path; char* path;
char* source; char* source;
char* position; char* position;
unsigned int line_number; size_t line_number;
// TO DO: move the environment up into the context class when it's ready // TO DO: move the environment up into the context class when it's ready
map<string, Node> environment; map<Token, Node> environment;
vector<Node> statements; vector<Node> statements;
Token top; Token top;
...@@ -24,7 +24,8 @@ namespace Sass { ...@@ -24,7 +24,8 @@ namespace Sass {
Document(char* _path, char* _source = 0); Document(char* _path, char* _source = 0);
~Document(); ~Document();
inline Token& peek() { return top; } template <prelexer mx>
char* peek() { return mx(position); }
template <prelexer mx> template <prelexer mx>
bool try_munching() { bool try_munching() {
...@@ -68,7 +69,7 @@ namespace Sass { ...@@ -68,7 +69,7 @@ namespace Sass {
Node parse_var_def(); Node parse_var_def();
Node parse_ruleset(); Node parse_ruleset();
Node parse_selector(); Node parse_selector();
Node parse_clauses(); Node parse_block();
Node parse_values(); Node parse_values();
string emit_css(CSS_Style style); string emit_css(CSS_Style style);
......
...@@ -3,88 +3,112 @@ ...@@ -3,88 +3,112 @@
namespace Sass { namespace Sass {
void Document::parse_scss() { void Document::parse_scss() {
try_munching<optional_spaces>(); // try_munching<optional_spaces>();
while (*position) { // while (*position) {
// statements.push_back(parse_statement());
// try_munching<optional_spaces>();
// }
lex<optional_spaces>();
while(*position) {
statements.push_back(parse_statement()); statements.push_back(parse_statement());
try_munching<optional_spaces>(); lex<optional_spaces>();
} }
} }
Node Document::parse_statement() { Node Document::parse_statement() {
if (try_munching<block_comment>()) { // if (try_munching<block_comment>()) {
return Node(Node::comment, top); // return Node(line_number, Node::comment, top);
// }
// else if (try_munching<variable>()) {
// return parse_var_def();
// }
// else return parse_ruleset();
if (lex<block_comment>()) {
return Node(line_number, Node::comment, lexed);
} }
else if (try_munching<variable>()) { else if (lex<variable>()) {
return parse_var_def(); return parse_var_def();
} }
else return parse_ruleset(); else return parse_ruleset();
} }
Node Document::parse_var_def() { Node Document::parse_var_def() {
const Token key = top; // const Token key(top);
try_munching<exactly<':'> >(); // try_munching<exactly<':'> >();
environment[string(key)] = parse_values(); // environment[key] = parse_values();
try_munching<exactly<';'> >(); // try_munching<exactly<';'> >();
return Node(Node::nil); // return Node(line_number, Node::nil, top);
const Token key(lexed);
lex< exactly<':'> >();
environment[key] = parse_values();
lex< exactly<';'> >();
return Node();
} }
Node Document::parse_ruleset() { Node Document::parse_ruleset() {
Node ruleset(Node::ruleset); Node ruleset(line_number, Node::ruleset, 2);
ruleset.push_child(parse_selector()); ruleset << parse_selector();
ruleset.push_child(parse_clauses()); ruleset << parse_block();
return ruleset; return ruleset;
} }
Node Document::parse_selector() { Node Document::parse_selector() {
try_munching<identifier>(); try_munching<identifier>();
return Node(Node::selector, top); return Node(line_number, Node::selector, top);
} }
Node Document::parse_clauses() { Node Document::parse_block() {
try_munching<exactly<'{'> >(); try_munching<exactly<'{'> >();
Node decls(Node::clauses); Node decls(line_number, Node::block);
while(!try_munching<exactly<'}'> >()) { while(!try_munching<exactly<'}'> >()) {
if (try_munching<block_comment>()) { if (try_munching<block_comment>()) {
decls.push_child(Node(Node::comment, top)); decls << Node(line_number, Node::comment, top);
continue; continue;
} }
else if (try_munching<variable>()) { else if (try_munching<variable>()) {
decls.push_child(parse_var_def()); decls << parse_var_def();
continue; continue;
} }
try_munching<identifier>(); try_munching<identifier>();
Token id = top; Token id = top;
if (try_munching<exactly<':'> >()) { if (try_munching<exactly<':'> >()) {
Node rule(Node::rule); Node rule(line_number, Node::rule, 2);
rule.push_child(Node(Node::property, id)); rule << Node(line_number, Node::property, id);
rule.push_child(parse_values()); rule << parse_values();
decls.push_child(rule); decls << rule;
decls.has_rules = true;
try_munching<exactly<';'> >(); try_munching<exactly<';'> >();
} }
else { else {
Node ruleset(Node::ruleset); Node ruleset(line_number, Node::ruleset, 2);
ruleset.push_child(Node(Node::selector, id)); ruleset << Node(line_number, Node::selector, id);
ruleset.push_child(parse_clauses()); ruleset << parse_block();
decls.push_opt_child(ruleset); decls << ruleset;
decls.has_rulesets = true;
} }
} }
return decls; return decls;
} }
Node Document::parse_values() { Node Document::parse_values() {
Node values(Node::values); Node values(line_number, Node::values);
while(try_munching<identifier>() || try_munching<dimension>() || while(try_munching<identifier>() || try_munching<dimension>() ||
try_munching<percentage>() || try_munching<number>() || try_munching<percentage>() || try_munching<number>() ||
try_munching<hex>() || try_munching<string_constant>() || try_munching<hex>() || try_munching<string_constant>() ||
try_munching<variable>()) { try_munching<variable>()) {
if (top.begin[0] == '$') { if (top.begin[0] == '$') {
Node stuff(environment[string(top)]); Node stuff(environment[top]);
for (int i = 0; i < stuff.children->size(); ++i) { for (int i = 0; i < stuff.children->size(); ++i) {
values.push_child((*(stuff.children))[i]); values << stuff.children->at(i);
} }
} }
else else
values.push_child(Node(Node::value, top)); {
values << Node(line_number, Node::value, top);
}
} }
return values; return values;
} }
......
...@@ -5,43 +5,44 @@ ...@@ -5,43 +5,44 @@
using std::string; using std::string;
using std::stringstream; using std::stringstream;
using std::cout; using std::cout;
using std::cerr;
using std::endl; using std::endl;
namespace Sass { namespace Sass {
unsigned int Node::fresh = 0; size_t Node::fresh = 0;
unsigned int Node::copied = 0; size_t Node::copied = 0;
Node::Node() { ++fresh; children = 0; opt_children = 0; } // Node::Node() { ++fresh; children = 0; opt_children = 0; }
Node::Node(Node_Type _type) { // Node::Node(Node_Type _type) {
type = _type; // type = _type;
children = new vector<Node>; // children = new vector<Node>;
opt_children = new vector<Node>; // opt_children = new vector<Node>;
++fresh; // ++fresh;
} // }
Node::Node(Node_Type _type, Token& _token) { // Node::Node(Node_Type _type, Token& _token) {
type = _type; // type = _type;
token = _token; // token = _token;
children = 0; // children = 0;
opt_children = 0; // opt_children = 0;
++fresh; // ++fresh;
} // }
Node::Node(const Node& n) { // Node::Node(const Node& n) {
type = n.type; // type = n.type;
token = n.token; // token = n.token;
children = n.children; // children = n.children;
opt_children = n.opt_children; // opt_children = n.opt_children;
++copied; // ++copied;
} // }
//
// void Node::push_child(const Node& node) {
// if (!children) children = new vector<Node>;
// children->push_back(node);
// }
// void Node::push_opt_child(const Node& node) {
// if (!opt_children) opt_children = new vector<Node>;
// opt_children->push_back(node);
// }
void Node::push_child(const Node& node) { // void Node::dump(unsigned int depth) {
if (!children) children = new vector<Node>;
children->push_back(node);
}
void Node::push_opt_child(const Node& node) {
if (!opt_children) opt_children = new vector<Node>;
opt_children->push_back(node);
}
void Node::dump(unsigned int depth) {
// switch (type) { // switch (type) {
// case comment: // case comment:
// for (int i = depth; i > 0; --i) cout << " "; // for (int i = depth; i > 0; --i) cout << " ";
...@@ -84,35 +85,32 @@ namespace Sass { ...@@ -84,35 +85,32 @@ namespace Sass {
// break; // break;
// default: cout << "HUH?"; break; // default: cout << "HUH?"; break;
// } // }
} // }
void Node::emit_nested_css(stringstream& buf, void Node::emit_nested_css(stringstream& buf,
const string& prefix, const string& prefix,
size_t depth) { size_t depth) {
string indentation(2 * depth, ' '); string indentation(2 * depth, ' ');
bool has_rules, has_nested_rulesets; vector<Node>* nodes;
if (type == ruleset) { if (type == ruleset) {
// has_rules = !((*children)[1].children->empty()); nodes = children->at(1).children;
has_rules = !(children->at(1).children->empty()); has_rules = children->at(1).has_rules;
// has_nested_rulesets = !((*children)[1].opt_children->empty()); has_rulesets = children->at(1).has_rulesets;
has_nested_rulesets = !(children->at(1).opt_children->empty());
} }
switch (type) { switch (type) {
case ruleset: case ruleset:
if (has_rules) { if (has_rules) {
buf << indentation; buf << indentation;
// (*children)[0].emit_nested_css(buf, prefix, depth); // selector
children->at(0).emit_nested_css(buf, prefix, depth); // selector children->at(0).emit_nested_css(buf, prefix, depth); // selector
buf << " {"; buf << " {";
for (int i = 0; i < (*children)[1].children->size(); ++i) { for (int i = 0; i < nodes->size(); ++i) {
// (*(*children)[1].children)[i].emit_nested_css(buf, "", depth + 1); // rules if (nodes->at(i).type == rule) nodes->at(i).emit_nested_css(buf, "", depth + 1); // rules
children->at(1).children->at(i).emit_nested_css(buf, "", depth + 1); // rules
} }
buf << " }" << endl; buf << " }" << endl;
} }
if (has_nested_rulesets) { if (has_rulesets) {
for (int i = 0; i < children->at(1).opt_children->size(); ++i) { // do each nested ruleset for (int i = 0; i < nodes->size(); ++i) { // do each nested ruleset
children->at(1).opt_children->at(i).emit_nested_css(buf, prefix + (prefix.empty() ? "" : " ") + string((*children)[0].token), depth + (has_rules ? 1 : 0)); if (nodes->at(i).type == ruleset) nodes->at(i).emit_nested_css(buf, prefix + (prefix.empty() ? "" : " ") + string((*children)[0].token), depth + (has_rules ? 1 : 0));
} }
} }
if (depth == 0 && prefix.empty()) buf << endl; if (depth == 0 && prefix.empty()) buf << endl;
......
...@@ -6,102 +6,156 @@ namespace Sass { ...@@ -6,102 +6,156 @@ namespace Sass {
using std::vector; using std::vector;
using std::stringstream; using std::stringstream;
// struct Node {
// enum Node_Type {
// nil,
// comment,
// ruleset,
// clauses,
// selector_group,
// selector,
// simple_selector_sequence,
// simple_selector,
// rule,
// property,
// values,
// value
// };
//
// static unsigned int fresh;
// static unsigned int copied;
//
// Node_Type type;
// Token token;
// vector<Node>* children;
// vector<Node>* opt_children;
//
// Node();
// Node(Node_Type _type);
// Node(Node_Type _type, Token& _token);
// Node(const Node& n);
//
// void push_child(const Node& node);
// void push_opt_child(const Node& node);
// void dump(unsigned int depth = 0);
// void emit_nested_css(stringstream& buf, const string& prefix, size_t depth);
// void emit_expanded_css(stringstream& buf, const string& prefix);
// };
struct Node { struct Node {
enum Node_Type { enum Type {
nil, nil,
comment, comment,
ruleset, ruleset,
clauses, propset,
selector_group, selector_group,
selector, selector,
simple_selector_sequence, simple_selector_sequence,
simple_selector, type_selector,
class_selector,
id_selector,
attribute_selector,
block,
rule, rule,
property, property,
values, values,
value value
}; };
static unsigned int fresh; static size_t fresh;
static unsigned int copied; static size_t copied;
Node_Type type; size_t line_number;
mutable vector<Node>* children;
Token token; Token token;
vector<Node>* children; Type type;
vector<Node>* opt_children; bool has_rules;
bool has_rulesets;
bool has_propsets;
Node() { ++fresh; }
Node(const Node& n)
: line_number(n.line_number),
children(n.children),
token(n.token),
type(n.type),
has_rules(n.has_rules),
has_rulesets(n.has_rulesets),
has_propsets(n.has_propsets)
{ /*n.release();*/ ++copied; } // No joint custody.
Node(size_t line_number, Type type, size_t length = 0)
: line_number(line_number),
children(new vector<Node>),
token(Token()),
type(type),
has_rules(false),
has_rulesets(false),
has_propsets(false)
{ children->reserve(length); ++fresh; }
Node(); Node(size_t line_number, Type type, const Node& n)
Node(Node_Type _type); : line_number(line_number),
Node(Node_Type _type, Token& _token); children(new vector<Node>(1, n)),
Node(const Node& n); token(Token()),
type(type),
has_rules(false),
has_rulesets(false),
has_propsets(false)
{ ++fresh; }
Node(size_t line_number, Type type, const Node& n, const Node& m)
: line_number(line_number),
children(new vector<Node>),
token(Token()),
type(type),
has_rules(false),
has_rulesets(false),
has_propsets(false)
{
children->reserve(2);
children->push_back(n);
children->push_back(m);
++fresh;
}
Node(size_t line_number, Type type, Token& token)
: line_number(line_number),
children(0),
token(token),
type(type),
has_rules(false),
has_rulesets(false),
has_propsets(false)
{ ++fresh; }
//~Node() { delete children; }
Node& operator=(const Node& n)
{
line_number = n.line_number;
children = n.children;
// n.release();
token = n.token;
type = n.type;
has_rules = n.has_rules;
has_rulesets = n.has_rulesets;
has_propsets = n.has_propsets;
++copied;
return *this;
}
// Node& operator+=(const Node& node);
Node& operator<<(const Node& n)
{
children->push_back(n);
return *this;
}
void release() const { children = 0; }
void push_child(const Node& node);
void push_opt_child(const Node& node);
void dump(unsigned int depth = 0);
void emit_nested_css(stringstream& buf, const string& prefix, size_t depth); void emit_nested_css(stringstream& buf, const string& prefix, size_t depth);
void emit_expanded_css(stringstream& buf, const string& prefix); void emit_expanded_css(stringstream& buf, const string& prefix);
}; };
// struct Node {
// enum Type {
// nil,
// comment,
// ruleset,
// selector_group,
// selector,
// simple_selector_sequence,
// type_selector,
// class_selector,
// id_selector,
// attribute_selector,
// clauses,
// rule,
// property,
// values,
// value
// };
//
// size_t line_number;
// mutable vector<Node>* children;
// Token token;
// Type type;
// bool has_rules;
// bool has_rulesets;
// bool has_nested_properties;
//
// Node(const Node& n)
// : line_number(n.line_number),
// children(n.children),
// token(n.token),
// type(n.type),
// has_rules(n.has_rules),
// has_rulesets(n.has_rulesets),
// has_nested_properties(n.has_nested_properties)
// { n.release(); } // No joint custody.
//
// Node(size_t line_number, Type type, size_t length = 0)
// : line_number(line_number),
// children(new vector<Node>),
// token(Token()),
// type(type),
// has_rules(false),
// has_rulesets(false),
// has_nested_properties(false)
// { children->reserve(length); }
//
// Node(size_t line_number, Type type, Token& token)
// : line_number(line_number),
// children(0),
// token(token),
// type(type),
// has_rules(false),
// has_rulesets(false),
// has_nested_properties(false)
// { }
//
// Node& operator=(const Node& node);
// Node& operator+=(const Node& node);
// Node& operator<<(const Node& node);
// void release() const { children = 0; }
// };
} }
\ No newline at end of file
...@@ -40,4 +40,20 @@ namespace Sass { ...@@ -40,4 +40,20 @@ namespace Sass {
return; return;
} }
} }
using std::lexicographical_compare;
bool Token::operator<(const Token& rhs) const
{
const char* first1 = begin;
const char* last1 = end;
const char* first2 = rhs.begin;
const char* last2 = rhs.end;
while (first1!=last1)
{
if (first2==last2 || *first2<*first1) return false;
else if (*first1<*first2) return true;
first1++; first2++;
}
return (first2!=last2);
}
} }
\ No newline at end of file
...@@ -21,5 +21,7 @@ namespace Sass { ...@@ -21,5 +21,7 @@ namespace Sass {
void stream_unquoted(std::stringstream& buf) const; void stream_unquoted(std::stringstream& buf) const;
bool operator<(const Token& rhs) const;
}; };
} }
\ 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