Commit 7c1bdd83 by Aaron Leung

Laying down infrastructure for selector inheritance.

parent 917e4d3b
......@@ -43,11 +43,13 @@ namespace Sass {
Context::Context(const char* paths_str)
: global_env(Environment()),
function_env(map<pair<string, size_t>, Function>()),
extensions(map<Node, Node>()),
pending_extensions(vector<pair<Node, Node> >()),
source_refs(vector<char*>()),
registry(vector<vector<Node>*>()),
include_paths(vector<string>()),
new_Node(Node_Factory()),
ref_count(0)
ref_count(0),
has_extensions(false)
{
register_functions();
collect_include_paths(paths_str);
......
......@@ -43,13 +43,15 @@ namespace Sass {
struct Context {
Environment global_env;
map<pair<string, size_t>, Function> function_env;
map<Node, Node> extensions;
vector<pair<Node, Node> > pending_extensions;
vector<char*> source_refs; // all the source c-strings
vector<vector<Node>*> registry; // all the child vectors
vector<string> include_paths;
Node_Factory new_Node;
size_t ref_count;
string sass_path;
string css_path;
bool has_extensions;
void collect_include_paths(const char* paths_str);
Context(const char* paths_str = 0);
......
......@@ -144,7 +144,7 @@ namespace Sass {
Node parse_simple_selector();
Node parse_pseudo();
Node parse_attribute_selector();
Node parse_block(bool in_definition = false);
Node parse_block(Node surrounding_rulesetbool, bool in_definition = false);
Node parse_rule();
Node parse_values();
Node parse_list();
......
......@@ -93,7 +93,7 @@ namespace Sass {
Node name(context.new_Node(Node::identifier, path, line, lexed));
Node params(parse_mixin_parameters());
if (!peek< exactly<'{'> >()) throw_syntax_error("body for mixin " + name.token().to_string() + " must begin with a '{'");
Node body(parse_block(true));
Node body(parse_block(Node(), true));
Node the_mixin(context.new_Node(Node::mixin, path, line, 3));
the_mixin << name << params << body;
return the_mixin;
......@@ -224,7 +224,7 @@ namespace Sass {
ruleset << parse_selector_group();
}
if (!peek< exactly<'{'> >()) throw_syntax_error("expected a '{' after the selector");
ruleset << parse_block(in_definition);
ruleset << parse_block(ruleset, in_definition);
return ruleset;
}
......@@ -308,7 +308,7 @@ namespace Sass {
if (peek< spaces >() || peek< exactly<'>'> >() ||
peek< exactly<'+'> >() || peek< exactly<'~'> >() ||
peek< exactly<','> >() || peek< exactly<')'> >() ||
peek< exactly<'{'> >())
peek< exactly<'{'> >() || peek< exactly<';'> >())
{ return simp1; }
// otherwise, we have a sequence of simple selectors
......@@ -321,7 +321,8 @@ namespace Sass {
peek < exactly<'>'> >(position) ||
peek < exactly<','> >(position) ||
peek < exactly<')'> >(position) ||
peek < exactly<'{'> >(position))) {
peek < exactly<'{'> >(position) ||
peek < exactly<';'> >(position))) {
seq << parse_simple_selector();
}
return seq;
......@@ -423,7 +424,7 @@ namespace Sass {
return attr_sel;
}
Node Document::parse_block(bool in_definition)
Node Document::parse_block(Node surrounding_ruleset, bool in_definition)
{
lex< exactly<'{'> >();
bool semicolon = false;
......@@ -475,11 +476,17 @@ namespace Sass {
block << parse_mixin_call();
semicolon = true;
}
else if (lex< extend >()) {
Node extendee(parse_simple_selector_sequence());
context.extensions[extendee] = surrounding_ruleset;
context.has_extensions = true;
semicolon = true;
}
else if (!peek< exactly<';'> >()) {
Node rule(parse_rule());
// check for lbrace; if it's there, we have a namespace property with a value
if (peek< exactly<'{'> >()) {
Node inner(parse_block());
Node inner(parse_block(Node()));
Node propset(context.new_Node(Node::propset, path, line, 2));
propset << rule[0];
rule[0] = context.new_Node(Node::property, path, line, Token::make());
......
......@@ -49,9 +49,15 @@ namespace Sass {
expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx);
}
// expand the selector with the prefix and save it in expr[2]
// cerr << "ABOUT TO EXPAND " << expr[0].to_string() << " WITH " << prefix.to_string() << endl;
expr << expand_selector(expr[0], prefix, new_Node);
// cerr << "EXPANDED SELECTOR: " << expr.back().to_string() << endl;
// gather selector extensions into a pending queue
if (ctx.has_extensions) {
Node sel(expr.back());
if (sel.type() == Node::selector) sel = sel.back();
if (ctx.extensions.count(sel)) {
ctx.pending_extensions.push_back(pair<Node, Node>(expr, ctx.extensions[sel]));
}
}
// eval the body with the current selector as the prefix
eval(expr[1], expr.back(), env, f_env, new_Node, ctx);
return expr;
......
......@@ -103,6 +103,23 @@ namespace Sass {
throw Error(Error::evaluation, path(), line(), "incompatible units");
}
}
else if ((type() >= selector_group && type() <=selector_schema) &&
(rhs.type() >= selector_group && rhs.type() <=selector_schema)) {
if (type() != rhs.type()) {
return type() < rhs.type();
}
switch (type())
{
case simple_selector: {
return token() < rhs.token();
} break;
default: {
return false;
} break;
}
}
else {
throw Error(Error::evaluation, path(), line(), "incomparable types");
}
......
......@@ -111,6 +111,10 @@ namespace Sass {
const char* include(const char* src) {
return exactly<include_kwd>(src);
}
extern const char extend_kwd[] = "@extend";
const char* extend(const char* src) {
return exactly<extend_kwd>(src);
}
const char* name(const char* src) {
return one_plus< alternatives< alnum,
......
......@@ -310,6 +310,7 @@ namespace Sass {
const char* import(const char* src);
const char* mixin(const char* src);
const char* include(const char* src);
const char* extend(const char* src);
// Match CSS type selectors
const char* namespace_prefix(const char* src);
const char* type_selector(const char* src);
......
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