diff --git a/src/ast.cpp b/src/ast.cpp index ceb5a206c..943168e73 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -22,6 +22,40 @@ namespace Sass { ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// + void AST_Node::update_pstate(const ParserState& pstate) + { + pstate_.offset += pstate - pstate_ + pstate.offset; + } + + const std::string AST_Node::to_string(Sass_Inspect_Options opt) const + { + Sass_Output_Options out(opt); + Emitter emitter(out); + Inspect i(emitter); + i.in_declaration = true; + // ToDo: inspect should be const + const_cast(this)->perform(&i); + return i.get_buffer(); + } + + const std::string AST_Node::to_string() const + { + return to_string({ NESTED, 5 }); + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Expression_Obj Hashed::at(Expression_Obj k) const + { + if (elements_.count(k)) + { return elements_.at(k); } + else { return {}; } + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + Statement::Statement(ParserState pstate, Type st, size_t t) : AST_Node(pstate), statement_type_(st), tabs_(t), group_end_(false) { } @@ -143,6 +177,14 @@ namespace Sass { : Has_Block(ptr), media_queries_(ptr->media_queries_) { statement_type(MEDIA); } + bool Media_Block::is_invisible() const { + for (size_t i = 0, L = block()->length(); i < L; ++i) { + Statement_Obj stm = block()->at(i); + if (!stm->is_invisible()) return false; + } + return true; + } + bool Media_Block::bubbles() { return true; @@ -767,18 +809,6 @@ namespace Sass { ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// - 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) { } @@ -832,80 +862,6 @@ namespace Sass { ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////// - - - 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); - if (!stm->is_invisible()) return false; - } - return true; - } - - Expression_Obj Hashed::at(Expression_Obj k) const - { - if (elements_.count(k)) - { return elements_.at(k); } - else { return {}; } - } - - bool Binary_Expression::is_left_interpolant(void) const - { - return is_interpolant() || (left() && left()->is_left_interpolant()); - } - bool Binary_Expression::is_right_interpolant(void) const - { - return is_interpolant() || (right() && right()->is_right_interpolant()); - } - - const std::string AST_Node::to_string(Sass_Inspect_Options opt) const - { - Sass_Output_Options out(opt); - Emitter emitter(out); - Inspect i(emitter); - i.in_declaration = true; - // ToDo: inspect should be const - const_cast(this)->perform(&i); - return i.get_buffer(); - } - - const std::string AST_Node::to_string() const - { - return to_string({ NESTED, 5 }); - } - - ////////////////////////////////////////////////////////////////////////////////////////// - // Additional method on Lists to retrieve values directly or from an encompassed Argument. - ////////////////////////////////////////////////////////////////////////////////////////// - Expression_Obj List::value_at_index(size_t i) { - Expression_Obj obj = this->at(i); - if (is_arglist_) { - if (Argument_Ptr arg = Cast(obj)) { - return arg->value(); - } else { - return obj; - } - } else { - return obj; - } - } - - ///////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////// - IMPLEMENT_AST_OPERATORS(Ruleset); IMPLEMENT_AST_OPERATORS(Media_Block); IMPLEMENT_AST_OPERATORS(Import); diff --git a/src/ast.hpp b/src/ast.hpp index 71a5186af..ca31ebb53 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -188,6 +188,7 @@ namespace Sass { C_ERROR, FUNCTION, VARIABLE, + PARENT, NUM_TYPES }; private: @@ -214,9 +215,11 @@ namespace Sass { { } virtual operator bool() { return true; } virtual ~Expression() { } - virtual std::string type() const { return ""; /* TODO: raise an error? */ } virtual bool is_invisible() const { return false; } + + virtual std::string type() const { return ""; } static std::string type_name() { return ""; } + virtual bool is_false() { return false; } // virtual bool is_true() { return !is_false(); } virtual bool operator< (const Expression& rhs) const { return false; } @@ -452,7 +455,6 @@ namespace Sass { void adjust_after_pushing(Statement_Obj s) override {} public: 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() @@ -480,7 +482,6 @@ namespace Sass { ADD_PROPERTY(bool, is_root); public: 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() @@ -494,7 +495,6 @@ namespace Sass { ADD_PROPERTY(bool, group_end) public: 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() @@ -508,7 +508,6 @@ namespace Sass { ADD_CONSTREF(std::string, name) public: Trace(ParserState pstate, std::string n, Block_Obj b = {}, char type = 'm'); - Trace(const Trace* ptr); ATTACH_AST_OPERATIONS(Trace) ATTACH_CRTP_PERFORM_METHODS() }; @@ -520,7 +519,6 @@ namespace Sass { ADD_PROPERTY(List_Obj, media_queries) public: 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) @@ -537,7 +535,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, value) public: 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(); @@ -554,7 +551,6 @@ namespace Sass { ADD_PROPERTY(Selector_List_Obj, name) public: Keyframe_Rule(ParserState pstate, Block_Obj b); - Keyframe_Rule(const Keyframe_Rule* ptr); ATTACH_AST_OPERATIONS(Keyframe_Rule) ATTACH_CRTP_PERFORM_METHODS() }; @@ -570,7 +566,6 @@ namespace Sass { ADD_PROPERTY(bool, is_indented) public: 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() @@ -586,7 +581,6 @@ namespace Sass { ADD_PROPERTY(bool, is_global) public: 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() }; @@ -601,7 +595,6 @@ namespace Sass { ADD_PROPERTY(List_Obj, import_queries); public: Import(ParserState pstate); - Import(const Import* ptr); std::vector& incs(); std::vector& urls(); ATTACH_AST_OPERATIONS(Import) @@ -614,7 +607,6 @@ namespace Sass { Include resource_; public: Import_Stub(ParserState pstate, Include res); - Import_Stub(const Import_Stub* ptr); Include resource(); std::string imp_path(); std::string abs_path(); @@ -629,7 +621,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, message) public: Warning(ParserState pstate, Expression_Obj msg); - Warning(const Warning* ptr); ATTACH_AST_OPERATIONS(Warning) ATTACH_CRTP_PERFORM_METHODS() }; @@ -641,7 +632,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, message) public: Error(ParserState pstate, Expression_Obj msg); - Error(const Error* ptr); ATTACH_AST_OPERATIONS(Error) ATTACH_CRTP_PERFORM_METHODS() }; @@ -653,7 +643,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, value) public: Debug(ParserState pstate, Expression_Obj val); - Debug(const Debug* ptr); ATTACH_AST_OPERATIONS(Debug) ATTACH_CRTP_PERFORM_METHODS() }; @@ -666,7 +655,6 @@ namespace Sass { ADD_PROPERTY(bool, is_important) public: 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() @@ -680,7 +668,6 @@ namespace Sass { ADD_PROPERTY(Block_Obj, alternative) public: 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() @@ -696,7 +683,6 @@ namespace Sass { ADD_PROPERTY(bool, is_inclusive) public: 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() }; @@ -709,7 +695,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, list) public: Each(ParserState pstate, std::vector vars, Expression_Obj lst, Block_Obj b); - Each(const Each* ptr); ATTACH_AST_OPERATIONS(Each) ATTACH_CRTP_PERFORM_METHODS() }; @@ -721,7 +706,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, predicate) public: While(ParserState pstate, Expression_Obj pred, Block_Obj b); - While(const While* ptr); ATTACH_AST_OPERATIONS(While) ATTACH_CRTP_PERFORM_METHODS() }; @@ -733,7 +717,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, value) public: Return(ParserState pstate, Expression_Obj val); - Return(const Return* ptr); ATTACH_AST_OPERATIONS(Return) ATTACH_CRTP_PERFORM_METHODS() }; @@ -745,7 +728,6 @@ namespace Sass { ADD_PROPERTY(Selector_List_Obj, selector) public: Extension(ParserState pstate, Selector_List_Obj s); - Extension(const Extension* ptr); ATTACH_AST_OPERATIONS(Extension) ATTACH_CRTP_PERFORM_METHODS() }; @@ -767,7 +749,6 @@ namespace Sass { ADD_PROPERTY(bool, is_overload_stub) ADD_PROPERTY(Signature, signature) public: - Definition(const Definition* ptr); Definition(ParserState pstate, std::string n, Parameters_Obj params, @@ -797,7 +778,6 @@ namespace Sass { ADD_PROPERTY(Parameters_Obj, block_parameters) public: 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() }; @@ -809,7 +789,6 @@ namespace Sass { ADD_PROPERTY(Arguments_Obj, arguments) public: Content(ParserState pstate, Arguments_Obj args); - Content(const Content* ptr); ATTACH_AST_OPERATIONS(Content) ATTACH_CRTP_PERFORM_METHODS() }; @@ -826,7 +805,6 @@ namespace Sass { mutable size_t hash_; public: 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; @@ -845,7 +823,6 @@ namespace Sass { mutable size_t hash_; public: 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; size_t hash() const override; @@ -866,7 +843,6 @@ namespace Sass { void adjust_after_pushing(Argument_Obj a) override; public: Arguments(ParserState pstate); - Arguments(const Arguments* ptr); void set_delayed(bool delayed) override; Argument_Obj get_rest_argument(); Argument_Obj get_keyword_argument(); @@ -884,7 +860,6 @@ namespace Sass { ADD_PROPERTY(bool, is_restricted) public: 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() }; @@ -898,7 +873,6 @@ namespace Sass { ADD_PROPERTY(bool, is_interpolated) public: 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() }; @@ -912,7 +886,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, value) public: 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() @@ -925,24 +898,12 @@ namespace Sass { ADD_PROPERTY(At_Root_Query_Obj, expression) public: 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. ///////////////////////////////////////////////////////// @@ -952,7 +913,6 @@ namespace Sass { ADD_PROPERTY(bool, is_rest_parameter) public: Parameter(ParserState pstate, std::string n, Expression_Obj def = {}, bool rest = false); - Parameter(const Parameter* ptr); ATTACH_AST_OPERATIONS(Parameter) ATTACH_CRTP_PERFORM_METHODS() }; @@ -969,7 +929,6 @@ namespace Sass { void adjust_after_pushing(Parameter_Obj p); public: Parameters(ParserState pstate); - Parameters(const Parameters* ptr); ATTACH_AST_OPERATIONS(Parameters) ATTACH_CRTP_PERFORM_METHODS() }; diff --git a/src/ast_def_macros.hpp b/src/ast_def_macros.hpp index d354f3185..75bb6fcde 100644 --- a/src/ast_def_macros.hpp +++ b/src/ast_def_macros.hpp @@ -78,6 +78,7 @@ public: \ virtual klass##_Ptr clone(std::string, size_t) const override = 0; \ #define ATTACH_AST_OPERATIONS(klass) \ + klass(const klass* ptr); \ virtual klass##_Ptr copy(std::string, size_t) const override; \ virtual klass##_Ptr clone(std::string, size_t) const override; \ @@ -92,6 +93,7 @@ public: \ virtual klass##_Ptr clone() const override = 0; \ #define ATTACH_AST_OPERATIONS(klass) \ + klass(const klass* ptr); \ virtual klass##_Ptr copy() const override; \ virtual klass##_Ptr clone() const override; \ diff --git a/src/ast_sel_cmp.cpp b/src/ast_sel_cmp.cpp index 658dcc696..72279da69 100644 --- a/src/ast_sel_cmp.cpp +++ b/src/ast_sel_cmp.cpp @@ -147,34 +147,17 @@ namespace Sass { bool Selector_List::operator== (const Selector_List& rhs) const { - // for array access - size_t i = 0, n = 0; - size_t iL = length(); - size_t nL = rhs.length(); - // create temporary vectors to sort them for compare - std::vector l_lst = this->elements(); - std::vector r_lst = rhs.elements(); - std::sort(l_lst.begin(), l_lst.end(), OrderNodes()); - std::sort(r_lst.begin(), r_lst.end(), OrderNodes()); - // process loop - while (true) - { - // first check for valid index - if (i == iL) return iL == nL; - else if (n == nL) return iL == nL; - // access the vector items - Complex_Selector_Ptr l = l_lst[i]; - Complex_Selector_Ptr r = r_lst[n]; - // skip nulls - if (!l) ++i; - else if (!r) ++n; - // do the check - else if (*l != *r) break; - // advance - ++i; ++n; + if (&rhs == this) return true; + if (rhs.length() != length()) return false; + std::unordered_set lhs_set; + lhs_set.reserve(length()); + for (const Complex_Selector_Obj &element : elements()) { + lhs_set.insert(element.ptr()); } - // not equal - return false; + for (const Complex_Selector_Obj &element : rhs.elements()) { + if (lhs_set.find(element.ptr()) == lhs_set.end()) return false; + } + return true; } bool Compound_Selector::operator< (const Compound_Selector& rhs) const diff --git a/src/ast_selectors.cpp b/src/ast_selectors.cpp index dc030593c..00a1b4fb3 100644 --- a/src/ast_selectors.cpp +++ b/src/ast_selectors.cpp @@ -18,45 +18,134 @@ namespace Sass { - bool Wrapped_Selector::find ( bool (*f)(AST_Node_Obj) ) + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Selector::Selector(ParserState pstate) + : Expression(pstate), + has_line_feed_(false), + has_line_break_(false), + is_optional_(false), + media_block_(0), + hash_(0) + { concrete_type(SELECTOR); } + + Selector::Selector(const Selector* ptr) + : Expression(ptr), + has_line_feed_(ptr->has_line_feed_), + has_line_break_(ptr->has_line_break_), + is_optional_(ptr->is_optional_), + media_block_(ptr->media_block_), + hash_(ptr->hash_) + { concrete_type(SELECTOR); } + + void Selector::set_media_block(Media_Block_Ptr mb) { - // check children first - if (selector_) { - if (selector_->find(f)) return true; + media_block(mb); + } + + bool Selector::has_parent_ref() const + { + return false; + } + + bool Selector::has_real_parent_ref() const + { + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Selector_Schema::Selector_Schema(ParserState pstate, String_Obj c) + : AST_Node(pstate), + contents_(c), + connect_parent_(true), + media_block_(NULL), + hash_(0) + { } + Selector_Schema::Selector_Schema(const Selector_Schema* ptr) + : AST_Node(ptr), + contents_(ptr->contents_), + connect_parent_(ptr->connect_parent_), + media_block_(ptr->media_block_), + hash_(ptr->hash_) + { } + + unsigned long Selector_Schema::specificity() const + { + return 0; + } + + size_t Selector_Schema::hash() const { + if (hash_ == 0) { + hash_combine(hash_, contents_->hash()); } - // execute last - return f(this); + return hash_; } - bool Selector_List::find ( bool (*f)(AST_Node_Obj) ) + bool Selector_Schema::has_parent_ref() const { - // check children first - for (Complex_Selector_Obj sel : elements()) { - if (sel->find(f)) return true; + if (String_Schema_Obj schema = Cast(contents())) { + return schema->length() > 0 && Cast(schema->at(0)) != NULL; } - // execute last - return f(this); + return false; } - bool Compound_Selector::find ( bool (*f)(AST_Node_Obj) ) + bool Selector_Schema::has_real_parent_ref() const { - // check children first - for (Simple_Selector_Obj sel : elements()) { - if (sel->find(f)) return true; + if (String_Schema_Obj schema = Cast(contents())) { + if (schema->length() == 0) return false; + return Cast(schema->at(0)); } - // execute last - return f(this); + return false; } - bool Complex_Selector::find ( bool (*f)(AST_Node_Obj) ) + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Simple_Selector::Simple_Selector(ParserState pstate, std::string n) + : Selector(pstate), ns_(""), name_(n), has_ns_(false) { - // check children first - if (head_ && head_->find(f)) return true; - if (tail_ && tail_->find(f)) return true; - // execute last - return f(this); + size_t pos = n.find('|'); + // found some namespace + if (pos != std::string::npos) { + has_ns_ = true; + ns_ = n.substr(0, pos); + name_ = n.substr(pos + 1); + } + } + Simple_Selector::Simple_Selector(const Simple_Selector* ptr) + : Selector(ptr), + ns_(ptr->ns_), + name_(ptr->name_), + has_ns_(ptr->has_ns_) + { } + + std::string Simple_Selector::ns_name() const + { + std::string name(""); + if (has_ns_) + name += ns_ + "|"; + return name + name_; } + size_t Simple_Selector::hash() const + { + if (hash_ == 0) { + hash_combine(hash_, std::hash()(SELECTOR)); + hash_combine(hash_, std::hash()(simple_type())); + hash_combine(hash_, std::hash()(ns())); + hash_combine(hash_, std::hash()(name())); + } + return hash_; + } + + bool Simple_Selector::empty() const { + return ns().empty() && name().empty(); + } + + // namespace compare functions bool Simple_Selector::is_ns_eq(const Simple_Selector& r) const { // https://github.com/sass/sass/issues/2229 @@ -71,34 +160,229 @@ namespace Sass { return false; } - bool Compound_Selector::has_parent_ref() const + // namespace query functions + bool Simple_Selector::is_universal_ns() const + { + return has_ns_ && ns_ == "*"; + } + + bool Simple_Selector::has_universal_ns() const + { + return !has_ns_ || ns_ == "*"; + } + + bool Simple_Selector::is_empty_ns() const + { + return !has_ns_ || ns_ == ""; + } + + bool Simple_Selector::has_empty_ns() const + { + return has_ns_ && ns_ == ""; + } + + bool Simple_Selector::has_qualified_ns() const + { + return has_ns_ && ns_ != "" && ns_ != "*"; + } + + // name query functions + bool Simple_Selector::is_universal() const + { + return name_ == "*"; + } + + bool Simple_Selector::has_placeholder() { - for (Simple_Selector_Obj s : *this) { - if (s && s->has_parent_ref()) return true; - } return false; } - bool Compound_Selector::has_real_parent_ref() const + bool Simple_Selector::has_parent_ref() const + { + return false; + }; + + bool Simple_Selector::has_real_parent_ref() const + { + return false; + }; + + bool Simple_Selector::is_pseudo_element() const { - for (Simple_Selector_Obj s : *this) { - if (s && s->has_real_parent_ref()) return true; - } return false; } - bool Complex_Selector::has_parent_ref() const + bool Simple_Selector::is_superselector_of(Compound_Selector_Ptr_Const sub) const { - return (head() && head()->has_parent_ref()) || - (tail() && tail()->has_parent_ref()); + return false; } - bool Complex_Selector::has_real_parent_ref() const + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Parent_Selector::Parent_Selector(ParserState pstate, bool r) + : Simple_Selector(pstate, "&"), real_(r) + { simple_type(PARENT_SEL); } + Parent_Selector::Parent_Selector(const Parent_Selector* ptr) + : Simple_Selector(ptr), real_(ptr->real_) + { simple_type(PARENT_SEL); } + + bool Parent_Selector::has_parent_ref() const { - return (head() && head()->has_real_parent_ref()) || - (tail() && tail()->has_real_parent_ref()); + return true; + }; + + bool Parent_Selector::has_real_parent_ref() const + { + return real(); + }; + + unsigned long Parent_Selector::specificity() const + { + return 0; } + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Placeholder_Selector::Placeholder_Selector(ParserState pstate, std::string n) + : Simple_Selector(pstate, n) + { simple_type(PLACEHOLDER_SEL); } + Placeholder_Selector::Placeholder_Selector(const Placeholder_Selector* ptr) + : Simple_Selector(ptr) + { simple_type(PLACEHOLDER_SEL); } + unsigned long Placeholder_Selector::specificity() const + { + return Constants::Specificity_Base; + } + bool Placeholder_Selector::has_placeholder() { + return true; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Type_Selector::Type_Selector(ParserState pstate, std::string n) + : Simple_Selector(pstate, n) + { simple_type(TYPE_SEL); } + Type_Selector::Type_Selector(const Type_Selector* ptr) + : Simple_Selector(ptr) + { simple_type(TYPE_SEL); } + + unsigned long Type_Selector::specificity() const + { + if (name() == "*") return 0; + else return Constants::Specificity_Element; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Class_Selector::Class_Selector(ParserState pstate, std::string n) + : Simple_Selector(pstate, n) + { simple_type(CLASS_SEL); } + Class_Selector::Class_Selector(const Class_Selector* ptr) + : Simple_Selector(ptr) + { simple_type(CLASS_SEL); } + + unsigned long Class_Selector::specificity() const + { + return Constants::Specificity_Class; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Id_Selector::Id_Selector(ParserState pstate, std::string n) + : Simple_Selector(pstate, n) + { simple_type(ID_SEL); } + Id_Selector::Id_Selector(const Id_Selector* ptr) + : Simple_Selector(ptr) + { simple_type(ID_SEL); } + + unsigned long Id_Selector::specificity() const + { + return Constants::Specificity_ID; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Attribute_Selector::Attribute_Selector(ParserState pstate, std::string n, std::string m, String_Obj v, char o) + : Simple_Selector(pstate, n), matcher_(m), value_(v), modifier_(o) + { simple_type(ATTRIBUTE_SEL); } + Attribute_Selector::Attribute_Selector(const Attribute_Selector* ptr) + : Simple_Selector(ptr), + matcher_(ptr->matcher_), + value_(ptr->value_), + modifier_(ptr->modifier_) + { simple_type(ATTRIBUTE_SEL); } + + size_t Attribute_Selector::hash() const + { + if (hash_ == 0) { + hash_combine(hash_, Simple_Selector::hash()); + hash_combine(hash_, std::hash()(matcher())); + if (value_) hash_combine(hash_, value_->hash()); + } + return hash_; + } + + unsigned long Attribute_Selector::specificity() const + { + return Constants::Specificity_Attr; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Pseudo_Selector::Pseudo_Selector(ParserState pstate, std::string n, String_Obj expr) + : Simple_Selector(pstate, n), expression_(expr) + { simple_type(PSEUDO_SEL); } + Pseudo_Selector::Pseudo_Selector(const Pseudo_Selector* ptr) + : Simple_Selector(ptr), expression_(ptr->expression_) + { simple_type(PSEUDO_SEL); } + + // A pseudo-element is made of two colons (::) followed by the name. + // The `::` notation is introduced by the current document in order to + // establish a discrimination between pseudo-classes and pseudo-elements. + // For compatibility with existing style sheets, user agents must also + // accept the previous one-colon notation for pseudo-elements introduced + // in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and + // :after). This compatibility is not allowed for the new pseudo-elements + // introduced in this specification. + bool Pseudo_Selector::is_pseudo_element() const + { + return (name_[0] == ':' && name_[1] == ':') + || is_pseudo_class_element(name_); + } + + size_t Pseudo_Selector::hash() const + { + if (hash_ == 0) { + hash_combine(hash_, Simple_Selector::hash()); + if (expression_) hash_combine(hash_, expression_->hash()); + } + return hash_; + } + + unsigned long Pseudo_Selector::specificity() const + { + if (is_pseudo_element()) + return Constants::Specificity_Element; + return Constants::Specificity_Pseudo; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Wrapped_Selector::Wrapped_Selector(ParserState pstate, std::string n, Selector_List_Obj sel) + : Simple_Selector(pstate, n), selector_(sel) + { simple_type(WRAPPED_SEL); } + Wrapped_Selector::Wrapped_Selector(const Wrapped_Selector* ptr) + : Simple_Selector(ptr), selector_(ptr->selector_) + { simple_type(WRAPPED_SEL); } + bool Wrapped_Selector::is_superselector_of(Wrapped_Selector_Ptr_Const sub) const { if (this->name() != sub->name()) return false; @@ -112,6 +396,105 @@ namespace Sass { return false; } + // Selectors inside the negation pseudo-class are counted like any + // other, but the negation itself does not count as a pseudo-class. + + void Wrapped_Selector::cloneChildren() + { + selector(SASS_MEMORY_CLONE(selector())); + } + + size_t Wrapped_Selector::hash() const + { + if (hash_ == 0) { + hash_combine(hash_, Simple_Selector::hash()); + if (selector_) hash_combine(hash_, selector_->hash()); + } + return hash_; + } + + bool Wrapped_Selector::has_parent_ref() const { + if (!selector()) return false; + return selector()->has_parent_ref(); + } + + bool Wrapped_Selector::has_real_parent_ref() const { + if (!selector()) return false; + return selector()->has_real_parent_ref(); + } + + unsigned long Wrapped_Selector::specificity() const + { + return selector_ ? selector_->specificity() : 0; + } + + bool Wrapped_Selector::find ( bool (*f)(AST_Node_Obj) ) + { + // check children first + if (selector_) { + if (selector_->find(f)) return true; + } + // execute last + return f(this); + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Compound_Selector::Compound_Selector(ParserState pstate, size_t s) + : Selector(pstate), + Vectorized(s), + extended_(false), + has_parent_reference_(false) + { } + + Compound_Selector::Compound_Selector(const Compound_Selector* ptr) + : Selector(ptr), + Vectorized(*ptr), + extended_(ptr->extended_), + has_parent_reference_(ptr->has_parent_reference_) + { } + + bool Compound_Selector::contains_placeholder() { + for (size_t i = 0, L = length(); i < L; ++i) { + if ((*this)[i]->has_placeholder()) return true; + } + return false; + }; + + void Compound_Selector::cloneChildren() + { + for (size_t i = 0, l = length(); i < l; i++) { + at(i) = SASS_MEMORY_CLONE(at(i)); + } + } + + bool Compound_Selector::find ( bool (*f)(AST_Node_Obj) ) + { + // check children first + for (Simple_Selector_Obj sel : elements()) { + if (sel->find(f)) return true; + } + // execute last + return f(this); + } + + bool Compound_Selector::has_parent_ref() const + { + for (Simple_Selector_Obj s : *this) { + if (s && s->has_parent_ref()) return true; + } + return false; + } + + bool Compound_Selector::has_real_parent_ref() const + { + for (Simple_Selector_Obj s : *this) { + if (s && s->has_real_parent_ref()) return true; + } + return false; + } + bool Compound_Selector::is_superselector_of(Selector_List_Ptr_Const rhs, std::string wrapped) const { for (Complex_Selector_Obj item : rhs->elements()) { @@ -211,7 +594,7 @@ namespace Sass { if (Wrapped_Selector_Obj wrapped = Cast(r)) { if (wrapped->name() == ":not") { if (Selector_List_Obj ls = Cast(wrapped->selector())) { - ls->remove_parent_selectors(); + ls->remove_parent_selectors(); // unverified if (is_superselector_of(ls, wrapped->name())) return false; } } @@ -220,7 +603,7 @@ namespace Sass { if (wrapping != wrapped->name()) return false; } if (Selector_List_Obj ls = Cast(wrapped->selector())) { - ls->remove_parent_selectors(); + ls->remove_parent_selectors(); // unverified return (is_superselector_of(ls, wrapped->name())); } } @@ -238,6 +621,11 @@ namespace Sass { } + bool Compound_Selector::is_universal() const + { + return length() == 1 && (*this)[0]->is_universal(); + } + // create complex selector (ancestor of) from compound selector Complex_Selector_Obj Compound_Selector::to_complex() { @@ -249,6 +637,232 @@ namespace Sass { {}); } + Simple_Selector_Ptr Compound_Selector::base() const { + if (length() == 0) return 0; + // ToDo: why is this needed? + if (Cast((*this)[0])) + return (*this)[0]; + return 0; + } + + size_t Compound_Selector::hash() const + { + if (Selector::hash_ == 0) { + hash_combine(Selector::hash_, std::hash()(SELECTOR)); + if (length()) hash_combine(Selector::hash_, Vectorized::hash()); + } + return Selector::hash_; + } + + unsigned long Compound_Selector::specificity() const + { + int sum = 0; + for (size_t i = 0, L = length(); i < L; ++i) + { sum += (*this)[i]->specificity(); } + return sum; + } + + bool Compound_Selector::has_placeholder() + { + if (length() == 0) return false; + if (Simple_Selector_Obj ss = elements().front()) { + if (ss->has_placeholder()) return true; + } + return false; + } + + bool Compound_Selector::is_empty_reference() + { + return length() == 1 && + Cast((*this)[0]); + } + + void Compound_Selector::append(Simple_Selector_Obj element) + { + Vectorized::append(element); + pstate_.offset += element->pstate().offset; + } + + Compound_Selector_Ptr Compound_Selector::minus(Compound_Selector_Ptr rhs) + { + Compound_Selector_Ptr result = SASS_MEMORY_NEW(Compound_Selector, pstate()); + // result->has_parent_reference(has_parent_reference()); + + // not very efficient because it needs to preserve order + for (size_t i = 0, L = length(); i < L; ++i) + { + bool found = false; + for (size_t j = 0, M = rhs->length(); j < M; ++j) + { + if (*get(i) == *rhs->get(j)) + { + found = true; + break; + } + } + if (!found) result->append(get(i)); + } + + return result; + } + + void Compound_Selector::mergeSources(ComplexSelectorSet& sources) + { + for (ComplexSelectorSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) { + this->sources_.insert(SASS_MEMORY_CLONE(*iterator)); + } + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Complex_Selector::Complex_Selector(ParserState pstate, + Combinator c, + Compound_Selector_Obj h, + Complex_Selector_Obj t, + String_Obj r) + : Selector(pstate), + combinator_(c), + head_(h), tail_(t), + reference_(r) + {} + Complex_Selector::Complex_Selector(const Complex_Selector* ptr) + : Selector(ptr), + combinator_(ptr->combinator_), + head_(ptr->head_), tail_(ptr->tail_), + reference_(ptr->reference_) + {} + + bool Complex_Selector::empty() const { + return (!tail() || tail()->empty()) + && (!head() || head()->empty()) + && combinator_ == ANCESTOR_OF; + } + + Complex_Selector_Obj Complex_Selector::skip_empty_reference() + { + if ((!head_ || !head_->length() || head_->is_empty_reference()) && + combinator() == Combinator::ANCESTOR_OF) + { + if (!tail_) return {}; + tail_->has_line_feed_ = this->has_line_feed_; + // tail_->has_line_break_ = this->has_line_break_; + return tail_->skip_empty_reference(); + } + return this; + } + + bool Complex_Selector::is_empty_ancestor() const + { + return (!head() || head()->length() == 0) && + combinator() == Combinator::ANCESTOR_OF; + } + + size_t Complex_Selector::hash() const + { + if (hash_ == 0) { + hash_combine(hash_, std::hash()(SELECTOR)); + hash_combine(hash_, std::hash()(combinator_)); + if (head_) hash_combine(hash_, head_->hash()); + if (tail_) hash_combine(hash_, tail_->hash()); + } + return hash_; + } + + unsigned long Complex_Selector::specificity() const + { + int sum = 0; + if (head()) sum += head()->specificity(); + if (tail()) sum += tail()->specificity(); + return sum; + } + + void Complex_Selector::set_media_block(Media_Block_Ptr mb) { + media_block(mb); + if (tail_) tail_->set_media_block(mb); + if (head_) head_->set_media_block(mb); + } + + bool Complex_Selector::has_placeholder() { + if (head_ && head_->has_placeholder()) return true; + if (tail_ && tail_->has_placeholder()) return true; + return false; + } + + const ComplexSelectorSet Complex_Selector::sources() + { + //s = Set.new + //seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)} + //s + + ComplexSelectorSet srcs; + + Compound_Selector_Obj pHead = head(); + Complex_Selector_Obj pTail = tail(); + + if (pHead) { + const ComplexSelectorSet& headSources = pHead->sources(); + srcs.insert(headSources.begin(), headSources.end()); + } + + if (pTail) { + const ComplexSelectorSet& tailSources = pTail->sources(); + srcs.insert(tailSources.begin(), tailSources.end()); + } + + return srcs; + } + + void Complex_Selector::addSources(ComplexSelectorSet& sources) + { + // members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m} + Complex_Selector_Ptr pIter = this; + while (pIter) { + Compound_Selector_Ptr pHead = pIter->head(); + + if (pHead) { + pHead->mergeSources(sources); + } + + pIter = pIter->tail(); + } + } + + void Complex_Selector::clearSources() + { + Complex_Selector_Ptr pIter = this; + while (pIter) { + Compound_Selector_Ptr pHead = pIter->head(); + + if (pHead) { + pHead->clearSources(); + } + + pIter = pIter->tail(); + } + } + + bool Complex_Selector::find ( bool (*f)(AST_Node_Obj) ) + { + // check children first + if (head_ && head_->find(f)) return true; + if (tail_ && tail_->find(f)) return true; + // execute last + return f(this); + } + + bool Complex_Selector::has_parent_ref() const + { + return (head() && head()->has_parent_ref()) || + (tail() && tail()->has_parent_ref()); + } + + bool Complex_Selector::has_real_parent_ref() const + { + return (head() && head()->has_real_parent_ref()) || + (tail() && tail()->has_real_parent_ref()); + } + bool Complex_Selector::is_superselector_of(Compound_Selector_Ptr_Const rhs, std::string wrapping) const { return last()->head() && last()->head()->is_superselector_of(rhs, wrapping); @@ -421,25 +1035,6 @@ namespace Sass { } - Selector_List_Obj Selector_List::eval(Eval& eval) - { - Selector_List_Obj list = schema() ? - eval(schema()) : eval(this); - list->schema(schema()); - return list; - } - - Selector_List_Ptr Selector_List::resolve_parent_refs(SelectorStack& pstack, Backtraces& traces, bool implicit_parent) - { - if (!this->has_parent_ref()) return this; - Selector_List_Ptr ss = SASS_MEMORY_NEW(Selector_List, pstate()); - for (size_t si = 0, sL = this->length(); si < sL; ++si) { - Selector_List_Obj rv = at(si)->resolve_parent_refs(pstack, traces, implicit_parent); - ss->concat(rv); - } - return ss; - } - Selector_List_Ptr Complex_Selector::resolve_parent_refs(SelectorStack& pstack, Backtraces& traces, bool implicit_parent) { Complex_Selector_Obj tail = this->tail(); @@ -672,23 +1267,67 @@ namespace Sass { if (tail()) tail(SASS_MEMORY_CLONE(tail())); } - void Compound_Selector::cloneChildren() + // it's a superselector if every selector of the right side + // list is a superselector of the given left side selector + bool Complex_Selector::is_superselector_of(Selector_List_Ptr_Const sub, std::string wrapping) const { - for (size_t i = 0, l = length(); i < l; i++) { - at(i) = SASS_MEMORY_CLONE(at(i)); + // Check every rhs selector against left hand list + for(size_t i = 0, L = sub->length(); i < L; ++i) { + if (!is_superselector_of((*sub)[i], wrapping)) return false; } + return true; } - void Selector_List::cloneChildren() + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Selector_List::Selector_List(ParserState pstate, size_t s) + : Selector(pstate), + Vectorized(s), + schema_({}), + wspace_(0) + { } + Selector_List::Selector_List(const Selector_List* ptr) + : Selector(ptr), + Vectorized(*ptr), + schema_(ptr->schema_), + wspace_(ptr->wspace_) + { } + + bool Selector_List::find ( bool (*f)(AST_Node_Obj) ) { - for (size_t i = 0, l = length(); i < l; i++) { - at(i) = SASS_MEMORY_CLONE(at(i)); + // check children first + for (Complex_Selector_Obj sel : elements()) { + if (sel->find(f)) return true; } + // execute last + return f(this); } - void Wrapped_Selector::cloneChildren() + Selector_List_Obj Selector_List::eval(Eval& eval) { - selector(SASS_MEMORY_CLONE(selector())); + Selector_List_Obj list = schema() ? + eval(schema()) : eval(this); + list->schema(schema()); + return list; + } + + Selector_List_Ptr Selector_List::resolve_parent_refs(SelectorStack& pstack, Backtraces& traces, bool implicit_parent) + { + if (!this->has_parent_ref()) return this; + Selector_List_Ptr ss = SASS_MEMORY_NEW(Selector_List, pstate()); + for (size_t si = 0, sL = this->length(); si < sL; ++si) { + Selector_List_Obj rv = at(si)->resolve_parent_refs(pstack, traces, implicit_parent); + ss->concat(rv); + } + return ss; + } + + void Selector_List::cloneChildren() + { + for (size_t i = 0, l = length(); i < l; i++) { + at(i) = SASS_MEMORY_CLONE(at(i)); + } } // remove parent selector references @@ -716,30 +1355,6 @@ namespace Sass { } } - size_t Wrapped_Selector::hash() const - { - if (hash_ == 0) { - hash_combine(hash_, Simple_Selector::hash()); - if (selector_) hash_combine(hash_, selector_->hash()); - } - return hash_; - } - bool Wrapped_Selector::has_parent_ref() const { - // if (has_reference()) return true; - if (!selector()) return false; - return selector()->has_parent_ref(); - } - bool Wrapped_Selector::has_real_parent_ref() const { - // if (has_reference()) return true; - if (!selector()) return false; - return selector()->has_real_parent_ref(); - } - unsigned long Wrapped_Selector::specificity() const - { - return selector_ ? selector_->specificity() : 0; - } - - bool Selector_List::has_parent_ref() const { for (Complex_Selector_Obj s : elements()) { @@ -756,39 +1371,11 @@ namespace Sass { return false; } - bool Selector_Schema::has_parent_ref() const - { - if (String_Schema_Obj schema = Cast(contents())) { - return schema->length() > 0 && Cast(schema->at(0)) != NULL; - } - return false; - } - - bool Selector_Schema::has_real_parent_ref() const - { - if (String_Schema_Obj schema = Cast(contents())) { - if (schema->length() == 0) return false; - return Cast(schema->at(0)) != nullptr; - } - return false; - } - void Selector_List::adjust_after_pushing(Complex_Selector_Obj c) { // if (c->has_reference()) has_reference(true); } - // it's a superselector if every selector of the right side - // list is a superselector of the given left side selector - bool Complex_Selector::is_superselector_of(Selector_List_Ptr_Const sub, std::string wrapping) const - { - // Check every rhs selector against left hand list - for(size_t i = 0, L = sub->length(); i < L; ++i) { - if (!is_superselector_of((*sub)[i], wrapping)) return false; - } - return true; - } - // it's a superselector if every selector of the right side // list is a superselector of the given left side selector bool Selector_List::is_superselector_of(Selector_List_Ptr_Const sub, std::string wrapping) const @@ -855,43 +1442,46 @@ namespace Sass { } }; - void Compound_Selector::append(Simple_Selector_Obj element) + size_t Selector_List::hash() const { - Vectorized::append(element); - pstate_.offset += element->pstate().offset; + if (Selector::hash_ == 0) { + hash_combine(Selector::hash_, std::hash()(SELECTOR)); + hash_combine(Selector::hash_, Vectorized::hash()); + } + return Selector::hash_; } - Compound_Selector_Ptr Compound_Selector::minus(Compound_Selector_Ptr rhs) + unsigned long Selector_List::specificity() const { - Compound_Selector_Ptr result = SASS_MEMORY_NEW(Compound_Selector, pstate()); - // result->has_parent_reference(has_parent_reference()); - - // not very efficient because it needs to preserve order + unsigned long sum = 0; + unsigned long specificity; for (size_t i = 0, L = length(); i < L; ++i) { - bool found = false; - std::string thisSelector((*this)[i]->to_string()); - for (size_t j = 0, M = rhs->length(); j < M; ++j) - { - if (thisSelector == (*rhs)[j]->to_string()) - { - found = true; - break; - } - } - if (!found) result->append((*this)[i]); + specificity = (*this)[i]->specificity(); + if (sum < specificity) sum = specificity; } + return sum; + } - return result; + void Selector_List::set_media_block(Media_Block_Ptr mb) + { + media_block(mb); + for (Complex_Selector_Obj cs : elements()) { + cs->set_media_block(mb); + } } - void Compound_Selector::mergeSources(ComplexSelectorSet& sources) + bool Selector_List::has_placeholder() { - for (ComplexSelectorSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) { - this->sources_.insert(SASS_MEMORY_CLONE(*iterator)); + for (Complex_Selector_Obj cs : elements()) { + if (cs->has_placeholder()) return true; } + return false; } + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + IMPLEMENT_AST_OPERATORS(Selector_Schema); IMPLEMENT_AST_OPERATORS(Placeholder_Selector); IMPLEMENT_AST_OPERATORS(Parent_Selector); diff --git a/src/ast_selectors.hpp b/src/ast_selectors.hpp index a81a697a7..37eef5d3e 100644 --- a/src/ast_selectors.hpp +++ b/src/ast_selectors.hpp @@ -37,51 +37,27 @@ namespace Sass { // Abstract base class for CSS selectors. ///////////////////////////////////////// class Selector : public Expression { - // ADD_PROPERTY(bool, has_reference) // line break before list separator ADD_PROPERTY(bool, has_line_feed) // line break after list separator ADD_PROPERTY(bool, has_line_break) // maybe we have optional flag ADD_PROPERTY(bool, is_optional) - // parent block pointers - // must not be a reference counted object // otherwise we create circular references ADD_PROPERTY(Media_Block_Ptr, media_block) protected: mutable size_t hash_; public: - Selector(ParserState pstate) - : Expression(pstate), - has_line_feed_(false), - has_line_break_(false), - is_optional_(false), - media_block_(0), - hash_(0) - { concrete_type(SELECTOR); } - Selector(const Selector* ptr) - : Expression(ptr), - // has_reference_(ptr->has_reference_), - has_line_feed_(ptr->has_line_feed_), - has_line_break_(ptr->has_line_break_), - is_optional_(ptr->is_optional_), - media_block_(ptr->media_block_), - hash_(ptr->hash_) - { concrete_type(SELECTOR); } + Selector(ParserState pstate); + Selector(const Selector* ptr); virtual ~Selector() = 0; size_t hash() const override = 0; virtual unsigned long specificity() const = 0; virtual int unification_order() const = 0; - virtual void set_media_block(Media_Block_Ptr mb) { - media_block(mb); - } - virtual bool has_parent_ref() const { - return false; - } - virtual bool has_real_parent_ref() const { - return false; - } + virtual void set_media_block(Media_Block_Ptr mb); + virtual bool has_parent_ref() const; + virtual bool has_real_parent_ref() const; // dispatch to correct handlers virtual bool operator<(const Selector& rhs) const = 0; virtual bool operator==(const Selector& rhs) const = 0; @@ -104,33 +80,15 @@ namespace Sass { // store computed hash mutable size_t hash_; public: - Selector_Schema(ParserState pstate, String_Obj c) - : AST_Node(pstate), - contents_(c), - connect_parent_(true), - media_block_(NULL), - hash_(0) - { } - Selector_Schema(const Selector_Schema* ptr) - : AST_Node(ptr), - contents_(ptr->contents_), - connect_parent_(ptr->connect_parent_), - media_block_(ptr->media_block_), - hash_(ptr->hash_) - { } + Selector_Schema(ParserState pstate, String_Obj c); bool has_parent_ref() const; bool has_real_parent_ref() const; bool operator<(const Selector& rhs) const; bool operator==(const Selector& rhs) const; // selector schema is not yet a final selector, so we do not // have a specificity for it yet. We need to - unsigned long specificity() const { return 0; } - size_t hash() const override { - if (hash_ == 0) { - hash_combine(hash_, contents_->hash()); - } - return hash_; - } + virtual unsigned long specificity() const; + size_t hash() const override; ATTACH_AST_OPERATIONS(Selector_Schema) ATTACH_CRTP_PERFORM_METHODS() }; @@ -156,81 +114,30 @@ namespace Sass { ADD_PROPERTY(Simple_Type, simple_type) ADD_PROPERTY(bool, has_ns) public: - Simple_Selector(ParserState pstate, std::string n = "") - : Selector(pstate), ns_(""), name_(n), has_ns_(false) - { - size_t pos = n.find('|'); - // found some namespace - if (pos != std::string::npos) { - has_ns_ = true; - ns_ = n.substr(0, pos); - name_ = n.substr(pos + 1); - } - } - Simple_Selector(const Simple_Selector* ptr) - : Selector(ptr), - ns_(ptr->ns_), - name_(ptr->name_), - has_ns_(ptr->has_ns_) - { } - std::string ns_name() const - { - std::string name(""); - if (has_ns_) - name += ns_ + "|"; - return name + name_; - } - virtual size_t hash() const override - { - if (hash_ == 0) { - hash_combine(hash_, std::hash()(SELECTOR)); - hash_combine(hash_, std::hash()(simple_type())); - hash_combine(hash_, std::hash()(ns())); - hash_combine(hash_, std::hash()(name())); - } - return hash_; - } - bool empty() const { - return ns().empty() && name().empty(); - } + Simple_Selector(ParserState pstate, std::string n = ""); + Simple_Selector(const Simple_Selector* ptr); + virtual std::string ns_name() const; + size_t hash() const override; + bool empty() const; // namespace compare functions bool is_ns_eq(const Simple_Selector& r) const; // namespace query functions - bool is_universal_ns() const - { - return has_ns_ && ns_ == "*"; - } - bool has_universal_ns() const - { - return !has_ns_ || ns_ == "*"; - } - bool is_empty_ns() const - { - return !has_ns_ || ns_ == ""; - } - bool has_empty_ns() const - { - return has_ns_ && ns_ == ""; - } - bool has_qualified_ns() const - { - return has_ns_ && ns_ != "" && ns_ != "*"; - } + bool is_universal_ns() const; + bool has_universal_ns() const; + bool is_empty_ns() const; + bool has_empty_ns() const; + bool has_qualified_ns() const; // name query functions - virtual bool is_universal() const - { - return name_ == "*"; - } - - virtual bool has_placeholder() { - return false; - } + bool is_universal() const; + virtual bool has_placeholder(); virtual ~Simple_Selector() = 0; virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr); - virtual bool is_pseudo_element() const { return false; } - virtual bool is_superselector_of(Compound_Selector_Ptr_Const sub) const { return false; } + virtual bool has_parent_ref() const; + virtual bool has_real_parent_ref() const ; + virtual bool is_pseudo_element() const; + virtual bool is_superselector_of(Compound_Selector_Ptr_Const sub) const; bool operator<(const Selector& rhs) const final override; bool operator==(const Selector& rhs) const final override; @@ -249,29 +156,23 @@ namespace Sass { }; inline Simple_Selector::~Simple_Selector() { } - ////////////////////////////////// // The Parent Selector Expression. ////////////////////////////////// - // parent selectors can occur in selectors but also - // inside strings in declarations (Compound_Selector). - // only one simple parent selector means the first case. class Parent_Selector final : public Simple_Selector { + // a real parent selector is given by the user + // others are added implicitly to connect the + // selector scopes automatically when rendered + // a Parent_Reference is never seen in selectors + // and is only used in values (e.g. `prop: #{&};`) ADD_PROPERTY(bool, real) public: - Parent_Selector(ParserState pstate, bool r = true) - : Simple_Selector(pstate, "&"), real_(r) - { simple_type(PARENT_SEL); } - Parent_Selector(const Parent_Selector* ptr) - : Simple_Selector(ptr), real_(ptr->real_) - { simple_type(PARENT_SEL); } - bool is_real_parent_ref() const { return real(); }; - bool has_parent_ref() const override { return true; }; - bool has_real_parent_ref() const override { return is_real_parent_ref(); }; - unsigned long specificity() const override - { - return 0; - } + Parent_Selector(ParserState pstate, bool r = true); + + virtual bool has_parent_ref() const; + virtual bool has_real_parent_ref() const; + + virtual unsigned long specificity() const; int unification_order() const override { throw std::runtime_error("unification_order for Parent_Selector is undefined"); @@ -292,26 +193,17 @@ namespace Sass { ///////////////////////////////////////////////////////////////////////// class Placeholder_Selector final : public Simple_Selector { public: - Placeholder_Selector(ParserState pstate, std::string n) - : Simple_Selector(pstate, n) - { simple_type(PLACEHOLDER_SEL); } - Placeholder_Selector(const Placeholder_Selector* ptr) - : Simple_Selector(ptr) - { simple_type(PLACEHOLDER_SEL); } - unsigned long specificity() const override - { - return Constants::Specificity_Base; - } + Placeholder_Selector(ParserState pstate, std::string n); + int unification_order() const override { return Constants::UnificationOrder_Placeholder; } - bool has_placeholder() override { - return true; - } virtual ~Placeholder_Selector() {}; - bool operator<(const Simple_Selector& rhs) const final override; - bool operator==(const Simple_Selector& rhs) const final override; + virtual unsigned long specificity() const; + virtual bool has_placeholder(); + bool operator<(const Simple_Selector& rhs) const; + bool operator==(const Simple_Selector& rhs) const; bool operator<(const Placeholder_Selector& rhs) const; bool operator==(const Placeholder_Selector& rhs) const; ATTACH_AST_OPERATIONS(Placeholder_Selector) @@ -323,17 +215,8 @@ namespace Sass { ///////////////////////////////////////////////////////////////////// class Type_Selector final : public Simple_Selector { public: - Type_Selector(ParserState pstate, std::string n) - : Simple_Selector(pstate, n) - { simple_type(TYPE_SEL); } - Type_Selector(const Type_Selector* ptr) - : Simple_Selector(ptr) - { simple_type(TYPE_SEL); } - unsigned long specificity() const override - { - if (name() == "*") return 0; - else return Constants::Specificity_Element; - } + Type_Selector(ParserState pstate, std::string n); + virtual unsigned long specificity() const; int unification_order() const override { return Constants::UnificationOrder_Element; @@ -353,16 +236,8 @@ namespace Sass { //////////////////////////////////////////////// class Class_Selector final : public Simple_Selector { public: - Class_Selector(ParserState pstate, std::string n) - : Simple_Selector(pstate, n) - { simple_type(CLASS_SEL); } - Class_Selector(const Class_Selector* ptr) - : Simple_Selector(ptr) - { simple_type(CLASS_SEL); } - unsigned long specificity() const override - { - return Constants::Specificity_Class; - } + Class_Selector(ParserState pstate, std::string n); + virtual unsigned long specificity() const; int unification_order() const override { return Constants::UnificationOrder_Class; @@ -381,16 +256,8 @@ namespace Sass { //////////////////////////////////////////////// class Id_Selector final : public Simple_Selector { public: - Id_Selector(ParserState pstate, std::string n) - : Simple_Selector(pstate, n) - { simple_type(ID_SEL); } - Id_Selector(const Id_Selector* ptr) - : Simple_Selector(ptr) - { simple_type(ID_SEL); } - unsigned long specificity() const override - { - return Constants::Specificity_ID; - } + Id_Selector(ParserState pstate, std::string n); + virtual unsigned long specificity() const; int unification_order() const override { return Constants::UnificationOrder_Id; @@ -413,28 +280,9 @@ namespace Sass { ADD_PROPERTY(String_Obj, value) // might be interpolated ADD_PROPERTY(char, modifier); public: - Attribute_Selector(ParserState pstate, std::string n, std::string m, String_Obj v, char o = 0) - : Simple_Selector(pstate, n), matcher_(m), value_(v), modifier_(o) - { simple_type(ATTRIBUTE_SEL); } - Attribute_Selector(const Attribute_Selector* ptr) - : Simple_Selector(ptr), - matcher_(ptr->matcher_), - value_(ptr->value_), - modifier_(ptr->modifier_) - { simple_type(ATTRIBUTE_SEL); } - size_t hash() const override - { - if (hash_ == 0) { - hash_combine(hash_, Simple_Selector::hash()); - hash_combine(hash_, std::hash()(matcher())); - if (value_) hash_combine(hash_, value_->hash()); - } - return hash_; - } - unsigned long specificity() const override - { - return Constants::Specificity_Attr; - } + Attribute_Selector(ParserState pstate, std::string n, std::string m, String_Obj v, char o = 0); + size_t hash() const override; + virtual unsigned long specificity() const; int unification_order() const override { return Constants::UnificationOrder_Attribute; @@ -466,40 +314,10 @@ namespace Sass { class Pseudo_Selector final : public Simple_Selector { ADD_PROPERTY(String_Obj, expression) public: - Pseudo_Selector(ParserState pstate, std::string n, String_Obj expr = {}) - : Simple_Selector(pstate, n), expression_(expr) - { simple_type(PSEUDO_SEL); } - Pseudo_Selector(const Pseudo_Selector* ptr) - : Simple_Selector(ptr), expression_(ptr->expression_) - { simple_type(PSEUDO_SEL); } - - // A pseudo-element is made of two colons (::) followed by the name. - // The `::` notation is introduced by the current document in order to - // establish a discrimination between pseudo-classes and pseudo-elements. - // For compatibility with existing style sheets, user agents must also - // accept the previous one-colon notation for pseudo-elements introduced - // in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and - // :after). This compatibility is not allowed for the new pseudo-elements - // introduced in this specification. - bool is_pseudo_element() const override - { - return (name_[0] == ':' && name_[1] == ':') - || is_pseudo_class_element(name_); - } - size_t hash() const override - { - if (hash_ == 0) { - hash_combine(hash_, Simple_Selector::hash()); - if (expression_) hash_combine(hash_, expression_->hash()); - } - return hash_; - } - unsigned long specificity() const override - { - if (is_pseudo_element()) - return Constants::Specificity_Element; - return Constants::Specificity_Pseudo; - } + Pseudo_Selector(ParserState pstate, std::string n, String_Obj expr = {}); + virtual bool is_pseudo_element() const; + size_t hash() const override; + virtual unsigned long specificity() const; int unification_order() const override { if (is_pseudo_element()) @@ -521,12 +339,7 @@ namespace Sass { class Wrapped_Selector final : public Simple_Selector { ADD_PROPERTY(Selector_List_Obj, selector) public: - Wrapped_Selector(ParserState pstate, std::string n, Selector_List_Obj sel) - : Simple_Selector(pstate, n), selector_(sel) - { simple_type(WRAPPED_SEL); } - Wrapped_Selector(const Wrapped_Selector* ptr) - : Simple_Selector(ptr), selector_(ptr->selector_) - { simple_type(WRAPPED_SEL); } + Wrapped_Selector(ParserState pstate, std::string n, Selector_List_Obj sel); using Simple_Selector::is_superselector_of; bool is_superselector_of(Wrapped_Selector_Ptr_Const sub) const; // Selectors inside the negation pseudo-class are counted like any @@ -565,82 +378,27 @@ namespace Sass { // if (s->has_placeholder()) has_placeholder(true); } public: - Compound_Selector(ParserState pstate, size_t s = 0) - : Selector(pstate), - Vectorized(s), - extended_(false), - has_parent_reference_(false) - { } - Compound_Selector(const Compound_Selector* ptr) - : Selector(ptr), - Vectorized(*ptr), - extended_(ptr->extended_), - has_parent_reference_(ptr->has_parent_reference_) - { } - bool contains_placeholder() { - for (size_t i = 0, L = length(); i < L; ++i) { - if ((*this)[i]->has_placeholder()) return true; - } - return false; - }; - + Compound_Selector(ParserState pstate, size_t s = 0); + bool contains_placeholder(); void append(Simple_Selector_Obj element) override; - - bool is_universal() const - { - return length() == 1 && (*this)[0]->is_universal(); - } - + bool is_universal() const; Complex_Selector_Obj to_complex(); Compound_Selector_Ptr unify_with(Compound_Selector_Ptr rhs); // virtual Placeholder_Selector_Ptr find_placeholder(); bool has_parent_ref() const override; bool has_real_parent_ref() const override; - Simple_Selector_Ptr base() const { - if (length() == 0) return 0; - // ToDo: why is this needed? - if (Cast((*this)[0])) - return (*this)[0]; - return 0; - } + Simple_Selector_Ptr base() const; bool is_superselector_of(Compound_Selector_Ptr_Const sub, std::string wrapped = "") const; bool is_superselector_of(Complex_Selector_Ptr_Const sub, std::string wrapped = "") const; bool is_superselector_of(Selector_List_Ptr_Const sub, std::string wrapped = "") const; - size_t hash() const override - { - if (Selector::hash_ == 0) { - hash_combine(Selector::hash_, std::hash()(SELECTOR)); - if (length()) hash_combine(Selector::hash_, Vectorized::hash()); - } - return Selector::hash_; - } - unsigned long specificity() const override - { - int sum = 0; - for (size_t i = 0, L = length(); i < L; ++i) - { sum += (*this)[i]->specificity(); } - return sum; - } + size_t hash() const override; + virtual unsigned long specificity() const override; + virtual bool has_placeholder(); + bool is_empty_reference(); int unification_order() const override { throw std::runtime_error("unification_order for Compound_Selector is undefined"); } - - bool has_placeholder() - { - if (length() == 0) return false; - if (Simple_Selector_Obj ss = elements().front()) { - if (ss->has_placeholder()) return true; - } - return false; - } - - bool is_empty_reference() - { - return length() == 1 && - Cast((*this)[0]); - } - bool find ( bool (*f)(AST_Node_Obj) ) override; bool operator<(const Selector& rhs) const override; @@ -687,45 +445,16 @@ namespace Sass { Combinator c = ANCESTOR_OF, Compound_Selector_Obj h = {}, Complex_Selector_Obj t = {}, - String_Obj r = {}) - : Selector(pstate), - combinator_(c), - head_(h), tail_(t), - reference_(r) - {} - Complex_Selector(const Complex_Selector* ptr) - : Selector(ptr), - combinator_(ptr->combinator_), - head_(ptr->head_), tail_(ptr->tail_), - reference_(ptr->reference_) - {}; - bool empty() const { - return (!tail() || tail()->empty()) - && (!head() || head()->empty()) - && combinator_ == ANCESTOR_OF; - } + String_Obj r = {}); + + bool empty() const; + bool has_parent_ref() const override; bool has_real_parent_ref() const override; - - Complex_Selector_Obj skip_empty_reference() - { - if ((!head_ || !head_->length() || head_->is_empty_reference()) && - combinator() == Combinator::ANCESTOR_OF) - { - if (!tail_) return {}; - tail_->has_line_feed_ = this->has_line_feed_; - // tail_->has_line_break_ = this->has_line_break_; - return tail_->skip_empty_reference(); - } - return this; - } + Complex_Selector_Obj skip_empty_reference(); // can still have a tail - bool is_empty_ancestor() const - { - return (!head() || head()->length() == 0) && - combinator() == Combinator::ANCESTOR_OF; - } + bool is_empty_ancestor() const; Selector_List_Ptr tails(Selector_List_Ptr tails); @@ -747,37 +476,15 @@ namespace Sass { Combinator clear_innermost(); void append(Complex_Selector_Obj, Backtraces& traces); void set_innermost(Complex_Selector_Obj, Combinator); - size_t hash() const override - { - if (hash_ == 0) { - hash_combine(hash_, std::hash()(SELECTOR)); - hash_combine(hash_, std::hash()(combinator_)); - if (head_) hash_combine(hash_, head_->hash()); - if (tail_) hash_combine(hash_, tail_->hash()); - } - return hash_; - } - unsigned long specificity() const override - { - int sum = 0; - if (head()) sum += head()->specificity(); - if (tail()) sum += tail()->specificity(); - return sum; - } + + size_t hash() const override; + virtual unsigned long specificity() const; + virtual void set_media_block(Media_Block_Ptr mb); + virtual bool has_placeholder(); int unification_order() const override { throw std::runtime_error("unification_order for Complex_Selector is undefined"); } - void set_media_block(Media_Block_Ptr mb) override { - media_block(mb); - if (tail_) tail_->set_media_block(mb); - if (head_) head_->set_media_block(mb); - } - bool has_placeholder() { - if (head_ && head_->has_placeholder()) return true; - if (tail_ && tail_->has_placeholder()) return true; - return false; - } bool find ( bool (*f)(AST_Node_Obj) ) override; bool operator<(const Selector& rhs) const override; @@ -791,54 +498,9 @@ namespace Sass { bool operator<(const Simple_Selector& rhs) const; bool operator==(const Simple_Selector& rhs) const; - const ComplexSelectorSet sources() - { - //s = Set.new - //seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)} - //s - - ComplexSelectorSet srcs; - - Compound_Selector_Obj pHead = head(); - Complex_Selector_Obj pTail = tail(); - - if (pHead) { - const ComplexSelectorSet& headSources = pHead->sources(); - srcs.insert(headSources.begin(), headSources.end()); - } - - if (pTail) { - const ComplexSelectorSet& tailSources = pTail->sources(); - srcs.insert(tailSources.begin(), tailSources.end()); - } - - return srcs; - } - void addSources(ComplexSelectorSet& sources) { - // members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m} - Complex_Selector_Ptr pIter = this; - while (pIter) { - Compound_Selector_Ptr pHead = pIter->head(); - - if (pHead) { - pHead->mergeSources(sources); - } - - pIter = pIter->tail(); - } - } - void clearSources() { - Complex_Selector_Ptr pIter = this; - while (pIter) { - Compound_Selector_Ptr pHead = pIter->head(); - - if (pHead) { - pHead->clearSources(); - } - - pIter = pIter->tail(); - } - } + const ComplexSelectorSet sources(); + void addSources(ComplexSelectorSet& sources); + void clearSources(); void cloneChildren() override; ATTACH_AST_OPERATIONS(Complex_Selector) @@ -854,18 +516,7 @@ namespace Sass { protected: void adjust_after_pushing(Complex_Selector_Obj c) override; public: - Selector_List(ParserState pstate, size_t s = 0) - : Selector(pstate), - Vectorized(s), - schema_({}), - wspace_(0) - { } - Selector_List(const Selector_List* ptr) - : Selector(ptr), - Vectorized(*ptr), - schema_(ptr->schema_), - wspace_(ptr->wspace_) - { } + Selector_List(ParserState pstate, size_t s = 0); std::string type() const override { return "list"; } // remove parent selector references // basically unwraps parsed selectors @@ -879,41 +530,15 @@ namespace Sass { Selector_List_Ptr unify_with(Selector_List_Ptr); void populate_extends(Selector_List_Obj, Subset_Map&); Selector_List_Obj eval(Eval& eval); - size_t hash() const override - { - if (Selector::hash_ == 0) { - hash_combine(Selector::hash_, std::hash()(SELECTOR)); - hash_combine(Selector::hash_, Vectorized::hash()); - } - return Selector::hash_; - } - unsigned long specificity() const override - { - unsigned long sum = 0; - unsigned long specificity; - for (size_t i = 0, L = length(); i < L; ++i) - { - specificity = (*this)[i]->specificity(); - if (sum < specificity) sum = specificity; - } - return sum; - } + + size_t hash() const override; + virtual unsigned long specificity() const; + virtual void set_media_block(Media_Block_Ptr mb); + virtual bool has_placeholder(); int unification_order() const override { throw std::runtime_error("unification_order for Selector_List is undefined"); } - void set_media_block(Media_Block_Ptr mb) override { - media_block(mb); - for (Complex_Selector_Obj cs : elements()) { - cs->set_media_block(mb); - } - } - bool has_placeholder() { - for (Complex_Selector_Obj cs : elements()) { - if (cs->has_placeholder()) return true; - } - return false; - } bool find ( bool (*f)(AST_Node_Obj) ) override; bool operator<(const Selector& rhs) const override; bool operator==(const Selector& rhs) const override; diff --git a/src/ast_supports.cpp b/src/ast_supports.cpp index 571a57245..087f14f0d 100644 --- a/src/ast_supports.cpp +++ b/src/ast_supports.cpp @@ -33,6 +33,17 @@ namespace Sass { ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// + Supports_Condition::Supports_Condition(ParserState pstate) + : Expression(pstate) + { } + + Supports_Condition::Supports_Condition(const Supports_Condition* ptr) + : Expression(ptr) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + 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) { } diff --git a/src/ast_supports.hpp b/src/ast_supports.hpp index e112876a9..6a27c14a0 100644 --- a/src/ast_supports.hpp +++ b/src/ast_supports.hpp @@ -40,7 +40,6 @@ namespace Sass { ADD_PROPERTY(Supports_Condition_Obj, condition) public: 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() @@ -51,12 +50,7 @@ namespace Sass { ////////////////////////////////////////////////////// class Supports_Condition : public Expression { public: - Supports_Condition(ParserState pstate) - : Expression(pstate) - { } - Supports_Condition(const Supports_Condition* ptr) - : Expression(ptr) - { } + Supports_Condition(ParserState pstate); virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; } ATTACH_AST_OPERATIONS(Supports_Condition) ATTACH_CRTP_PERFORM_METHODS() @@ -74,7 +68,6 @@ namespace Sass { ADD_PROPERTY(Operand, operand); public: Supports_Operator(ParserState pstate, Supports_Condition_Obj l, Supports_Condition_Obj r, Operand o); - Supports_Operator(const Supports_Operator* ptr); virtual bool needs_parens(Supports_Condition_Obj cond) const; ATTACH_AST_OPERATIONS(Supports_Operator) ATTACH_CRTP_PERFORM_METHODS() @@ -88,7 +81,6 @@ namespace Sass { ADD_PROPERTY(Supports_Condition_Obj, condition); public: Supports_Negation(ParserState pstate, Supports_Condition_Obj c); - Supports_Negation(const Supports_Negation* ptr); virtual bool needs_parens(Supports_Condition_Obj cond) const; ATTACH_AST_OPERATIONS(Supports_Negation) ATTACH_CRTP_PERFORM_METHODS() @@ -103,7 +95,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, value); public: 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() @@ -117,7 +108,6 @@ namespace Sass { ADD_PROPERTY(Expression_Obj, value); public: 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() diff --git a/src/ast_values.cpp b/src/ast_values.cpp index b30673b8f..78649b9b8 100644 --- a/src/ast_values.cpp +++ b/src/ast_values.cpp @@ -24,18 +24,368 @@ namespace Sass { str.erase( str.find_last_not_of( delimiters ) + 1 ); } - void String_Constant::rtrim() + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + PreValue::PreValue(ParserState pstate, bool d, bool e, bool i, Type ct) + : Expression(pstate, d, e, i, ct) + { } + PreValue::PreValue(const PreValue* ptr) + : Expression(ptr) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Value::Value(ParserState pstate, bool d, bool e, bool i, Type ct) + : PreValue(pstate, d, e, i, ct) + { } + Value::Value(const Value* ptr) + : PreValue(ptr) + { } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + List::List(ParserState pstate, size_t size, enum Sass_Separator sep, bool argl, bool bracket) + : Value(pstate), + Vectorized(size), + separator_(sep), + is_arglist_(argl), + is_bracketed_(bracket), + from_selector_(false) + { concrete_type(LIST); } + + List::List(const List* ptr) + : Value(ptr), + Vectorized(*ptr), + separator_(ptr->separator_), + is_arglist_(ptr->is_arglist_), + is_bracketed_(ptr->is_bracketed_), + from_selector_(ptr->from_selector_) + { concrete_type(LIST); } + + size_t List::hash() const { - str_rtrim(value_); + if (hash_ == 0) { + hash_ = std::hash()(sep_string()); + hash_combine(hash_, std::hash()(is_bracketed())); + for (size_t i = 0, L = length(); i < L; ++i) + hash_combine(hash_, (elements()[i])->hash()); + } + return hash_; } - void String_Schema::rtrim() + void List::set_delayed(bool delayed) { - if (!empty()) { - if (String_Ptr str = Cast(last())) str->rtrim(); + is_delayed(delayed); + // don't set children + } + + bool List::operator== (const Expression& rhs) const + { + if (List_Ptr_Const r = Cast(&rhs)) { + if (length() != r->length()) return false; + if (separator() != r->separator()) return false; + if (is_bracketed() != r->is_bracketed()) return false; + for (size_t i = 0, L = length(); i < L; ++i) { + Expression_Obj rv = r->at(i); + Expression_Obj lv = this->at(i); + if (!lv || !rv) return false; + if (!(*lv == *rv)) return false; + } + return true; + } + return false; + } + + size_t List::size() const { + if (!is_arglist_) return length(); + // arglist expects a list of arguments + // so we need to break before keywords + for (size_t i = 0, L = length(); i < L; ++i) { + Expression_Obj obj = this->at(i); + if (Argument_Ptr arg = Cast(obj)) { + if (!arg->name().empty()) return i; + } + } + return length(); + } + + + Expression_Obj List::value_at_index(size_t i) { + Expression_Obj obj = this->at(i); + if (is_arglist_) { + if (Argument_Ptr arg = Cast(obj)) { + return arg->value(); + } else { + return obj; + } + } else { + return obj; + } + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Map::Map(ParserState pstate, size_t size) + : Value(pstate), + Hashed(size) + { concrete_type(MAP); } + + Map::Map(const Map* ptr) + : Value(ptr), + Hashed(*ptr) + { concrete_type(MAP); } + + bool Map::operator== (const Expression& rhs) const + { + if (Map_Ptr_Const r = Cast(&rhs)) { + if (length() != r->length()) return false; + for (auto key : keys()) { + Expression_Obj lv = at(key); + Expression_Obj rv = r->at(key); + if (!rv || !lv) return false; + if (!(*lv == *rv)) return false; + } + return true; + } + return false; + } + + List_Obj Map::to_list(ParserState& pstate) { + List_Obj ret = SASS_MEMORY_NEW(List, pstate, length(), SASS_COMMA); + + for (auto key : keys()) { + List_Obj l = SASS_MEMORY_NEW(List, pstate, 2); + l->append(key); + l->append(at(key)); + ret->append(l); + } + + return ret; + } + + size_t Map::hash() const + { + if (hash_ == 0) { + for (auto key : keys()) { + hash_combine(hash_, key->hash()); + hash_combine(hash_, at(key)->hash()); + } + } + + return hash_; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Binary_Expression::Binary_Expression(ParserState pstate, + Operand op, Expression_Obj lhs, Expression_Obj rhs) + : PreValue(pstate), op_(op), left_(lhs), right_(rhs), hash_(0) + { } + + Binary_Expression::Binary_Expression(const Binary_Expression* ptr) + : PreValue(ptr), + op_(ptr->op_), + left_(ptr->left_), + right_(ptr->right_), + hash_(ptr->hash_) + { } + + bool Binary_Expression::is_left_interpolant(void) const + { + return is_interpolant() || (left() && left()->is_left_interpolant()); + } + bool Binary_Expression::is_right_interpolant(void) const + { + return is_interpolant() || (right() && right()->is_right_interpolant()); + } + + const std::string Binary_Expression::type_name() + { + return sass_op_to_name(optype()); + } + + const std::string Binary_Expression::separator() + { + return sass_op_separator(optype()); + } + + bool Binary_Expression::has_interpolant() const + { + return is_left_interpolant() || + is_right_interpolant(); + } + + void Binary_Expression::set_delayed(bool delayed) + { + right()->set_delayed(delayed); + left()->set_delayed(delayed); + is_delayed(delayed); + } + + bool Binary_Expression::operator==(const Expression& rhs) const + { + try + { + Binary_Expression_Ptr_Const m = Cast(&rhs); + if (m == 0) return false; + return type() == m->type() && + *left() == *m->left() && + *right() == *m->right(); + } + catch (std::bad_cast&) + { + return false; + } + catch (...) { throw; } + } + + size_t Binary_Expression::hash() const + { + if (hash_ == 0) { + hash_ = std::hash()(optype()); + hash_combine(hash_, left()->hash()); + hash_combine(hash_, right()->hash()); + } + return hash_; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Function::Function(ParserState pstate, Definition_Obj def, bool css) + : Value(pstate), definition_(def), is_css_(css) + { concrete_type(FUNCTION_VAL); } + + Function::Function(const Function* ptr) + : Value(ptr), definition_(ptr->definition_), is_css_(ptr->is_css_) + { concrete_type(FUNCTION_VAL); } + + bool Function::operator== (const Expression& rhs) const + { + if (Function_Ptr_Const r = Cast(&rhs)) { + Definition_Ptr_Const d1 = Cast(definition()); + Definition_Ptr_Const d2 = Cast(r->definition()); + return d1 && d2 && d1 == d2 && is_css() == r->is_css(); + } + return false; + } + + std::string Function::name() { + if (definition_) { + return definition_->name(); + } + return ""; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Function_Call::Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args, void* cookie) + : PreValue(pstate), sname_(n), arguments_(args), func_(), via_call_(false), cookie_(cookie), hash_(0) + { concrete_type(FUNCTION); } + Function_Call::Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args, Function_Obj func) + : PreValue(pstate), sname_(n), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0) + { concrete_type(FUNCTION); } + Function_Call::Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args) + : PreValue(pstate), sname_(n), arguments_(args), via_call_(false), cookie_(0), hash_(0) + { concrete_type(FUNCTION); } + + Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args, void* cookie) + : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), func_(), via_call_(false), cookie_(cookie), hash_(0) + { concrete_type(FUNCTION); } + Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args, Function_Obj func) + : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0) + { concrete_type(FUNCTION); } + Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args) + : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), via_call_(false), cookie_(0), hash_(0) + { concrete_type(FUNCTION); } + + Function_Call::Function_Call(const Function_Call* ptr) + : PreValue(ptr), + sname_(ptr->sname_), + arguments_(ptr->arguments_), + func_(ptr->func_), + via_call_(ptr->via_call_), + cookie_(ptr->cookie_), + hash_(ptr->hash_) + { concrete_type(FUNCTION); } + + bool Function_Call::operator==(const Expression& rhs) const + { + try + { + Function_Call_Ptr_Const m = Cast(&rhs); + if (!(m && *sname() == *m->sname())) return false; + if (!(m && arguments()->length() == m->arguments()->length())) return false; + for (size_t i =0, L = arguments()->length(); i < L; ++i) + if (!(*(*arguments())[i] == *(*m->arguments())[i])) return false; + return true; } + catch (std::bad_cast&) + { + return false; + } + catch (...) { throw; } } + size_t Function_Call::hash() const + { + if (hash_ == 0) { + hash_ = std::hash()(name()); + for (auto argument : arguments()->elements()) + hash_combine(hash_, argument->hash()); + } + return hash_; + } + + std::string Function_Call::name() const + { + return sname(); + } + + bool Function_Call::is_css() { + if (func_) return func_->is_css(); + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Variable::Variable(ParserState pstate, std::string n) + : PreValue(pstate), name_(n) + { concrete_type(VARIABLE); } + + Variable::Variable(const Variable* ptr) + : PreValue(ptr), name_(ptr->name_) + { concrete_type(VARIABLE); } + + bool Variable::operator==(const Expression& rhs) const + { + try + { + Variable_Ptr_Const e = Cast(&rhs); + return e && name() == e->name(); + } + catch (std::bad_cast&) + { + return false; + } + catch (...) { throw; } + } + + size_t Variable::hash() + { + return std::hash()(name()); + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + Number::Number(ParserState pstate, double val, std::string u, bool zero) : Value(pstate), Units(), @@ -68,6 +418,13 @@ namespace Sass { concrete_type(NUMBER); } + Number::Number(const Number* ptr) + : Value(ptr), + Units(ptr), + value_(ptr->value_), zero_(ptr->zero_), + hash_(ptr->hash_) + { concrete_type(NUMBER); } + // cancel out unnecessary units void Number::reduce() { @@ -81,20 +438,16 @@ namespace Sass { value_ *= this->Units::normalize(); } - bool Custom_Warning::operator== (const Expression& rhs) const - { - if (Custom_Warning_Ptr_Const r = Cast(&rhs)) { - return message() == r->message(); - } - return false; - } - - bool Custom_Error::operator== (const Expression& rhs) const + size_t Number::hash() const { - if (Custom_Error_Ptr_Const r = Cast(&rhs)) { - return message() == r->message(); + if (hash_ == 0) { + hash_ = std::hash()(value_); + for (const auto numerator : numerators) + hash_combine(hash_, std::hash()(numerator)); + for (const auto denominator : denominators) + hash_combine(hash_, std::hash()(denominator)); } - return false; + return hash_; } bool Number::operator== (const Expression& rhs) const @@ -139,30 +492,145 @@ namespace Sass { l.value() < r.value(); } - bool String_Quoted::operator== (const Expression& rhs) const + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Color::Color(ParserState pstate, double r, double g, double b, double a, const std::string disp) + : Value(pstate), r_(r), g_(g), b_(b), a_(a), disp_(disp), + hash_(0) + { concrete_type(COLOR); } + + Color::Color(const Color* ptr) + : Value(ptr), + r_(ptr->r_), + g_(ptr->g_), + b_(ptr->b_), + a_(ptr->a_), + disp_(ptr->disp_), + hash_(ptr->hash_) + { concrete_type(COLOR); } + + bool Color::operator== (const Expression& rhs) const { - if (String_Quoted_Ptr_Const qstr = Cast(&rhs)) { - return (value() == qstr->value()); - } else if (String_Constant_Ptr_Const cstr = Cast(&rhs)) { - return (value() == cstr->value()); + if (Color_Ptr_Const r = Cast(&rhs)) { + return r_ == r->r() && + g_ == r->g() && + b_ == r->b() && + a_ == r->a(); } return false; } - bool String_Constant::is_invisible() const { - return value_.empty() && quote_mark_ == 0; + size_t Color::hash() const + { + if (hash_ == 0) { + hash_ = std::hash()(a_); + hash_combine(hash_, std::hash()(r_)); + hash_combine(hash_, std::hash()(g_)); + hash_combine(hash_, std::hash()(b_)); + } + return hash_; } - bool String_Constant::operator== (const Expression& rhs) const + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Custom_Error::Custom_Error(ParserState pstate, std::string msg) + : Value(pstate), message_(msg) + { concrete_type(C_ERROR); } + + Custom_Error::Custom_Error(const Custom_Error* ptr) + : Value(ptr), message_(ptr->message_) + { concrete_type(C_ERROR); } + + bool Custom_Error::operator== (const Expression& rhs) const { - if (String_Quoted_Ptr_Const qstr = Cast(&rhs)) { - return (value() == qstr->value()); - } else if (String_Constant_Ptr_Const cstr = Cast(&rhs)) { - return (value() == cstr->value()); + if (Custom_Error_Ptr_Const r = Cast(&rhs)) { + return message() == r->message(); + } + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Custom_Warning::Custom_Warning(ParserState pstate, std::string msg) + : Value(pstate), message_(msg) + { concrete_type(C_WARNING); } + + Custom_Warning::Custom_Warning(const Custom_Warning* ptr) + : Value(ptr), message_(ptr->message_) + { concrete_type(C_WARNING); } + + bool Custom_Warning::operator== (const Expression& rhs) const + { + if (Custom_Warning_Ptr_Const r = Cast(&rhs)) { + return message() == r->message(); + } + return false; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + Boolean::Boolean(ParserState pstate, bool val) + : Value(pstate), value_(val), + hash_(0) + { concrete_type(BOOLEAN); } + + Boolean::Boolean(const Boolean* ptr) + : Value(ptr), + value_(ptr->value_), + hash_(ptr->hash_) + { concrete_type(BOOLEAN); } + + bool Boolean::operator== (const Expression& rhs) const + { + if (Boolean_Ptr_Const r = Cast(&rhs)) { + return (value() == r->value()); } return false; } + size_t Boolean::hash() const + { + if (hash_ == 0) { + hash_ = std::hash()(value_); + } + return hash_; + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + String::String(ParserState pstate, bool delayed) + : Value(pstate, delayed) + { concrete_type(STRING); } + String::String(const String* ptr) + : Value(ptr) + { concrete_type(STRING); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + String_Schema::String_Schema(ParserState pstate, size_t size, bool css) + : String(pstate), Vectorized(size), css_(css), hash_(0) + { concrete_type(STRING); } + + String_Schema::String_Schema(const String_Schema* ptr) + : String(ptr), + Vectorized(*ptr), + css_(ptr->css_), + hash_(ptr->hash_) + { concrete_type(STRING); } + + void String_Schema::rtrim() + { + if (!empty()) { + if (String_Ptr str = Cast(last())) str->rtrim(); + } + } + bool String_Schema::is_left_interpolant(void) const { return length() && first()->is_left_interpolant(); @@ -187,148 +655,150 @@ namespace Sass { return false; } - bool Boolean::operator== (const Expression& rhs) const + bool String_Schema::has_interpolants() { - if (Boolean_Ptr_Const r = Cast(&rhs)) { - return (value() == r->value()); + for (auto el : elements()) { + if (el->is_interpolant()) return true; } return false; } - bool Color::operator== (const Expression& rhs) const + size_t String_Schema::hash() const { - if (Color_Ptr_Const r = Cast(&rhs)) { - return r_ == r->r() && - g_ == r->g() && - b_ == r->b() && - a_ == r->a(); + if (hash_ == 0) { + for (auto string : elements()) + hash_combine(hash_, string->hash()); } - return false; + return hash_; } - bool List::operator== (const Expression& rhs) const + void String_Schema::set_delayed(bool delayed) { - if (List_Ptr_Const r = Cast(&rhs)) { - if (length() != r->length()) return false; - if (separator() != r->separator()) return false; - if (is_bracketed() != r->is_bracketed()) return false; - for (size_t i = 0, L = length(); i < L; ++i) { - Expression_Obj rv = r->at(i); - Expression_Obj lv = this->at(i); - if (!lv || !rv) return false; - if (!(*lv == *rv)) return false; - } - return true; - } - return false; + is_delayed(delayed); } - bool Map::operator== (const Expression& rhs) const + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + String_Constant::String_Constant(ParserState pstate, std::string val, bool css) + : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(val, css)), hash_(0) + { } + String_Constant::String_Constant(ParserState pstate, const char* beg, bool css) + : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg), css)), hash_(0) + { } + String_Constant::String_Constant(ParserState pstate, const char* beg, const char* end, bool css) + : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg, end-beg), css)), hash_(0) + { } + String_Constant::String_Constant(ParserState pstate, const Token& tok, bool css) + : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(tok.begin, tok.end), css)), hash_(0) + { } + + String_Constant::String_Constant(const String_Constant* ptr) + : String(ptr), + quote_mark_(ptr->quote_mark_), + can_compress_whitespace_(ptr->can_compress_whitespace_), + value_(ptr->value_), + hash_(ptr->hash_) + { } + + bool String_Constant::is_invisible() const { + return value_.empty() && quote_mark_ == 0; + } + + bool String_Constant::operator== (const Expression& rhs) const { - if (Map_Ptr_Const r = Cast(&rhs)) { - if (length() != r->length()) return false; - for (auto key : keys()) { - Expression_Obj lv = at(key); - Expression_Obj rv = r->at(key); - if (!rv || !lv) return false; - if (!(*lv == *rv)) return false; - } - return true; + if (String_Quoted_Ptr_Const qstr = Cast(&rhs)) { + return (value() == qstr->value()); + } else if (String_Constant_Ptr_Const cstr = Cast(&rhs)) { + return (value() == cstr->value()); } return false; } - bool Null::operator== (const Expression& rhs) const + std::string String_Constant::inspect() const { - return rhs.concrete_type() == NULL_VAL; + return quote(value_, '*'); } - bool Function::operator== (const Expression& rhs) const + void String_Constant::rtrim() { - if (Function_Ptr_Const r = Cast(&rhs)) { - Definition_Ptr_Const d1 = Cast(definition()); - Definition_Ptr_Const d2 = Cast(r->definition()); - return d1 && d2 && d1 == d2 && is_css() == r->is_css(); + str_rtrim(value_); + } + + size_t String_Constant::hash() const + { + if (hash_ == 0) { + hash_ = std::hash()(value_); } - return false; + return hash_; } - size_t List::size() const { - if (!is_arglist_) return length(); - // arglist expects a list of arguments - // so we need to break before keywords - for (size_t i = 0, L = length(); i < L; ++i) { - Expression_Obj obj = this->at(i); - if (Argument_Ptr arg = Cast(obj)) { - if (!arg->name().empty()) return i; - } + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + String_Quoted::String_Quoted(ParserState pstate, std::string val, char q, + bool keep_utf8_escapes, bool skip_unquoting, + bool strict_unquoting, bool css) + : String_Constant(pstate, val, css) + { + if (skip_unquoting == false) { + value_ = unquote(value_, "e_mark_, keep_utf8_escapes, strict_unquoting); } - return length(); + if (q && quote_mark_) quote_mark_ = q; } - std::string String_Quoted::inspect() const + String_Quoted::String_Quoted(const String_Quoted* ptr) + : String_Constant(ptr) + { } + + bool String_Quoted::operator== (const Expression& rhs) const { - return quote(value_, '*'); + if (String_Quoted_Ptr_Const qstr = Cast(&rhs)) { + return (value() == qstr->value()); + } else if (String_Constant_Ptr_Const cstr = Cast(&rhs)) { + return (value() == cstr->value()); + } + return false; } - std::string String_Constant::inspect() const + std::string String_Quoted::inspect() const { return quote(value_, '*'); } - Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args, void* cookie) - : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), func_(), via_call_(false), cookie_(cookie), hash_(0) - { concrete_type(FUNCTION); } - Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args, Function_Obj func) - : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0) - { concrete_type(FUNCTION); } - Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args) - : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), via_call_(false), cookie_(0), hash_(0) - { concrete_type(FUNCTION); } + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// - bool Function_Call::operator==(const Expression& rhs) const + Null::Null(ParserState pstate) + : Value(pstate) + { concrete_type(NULL_VAL); } + + Null::Null(const Null* ptr) : Value(ptr) + { concrete_type(NULL_VAL); } + + bool Null::operator== (const Expression& rhs) const { - try - { - Function_Call_Ptr_Const m = Cast(&rhs); - if (!(m && *sname() == *m->sname())) return false; - if (!(m && arguments()->length() == m->arguments()->length())) return false; - for (size_t i =0, L = arguments()->length(); i < L; ++i) - if (!(*(*arguments())[i] == *(*m->arguments())[i])) return false; - return true; - } - catch (std::bad_cast&) - { - return false; - } - catch (...) { throw; } + return rhs.concrete_type() == NULL_VAL; } - size_t Function_Call::hash() const + size_t Null::hash() const { - if (hash_ == 0) { - hash_ = std::hash()(name()); - for (auto argument : arguments()->elements()) - hash_combine(hash_, argument->hash()); - } - return hash_; + return -1; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Convert map to (key, value) list. - ////////////////////////////////////////////////////////////////////////////////////////// - List_Obj Map::to_list(ParserState& pstate) { - List_Obj ret = SASS_MEMORY_NEW(List, pstate, length(), SASS_COMMA); + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// - for (auto key : keys()) { - List_Obj l = SASS_MEMORY_NEW(List, pstate, 2); - l->append(key); - l->append(at(key)); - ret->append(l); - } + Parent_Reference::Parent_Reference(ParserState pstate) + : Value(pstate) + { concrete_type(PARENT); } - return ret; - } + Parent_Reference::Parent_Reference(const Parent_Reference* ptr) + : Value(ptr) + { concrete_type(PARENT); } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// IMPLEMENT_AST_OPERATORS(List); IMPLEMENT_AST_OPERATORS(Map); @@ -347,4 +817,7 @@ namespace Sass { IMPLEMENT_AST_OPERATORS(Null); IMPLEMENT_AST_OPERATORS(Parent_Reference); + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + } \ No newline at end of file diff --git a/src/ast_values.hpp b/src/ast_values.hpp index 2c029a268..b3661faee 100644 --- a/src/ast_values.hpp +++ b/src/ast_values.hpp @@ -38,13 +38,8 @@ namespace Sass { ////////////////////////////////////////////////////////////////////// class PreValue : public Expression { public: - PreValue(ParserState pstate, - bool d = false, bool e = false, bool i = false, Type ct = NONE) - : Expression(pstate, d, e, i, ct) - { } - PreValue(const PreValue* ptr) - : Expression(ptr) - { } + PreValue(ParserState pstate, bool d = false, bool e = false, bool i = false, Type ct = NONE); + PreValue(const PreValue* ptr); ATTACH_VIRTUAL_AST_OPERATIONS(PreValue); virtual ~PreValue() { } }; @@ -54,13 +49,8 @@ namespace Sass { ////////////////////////////////////////////////////////////////////// class Value : public PreValue { public: - Value(ParserState pstate, - bool d = false, bool e = false, bool i = false, Type ct = NONE) - : PreValue(pstate, d, e, i, ct) - { } - Value(const Value* ptr) - : PreValue(ptr) - { } + Value(ParserState pstate, bool d = false, bool e = false, bool i = false, Type ct = NONE); + Value(const Value* ptr); ATTACH_VIRTUAL_AST_OPERATIONS(Value); virtual bool operator== (const Expression& rhs) const override = 0; }; @@ -77,23 +67,7 @@ namespace Sass { ADD_PROPERTY(bool, is_bracketed) ADD_PROPERTY(bool, from_selector) public: - List(ParserState pstate, - size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false, bool bracket = false) - : Value(pstate), - Vectorized(size), - separator_(sep), - is_arglist_(argl), - is_bracketed_(bracket), - from_selector_(false) - { concrete_type(LIST); } - List(const List* ptr) - : Value(ptr), - Vectorized(*ptr), - separator_(ptr->separator_), - is_arglist_(ptr->is_arglist_), - is_bracketed_(ptr->is_bracketed_), - from_selector_(ptr->from_selector_) - { concrete_type(LIST); } + List(ParserState pstate, size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false, bool bracket = false); std::string type() const override { return is_arglist_ ? "arglist" : "list"; } static std::string type_name() { return "list"; } const char* sep_string(bool compressed = false) const { @@ -103,25 +77,9 @@ namespace Sass { bool is_invisible() const override { return empty() && !is_bracketed(); } Expression_Obj value_at_index(size_t i); + virtual size_t hash() const override; virtual size_t size() const; - - virtual size_t hash() const override - { - if (hash_ == 0) { - hash_ = std::hash()(sep_string()); - hash_combine(hash_, std::hash()(is_bracketed())); - for (size_t i = 0, L = length(); i < L; ++i) - hash_combine(hash_, (elements()[i])->hash()); - } - return hash_; - } - - virtual void set_delayed(bool delayed) override - { - is_delayed(delayed); - // don't set children - } - + virtual void set_delayed(bool delayed); virtual bool operator== (const Expression& rhs) const override; ATTACH_AST_OPERATIONS(List) @@ -134,32 +92,13 @@ namespace Sass { class Map : public Value, public Hashed { void adjust_after_pushing(std::pair p) override { is_expanded(false); } public: - Map(ParserState pstate, - size_t size = 0) - : Value(pstate), - Hashed(size) - { concrete_type(MAP); } - Map(const Map* ptr) - : Value(ptr), - Hashed(*ptr) - { concrete_type(MAP); } + Map(ParserState pstate, size_t size = 0); std::string type() const override { return "map"; } static std::string type_name() { return "map"; } bool is_invisible() const override { return empty(); } List_Obj to_list(ParserState& pstate); - virtual size_t hash() const override - { - if (hash_ == 0) { - for (auto key : keys()) { - hash_combine(hash_, key->hash()); - hash_combine(hash_, at(key)->hash()); - } - } - - return hash_; - } - + virtual size_t hash() const override; virtual bool operator== (const Expression& rhs) const override; ATTACH_AST_OPERATIONS(Map) @@ -180,60 +119,19 @@ namespace Sass { mutable size_t hash_; public: Binary_Expression(ParserState pstate, - Operand op, Expression_Obj lhs, Expression_Obj rhs) - : PreValue(pstate), op_(op), left_(lhs), right_(rhs), hash_(0) - { } - Binary_Expression(const Binary_Expression* ptr) - : PreValue(ptr), - op_(ptr->op_), - left_(ptr->left_), - right_(ptr->right_), - hash_(ptr->hash_) - { } - const std::string type_name() { - return sass_op_to_name(optype()); - } - const std::string separator() { - return sass_op_separator(optype()); - } + Operand op, Expression_Obj lhs, Expression_Obj rhs); + + const std::string type_name(); + const std::string separator(); bool is_left_interpolant(void) const override; bool is_right_interpolant(void) const override; - bool has_interpolant() const override - { - return is_left_interpolant() || - is_right_interpolant(); - } - virtual void set_delayed(bool delayed) override - { - right()->set_delayed(delayed); - left()->set_delayed(delayed); - is_delayed(delayed); - } - virtual bool operator==(const Expression& rhs) const override - { - try - { - Binary_Expression_Ptr_Const m = Cast(&rhs); - if (m == 0) return false; - return type() == m->type() && - *left() == *m->left() && - *right() == *m->right(); - } - catch (std::bad_cast&) - { - return false; - } - catch (...) { throw; } - } - virtual size_t hash() const override - { - if (hash_ == 0) { - hash_ = std::hash()(optype()); - hash_combine(hash_, left()->hash()); - hash_combine(hash_, right()->hash()); - } - return hash_; - } + bool has_interpolant() const override; + + virtual void set_delayed(bool delayed) override; + + virtual bool operator==(const Expression& rhs) const override; + + virtual size_t hash() const; enum Sass_OP optype() const { return op_.operand; } ATTACH_AST_OPERATIONS(Binary_Expression) ATTACH_CRTP_PERFORM_METHODS() @@ -247,23 +145,13 @@ namespace Sass { ADD_PROPERTY(Definition_Obj, definition) ADD_PROPERTY(bool, is_css) public: - Function(ParserState pstate, Definition_Obj def, bool css) - : Value(pstate), definition_(def), is_css_(css) - { concrete_type(FUNCTION_VAL); } - Function(const Function* ptr) - : Value(ptr), definition_(ptr->definition_), is_css_(ptr->is_css_) - { concrete_type(FUNCTION_VAL); } + Function(ParserState pstate, Definition_Obj def, bool css); std::string type() const override { return "function"; } static std::string type_name() { return "function"; } bool is_invisible() const override { return true; } - std::string name() { - if (definition_) { - return definition_->name(); - } - return ""; - } + std::string name(); bool operator== (const Expression& rhs) const override; @@ -286,34 +174,12 @@ namespace Sass { Function_Call(ParserState pstate, std::string n, Arguments_Obj args, Function_Obj func); Function_Call(ParserState pstate, std::string n, Arguments_Obj args); - Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args, void* cookie) - : PreValue(pstate), sname_(n), arguments_(args), func_(), via_call_(false), cookie_(cookie), hash_(0) - { concrete_type(FUNCTION); } - Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args, Function_Obj func) - : PreValue(pstate), sname_(n), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0) - { concrete_type(FUNCTION); } - Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args) - : PreValue(pstate), sname_(n), arguments_(args), via_call_(false), cookie_(0), hash_(0) - { concrete_type(FUNCTION); } - - std::string name() const { - return sname(); - } + Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args, void* cookie); + Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args, Function_Obj func); + Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args); - Function_Call(const Function_Call* ptr) - : PreValue(ptr), - sname_(ptr->sname_), - arguments_(ptr->arguments_), - func_(ptr->func_), - via_call_(ptr->via_call_), - cookie_(ptr->cookie_), - hash_(ptr->hash_) - { concrete_type(FUNCTION); } - - bool is_css() { - if (func_) return func_->is_css(); - return false; - } + std::string name() const; + bool is_css(); bool operator==(const Expression& rhs) const override; @@ -329,32 +195,9 @@ namespace Sass { class Variable final : public PreValue { ADD_CONSTREF(std::string, name) public: - Variable(ParserState pstate, std::string n) - : PreValue(pstate), name_(n) - { concrete_type(VARIABLE); } - Variable(const Variable* ptr) - : PreValue(ptr), name_(ptr->name_) - { concrete_type(VARIABLE); } - - bool operator==(const Expression& rhs) const override - { - try - { - Variable_Ptr_Const e = Cast(&rhs); - return e && name() == e->name(); - } - catch (std::bad_cast&) - { - return false; - } - catch (...) { throw; } - } - - size_t hash() const override - { - return std::hash()(name()); - } - + Variable(ParserState pstate, std::string n); + virtual bool operator==(const Expression& rhs) const; + virtual size_t hash(); ATTACH_AST_OPERATIONS(Variable) ATTACH_CRTP_PERFORM_METHODS() }; @@ -369,31 +212,20 @@ namespace Sass { public: Number(ParserState pstate, double val, std::string u = "", bool zero = true); - Number(const Number* ptr) - : Value(ptr), - Units(ptr), - value_(ptr->value_), zero_(ptr->zero_), - hash_(ptr->hash_) - { concrete_type(NUMBER); } - bool zero() { return zero_; } + std::string type() const override { return "number"; } static std::string type_name() { return "number"; } + // cancel out unnecessary units + // result will be in input units void reduce(); + + // normalize units to defaults + // needed to compare two numbers void normalize(); - size_t hash() const override - { - if (hash_ == 0) { - hash_ = std::hash()(value_); - for (const auto numerator : numerators) - hash_combine(hash_, std::hash()(numerator)); - for (const auto denominator : denominators) - hash_combine(hash_, std::hash()(denominator)); - } - return hash_; - } + size_t hash() const override; bool operator< (const Number& rhs) const; bool operator== (const Number& rhs) const; @@ -413,32 +245,12 @@ namespace Sass { ADD_CONSTREF(std::string, disp) mutable size_t hash_; public: - Color(ParserState pstate, double r, double g, double b, double a = 1, const std::string disp = "") - : Value(pstate), r_(r), g_(g), b_(b), a_(a), disp_(disp), - hash_(0) - { concrete_type(COLOR); } - Color(const Color* ptr) - : Value(ptr), - r_(ptr->r_), - g_(ptr->g_), - b_(ptr->b_), - a_(ptr->a_), - disp_(ptr->disp_), - hash_(ptr->hash_) - { concrete_type(COLOR); } + Color(ParserState pstate, double r, double g, double b, double a = 1, const std::string disp = ""); + std::string type() const override { return "color"; } static std::string type_name() { return "color"; } - size_t hash() const override - { - if (hash_ == 0) { - hash_ = std::hash()(a_); - hash_combine(hash_, std::hash()(r_)); - hash_combine(hash_, std::hash()(g_)); - hash_combine(hash_, std::hash()(b_)); - } - return hash_; - } + size_t hash() const override; bool operator== (const Expression& rhs) const override; @@ -452,12 +264,7 @@ namespace Sass { class Custom_Error final : public Value { ADD_CONSTREF(std::string, message) public: - Custom_Error(ParserState pstate, std::string msg) - : Value(pstate), message_(msg) - { concrete_type(C_ERROR); } - Custom_Error(const Custom_Error* ptr) - : Value(ptr), message_(ptr->message_) - { concrete_type(C_ERROR); } + Custom_Error(ParserState pstate, std::string msg); bool operator== (const Expression& rhs) const override; ATTACH_AST_OPERATIONS(Custom_Error) ATTACH_CRTP_PERFORM_METHODS() @@ -469,12 +276,7 @@ namespace Sass { class Custom_Warning final : public Value { ADD_CONSTREF(std::string, message) public: - Custom_Warning(ParserState pstate, std::string msg) - : Value(pstate), message_(msg) - { concrete_type(C_WARNING); } - Custom_Warning(const Custom_Warning* ptr) - : Value(ptr), message_(ptr->message_) - { concrete_type(C_WARNING); } + Custom_Warning(ParserState pstate, std::string msg); bool operator== (const Expression& rhs) const override; ATTACH_AST_OPERATIONS(Custom_Warning) ATTACH_CRTP_PERFORM_METHODS() @@ -487,27 +289,15 @@ namespace Sass { HASH_PROPERTY(bool, value) mutable size_t hash_; public: - Boolean(ParserState pstate, bool val) - : Value(pstate), value_(val), - hash_(0) - { concrete_type(BOOLEAN); } - Boolean(const Boolean* ptr) - : Value(ptr), - value_(ptr->value_), - hash_(ptr->hash_) - { concrete_type(BOOLEAN); } + Boolean(ParserState pstate, bool val); operator bool() override { return value_; } - std::string type() const override { return "bool"; } + + std::string type() const { return "bool"; } static std::string type_name() { return "bool"; } - bool is_false() override { return !value_; } - size_t hash() const override - { - if (hash_ == 0) { - hash_ = std::hash()(value_); - } - return hash_; - } + size_t hash() const override; + + bool is_false() override { return !value_; } bool operator== (const Expression& rhs) const override; @@ -521,12 +311,8 @@ namespace Sass { //////////////////////////////////////////////////////////////////////// class String : public Value { public: - String(ParserState pstate, bool delayed = false) - : Value(pstate, delayed) - { concrete_type(STRING); } - String(const String* ptr) - : Value(ptr) - { concrete_type(STRING); } + String(ParserState pstate, bool delayed = false); + String(const String* ptr); static std::string type_name() { return "string"; } virtual ~String() = 0; virtual void rtrim() = 0; @@ -546,42 +332,18 @@ namespace Sass { ADD_PROPERTY(bool, css) mutable size_t hash_; public: - String_Schema(ParserState pstate, size_t size = 0, bool css = true) - : String(pstate), Vectorized(size), css_(css), hash_(0) - { concrete_type(STRING); } - String_Schema(const String_Schema* ptr) - : String(ptr), - Vectorized(*ptr), - css_(ptr->css_), - hash_(ptr->hash_) - { concrete_type(STRING); } + String_Schema(ParserState pstate, size_t size = 0, bool css = true); std::string type() const override { return "string"; } static std::string type_name() { return "string"; } bool is_left_interpolant(void) const override; bool is_right_interpolant(void) const override; - // void has_interpolants(bool tc) { } - bool has_interpolants() { - for (auto el : elements()) { - if (el->is_interpolant()) return true; - } - return false; - } - void rtrim() override; - size_t hash() const override - { - if (hash_ == 0) { - for (const auto &str : elements()) - hash_combine(hash_, str->hash()); - } - return hash_; - } - - void set_delayed(bool delayed) override { - is_delayed(delayed); - } + bool has_interpolants(); + void rtrim() override; + size_t hash() const override; + virtual void set_delayed(bool delayed); bool operator==(const Expression& rhs) const override; ATTACH_AST_OPERATIONS(String_Schema) @@ -598,45 +360,18 @@ namespace Sass { protected: mutable size_t hash_; public: - String_Constant(const String_Constant* ptr) - : String(ptr), - quote_mark_(ptr->quote_mark_), - can_compress_whitespace_(ptr->can_compress_whitespace_), - value_(ptr->value_), - hash_(ptr->hash_) - { } - String_Constant(ParserState pstate, std::string val, bool css = true) - : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(val, css)), hash_(0) - { } - String_Constant(ParserState pstate, const char* beg, bool css = true) - : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg), css)), hash_(0) - { } - String_Constant(ParserState pstate, const char* beg, const char* end, bool css = true) - : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg, end-beg), css)), hash_(0) - { } - String_Constant(ParserState pstate, const Token& tok, bool css = true) - : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(tok.begin, tok.end), css)), hash_(0) - { } + String_Constant(ParserState pstate, std::string val, bool css = true); + String_Constant(ParserState pstate, const char* beg, bool css = true); + String_Constant(ParserState pstate, const char* beg, const char* end, bool css = true); + String_Constant(ParserState pstate, const Token& tok, bool css = true); std::string type() const override { return "string"; } static std::string type_name() { return "string"; } bool is_invisible() const override; virtual void rtrim() override; - - size_t hash() const override - { - if (hash_ == 0) { - hash_ = std::hash()(value_); - } - return hash_; - } - + size_t hash() const override; bool operator==(const Expression& rhs) const override; - virtual std::string inspect() const override; // quotes are forced on inspection - - // static char auto_quote() { return '*'; } - static char double_quote() { return '"'; } - static char single_quote() { return '\''; } - + // quotes are forced on inspection + virtual std::string inspect() const override; ATTACH_AST_OPERATIONS(String_Constant) ATTACH_CRTP_PERFORM_METHODS() }; @@ -648,19 +383,10 @@ namespace Sass { public: String_Quoted(ParserState pstate, std::string val, char q = 0, bool keep_utf8_escapes = false, bool skip_unquoting = false, - bool strict_unquoting = true, bool css = true) - : String_Constant(pstate, val, css) - { - if (skip_unquoting == false) { - value_ = unquote(value_, "e_mark_, keep_utf8_escapes, strict_unquoting); - } - if (q && quote_mark_) quote_mark_ = q; - } - String_Quoted(const String_Quoted* ptr) - : String_Constant(ptr) - { } + bool strict_unquoting = true, bool css = true); bool operator==(const Expression& rhs) const override; - std::string inspect() const override; // quotes are forced on inspection + // quotes are forced on inspection + std::string inspect() const override; ATTACH_AST_OPERATIONS(String_Quoted) ATTACH_CRTP_PERFORM_METHODS() }; @@ -670,18 +396,14 @@ namespace Sass { ////////////////// class Null final : public Value { public: - Null(ParserState pstate) : Value(pstate) { concrete_type(NULL_VAL); } - Null(const Null* ptr) : Value(ptr) { concrete_type(NULL_VAL); } + Null(ParserState pstate); std::string type() const override { return "null"; } static std::string type_name() { return "null"; } bool is_invisible() const override { return true; } operator bool() override { return false; } bool is_false() override { return true; } - size_t hash() const override - { - return -1; - } + size_t hash() const override; bool operator== (const Expression& rhs) const override; @@ -694,10 +416,7 @@ namespace Sass { ////////////////////////////////// class Parent_Reference final : public Value { public: - Parent_Reference(ParserState pstate) - : Value(pstate) {} - Parent_Reference(const Parent_Reference* ptr) - : Value(ptr) {} + Parent_Reference(ParserState pstate); std::string type() const override { return "parent"; } static std::string type_name() { return "parent"; } bool operator==(const Expression& rhs) const override { diff --git a/src/debugger.hpp b/src/debugger.hpp index ec774bcda..dfad6817a 100644 --- a/src/debugger.hpp +++ b/src/debugger.hpp @@ -126,7 +126,7 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) // if (selector->not_selector()) cerr << " [in_declaration]"; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; - std::cerr << " [" << (selector->is_real_parent_ref() ? "REAL" : "FAKE") << "]"; + std::cerr << " [" << (selector->real() ? "REAL" : "FAKE") << "]"; std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; // debug_ast(selector->selector(), ind + "->", env); diff --git a/src/fn_strings.cpp b/src/fn_strings.cpp index 16ed74b34..780e7d8e6 100644 --- a/src/fn_strings.cpp +++ b/src/fn_strings.cpp @@ -69,7 +69,7 @@ namespace Sass { return qstr; } // all other nodes must be converted to a string node - std::string str(quote(arg->to_string(ctx.c_options), String_Constant::double_quote())); + std::string str(quote(arg->to_string(ctx.c_options), '"')); String_Quoted_Ptr result = SASS_MEMORY_NEW(String_Quoted, pstate, str); result->quote_mark('*'); return result; diff --git a/src/inspect.cpp b/src/inspect.cpp index 2fb04a78c..1cfeba2e3 100644 --- a/src/inspect.cpp +++ b/src/inspect.cpp @@ -913,7 +913,7 @@ namespace Sass { void Inspect::operator()(Parent_Selector_Ptr p) { - if (p->is_real_parent_ref()) append_string("&"); + if (p->real()) append_string("&"); } void Inspect::operator()(Placeholder_Selector_Ptr s)