Blame src/ast.hpp

Packit bfcc33
#ifndef SASS_AST_H
Packit bfcc33
#define SASS_AST_H
Packit bfcc33
Packit bfcc33
#include "sass.hpp"
Packit bfcc33
#include <set>
Packit bfcc33
#include <deque>
Packit bfcc33
#include <vector>
Packit bfcc33
#include <string>
Packit bfcc33
#include <sstream>
Packit bfcc33
#include <iostream>
Packit bfcc33
#include <typeinfo>
Packit bfcc33
#include <algorithm>
Packit bfcc33
#include "sass/base.h"
Packit bfcc33
#include "ast_fwd_decl.hpp"
Packit bfcc33
Packit bfcc33
#ifdef DEBUG_SHARED_PTR
Packit bfcc33
Packit bfcc33
#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \
Packit bfcc33
  virtual klass##_Ptr copy(std::string, size_t) const = 0; \
Packit bfcc33
  virtual klass##_Ptr clone(std::string, size_t) const = 0; \
Packit bfcc33
Packit bfcc33
#define ATTACH_AST_OPERATIONS(klass) \
Packit bfcc33
  virtual klass##_Ptr copy(std::string, size_t) const; \
Packit bfcc33
  virtual klass##_Ptr clone(std::string, size_t) const; \
Packit bfcc33
Packit bfcc33
#else
Packit bfcc33
Packit bfcc33
#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \
Packit bfcc33
  virtual klass##_Ptr copy() const = 0; \
Packit bfcc33
  virtual klass##_Ptr clone() const = 0; \
Packit bfcc33
Packit bfcc33
#define ATTACH_AST_OPERATIONS(klass) \
Packit bfcc33
  virtual klass##_Ptr copy() const; \
Packit bfcc33
  virtual klass##_Ptr clone() const; \
Packit bfcc33
Packit bfcc33
#endif
Packit bfcc33
Packit bfcc33
#ifdef __clang__
Packit bfcc33
Packit bfcc33
/*
Packit bfcc33
 * There are some overloads used here that trigger the clang overload
Packit bfcc33
 * hiding warning. Specifically:
Packit bfcc33
 *
Packit bfcc33
 * Type type() which hides string type() from Expression
Packit bfcc33
 *
Packit bfcc33
 */
Packit bfcc33
#pragma clang diagnostic push
Packit bfcc33
#pragma clang diagnostic ignored "-Woverloaded-virtual"
Packit bfcc33
Packit bfcc33
#endif
Packit bfcc33
Packit bfcc33
#include "util.hpp"
Packit bfcc33
#include "units.hpp"
Packit bfcc33
#include "context.hpp"
Packit bfcc33
#include "position.hpp"
Packit bfcc33
#include "constants.hpp"
Packit bfcc33
#include "operation.hpp"
Packit bfcc33
#include "position.hpp"
Packit bfcc33
#include "inspect.hpp"
Packit bfcc33
#include "source_map.hpp"
Packit bfcc33
#include "environment.hpp"
Packit bfcc33
#include "error_handling.hpp"
Packit bfcc33
#include "ast_def_macros.hpp"
Packit bfcc33
#include "ast_fwd_decl.hpp"
Packit bfcc33
#include "source_map.hpp"
Packit bfcc33
Packit bfcc33
#include "sass.h"
Packit bfcc33
Packit bfcc33
namespace Sass {
Packit bfcc33
Packit bfcc33
  // easier to search with name
Packit bfcc33
  const bool DELAYED = true;
Packit bfcc33
Packit bfcc33
  // ToDo: should this really be hardcoded
Packit bfcc33
  // Note: most methods follow precision option
Packit bfcc33
  const double NUMBER_EPSILON = 0.00000000000001;
Packit bfcc33
Packit bfcc33
  // ToDo: where does this fit best?
Packit bfcc33
  // We don't share this with C-API?
Packit bfcc33
  class Operand {
Packit bfcc33
    public:
Packit bfcc33
      Operand(Sass_OP operand, bool ws_before = false, bool ws_after = false)
Packit bfcc33
      : operand(operand), ws_before(ws_before), ws_after(ws_after)
Packit bfcc33
      { }
Packit bfcc33
    public:
Packit bfcc33
      enum Sass_OP operand;
Packit bfcc33
      bool ws_before;
Packit bfcc33
      bool ws_after;
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////////
Packit bfcc33
  // `hash_combine` comes from boost (functional/hash):
Packit bfcc33
  // http://www.boost.org/doc/libs/1_35_0/doc/html/hash/combine.html
Packit bfcc33
  // Boost Software License - Version 1.0
Packit bfcc33
  // http://www.boost.org/users/license.html
Packit bfcc33
  template <typename T>
Packit bfcc33
  void hash_combine (std::size_t& seed, const T& val)
Packit bfcc33
  {
Packit bfcc33
    seed ^= std::hash<T>()(val) + 0x9e3779b9
Packit bfcc33
             + (seed<<6) + (seed>>2);
Packit bfcc33
  }
Packit bfcc33
  //////////////////////////////////////////////////////////
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////////
Packit bfcc33
  // Abstract base class for all abstract syntax tree nodes.
Packit bfcc33
  //////////////////////////////////////////////////////////
Packit bfcc33
  class AST_Node : public SharedObj {
Packit bfcc33
    ADD_PROPERTY(ParserState, pstate)
Packit bfcc33
  public:
Packit bfcc33
    AST_Node(ParserState pstate)
Packit bfcc33
    : pstate_(pstate)
Packit bfcc33
    { }
Packit bfcc33
    AST_Node(const AST_Node* ptr)
Packit bfcc33
    : pstate_(ptr->pstate_)
Packit bfcc33
    { }
Packit bfcc33
Packit bfcc33
    // AST_Node(AST_Node& ptr) = delete;
Packit bfcc33
Packit bfcc33
    virtual ~AST_Node() = 0;
Packit bfcc33
    virtual size_t hash() { return 0; }
Packit bfcc33
    ATTACH_VIRTUAL_AST_OPERATIONS(AST_Node);
Packit bfcc33
    virtual std::string inspect() const { return to_string({ INSPECT, 5 }); }
Packit bfcc33
    virtual std::string to_sass() const { return to_string({ TO_SASS, 5 }); }
Packit bfcc33
    virtual const std::string to_string(Sass_Inspect_Options opt) const;
Packit bfcc33
    virtual const std::string to_string() const;
Packit bfcc33
    virtual void cloneChildren() {};
Packit bfcc33
    // generic find function (not fully implemented yet)
Packit bfcc33
    // ToDo: add specific implementions to all children
Packit bfcc33
    virtual bool find ( bool (*f)(AST_Node_Obj) ) { return f(this); };
Packit bfcc33
  public:
Packit bfcc33
    void update_pstate(const ParserState& pstate);
Packit bfcc33
  public:
Packit bfcc33
    Offset off() { return pstate(); }
Packit bfcc33
    Position pos() { return pstate(); }
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
  inline AST_Node::~AST_Node() { }
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////////////////////
Packit bfcc33
  // define cast template now (need complete type)
Packit bfcc33
  //////////////////////////////////////////////////////////////////////
Packit bfcc33
Packit bfcc33
  template<class T>
Packit bfcc33
  T* Cast(AST_Node* ptr) {
Packit bfcc33
    return ptr && typeid(T) == typeid(*ptr) ?
Packit bfcc33
           static_cast<T*>(ptr) : NULL;
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  template<class T>
Packit bfcc33
  const T* Cast(const AST_Node* ptr) {
Packit bfcc33
    return ptr && typeid(T) == typeid(*ptr) ?
Packit bfcc33
           static_cast<const T*>(ptr) : NULL;
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Abstract base class for expressions. This side of the AST hierarchy
Packit bfcc33
  // represents elements in value contexts, which exist primarily to be
Packit bfcc33
  // evaluated and returned.
Packit bfcc33
  //////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Expression : public AST_Node {
Packit bfcc33
  public:
Packit bfcc33
    enum Concrete_Type {
Packit bfcc33
      NONE,
Packit bfcc33
      BOOLEAN,
Packit bfcc33
      NUMBER,
Packit bfcc33
      COLOR,
Packit bfcc33
      STRING,
Packit bfcc33
      LIST,
Packit bfcc33
      MAP,
Packit bfcc33
      SELECTOR,
Packit bfcc33
      NULL_VAL,
Packit bfcc33
      C_WARNING,
Packit bfcc33
      C_ERROR,
Packit bfcc33
      FUNCTION,
Packit bfcc33
      VARIABLE,
Packit bfcc33
      NUM_TYPES
Packit bfcc33
    };
Packit bfcc33
    enum Simple_Type {
Packit bfcc33
      SIMPLE,
Packit bfcc33
      ATTR_SEL,
Packit bfcc33
      PSEUDO_SEL,
Packit bfcc33
      WRAPPED_SEL,
Packit bfcc33
    };
Packit bfcc33
  private:
Packit bfcc33
    // expressions in some contexts shouldn't be evaluated
Packit bfcc33
    ADD_PROPERTY(bool, is_delayed)
Packit bfcc33
    ADD_PROPERTY(bool, is_expanded)
Packit bfcc33
    ADD_PROPERTY(bool, is_interpolant)
Packit bfcc33
    ADD_PROPERTY(Concrete_Type, concrete_type)
Packit bfcc33
  public:
Packit bfcc33
    Expression(ParserState pstate,
Packit bfcc33
               bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
Packit bfcc33
    : AST_Node(pstate),
Packit bfcc33
      is_delayed_(d),
Packit bfcc33
      is_expanded_(e),
Packit bfcc33
      is_interpolant_(i),
Packit bfcc33
      concrete_type_(ct)
Packit bfcc33
    { }
Packit bfcc33
    Expression(const Expression* ptr)
Packit bfcc33
    : AST_Node(ptr),
Packit bfcc33
      is_delayed_(ptr->is_delayed_),
Packit bfcc33
      is_expanded_(ptr->is_expanded_),
Packit bfcc33
      is_interpolant_(ptr->is_interpolant_),
Packit bfcc33
      concrete_type_(ptr->concrete_type_)
Packit bfcc33
    { }
Packit bfcc33
    virtual operator bool() { return true; }
Packit bfcc33
    virtual ~Expression() { }
Packit bfcc33
    virtual std::string type() const { return ""; /* TODO: raise an error? */ }
Packit bfcc33
    virtual bool is_invisible() const { return false; }
Packit bfcc33
    static std::string type_name() { return ""; }
Packit bfcc33
    virtual bool is_false() { return false; }
Packit bfcc33
    // virtual bool is_true() { return !is_false(); }
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const { return false; }
Packit bfcc33
    virtual bool eq(const Expression& rhs) const { return *this == rhs; };
Packit bfcc33
    virtual void set_delayed(bool delayed) { is_delayed(delayed); }
Packit bfcc33
    virtual bool has_interpolant() const { return is_interpolant(); }
Packit bfcc33
    virtual bool is_left_interpolant() const { return is_interpolant(); }
Packit bfcc33
    virtual bool is_right_interpolant() const { return is_interpolant(); }
Packit bfcc33
    virtual std::string inspect() const { return to_string({ INSPECT, 5 }); }
Packit bfcc33
    virtual std::string to_sass() const { return to_string({ TO_SASS, 5 }); }
Packit bfcc33
    ATTACH_VIRTUAL_AST_OPERATIONS(Expression);
Packit bfcc33
    virtual size_t hash() { return 0; }
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Still just an expression, but with a to_string method
Packit bfcc33
  //////////////////////////////////////////////////////////////////////
Packit bfcc33
  class PreValue : public Expression {
Packit bfcc33
  public:
Packit bfcc33
    PreValue(ParserState pstate,
Packit bfcc33
               bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
Packit bfcc33
    : Expression(pstate, d, e, i, ct)
Packit bfcc33
    { }
Packit bfcc33
    PreValue(const PreValue* ptr)
Packit bfcc33
    : Expression(ptr)
Packit bfcc33
    { }
Packit bfcc33
    ATTACH_VIRTUAL_AST_OPERATIONS(PreValue);
Packit bfcc33
    virtual ~PreValue() { }
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////////////////////
Packit bfcc33
  // base class for values that support operations
Packit bfcc33
  //////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Value : public Expression {
Packit bfcc33
  public:
Packit bfcc33
    Value(ParserState pstate,
Packit bfcc33
          bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
Packit bfcc33
    : Expression(pstate, d, e, i, ct)
Packit bfcc33
    { }
Packit bfcc33
    Value(const Value* ptr)
Packit bfcc33
    : Expression(ptr)
Packit bfcc33
    { }
Packit bfcc33
    ATTACH_VIRTUAL_AST_OPERATIONS(Value);
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const = 0;
Packit bfcc33
  };
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
/////////////////////////////////////////////////////////////////////////////////////
Packit bfcc33
// Hash method specializations for std::unordered_map to work with Sass::Expression
Packit bfcc33
/////////////////////////////////////////////////////////////////////////////////////
Packit bfcc33
Packit bfcc33
namespace std {
Packit bfcc33
  template<>
Packit bfcc33
  struct hash<Sass::Expression_Obj>
Packit bfcc33
  {
Packit bfcc33
    size_t operator()(Sass::Expression_Obj s) const
Packit bfcc33
    {
Packit bfcc33
      return s->hash();
Packit bfcc33
    }
Packit bfcc33
  };
Packit bfcc33
  template<>
Packit bfcc33
  struct equal_to<Sass::Expression_Obj>
Packit bfcc33
  {
Packit bfcc33
    bool operator()( Sass::Expression_Obj lhs,  Sass::Expression_Obj rhs) const
Packit bfcc33
    {
Packit bfcc33
      return lhs->hash() == rhs->hash();
Packit bfcc33
    }
Packit bfcc33
  };
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
namespace Sass {
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Mixin class for AST nodes that should behave like vectors. Uses the
Packit bfcc33
  // "Template Method" design pattern to allow subclasses to adjust their flags
Packit bfcc33
  // when certain objects are pushed.
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  template <typename T>
Packit bfcc33
  class Vectorized {
Packit bfcc33
    std::vector<T> elements_;
Packit bfcc33
  protected:
Packit bfcc33
    size_t hash_;
Packit bfcc33
    void reset_hash() { hash_ = 0; }
Packit bfcc33
    virtual void adjust_after_pushing(T element) { }
Packit bfcc33
  public:
Packit bfcc33
    Vectorized(size_t s = 0) : elements_(std::vector<T>()), hash_(0)
Packit bfcc33
    { elements_.reserve(s); }
Packit bfcc33
    virtual ~Vectorized() = 0;
Packit bfcc33
    size_t length() const   { return elements_.size(); }
Packit bfcc33
    bool empty() const      { return elements_.empty(); }
Packit bfcc33
    void clear()            { return elements_.clear(); }
Packit bfcc33
    T last() const          { return elements_.back(); }
Packit bfcc33
    T first() const         { return elements_.front(); }
Packit bfcc33
    T& operator[](size_t i) { return elements_[i]; }
Packit bfcc33
    virtual const T& at(size_t i) const { return elements_.at(i); }
Packit bfcc33
    virtual T& at(size_t i) { return elements_.at(i); }
Packit bfcc33
    const T& operator[](size_t i) const { return elements_[i]; }
Packit bfcc33
    virtual void append(T element)
Packit bfcc33
    {
Packit bfcc33
      if (element) {
Packit bfcc33
        reset_hash();
Packit bfcc33
        elements_.push_back(element);
Packit bfcc33
        adjust_after_pushing(element);
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    virtual void concat(Vectorized* v)
Packit bfcc33
    {
Packit bfcc33
      for (size_t i = 0, L = v->length(); i < L; ++i) this->append((*v)[i]);
Packit bfcc33
    }
Packit bfcc33
    Vectorized& unshift(T element)
Packit bfcc33
    {
Packit bfcc33
      elements_.insert(elements_.begin(), element);
Packit bfcc33
      return *this;
Packit bfcc33
    }
Packit bfcc33
    std::vector<T>& elements() { return elements_; }
Packit bfcc33
    const std::vector<T>& elements() const { return elements_; }
Packit bfcc33
    std::vector<T>& elements(std::vector<T>& e) { elements_ = e; return elements_; }
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        for (T& el : elements_) {
Packit bfcc33
          hash_combine(hash_, el->hash());
Packit bfcc33
        }
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    typename std::vector<T>::iterator end() { return elements_.end(); }
Packit bfcc33
    typename std::vector<T>::iterator begin() { return elements_.begin(); }
Packit bfcc33
    typename std::vector<T>::const_iterator end() const { return elements_.end(); }
Packit bfcc33
    typename std::vector<T>::const_iterator begin() const { return elements_.begin(); }
Packit bfcc33
    typename std::vector<T>::iterator erase(typename std::vector<T>::iterator el) { return elements_.erase(el); }
Packit bfcc33
    typename std::vector<T>::const_iterator erase(typename std::vector<T>::const_iterator el) { return elements_.erase(el); }
Packit bfcc33
Packit bfcc33
  };
Packit bfcc33
  template <typename T>
Packit bfcc33
  inline Vectorized<T>::~Vectorized() { }
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Mixin class for AST nodes that should behave like a hash table. Uses an
Packit bfcc33
  // extra <std::vector> internally to maintain insertion order for interation.
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Hashed {
Packit bfcc33
  private:
Packit bfcc33
    ExpressionMap elements_;
Packit bfcc33
    std::vector<Expression_Obj> list_;
Packit bfcc33
  protected:
Packit bfcc33
    size_t hash_;
Packit bfcc33
    Expression_Obj duplicate_key_;
Packit bfcc33
    void reset_hash() { hash_ = 0; }
Packit bfcc33
    void reset_duplicate_key() { duplicate_key_ = 0; }
Packit bfcc33
    virtual void adjust_after_pushing(std::pair<Expression_Obj, Expression_Obj> p) { }
Packit bfcc33
  public:
Packit bfcc33
    Hashed(size_t s = 0)
Packit bfcc33
    : elements_(ExpressionMap(s)),
Packit bfcc33
      list_(std::vector<Expression_Obj>()),
Packit bfcc33
      hash_(0), duplicate_key_(NULL)
Packit bfcc33
    { elements_.reserve(s); list_.reserve(s); }
Packit bfcc33
    virtual ~Hashed();
Packit bfcc33
    size_t length() const                  { return list_.size(); }
Packit bfcc33
    bool empty() const                     { return list_.empty(); }
Packit bfcc33
    bool has(Expression_Obj k) const          { return elements_.count(k) == 1; }
Packit bfcc33
    Expression_Obj at(Expression_Obj k) const;
Packit bfcc33
    bool has_duplicate_key() const         { return duplicate_key_ != 0; }
Packit bfcc33
    Expression_Obj get_duplicate_key() const  { return duplicate_key_; }
Packit bfcc33
    const ExpressionMap elements() { return elements_; }
Packit bfcc33
    Hashed& operator<<(std::pair<Expression_Obj, Expression_Obj> p)
Packit bfcc33
    {
Packit bfcc33
      reset_hash();
Packit bfcc33
Packit bfcc33
      if (!has(p.first)) list_.push_back(p.first);
Packit bfcc33
      else if (!duplicate_key_) duplicate_key_ = p.first;
Packit bfcc33
Packit bfcc33
      elements_[p.first] = p.second;
Packit bfcc33
Packit bfcc33
      adjust_after_pushing(p);
Packit bfcc33
      return *this;
Packit bfcc33
    }
Packit bfcc33
    Hashed& operator+=(Hashed* h)
Packit bfcc33
    {
Packit bfcc33
      if (length() == 0) {
Packit bfcc33
        this->elements_ = h->elements_;
Packit bfcc33
        this->list_ = h->list_;
Packit bfcc33
        return *this;
Packit bfcc33
      }
Packit bfcc33
Packit bfcc33
      for (auto key : h->keys()) {
Packit bfcc33
        *this << std::make_pair(key, h->at(key));
Packit bfcc33
      }
Packit bfcc33
Packit bfcc33
      reset_duplicate_key();
Packit bfcc33
      return *this;
Packit bfcc33
    }
Packit bfcc33
    const ExpressionMap& pairs() const { return elements_; }
Packit bfcc33
    const std::vector<Expression_Obj>& keys() const { return list_; }
Packit bfcc33
Packit bfcc33
//    std::unordered_map<Expression_Obj, Expression_Obj>::iterator end() { return elements_.end(); }
Packit bfcc33
//    std::unordered_map<Expression_Obj, Expression_Obj>::iterator begin() { return elements_.begin(); }
Packit bfcc33
//    std::unordered_map<Expression_Obj, Expression_Obj>::const_iterator end() const { return elements_.end(); }
Packit bfcc33
//    std::unordered_map<Expression_Obj, Expression_Obj>::const_iterator begin() const { return elements_.begin(); }
Packit bfcc33
Packit bfcc33
  };
Packit bfcc33
  inline Hashed::~Hashed() { }
Packit bfcc33
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Abstract base class for statements. This side of the AST hierarchy
Packit bfcc33
  // represents elements in expansion contexts, which exist primarily to be
Packit bfcc33
  // rewritten and macro-expanded.
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Statement : public AST_Node {
Packit bfcc33
  public:
Packit bfcc33
    enum Statement_Type {
Packit bfcc33
      NONE,
Packit bfcc33
      RULESET,
Packit bfcc33
      MEDIA,
Packit bfcc33
      DIRECTIVE,
Packit bfcc33
      SUPPORTS,
Packit bfcc33
      ATROOT,
Packit bfcc33
      BUBBLE,
Packit bfcc33
      CONTENT,
Packit bfcc33
      KEYFRAMERULE,
Packit bfcc33
      DECLARATION,
Packit bfcc33
      ASSIGNMENT,
Packit bfcc33
      IMPORT_STUB,
Packit bfcc33
      IMPORT,
Packit bfcc33
      COMMENT,
Packit bfcc33
      WARNING,
Packit bfcc33
      RETURN,
Packit bfcc33
      EXTEND,
Packit bfcc33
      ERROR,
Packit bfcc33
      DEBUGSTMT,
Packit bfcc33
      WHILE,
Packit bfcc33
      EACH,
Packit bfcc33
      FOR,
Packit bfcc33
      IF
Packit bfcc33
    };
Packit bfcc33
  private:
Packit bfcc33
    ADD_PROPERTY(Statement_Type, statement_type)
Packit bfcc33
    ADD_PROPERTY(size_t, tabs)
Packit bfcc33
    ADD_PROPERTY(bool, group_end)
Packit bfcc33
  public:
Packit bfcc33
    Statement(ParserState pstate, Statement_Type st = NONE, size_t t = 0)
Packit bfcc33
    : AST_Node(pstate), statement_type_(st), tabs_(t), group_end_(false)
Packit bfcc33
     { }
Packit bfcc33
    Statement(const Statement* ptr)
Packit bfcc33
    : AST_Node(ptr),
Packit bfcc33
      statement_type_(ptr->statement_type_),
Packit bfcc33
      tabs_(ptr->tabs_),
Packit bfcc33
      group_end_(ptr->group_end_)
Packit bfcc33
     { }
Packit bfcc33
    virtual ~Statement() = 0;
Packit bfcc33
    // needed for rearranging nested rulesets during CSS emission
Packit bfcc33
    virtual bool   is_invisible() const { return false; }
Packit bfcc33
    virtual bool   bubbles() { return false; }
Packit bfcc33
    virtual bool has_content()
Packit bfcc33
    {
Packit bfcc33
      return statement_type_ == CONTENT;
Packit bfcc33
    }
Packit bfcc33
  };
Packit bfcc33
  inline Statement::~Statement() { }
Packit bfcc33
Packit bfcc33
  ////////////////////////
Packit bfcc33
  // Blocks of statements.
Packit bfcc33
  ////////////////////////
Packit bfcc33
  class Block : public Statement, public Vectorized<Statement_Obj> {
Packit bfcc33
    ADD_PROPERTY(bool, is_root)
Packit bfcc33
    // needed for properly formatted CSS emission
Packit bfcc33
  protected:
Packit bfcc33
    void adjust_after_pushing(Statement_Obj s)
Packit bfcc33
    {
Packit bfcc33
    }
Packit bfcc33
  public:
Packit bfcc33
    Block(ParserState pstate, size_t s = 0, bool r = false)
Packit bfcc33
    : Statement(pstate),
Packit bfcc33
      Vectorized<Statement_Obj>(s),
Packit bfcc33
      is_root_(r)
Packit bfcc33
    { }
Packit bfcc33
    Block(const Block* ptr)
Packit bfcc33
    : Statement(ptr),
Packit bfcc33
      Vectorized<Statement_Obj>(*ptr),
Packit bfcc33
      is_root_(ptr->is_root_)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool has_content()
Packit bfcc33
    {
Packit bfcc33
      for (size_t i = 0, L = elements().size(); i < L; ++i) {
Packit bfcc33
        if (elements()[i]->has_content()) return true;
Packit bfcc33
      }
Packit bfcc33
      return Statement::has_content();
Packit bfcc33
    }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Block)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Abstract base class for statements that contain blocks of statements.
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Has_Block : public Statement {
Packit bfcc33
    ADD_PROPERTY(Block_Obj, block)
Packit bfcc33
  public:
Packit bfcc33
    Has_Block(ParserState pstate, Block_Obj b)
Packit bfcc33
    : Statement(pstate), block_(b)
Packit bfcc33
    { }
Packit bfcc33
    Has_Block(const Has_Block* ptr)
Packit bfcc33
    : Statement(ptr), block_(ptr->block_)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool has_content()
Packit bfcc33
    {
Packit bfcc33
      return (block_ && block_->has_content()) || Statement::has_content();
Packit bfcc33
    }
Packit bfcc33
    virtual ~Has_Block() = 0;
Packit bfcc33
  };
Packit bfcc33
  inline Has_Block::~Has_Block() { }
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Rulesets (i.e., sets of styles headed by a selector and containing a block
Packit bfcc33
  // of style declarations.
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Ruleset : public Has_Block {
Packit bfcc33
    ADD_PROPERTY(Selector_List_Obj, selector)
Packit bfcc33
    ADD_PROPERTY(bool, is_root);
Packit bfcc33
  public:
Packit bfcc33
    Ruleset(ParserState pstate, Selector_List_Obj s = 0, Block_Obj b = 0)
Packit bfcc33
    : Has_Block(pstate, b), selector_(s), is_root_(false)
Packit bfcc33
    { statement_type(RULESET); }
Packit bfcc33
    Ruleset(const Ruleset* ptr)
Packit bfcc33
    : Has_Block(ptr),
Packit bfcc33
      selector_(ptr->selector_),
Packit bfcc33
      is_root_(ptr->is_root_)
Packit bfcc33
    { statement_type(RULESET); }
Packit bfcc33
    bool is_invisible() const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Ruleset)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////
Packit bfcc33
  // Bubble.
Packit bfcc33
  /////////////////
Packit bfcc33
  class Bubble : public Statement {
Packit bfcc33
    ADD_PROPERTY(Statement_Obj, node)
Packit bfcc33
    ADD_PROPERTY(bool, group_end)
Packit bfcc33
  public:
Packit bfcc33
    Bubble(ParserState pstate, Statement_Obj n, Statement_Obj g = 0, size_t t = 0)
Packit bfcc33
    : Statement(pstate, Statement::BUBBLE, t), node_(n), group_end_(g == 0)
Packit bfcc33
    { }
Packit bfcc33
    Bubble(const Bubble* ptr)
Packit bfcc33
    : Statement(ptr),
Packit bfcc33
      node_(ptr->node_),
Packit bfcc33
      group_end_(ptr->group_end_)
Packit bfcc33
    { }
Packit bfcc33
    bool bubbles() { return true; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Bubble)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////
Packit bfcc33
  // Trace.
Packit bfcc33
  /////////////////
Packit bfcc33
  class Trace : public Has_Block {
Packit bfcc33
    ADD_CONSTREF(std::string, name)
Packit bfcc33
  public:
Packit bfcc33
    Trace(ParserState pstate, std::string n, Block_Obj b = 0)
Packit bfcc33
    : Has_Block(pstate, b), name_(n)
Packit bfcc33
    { }
Packit bfcc33
    Trace(const Trace* ptr)
Packit bfcc33
    : Has_Block(ptr),
Packit bfcc33
      name_(ptr->name_)
Packit bfcc33
    { }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Trace)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////
Packit bfcc33
  // Media queries.
Packit bfcc33
  /////////////////
Packit bfcc33
  class Media_Block : public Has_Block {
Packit bfcc33
    ADD_PROPERTY(List_Obj, media_queries)
Packit bfcc33
  public:
Packit bfcc33
    Media_Block(ParserState pstate, List_Obj mqs, Block_Obj b)
Packit bfcc33
    : Has_Block(pstate, b), media_queries_(mqs)
Packit bfcc33
    { statement_type(MEDIA); }
Packit bfcc33
    Media_Block(const Media_Block* ptr)
Packit bfcc33
    : Has_Block(ptr), media_queries_(ptr->media_queries_)
Packit bfcc33
    { statement_type(MEDIA); }
Packit bfcc33
    bool bubbles() { return true; }
Packit bfcc33
    bool is_invisible() const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Media_Block)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  // At-rules -- arbitrary directives beginning with "@" that may have an
Packit bfcc33
  // optional statement block.
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Directive : public Has_Block {
Packit bfcc33
    ADD_CONSTREF(std::string, keyword)
Packit bfcc33
    ADD_PROPERTY(Selector_List_Obj, selector)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value)
Packit bfcc33
  public:
Packit bfcc33
    Directive(ParserState pstate, std::string kwd, Selector_List_Obj sel = 0, Block_Obj b = 0, Expression_Obj val = 0)
Packit bfcc33
    : Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed
Packit bfcc33
    { statement_type(DIRECTIVE); }
Packit bfcc33
    Directive(const Directive* ptr)
Packit bfcc33
    : Has_Block(ptr),
Packit bfcc33
      keyword_(ptr->keyword_),
Packit bfcc33
      selector_(ptr->selector_),
Packit bfcc33
      value_(ptr->value_) // set value manually if needed
Packit bfcc33
    { statement_type(DIRECTIVE); }
Packit bfcc33
    bool bubbles() { return is_keyframes() || is_media(); }
Packit bfcc33
    bool is_media() {
Packit bfcc33
      return keyword_.compare("@-webkit-media") == 0 ||
Packit bfcc33
             keyword_.compare("@-moz-media") == 0 ||
Packit bfcc33
             keyword_.compare("@-o-media") == 0 ||
Packit bfcc33
             keyword_.compare("@media") == 0;
Packit bfcc33
    }
Packit bfcc33
    bool is_keyframes() {
Packit bfcc33
      return keyword_.compare("@-webkit-keyframes") == 0 ||
Packit bfcc33
             keyword_.compare("@-moz-keyframes") == 0 ||
Packit bfcc33
             keyword_.compare("@-o-keyframes") == 0 ||
Packit bfcc33
             keyword_.compare("@keyframes") == 0;
Packit bfcc33
    }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Directive)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Keyframe-rules -- the child blocks of "@keyframes" nodes.
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Keyframe_Rule : public Has_Block {
Packit bfcc33
    // according to css spec, this should be <keyframes-name>
Packit bfcc33
    // <keyframes-name> = <custom-ident> | <string>
Packit bfcc33
    ADD_PROPERTY(Selector_List_Obj, name)
Packit bfcc33
  public:
Packit bfcc33
    Keyframe_Rule(ParserState pstate, Block_Obj b)
Packit bfcc33
    : Has_Block(pstate, b), name_()
Packit bfcc33
    { statement_type(KEYFRAMERULE); }
Packit bfcc33
    Keyframe_Rule(const Keyframe_Rule* ptr)
Packit bfcc33
    : Has_Block(ptr), name_(ptr->name_)
Packit bfcc33
    { statement_type(KEYFRAMERULE); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Keyframe_Rule)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Declarations -- style rules consisting of a property name and values.
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Declaration : public Has_Block {
Packit bfcc33
    ADD_PROPERTY(String_Obj, property)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value)
Packit bfcc33
    ADD_PROPERTY(bool, is_important)
Packit bfcc33
    ADD_PROPERTY(bool, is_indented)
Packit bfcc33
  public:
Packit bfcc33
    Declaration(ParserState pstate,
Packit bfcc33
                String_Obj prop, Expression_Obj val, bool i = false, Block_Obj b = 0)
Packit bfcc33
    : Has_Block(pstate, b), property_(prop), value_(val), is_important_(i), is_indented_(false)
Packit bfcc33
    { statement_type(DECLARATION); }
Packit bfcc33
    Declaration(const Declaration* ptr)
Packit bfcc33
    : Has_Block(ptr),
Packit bfcc33
      property_(ptr->property_),
Packit bfcc33
      value_(ptr->value_),
Packit bfcc33
      is_important_(ptr->is_important_),
Packit bfcc33
      is_indented_(ptr->is_indented_)
Packit bfcc33
    { statement_type(DECLARATION); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Declaration)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////
Packit bfcc33
  // Assignments -- variable and value.
Packit bfcc33
  /////////////////////////////////////
Packit bfcc33
  class Assignment : public Statement {
Packit bfcc33
    ADD_CONSTREF(std::string, variable)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value)
Packit bfcc33
    ADD_PROPERTY(bool, is_default)
Packit bfcc33
    ADD_PROPERTY(bool, is_global)
Packit bfcc33
  public:
Packit bfcc33
    Assignment(ParserState pstate,
Packit bfcc33
               std::string var, Expression_Obj val,
Packit bfcc33
               bool is_default = false,
Packit bfcc33
               bool is_global = false)
Packit bfcc33
    : Statement(pstate), variable_(var), value_(val), is_default_(is_default), is_global_(is_global)
Packit bfcc33
    { statement_type(ASSIGNMENT); }
Packit bfcc33
    Assignment(const Assignment* ptr)
Packit bfcc33
    : Statement(ptr),
Packit bfcc33
      variable_(ptr->variable_),
Packit bfcc33
      value_(ptr->value_),
Packit bfcc33
      is_default_(ptr->is_default_),
Packit bfcc33
      is_global_(ptr->is_global_)
Packit bfcc33
    { statement_type(ASSIGNMENT); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Assignment)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Import directives. CSS and Sass import lists can be intermingled, so it's
Packit bfcc33
  // necessary to store a list of each in an Import node.
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Import : public Statement {
Packit bfcc33
    std::vector<Expression_Obj> urls_;
Packit bfcc33
    std::vector<Include>     incs_;
Packit bfcc33
    ADD_PROPERTY(List_Obj,      import_queries);
Packit bfcc33
  public:
Packit bfcc33
    Import(ParserState pstate)
Packit bfcc33
    : Statement(pstate),
Packit bfcc33
      urls_(std::vector<Expression_Obj>()),
Packit bfcc33
      incs_(std::vector<Include>()),
Packit bfcc33
      import_queries_()
Packit bfcc33
    { statement_type(IMPORT); }
Packit bfcc33
    Import(const Import* ptr)
Packit bfcc33
    : Statement(ptr),
Packit bfcc33
      urls_(ptr->urls_),
Packit bfcc33
      incs_(ptr->incs_),
Packit bfcc33
      import_queries_(ptr->import_queries_)
Packit bfcc33
    { statement_type(IMPORT); }
Packit bfcc33
    std::vector<Expression_Obj>& urls() { return urls_; }
Packit bfcc33
    std::vector<Include>& incs() { return incs_; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Import)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  // not yet resolved single import
Packit bfcc33
  // so far we only know requested name
Packit bfcc33
  class Import_Stub : public Statement {
Packit bfcc33
    Include resource_;
Packit bfcc33
  public:
Packit bfcc33
    std::string abs_path() { return resource_.abs_path; };
Packit bfcc33
    std::string imp_path() { return resource_.imp_path; };
Packit bfcc33
    Include resource() { return resource_; };
Packit bfcc33
Packit bfcc33
    Import_Stub(ParserState pstate, Include res)
Packit bfcc33
    : Statement(pstate), resource_(res)
Packit bfcc33
    { statement_type(IMPORT_STUB); }
Packit bfcc33
    Import_Stub(const Import_Stub* ptr)
Packit bfcc33
    : Statement(ptr), resource_(ptr->resource_)
Packit bfcc33
    { statement_type(IMPORT_STUB); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Import_Stub)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////
Packit bfcc33
  // The Sass `@warn` directive.
Packit bfcc33
  //////////////////////////////
Packit bfcc33
  class Warning : public Statement {
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, message)
Packit bfcc33
  public:
Packit bfcc33
    Warning(ParserState pstate, Expression_Obj msg)
Packit bfcc33
    : Statement(pstate), message_(msg)
Packit bfcc33
    { statement_type(WARNING); }
Packit bfcc33
    Warning(const Warning* ptr)
Packit bfcc33
    : Statement(ptr), message_(ptr->message_)
Packit bfcc33
    { statement_type(WARNING); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Warning)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////
Packit bfcc33
  // The Sass `@error` directive.
Packit bfcc33
  ///////////////////////////////
Packit bfcc33
  class Error : public Statement {
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, message)
Packit bfcc33
  public:
Packit bfcc33
    Error(ParserState pstate, Expression_Obj msg)
Packit bfcc33
    : Statement(pstate), message_(msg)
Packit bfcc33
    { statement_type(ERROR); }
Packit bfcc33
    Error(const Error* ptr)
Packit bfcc33
    : Statement(ptr), message_(ptr->message_)
Packit bfcc33
    { statement_type(ERROR); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Error)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////
Packit bfcc33
  // The Sass `@debug` directive.
Packit bfcc33
  ///////////////////////////////
Packit bfcc33
  class Debug : public Statement {
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value)
Packit bfcc33
  public:
Packit bfcc33
    Debug(ParserState pstate, Expression_Obj val)
Packit bfcc33
    : Statement(pstate), value_(val)
Packit bfcc33
    { statement_type(DEBUGSTMT); }
Packit bfcc33
    Debug(const Debug* ptr)
Packit bfcc33
    : Statement(ptr), value_(ptr->value_)
Packit bfcc33
    { statement_type(DEBUGSTMT); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Debug)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////
Packit bfcc33
  // CSS comments. These may be interpolated.
Packit bfcc33
  ///////////////////////////////////////////
Packit bfcc33
  class Comment : public Statement {
Packit bfcc33
    ADD_PROPERTY(String_Obj, text)
Packit bfcc33
    ADD_PROPERTY(bool, is_important)
Packit bfcc33
  public:
Packit bfcc33
    Comment(ParserState pstate, String_Obj txt, bool is_important)
Packit bfcc33
    : Statement(pstate), text_(txt), is_important_(is_important)
Packit bfcc33
    { statement_type(COMMENT); }
Packit bfcc33
    Comment(const Comment* ptr)
Packit bfcc33
    : Statement(ptr),
Packit bfcc33
      text_(ptr->text_),
Packit bfcc33
      is_important_(ptr->is_important_)
Packit bfcc33
    { statement_type(COMMENT); }
Packit bfcc33
    virtual bool is_invisible() const
Packit bfcc33
    { return /* is_important() == */ false; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Comment)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////
Packit bfcc33
  // The Sass `@if` control directive.
Packit bfcc33
  ////////////////////////////////////
Packit bfcc33
  class If : public Has_Block {
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, predicate)
Packit bfcc33
    ADD_PROPERTY(Block_Obj, alternative)
Packit bfcc33
  public:
Packit bfcc33
    If(ParserState pstate, Expression_Obj pred, Block_Obj con, Block_Obj alt = 0)
Packit bfcc33
    : Has_Block(pstate, con), predicate_(pred), alternative_(alt)
Packit bfcc33
    { statement_type(IF); }
Packit bfcc33
    If(const If* ptr)
Packit bfcc33
    : Has_Block(ptr),
Packit bfcc33
      predicate_(ptr->predicate_),
Packit bfcc33
      alternative_(ptr->alternative_)
Packit bfcc33
    { statement_type(IF); }
Packit bfcc33
    virtual bool has_content()
Packit bfcc33
    {
Packit bfcc33
      return Has_Block::has_content() || (alternative_ && alternative_->has_content());
Packit bfcc33
    }
Packit bfcc33
    ATTACH_AST_OPERATIONS(If)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////
Packit bfcc33
  // The Sass `@for` control directive.
Packit bfcc33
  /////////////////////////////////////
Packit bfcc33
  class For : public Has_Block {
Packit bfcc33
    ADD_CONSTREF(std::string, variable)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, lower_bound)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, upper_bound)
Packit bfcc33
    ADD_PROPERTY(bool, is_inclusive)
Packit bfcc33
  public:
Packit bfcc33
    For(ParserState pstate,
Packit bfcc33
        std::string var, Expression_Obj lo, Expression_Obj hi, Block_Obj b, bool inc)
Packit bfcc33
    : Has_Block(pstate, b),
Packit bfcc33
      variable_(var), lower_bound_(lo), upper_bound_(hi), is_inclusive_(inc)
Packit bfcc33
    { statement_type(FOR); }
Packit bfcc33
    For(const For* ptr)
Packit bfcc33
    : Has_Block(ptr),
Packit bfcc33
      variable_(ptr->variable_),
Packit bfcc33
      lower_bound_(ptr->lower_bound_),
Packit bfcc33
      upper_bound_(ptr->upper_bound_),
Packit bfcc33
      is_inclusive_(ptr->is_inclusive_)
Packit bfcc33
    { statement_type(FOR); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(For)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////
Packit bfcc33
  // The Sass `@each` control directive.
Packit bfcc33
  //////////////////////////////////////
Packit bfcc33
  class Each : public Has_Block {
Packit bfcc33
    ADD_PROPERTY(std::vector<std::string>, variables)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, list)
Packit bfcc33
  public:
Packit bfcc33
    Each(ParserState pstate, std::vector<std::string> vars, Expression_Obj lst, Block_Obj b)
Packit bfcc33
    : Has_Block(pstate, b), variables_(vars), list_(lst)
Packit bfcc33
    { statement_type(EACH); }
Packit bfcc33
    Each(const Each* ptr)
Packit bfcc33
    : Has_Block(ptr), variables_(ptr->variables_), list_(ptr->list_)
Packit bfcc33
    { statement_type(EACH); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Each)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////
Packit bfcc33
  // The Sass `@while` control directive.
Packit bfcc33
  ///////////////////////////////////////
Packit bfcc33
  class While : public Has_Block {
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, predicate)
Packit bfcc33
  public:
Packit bfcc33
    While(ParserState pstate, Expression_Obj pred, Block_Obj b)
Packit bfcc33
    : Has_Block(pstate, b), predicate_(pred)
Packit bfcc33
    { statement_type(WHILE); }
Packit bfcc33
    While(const While* ptr)
Packit bfcc33
    : Has_Block(ptr), predicate_(ptr->predicate_)
Packit bfcc33
    { statement_type(WHILE); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(While)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////
Packit bfcc33
  // The @return directive for use inside SassScript functions.
Packit bfcc33
  /////////////////////////////////////////////////////////////
Packit bfcc33
  class Return : public Statement {
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value)
Packit bfcc33
  public:
Packit bfcc33
    Return(ParserState pstate, Expression_Obj val)
Packit bfcc33
    : Statement(pstate), value_(val)
Packit bfcc33
    { statement_type(RETURN); }
Packit bfcc33
    Return(const Return* ptr)
Packit bfcc33
    : Statement(ptr), value_(ptr->value_)
Packit bfcc33
    { statement_type(RETURN); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Return)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////
Packit bfcc33
  // The Sass `@extend` directive.
Packit bfcc33
  ////////////////////////////////
Packit bfcc33
  class Extension : public Statement {
Packit bfcc33
    ADD_PROPERTY(Selector_List_Obj, selector)
Packit bfcc33
  public:
Packit bfcc33
    Extension(ParserState pstate, Selector_List_Obj s)
Packit bfcc33
    : Statement(pstate), selector_(s)
Packit bfcc33
    { statement_type(EXTEND); }
Packit bfcc33
    Extension(const Extension* ptr)
Packit bfcc33
    : Statement(ptr), selector_(ptr->selector_)
Packit bfcc33
    { statement_type(EXTEND); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Extension)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Definitions for both mixins and functions. The two cases are distinguished
Packit bfcc33
  // by a type tag.
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  struct Backtrace;
Packit bfcc33
  typedef const char* Signature;
Packit bfcc33
  typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*, std::vector<Selector_List_Obj>);
Packit bfcc33
  class Definition : public Has_Block {
Packit bfcc33
  public:
Packit bfcc33
    enum Type { MIXIN, FUNCTION };
Packit bfcc33
    ADD_CONSTREF(std::string, name)
Packit bfcc33
    ADD_PROPERTY(Parameters_Obj, parameters)
Packit bfcc33
    ADD_PROPERTY(Env*, environment)
Packit bfcc33
    ADD_PROPERTY(Type, type)
Packit bfcc33
    ADD_PROPERTY(Native_Function, native_function)
Packit bfcc33
    ADD_PROPERTY(Sass_Function_Entry, c_function)
Packit bfcc33
    ADD_PROPERTY(void*, cookie)
Packit bfcc33
    ADD_PROPERTY(bool, is_overload_stub)
Packit bfcc33
    ADD_PROPERTY(Signature, signature)
Packit bfcc33
  public:
Packit bfcc33
    Definition(const Definition* ptr)
Packit bfcc33
    : Has_Block(ptr),
Packit bfcc33
      name_(ptr->name_),
Packit bfcc33
      parameters_(ptr->parameters_),
Packit bfcc33
      environment_(ptr->environment_),
Packit bfcc33
      type_(ptr->type_),
Packit bfcc33
      native_function_(ptr->native_function_),
Packit bfcc33
      c_function_(ptr->c_function_),
Packit bfcc33
      cookie_(ptr->cookie_),
Packit bfcc33
      is_overload_stub_(ptr->is_overload_stub_),
Packit bfcc33
      signature_(ptr->signature_)
Packit bfcc33
    { }
Packit bfcc33
Packit bfcc33
    Definition(ParserState pstate,
Packit bfcc33
               std::string n,
Packit bfcc33
               Parameters_Obj params,
Packit bfcc33
               Block_Obj b,
Packit bfcc33
               Type t)
Packit bfcc33
    : Has_Block(pstate, b),
Packit bfcc33
      name_(n),
Packit bfcc33
      parameters_(params),
Packit bfcc33
      environment_(0),
Packit bfcc33
      type_(t),
Packit bfcc33
      native_function_(0),
Packit bfcc33
      c_function_(0),
Packit bfcc33
      cookie_(0),
Packit bfcc33
      is_overload_stub_(false),
Packit bfcc33
      signature_(0)
Packit bfcc33
    { }
Packit bfcc33
    Definition(ParserState pstate,
Packit bfcc33
               Signature sig,
Packit bfcc33
               std::string n,
Packit bfcc33
               Parameters_Obj params,
Packit bfcc33
               Native_Function func_ptr,
Packit bfcc33
               bool overload_stub = false)
Packit bfcc33
    : Has_Block(pstate, 0),
Packit bfcc33
      name_(n),
Packit bfcc33
      parameters_(params),
Packit bfcc33
      environment_(0),
Packit bfcc33
      type_(FUNCTION),
Packit bfcc33
      native_function_(func_ptr),
Packit bfcc33
      c_function_(0),
Packit bfcc33
      cookie_(0),
Packit bfcc33
      is_overload_stub_(overload_stub),
Packit bfcc33
      signature_(sig)
Packit bfcc33
    { }
Packit bfcc33
    Definition(ParserState pstate,
Packit bfcc33
               Signature sig,
Packit bfcc33
               std::string n,
Packit bfcc33
               Parameters_Obj params,
Packit bfcc33
               Sass_Function_Entry c_func,
Packit bfcc33
               bool whatever,
Packit bfcc33
               bool whatever2)
Packit bfcc33
    : Has_Block(pstate, 0),
Packit bfcc33
      name_(n),
Packit bfcc33
      parameters_(params),
Packit bfcc33
      environment_(0),
Packit bfcc33
      type_(FUNCTION),
Packit bfcc33
      native_function_(0),
Packit bfcc33
      c_function_(c_func),
Packit bfcc33
      cookie_(sass_function_get_cookie(c_func)),
Packit bfcc33
      is_overload_stub_(false),
Packit bfcc33
      signature_(sig)
Packit bfcc33
    { }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Definition)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////
Packit bfcc33
  // Mixin calls (i.e., `@include ...`).
Packit bfcc33
  //////////////////////////////////////
Packit bfcc33
  class Mixin_Call : public Has_Block {
Packit bfcc33
    ADD_CONSTREF(std::string, name)
Packit bfcc33
    ADD_PROPERTY(Arguments_Obj, arguments)
Packit bfcc33
  public:
Packit bfcc33
    Mixin_Call(ParserState pstate, std::string n, Arguments_Obj args, Block_Obj b = 0)
Packit bfcc33
    : Has_Block(pstate, b), name_(n), arguments_(args)
Packit bfcc33
    { }
Packit bfcc33
    Mixin_Call(const Mixin_Call* ptr)
Packit bfcc33
    : Has_Block(ptr),
Packit bfcc33
      name_(ptr->name_),
Packit bfcc33
      arguments_(ptr->arguments_)
Packit bfcc33
    { }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Mixin_Call)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////////////
Packit bfcc33
  // The @content directive for mixin content blocks.
Packit bfcc33
  ///////////////////////////////////////////////////
Packit bfcc33
  class Content : public Statement {
Packit bfcc33
    ADD_PROPERTY(Media_Block_Ptr, media_block)
Packit bfcc33
  public:
Packit bfcc33
    Content(ParserState pstate)
Packit bfcc33
    : Statement(pstate),
Packit bfcc33
      media_block_(NULL)
Packit bfcc33
    { statement_type(CONTENT); }
Packit bfcc33
    Content(const Content* ptr)
Packit bfcc33
    : Statement(ptr),
Packit bfcc33
      media_block_(ptr->media_block_)
Packit bfcc33
    { statement_type(CONTENT); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Content)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Lists of values, both comma- and space-separated (distinguished by a
Packit bfcc33
  // type-tag.) Also used to represent variable-length argument lists.
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  class List : public Value, public Vectorized<Expression_Obj> {
Packit bfcc33
    void adjust_after_pushing(Expression_Obj e) { is_expanded(false); }
Packit bfcc33
  private:
Packit bfcc33
    ADD_PROPERTY(enum Sass_Separator, separator)
Packit bfcc33
    ADD_PROPERTY(bool, is_arglist)
Packit bfcc33
    ADD_PROPERTY(bool, from_selector)
Packit bfcc33
  public:
Packit bfcc33
    List(ParserState pstate,
Packit bfcc33
         size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false)
Packit bfcc33
    : Value(pstate),
Packit bfcc33
      Vectorized<Expression_Obj>(size),
Packit bfcc33
      separator_(sep),
Packit bfcc33
      is_arglist_(argl),
Packit bfcc33
      from_selector_(false)
Packit bfcc33
    { concrete_type(LIST); }
Packit bfcc33
    List(const List* ptr)
Packit bfcc33
    : Value(ptr),
Packit bfcc33
      Vectorized<Expression_Obj>(*ptr),
Packit bfcc33
      separator_(ptr->separator_),
Packit bfcc33
      is_arglist_(ptr->is_arglist_),
Packit bfcc33
      from_selector_(ptr->from_selector_)
Packit bfcc33
    { concrete_type(LIST); }
Packit bfcc33
    std::string type() const { return is_arglist_ ? "arglist" : "list"; }
Packit bfcc33
    static std::string type_name() { return "list"; }
Packit bfcc33
    const char* sep_string(bool compressed = false) const {
Packit bfcc33
      return separator() == SASS_SPACE ?
Packit bfcc33
        " " : (compressed ? "," : ", ");
Packit bfcc33
    }
Packit bfcc33
    bool is_invisible() const { return empty(); }
Packit bfcc33
    Expression_Obj value_at_index(size_t i);
Packit bfcc33
Packit bfcc33
    virtual size_t size() const;
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<std::string>()(sep_string());
Packit bfcc33
        for (size_t i = 0, L = length(); i < L; ++i)
Packit bfcc33
          hash_combine(hash_, (elements()[i])->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual void set_delayed(bool delayed)
Packit bfcc33
    {
Packit bfcc33
      is_delayed(delayed);
Packit bfcc33
      // don't set children
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const;
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(List)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Key value paris.
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Map : public Value, public Hashed {
Packit bfcc33
    void adjust_after_pushing(std::pair<Expression_Obj, Expression_Obj> p) { is_expanded(false); }
Packit bfcc33
  public:
Packit bfcc33
    Map(ParserState pstate,
Packit bfcc33
         size_t size = 0)
Packit bfcc33
    : Value(pstate),
Packit bfcc33
      Hashed(size)
Packit bfcc33
    { concrete_type(MAP); }
Packit bfcc33
    Map(const Map* ptr)
Packit bfcc33
    : Value(ptr),
Packit bfcc33
      Hashed(*ptr)
Packit bfcc33
    { concrete_type(MAP); }
Packit bfcc33
    std::string type() const { return "map"; }
Packit bfcc33
    static std::string type_name() { return "map"; }
Packit bfcc33
    bool is_invisible() const { return empty(); }
Packit bfcc33
    List_Obj to_list(ParserState& pstate);
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        for (auto key : keys()) {
Packit bfcc33
          hash_combine(hash_, key->hash());
Packit bfcc33
          hash_combine(hash_, at(key)->hash());
Packit bfcc33
        }
Packit bfcc33
      }
Packit bfcc33
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const;
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(Map)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  inline static const std::string sass_op_to_name(enum Sass_OP op) {
Packit bfcc33
    switch (op) {
Packit bfcc33
      case AND: return "and";
Packit bfcc33
      case OR: return "or";
Packit bfcc33
      case EQ: return "eq";
Packit bfcc33
      case NEQ: return "neq";
Packit bfcc33
      case GT: return "gt";
Packit bfcc33
      case GTE: return "gte";
Packit bfcc33
      case LT: return "lt";
Packit bfcc33
      case LTE: return "lte";
Packit bfcc33
      case ADD: return "plus";
Packit bfcc33
      case SUB: return "sub";
Packit bfcc33
      case MUL: return "times";
Packit bfcc33
      case DIV: return "div";
Packit bfcc33
      case MOD: return "mod";
Packit bfcc33
      // this is only used internally!
Packit bfcc33
      case NUM_OPS: return "[OPS]";
Packit bfcc33
      default: return "invalid";
Packit bfcc33
    }
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Binary expressions. Represents logical, relational, and arithmetic
Packit bfcc33
  // operations. Templatized to avoid large switch statements and repetitive
Packit bfcc33
  // subclassing.
Packit bfcc33
  //////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Binary_Expression : public PreValue {
Packit bfcc33
  private:
Packit bfcc33
    HASH_PROPERTY(Operand, op)
Packit bfcc33
    HASH_PROPERTY(Expression_Obj, left)
Packit bfcc33
    HASH_PROPERTY(Expression_Obj, right)
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Binary_Expression(ParserState pstate,
Packit bfcc33
                      Operand op, Expression_Obj lhs, Expression_Obj rhs)
Packit bfcc33
    : PreValue(pstate), op_(op), left_(lhs), right_(rhs), hash_(0)
Packit bfcc33
    { }
Packit bfcc33
    Binary_Expression(const Binary_Expression* ptr)
Packit bfcc33
    : PreValue(ptr),
Packit bfcc33
      op_(ptr->op_),
Packit bfcc33
      left_(ptr->left_),
Packit bfcc33
      right_(ptr->right_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { }
Packit bfcc33
    const std::string type_name() {
Packit bfcc33
      switch (optype()) {
Packit bfcc33
        case AND: return "and";
Packit bfcc33
        case OR: return "or";
Packit bfcc33
        case EQ: return "eq";
Packit bfcc33
        case NEQ: return "neq";
Packit bfcc33
        case GT: return "gt";
Packit bfcc33
        case GTE: return "gte";
Packit bfcc33
        case LT: return "lt";
Packit bfcc33
        case LTE: return "lte";
Packit bfcc33
        case ADD: return "add";
Packit bfcc33
        case SUB: return "sub";
Packit bfcc33
        case MUL: return "mul";
Packit bfcc33
        case DIV: return "div";
Packit bfcc33
        case MOD: return "mod";
Packit bfcc33
        // this is only used internally!
Packit bfcc33
        case NUM_OPS: return "[OPS]";
Packit bfcc33
        default: return "invalid";
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    const std::string separator() {
Packit bfcc33
      switch (optype()) {
Packit bfcc33
        case AND: return "&&";
Packit bfcc33
        case OR: return "||";
Packit bfcc33
        case EQ: return "==";
Packit bfcc33
        case NEQ: return "!=";
Packit bfcc33
        case GT: return ">";
Packit bfcc33
        case GTE: return ">=";
Packit bfcc33
        case LT: return "<";
Packit bfcc33
        case LTE: return "<=";
Packit bfcc33
        case ADD: return "+";
Packit bfcc33
        case SUB: return "-";
Packit bfcc33
        case MUL: return "*";
Packit bfcc33
        case DIV: return "/";
Packit bfcc33
        case MOD: return "%";
Packit bfcc33
        // this is only used internally!
Packit bfcc33
        case NUM_OPS: return "[OPS]";
Packit bfcc33
        default: return "invalid";
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    bool is_left_interpolant(void) const;
Packit bfcc33
    bool is_right_interpolant(void) const;
Packit bfcc33
    bool has_interpolant() const
Packit bfcc33
    {
Packit bfcc33
      return is_left_interpolant() ||
Packit bfcc33
             is_right_interpolant();
Packit bfcc33
    }
Packit bfcc33
    virtual void set_delayed(bool delayed)
Packit bfcc33
    {
Packit bfcc33
      right()->set_delayed(delayed);
Packit bfcc33
      left()->set_delayed(delayed);
Packit bfcc33
      is_delayed(delayed);
Packit bfcc33
    }
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const
Packit bfcc33
    {
Packit bfcc33
      try
Packit bfcc33
      {
Packit bfcc33
        Binary_Expression_Ptr_Const m = Cast<Binary_Expression>(&rhs;;
Packit bfcc33
        if (m == 0) return false;
Packit bfcc33
        return type() == m->type() &&
Packit bfcc33
               *left() == *m->left() &&
Packit bfcc33
               *right() == *m->right();
Packit bfcc33
      }
Packit bfcc33
      catch (std::bad_cast&)
Packit bfcc33
      {
Packit bfcc33
        return false;
Packit bfcc33
      }
Packit bfcc33
      catch (...) { throw; }
Packit bfcc33
    }
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<size_t>()(optype());
Packit bfcc33
        hash_combine(hash_, left()->hash());
Packit bfcc33
        hash_combine(hash_, right()->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
    enum Sass_OP optype() const { return op_.operand; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Binary_Expression)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Arithmetic negation (logical negation is just an ordinary function call).
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Unary_Expression : public Expression {
Packit bfcc33
  public:
Packit bfcc33
    enum Type { PLUS, MINUS, NOT, SLASH };
Packit bfcc33
  private:
Packit bfcc33
    HASH_PROPERTY(Type, optype)
Packit bfcc33
    HASH_PROPERTY(Expression_Obj, operand)
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Unary_Expression(ParserState pstate, Type t, Expression_Obj o)
Packit bfcc33
    : Expression(pstate), optype_(t), operand_(o), hash_(0)
Packit bfcc33
    { }
Packit bfcc33
    Unary_Expression(const Unary_Expression* ptr)
Packit bfcc33
    : Expression(ptr),
Packit bfcc33
      optype_(ptr->optype_),
Packit bfcc33
      operand_(ptr->operand_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { }
Packit bfcc33
    const std::string type_name() {
Packit bfcc33
      switch (optype_) {
Packit bfcc33
        case PLUS: return "plus";
Packit bfcc33
        case MINUS: return "minus";
Packit bfcc33
        case SLASH: return "slash";
Packit bfcc33
        case NOT: return "not";
Packit bfcc33
        default: return "invalid";
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const
Packit bfcc33
    {
Packit bfcc33
      try
Packit bfcc33
      {
Packit bfcc33
        Unary_Expression_Ptr_Const m = Cast<Unary_Expression>(&rhs;;
Packit bfcc33
        if (m == 0) return false;
Packit bfcc33
        return type() == m->type() &&
Packit bfcc33
               *operand() == *m->operand();
Packit bfcc33
      }
Packit bfcc33
      catch (std::bad_cast&)
Packit bfcc33
      {
Packit bfcc33
        return false;
Packit bfcc33
      }
Packit bfcc33
      catch (...) { throw; }
Packit bfcc33
    }
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<size_t>()(optype_);
Packit bfcc33
        hash_combine(hash_, operand()->hash());
Packit bfcc33
      };
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Unary_Expression)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////
Packit bfcc33
  // Individual argument objects for mixin and function calls.
Packit bfcc33
  ////////////////////////////////////////////////////////////
Packit bfcc33
  class Argument : public Expression {
Packit bfcc33
    HASH_PROPERTY(Expression_Obj, value)
Packit bfcc33
    HASH_CONSTREF(std::string, name)
Packit bfcc33
    ADD_PROPERTY(bool, is_rest_argument)
Packit bfcc33
    ADD_PROPERTY(bool, is_keyword_argument)
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Argument(ParserState pstate, Expression_Obj val, std::string n = "", bool rest = false, bool keyword = false)
Packit bfcc33
    : Expression(pstate), value_(val), name_(n), is_rest_argument_(rest), is_keyword_argument_(keyword), hash_(0)
Packit bfcc33
    {
Packit bfcc33
      if (!name_.empty() && is_rest_argument_) {
Packit bfcc33
        error("variable-length argument may not be passed by name", pstate_);
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    Argument(const Argument* ptr)
Packit bfcc33
    : Expression(ptr),
Packit bfcc33
      value_(ptr->value_),
Packit bfcc33
      name_(ptr->name_),
Packit bfcc33
      is_rest_argument_(ptr->is_rest_argument_),
Packit bfcc33
      is_keyword_argument_(ptr->is_keyword_argument_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    {
Packit bfcc33
      if (!name_.empty() && is_rest_argument_) {
Packit bfcc33
        error("variable-length argument may not be passed by name", pstate_);
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual void set_delayed(bool delayed);
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const
Packit bfcc33
    {
Packit bfcc33
      try
Packit bfcc33
      {
Packit bfcc33
        Argument_Ptr_Const m = Cast<Argument>(&rhs;;
Packit bfcc33
        if (!(m && name() == m->name())) return false;
Packit bfcc33
        return *value() == *m->value();
Packit bfcc33
      }
Packit bfcc33
      catch (std::bad_cast&)
Packit bfcc33
      {
Packit bfcc33
        return false;
Packit bfcc33
      }
Packit bfcc33
      catch (...) { throw; }
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<std::string>()(name());
Packit bfcc33
        hash_combine(hash_, value()->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(Argument)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Argument lists -- in their own class to facilitate context-sensitive
Packit bfcc33
  // error checking (e.g., ensuring that all ordinal arguments precede all
Packit bfcc33
  // named arguments).
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Arguments : public Expression, public Vectorized<Argument_Obj> {
Packit bfcc33
    ADD_PROPERTY(bool, has_named_arguments)
Packit bfcc33
    ADD_PROPERTY(bool, has_rest_argument)
Packit bfcc33
    ADD_PROPERTY(bool, has_keyword_argument)
Packit bfcc33
  protected:
Packit bfcc33
    void adjust_after_pushing(Argument_Obj a);
Packit bfcc33
  public:
Packit bfcc33
    Arguments(ParserState pstate)
Packit bfcc33
    : Expression(pstate),
Packit bfcc33
      Vectorized<Argument_Obj>(),
Packit bfcc33
      has_named_arguments_(false),
Packit bfcc33
      has_rest_argument_(false),
Packit bfcc33
      has_keyword_argument_(false)
Packit bfcc33
    { }
Packit bfcc33
    Arguments(const Arguments* ptr)
Packit bfcc33
    : Expression(ptr),
Packit bfcc33
      Vectorized<Argument_Obj>(*ptr),
Packit bfcc33
      has_named_arguments_(ptr->has_named_arguments_),
Packit bfcc33
      has_rest_argument_(ptr->has_rest_argument_),
Packit bfcc33
      has_keyword_argument_(ptr->has_keyword_argument_)
Packit bfcc33
    { }
Packit bfcc33
Packit bfcc33
    virtual void set_delayed(bool delayed);
Packit bfcc33
Packit bfcc33
    Argument_Obj get_rest_argument();
Packit bfcc33
    Argument_Obj get_keyword_argument();
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(Arguments)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////
Packit bfcc33
  // Function calls.
Packit bfcc33
  //////////////////
Packit bfcc33
  class Function_Call : public PreValue {
Packit bfcc33
    HASH_CONSTREF(std::string, name)
Packit bfcc33
    HASH_PROPERTY(Arguments_Obj, arguments)
Packit bfcc33
    ADD_PROPERTY(bool, via_call)
Packit bfcc33
    ADD_PROPERTY(void*, cookie)
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Function_Call(ParserState pstate, std::string n, Arguments_Obj args, void* cookie)
Packit bfcc33
    : PreValue(pstate), name_(n), arguments_(args), via_call_(false), cookie_(cookie), hash_(0)
Packit bfcc33
    { concrete_type(FUNCTION); }
Packit bfcc33
    Function_Call(ParserState pstate, std::string n, Arguments_Obj args)
Packit bfcc33
    : PreValue(pstate), name_(n), arguments_(args), via_call_(false), cookie_(0), hash_(0)
Packit bfcc33
    { concrete_type(FUNCTION); }
Packit bfcc33
    Function_Call(const Function_Call* ptr)
Packit bfcc33
    : PreValue(ptr),
Packit bfcc33
      name_(ptr->name_),
Packit bfcc33
      arguments_(ptr->arguments_),
Packit bfcc33
      via_call_(ptr->via_call_),
Packit bfcc33
      cookie_(ptr->cookie_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { concrete_type(FUNCTION); }
Packit bfcc33
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const
Packit bfcc33
    {
Packit bfcc33
      try
Packit bfcc33
      {
Packit bfcc33
        Function_Call_Ptr_Const m = Cast<Function_Call>(&rhs;;
Packit bfcc33
        if (!(m && name() == m->name())) return false;
Packit bfcc33
        if (!(m && arguments()->length() == m->arguments()->length())) return false;
Packit bfcc33
        for (size_t i =0, L = arguments()->length(); i < L; ++i)
Packit bfcc33
          if (!(*(*arguments())[i] == *(*m->arguments())[i])) return false;
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      catch (std::bad_cast&)
Packit bfcc33
      {
Packit bfcc33
        return false;
Packit bfcc33
      }
Packit bfcc33
      catch (...) { throw; }
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<std::string>()(name());
Packit bfcc33
        for (auto argument : arguments()->elements())
Packit bfcc33
          hash_combine(hash_, argument->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Function_Call)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////
Packit bfcc33
  // Function call schemas.
Packit bfcc33
  /////////////////////////
Packit bfcc33
  class Function_Call_Schema : public Expression {
Packit bfcc33
    ADD_PROPERTY(String_Obj, name)
Packit bfcc33
    ADD_PROPERTY(Arguments_Obj, arguments)
Packit bfcc33
  public:
Packit bfcc33
    Function_Call_Schema(ParserState pstate, String_Obj n, Arguments_Obj args)
Packit bfcc33
    : Expression(pstate), name_(n), arguments_(args)
Packit bfcc33
    { concrete_type(STRING); }
Packit bfcc33
    Function_Call_Schema(const Function_Call_Schema* ptr)
Packit bfcc33
    : Expression(ptr),
Packit bfcc33
      name_(ptr->name_),
Packit bfcc33
      arguments_(ptr->arguments_)
Packit bfcc33
    { concrete_type(STRING); }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Function_Call_Schema)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////
Packit bfcc33
  // Variable references.
Packit bfcc33
  ///////////////////////
Packit bfcc33
  class Variable : public PreValue {
Packit bfcc33
    ADD_CONSTREF(std::string, name)
Packit bfcc33
  public:
Packit bfcc33
    Variable(ParserState pstate, std::string n)
Packit bfcc33
    : PreValue(pstate), name_(n)
Packit bfcc33
    { concrete_type(VARIABLE); }
Packit bfcc33
    Variable(const Variable* ptr)
Packit bfcc33
    : PreValue(ptr), name_(ptr->name_)
Packit bfcc33
    { concrete_type(VARIABLE); }
Packit bfcc33
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const
Packit bfcc33
    {
Packit bfcc33
      try
Packit bfcc33
      {
Packit bfcc33
        Variable_Ptr_Const e = Cast<Variable>(&rhs;;
Packit bfcc33
        return e && name() == e->name();
Packit bfcc33
      }
Packit bfcc33
      catch (std::bad_cast&)
Packit bfcc33
      {
Packit bfcc33
        return false;
Packit bfcc33
      }
Packit bfcc33
      catch (...) { throw; }
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      return std::hash<std::string>()(name());
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(Variable)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////
Packit bfcc33
  // Numbers, percentages, dimensions, and colors.
Packit bfcc33
  ////////////////////////////////////////////////
Packit bfcc33
  class Number : public Value {
Packit bfcc33
    HASH_PROPERTY(double, value)
Packit bfcc33
    ADD_PROPERTY(bool, zero)
Packit bfcc33
    std::vector<std::string> numerator_units_;
Packit bfcc33
    std::vector<std::string> denominator_units_;
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Number(ParserState pstate, double val, std::string u = "", bool zero = true);
Packit bfcc33
Packit bfcc33
    Number(const Number* ptr)
Packit bfcc33
    : Value(ptr),
Packit bfcc33
      value_(ptr->value_), zero_(ptr->zero_),
Packit bfcc33
      numerator_units_(ptr->numerator_units_),
Packit bfcc33
      denominator_units_(ptr->denominator_units_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { concrete_type(NUMBER); }
Packit bfcc33
Packit bfcc33
    bool zero() { return zero_; }
Packit bfcc33
    bool is_valid_css_unit() const;
Packit bfcc33
    std::vector<std::string>& numerator_units()   { return numerator_units_; }
Packit bfcc33
    std::vector<std::string>& denominator_units() { return denominator_units_; }
Packit bfcc33
    const std::vector<std::string>& numerator_units() const   { return numerator_units_; }
Packit bfcc33
    const std::vector<std::string>& denominator_units() const { return denominator_units_; }
Packit bfcc33
    std::string type() const { return "number"; }
Packit bfcc33
    static std::string type_name() { return "number"; }
Packit bfcc33
    std::string unit() const;
Packit bfcc33
Packit bfcc33
    bool is_unitless() const;
Packit bfcc33
    double convert_factor(const Number&) const;
Packit bfcc33
    bool convert(const std::string& unit = "", bool strict = false);
Packit bfcc33
    void normalize(const std::string& unit = "", bool strict = false);
Packit bfcc33
    // useful for making one number compatible with another
Packit bfcc33
    std::string find_convertible_unit() const;
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<double>()(value_);
Packit bfcc33
        for (const auto numerator : numerator_units())
Packit bfcc33
          hash_combine(hash_, std::hash<std::string>()(numerator));
Packit bfcc33
        for (const auto denominator : denominator_units())
Packit bfcc33
          hash_combine(hash_, std::hash<std::string>()(denominator));
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool operator< (const Number& rhs) const;
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Number)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////
Packit bfcc33
  // Colors.
Packit bfcc33
  //////////
Packit bfcc33
  class Color : public Value {
Packit bfcc33
    HASH_PROPERTY(double, r)
Packit bfcc33
    HASH_PROPERTY(double, g)
Packit bfcc33
    HASH_PROPERTY(double, b)
Packit bfcc33
    HASH_PROPERTY(double, a)
Packit bfcc33
    ADD_CONSTREF(std::string, disp)
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Color(ParserState pstate, double r, double g, double b, double a = 1, const std::string disp = "")
Packit bfcc33
    : Value(pstate), r_(r), g_(g), b_(b), a_(a), disp_(disp),
Packit bfcc33
      hash_(0)
Packit bfcc33
    { concrete_type(COLOR); }
Packit bfcc33
    Color(const Color* ptr)
Packit bfcc33
    : Value(ptr),
Packit bfcc33
      r_(ptr->r_),
Packit bfcc33
      g_(ptr->g_),
Packit bfcc33
      b_(ptr->b_),
Packit bfcc33
      a_(ptr->a_),
Packit bfcc33
      disp_(ptr->disp_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { concrete_type(COLOR); }
Packit bfcc33
    std::string type() const { return "color"; }
Packit bfcc33
    static std::string type_name() { return "color"; }
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<double>()(a_);
Packit bfcc33
        hash_combine(hash_, std::hash<double>()(r_));
Packit bfcc33
        hash_combine(hash_, std::hash<double>()(g_));
Packit bfcc33
        hash_combine(hash_, std::hash<double>()(b_));
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const;
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(Color)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////
Packit bfcc33
  // Errors from Sass_Values.
Packit bfcc33
  //////////////////////////////
Packit bfcc33
  class Custom_Error : public Value {
Packit bfcc33
    ADD_CONSTREF(std::string, message)
Packit bfcc33
  public:
Packit bfcc33
    Custom_Error(ParserState pstate, std::string msg)
Packit bfcc33
    : Value(pstate), message_(msg)
Packit bfcc33
    { concrete_type(C_ERROR); }
Packit bfcc33
    Custom_Error(const Custom_Error* ptr)
Packit bfcc33
    : Value(ptr), message_(ptr->message_)
Packit bfcc33
    { concrete_type(C_ERROR); }
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Custom_Error)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////
Packit bfcc33
  // Warnings from Sass_Values.
Packit bfcc33
  //////////////////////////////
Packit bfcc33
  class Custom_Warning : public Value {
Packit bfcc33
    ADD_CONSTREF(std::string, message)
Packit bfcc33
  public:
Packit bfcc33
    Custom_Warning(ParserState pstate, std::string msg)
Packit bfcc33
    : Value(pstate), message_(msg)
Packit bfcc33
    { concrete_type(C_WARNING); }
Packit bfcc33
    Custom_Warning(const Custom_Warning* ptr)
Packit bfcc33
    : Value(ptr), message_(ptr->message_)
Packit bfcc33
    { concrete_type(C_WARNING); }
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Custom_Warning)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////
Packit bfcc33
  // Booleans.
Packit bfcc33
  ////////////
Packit bfcc33
  class Boolean : public Value {
Packit bfcc33
    HASH_PROPERTY(bool, value)
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Boolean(ParserState pstate, bool val)
Packit bfcc33
    : Value(pstate), value_(val),
Packit bfcc33
      hash_(0)
Packit bfcc33
    { concrete_type(BOOLEAN); }
Packit bfcc33
    Boolean(const Boolean* ptr)
Packit bfcc33
    : Value(ptr),
Packit bfcc33
      value_(ptr->value_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { concrete_type(BOOLEAN); }
Packit bfcc33
    virtual operator bool() { return value_; }
Packit bfcc33
    std::string type() const { return "bool"; }
Packit bfcc33
    static std::string type_name() { return "bool"; }
Packit bfcc33
    virtual bool is_false() { return !value_; }
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<bool>()(value_);
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const;
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(Boolean)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Abstract base class for Sass string values. Includes interpolated and
Packit bfcc33
  // "flat" strings.
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class String : public Value {
Packit bfcc33
  public:
Packit bfcc33
    String(ParserState pstate, bool delayed = false)
Packit bfcc33
    : Value(pstate, delayed)
Packit bfcc33
    { concrete_type(STRING); }
Packit bfcc33
    String(const String* ptr)
Packit bfcc33
    : Value(ptr)
Packit bfcc33
    { concrete_type(STRING); }
Packit bfcc33
    static std::string type_name() { return "string"; }
Packit bfcc33
    virtual ~String() = 0;
Packit bfcc33
    virtual void rtrim() = 0;
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const = 0;
Packit bfcc33
    virtual bool operator<(const Expression& rhs) const {
Packit bfcc33
      return this->to_string() < rhs.to_string();
Packit bfcc33
    };
Packit bfcc33
    ATTACH_VIRTUAL_AST_OPERATIONS(String);
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
  inline String::~String() { };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Interpolated strings. Meant to be reduced to flat strings during the
Packit bfcc33
  // evaluation phase.
Packit bfcc33
  ///////////////////////////////////////////////////////////////////////
Packit bfcc33
  class String_Schema : public String, public Vectorized<Expression_Obj> {
Packit bfcc33
    // ADD_PROPERTY(bool, has_interpolants)
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    String_Schema(ParserState pstate, size_t size = 0, bool has_interpolants = false)
Packit bfcc33
    : String(pstate), Vectorized<Expression_Obj>(size), hash_(0)
Packit bfcc33
    { concrete_type(STRING); }
Packit bfcc33
    String_Schema(const String_Schema* ptr)
Packit bfcc33
    : String(ptr),
Packit bfcc33
      Vectorized<Expression_Obj>(*ptr),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { concrete_type(STRING); }
Packit bfcc33
Packit bfcc33
    std::string type() const { return "string"; }
Packit bfcc33
    static std::string type_name() { return "string"; }
Packit bfcc33
Packit bfcc33
    bool is_left_interpolant(void) const;
Packit bfcc33
    bool is_right_interpolant(void) const;
Packit bfcc33
    // void has_interpolants(bool tc) { }
Packit bfcc33
    bool has_interpolants() {
Packit bfcc33
      for (auto el : elements()) {
Packit bfcc33
        if (el->is_interpolant()) return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
    virtual void rtrim();
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        for (auto string : elements())
Packit bfcc33
          hash_combine(hash_, string->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual void set_delayed(bool delayed) {
Packit bfcc33
      is_delayed(delayed);
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(String_Schema)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////
Packit bfcc33
  // Flat strings -- the lowest level of raw textual data.
Packit bfcc33
  ////////////////////////////////////////////////////////
Packit bfcc33
  class String_Constant : public String {
Packit bfcc33
    ADD_PROPERTY(char, quote_mark)
Packit bfcc33
    ADD_PROPERTY(bool, can_compress_whitespace)
Packit bfcc33
    HASH_CONSTREF(std::string, value)
Packit bfcc33
  protected:
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    String_Constant(const String_Constant* ptr)
Packit bfcc33
    : String(ptr),
Packit bfcc33
      quote_mark_(ptr->quote_mark_),
Packit bfcc33
      can_compress_whitespace_(ptr->can_compress_whitespace_),
Packit bfcc33
      value_(ptr->value_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { }
Packit bfcc33
    String_Constant(ParserState pstate, std::string val)
Packit bfcc33
    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(val)), hash_(0)
Packit bfcc33
    { }
Packit bfcc33
    String_Constant(ParserState pstate, const char* beg)
Packit bfcc33
    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg))), hash_(0)
Packit bfcc33
    { }
Packit bfcc33
    String_Constant(ParserState pstate, const char* beg, const char* end)
Packit bfcc33
    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg, end-beg))), hash_(0)
Packit bfcc33
    { }
Packit bfcc33
    String_Constant(ParserState pstate, const Token& tok)
Packit bfcc33
    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(tok.begin, tok.end))), hash_(0)
Packit bfcc33
    { }
Packit bfcc33
    std::string type() const { return "string"; }
Packit bfcc33
    static std::string type_name() { return "string"; }
Packit bfcc33
    virtual bool is_invisible() const;
Packit bfcc33
    virtual void rtrim();
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_ = std::hash<std::string>()(value_);
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const;
Packit bfcc33
    virtual std::string inspect() const; // quotes are forced on inspection
Packit bfcc33
Packit bfcc33
    // static char auto_quote() { return '*'; }
Packit bfcc33
    static char double_quote() { return '"'; }
Packit bfcc33
    static char single_quote() { return '\''; }
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(String_Constant)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////
Packit bfcc33
  // Possibly quoted string (unquote on instantiation)
Packit bfcc33
  ////////////////////////////////////////////////////////
Packit bfcc33
  class String_Quoted : public String_Constant {
Packit bfcc33
  public:
Packit bfcc33
    String_Quoted(ParserState pstate, std::string val, char q = 0,
Packit bfcc33
      bool keep_utf8_escapes = false, bool skip_unquoting = false,
Packit bfcc33
      bool strict_unquoting = true)
Packit bfcc33
    : String_Constant(pstate, val)
Packit bfcc33
    {
Packit bfcc33
      if (skip_unquoting == false) {
Packit bfcc33
        value_ = unquote(value_, &quote_mark_, keep_utf8_escapes, strict_unquoting);
Packit bfcc33
      }
Packit bfcc33
      if (q && quote_mark_) quote_mark_ = q;
Packit bfcc33
    }
Packit bfcc33
    String_Quoted(const String_Quoted* ptr)
Packit bfcc33
    : String_Constant(ptr)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const;
Packit bfcc33
    virtual std::string inspect() const; // quotes are forced on inspection
Packit bfcc33
    ATTACH_AST_OPERATIONS(String_Quoted)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////
Packit bfcc33
  // Media queries.
Packit bfcc33
  /////////////////
Packit bfcc33
  class Media_Query : public Expression,
Packit bfcc33
                      public Vectorized<Media_Query_Expression_Obj> {
Packit bfcc33
    ADD_PROPERTY(String_Obj, media_type)
Packit bfcc33
    ADD_PROPERTY(bool, is_negated)
Packit bfcc33
    ADD_PROPERTY(bool, is_restricted)
Packit bfcc33
  public:
Packit bfcc33
    Media_Query(ParserState pstate,
Packit bfcc33
                String_Obj t = 0, size_t s = 0, bool n = false, bool r = false)
Packit bfcc33
    : Expression(pstate), Vectorized<Media_Query_Expression_Obj>(s),
Packit bfcc33
      media_type_(t), is_negated_(n), is_restricted_(r)
Packit bfcc33
    { }
Packit bfcc33
    Media_Query(const Media_Query* ptr)
Packit bfcc33
    : Expression(ptr),
Packit bfcc33
      Vectorized<Media_Query_Expression_Obj>(*ptr),
Packit bfcc33
      media_type_(ptr->media_type_),
Packit bfcc33
      is_negated_(ptr->is_negated_),
Packit bfcc33
      is_restricted_(ptr->is_restricted_)
Packit bfcc33
    { }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Media_Query)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////
Packit bfcc33
  // Media expressions (for use inside media queries).
Packit bfcc33
  ////////////////////////////////////////////////////
Packit bfcc33
  class Media_Query_Expression : public Expression {
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, feature)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value)
Packit bfcc33
    ADD_PROPERTY(bool, is_interpolated)
Packit bfcc33
  public:
Packit bfcc33
    Media_Query_Expression(ParserState pstate,
Packit bfcc33
                           Expression_Obj f, Expression_Obj v, bool i = false)
Packit bfcc33
    : Expression(pstate), feature_(f), value_(v), is_interpolated_(i)
Packit bfcc33
    { }
Packit bfcc33
    Media_Query_Expression(const Media_Query_Expression* ptr)
Packit bfcc33
    : Expression(ptr),
Packit bfcc33
      feature_(ptr->feature_),
Packit bfcc33
      value_(ptr->value_),
Packit bfcc33
      is_interpolated_(ptr->is_interpolated_)
Packit bfcc33
    { }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Media_Query_Expression)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////
Packit bfcc33
  // `@supports` rule.
Packit bfcc33
  ////////////////////
Packit bfcc33
  class Supports_Block : public Has_Block {
Packit bfcc33
    ADD_PROPERTY(Supports_Condition_Obj, condition)
Packit bfcc33
  public:
Packit bfcc33
    Supports_Block(ParserState pstate, Supports_Condition_Obj condition, Block_Obj block = 0)
Packit bfcc33
    : Has_Block(pstate, block), condition_(condition)
Packit bfcc33
    { statement_type(SUPPORTS); }
Packit bfcc33
    Supports_Block(const Supports_Block* ptr)
Packit bfcc33
    : Has_Block(ptr), condition_(ptr->condition_)
Packit bfcc33
    { statement_type(SUPPORTS); }
Packit bfcc33
    bool bubbles() { return true; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Supports_Block)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////
Packit bfcc33
  // The abstract superclass of all Supports conditions.
Packit bfcc33
  //////////////////////////////////////////////////////
Packit bfcc33
  class Supports_Condition : public Expression {
Packit bfcc33
  public:
Packit bfcc33
    Supports_Condition(ParserState pstate)
Packit bfcc33
    : Expression(pstate)
Packit bfcc33
    { }
Packit bfcc33
    Supports_Condition(const Supports_Condition* ptr)
Packit bfcc33
    : Expression(ptr)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Supports_Condition)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////
Packit bfcc33
  // An operator condition (e.g. `CONDITION1 and CONDITION2`).
Packit bfcc33
  ////////////////////////////////////////////////////////////
Packit bfcc33
  class Supports_Operator : public Supports_Condition {
Packit bfcc33
  public:
Packit bfcc33
    enum Operand { AND, OR };
Packit bfcc33
  private:
Packit bfcc33
    ADD_PROPERTY(Supports_Condition_Obj, left);
Packit bfcc33
    ADD_PROPERTY(Supports_Condition_Obj, right);
Packit bfcc33
    ADD_PROPERTY(Operand, operand);
Packit bfcc33
  public:
Packit bfcc33
    Supports_Operator(ParserState pstate, Supports_Condition_Obj l, Supports_Condition_Obj r, Operand o)
Packit bfcc33
    : Supports_Condition(pstate), left_(l), right_(r), operand_(o)
Packit bfcc33
    { }
Packit bfcc33
    Supports_Operator(const Supports_Operator* ptr)
Packit bfcc33
    : Supports_Condition(ptr),
Packit bfcc33
      left_(ptr->left_),
Packit bfcc33
      right_(ptr->right_),
Packit bfcc33
      operand_(ptr->operand_)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool needs_parens(Supports_Condition_Obj cond) const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Supports_Operator)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////
Packit bfcc33
  // A negation condition (`not CONDITION`).
Packit bfcc33
  //////////////////////////////////////////
Packit bfcc33
  class Supports_Negation : public Supports_Condition {
Packit bfcc33
  private:
Packit bfcc33
    ADD_PROPERTY(Supports_Condition_Obj, condition);
Packit bfcc33
  public:
Packit bfcc33
    Supports_Negation(ParserState pstate, Supports_Condition_Obj c)
Packit bfcc33
    : Supports_Condition(pstate), condition_(c)
Packit bfcc33
    { }
Packit bfcc33
    Supports_Negation(const Supports_Negation* ptr)
Packit bfcc33
    : Supports_Condition(ptr), condition_(ptr->condition_)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool needs_parens(Supports_Condition_Obj cond) const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Supports_Negation)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////
Packit bfcc33
  // A declaration condition (e.g. `(feature: value)`).
Packit bfcc33
  /////////////////////////////////////////////////////
Packit bfcc33
  class Supports_Declaration : public Supports_Condition {
Packit bfcc33
  private:
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, feature);
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value);
Packit bfcc33
  public:
Packit bfcc33
    Supports_Declaration(ParserState pstate, Expression_Obj f, Expression_Obj v)
Packit bfcc33
    : Supports_Condition(pstate), feature_(f), value_(v)
Packit bfcc33
    { }
Packit bfcc33
    Supports_Declaration(const Supports_Declaration* ptr)
Packit bfcc33
    : Supports_Condition(ptr),
Packit bfcc33
      feature_(ptr->feature_),
Packit bfcc33
      value_(ptr->value_)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Supports_Declaration)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////////
Packit bfcc33
  // An interpolation condition (e.g. `#{$var}`).
Packit bfcc33
  ///////////////////////////////////////////////
Packit bfcc33
  class Supports_Interpolation : public Supports_Condition {
Packit bfcc33
  private:
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value);
Packit bfcc33
  public:
Packit bfcc33
    Supports_Interpolation(ParserState pstate, Expression_Obj v)
Packit bfcc33
    : Supports_Condition(pstate), value_(v)
Packit bfcc33
    { }
Packit bfcc33
    Supports_Interpolation(const Supports_Interpolation* ptr)
Packit bfcc33
    : Supports_Condition(ptr),
Packit bfcc33
      value_(ptr->value_)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Supports_Interpolation)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////
Packit bfcc33
  // At root expressions (for use inside @at-root).
Packit bfcc33
  /////////////////////////////////////////////////
Packit bfcc33
  class At_Root_Query : public Expression {
Packit bfcc33
  private:
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, feature)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, value)
Packit bfcc33
  public:
Packit bfcc33
    At_Root_Query(ParserState pstate, Expression_Obj f = 0, Expression_Obj v = 0, bool i = false)
Packit bfcc33
    : Expression(pstate), feature_(f), value_(v)
Packit bfcc33
    { }
Packit bfcc33
    At_Root_Query(const At_Root_Query* ptr)
Packit bfcc33
    : Expression(ptr),
Packit bfcc33
      feature_(ptr->feature_),
Packit bfcc33
      value_(ptr->value_)
Packit bfcc33
    { }
Packit bfcc33
    bool exclude(std::string str);
Packit bfcc33
    ATTACH_AST_OPERATIONS(At_Root_Query)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////
Packit bfcc33
  // At-root.
Packit bfcc33
  ///////////
Packit bfcc33
  class At_Root_Block : public Has_Block {
Packit bfcc33
    ADD_PROPERTY(At_Root_Query_Obj, expression)
Packit bfcc33
  public:
Packit bfcc33
    At_Root_Block(ParserState pstate, Block_Obj b = 0, At_Root_Query_Obj e = 0)
Packit bfcc33
    : Has_Block(pstate, b), expression_(e)
Packit bfcc33
    { statement_type(ATROOT); }
Packit bfcc33
    At_Root_Block(const At_Root_Block* ptr)
Packit bfcc33
    : Has_Block(ptr), expression_(ptr->expression_)
Packit bfcc33
    { statement_type(ATROOT); }
Packit bfcc33
    bool bubbles() { return true; }
Packit bfcc33
    bool exclude_node(Statement_Obj s) {
Packit bfcc33
      if (expression() == 0)
Packit bfcc33
      {
Packit bfcc33
        return s->statement_type() == Statement::RULESET;
Packit bfcc33
      }
Packit bfcc33
Packit bfcc33
      if (s->statement_type() == Statement::DIRECTIVE)
Packit bfcc33
      {
Packit bfcc33
        if (Directive_Obj dir = Cast<Directive>(s))
Packit bfcc33
        {
Packit bfcc33
          std::string keyword(dir->keyword());
Packit bfcc33
          if (keyword.length() > 0) keyword.erase(0, 1);
Packit bfcc33
          return expression()->exclude(keyword);
Packit bfcc33
        }
Packit bfcc33
      }
Packit bfcc33
      if (s->statement_type() == Statement::MEDIA)
Packit bfcc33
      {
Packit bfcc33
        return expression()->exclude("media");
Packit bfcc33
      }
Packit bfcc33
      if (s->statement_type() == Statement::RULESET)
Packit bfcc33
      {
Packit bfcc33
        return expression()->exclude("rule");
Packit bfcc33
      }
Packit bfcc33
      if (s->statement_type() == Statement::SUPPORTS)
Packit bfcc33
      {
Packit bfcc33
        return expression()->exclude("supports");
Packit bfcc33
      }
Packit bfcc33
      if (Directive_Obj dir = Cast<Directive>(s))
Packit bfcc33
      {
Packit bfcc33
        if (dir->is_keyframes()) return expression()->exclude("keyframes");
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
    ATTACH_AST_OPERATIONS(At_Root_Block)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////
Packit bfcc33
  // The null value.
Packit bfcc33
  //////////////////
Packit bfcc33
  class Null : public Value {
Packit bfcc33
  public:
Packit bfcc33
    Null(ParserState pstate) : Value(pstate) { concrete_type(NULL_VAL); }
Packit bfcc33
    Null(const Null* ptr) : Value(ptr) { concrete_type(NULL_VAL); }
Packit bfcc33
    std::string type() const { return "null"; }
Packit bfcc33
    static std::string type_name() { return "null"; }
Packit bfcc33
    bool is_invisible() const { return true; }
Packit bfcc33
    operator bool() { return false; }
Packit bfcc33
    bool is_false() { return true; }
Packit bfcc33
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      return -1;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool operator== (const Expression& rhs) const;
Packit bfcc33
Packit bfcc33
    ATTACH_AST_OPERATIONS(Null)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////
Packit bfcc33
  // Thunks for delayed evaluation.
Packit bfcc33
  /////////////////////////////////
Packit bfcc33
  class Thunk : public Expression {
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, expression)
Packit bfcc33
    ADD_PROPERTY(Env*, environment)
Packit bfcc33
  public:
Packit bfcc33
    Thunk(ParserState pstate, Expression_Obj exp, Env* env = 0)
Packit bfcc33
    : Expression(pstate), expression_(exp), environment_(env)
Packit bfcc33
    { }
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////
Packit bfcc33
  // Individual parameter objects for mixins and functions.
Packit bfcc33
  /////////////////////////////////////////////////////////
Packit bfcc33
  class Parameter : public AST_Node {
Packit bfcc33
    ADD_CONSTREF(std::string, name)
Packit bfcc33
    ADD_PROPERTY(Expression_Obj, default_value)
Packit bfcc33
    ADD_PROPERTY(bool, is_rest_parameter)
Packit bfcc33
  public:
Packit bfcc33
    Parameter(ParserState pstate,
Packit bfcc33
              std::string n, Expression_Obj def = 0, bool rest = false)
Packit bfcc33
    : AST_Node(pstate), name_(n), default_value_(def), is_rest_parameter_(rest)
Packit bfcc33
    {
Packit bfcc33
      // tried to come up with a spec test for this, but it does no longer
Packit bfcc33
      // get  past the parser (it error out earlier). A spec test was added!
Packit bfcc33
      // if (default_value_ && is_rest_parameter_) {
Packit bfcc33
      //   error("variable-length parameter may not have a default value", pstate_);
Packit bfcc33
      // }
Packit bfcc33
    }
Packit bfcc33
    Parameter(const Parameter* ptr)
Packit bfcc33
    : AST_Node(ptr),
Packit bfcc33
      name_(ptr->name_),
Packit bfcc33
      default_value_(ptr->default_value_),
Packit bfcc33
      is_rest_parameter_(ptr->is_rest_parameter_)
Packit bfcc33
    {
Packit bfcc33
      // tried to come up with a spec test for this, but it does no longer
Packit bfcc33
      // get  past the parser (it error out earlier). A spec test was added!
Packit bfcc33
      // if (default_value_ && is_rest_parameter_) {
Packit bfcc33
      //   error("variable-length parameter may not have a default value", pstate_);
Packit bfcc33
      // }
Packit bfcc33
    }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Parameter)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Parameter lists -- in their own class to facilitate context-sensitive
Packit bfcc33
  // error checking (e.g., ensuring that all optional parameters follow all
Packit bfcc33
  // required parameters).
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Parameters : public AST_Node, public Vectorized<Parameter_Obj> {
Packit bfcc33
    ADD_PROPERTY(bool, has_optional_parameters)
Packit bfcc33
    ADD_PROPERTY(bool, has_rest_parameter)
Packit bfcc33
  protected:
Packit bfcc33
    void adjust_after_pushing(Parameter_Obj p)
Packit bfcc33
    {
Packit bfcc33
      if (p->default_value()) {
Packit bfcc33
        if (has_rest_parameter()) {
Packit bfcc33
          error("optional parameters may not be combined with variable-length parameters", p->pstate());
Packit bfcc33
        }
Packit bfcc33
        has_optional_parameters(true);
Packit bfcc33
      }
Packit bfcc33
      else if (p->is_rest_parameter()) {
Packit bfcc33
        if (has_rest_parameter()) {
Packit bfcc33
          error("functions and mixins cannot have more than one variable-length parameter", p->pstate());
Packit bfcc33
        }
Packit bfcc33
        has_rest_parameter(true);
Packit bfcc33
      }
Packit bfcc33
      else {
Packit bfcc33
        if (has_rest_parameter()) {
Packit bfcc33
          error("required parameters must precede variable-length parameters", p->pstate());
Packit bfcc33
        }
Packit bfcc33
        if (has_optional_parameters()) {
Packit bfcc33
          error("required parameters must precede optional parameters", p->pstate());
Packit bfcc33
        }
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
  public:
Packit bfcc33
    Parameters(ParserState pstate)
Packit bfcc33
    : AST_Node(pstate),
Packit bfcc33
      Vectorized<Parameter_Obj>(),
Packit bfcc33
      has_optional_parameters_(false),
Packit bfcc33
      has_rest_parameter_(false)
Packit bfcc33
    { }
Packit bfcc33
    Parameters(const Parameters* ptr)
Packit bfcc33
    : AST_Node(ptr),
Packit bfcc33
      Vectorized<Parameter_Obj>(*ptr),
Packit bfcc33
      has_optional_parameters_(ptr->has_optional_parameters_),
Packit bfcc33
      has_rest_parameter_(ptr->has_rest_parameter_)
Packit bfcc33
    { }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Parameters)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////
Packit bfcc33
  // Abstract base class for CSS selectors.
Packit bfcc33
  /////////////////////////////////////////
Packit bfcc33
  class Selector : public Expression {
Packit bfcc33
    // ADD_PROPERTY(bool, has_reference)
Packit bfcc33
    // line break before list separator
Packit bfcc33
    ADD_PROPERTY(bool, has_line_feed)
Packit bfcc33
    // line break after list separator
Packit bfcc33
    ADD_PROPERTY(bool, has_line_break)
Packit bfcc33
    // maybe we have optional flag
Packit bfcc33
    ADD_PROPERTY(bool, is_optional)
Packit bfcc33
    // parent block pointers
Packit bfcc33
Packit bfcc33
    // must not be a reference counted object
Packit bfcc33
    // otherwise we create circular references
Packit bfcc33
    ADD_PROPERTY(Media_Block_Ptr, media_block)
Packit bfcc33
  protected:
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Selector(ParserState pstate)
Packit bfcc33
    : Expression(pstate),
Packit bfcc33
      has_line_feed_(false),
Packit bfcc33
      has_line_break_(false),
Packit bfcc33
      is_optional_(false),
Packit bfcc33
      media_block_(0),
Packit bfcc33
      hash_(0)
Packit bfcc33
    { concrete_type(SELECTOR); }
Packit bfcc33
    Selector(const Selector* ptr)
Packit bfcc33
    : Expression(ptr),
Packit bfcc33
      // has_reference_(ptr->has_reference_),
Packit bfcc33
      has_line_feed_(ptr->has_line_feed_),
Packit bfcc33
      has_line_break_(ptr->has_line_break_),
Packit bfcc33
      is_optional_(ptr->is_optional_),
Packit bfcc33
      media_block_(ptr->media_block_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { concrete_type(SELECTOR); }
Packit bfcc33
    virtual ~Selector() = 0;
Packit bfcc33
    virtual size_t hash() = 0;
Packit bfcc33
    virtual unsigned long specificity() const = 0;
Packit bfcc33
    virtual void set_media_block(Media_Block_Ptr mb) {
Packit bfcc33
      media_block(mb);
Packit bfcc33
    }
Packit bfcc33
    virtual bool has_parent_ref() const {
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
    virtual bool has_real_parent_ref() const {
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
    // dispatch to correct handlers
Packit bfcc33
    virtual bool operator<(const Selector& rhs) const = 0;
Packit bfcc33
    virtual bool operator==(const Selector& rhs) const = 0;
Packit bfcc33
    ATTACH_VIRTUAL_AST_OPERATIONS(Selector);
Packit bfcc33
  };
Packit bfcc33
  inline Selector::~Selector() { }
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Interpolated selectors -- the interpolated String will be expanded and
Packit bfcc33
  // re-parsed into a normal selector class.
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Selector_Schema : public AST_Node {
Packit bfcc33
    ADD_PROPERTY(String_Obj, contents)
Packit bfcc33
    ADD_PROPERTY(bool, connect_parent);
Packit bfcc33
    // must not be a reference counted object
Packit bfcc33
    // otherwise we create circular references
Packit bfcc33
    ADD_PROPERTY(Media_Block_Ptr, media_block)
Packit bfcc33
    // store computed hash
Packit bfcc33
    size_t hash_;
Packit bfcc33
  public:
Packit bfcc33
    Selector_Schema(ParserState pstate, String_Obj c)
Packit bfcc33
    : AST_Node(pstate),
Packit bfcc33
      contents_(c),
Packit bfcc33
      connect_parent_(true),
Packit bfcc33
      media_block_(NULL),
Packit bfcc33
      hash_(0)
Packit bfcc33
    { }
Packit bfcc33
    Selector_Schema(const Selector_Schema* ptr)
Packit bfcc33
    : AST_Node(ptr),
Packit bfcc33
      contents_(ptr->contents_),
Packit bfcc33
      connect_parent_(ptr->connect_parent_),
Packit bfcc33
      media_block_(ptr->media_block_),
Packit bfcc33
      hash_(ptr->hash_)
Packit bfcc33
    { }
Packit bfcc33
    virtual bool has_parent_ref() const;
Packit bfcc33
    virtual bool has_real_parent_ref() const;
Packit bfcc33
    virtual bool operator<(const Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Selector& rhs) const;
Packit bfcc33
    // selector schema is not yet a final selector, so we do not
Packit bfcc33
    // have a specificity for it yet. We need to
Packit bfcc33
    virtual unsigned long specificity() const { return 0; }
Packit bfcc33
    virtual size_t hash() {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_combine(hash_, contents_->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Selector_Schema)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////
Packit bfcc33
  // Abstract base class for simple selectors.
Packit bfcc33
  ////////////////////////////////////////////
Packit bfcc33
  class Simple_Selector : public Selector {
Packit bfcc33
    ADD_CONSTREF(std::string, ns)
Packit bfcc33
    ADD_CONSTREF(std::string, name)
Packit bfcc33
    ADD_PROPERTY(Simple_Type, simple_type)
Packit bfcc33
    ADD_PROPERTY(bool, has_ns)
Packit bfcc33
  public:
Packit bfcc33
    Simple_Selector(ParserState pstate, std::string n = "")
Packit bfcc33
    : Selector(pstate), ns_(""), name_(n), has_ns_(false)
Packit bfcc33
    {
Packit bfcc33
      simple_type(SIMPLE);
Packit bfcc33
      size_t pos = n.find('|');
Packit bfcc33
      // found some namespace
Packit bfcc33
      if (pos != std::string::npos) {
Packit bfcc33
        has_ns_ = true;
Packit bfcc33
        ns_ = n.substr(0, pos);
Packit bfcc33
        name_ = n.substr(pos + 1);
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    Simple_Selector(const Simple_Selector* ptr)
Packit bfcc33
    : Selector(ptr),
Packit bfcc33
      ns_(ptr->ns_),
Packit bfcc33
      name_(ptr->name_),
Packit bfcc33
      has_ns_(ptr->has_ns_)
Packit bfcc33
    { simple_type(SIMPLE); }
Packit bfcc33
    virtual std::string ns_name() const
Packit bfcc33
    {
Packit bfcc33
      std::string name("");
Packit bfcc33
      if (has_ns_)
Packit bfcc33
        name += ns_ + "|";
Packit bfcc33
      return name + name_;
Packit bfcc33
    }
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_combine(hash_, std::hash<int>()(SELECTOR));
Packit bfcc33
        hash_combine(hash_, std::hash<std::string>()(ns()));
Packit bfcc33
        hash_combine(hash_, std::hash<std::string>()(name()));
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
    // namespace compare functions
Packit bfcc33
    bool is_ns_eq(const Simple_Selector& r) const;
Packit bfcc33
    // namespace query functions
Packit bfcc33
    bool is_universal_ns() const
Packit bfcc33
    {
Packit bfcc33
      return has_ns_ && ns_ == "*";
Packit bfcc33
    }
Packit bfcc33
    bool has_universal_ns() const
Packit bfcc33
    {
Packit bfcc33
      return !has_ns_ || ns_ == "*";
Packit bfcc33
    }
Packit bfcc33
    bool is_empty_ns() const
Packit bfcc33
    {
Packit bfcc33
      return !has_ns_ || ns_ == "";
Packit bfcc33
    }
Packit bfcc33
    bool has_empty_ns() const
Packit bfcc33
    {
Packit bfcc33
      return has_ns_ && ns_ == "";
Packit bfcc33
    }
Packit bfcc33
    bool has_qualified_ns() const
Packit bfcc33
    {
Packit bfcc33
      return has_ns_ && ns_ != "" && ns_ != "*";
Packit bfcc33
    }
Packit bfcc33
    // name query functions
Packit bfcc33
    bool is_universal() const
Packit bfcc33
    {
Packit bfcc33
      return name_ == "*";
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool has_placeholder() {
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual ~Simple_Selector() = 0;
Packit bfcc33
    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
Packit bfcc33
    virtual bool has_parent_ref() const { return false; };
Packit bfcc33
    virtual bool has_real_parent_ref() const  { return false; };
Packit bfcc33
    virtual bool is_pseudo_element() const { return false; }
Packit bfcc33
Packit bfcc33
    virtual bool is_superselector_of(Compound_Selector_Obj sub) { return false; }
Packit bfcc33
Packit bfcc33
    virtual bool operator==(const Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Simple_Selector& rhs) const;
Packit bfcc33
    inline bool operator!=(const Simple_Selector& rhs) const { return !(*this == rhs); }
Packit bfcc33
Packit bfcc33
    bool operator<(const Selector& rhs) const;
Packit bfcc33
    bool operator<(const Simple_Selector& rhs) const;
Packit bfcc33
    // default implementation should work for most of the simple selectors (otherwise overload)
Packit bfcc33
    ATTACH_VIRTUAL_AST_OPERATIONS(Simple_Selector);
Packit bfcc33
    ATTACH_OPERATIONS();
Packit bfcc33
  };
Packit bfcc33
  inline Simple_Selector::~Simple_Selector() { }
Packit bfcc33
Packit bfcc33
Packit bfcc33
  //////////////////////////////////
Packit bfcc33
  // The Parent Selector Expression.
Packit bfcc33
  //////////////////////////////////
Packit bfcc33
  // parent selectors can occur in selectors but also
Packit bfcc33
  // inside strings in declarations (Compound_Selector).
Packit bfcc33
  // only one simple parent selector means the first case.
Packit bfcc33
  class Parent_Selector : public Simple_Selector {
Packit bfcc33
    ADD_PROPERTY(bool, real)
Packit bfcc33
  public:
Packit bfcc33
    Parent_Selector(ParserState pstate, bool r = true)
Packit bfcc33
    : Simple_Selector(pstate, "&"), real_(r)
Packit bfcc33
    { /* has_reference(true); */ }
Packit bfcc33
    Parent_Selector(const Parent_Selector* ptr)
Packit bfcc33
    : Simple_Selector(ptr), real_(ptr->real_)
Packit bfcc33
    { /* has_reference(true); */ }
Packit bfcc33
    bool is_real_parent_ref() const { return real(); };
Packit bfcc33
    virtual bool has_parent_ref() const { return true; };
Packit bfcc33
    virtual bool has_real_parent_ref() const { return is_real_parent_ref(); };
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      return 0;
Packit bfcc33
    }
Packit bfcc33
    std::string type() const { return "selector"; }
Packit bfcc33
    static std::string type_name() { return "selector"; }
Packit bfcc33
    ATTACH_AST_OPERATIONS(Parent_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Placeholder selectors (e.g., "%foo") for use in extend-only selectors.
Packit bfcc33
  /////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Placeholder_Selector : public Simple_Selector {
Packit bfcc33
  public:
Packit bfcc33
    Placeholder_Selector(ParserState pstate, std::string n)
Packit bfcc33
    : Simple_Selector(pstate, n)
Packit bfcc33
    { }
Packit bfcc33
    Placeholder_Selector(const Placeholder_Selector* ptr)
Packit bfcc33
    : Simple_Selector(ptr)
Packit bfcc33
    { }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      return Constants::Specificity_Base;
Packit bfcc33
    }
Packit bfcc33
    virtual bool has_placeholder() {
Packit bfcc33
      return true;
Packit bfcc33
    }
Packit bfcc33
    virtual ~Placeholder_Selector() {};
Packit bfcc33
    ATTACH_AST_OPERATIONS(Placeholder_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Element selectors (and the universal selector) -- e.g., div, span, *.
Packit bfcc33
  /////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Element_Selector : public Simple_Selector {
Packit bfcc33
  public:
Packit bfcc33
    Element_Selector(ParserState pstate, std::string n)
Packit bfcc33
    : Simple_Selector(pstate, n)
Packit bfcc33
    { }
Packit bfcc33
    Element_Selector(const Element_Selector* ptr)
Packit bfcc33
    : Simple_Selector(ptr)
Packit bfcc33
    { }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      if (name() == "*") return 0;
Packit bfcc33
      else               return Constants::Specificity_Element;
Packit bfcc33
    }
Packit bfcc33
    virtual Simple_Selector_Ptr unify_with(Simple_Selector_Ptr);
Packit bfcc33
    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
Packit bfcc33
    virtual bool operator==(const Simple_Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Element_Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Simple_Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Element_Selector& rhs) const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Element_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////
Packit bfcc33
  // Class selectors  -- i.e., .foo.
Packit bfcc33
  ////////////////////////////////////////////////
Packit bfcc33
  class Class_Selector : public Simple_Selector {
Packit bfcc33
  public:
Packit bfcc33
    Class_Selector(ParserState pstate, std::string n)
Packit bfcc33
    : Simple_Selector(pstate, n)
Packit bfcc33
    { }
Packit bfcc33
    Class_Selector(const Class_Selector* ptr)
Packit bfcc33
    : Simple_Selector(ptr)
Packit bfcc33
    { }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      return Constants::Specificity_Class;
Packit bfcc33
    }
Packit bfcc33
    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
Packit bfcc33
    ATTACH_AST_OPERATIONS(Class_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////
Packit bfcc33
  // ID selectors -- i.e., #foo.
Packit bfcc33
  ////////////////////////////////////////////////
Packit bfcc33
  class Id_Selector : public Simple_Selector {
Packit bfcc33
  public:
Packit bfcc33
    Id_Selector(ParserState pstate, std::string n)
Packit bfcc33
    : Simple_Selector(pstate, n)
Packit bfcc33
    { }
Packit bfcc33
    Id_Selector(const Id_Selector* ptr)
Packit bfcc33
    : Simple_Selector(ptr)
Packit bfcc33
    { }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      return Constants::Specificity_ID;
Packit bfcc33
    }
Packit bfcc33
    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
Packit bfcc33
    ATTACH_AST_OPERATIONS(Id_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////////////////////
Packit bfcc33
  // Attribute selectors -- e.g., [src*=".jpg"], etc.
Packit bfcc33
  ///////////////////////////////////////////////////
Packit bfcc33
  class Attribute_Selector : public Simple_Selector {
Packit bfcc33
    ADD_CONSTREF(std::string, matcher)
Packit bfcc33
    // this cannot be changed to obj atm!!!!!!????!!!!!!!
Packit bfcc33
    ADD_PROPERTY(String_Obj, value) // might be interpolated
Packit bfcc33
  public:
Packit bfcc33
    Attribute_Selector(ParserState pstate, std::string n, std::string m, String_Obj v)
Packit bfcc33
    : Simple_Selector(pstate, n), matcher_(m), value_(v)
Packit bfcc33
    { simple_type(ATTR_SEL); }
Packit bfcc33
    Attribute_Selector(const Attribute_Selector* ptr)
Packit bfcc33
    : Simple_Selector(ptr),
Packit bfcc33
      matcher_(ptr->matcher_),
Packit bfcc33
      value_(ptr->value_)
Packit bfcc33
    { simple_type(ATTR_SEL); }
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_combine(hash_, Simple_Selector::hash());
Packit bfcc33
        hash_combine(hash_, std::hash<std::string>()(matcher()));
Packit bfcc33
        if (value_) hash_combine(hash_, value_->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      return Constants::Specificity_Attr;
Packit bfcc33
    }
Packit bfcc33
    virtual bool operator==(const Simple_Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Attribute_Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Simple_Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Attribute_Selector& rhs) const;
Packit bfcc33
    ATTACH_AST_OPERATIONS(Attribute_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  //////////////////////////////////////////////////////////////////
Packit bfcc33
  // Pseudo selectors -- e.g., :first-child, :nth-of-type(...), etc.
Packit bfcc33
  //////////////////////////////////////////////////////////////////
Packit bfcc33
  /* '::' starts a pseudo-element, ':' a pseudo-class */
Packit bfcc33
  /* Except :first-line, :first-letter, :before and :after */
Packit bfcc33
  /* Note that pseudo-elements are restricted to one per selector */
Packit bfcc33
  /* and occur only in the last simple_selector_sequence. */
Packit bfcc33
  inline bool is_pseudo_class_element(const std::string& name)
Packit bfcc33
  {
Packit bfcc33
    return name == ":before"       ||
Packit bfcc33
           name == ":after"        ||
Packit bfcc33
           name == ":first-line"   ||
Packit bfcc33
           name == ":first-letter";
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  // Pseudo Selector cannot have any namespace?
Packit bfcc33
  class Pseudo_Selector : public Simple_Selector {
Packit bfcc33
    ADD_PROPERTY(String_Obj, expression)
Packit bfcc33
  public:
Packit bfcc33
    Pseudo_Selector(ParserState pstate, std::string n, String_Obj expr = 0)
Packit bfcc33
    : Simple_Selector(pstate, n), expression_(expr)
Packit bfcc33
    { simple_type(PSEUDO_SEL); }
Packit bfcc33
    Pseudo_Selector(const Pseudo_Selector* ptr)
Packit bfcc33
    : Simple_Selector(ptr), expression_(ptr->expression_)
Packit bfcc33
    { simple_type(PSEUDO_SEL); }
Packit bfcc33
Packit bfcc33
    // A pseudo-element is made of two colons (::) followed by the name.
Packit bfcc33
    // The `::` notation is introduced by the current document in order to
Packit bfcc33
    // establish a discrimination between pseudo-classes and pseudo-elements.
Packit bfcc33
    // For compatibility with existing style sheets, user agents must also
Packit bfcc33
    // accept the previous one-colon notation for pseudo-elements introduced
Packit bfcc33
    // in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and
Packit bfcc33
    // :after). This compatibility is not allowed for the new pseudo-elements
Packit bfcc33
    // introduced in this specification.
Packit bfcc33
    virtual bool is_pseudo_element() const
Packit bfcc33
    {
Packit bfcc33
      return (name_[0] == ':' && name_[1] == ':')
Packit bfcc33
             || is_pseudo_class_element(name_);
Packit bfcc33
    }
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_combine(hash_, Simple_Selector::hash());
Packit bfcc33
        if (expression_) hash_combine(hash_, expression_->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      if (is_pseudo_element())
Packit bfcc33
        return Constants::Specificity_Element;
Packit bfcc33
      return Constants::Specificity_Pseudo;
Packit bfcc33
    }
Packit bfcc33
    virtual bool operator==(const Simple_Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Pseudo_Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Simple_Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Pseudo_Selector& rhs) const;
Packit bfcc33
    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
Packit bfcc33
    ATTACH_AST_OPERATIONS(Pseudo_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  /////////////////////////////////////////////////
Packit bfcc33
  // Wrapped selector -- pseudo selector that takes a list of selectors as argument(s) e.g., :not(:first-of-type), :-moz-any(ol p.blah, ul, menu, dir)
Packit bfcc33
  /////////////////////////////////////////////////
Packit bfcc33
  class Wrapped_Selector : public Simple_Selector {
Packit bfcc33
    ADD_PROPERTY(Selector_List_Obj, selector)
Packit bfcc33
  public:
Packit bfcc33
    Wrapped_Selector(ParserState pstate, std::string n, Selector_List_Obj sel)
Packit bfcc33
    : Simple_Selector(pstate, n), selector_(sel)
Packit bfcc33
    { simple_type(WRAPPED_SEL); }
Packit bfcc33
    Wrapped_Selector(const Wrapped_Selector* ptr)
Packit bfcc33
    : Simple_Selector(ptr), selector_(ptr->selector_)
Packit bfcc33
    { simple_type(WRAPPED_SEL); }
Packit bfcc33
    virtual bool is_superselector_of(Wrapped_Selector_Obj sub);
Packit bfcc33
    // Selectors inside the negation pseudo-class are counted like any
Packit bfcc33
    // other, but the negation itself does not count as a pseudo-class.
Packit bfcc33
    virtual size_t hash();
Packit bfcc33
    virtual bool has_parent_ref() const;
Packit bfcc33
    virtual bool has_real_parent_ref() const;
Packit bfcc33
    virtual unsigned long specificity() const;
Packit bfcc33
    virtual bool find ( bool (*f)(AST_Node_Obj) );
Packit bfcc33
    virtual bool operator==(const Simple_Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Wrapped_Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Simple_Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Wrapped_Selector& rhs) const;
Packit bfcc33
    virtual void cloneChildren();
Packit bfcc33
    ATTACH_AST_OPERATIONS(Wrapped_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // Simple selector sequences. Maintains flags indicating whether it contains
Packit bfcc33
  // any parent references or placeholders, to simplify expansion.
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Compound_Selector : public Selector, public Vectorized<Simple_Selector_Obj> {
Packit bfcc33
  private:
Packit bfcc33
    ComplexSelectorSet sources_;
Packit bfcc33
    ADD_PROPERTY(bool, extended);
Packit bfcc33
    ADD_PROPERTY(bool, has_parent_reference);
Packit bfcc33
  protected:
Packit bfcc33
    void adjust_after_pushing(Simple_Selector_Obj s)
Packit bfcc33
    {
Packit bfcc33
      // if (s->has_reference())   has_reference(true);
Packit bfcc33
      // if (s->has_placeholder()) has_placeholder(true);
Packit bfcc33
    }
Packit bfcc33
  public:
Packit bfcc33
    Compound_Selector(ParserState pstate, size_t s = 0)
Packit bfcc33
    : Selector(pstate),
Packit bfcc33
      Vectorized<Simple_Selector_Obj>(s),
Packit bfcc33
      extended_(false),
Packit bfcc33
      has_parent_reference_(false)
Packit bfcc33
    { }
Packit bfcc33
    Compound_Selector(const Compound_Selector* ptr)
Packit bfcc33
    : Selector(ptr),
Packit bfcc33
      Vectorized<Simple_Selector_Obj>(*ptr),
Packit bfcc33
      extended_(ptr->extended_),
Packit bfcc33
      has_parent_reference_(ptr->has_parent_reference_)
Packit bfcc33
    { }
Packit bfcc33
    bool contains_placeholder() {
Packit bfcc33
      for (size_t i = 0, L = length(); i < L; ++i) {
Packit bfcc33
        if ((*this)[i]->has_placeholder()) return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
    };
Packit bfcc33
Packit bfcc33
    void append(Simple_Selector_Ptr element);
Packit bfcc33
Packit bfcc33
    bool is_universal() const
Packit bfcc33
    {
Packit bfcc33
      return length() == 1 && (*this)[0]->is_universal();
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    Complex_Selector_Obj to_complex();
Packit bfcc33
    Compound_Selector_Ptr unify_with(Compound_Selector_Ptr rhs);
Packit bfcc33
    // virtual Placeholder_Selector_Ptr find_placeholder();
Packit bfcc33
    virtual bool has_parent_ref() const;
Packit bfcc33
    virtual bool has_real_parent_ref() const;
Packit bfcc33
    Simple_Selector_Ptr base() const {
Packit bfcc33
      if (length() == 0) return 0;
Packit bfcc33
      // ToDo: why is this needed?
Packit bfcc33
      if (Cast<Element_Selector>((*this)[0]))
Packit bfcc33
        return (*this)[0];
Packit bfcc33
      return 0;
Packit bfcc33
    }
Packit bfcc33
    virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapped = "");
Packit bfcc33
    virtual bool is_superselector_of(Complex_Selector_Obj sub, std::string wrapped = "");
Packit bfcc33
    virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapped = "");
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (Selector::hash_ == 0) {
Packit bfcc33
        hash_combine(Selector::hash_, std::hash<int>()(SELECTOR));
Packit bfcc33
        if (length()) hash_combine(Selector::hash_, Vectorized::hash());
Packit bfcc33
      }
Packit bfcc33
      return Selector::hash_;
Packit bfcc33
    }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      int sum = 0;
Packit bfcc33
      for (size_t i = 0, L = length(); i < L; ++i)
Packit bfcc33
      { sum += (*this)[i]->specificity(); }
Packit bfcc33
      return sum;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool has_placeholder()
Packit bfcc33
    {
Packit bfcc33
      if (length() == 0) return false;
Packit bfcc33
      if (Simple_Selector_Obj ss = elements().front()) {
Packit bfcc33
        if (ss->has_placeholder()) return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    bool is_empty_reference()
Packit bfcc33
    {
Packit bfcc33
      return length() == 1 &&
Packit bfcc33
             Cast<Parent_Selector>((*this)[0]);
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual bool find ( bool (*f)(AST_Node_Obj) );
Packit bfcc33
    virtual bool operator<(const Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Compound_Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Compound_Selector& rhs) const;
Packit bfcc33
    inline bool operator!=(const Compound_Selector& rhs) const { return !(*this == rhs); }
Packit bfcc33
Packit bfcc33
    ComplexSelectorSet& sources() { return sources_; }
Packit bfcc33
    void clearSources() { sources_.clear(); }
Packit bfcc33
    void mergeSources(ComplexSelectorSet& sources);
Packit bfcc33
Packit bfcc33
    Compound_Selector_Ptr minus(Compound_Selector_Ptr rhs);
Packit bfcc33
    virtual void cloneChildren();
Packit bfcc33
    ATTACH_AST_OPERATIONS(Compound_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  // General selectors -- i.e., simple sequences combined with one of the four
Packit bfcc33
  // CSS selector combinators (">", "+", "~", and whitespace). Essentially a
Packit bfcc33
  // linked list.
Packit bfcc33
  ////////////////////////////////////////////////////////////////////////////
Packit bfcc33
  class Complex_Selector : public Selector {
Packit bfcc33
  public:
Packit bfcc33
    enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO, REFERENCE };
Packit bfcc33
  private:
Packit bfcc33
    HASH_CONSTREF(Combinator, combinator)
Packit bfcc33
    HASH_PROPERTY(Compound_Selector_Obj, head)
Packit bfcc33
    HASH_PROPERTY(Complex_Selector_Obj, tail)
Packit bfcc33
    HASH_PROPERTY(String_Obj, reference);
Packit bfcc33
  public:
Packit bfcc33
    bool contains_placeholder() {
Packit bfcc33
      if (head() && head()->contains_placeholder()) return true;
Packit bfcc33
      if (tail() && tail()->contains_placeholder()) return true;
Packit bfcc33
      return false;
Packit bfcc33
    };
Packit bfcc33
    Complex_Selector(ParserState pstate,
Packit bfcc33
                     Combinator c = ANCESTOR_OF,
Packit bfcc33
                     Compound_Selector_Obj h = 0,
Packit bfcc33
                     Complex_Selector_Obj t = 0,
Packit bfcc33
                     String_Obj r = 0)
Packit bfcc33
    : Selector(pstate),
Packit bfcc33
      combinator_(c),
Packit bfcc33
      head_(h), tail_(t),
Packit bfcc33
      reference_(r)
Packit bfcc33
    {}
Packit bfcc33
    Complex_Selector(const Complex_Selector* ptr)
Packit bfcc33
    : Selector(ptr),
Packit bfcc33
      combinator_(ptr->combinator_),
Packit bfcc33
      head_(ptr->head_), tail_(ptr->tail_),
Packit bfcc33
      reference_(ptr->reference_)
Packit bfcc33
    {};
Packit bfcc33
    virtual bool has_parent_ref() const;
Packit bfcc33
    virtual bool has_real_parent_ref() const;
Packit bfcc33
Packit bfcc33
    Complex_Selector_Obj skip_empty_reference()
Packit bfcc33
    {
Packit bfcc33
      if ((!head_ || !head_->length() || head_->is_empty_reference()) &&
Packit bfcc33
          combinator() == Combinator::ANCESTOR_OF)
Packit bfcc33
      {
Packit bfcc33
        if (!tail_) return 0;
Packit bfcc33
        tail_->has_line_feed_ = this->has_line_feed_;
Packit bfcc33
        // tail_->has_line_break_ = this->has_line_break_;
Packit bfcc33
        return tail_->skip_empty_reference();
Packit bfcc33
      }
Packit bfcc33
      return this;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    // can still have a tail
Packit bfcc33
    bool is_empty_ancestor() const
Packit bfcc33
    {
Packit bfcc33
      return (!head() || head()->length() == 0) &&
Packit bfcc33
             combinator() == Combinator::ANCESTOR_OF;
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    Selector_List_Ptr tails(Selector_List_Ptr tails);
Packit bfcc33
Packit bfcc33
    // front returns the first real tail
Packit bfcc33
    // skips over parent and empty ones
Packit bfcc33
    Complex_Selector_Obj first();
Packit bfcc33
    // last returns the last real tail
Packit bfcc33
    Complex_Selector_Obj last();
Packit bfcc33
Packit bfcc33
    // some shortcuts that should be removed
Packit bfcc33
    Complex_Selector_Obj innermost() { return last(); };
Packit bfcc33
Packit bfcc33
    size_t length() const;
Packit bfcc33
    Selector_List_Ptr resolve_parent_refs(std::vector<Selector_List_Obj>& pstack, bool implicit_parent = true);
Packit bfcc33
    virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapping = "");
Packit bfcc33
    virtual bool is_superselector_of(Complex_Selector_Obj sub, std::string wrapping = "");
Packit bfcc33
    virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapping = "");
Packit bfcc33
    Selector_List_Ptr unify_with(Complex_Selector_Ptr rhs);
Packit bfcc33
    Combinator clear_innermost();
Packit bfcc33
    void append(Complex_Selector_Obj);
Packit bfcc33
    void set_innermost(Complex_Selector_Obj, Combinator);
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (hash_ == 0) {
Packit bfcc33
        hash_combine(hash_, std::hash<int>()(SELECTOR));
Packit bfcc33
        hash_combine(hash_, std::hash<int>()(combinator_));
Packit bfcc33
        if (head_) hash_combine(hash_, head_->hash());
Packit bfcc33
        if (tail_) hash_combine(hash_, tail_->hash());
Packit bfcc33
      }
Packit bfcc33
      return hash_;
Packit bfcc33
    }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      int sum = 0;
Packit bfcc33
      if (head()) sum += head()->specificity();
Packit bfcc33
      if (tail()) sum += tail()->specificity();
Packit bfcc33
      return sum;
Packit bfcc33
    }
Packit bfcc33
    virtual void set_media_block(Media_Block_Ptr mb) {
Packit bfcc33
      media_block(mb);
Packit bfcc33
      if (tail_) tail_->set_media_block(mb);
Packit bfcc33
      if (head_) head_->set_media_block(mb);
Packit bfcc33
    }
Packit bfcc33
    virtual bool has_placeholder() {
Packit bfcc33
      if (head_ && head_->has_placeholder()) return true;
Packit bfcc33
      if (tail_ && tail_->has_placeholder()) return true;
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
    virtual bool find ( bool (*f)(AST_Node_Obj) );
Packit bfcc33
    virtual bool operator<(const Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Complex_Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Complex_Selector& rhs) const;
Packit bfcc33
    inline bool operator!=(const Complex_Selector& rhs) const { return !(*this == rhs); }
Packit bfcc33
    const ComplexSelectorSet sources()
Packit bfcc33
    {
Packit bfcc33
      //s = Set.new
Packit bfcc33
      //seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)}
Packit bfcc33
      //s
Packit bfcc33
Packit bfcc33
      ComplexSelectorSet srcs;
Packit bfcc33
Packit bfcc33
      Compound_Selector_Obj pHead = head();
Packit bfcc33
      Complex_Selector_Obj  pTail = tail();
Packit bfcc33
Packit bfcc33
      if (pHead) {
Packit bfcc33
        const ComplexSelectorSet& headSources = pHead->sources();
Packit bfcc33
        srcs.insert(headSources.begin(), headSources.end());
Packit bfcc33
      }
Packit bfcc33
Packit bfcc33
      if (pTail) {
Packit bfcc33
        const ComplexSelectorSet& tailSources = pTail->sources();
Packit bfcc33
        srcs.insert(tailSources.begin(), tailSources.end());
Packit bfcc33
      }
Packit bfcc33
Packit bfcc33
      return srcs;
Packit bfcc33
    }
Packit bfcc33
    void addSources(ComplexSelectorSet& sources) {
Packit bfcc33
      // members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m}
Packit bfcc33
      Complex_Selector_Ptr pIter = this;
Packit bfcc33
      while (pIter) {
Packit bfcc33
        Compound_Selector_Ptr pHead = pIter->head();
Packit bfcc33
Packit bfcc33
        if (pHead) {
Packit bfcc33
          pHead->mergeSources(sources);
Packit bfcc33
        }
Packit bfcc33
Packit bfcc33
        pIter = pIter->tail();
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    void clearSources() {
Packit bfcc33
      Complex_Selector_Ptr pIter = this;
Packit bfcc33
      while (pIter) {
Packit bfcc33
        Compound_Selector_Ptr pHead = pIter->head();
Packit bfcc33
Packit bfcc33
        if (pHead) {
Packit bfcc33
          pHead->clearSources();
Packit bfcc33
        }
Packit bfcc33
Packit bfcc33
        pIter = pIter->tail();
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
Packit bfcc33
    virtual void cloneChildren();
Packit bfcc33
    ATTACH_AST_OPERATIONS(Complex_Selector)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  ///////////////////////////////////
Packit bfcc33
  // Comma-separated selector groups.
Packit bfcc33
  ///////////////////////////////////
Packit bfcc33
  class Selector_List : public Selector, public Vectorized<Complex_Selector_Obj> {
Packit bfcc33
    ADD_PROPERTY(Selector_Schema_Obj, schema)
Packit bfcc33
    ADD_CONSTREF(std::vector<std::string>, wspace)
Packit bfcc33
  protected:
Packit bfcc33
    void adjust_after_pushing(Complex_Selector_Obj c);
Packit bfcc33
  public:
Packit bfcc33
    Selector_List(ParserState pstate, size_t s = 0)
Packit bfcc33
    : Selector(pstate),
Packit bfcc33
      Vectorized<Complex_Selector_Obj>(s),
Packit bfcc33
      schema_(NULL),
Packit bfcc33
      wspace_(0)
Packit bfcc33
    { }
Packit bfcc33
    Selector_List(const Selector_List* ptr)
Packit bfcc33
    : Selector(ptr),
Packit bfcc33
      Vectorized<Complex_Selector_Obj>(*ptr),
Packit bfcc33
      schema_(ptr->schema_),
Packit bfcc33
      wspace_(ptr->wspace_)
Packit bfcc33
    { }
Packit bfcc33
    std::string type() const { return "list"; }
Packit bfcc33
    // remove parent selector references
Packit bfcc33
    // basically unwraps parsed selectors
Packit bfcc33
    virtual bool has_parent_ref() const;
Packit bfcc33
    virtual bool has_real_parent_ref() const;
Packit bfcc33
    void remove_parent_selectors();
Packit bfcc33
    Selector_List_Ptr resolve_parent_refs(std::vector<Selector_List_Obj>& pstack, bool implicit_parent = true);
Packit bfcc33
    virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapping = "");
Packit bfcc33
    virtual bool is_superselector_of(Complex_Selector_Obj sub, std::string wrapping = "");
Packit bfcc33
    virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapping = "");
Packit bfcc33
    Selector_List_Ptr unify_with(Selector_List_Ptr);
Packit bfcc33
    void populate_extends(Selector_List_Obj, Subset_Map&);
Packit bfcc33
    Selector_List_Obj eval(Eval& eval);
Packit bfcc33
    virtual size_t hash()
Packit bfcc33
    {
Packit bfcc33
      if (Selector::hash_ == 0) {
Packit bfcc33
        hash_combine(Selector::hash_, std::hash<int>()(SELECTOR));
Packit bfcc33
        hash_combine(Selector::hash_, Vectorized::hash());
Packit bfcc33
      }
Packit bfcc33
      return Selector::hash_;
Packit bfcc33
    }
Packit bfcc33
    virtual unsigned long specificity() const
Packit bfcc33
    {
Packit bfcc33
      unsigned long sum = 0;
Packit bfcc33
      unsigned long specificity;
Packit bfcc33
      for (size_t i = 0, L = length(); i < L; ++i)
Packit bfcc33
      {
Packit bfcc33
        specificity = (*this)[i]->specificity();
Packit bfcc33
        if (sum < specificity) sum = specificity;
Packit bfcc33
      }
Packit bfcc33
      return sum;
Packit bfcc33
    }
Packit bfcc33
    virtual void set_media_block(Media_Block_Ptr mb) {
Packit bfcc33
      media_block(mb);
Packit bfcc33
      for (Complex_Selector_Obj cs : elements()) {
Packit bfcc33
        cs->set_media_block(mb);
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    virtual bool has_placeholder() {
Packit bfcc33
      for (Complex_Selector_Obj cs : elements()) {
Packit bfcc33
        if (cs->has_placeholder()) return true;
Packit bfcc33
      }
Packit bfcc33
      return false;
Packit bfcc33
    }
Packit bfcc33
    virtual bool find ( bool (*f)(AST_Node_Obj) );
Packit bfcc33
    virtual bool operator<(const Selector& rhs) const;
Packit bfcc33
    virtual bool operator==(const Selector& rhs) const;
Packit bfcc33
    virtual bool operator<(const Selector_List& rhs) const;
Packit bfcc33
    virtual bool operator==(const Selector_List& rhs) const;
Packit bfcc33
    // Selector Lists can be compared to comma lists
Packit bfcc33
    virtual bool operator==(const Expression& rhs) const;
Packit bfcc33
    virtual void cloneChildren();
Packit bfcc33
    ATTACH_AST_OPERATIONS(Selector_List)
Packit bfcc33
    ATTACH_OPERATIONS()
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  // compare function for sorting and probably other other uses
Packit bfcc33
  struct cmp_complex_selector { inline bool operator() (const Complex_Selector_Obj l, const Complex_Selector_Obj r) { return (*l < *r); } };
Packit bfcc33
  struct cmp_compound_selector { inline bool operator() (const Compound_Selector_Obj l, const Compound_Selector_Obj r) { return (*l < *r); } };
Packit bfcc33
  struct cmp_simple_selector { inline bool operator() (const Simple_Selector_Obj l, const Simple_Selector_Obj r) { return (*l < *r); } };
Packit bfcc33
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
#ifdef __clang__
Packit bfcc33
Packit bfcc33
#pragma clang diagnostic pop
Packit bfcc33
Packit bfcc33
#endif
Packit bfcc33
Packit bfcc33
#endif