diff --git a/src/ast.cpp b/src/ast.cpp index 17afcf72a..a60052ddf 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -19,64 +19,575 @@ namespace Sass { static Null sass_null(ParserState("null")); - bool Supports_Operator::needs_parens(Supports_Condition_Obj cond) const { - if (Supports_Operator_Obj op = Cast(cond)) { - return op->operand() != operand(); + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Statement::Statement(ParserState pstate, Type st, size_t t) + : AST_Node(pstate), statement_type_(st), tabs_(t), group_end_(false) + { } + Statement::Statement(const Statement* ptr) + : AST_Node(ptr), + statement_type_(ptr->statement_type_), + tabs_(ptr->tabs_), + group_end_(ptr->group_end_) + { } + + bool Statement::bubbles() + { + return false; + } + + bool Statement::has_content() + { + return statement_type_ == CONTENT; + } + + bool Statement::is_invisible() const + { + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Block::Block(ParserState pstate, size_t s, bool r) + : Statement(pstate), + Vectorized(s), + is_root_(r) + { } + Block::Block(const Block* ptr) + : Statement(ptr), + Vectorized(*ptr), + is_root_(ptr->is_root_) + { } + + bool Block::has_content() + { + for (size_t i = 0, L = elements().size(); i < L; ++i) { + if (elements()[i]->has_content()) return true; } - return Cast(cond) != NULL; + return Statement::has_content(); } - bool Supports_Negation::needs_parens(Supports_Condition_Obj cond) const { - return Cast(cond) || - Cast(cond); + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Has_Block::Has_Block(ParserState pstate, Block_Obj b) + : Statement(pstate), block_(b) + { } + Has_Block::Has_Block(const Has_Block* ptr) + : Statement(ptr), block_(ptr->block_) + { } + + bool Has_Block::has_content() + { + return (block_ && block_->has_content()) || Statement::has_content(); } - void Argument::set_delayed(bool delayed) + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Ruleset::Ruleset(ParserState pstate, Selector_List_Obj s, Block_Obj b) + : Has_Block(pstate, b), selector_(s), is_root_(false) + { statement_type(RULESET); } + Ruleset::Ruleset(const Ruleset* ptr) + : Has_Block(ptr), + selector_(ptr->selector_), + is_root_(ptr->is_root_) + { statement_type(RULESET); } + + bool Ruleset::is_invisible() const { + if (Selector_List_Ptr sl = Cast(selector())) { + for (size_t i = 0, L = sl->length(); i < L; ++i) + if (!(*sl)[i]->has_placeholder()) return false; + } + return true; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Bubble::Bubble(ParserState pstate, Statement_Obj n, Statement_Obj g, size_t t) + : Statement(pstate, Statement::BUBBLE, t), node_(n), group_end_(g == 0) + { } + Bubble::Bubble(const Bubble* ptr) + : Statement(ptr), + node_(ptr->node_), + group_end_(ptr->group_end_) + { } + + bool Bubble::bubbles() { - if (value_) value_->set_delayed(delayed); - is_delayed(delayed); + return true; } - void Arguments::set_delayed(bool delayed) + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Trace::Trace(ParserState pstate, std::string n, Block_Obj b, char type) + : Has_Block(pstate, b), type_(type), name_(n) + { } + Trace::Trace(const Trace* ptr) + : Has_Block(ptr), + type_(ptr->type_), + name_(ptr->name_) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Media_Block::Media_Block(ParserState pstate, List_Obj mqs, Block_Obj b) + : Has_Block(pstate, b), media_queries_(mqs) + { statement_type(MEDIA); } + Media_Block::Media_Block(const Media_Block* ptr) + : Has_Block(ptr), media_queries_(ptr->media_queries_) + { statement_type(MEDIA); } + + bool Media_Block::bubbles() { - for (Argument_Obj arg : elements()) { - if (arg) arg->set_delayed(delayed); + return true; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Directive::Directive(ParserState pstate, std::string kwd, Selector_List_Obj sel, Block_Obj b, Expression_Obj val) + : Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed + { statement_type(DIRECTIVE); } + Directive::Directive(const Directive* ptr) + : Has_Block(ptr), + keyword_(ptr->keyword_), + selector_(ptr->selector_), + value_(ptr->value_) // set value manually if needed + { statement_type(DIRECTIVE); } + + bool Directive::bubbles() { return is_keyframes() || is_media(); } + + bool Directive::is_media() { + return keyword_.compare("@-webkit-media") == 0 || + keyword_.compare("@-moz-media") == 0 || + keyword_.compare("@-o-media") == 0 || + keyword_.compare("@media") == 0; + } + bool Directive::is_keyframes() { + return keyword_.compare("@-webkit-keyframes") == 0 || + keyword_.compare("@-moz-keyframes") == 0 || + keyword_.compare("@-o-keyframes") == 0 || + keyword_.compare("@keyframes") == 0; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Keyframe_Rule::Keyframe_Rule(ParserState pstate, Block_Obj b) + : Has_Block(pstate, b), name_() + { statement_type(KEYFRAMERULE); } + Keyframe_Rule::Keyframe_Rule(const Keyframe_Rule* ptr) + : Has_Block(ptr), name_(ptr->name_) + { statement_type(KEYFRAMERULE); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Declaration::Declaration(ParserState pstate, String_Obj prop, Expression_Obj val, bool i, bool c, Block_Obj b) + : Has_Block(pstate, b), property_(prop), value_(val), is_important_(i), is_custom_property_(c), is_indented_(false) + { statement_type(DECLARATION); } + Declaration::Declaration(const Declaration* ptr) + : Has_Block(ptr), + property_(ptr->property_), + value_(ptr->value_), + is_important_(ptr->is_important_), + is_custom_property_(ptr->is_custom_property_), + is_indented_(ptr->is_indented_) + { statement_type(DECLARATION); } + + bool Declaration::is_invisible() const + { + if (is_custom_property()) return false; + return !(value_ && !Cast(value_)); + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Assignment::Assignment(ParserState pstate, std::string var, Expression_Obj val, bool is_default, bool is_global) + : Statement(pstate), variable_(var), value_(val), is_default_(is_default), is_global_(is_global) + { statement_type(ASSIGNMENT); } + Assignment::Assignment(const Assignment* ptr) + : Statement(ptr), + variable_(ptr->variable_), + value_(ptr->value_), + is_default_(ptr->is_default_), + is_global_(ptr->is_global_) + { statement_type(ASSIGNMENT); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Import::Import(ParserState pstate) + : Statement(pstate), + urls_(std::vector()), + incs_(std::vector()), + import_queries_() + { statement_type(IMPORT); } + Import::Import(const Import* ptr) + : Statement(ptr), + urls_(ptr->urls_), + incs_(ptr->incs_), + import_queries_(ptr->import_queries_) + { statement_type(IMPORT); } + + std::vector& Import::incs() { return incs_; } + std::vector& Import::urls() { return urls_; } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Import_Stub::Import_Stub(ParserState pstate, Include res) + : Statement(pstate), resource_(res) + { statement_type(IMPORT_STUB); } + Import_Stub::Import_Stub(const Import_Stub* ptr) + : Statement(ptr), resource_(ptr->resource_) + { statement_type(IMPORT_STUB); } + Include Import_Stub::resource() { return resource_; }; + std::string Import_Stub::imp_path() { return resource_.imp_path; }; + std::string Import_Stub::abs_path() { return resource_.abs_path; }; + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Warning::Warning(ParserState pstate, Expression_Obj msg) + : Statement(pstate), message_(msg) + { statement_type(WARNING); } + Warning::Warning(const Warning* ptr) + : Statement(ptr), message_(ptr->message_) + { statement_type(WARNING); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Error::Error(ParserState pstate, Expression_Obj msg) + : Statement(pstate), message_(msg) + { statement_type(ERROR); } + Error::Error(const Error* ptr) + : Statement(ptr), message_(ptr->message_) + { statement_type(ERROR); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Debug::Debug(ParserState pstate, Expression_Obj val) + : Statement(pstate), value_(val) + { statement_type(DEBUGSTMT); } + Debug::Debug(const Debug* ptr) + : Statement(ptr), value_(ptr->value_) + { statement_type(DEBUGSTMT); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Comment::Comment(ParserState pstate, String_Obj txt, bool is_important) + : Statement(pstate), text_(txt), is_important_(is_important) + { statement_type(COMMENT); } + Comment::Comment(const Comment* ptr) + : Statement(ptr), + text_(ptr->text_), + is_important_(ptr->is_important_) + { statement_type(COMMENT); } + + bool Comment::is_invisible() const + { + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + If::If(ParserState pstate, Expression_Obj pred, Block_Obj con, Block_Obj alt) + : Has_Block(pstate, con), predicate_(pred), alternative_(alt) + { statement_type(IF); } + If::If(const If* ptr) + : Has_Block(ptr), + predicate_(ptr->predicate_), + alternative_(ptr->alternative_) + { statement_type(IF); } + + bool If::has_content() + { + return Has_Block::has_content() || (alternative_ && alternative_->has_content()); + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + For::For(ParserState pstate, + std::string var, Expression_Obj lo, Expression_Obj hi, Block_Obj b, bool inc) + : Has_Block(pstate, b), + variable_(var), lower_bound_(lo), upper_bound_(hi), is_inclusive_(inc) + { statement_type(FOR); } + For::For(const For* ptr) + : Has_Block(ptr), + variable_(ptr->variable_), + lower_bound_(ptr->lower_bound_), + upper_bound_(ptr->upper_bound_), + is_inclusive_(ptr->is_inclusive_) + { statement_type(FOR); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Each::Each(ParserState pstate, std::vector vars, Expression_Obj lst, Block_Obj b) + : Has_Block(pstate, b), variables_(vars), list_(lst) + { statement_type(EACH); } + Each::Each(const Each* ptr) + : Has_Block(ptr), variables_(ptr->variables_), list_(ptr->list_) + { statement_type(EACH); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + While::While(ParserState pstate, Expression_Obj pred, Block_Obj b) + : Has_Block(pstate, b), predicate_(pred) + { statement_type(WHILE); } + While::While(const While* ptr) + : Has_Block(ptr), predicate_(ptr->predicate_) + { statement_type(WHILE); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Return::Return(ParserState pstate, Expression_Obj val) + : Statement(pstate), value_(val) + { statement_type(RETURN); } + Return::Return(const Return* ptr) + : Statement(ptr), value_(ptr->value_) + { statement_type(RETURN); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Extension::Extension(ParserState pstate, Selector_List_Obj s) + : Statement(pstate), selector_(s) + { statement_type(EXTEND); } + Extension::Extension(const Extension* ptr) + : Statement(ptr), selector_(ptr->selector_) + { statement_type(EXTEND); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Definition::Definition(const Definition* ptr) + : Has_Block(ptr), + name_(ptr->name_), + parameters_(ptr->parameters_), + environment_(ptr->environment_), + type_(ptr->type_), + native_function_(ptr->native_function_), + c_function_(ptr->c_function_), + cookie_(ptr->cookie_), + is_overload_stub_(ptr->is_overload_stub_), + signature_(ptr->signature_) + { } + + Definition::Definition(ParserState pstate, + std::string n, + Parameters_Obj params, + Block_Obj b, + Type t) + : Has_Block(pstate, b), + name_(n), + parameters_(params), + environment_(0), + type_(t), + native_function_(0), + c_function_(0), + cookie_(0), + is_overload_stub_(false), + signature_(0) + { } + + Definition::Definition(ParserState pstate, + Signature sig, + std::string n, + Parameters_Obj params, + Native_Function func_ptr, + bool overload_stub) + : Has_Block(pstate, {}), + name_(n), + parameters_(params), + environment_(0), + type_(FUNCTION), + native_function_(func_ptr), + c_function_(0), + cookie_(0), + is_overload_stub_(overload_stub), + signature_(sig) + { } + + Definition::Definition(ParserState pstate, + Signature sig, + std::string n, + Parameters_Obj params, + Sass_Function_Entry c_func) + : Has_Block(pstate, {}), + name_(n), + parameters_(params), + environment_(0), + type_(FUNCTION), + native_function_(0), + c_function_(c_func), + cookie_(sass_function_get_cookie(c_func)), + is_overload_stub_(false), + signature_(sig) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Mixin_Call::Mixin_Call(ParserState pstate, std::string n, Arguments_Obj args, Parameters_Obj b_params, Block_Obj b) + : Has_Block(pstate, b), name_(n), arguments_(args), block_parameters_(b_params) + { } + Mixin_Call::Mixin_Call(const Mixin_Call* ptr) + : Has_Block(ptr), + name_(ptr->name_), + arguments_(ptr->arguments_), + block_parameters_(ptr->block_parameters_) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Content::Content(ParserState pstate, Arguments_Obj args) + : Statement(pstate), + arguments_(args) + { statement_type(CONTENT); } + Content::Content(const Content* ptr) + : Statement(ptr), + arguments_(ptr->arguments_) + { statement_type(CONTENT); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Unary_Expression::Unary_Expression(ParserState pstate, Type t, Expression_Obj o) + : Expression(pstate), optype_(t), operand_(o), hash_(0) + { } + Unary_Expression::Unary_Expression(const Unary_Expression* ptr) + : Expression(ptr), + optype_(ptr->optype_), + operand_(ptr->operand_), + hash_(ptr->hash_) + { } + const std::string Unary_Expression::type_name() { + switch (optype_) { + case PLUS: return "plus"; + case MINUS: return "minus"; + case SLASH: return "slash"; + case NOT: return "not"; + default: return "invalid"; } - is_delayed(delayed); + } + bool Unary_Expression::operator==(const Expression& rhs) const + { + try + { + Unary_Expression_Ptr_Const m = Cast(&rhs); + if (m == 0) return false; + return type() == m->type() && + *operand() == *m->operand(); + } + catch (std::bad_cast&) + { + return false; + } + catch (...) { throw; } + } + size_t Unary_Expression::hash() const + { + if (hash_ == 0) { + hash_ = std::hash()(optype_); + hash_combine(hash_, operand()->hash()); + }; + return hash_; } + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// - bool At_Root_Query::exclude(std::string str) + Argument::Argument(ParserState pstate, Expression_Obj val, std::string n, bool rest, bool keyword) + : Expression(pstate), value_(val), name_(n), is_rest_argument_(rest), is_keyword_argument_(keyword), hash_(0) { - bool with = feature() && unquote(feature()->to_string()).compare("with") == 0; - List_Ptr l = static_cast(value().ptr()); - std::string v; + if (!name_.empty() && is_rest_argument_) { + coreError("variable-length argument may not be passed by name", pstate_); + } + } + Argument::Argument(const Argument* ptr) + : Expression(ptr), + value_(ptr->value_), + name_(ptr->name_), + is_rest_argument_(ptr->is_rest_argument_), + is_keyword_argument_(ptr->is_keyword_argument_), + hash_(ptr->hash_) + { + if (!name_.empty() && is_rest_argument_) { + coreError("variable-length argument may not be passed by name", pstate_); + } + } - if (with) + void Argument::set_delayed(bool delayed) + { + if (value_) value_->set_delayed(delayed); + is_delayed(delayed); + } + + bool Argument::operator==(const Expression& rhs) const + { + try { - if (!l || l->length() == 0) return str.compare("rule") != 0; - for (size_t i = 0, L = l->length(); i < L; ++i) - { - v = unquote((*l)[i]->to_string()); - if (v.compare("all") == 0 || v == str) return false; - } - return true; + Argument_Ptr_Const m = Cast(&rhs); + if (!(m && name() == m->name())) return false; + return *value() == *m->value(); } - else + catch (std::bad_cast&) { - if (!l || !l->length()) return str.compare("rule") == 0; - for (size_t i = 0, L = l->length(); i < L; ++i) - { - v = unquote((*l)[i]->to_string()); - if (v.compare("all") == 0 || v == str) return true; - } return false; } + catch (...) { throw; } } - void AST_Node::update_pstate(const ParserState& pstate) + size_t Argument::hash() const { - pstate_.offset += pstate - pstate_ + pstate.offset; + if (hash_ == 0) { + hash_ = std::hash()(name()); + hash_combine(hash_, value()->hash()); + } + return hash_; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Arguments::Arguments(ParserState pstate) + : Expression(pstate), + Vectorized(), + has_named_arguments_(false), + has_rest_argument_(false), + has_keyword_argument_(false) + { } + Arguments::Arguments(const Arguments* ptr) + : Expression(ptr), + Vectorized(*ptr), + has_named_arguments_(ptr->has_named_arguments_), + has_rest_argument_(ptr->has_rest_argument_), + has_keyword_argument_(ptr->has_keyword_argument_) + { } + + void Arguments::set_delayed(bool delayed) + { + for (Argument_Obj arg : elements()) { + if (arg) arg->set_delayed(delayed); + } + is_delayed(delayed); } Argument_Obj Arguments::get_rest_argument() @@ -136,14 +647,287 @@ namespace Sass { } } - bool Ruleset::is_invisible() const { - if (Selector_List_Ptr sl = Cast(selector())) { - for (size_t i = 0, L = sl->length(); i < L; ++i) - if (!(*sl)[i]->has_placeholder()) return false; + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Media_Query::Media_Query(ParserState pstate, String_Obj t, size_t s, bool n, bool r) + : Expression(pstate), Vectorized(s), + media_type_(t), is_negated_(n), is_restricted_(r) + { } + Media_Query::Media_Query(const Media_Query* ptr) + : Expression(ptr), + Vectorized(*ptr), + media_type_(ptr->media_type_), + is_negated_(ptr->is_negated_), + is_restricted_(ptr->is_restricted_) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Media_Query_Expression::Media_Query_Expression(ParserState pstate, + Expression_Obj f, Expression_Obj v, bool i) + : Expression(pstate), feature_(f), value_(v), is_interpolated_(i) + { } + Media_Query_Expression::Media_Query_Expression(const Media_Query_Expression* ptr) + : Expression(ptr), + feature_(ptr->feature_), + value_(ptr->value_), + is_interpolated_(ptr->is_interpolated_) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Supports_Block::Supports_Block(ParserState pstate, Supports_Condition_Obj condition, Block_Obj block) + : Has_Block(pstate, block), condition_(condition) + { statement_type(SUPPORTS); } + Supports_Block::Supports_Block(const Supports_Block* ptr) + : Has_Block(ptr), condition_(ptr->condition_) + { statement_type(SUPPORTS); } + bool Supports_Block::bubbles() { return true; } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Supports_Operator::Supports_Operator(ParserState pstate, Supports_Condition_Obj l, Supports_Condition_Obj r, Operand o) + : Supports_Condition(pstate), left_(l), right_(r), operand_(o) + { } + Supports_Operator::Supports_Operator(const Supports_Operator* ptr) + : Supports_Condition(ptr), + left_(ptr->left_), + right_(ptr->right_), + operand_(ptr->operand_) + { } + + bool Supports_Operator::needs_parens(Supports_Condition_Obj cond) const + { + if (Supports_Operator_Obj op = Cast(cond)) { + return op->operand() != operand(); + } + return Cast(cond) != NULL; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Supports_Negation::Supports_Negation(ParserState pstate, Supports_Condition_Obj c) + : Supports_Condition(pstate), condition_(c) + { } + Supports_Negation::Supports_Negation(const Supports_Negation* ptr) + : Supports_Condition(ptr), condition_(ptr->condition_) + { } + + bool Supports_Negation::needs_parens(Supports_Condition_Obj cond) const + { + return Cast(cond) || + Cast(cond); + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Supports_Declaration::Supports_Declaration(ParserState pstate, Expression_Obj f, Expression_Obj v) + : Supports_Condition(pstate), feature_(f), value_(v) + { } + Supports_Declaration::Supports_Declaration(const Supports_Declaration* ptr) + : Supports_Condition(ptr), + feature_(ptr->feature_), + value_(ptr->value_) + { } + + bool Supports_Declaration::needs_parens(Supports_Condition_Obj cond) const + { + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Supports_Interpolation::Supports_Interpolation(ParserState pstate, Expression_Obj v) + : Supports_Condition(pstate), value_(v) + { } + Supports_Interpolation::Supports_Interpolation(const Supports_Interpolation* ptr) + : Supports_Condition(ptr), + value_(ptr->value_) + { } + + bool Supports_Interpolation::needs_parens(Supports_Condition_Obj cond) const + { + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + At_Root_Query::At_Root_Query(ParserState pstate, Expression_Obj f, Expression_Obj v, bool i) + : Expression(pstate), feature_(f), value_(v) + { } + At_Root_Query::At_Root_Query(const At_Root_Query* ptr) + : Expression(ptr), + feature_(ptr->feature_), + value_(ptr->value_) + { } + + bool At_Root_Query::exclude(std::string str) + { + bool with = feature() && unquote(feature()->to_string()).compare("with") == 0; + List_Ptr l = static_cast(value().ptr()); + std::string v; + + if (with) + { + if (!l || l->length() == 0) return str.compare("rule") != 0; + for (size_t i = 0, L = l->length(); i < L; ++i) + { + v = unquote((*l)[i]->to_string()); + if (v.compare("all") == 0 || v == str) return false; + } + return true; + } + else + { + if (!l || !l->length()) return str.compare("rule") == 0; + for (size_t i = 0, L = l->length(); i < L; ++i) + { + v = unquote((*l)[i]->to_string()); + if (v.compare("all") == 0 || v == str) return true; + } + return false; } + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + At_Root_Block::At_Root_Block(ParserState pstate, Block_Obj b, At_Root_Query_Obj e) + : Has_Block(pstate, b), expression_(e) + { statement_type(ATROOT); } + At_Root_Block::At_Root_Block(const At_Root_Block* ptr) + : Has_Block(ptr), expression_(ptr->expression_) + { statement_type(ATROOT); } + + bool At_Root_Block::bubbles() { return true; } + bool At_Root_Block::exclude_node(Statement_Obj s) { + if (expression() == 0) + { + return s->statement_type() == Statement::RULESET; + } + + if (s->statement_type() == Statement::DIRECTIVE) + { + if (Directive_Obj dir = Cast(s)) + { + std::string keyword(dir->keyword()); + if (keyword.length() > 0) keyword.erase(0, 1); + return expression()->exclude(keyword); + } + } + if (s->statement_type() == Statement::MEDIA) + { + return expression()->exclude("media"); + } + if (s->statement_type() == Statement::RULESET) + { + return expression()->exclude("rule"); + } + if (s->statement_type() == Statement::SUPPORTS) + { + return expression()->exclude("supports"); + } + if (Directive_Obj dir = Cast(s)) + { + if (dir->is_keyframes()) return expression()->exclude("keyframes"); + } + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Thunk::Thunk(ParserState pstate, Expression_Obj exp, Env* env) + : Expression(pstate), expression_(exp), environment_(env) + { } + Thunk::Thunk(const Thunk* ptr) + : Expression(ptr->pstate_), + expression_(ptr->expression_), + environment_(ptr->environment_) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Parameter::Parameter(ParserState pstate, std::string n, Expression_Obj def, bool rest) + : AST_Node(pstate), name_(n), default_value_(def), is_rest_parameter_(rest) + { } + Parameter::Parameter(const Parameter* ptr) + : AST_Node(ptr), + name_(ptr->name_), + default_value_(ptr->default_value_), + is_rest_parameter_(ptr->is_rest_parameter_) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Parameters::Parameters(ParserState pstate) + : AST_Node(pstate), + Vectorized(), + has_optional_parameters_(false), + has_rest_parameter_(false) + { } + Parameters::Parameters(const Parameters* ptr) + : AST_Node(ptr), + Vectorized(*ptr), + has_optional_parameters_(ptr->has_optional_parameters_), + has_rest_parameter_(ptr->has_rest_parameter_) + { } + + void Parameters::adjust_after_pushing(Parameter_Obj p) + { + if (p->default_value()) { + if (has_rest_parameter()) { + coreError("optional parameters may not be combined with variable-length parameters", p->pstate()); + } + has_optional_parameters(true); + } + else if (p->is_rest_parameter()) { + if (has_rest_parameter()) { + coreError("functions and mixins cannot have more than one variable-length parameter", p->pstate()); + } + has_rest_parameter(true); + } + else { + if (has_rest_parameter()) { + coreError("required parameters must precede variable-length parameters", p->pstate()); + } + if (has_optional_parameters()) { + coreError("required parameters must precede optional parameters", p->pstate()); + } + } + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + + void AST_Node::update_pstate(const ParserState& pstate) + { + pstate_.offset += pstate - pstate_ + pstate.offset; + } + bool Media_Block::is_invisible() const { for (size_t i = 0, L = block()->length(); i < L; ++i) { Statement_Obj stm = block()->at(i); @@ -184,13 +968,6 @@ namespace Sass { return to_string({ NESTED, 5 }); } - bool Declaration::is_invisible() const - { - if (is_custom_property()) return false; - - return !(value_ && value_->concrete_type() != Expression::NULL_VAL); - } - ////////////////////////////////////////////////////////////////////////////////////////// // Additional method on Lists to retrieve values directly or from an encompassed Argument. ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/ast.hpp b/src/ast.hpp index 4cf99d502..2f924bbbe 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -69,6 +69,48 @@ namespace Sass { } ////////////////////////////////////////////////////////// + inline static const std::string sass_op_to_name(enum Sass_OP op) { + switch (op) { + case AND: return "and"; + case OR: return "or"; + case EQ: return "eq"; + case NEQ: return "neq"; + case GT: return "gt"; + case GTE: return "gte"; + case LT: return "lt"; + case LTE: return "lte"; + case ADD: return "plus"; + case SUB: return "sub"; + case MUL: return "times"; + case DIV: return "div"; + case MOD: return "mod"; + // this is only used internally! + case NUM_OPS: return "[OPS]"; + default: return "invalid"; + } + } + + inline static const std::string sass_op_separator(enum Sass_OP op) { + switch (op) { + case AND: return "&&"; + case OR: return "||"; + case EQ: return "=="; + case NEQ: return "!="; + case GT: return ">"; + case GTE: return ">="; + case LT: return "<"; + case LTE: return "<="; + case ADD: return "+"; + case SUB: return "-"; + case MUL: return "*"; + case DIV: return "/"; + case MOD: return "%"; + // this is only used internally! + case NUM_OPS: return "[OPS]"; + default: return "invalid"; + } + } + ////////////////////////////////////////////////////////// // Abstract base class for all abstract syntax tree nodes. ////////////////////////////////////////////////////////// @@ -389,23 +431,14 @@ namespace Sass { ADD_PROPERTY(size_t, tabs) ADD_PROPERTY(bool, group_end) public: - Statement(ParserState pstate, Type st = NONE, size_t t = 0) - : AST_Node(pstate), statement_type_(st), tabs_(t), group_end_(false) - { } - Statement(const Statement* ptr) - : AST_Node(ptr), - statement_type_(ptr->statement_type_), - tabs_(ptr->tabs_), - group_end_(ptr->group_end_) - { } - virtual ~Statement() = 0; + Statement(ParserState pstate, Type st = NONE, size_t t = 0); + Statement(const Statement* ptr); // copy constructor + virtual ~Statement() = 0; // virtual destructor // needed for rearranging nested rulesets during CSS emission - virtual bool is_invisible() const { return false; } - virtual bool bubbles() { return false; } - virtual bool has_content() - { - return statement_type_ == CONTENT; - } + virtual bool bubbles(); + virtual bool has_content(); + virtual bool is_invisible() const; + ATTACH_VIRTUAL_AST_OPERATIONS(Statement) }; inline Statement::~Statement() { } @@ -416,27 +449,11 @@ namespace Sass { ADD_PROPERTY(bool, is_root) // needed for properly formatted CSS emission protected: - void adjust_after_pushing(Statement_Obj s) override - { - } + void adjust_after_pushing(Statement_Obj s) override {} public: - Block(ParserState pstate, size_t s = 0, bool r = false) - : Statement(pstate), - Vectorized(s), - is_root_(r) - { } - Block(const Block* ptr) - : Statement(ptr), - Vectorized(*ptr), - is_root_(ptr->is_root_) - { } - bool has_content() override - { - for (size_t i = 0, L = elements().size(); i < L; ++i) { - if (elements()[i]->has_content()) return true; - } - return Statement::has_content(); - } + Block(ParserState pstate, size_t s = 0, bool r = false); + Block(const Block* ptr); // copy constructor + bool has_content() override; ATTACH_AST_OPERATIONS(Block) ATTACH_CRTP_PERFORM_METHODS() }; @@ -447,17 +464,10 @@ namespace Sass { class Has_Block : public Statement { ADD_PROPERTY(Block_Obj, block) public: - Has_Block(ParserState pstate, Block_Obj b) - : Statement(pstate), block_(b) - { } - Has_Block(const Has_Block* ptr) - : Statement(ptr), block_(ptr->block_) - { } - virtual bool has_content() override - { - return (block_ && block_->has_content()) || Statement::has_content(); - } - virtual ~Has_Block() = 0; + Has_Block(ParserState pstate, Block_Obj b); + Has_Block(const Has_Block* ptr); // copy constructor + virtual ~Has_Block() = 0; // virtual destructor + virtual bool has_content() override; }; inline Has_Block::~Has_Block() { } @@ -469,14 +479,8 @@ namespace Sass { ADD_PROPERTY(Selector_List_Obj, selector) ADD_PROPERTY(bool, is_root); public: - Ruleset(ParserState pstate, Selector_List_Obj s = {}, Block_Obj b = {}) - : Has_Block(pstate, b), selector_(s), is_root_(false) - { statement_type(RULESET); } - Ruleset(const Ruleset* ptr) - : Has_Block(ptr), - selector_(ptr->selector_), - is_root_(ptr->is_root_) - { statement_type(RULESET); } + Ruleset(ParserState pstate, Selector_List_Obj s = {}, Block_Obj b = {}); + Ruleset(const Ruleset* ptr); bool is_invisible() const override; ATTACH_AST_OPERATIONS(Ruleset) ATTACH_CRTP_PERFORM_METHODS() @@ -489,15 +493,9 @@ namespace Sass { ADD_PROPERTY(Statement_Obj, node) ADD_PROPERTY(bool, group_end) public: - Bubble(ParserState pstate, Statement_Obj n, Statement_Obj g = {}, size_t t = 0) - : Statement(pstate, Statement::BUBBLE, t), node_(n), group_end_(g == 0) - { } - Bubble(const Bubble* ptr) - : Statement(ptr), - node_(ptr->node_), - group_end_(ptr->group_end_) - { } - bool bubbles() override { return true; } + Bubble(ParserState pstate, Statement_Obj n, Statement_Obj g = {}, size_t t = 0); + Bubble(const Bubble* ptr); + bool bubbles(); ATTACH_AST_OPERATIONS(Bubble) ATTACH_CRTP_PERFORM_METHODS() }; @@ -509,14 +507,8 @@ namespace Sass { ADD_CONSTREF(char, type) ADD_CONSTREF(std::string, name) public: - Trace(ParserState pstate, std::string n, Block_Obj b = {}, char type = 'm') - : Has_Block(pstate, b), type_(type), name_(n) - { } - Trace(const Trace* ptr) - : Has_Block(ptr), - type_(ptr->type_), - name_(ptr->name_) - { } + Trace(ParserState pstate, std::string n, Block_Obj b = {}, char type = 'm'); + Trace(const Trace* ptr); ATTACH_AST_OPERATIONS(Trace) ATTACH_CRTP_PERFORM_METHODS() }; @@ -527,13 +519,9 @@ namespace Sass { class Media_Block final : public Has_Block { ADD_PROPERTY(List_Obj, media_queries) public: - Media_Block(ParserState pstate, List_Obj mqs, Block_Obj b) - : Has_Block(pstate, b), media_queries_(mqs) - { statement_type(MEDIA); } - Media_Block(const Media_Block* ptr) - : Has_Block(ptr), media_queries_(ptr->media_queries_) - { statement_type(MEDIA); } - bool bubbles() override { return true; } + Media_Block(ParserState pstate, List_Obj mqs, Block_Obj b); + Media_Block(const Media_Block* ptr); + bool bubbles() override; bool is_invisible() const override; ATTACH_AST_OPERATIONS(Media_Block) ATTACH_CRTP_PERFORM_METHODS() @@ -548,28 +536,11 @@ namespace Sass { ADD_PROPERTY(Selector_List_Obj, selector) ADD_PROPERTY(Expression_Obj, value) public: - Directive(ParserState pstate, std::string kwd, Selector_List_Obj sel = {}, Block_Obj b = {}, Expression_Obj val = {}) - : Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed - { statement_type(DIRECTIVE); } - Directive(const Directive* ptr) - : Has_Block(ptr), - keyword_(ptr->keyword_), - selector_(ptr->selector_), - value_(ptr->value_) // set value manually if needed - { statement_type(DIRECTIVE); } - bool bubbles() override { return is_keyframes() || is_media(); } - bool is_media() { - return keyword_.compare("@-webkit-media") == 0 || - keyword_.compare("@-moz-media") == 0 || - keyword_.compare("@-o-media") == 0 || - keyword_.compare("@media") == 0; - } - bool is_keyframes() { - return keyword_.compare("@-webkit-keyframes") == 0 || - keyword_.compare("@-moz-keyframes") == 0 || - keyword_.compare("@-o-keyframes") == 0 || - keyword_.compare("@keyframes") == 0; - } + Directive(ParserState pstate, std::string kwd, Selector_List_Obj sel = {}, Block_Obj b = {}, Expression_Obj val = {}); + Directive(const Directive* ptr); + bool bubbles() override; + bool is_media(); + bool is_keyframes(); ATTACH_AST_OPERATIONS(Directive) ATTACH_CRTP_PERFORM_METHODS() }; @@ -582,12 +553,8 @@ namespace Sass { // = | ADD_PROPERTY(Selector_List_Obj, name) public: - Keyframe_Rule(ParserState pstate, Block_Obj b) - : Has_Block(pstate, b), name_() - { statement_type(KEYFRAMERULE); } - Keyframe_Rule(const Keyframe_Rule* ptr) - : Has_Block(ptr), name_(ptr->name_) - { statement_type(KEYFRAMERULE); } + Keyframe_Rule(ParserState pstate, Block_Obj b); + Keyframe_Rule(const Keyframe_Rule* ptr); ATTACH_AST_OPERATIONS(Keyframe_Rule) ATTACH_CRTP_PERFORM_METHODS() }; @@ -602,18 +569,8 @@ namespace Sass { ADD_PROPERTY(bool, is_custom_property) ADD_PROPERTY(bool, is_indented) public: - Declaration(ParserState pstate, - String_Obj prop, Expression_Obj val, bool i = false, bool c = false, Block_Obj b = {}) - : Has_Block(pstate, b), property_(prop), value_(val), is_important_(i), is_custom_property_(c), is_indented_(false) - { statement_type(DECLARATION); } - Declaration(const Declaration* ptr) - : Has_Block(ptr), - property_(ptr->property_), - value_(ptr->value_), - is_important_(ptr->is_important_), - is_custom_property_(ptr->is_custom_property_), - is_indented_(ptr->is_indented_) - { statement_type(DECLARATION); } + Declaration(ParserState pstate, String_Obj prop, Expression_Obj val, bool i = false, bool c = false, Block_Obj b = {}); + Declaration(const Declaration* ptr); bool is_invisible() const override; ATTACH_AST_OPERATIONS(Declaration) ATTACH_CRTP_PERFORM_METHODS() @@ -628,19 +585,8 @@ namespace Sass { ADD_PROPERTY(bool, is_default) ADD_PROPERTY(bool, is_global) public: - Assignment(ParserState pstate, - std::string var, Expression_Obj val, - bool is_default = false, - bool is_global = false) - : Statement(pstate), variable_(var), value_(val), is_default_(is_default), is_global_(is_global) - { statement_type(ASSIGNMENT); } - Assignment(const Assignment* ptr) - : Statement(ptr), - variable_(ptr->variable_), - value_(ptr->value_), - is_default_(ptr->is_default_), - is_global_(ptr->is_global_) - { statement_type(ASSIGNMENT); } + Assignment(ParserState pstate, std::string var, Expression_Obj val, bool is_default = false, bool is_global = false); + Assignment(const Assignment* ptr); ATTACH_AST_OPERATIONS(Assignment) ATTACH_CRTP_PERFORM_METHODS() }; @@ -651,23 +597,13 @@ namespace Sass { //////////////////////////////////////////////////////////////////////////// class Import final : public Statement { std::vector urls_; - std::vector incs_; + std::vector incs_; ADD_PROPERTY(List_Obj, import_queries); public: - Import(ParserState pstate) - : Statement(pstate), - urls_(std::vector()), - incs_(std::vector()), - import_queries_() - { statement_type(IMPORT); } - Import(const Import* ptr) - : Statement(ptr), - urls_(ptr->urls_), - incs_(ptr->incs_), - import_queries_(ptr->import_queries_) - { statement_type(IMPORT); } - std::vector& urls() { return urls_; } - std::vector& incs() { return incs_; } + Import(ParserState pstate); + Import(const Import* ptr); + std::vector& incs(); + std::vector& urls(); ATTACH_AST_OPERATIONS(Import) ATTACH_CRTP_PERFORM_METHODS() }; @@ -677,16 +613,11 @@ namespace Sass { class Import_Stub final : public Statement { Include resource_; public: - std::string abs_path() { return resource_.abs_path; }; - std::string imp_path() { return resource_.imp_path; }; - Include resource() { return resource_; }; - - Import_Stub(ParserState pstate, Include res) - : Statement(pstate), resource_(res) - { statement_type(IMPORT_STUB); } - Import_Stub(const Import_Stub* ptr) - : Statement(ptr), resource_(ptr->resource_) - { statement_type(IMPORT_STUB); } + Import_Stub(ParserState pstate, Include res); + Import_Stub(const Import_Stub* ptr); + Include resource(); + std::string imp_path(); + std::string abs_path(); ATTACH_AST_OPERATIONS(Import_Stub) ATTACH_CRTP_PERFORM_METHODS() }; @@ -697,12 +628,8 @@ namespace Sass { class Warning final : public Statement { ADD_PROPERTY(Expression_Obj, message) public: - Warning(ParserState pstate, Expression_Obj msg) - : Statement(pstate), message_(msg) - { statement_type(WARNING); } - Warning(const Warning* ptr) - : Statement(ptr), message_(ptr->message_) - { statement_type(WARNING); } + Warning(ParserState pstate, Expression_Obj msg); + Warning(const Warning* ptr); ATTACH_AST_OPERATIONS(Warning) ATTACH_CRTP_PERFORM_METHODS() }; @@ -713,12 +640,8 @@ namespace Sass { class Error final : public Statement { ADD_PROPERTY(Expression_Obj, message) public: - Error(ParserState pstate, Expression_Obj msg) - : Statement(pstate), message_(msg) - { statement_type(ERROR); } - Error(const Error* ptr) - : Statement(ptr), message_(ptr->message_) - { statement_type(ERROR); } + Error(ParserState pstate, Expression_Obj msg); + Error(const Error* ptr); ATTACH_AST_OPERATIONS(Error) ATTACH_CRTP_PERFORM_METHODS() }; @@ -729,12 +652,8 @@ namespace Sass { class Debug final : public Statement { ADD_PROPERTY(Expression_Obj, value) public: - Debug(ParserState pstate, Expression_Obj val) - : Statement(pstate), value_(val) - { statement_type(DEBUGSTMT); } - Debug(const Debug* ptr) - : Statement(ptr), value_(ptr->value_) - { statement_type(DEBUGSTMT); } + Debug(ParserState pstate, Expression_Obj val); + Debug(const Debug* ptr); ATTACH_AST_OPERATIONS(Debug) ATTACH_CRTP_PERFORM_METHODS() }; @@ -746,16 +665,9 @@ namespace Sass { ADD_PROPERTY(String_Obj, text) ADD_PROPERTY(bool, is_important) public: - Comment(ParserState pstate, String_Obj txt, bool is_important) - : Statement(pstate), text_(txt), is_important_(is_important) - { statement_type(COMMENT); } - Comment(const Comment* ptr) - : Statement(ptr), - text_(ptr->text_), - is_important_(ptr->is_important_) - { statement_type(COMMENT); } - bool is_invisible() const override - { return /* is_important() == */ false; } + Comment(ParserState pstate, String_Obj txt, bool is_important); + Comment(const Comment* ptr); + virtual bool is_invisible() const override; ATTACH_AST_OPERATIONS(Comment) ATTACH_CRTP_PERFORM_METHODS() }; @@ -767,18 +679,9 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, predicate) ADD_PROPERTY(Block_Obj, alternative) public: - If(ParserState pstate, Expression_Obj pred, Block_Obj con, Block_Obj alt = {}) - : Has_Block(pstate, con), predicate_(pred), alternative_(alt) - { statement_type(IF); } - If(const If* ptr) - : Has_Block(ptr), - predicate_(ptr->predicate_), - alternative_(ptr->alternative_) - { statement_type(IF); } - bool has_content() override - { - return Has_Block::has_content() || (alternative_ && alternative_->has_content()); - } + If(ParserState pstate, Expression_Obj pred, Block_Obj con, Block_Obj alt = {}); + If(const If* ptr); + virtual bool has_content() override; ATTACH_AST_OPERATIONS(If) ATTACH_CRTP_PERFORM_METHODS() }; @@ -792,18 +695,8 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, upper_bound) ADD_PROPERTY(bool, is_inclusive) public: - For(ParserState pstate, - std::string var, Expression_Obj lo, Expression_Obj hi, Block_Obj b, bool inc) - : Has_Block(pstate, b), - variable_(var), lower_bound_(lo), upper_bound_(hi), is_inclusive_(inc) - { statement_type(FOR); } - For(const For* ptr) - : Has_Block(ptr), - variable_(ptr->variable_), - lower_bound_(ptr->lower_bound_), - upper_bound_(ptr->upper_bound_), - is_inclusive_(ptr->is_inclusive_) - { statement_type(FOR); } + For(ParserState pstate, std::string var, Expression_Obj lo, Expression_Obj hi, Block_Obj b, bool inc); + For(const For* ptr); ATTACH_AST_OPERATIONS(For) ATTACH_CRTP_PERFORM_METHODS() }; @@ -815,12 +708,8 @@ namespace Sass { ADD_PROPERTY(std::vector, variables) ADD_PROPERTY(Expression_Obj, list) public: - Each(ParserState pstate, std::vector vars, Expression_Obj lst, Block_Obj b) - : Has_Block(pstate, b), variables_(vars), list_(lst) - { statement_type(EACH); } - Each(const Each* ptr) - : Has_Block(ptr), variables_(ptr->variables_), list_(ptr->list_) - { statement_type(EACH); } + Each(ParserState pstate, std::vector vars, Expression_Obj lst, Block_Obj b); + Each(const Each* ptr); ATTACH_AST_OPERATIONS(Each) ATTACH_CRTP_PERFORM_METHODS() }; @@ -831,12 +720,8 @@ namespace Sass { class While final : public Has_Block { ADD_PROPERTY(Expression_Obj, predicate) public: - While(ParserState pstate, Expression_Obj pred, Block_Obj b) - : Has_Block(pstate, b), predicate_(pred) - { statement_type(WHILE); } - While(const While* ptr) - : Has_Block(ptr), predicate_(ptr->predicate_) - { statement_type(WHILE); } + While(ParserState pstate, Expression_Obj pred, Block_Obj b); + While(const While* ptr); ATTACH_AST_OPERATIONS(While) ATTACH_CRTP_PERFORM_METHODS() }; @@ -847,12 +732,8 @@ namespace Sass { class Return final : public Statement { ADD_PROPERTY(Expression_Obj, value) public: - Return(ParserState pstate, Expression_Obj val) - : Statement(pstate), value_(val) - { statement_type(RETURN); } - Return(const Return* ptr) - : Statement(ptr), value_(ptr->value_) - { statement_type(RETURN); } + Return(ParserState pstate, Expression_Obj val); + Return(const Return* ptr); ATTACH_AST_OPERATIONS(Return) ATTACH_CRTP_PERFORM_METHODS() }; @@ -863,12 +744,8 @@ namespace Sass { class Extension final : public Statement { ADD_PROPERTY(Selector_List_Obj, selector) public: - Extension(ParserState pstate, Selector_List_Obj s) - : Statement(pstate), selector_(s) - { statement_type(EXTEND); } - Extension(const Extension* ptr) - : Statement(ptr), selector_(ptr->selector_) - { statement_type(EXTEND); } + Extension(ParserState pstate, Selector_List_Obj s); + Extension(const Extension* ptr); ATTACH_AST_OPERATIONS(Extension) ATTACH_CRTP_PERFORM_METHODS() }; @@ -890,68 +767,23 @@ namespace Sass { ADD_PROPERTY(bool, is_overload_stub) ADD_PROPERTY(Signature, signature) public: - Definition(const Definition* ptr) - : Has_Block(ptr), - name_(ptr->name_), - parameters_(ptr->parameters_), - environment_(ptr->environment_), - type_(ptr->type_), - native_function_(ptr->native_function_), - c_function_(ptr->c_function_), - cookie_(ptr->cookie_), - is_overload_stub_(ptr->is_overload_stub_), - signature_(ptr->signature_) - { } - + Definition(const Definition* ptr); Definition(ParserState pstate, std::string n, Parameters_Obj params, Block_Obj b, - Type t) - : Has_Block(pstate, b), - name_(n), - parameters_(params), - environment_(0), - type_(t), - native_function_(0), - c_function_(0), - cookie_(0), - is_overload_stub_(false), - signature_(0) - { } + Type t); Definition(ParserState pstate, Signature sig, std::string n, Parameters_Obj params, Native_Function func_ptr, - bool overload_stub = false) - : Has_Block(pstate, {}), - name_(n), - parameters_(params), - environment_(0), - type_(FUNCTION), - native_function_(func_ptr), - c_function_(0), - cookie_(0), - is_overload_stub_(overload_stub), - signature_(sig) - { } + bool overload_stub = false); Definition(ParserState pstate, Signature sig, std::string n, Parameters_Obj params, - Sass_Function_Entry c_func) - : Has_Block(pstate, {}), - name_(n), - parameters_(params), - environment_(0), - type_(FUNCTION), - native_function_(0), - c_function_(c_func), - cookie_(sass_function_get_cookie(c_func)), - is_overload_stub_(false), - signature_(sig) - { } + Sass_Function_Entry c_func); ATTACH_AST_OPERATIONS(Definition) ATTACH_CRTP_PERFORM_METHODS() }; @@ -964,15 +796,8 @@ namespace Sass { ADD_PROPERTY(Arguments_Obj, arguments) ADD_PROPERTY(Parameters_Obj, block_parameters) public: - Mixin_Call(ParserState pstate, std::string n, Arguments_Obj args, Parameters_Obj b_params = {}, Block_Obj b = {}) - : Has_Block(pstate, b), name_(n), arguments_(args), block_parameters_(b_params) - { } - Mixin_Call(const Mixin_Call* ptr) - : Has_Block(ptr), - name_(ptr->name_), - arguments_(ptr->arguments_), - block_parameters_(ptr->block_parameters_) - { } + Mixin_Call(ParserState pstate, std::string n, Arguments_Obj args, Parameters_Obj b_params = {}, Block_Obj b = {}); + Mixin_Call(const Mixin_Call* ptr); ATTACH_AST_OPERATIONS(Mixin_Call) ATTACH_CRTP_PERFORM_METHODS() }; @@ -983,60 +808,12 @@ namespace Sass { class Content final : public Statement { ADD_PROPERTY(Arguments_Obj, arguments) public: - Content(ParserState pstate, Arguments_Obj args) - : Statement(pstate), - arguments_(args) - { statement_type(CONTENT); } - Content(const Content* ptr) - : Statement(ptr), - arguments_(ptr->arguments_) - { statement_type(CONTENT); } + Content(ParserState pstate, Arguments_Obj args); + Content(const Content* ptr); ATTACH_AST_OPERATIONS(Content) ATTACH_CRTP_PERFORM_METHODS() }; - inline static const std::string sass_op_to_name(enum Sass_OP op) { - switch (op) { - case AND: return "and"; - case OR: return "or"; - case EQ: return "eq"; - case NEQ: return "neq"; - case GT: return "gt"; - case GTE: return "gte"; - case LT: return "lt"; - case LTE: return "lte"; - case ADD: return "plus"; - case SUB: return "sub"; - case MUL: return "times"; - case DIV: return "div"; - case MOD: return "mod"; - // this is only used internally! - case NUM_OPS: return "[OPS]"; - default: return "invalid"; - } - } - - inline static const std::string sass_op_separator(enum Sass_OP op) { - switch (op) { - case AND: return "&&"; - case OR: return "||"; - case EQ: return "=="; - case NEQ: return "!="; - case GT: return ">"; - case GTE: return ">="; - case LT: return "<"; - case LTE: return "<="; - case ADD: return "+"; - case SUB: return "-"; - case MUL: return "*"; - case DIV: return "/"; - case MOD: return "%"; - // this is only used internally! - case NUM_OPS: return "[OPS]"; - default: return "invalid"; - } - } - //////////////////////////////////////////////////////////////////////////// // Arithmetic negation (logical negation is just an ordinary function call). //////////////////////////////////////////////////////////////////////////// @@ -1048,47 +825,11 @@ namespace Sass { HASH_PROPERTY(Expression_Obj, operand) mutable size_t hash_; public: - Unary_Expression(ParserState pstate, Type t, Expression_Obj o) - : Expression(pstate), optype_(t), operand_(o), hash_(0) - { } - Unary_Expression(const Unary_Expression* ptr) - : Expression(ptr), - optype_(ptr->optype_), - operand_(ptr->operand_), - hash_(ptr->hash_) - { } - const std::string type_name() { - switch (optype_) { - case PLUS: return "plus"; - case MINUS: return "minus"; - case SLASH: return "slash"; - case NOT: return "not"; - default: return "invalid"; - } - } - bool operator==(const Expression& rhs) const override - { - try - { - Unary_Expression_Ptr_Const m = Cast(&rhs); - if (m == 0) return false; - return type() == m->type() && - *operand() == *m->operand(); - } - catch (std::bad_cast&) - { - return false; - } - catch (...) { throw; } - } - size_t hash() const override - { - if (hash_ == 0) { - hash_ = std::hash()(optype_); - hash_combine(hash_, operand()->hash()); - }; - return hash_; - } + Unary_Expression(ParserState pstate, Type t, Expression_Obj o); + Unary_Expression(const Unary_Expression* ptr); + const std::string type_name(); + virtual bool operator==(const Expression& rhs) const; + size_t hash() const override; ATTACH_AST_OPERATIONS(Unary_Expression) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1103,51 +844,11 @@ namespace Sass { ADD_PROPERTY(bool, is_keyword_argument) mutable size_t hash_; public: - Argument(ParserState pstate, Expression_Obj val, std::string n = "", bool rest = false, bool keyword = false) - : Expression(pstate), value_(val), name_(n), is_rest_argument_(rest), is_keyword_argument_(keyword), hash_(0) - { - if (!name_.empty() && is_rest_argument_) { - coreError("variable-length argument may not be passed by name", pstate_); - } - } - Argument(const Argument* ptr) - : Expression(ptr), - value_(ptr->value_), - name_(ptr->name_), - is_rest_argument_(ptr->is_rest_argument_), - is_keyword_argument_(ptr->is_keyword_argument_), - hash_(ptr->hash_) - { - if (!name_.empty() && is_rest_argument_) { - coreError("variable-length argument may not be passed by name", pstate_); - } - } - + Argument(ParserState pstate, Expression_Obj val, std::string n = "", bool rest = false, bool keyword = false); + Argument(const Argument* ptr); void set_delayed(bool delayed) override; - bool operator==(const Expression& rhs) const override - { - try - { - Argument_Ptr_Const m = Cast(&rhs); - if (!(m && name() == m->name())) return false; - return *value() == *m->value(); - } - catch (std::bad_cast&) - { - return false; - } - catch (...) { throw; } - } - - size_t hash() const override - { - if (hash_ == 0) { - hash_ = std::hash()(name()); - hash_combine(hash_, value()->hash()); - } - return hash_; - } - + bool operator==(const Expression& rhs) const override; + size_t hash() const override; ATTACH_AST_OPERATIONS(Argument) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1164,26 +865,11 @@ namespace Sass { protected: void adjust_after_pushing(Argument_Obj a) override; public: - Arguments(ParserState pstate) - : Expression(pstate), - Vectorized(), - has_named_arguments_(false), - has_rest_argument_(false), - has_keyword_argument_(false) - { } - Arguments(const Arguments* ptr) - : Expression(ptr), - Vectorized(*ptr), - has_named_arguments_(ptr->has_named_arguments_), - has_rest_argument_(ptr->has_rest_argument_), - has_keyword_argument_(ptr->has_keyword_argument_) - { } - + Arguments(ParserState pstate); + Arguments(const Arguments* ptr); void set_delayed(bool delayed) override; - Argument_Obj get_rest_argument(); Argument_Obj get_keyword_argument(); - ATTACH_AST_OPERATIONS(Arguments) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1197,18 +883,8 @@ namespace Sass { ADD_PROPERTY(bool, is_negated) ADD_PROPERTY(bool, is_restricted) public: - Media_Query(ParserState pstate, - String_Obj t = {}, size_t s = 0, bool n = false, bool r = false) - : Expression(pstate), Vectorized(s), - media_type_(t), is_negated_(n), is_restricted_(r) - { } - Media_Query(const Media_Query* ptr) - : Expression(ptr), - Vectorized(*ptr), - media_type_(ptr->media_type_), - is_negated_(ptr->is_negated_), - is_restricted_(ptr->is_restricted_) - { } + Media_Query(ParserState pstate, String_Obj t = {}, size_t s = 0, bool n = false, bool r = false); + Media_Query(const Media_Query* ptr); ATTACH_AST_OPERATIONS(Media_Query) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1221,16 +897,8 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, value) ADD_PROPERTY(bool, is_interpolated) public: - Media_Query_Expression(ParserState pstate, - Expression_Obj f, Expression_Obj v, bool i = false) - : Expression(pstate), feature_(f), value_(v), is_interpolated_(i) - { } - Media_Query_Expression(const Media_Query_Expression* ptr) - : Expression(ptr), - feature_(ptr->feature_), - value_(ptr->value_), - is_interpolated_(ptr->is_interpolated_) - { } + Media_Query_Expression(ParserState pstate, Expression_Obj f, Expression_Obj v, bool i = false); + Media_Query_Expression(const Media_Query_Expression* ptr); ATTACH_AST_OPERATIONS(Media_Query_Expression) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1241,13 +909,9 @@ namespace Sass { class Supports_Block final : public Has_Block { ADD_PROPERTY(Supports_Condition_Obj, condition) public: - Supports_Block(ParserState pstate, Supports_Condition_Obj condition, Block_Obj block = {}) - : Has_Block(pstate, block), condition_(condition) - { statement_type(SUPPORTS); } - Supports_Block(const Supports_Block* ptr) - : Has_Block(ptr), condition_(ptr->condition_) - { statement_type(SUPPORTS); } - bool bubbles() override { return true; } + Supports_Block(ParserState pstate, Supports_Condition_Obj condition, Block_Obj block = {}); + Supports_Block(const Supports_Block* ptr); + bool bubbles(); ATTACH_AST_OPERATIONS(Supports_Block) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1279,15 +943,8 @@ namespace Sass { ADD_PROPERTY(Supports_Condition_Obj, right); ADD_PROPERTY(Operand, operand); public: - Supports_Operator(ParserState pstate, Supports_Condition_Obj l, Supports_Condition_Obj r, Operand o) - : Supports_Condition(pstate), left_(l), right_(r), operand_(o) - { } - Supports_Operator(const Supports_Operator* ptr) - : Supports_Condition(ptr), - left_(ptr->left_), - right_(ptr->right_), - operand_(ptr->operand_) - { } + Supports_Operator(ParserState pstate, Supports_Condition_Obj l, Supports_Condition_Obj r, Operand o); + Supports_Operator(const Supports_Operator* ptr); bool needs_parens(Supports_Condition_Obj cond) const override; ATTACH_AST_OPERATIONS(Supports_Operator) ATTACH_CRTP_PERFORM_METHODS() @@ -1300,12 +957,8 @@ namespace Sass { private: ADD_PROPERTY(Supports_Condition_Obj, condition); public: - Supports_Negation(ParserState pstate, Supports_Condition_Obj c) - : Supports_Condition(pstate), condition_(c) - { } - Supports_Negation(const Supports_Negation* ptr) - : Supports_Condition(ptr), condition_(ptr->condition_) - { } + Supports_Negation(ParserState pstate, Supports_Condition_Obj c); + Supports_Negation(const Supports_Negation* ptr); bool needs_parens(Supports_Condition_Obj cond) const override; ATTACH_AST_OPERATIONS(Supports_Negation) ATTACH_CRTP_PERFORM_METHODS() @@ -1319,15 +972,9 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, feature); ADD_PROPERTY(Expression_Obj, value); public: - Supports_Declaration(ParserState pstate, Expression_Obj f, Expression_Obj v) - : Supports_Condition(pstate), feature_(f), value_(v) - { } - Supports_Declaration(const Supports_Declaration* ptr) - : Supports_Condition(ptr), - feature_(ptr->feature_), - value_(ptr->value_) - { } - bool needs_parens(Supports_Condition_Obj cond) const override { return false; } + Supports_Declaration(ParserState pstate, Expression_Obj f, Expression_Obj v); + Supports_Declaration(const Supports_Declaration* ptr); + virtual bool needs_parens(Supports_Condition_Obj cond) const; ATTACH_AST_OPERATIONS(Supports_Declaration) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1339,14 +986,9 @@ namespace Sass { private: ADD_PROPERTY(Expression_Obj, value); public: - Supports_Interpolation(ParserState pstate, Expression_Obj v) - : Supports_Condition(pstate), value_(v) - { } - Supports_Interpolation(const Supports_Interpolation* ptr) - : Supports_Condition(ptr), - value_(ptr->value_) - { } - bool needs_parens(Supports_Condition_Obj cond) const override { return false; } + Supports_Interpolation(ParserState pstate, Expression_Obj v); + Supports_Interpolation(const Supports_Interpolation* ptr); + virtual bool needs_parens(Supports_Condition_Obj cond) const; ATTACH_AST_OPERATIONS(Supports_Interpolation) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1359,14 +1001,8 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, feature) ADD_PROPERTY(Expression_Obj, value) public: - At_Root_Query(ParserState pstate, Expression_Obj f = {}, Expression_Obj v = {}, bool i = false) - : Expression(pstate), feature_(f), value_(v) - { } - At_Root_Query(const At_Root_Query* ptr) - : Expression(ptr), - feature_(ptr->feature_), - value_(ptr->value_) - { } + At_Root_Query(ParserState pstate, Expression_Obj f = {}, Expression_Obj v = {}, bool i = false); + At_Root_Query(const At_Root_Query* ptr); bool exclude(std::string str); ATTACH_AST_OPERATIONS(At_Root_Query) ATTACH_CRTP_PERFORM_METHODS() @@ -1378,50 +1014,24 @@ namespace Sass { class At_Root_Block final : public Has_Block { ADD_PROPERTY(At_Root_Query_Obj, expression) public: - At_Root_Block(ParserState pstate, Block_Obj b = {}, At_Root_Query_Obj e = {}) - : Has_Block(pstate, b), expression_(e) - { statement_type(ATROOT); } - At_Root_Block(const At_Root_Block* ptr) - : Has_Block(ptr), expression_(ptr->expression_) - { statement_type(ATROOT); } - bool bubbles() override { return true; } - bool exclude_node(Statement_Obj s) { - if (expression() == 0) - { - return s->statement_type() == Statement::RULESET; - } - - if (s->statement_type() == Statement::DIRECTIVE) - { - if (Directive_Obj dir = Cast(s)) - { - std::string keyword(dir->keyword()); - if (keyword.length() > 0) keyword.erase(0, 1); - return expression()->exclude(keyword); - } - } - if (s->statement_type() == Statement::MEDIA) - { - return expression()->exclude("media"); - } - if (s->statement_type() == Statement::RULESET) - { - return expression()->exclude("rule"); - } - if (s->statement_type() == Statement::SUPPORTS) - { - return expression()->exclude("supports"); - } - if (Directive_Obj dir = Cast(s)) - { - if (dir->is_keyframes()) return expression()->exclude("keyframes"); - } - return false; - } + At_Root_Block(ParserState pstate, Block_Obj b = {}, At_Root_Query_Obj e = {}); + At_Root_Block(const At_Root_Block* ptr); + bool bubbles(); + bool exclude_node(Statement_Obj s); ATTACH_AST_OPERATIONS(At_Root_Block) ATTACH_CRTP_PERFORM_METHODS() }; + ///////////////////////////////// + // Thunks for delayed evaluation. + ///////////////////////////////// + class Thunk : public Expression { + ADD_PROPERTY(Expression_Obj, expression) + ADD_PROPERTY(Env*, environment) + public: + Thunk(ParserState pstate, Expression_Obj exp, Env* env = 0); + Thunk(const Thunk* ptr); + }; ///////////////////////////////////////////////////////// // Individual parameter objects for mixins and functions. @@ -1431,28 +1041,8 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, default_value) ADD_PROPERTY(bool, is_rest_parameter) public: - Parameter(ParserState pstate, - std::string n, Expression_Obj def = {}, bool rest = false) - : AST_Node(pstate), name_(n), default_value_(def), is_rest_parameter_(rest) - { - // tried to come up with a spec test for this, but it does no longer - // get past the parser (it error out earlier). A spec test was added! - // if (default_value_ && is_rest_parameter_) { - // error("variable-length parameter may not have a default value", pstate_); - // } - } - Parameter(const Parameter* ptr) - : AST_Node(ptr), - name_(ptr->name_), - default_value_(ptr->default_value_), - is_rest_parameter_(ptr->is_rest_parameter_) - { - // tried to come up with a spec test for this, but it does no longer - // get past the parser (it error out earlier). A spec test was added! - // if (default_value_ && is_rest_parameter_) { - // error("variable-length parameter may not have a default value", pstate_); - // } - } + Parameter(ParserState pstate, std::string n, Expression_Obj def = {}, bool rest = false); + Parameter(const Parameter* ptr); ATTACH_AST_OPERATIONS(Parameter) ATTACH_CRTP_PERFORM_METHODS() }; @@ -1466,42 +1056,10 @@ namespace Sass { ADD_PROPERTY(bool, has_optional_parameters) ADD_PROPERTY(bool, has_rest_parameter) protected: - void adjust_after_pushing(Parameter_Obj p) override - { - if (p->default_value()) { - if (has_rest_parameter()) { - coreError("optional parameters may not be combined with variable-length parameters", p->pstate()); - } - has_optional_parameters(true); - } - else if (p->is_rest_parameter()) { - if (has_rest_parameter()) { - coreError("functions and mixins cannot have more than one variable-length parameter", p->pstate()); - } - has_rest_parameter(true); - } - else { - if (has_rest_parameter()) { - coreError("required parameters must precede variable-length parameters", p->pstate()); - } - if (has_optional_parameters()) { - coreError("required parameters must precede optional parameters", p->pstate()); - } - } - } + void adjust_after_pushing(Parameter_Obj p); public: - Parameters(ParserState pstate) - : AST_Node(pstate), - Vectorized(), - has_optional_parameters_(false), - has_rest_parameter_(false) - { } - Parameters(const Parameters* ptr) - : AST_Node(ptr), - Vectorized(*ptr), - has_optional_parameters_(ptr->has_optional_parameters_), - has_rest_parameter_(ptr->has_rest_parameter_) - { } + Parameters(ParserState pstate); + Parameters(const Parameters* ptr); ATTACH_AST_OPERATIONS(Parameters) ATTACH_CRTP_PERFORM_METHODS() };