Commit a6ae423a by Aaron Leung

Gah, finally got parsing of comma-separated groups of simple selectors working.

parent 5020e4bd
......@@ -7,7 +7,7 @@ namespace Sass {
using namespace Prelexer;
struct Document {
enum CSS_Style { nested, expanded, compact, compressed };
enum CSS_Style { nested, expanded, compact, compressed, echo };
char* path;
char* source;
......@@ -130,8 +130,8 @@ namespace Sass {
// }
void parse_scss();
Node parse_statement();
Node parse_var_def();
// Node parse_statement();
void parse_var_def();
Node parse_ruleset();
Node parse_selector_group();
Node parse_selector();
......
......@@ -9,6 +9,9 @@ namespace Sass {
stringstream output;
for (int i = 0; i < statements.size(); ++i) {
switch (style) {
case echo:
statements[i].echo();
break;
case nested:
statements[i].emit_nested_css(output, "", 0);
break;
......
#include "document.hpp"
#include <iostream>
namespace Sass {
using namespace std;
void Document::parse_scss()
{
// cerr << "parse_scss" << endl;
lex<optional_spaces>();
while(*position) {
statements.push_back(parse_statement());
if (lex< block_comment >()) {
statements.push_back(Node(line_number, Node::comment, lexed));
}
else if (lex< variable >()) {
parse_var_def();
}
else {
statements.push_back(parse_ruleset());
}
lex<optional_spaces>();
}
}
Node Document::parse_statement()
{
if (lex<block_comment>()) {
return Node(line_number, Node::comment, lexed);
}
else if (lex<variable>()) {
return parse_var_def();
}
else return parse_ruleset();
}
// Node Document::parse_statement()
// {
// if (lex<block_comment>()) {
// return Node(line_number, Node::comment, lexed);
// }
// else if (lex<variable>()) {
// parse_var_def();
// }
// else return parse_ruleset();
// }
Node Document::parse_var_def()
void Document::parse_var_def()
{
// cerr << "parse_var_def" << endl;
const Token key(lexed);
lex< exactly<':'> >();
environment[key] = parse_values();
lex< exactly<';'> >();
return Node();
}
Node Document::parse_ruleset()
{
// cerr << "parse_ruleset" << endl;
Node ruleset(line_number, Node::ruleset, 2);
ruleset << parse_selector_group();
ruleset << parse_block();
......@@ -41,6 +53,7 @@ namespace Sass {
Node Document::parse_selector_group()
{
// cerr << "parse_selector_group" << endl;
Node group(line_number, Node::selector_group, 1);
group << parse_selector();
while (lex< exactly<','> >()) group << parse_selector();
......@@ -49,27 +62,38 @@ namespace Sass {
Node Document::parse_selector()
{
// cerr << "parse_selector" << endl;
lex<identifier>();
return Node(line_number, Node::selector, lexed);
}
Node Document::parse_block()
{
// cerr << "parse_block" << endl;
lex< exactly<'{'> >();
bool semicolon = false;
Node block(line_number, Node::block);
while (!lex< exactly<'}'> >()) {
while (!lex < exactly<'}'> >()) {
if (semicolon) {
lex< exactly<';'> >(); // enforce terminal ';' here
semicolon = false;
if (lex< exactly<'}'> >()) break;
}
if (lex< block_comment >()) {
// cerr << "grabbed a comment" << endl;
block << Node(line_number, Node::comment, lexed);
block.has_comments = true;
block.has_rules_or_comments = true;
semicolon = true;
continue;
}
else if (lex< variable >()) {
block << parse_var_def();
parse_var_def();
continue;
}
else if (look_for_rule()) {
else if (look_for_rule(position)) {
block << parse_rule();
block.has_rules = true;
block.has_rules_or_comments = true;
semicolon = true;
continue;
}
else {
......@@ -102,6 +126,7 @@ namespace Sass {
}
Node Document::parse_rule() {
// cerr << "parse_rule" << endl;
Node rule(line_number, Node::rule, 2);
lex< identifier >();
rule << Node(line_number, Node::property, lexed);
......@@ -112,6 +137,7 @@ namespace Sass {
Node Document::parse_values()
{
// cerr << "parse_value" << endl;
Node values(line_number, Node::values);
while (lex< identifier >() || lex < dimension >() ||
lex< percentage >() || lex < number >() ||
......@@ -132,7 +158,12 @@ namespace Sass {
char* Document::look_for_rule(char* start)
{
// cerr << "look_for_rule" << endl;
char* p = start ? start : position;
// if (p = peek<identifier>(p)) cerr << string(Token(start, p)) << endl;
// if (p = peek<exactly<':'> >(p)) cerr << string(Token(start, p)) << endl;
// if (p = look_for_values(p)) cerr << string(Token(start, p)) << endl;
// if (p = peek< alternatives< exactly<';'>, exactly<'}'> > >(p)) cerr << string(Token(start, p)) << endl;
(p = peek< identifier >(p)) &&
(p = peek< exactly<':'> >(p)) &&
(p = look_for_values(p)) &&
......@@ -142,13 +173,16 @@ namespace Sass {
char* Document::look_for_values(char* start)
{
// cerr << "look_for_values" << endl;
char* p = start ? start : position;
char* q;
while ((q = peek< identifier >(p)) || (q = peek< dimension >(p)) ||
(q = peek< percentage >(p)) || (q = peek< number >(p)) ||
(q = peek< hex >(p)) || (q = peek< string_constant >(p)) ||
(q = peek< variable >(p)))
{ p = q; }
{ /* cerr << *q; */ p = q; }
// cerr << string(Token(start, p)) << "blah" ;
// cerr << (p == start ? "nothing" : "something") << endl;
return p == start ? 0 : p;
}
}
\ No newline at end of file
......@@ -87,31 +87,80 @@ namespace Sass {
// }
// }
void Node::echo(size_t depth) {
string indentation(2*depth, ' ');
// cout << "Trying to echo!";
switch (type) {
case comment:
cout << indentation << string(token) << endl;
break;
case ruleset:
cout << indentation;
children->at(0).echo(depth);
children->at(1).echo(depth);
break;
case selector_group:
children->at(0).echo(depth);
for (int i = 1; i < children->size(); ++i) {
cout << ", ";
children->at(i).echo(depth);
}
break;
case selector:
cout << string(token);
break;
case block:
cout << " {" << endl;
for (int i = 0; i < children->size(); children->at(i++).echo(depth+1)) ;
cout << indentation << "}" << endl;
break;
case rule:
cout << indentation;
children->at(0).echo(depth);
cout << ':';
children->at(1).echo(depth);
cout << ';' << endl;
break;
case property:
cout << string(token);
break;
case values:
for (int i = 0; i < children->size(); children->at(i++).echo(depth)) ;
break;
case value:
cout << ' ' << string(token);
break;
}
}
void Node::emit_nested_css(stringstream& buf,
const string& prefix,
size_t depth) {
string indentation(2 * depth, ' ');
vector<Node>* nodes;
vector<Node>* contents;
if (type == ruleset) {
nodes = children->at(1).children;
has_comments = children->at(1).has_comments;
has_rules = children->at(1).has_rules;
has_rulesets = children->at(1).has_rulesets;
Node block(children->at(1));
contents = block.children;
has_rules_or_comments = block.has_rules_or_comments;
has_rulesets = block.has_rulesets;
}
switch (type) {
case ruleset:
if (has_comments || has_rules) {
if (has_rules_or_comments) {
buf << indentation;
children->at(0).emit_nested_css(buf, prefix, depth); // selector group
buf << " {";
for (int i = 0; i < nodes->size(); ++i) {
if (nodes->at(i).type == comment || nodes->at(i).type == rule) nodes->at(i).emit_nested_css(buf, "", depth + 1); // rules
for (int i = 0; i < contents->size(); ++i) {
if (contents->at(i).type == comment || contents->at(i).type == rule) contents->at(i).emit_nested_css(buf, "", depth + 1); // rules
}
buf << " }" << endl;
}
if (has_rulesets) {
for (int i = 0; i < nodes->size(); ++i) { // do each nested ruleset
if (nodes->at(i).type == ruleset) nodes->at(i).emit_nested_css(buf, prefix + (prefix.empty() ? "" : " ") + string((*children)[0].token), depth + (has_comments || has_rules ? 1 : 0));
for (int i = 0; i < contents->size(); ++i) { // do each nested ruleset
if (contents->at(i).type == ruleset) contents->at(i).emit_nested_css(buf, prefix + (prefix.empty() ? "" : " ") + string((*children)[0].token), depth + (has_rules_or_comments ? 1 : 0));
}
}
if (depth == 0 && prefix.empty()) buf << endl;
......@@ -131,8 +180,10 @@ namespace Sass {
}
break;
case selector_group:
// UNFINISHED
children->at(0).emit_nested_css(buf, prefix, depth);
for (int i = 1; i < children->size(); ++i) {
children->at(i).emit_nested_css(buf, prefix, depth);
}
break;
case selector:
buf << prefix << (prefix.empty() ? "" : " ") << string(token);
......
......@@ -69,8 +69,7 @@ namespace Sass {
mutable vector<Node>* children;
Token token;
Type type;
bool has_comments;
bool has_rules;
bool has_rules_or_comments;
bool has_rulesets;
bool has_propsets;
......@@ -81,7 +80,7 @@ namespace Sass {
children(n.children),
token(n.token),
type(n.type),
has_rules(n.has_rules),
has_rules_or_comments(n.has_rules_or_comments),
has_rulesets(n.has_rulesets),
has_propsets(n.has_propsets)
{ /*n.release();*/ ++copied; } // No joint custody.
......@@ -91,7 +90,7 @@ namespace Sass {
children(new vector<Node>),
token(Token()),
type(type),
has_rules(false),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false)
{ children->reserve(length); ++fresh; }
......@@ -101,7 +100,7 @@ namespace Sass {
children(new vector<Node>(1, n)),
token(Token()),
type(type),
has_rules(false),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false)
{ ++fresh; }
......@@ -111,7 +110,7 @@ namespace Sass {
children(new vector<Node>),
token(Token()),
type(type),
has_rules(false),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false)
{
......@@ -126,7 +125,7 @@ namespace Sass {
children(0),
token(token),
type(type),
has_rules(false),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false)
{ ++fresh; }
......@@ -140,7 +139,7 @@ namespace Sass {
// n.release();
token = n.token;
type = n.type;
has_rules = n.has_rules;
has_rules_or_comments = n.has_rules_or_comments;
has_rulesets = n.has_rulesets;
has_propsets = n.has_propsets;
++copied;
......@@ -156,6 +155,7 @@ namespace Sass {
void release() const { children = 0; }
void echo(size_t depth = 0);
void emit_nested_css(stringstream& buf, const string& prefix, size_t depth);
void emit_expanded_css(stringstream& buf, const string& prefix);
};
......
......@@ -20,6 +20,7 @@ int main(int argc, char* argv[]) {
string style_name(argv[++i]);
if (style_name == "nested") style = Document::nested;
else if (style_name == "expanded") style = Document::expanded;
else if (style_name == "echo") style = Document::echo;
}
else {
path = argv[i];
......
......@@ -4,7 +4,7 @@ $blip: "a 'red' and \"blue\" value";
/* top level comment -- should be preserved */
div {
/* another comment that should be preserved */
color: red;
color: gray;
background: blue;
$blux: hux; // gone!
span {
......@@ -21,7 +21,7 @@ div {
empty {
not_empty {
blah: blah; // gone!
bloo: bloo;
bloo: bloo // the last rule in a block may omit the semicolon
}
}
p {
......
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