diff --git a/Makefile b/Makefile index dea46dadd..221f4ed92 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,9 @@ SOURCES = \ constants.cpp \ context.cpp \ contextualize.cpp \ + contextualize_eval.cpp \ cssize.cpp \ + listize.cpp \ error_handling.cpp \ eval.cpp \ expand.cpp \ diff --git a/Makefile.am b/Makefile.am index d4c56043b..f4f89a3d3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -55,11 +55,13 @@ libsass_la_SOURCES = \ constants.cpp constants.hpp \ context.cpp context.hpp \ contextualize.cpp contextualize.hpp \ + contextualize_eval.cpp contextualize_eval.hpp \ error_handling.cpp error_handling.hpp \ eval.cpp eval.hpp \ expand.cpp expand.hpp \ extend.cpp extend.hpp \ cssize.cpp cssize.hpp \ + listize.cpp listize.hpp \ file.cpp file.hpp \ functions.cpp functions.hpp \ inspect.cpp inspect.hpp \ diff --git a/ast.hpp b/ast.hpp index 80232b62c..fcd906916 100644 --- a/ast.hpp +++ b/ast.hpp @@ -87,6 +87,7 @@ namespace Sass { STRING, LIST, MAP, + SELECTOR, NULL_VAL, NUM_TYPES }; @@ -1695,6 +1696,22 @@ namespace Sass { ////////////////////////////////////////////////////////////////////////////////////////// inline Expression* List::value_at_index(size_t i) { return is_arglist_ ? ((Argument*)(*this)[i])->value() : (*this)[i]; } + //////////// + // The Parent Selector Expression. + //////////// + class Parent_Selector : public Expression { + ADD_PROPERTY(Selector*, selector); + public: + Parent_Selector(ParserState pstate, Selector* r = 0) + : Expression(pstate), selector_(r) + { concrete_type(SELECTOR); } + virtual Selector* selector() { return selector_; } + string type() { return "selector"; } + static string type_name() { return "selector"; } + + ATTACH_OPERATIONS(); + }; + ///////////////////////////////////////// // Abstract base class for CSS selectors. ///////////////////////////////////////// diff --git a/ast_factory.hpp b/ast_factory.hpp index eae09a92d..33646ff8b 100644 --- a/ast_factory.hpp +++ b/ast_factory.hpp @@ -69,6 +69,7 @@ namespace Sass { String_Constant* new_String_Constant(string p, size_t l, const char* beg, const char* end); Feature_Query_Condition* new_Feature_Query_Condition(string p, size_t l, String* f, Expression* v); Media_Expression* new_Media_Expression(string p, size_t l, String* f, Expression* v); + Parent_Selector* new_Parent_Selector(string p, size_t l, Selector* s); // parameters and arguments Parameter* new_Parameter(string p, size_t l, string n, Expression* def = 0, bool rest = false); Parameters* new_Parameters(string p, size_t l); @@ -76,6 +77,7 @@ namespace Sass { Arguments* new_Arguments(string p, size_t l); // selectors Selector_Schema* new_Selector_Schema(string p, size_t l, String* c); + Attribute_Selector* new_Attribute_Selector(string p, size_t l, string n, string m, String* v); Simple_Selector* new_Simple_Selector(string p, size_t l, string c); Reference_Selector* new_Reference_Selector(string p, size_t l); Placeholder_Selector* new_Placeholder_Selector(string p, size_t l, string n); diff --git a/ast_fwd_decl.hpp b/ast_fwd_decl.hpp index 83b46d0fc..7da1fa701 100644 --- a/ast_fwd_decl.hpp +++ b/ast_fwd_decl.hpp @@ -60,6 +60,7 @@ namespace Sass { class Feature_Query_Condition; class At_Root_Expression; class Null; + class Parent_Selector; // parameters and arguments class Parameter; class Parameters; diff --git a/bind.cpp b/bind.cpp index d0cba9e71..b64e6f331 100644 --- a/bind.cpp +++ b/bind.cpp @@ -161,9 +161,11 @@ namespace Sass { // make sure to eval the default value in the env that we've been populating Env* old_env = eval->env; Backtrace* old_bt = eval->backtrace; + Contextualize* old_context = eval->contextualize; Expression* dv = leftover->default_value()->perform(eval->with(env, eval->backtrace)); eval->env = old_env; eval->backtrace = old_bt; + eval->contextualize = old_context; // dv->perform(&to_string); env->current_frame()[leftover->name()] = dv; } diff --git a/context.cpp b/context.cpp index f1facefec..7e59ea45f 100644 --- a/context.cpp +++ b/context.cpp @@ -17,7 +17,9 @@ #include "expand.hpp" #include "eval.hpp" #include "contextualize.hpp" +#include "contextualize_eval.hpp" #include "cssize.hpp" +#include "listize.hpp" #include "extend.hpp" #include "remove_placeholders.hpp" #include "color_names.hpp" @@ -311,9 +313,11 @@ namespace Sass { for (size_t i = 0, S = c_functions.size(); i < S; ++i) { register_c_function(*this, &tge, c_functions[i]); } - Eval eval(*this, &tge, &backtrace); - Contextualize contextualize(*this, &eval, &tge, &backtrace); - Expand expand(*this, &eval, &contextualize, &tge, &backtrace); + Contextualize contextualize(*this, &tge, &backtrace); + Listize listize(*this, &tge, &backtrace); + Eval eval(*this, &contextualize, &listize, &tge, &backtrace); + Contextualize_Eval contextualize_eval(*this, &eval, &tge, &backtrace); + Expand expand(*this, &eval, &contextualize_eval, &tge, &backtrace); Cssize cssize(*this, &tge, &backtrace); root = root->perform(&expand)->block(); root = root->perform(&cssize)->block(); diff --git a/contextualize.cpp b/contextualize.cpp index 07c2a1a76..48917e18e 100644 --- a/contextualize.cpp +++ b/contextualize.cpp @@ -7,8 +7,8 @@ namespace Sass { - Contextualize::Contextualize(Context& ctx, Eval* eval, Env* env, Backtrace* bt, Selector* placeholder, Selector* extender) - : ctx(ctx), eval(eval), env(env), parent(0), backtrace(bt), placeholder(placeholder), extender(extender) + Contextualize::Contextualize(Context& ctx, Env* env, Backtrace* bt, Selector* placeholder, Selector* extender) + : ctx(ctx), env(env), backtrace(bt), parent(0), placeholder(placeholder), extender(extender) { } Contextualize::~Contextualize() { } @@ -26,18 +26,6 @@ namespace Sass { return this; } - Selector* Contextualize::operator()(Selector_Schema* s) - { - To_String to_string(&ctx); - string result_str(s->contents()->perform(eval->with(env, backtrace))->perform(&to_string)); - result_str += '{'; // the parser looks for a brace to end the selector - Parser p = Parser::from_c_str(result_str.c_str(), ctx, s->pstate()); - p.block_stack.push_back(s->last_block()); - p.last_media_block = s->media_block(); - Selector* result_sel = p.parse_selector_group(); - return result_sel->perform(this); - } - Selector* Contextualize::operator()(Selector_List* s) { Selector_List* p = static_cast(parent); @@ -126,18 +114,6 @@ namespace Sass { Selector* Contextualize::operator()(Pseudo_Selector* s) { return s; } - Selector* Contextualize::operator()(Attribute_Selector* s) - { - // the value might be interpolated; evaluate it - String* v = s->value(); - if (v && eval) { - v = static_cast(v->perform(eval->with(env, backtrace))); - } - Attribute_Selector* ss = new (ctx.mem) Attribute_Selector(*s); - ss->value(v); - return ss; - } - Selector* Contextualize::operator()(Selector_Qualifier* s) { return s; } @@ -162,6 +138,4 @@ namespace Sass { ss->selector(parent); return ss; } - - } diff --git a/contextualize.hpp b/contextualize.hpp index 49d27e6da..7efccd1c0 100644 --- a/contextualize.hpp +++ b/contextualize.hpp @@ -1,7 +1,6 @@ #ifndef SASS_CONTEXTUALIZE_H #define SASS_CONTEXTUALIZE_H -#include "eval.hpp" #include "context.hpp" #include "operation.hpp" #include "environment.hpp" @@ -14,29 +13,26 @@ namespace Sass { class Contextualize : public Operation_CRTP { + + public: Context& ctx; - Eval* eval; Env* env; - Selector* parent; Backtrace* backtrace; - - Selector* fallback_impl(AST_Node* n); - - public: + Selector* parent; Selector* placeholder; Selector* extender; - Contextualize(Context&, Eval*, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0); + + Selector* fallback_impl(AST_Node* n); + Contextualize(Context&, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0); virtual ~Contextualize(); Contextualize* with(Selector*, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0); using Operation::operator(); - Selector* operator()(Selector_Schema*); Selector* operator()(Selector_List*); Selector* operator()(Complex_Selector*); Selector* operator()(Compound_Selector*); Selector* operator()(Wrapped_Selector*); Selector* operator()(Pseudo_Selector*); - Selector* operator()(Attribute_Selector*); Selector* operator()(Selector_Qualifier*); Selector* operator()(Type_Selector*); Selector* operator()(Selector_Placeholder*); diff --git a/contextualize_eval.cpp b/contextualize_eval.cpp new file mode 100644 index 000000000..762ab1874 --- /dev/null +++ b/contextualize_eval.cpp @@ -0,0 +1,88 @@ +#include "contextualize_eval.hpp" +#include "ast.hpp" +#include "eval.hpp" +#include "backtrace.hpp" +#include "to_string.hpp" +#include "parser.hpp" + +namespace Sass { + + Contextualize_Eval::Contextualize_Eval(Context& ctx, Eval* eval, Env* env, Backtrace* bt) + : Contextualize(ctx, env, bt), eval(eval) + { } + + Contextualize_Eval::~Contextualize_Eval() { } + + Selector* Contextualize_Eval::fallback_impl(AST_Node* n) + { return Contextualize::fallback_impl(n); } + + Contextualize_Eval* Contextualize_Eval::with(Selector* s, Env* e, Backtrace* bt, Selector* p, Selector* ex) + { + Contextualize::with(s, e, bt, p, ex); + eval = eval->with(s, e, bt, p, ex); + return this; + } + + Selector* Contextualize_Eval::operator()(Selector_Schema* s) + { + To_String to_string; + string result_str(s->contents()->perform(eval)->perform(&to_string)); + result_str += '{'; // the parser looks for a brace to end the selector + Selector* result_sel = Parser::from_c_str(result_str.c_str(), ctx, s->pstate()).parse_selector_group(); + return result_sel->perform(this); + } + + Selector* Contextualize_Eval::operator()(Selector_List* s) + { + return Contextualize::operator ()(s); + } + + Selector* Contextualize_Eval::operator()(Complex_Selector* s) + { + return Contextualize::operator ()(s); + } + + Selector* Contextualize_Eval::operator()(Compound_Selector* s) + { + return Contextualize::operator ()(s); + } + + Selector* Contextualize_Eval::operator()(Wrapped_Selector* s) + { + return Contextualize::operator ()(s); + } + + Selector* Contextualize_Eval::operator()(Pseudo_Selector* s) + { return Contextualize::operator ()(s); } + + Selector* Contextualize_Eval::operator()(Attribute_Selector* s) + { + // the value might be interpolated; evaluate it + String* v = s->value(); + if (v && eval) { + v = static_cast(v->perform(eval->with(env, backtrace))); + } + To_String toString; + Attribute_Selector* ss = new (ctx.mem) Attribute_Selector(*s); + ss->value(v); + return ss; + } + + Selector* Contextualize_Eval::operator()(Selector_Qualifier* s) + { return Contextualize::operator ()(s); + } + + Selector* Contextualize_Eval::operator()(Type_Selector* s) + { return Contextualize::operator ()(s); + } + + Selector* Contextualize_Eval::operator()(Selector_Placeholder* p) + { + return Contextualize::operator ()(p); + } + + Selector* Contextualize_Eval::operator()(Selector_Reference* s) + { + return Contextualize::operator ()(s); + } +} diff --git a/contextualize_eval.hpp b/contextualize_eval.hpp new file mode 100644 index 000000000..738b4d606 --- /dev/null +++ b/contextualize_eval.hpp @@ -0,0 +1,44 @@ +#ifndef SASS_CONTEXTUALIZE_EVAL_H +#define SASS_CONTEXTUALIZE_EVAL_H + +#include "eval.hpp" +#include "context.hpp" +#include "operation.hpp" +#include "environment.hpp" +#include "ast_fwd_decl.hpp" + +namespace Sass { + struct Backtrace; + + typedef Environment Env; + + class Contextualize_Eval : public Contextualize { + + Eval* eval; + + Selector* fallback_impl(AST_Node* n); + + public: + Contextualize_Eval(Context&, Eval*, Env*, Backtrace*); + virtual ~Contextualize_Eval(); + Contextualize_Eval* with(Selector*, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0); + using Operation::operator(); + + Selector* operator()(Selector_Schema*); + Selector* operator()(Selector_List*); + Selector* operator()(Complex_Selector*); + Selector* operator()(Compound_Selector*); + Selector* operator()(Wrapped_Selector*); + Selector* operator()(Pseudo_Selector*); + Selector* operator()(Attribute_Selector*); + Selector* operator()(Selector_Qualifier*); + Selector* operator()(Type_Selector*); + Selector* operator()(Selector_Placeholder*); + Selector* operator()(Selector_Reference*); + + template + Selector* fallback(U x) { return fallback_impl(x); } + }; +} + +#endif diff --git a/eval.cpp b/eval.cpp index a25ee8100..c6bf5bc1c 100644 --- a/eval.cpp +++ b/eval.cpp @@ -31,12 +31,21 @@ namespace Sass { add, sub, mul, div, fmod }; - Eval::Eval(Context& ctx, Env* env, Backtrace* bt) - : ctx(ctx), env(env), backtrace(bt) { } + Eval::Eval(Context& ctx, Contextualize* contextualize, Listize* listize, Env* env, Backtrace* bt) + : ctx(ctx), contextualize(contextualize), listize(listize), env(env), backtrace(bt) { } Eval::~Eval() { } Eval* Eval::with(Env* e, Backtrace* bt) // for setting the env before eval'ing an expression { + contextualize = contextualize->with(0, e, bt); + env = e; + backtrace = bt; + return this; + } + + Eval* Eval::with(Selector* c, Env* e, Backtrace* bt, Selector* p, Selector* ex) // for setting the env before eval'ing an expression + { + contextualize = contextualize->with(c, e, bt, p, ex); env = e; backtrace = bt; return this; @@ -727,21 +736,15 @@ namespace Sass { } string Eval::interpolation(Expression* s) { - if (String_Quoted* str_quoted = dynamic_cast(s)) { - if (str_quoted->quote_mark()) { return string_escape(str_quoted->value()); } else { return evacuate_escapes(str_quoted->value()); } - } else if (String_Constant* str_constant = dynamic_cast(s)) { - return evacuate_escapes(str_constant->value()); - } else if (String_Schema* str_schema = dynamic_cast(s)) { - string res = ""; for(auto i : str_schema->elements()) res += (interpolation(i)); @@ -753,9 +756,7 @@ namespace Sass { } else { return evacuate_quotes(unq); } - } else if (List* list = dynamic_cast(s)) { - string acc = ""; // ToDo: different output styles string sep = list->separator() == List::Separator::COMMA ? "," : " "; if (ctx.output_style != COMPRESSED && sep == ",") sep += " "; @@ -766,30 +767,24 @@ namespace Sass { initial = true; } return evacuate_quotes(acc); - } else if (Variable* var = dynamic_cast(s)) { - string name(var->name()); if (!env->has(name)) error("Undefined variable: \"" + var->name() + "\".", var->pstate()); Expression* value = static_cast((*env)[name]); return evacuate_quotes(interpolation(value)); - } else if (Binary_Expression* var = dynamic_cast(s)) { - - Expression* ex = operator()(var); + Expression* ex = var->perform(this); return evacuate_quotes(interpolation(ex)); - } else if (Function_Call* var = dynamic_cast(s)) { - - Expression* ex = operator()(var); + Expression* ex = var->perform(this); + return evacuate_quotes(interpolation(ex)); + } else if (Parent_Selector* var = dynamic_cast(s)) { + Expression* ex = var->perform(this); return evacuate_quotes(interpolation(ex)); - } else { - To_String to_string(&ctx); // to_string.in_decl_list = true; return evacuate_quotes(s->perform(&to_string)); - } } @@ -938,6 +933,13 @@ namespace Sass { return 0; } + Expression* Eval::operator()(Parent_Selector* p) + { + Selector* s = p->perform(contextualize); + Expression* e = static_cast(s)->perform(listize); + return e; + } + inline Expression* Eval::fallback_impl(AST_Node* n) { return static_cast(n); diff --git a/eval.hpp b/eval.hpp index c902687de..86e95eee8 100644 --- a/eval.hpp +++ b/eval.hpp @@ -7,6 +7,8 @@ #include "position.hpp" #include "operation.hpp" #include "environment.hpp" +#include "contextualize.hpp" +#include "listize.hpp" #include "sass_values.h" namespace Sass { @@ -14,6 +16,8 @@ namespace Sass { typedef Environment Env; struct Backtrace; + class Contextualize; + class Listize; class Eval : public Operation_CRTP { @@ -22,11 +26,14 @@ namespace Sass { Expression* fallback_impl(AST_Node* n); public: + Contextualize* contextualize; + Listize* listize; Env* env; Backtrace* backtrace; - Eval(Context&, Env*, Backtrace*); + Eval(Context&, Contextualize*, Listize*, Env*, Backtrace*); virtual ~Eval(); Eval* with(Env* e, Backtrace* bt); // for setting the env before eval'ing an expression + Eval* with(Selector* c, Env* e, Backtrace* bt, Selector* placeholder = 0, Selector* extender = 0); // for setting the env before eval'ing an expression using Operation::operator(); // for evaluating function bodies @@ -62,6 +69,7 @@ namespace Sass { Expression* operator()(Argument*); Expression* operator()(Arguments*); Expression* operator()(Comment*); + Expression* operator()(Parent_Selector* p); template Expression* fallback(U x) { return fallback_impl(x); } diff --git a/expand.cpp b/expand.cpp index 6d7cda164..900a974ca 100644 --- a/expand.cpp +++ b/expand.cpp @@ -4,7 +4,7 @@ #include "expand.hpp" #include "bind.hpp" #include "eval.hpp" -#include "contextualize.hpp" +#include "contextualize_eval.hpp" #include "to_string.hpp" #include "backtrace.hpp" #include "context.hpp" @@ -12,10 +12,10 @@ namespace Sass { - Expand::Expand(Context& ctx, Eval* eval, Contextualize* contextualize, Env* env, Backtrace* bt) + Expand::Expand(Context& ctx, Eval* eval, Contextualize_Eval* contextualize_eval, Env* env, Backtrace* bt) : ctx(ctx), eval(eval), - contextualize(contextualize), + contextualize_eval(contextualize_eval), env(env), block_stack(vector()), property_stack(vector()), @@ -57,9 +57,9 @@ namespace Sass { return k; } - Contextualize* contextual = contextualize->with(selector_stack.back(), env, backtrace); + Contextualize_Eval* contextual = contextualize_eval->with(selector_stack.back(), env, backtrace); if (old_in_at_root && !r->selector()->has_reference()) - contextual = contextualize->with(at_root_selector_stack.back(), env, backtrace); + contextual = contextualize_eval->with(at_root_selector_stack.back(), env, backtrace); Selector* sel_ctx = r->selector()->perform(contextual); if (sel_ctx == 0) throw "Cannot expand null selector"; @@ -188,7 +188,7 @@ namespace Sass { Block* ab = a->block(); Selector* as = a->selector(); Expression* av = a->value(); - if (as) as = as->perform(contextualize->with(0, env, backtrace)); + if (as) as = as->perform(contextualize_eval->with(0, env, backtrace)); else if (av) av = av->perform(eval->with(env, backtrace)); Block* bb = ab ? ab->perform(this)->block() : 0; At_Rule* aa = new (ctx.mem) At_Rule(a->pstate(), @@ -204,10 +204,9 @@ namespace Sass { { String* old_p = d->property(); String* new_p = static_cast(old_p->perform(eval->with(env, backtrace))); - Expression* value = d->value()->perform(eval->with(env, backtrace)); - + Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back(); + Expression* value = d->value()->perform(eval->with(p, env, backtrace)); if (value->is_invisible() && !d->is_important()) return 0; - Declaration* decl = new (ctx.mem) Declaration(d->pstate(), new_p, value, @@ -219,12 +218,13 @@ namespace Sass { Statement* Expand::operator()(Assignment* a) { string var(a->variable()); + Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back(); if (env->has(var)) { Expression* v = static_cast((*env)[var]); - if (!a->is_guarded() || v->concrete_type() == Expression::NULL_VAL) (*env)[var] = a->value()->perform(eval->with(env, backtrace)); + if (!a->is_guarded() || v->concrete_type() == Expression::NULL_VAL) (*env)[var] = a->value()->perform(eval->with(p, env, backtrace)); } else { - env->current_frame()[var] = a->value()->perform(eval->with(env, backtrace)); + env->current_frame()[var] = a->value()->perform(eval->with(p, env, backtrace)); } return 0; } @@ -406,7 +406,7 @@ namespace Sass { Selector_List* extender = static_cast(selector_stack.back()); if (!extender) return 0; Selector_List* org_extendee = static_cast(e->selector()); - Selector_List* extendee = static_cast(org_extendee->perform(contextualize->with(0, env, backtrace))); + Selector_List* extendee = static_cast(org_extendee->perform(contextualize_eval->with(0, env, backtrace))); if (extendee->length() != 1) { error("selector groups may not be extended", extendee->pstate(), backtrace); } @@ -448,8 +448,10 @@ namespace Sass { Definition* def = static_cast((*env)[full_name]); Block* body = def->block(); Parameters* params = def->parameters(); + Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back(); + Arguments* args = static_cast(c->arguments() - ->perform(eval->with(env, backtrace))); + ->perform(eval->with(p, env, backtrace))); Backtrace here(backtrace, c->pstate(), ", in mixin `" + c->name() + "`"); backtrace = &here; Env new_env; diff --git a/expand.hpp b/expand.hpp index e6962f7a8..58c6d4ea0 100644 --- a/expand.hpp +++ b/expand.hpp @@ -14,6 +14,9 @@ namespace Sass { using namespace std; + class Context; + class Eval; + class Contextualize_Eval; typedef Environment Env; struct Backtrace; @@ -21,7 +24,7 @@ namespace Sass { Context& ctx; Eval* eval; - Contextualize* contextualize; + Contextualize_Eval* contextualize_eval; Env* env; vector block_stack; vector property_stack; @@ -34,7 +37,7 @@ namespace Sass { Statement* fallback_impl(AST_Node* n); public: - Expand(Context&, Eval*, Contextualize*, Env*, Backtrace*); + Expand(Context&, Eval*, Contextualize_Eval*, Env*, Backtrace*); virtual ~Expand() { } using Operation::operator(); diff --git a/functions.cpp b/functions.cpp index afa4c63bd..c2c8d7166 100644 --- a/functions.cpp +++ b/functions.cpp @@ -1467,7 +1467,9 @@ namespace Sass { *args << arg; } Function_Call* func = new (ctx.mem) Function_Call(pstate, name, args); - Eval eval(ctx, &d_env, backtrace); + Contextualize contextualize(ctx, &d_env, backtrace); + Listize listize(ctx, &d_env, backtrace); + Eval eval(ctx, &contextualize, &listize, &d_env, backtrace); return func->perform(&eval); } @@ -1485,7 +1487,9 @@ namespace Sass { // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); } BUILT_IN(sass_if) { - Eval eval(ctx, &d_env, backtrace); + Contextualize contextualize(ctx, &d_env, backtrace); + Listize listize(ctx, &d_env, backtrace); + Eval eval(ctx, &contextualize, &listize, &d_env, backtrace); bool is_true = !ARG("$condition", Expression)->perform(&eval)->is_false(); if (is_true) { return ARG("$if-true", Expression)->perform(&eval); diff --git a/inspect.cpp b/inspect.cpp index fc5999bbd..148772037 100644 --- a/inspect.cpp +++ b/inspect.cpp @@ -665,6 +665,17 @@ namespace Sass { append_token("null", n); } + void Inspect::operator()(Parent_Selector* p) + { + if (p->selector()) { + p->selector()->perform(this); + append_delimiter(); + } + else { + append_string("&"); + } + } + // parameters and arguments void Inspect::operator()(Parameter* p) { diff --git a/inspect.hpp b/inspect.hpp index 702d562fd..7cd0f51c1 100644 --- a/inspect.hpp +++ b/inspect.hpp @@ -71,6 +71,7 @@ namespace Sass { virtual void operator()(Media_Query_Expression*); virtual void operator()(At_Root_Expression*); virtual void operator()(Null*); + virtual void operator()(Parent_Selector* p); // parameters and arguments virtual void operator()(Parameter*); virtual void operator()(Parameters*); diff --git a/listize.cpp b/listize.cpp new file mode 100644 index 000000000..3666485ff --- /dev/null +++ b/listize.cpp @@ -0,0 +1,95 @@ +#include +#include + +#include "listize.hpp" +#include "to_string.hpp" +#include "context.hpp" +#include "backtrace.hpp" +#include "error_handling.hpp" + +namespace Sass { + + Listize::Listize(Context& ctx, Env* env, Backtrace* bt) + : ctx(ctx), + env(env), + backtrace(bt) + { } + + Expression* Listize::operator()(Selector_List* sel) + { + List* l = new (ctx.mem) List(sel->pstate(), sel->length(), List::COMMA); + for (size_t i = 0, L = sel->length(); i < L; ++i) { + *l << (*sel)[i]->perform(this); + } + return l; + } + + Expression* Listize::operator()(Compound_Selector* sel) + { + To_String to_string; + string str; + for (size_t i = 0, L = sel->length(); i < L; ++i) { + Expression* e = (*sel)[i]->perform(this); + if (e) str += e->perform(&to_string); + } + return new (ctx.mem) String_Constant(sel->pstate(), str); + } + + Expression* Listize::operator()(Type_Selector* sel) + { + return new (ctx.mem) String_Constant(sel->pstate(), sel->name()); + } + + Expression* Listize::operator()(Selector_Qualifier* sel) + { + return new (ctx.mem) String_Constant(sel->pstate(), sel->name()); + } + + Expression* Listize::operator()(Complex_Selector* sel) + { + List* l = new (ctx.mem) List(sel->pstate(), 2); + + Compound_Selector* head = sel->head(); + if (head && !head->is_empty_reference()) + { + Expression* hh = head->perform(this); + if (hh) *l << hh; + } + + switch(sel->combinator()) + { + case Complex_Selector::PARENT_OF: + *l << new (ctx.mem) String_Constant(sel->pstate(), ">"); + break; + case Complex_Selector::ADJACENT_TO: + *l << new (ctx.mem) String_Constant(sel->pstate(), "+"); + break; + case Complex_Selector::PRECEDES: + *l << new (ctx.mem) String_Constant(sel->pstate(), "~"); + break; + case Complex_Selector::ANCESTOR_OF: + break; + } + + Complex_Selector* tail = sel->tail(); + if (tail) + { + Expression* tt = tail->perform(this); + if (tt && tt->concrete_type() == Expression::LIST) + { *l += static_cast(tt); } + else if (tt) *l << static_cast(tt); + } + if (l->length() == 0) return 0; + return l; + } + + Expression* Listize::operator()(Selector_Reference* sel) + { + return 0; + } + + Expression* Listize::fallback_impl(AST_Node* n) + { + return 0; + } +} diff --git a/listize.hpp b/listize.hpp new file mode 100644 index 000000000..916b75ff0 --- /dev/null +++ b/listize.hpp @@ -0,0 +1,45 @@ +#ifndef SASS_LISTIZE_H +#define SASS_LISTIZE_H + +#include +#include + +#include "ast.hpp" +#include "context.hpp" +#include "operation.hpp" +#include "environment.hpp" + +namespace Sass { + using namespace std; + + typedef Environment Env; + struct Backtrace; + + class Listize : public Operation_CRTP { + + Context& ctx; + Env* env; + Backtrace* backtrace; + + Expression* fallback_impl(AST_Node* n); + + public: + Listize(Context&, Env*, Backtrace*); + virtual ~Listize() { } + + using Operation::operator(); + + Expression* operator()(Selector_List*); + Expression* operator()(Complex_Selector*); + Expression* operator()(Compound_Selector*); + Expression* operator()(Type_Selector*); + Expression* operator()(Selector_Qualifier*); + Expression* operator()(Selector_Reference*); + + template + Expression* fallback(U x) { return fallback_impl(x); } + }; + +} + +#endif diff --git a/operation.hpp b/operation.hpp index c48535964..b470fe8ad 100644 --- a/operation.hpp +++ b/operation.hpp @@ -61,6 +61,7 @@ namespace Sass { virtual T operator()(Media_Query_Expression* x) = 0; virtual T operator()(At_Root_Expression* x) = 0; virtual T operator()(Null* x) = 0; + virtual T operator()(Parent_Selector* x) = 0; // parameters and arguments virtual T operator()(Parameter* x) = 0; virtual T operator()(Parameters* x) = 0; @@ -135,6 +136,7 @@ namespace Sass { virtual T operator()(Media_Query_Expression* x) { return static_cast(this)->fallback(x); } virtual T operator()(At_Root_Expression* x) { return static_cast(this)->fallback(x); } virtual T operator()(Null* x) { return static_cast(this)->fallback(x); } + virtual T operator()(Parent_Selector* x) { return static_cast(this)->fallback(x); } // parameters and arguments virtual T operator()(Parameter* x) { return static_cast(this)->fallback(x); } virtual T operator()(Parameters* x) { return static_cast(this)->fallback(x); } diff --git a/parser.cpp b/parser.cpp index 2a229c559..a6e7e8bc2 100644 --- a/parser.cpp +++ b/parser.cpp @@ -582,12 +582,12 @@ namespace Sass { if (lex< exactly<'&'> >()) { // check if we have a parent selector on the root level block if (block_stack.back() && block_stack.back()->is_root()) { - error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate); + //error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate); } (*seq) << new (ctx.mem) Selector_Reference(pstate); sawsomething = true; // if you see a space after a &, then you're done - if(peek< spaces >()) { + if(peek< spaces >() || peek< alternatives < spaces, exactly<';'> > >()) { return seq; } } @@ -1286,6 +1286,10 @@ namespace Sass { return result; } + if (lex< ampersand >()) + { + return new (ctx.mem) Parent_Selector(pstate, parse_selector_group()); } + if (lex< important >()) { return new (ctx.mem) String_Constant(pstate, "!important"); } diff --git a/prelexer.cpp b/prelexer.cpp index d1f606534..dadf273f7 100644 --- a/prelexer.cpp +++ b/prelexer.cpp @@ -437,6 +437,9 @@ namespace Sass { const char* percentage(const char* src) { return sequence< number, exactly<'%'> >(src); } + const char* ampersand(const char* src) { + return exactly<'&'>(src); + } /* not used anymore - remove? const char* em(const char* src) { diff --git a/prelexer.hpp b/prelexer.hpp index 0a2324f49..3e6db55c3 100644 --- a/prelexer.hpp +++ b/prelexer.hpp @@ -484,6 +484,7 @@ namespace Sass { const char* coefficient(const char* src); const char* binomial(const char* src); const char* percentage(const char* src); + const char* ampersand(const char* src); const char* dimension(const char* src); const char* hex(const char* src); const char* hexa(const char* src); diff --git a/win/libsass.filters b/win/libsass.filters index fb566b2a0..dc08be9df 100644 --- a/win/libsass.filters +++ b/win/libsass.filters @@ -51,6 +51,9 @@ Source Files + + Source Files + Source Files @@ -194,6 +197,9 @@ Header Files + + Header Files + Header Files diff --git a/win/libsass.vcxproj b/win/libsass.vcxproj index dac9b18c5..0108bf344 100644 --- a/win/libsass.vcxproj +++ b/win/libsass.vcxproj @@ -164,10 +164,12 @@ + + @@ -208,12 +210,14 @@ + +