The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#define SASS_AST

#define ATTACH_OPERATION(type) \
virtual type perform(Operation<type>* op) { return (*op)(this); }

#define ADD_PROPERTY(type, name)\
private:\
  type name##_;\
public:\
  type name() const        { return name##_; }\
  type name(type name##__) { return name##_ = name##__; }\
private:

#include <string>
#include <sstream>
#include <vector>

#ifndef SASS_OPERATION
#include "operation.hpp"
#endif

namespace Sass {
  using namespace std;

  //////////////////////////////////////////////////////////
  // Abstract base class for all abstract syntax tree nodes.
  //////////////////////////////////////////////////////////
  struct AST_Node {
    string path;
    size_t line;

    AST_Node(string p, size_t l) : path(p), line(l) { }
    virtual ~AST_Node() = 0;
    ATTACH_OPERATIONS();
  };
  inline AST_Node::~AST_Node() { }

  /////////////////////////////////////////////////////////////////////////
  // Abstract base class for statements. This side of the AST hierarchy
  // represents elements in expansion contexts, which exist primarily to be
  // rewritten and macro-expanded.
  /////////////////////////////////////////////////////////////////////////
  struct Statement : public AST_Node {
    Statement(string p, size_t l)
    : AST_Node(p, l) { }
    virtual ~Statement() = 0;
    // needed for rearranging nested rulesets during CSS emission
    virtual bool hoistable() { return false; }
  };
  inline Statement::~Statement() { }

  ////////////////////////
  // Blocks of statements.
  ////////////////////////
  struct Block : public Statement {
    vector<Statement*> statements;
    bool               is_root;
    // needed for properly formatted CSS emission
    bool               has_hoistable;
    bool               has_non_hoistable;

    Block(string p, size_t l, size_t size = 0, bool root = false)
    : Statement(p, l), statements(vector<Statement*>()), is_root(root)
    { statements.reserve(size); }

    size_t length() const
    { return statements.size(); }
    Statement*& operator[](size_t i)
    { return statements[i]; }
    Block& operator<<(Statement* s)
    {
      statements.push_back(s);
      if (s->hoistable()) has_hoistable     = true;
      else                has_non_hoistable = true;
      return *this;
    }
    Block& operator+=(Block* b)
    {
      for (size_t i = 0, L = b->length(); i < L; ++i) *this << (*b)[i];
      return *this;
    }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////////////////
  // Abstract base class for statements that contain blocks of statements.
  ////////////////////////////////////////////////////////////////////////
  struct Has_Block : public Statement {
    Block* block;
    Has_Block(string p, size_t l, Block* b)
    : Statement(p, l), block(b)
    { }
    virtual ~Has_Block() = 0;
  };
  inline Has_Block::~Has_Block() { }

  /////////////////////////////////////////////////////////////////////////////
  // Rulesets (i.e., sets of styles headed by a selector and containing a block
  // of style declarations.
  /////////////////////////////////////////////////////////////////////////////
  struct Selector;
  struct Ruleset : public Has_Block {
    Selector* selector;

    Ruleset(string p, size_t l, Selector* s, Block* b)
    : Has_Block(p, l, b), selector(s)
    { }
    // nested rulesets need to be hoisted out of their enclosing blocks
    bool hoistable() { return true; }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////////////////////
  // Nested declaration sets (i.e., namespaced properties).
  /////////////////////////////////////////////////////////
  struct String;
  struct Propset : public Has_Block {
    String* property_fragment;

    Propset(string p, size_t l, String* pf, Block* b)
    : Has_Block(p, l, b), property_fragment(pf)
    { }
    ATTACH_OPERATIONS();
  };

  /////////////////
  // Media queries.
  /////////////////
  struct List;
  struct Media_Query : public Has_Block {
    List* query_list;

    Media_Query(string p, size_t l, List* q, Block* b)
    : Has_Block(p, l, b), query_list(q)
    { }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////////////////////////////////////////
  // Directives -- arbitrary rules beginning with "@" that may have an optional
  // statement block.
  /////////////////////////////////////////////////////////////////////////////
  struct Directive : public Has_Block {
    string    keyword;
    Selector* selector;

    Directive(string p, size_t l,
              string kwd, Selector* sel, Block* b)
    : Has_Block(p, l, b), keyword(kwd), selector(sel)
    { }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////////////////
  // Declarations -- style rules consisting of a property name and values.
  ////////////////////////////////////////////////////////////////////////
  struct Declaration : public Statement {
    String* property;
    List*   values;

    Declaration(string p, size_t l, String* prop, List* vals)
    : Statement(p, l), property(prop), values(vals)
    { }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////
  // Assignments -- variable and value.
  /////////////////////////////////////
  struct Variable;
  struct Expression;
  struct Assignment : public Statement {
    string variable;
    Expression* value;
    bool   is_guarded;

    Assignment(string p, size_t l,
               string var, Expression* val, bool guarded = false)
    : Statement(p, l), variable(var), value(val), is_guarded(guarded)
    { }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////////////////////////////////////////
  // CSS import directives. CSS url imports need to be distinguished from Sass
  // file imports. T should be instantiated with Function_Call or String.
  /////////////////////////////////////////////////////////////////////////////
  template <typename T>
  struct Import : public Statement {
    T* location;

    Import(string p, size_t l, T* loc)
    : Statement(p, l), location(loc)
    { }
    ATTACH_OPERATIONS();
  };

  //////////////////////////////
  // The Sass `@warn` directive.
  //////////////////////////////
  struct Warning : public Statement {
    Expression* message;

    Warning(string p, size_t l, Expression* msg)
    : Statement(p, l), message(msg)
    { }
    ATTACH_OPERATIONS();
  };

  ///////////////////////////////////////////
  // CSS comments. These may be interpolated.
  ///////////////////////////////////////////
  struct Comment : public Statement {
    String* text;

    Comment(string p, size_t l, String* txt)
    : Statement(p, l), text(txt)
    { }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////
  // The Sass `@if` control directive.
  ////////////////////////////////////
  struct If : public Statement {
    Expression* predicate;
    Block* consequent;
    Block* alternative;

    If(string p, size_t l, Expression* pred, Block* con, Block* alt = 0)
    : Statement(p, l), predicate(pred), consequent(con), alternative(alt)
    { }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////
  // The Sass `@for` control directive.
  /////////////////////////////////////
  struct For : public Has_Block {
    string variable;
    Expression* lower_bound;
    Expression* upper_bound;
    bool   is_inclusive;

    For(string p, size_t l,
        string var, Expression* lo, Expression* hi, Block* b, bool inc)
    : Has_Block(p, l, b),
      variable(var), lower_bound(lo), upper_bound(hi), is_inclusive(inc)
    { }
    ATTACH_OPERATIONS();
  };

  //////////////////////////////////////
  // The Sass `@each` control directive.
  //////////////////////////////////////
  struct Each : public Has_Block {
    string variable;
    Expression* list;

    Each(string p, size_t l, string var, Expression* lst, Block* b)
    : Has_Block(p, l, b), variable(var), list(lst)
    { }
    ATTACH_OPERATIONS();
  };

  ///////////////////////////////////////
  // The Sass `@while` control directive.
  ///////////////////////////////////////
  struct While : public Has_Block {
    Expression* predicate;

    While(string p, size_t l, Expression* pred, Block* b)
    : Has_Block(p, l, b), predicate(pred)
    { }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////
  // The Sass `@extend` directive.
  ////////////////////////////////
  struct Extend : public Statement {
    Selector* selector;

    Extend(string p, size_t l, Selector* s)
    : Statement(p, l), selector(s)
    { }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////////////////////
  // Definitions for both mixins and functions. Templatized to avoid type-tags
  // and unnecessary subclassing.
  ////////////////////////////////////////////////////////////////////////////
  struct Parameters;
  enum Definition_Type { MIXIN, FUNCTION };
  template <Definition_Type t>
  struct Definition : public Has_Block {
    string      name;
    Parameters* parameters;

    Definition(string p, size_t l,
               string n, Parameters* params, Block* b)
    : Has_Block(p, l, b), name(n), parameters(params)
    { }
    ATTACH_OPERATIONS();
  };

  //////////////////////////////////////
  // Mixin calls (i.e., `@include ...`).
  //////////////////////////////////////
  struct Arguments;
  struct Mixin_Call : public Has_Block {
    string name;
    Arguments* arguments;

    Mixin_Call(string p, size_t l, string n, Arguments* args, Block* b = 0)
    : Has_Block(p, l, b), name(n), arguments(args)
    { }
    ATTACH_OPERATIONS();
  };

  //////////////////////////////////////////////////////////////////////
  // Abstract base class for expressions. This side of the AST hierarchy
  // represents elements in value contexts, which exist primarily to be
  // evaluated and returned.
  //////////////////////////////////////////////////////////////////////
  struct Expression : public AST_Node {
    bool delayed;       // expressions in some contexts shouldn't be evaluated
    bool parenthesized; // for media features, if I recall

    Expression(string p, size_t l)
    : AST_Node(p, l), delayed(false), parenthesized(false)
    { }
    virtual ~Expression() = 0;
    virtual string type() { return ""; /* TODO: raise an error */ }
  };
  inline Expression::~Expression() { }

  ///////////////////////////////////////////////////////////////////////
  // Lists of values, both comma- and space-separated (distinguished by a
  // type-tag.) Also used to represent variable-length argument lists.
  ///////////////////////////////////////////////////////////////////////
  struct List : public Expression {
    enum Separator { space, comma };
    vector<Expression*> values;
    Separator           separator;
    bool                is_arglist;

    List(string p, size_t l,
         size_t size = 0, Separator sep = space, bool argl = false)
    : Expression(p, l),
      values(vector<Expression*>()), separator(sep), is_arglist(argl)
    { values.reserve(size); }

    size_t length() const
    { return values.size(); }
    Expression*& operator[](size_t i)
    { return values[i]; }
    List& operator<<(Expression* v)
    {
      values.push_back(v);
      return *this;
    }
    List& operator+=(List* l)
    {
      for (size_t i = 0, L = l->length(); i < L; ++i)
        values.push_back((*l)[i]);
      return *this;
    }
    string type() { return is_arglist ? "arglist" : "list"; }
    ATTACH_OPERATIONS();
  };

  //////////////////////////////////////////////////////////////////////////
  // Binary expressions. Represents logical, relational, and arithmetic
  // operations. Templatized to avoid large switch statements and repetitive
  // subclassing.
  //////////////////////////////////////////////////////////////////////////
  enum Binary_Operator {
    AND, OR,                   // logical connectives
    EQ, NEQ, GT, GTE, LT, LTE, // arithmetic relations
    ADD, SUB, MUL, DIV         // arithmetic functions
  };
  template<Binary_Operator oper>
  struct Binary_Expression : public Expression {
    Expression* left;
    Expression* right;

    Binary_Expression(string p, size_t l, Expression* lhs, Expression* rhs)
    : Expression(p, l), left(lhs), right(rhs)
    { }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////////////////////
  // Arithmetic negation (logical negation is just an ordinary function call).
  ////////////////////////////////////////////////////////////////////////////
  struct Negation : public Expression {
    Expression* operand;
    Negation(string p, size_t l, Expression* o)
    : Expression(p, l), operand(o)
    { }
    ATTACH_OPERATIONS();
  };

  //////////////////
  // Function calls.
  //////////////////
  struct Function_Call : public Expression {
    String*    name;
    Arguments* arguments;

    Function_Call(string p, size_t l, String* n, Arguments* args)
    : Expression(p, l), name(n), arguments(args)
    { }
    ATTACH_OPERATIONS();
  };

  ///////////////////////
  // Variable references.
  ///////////////////////
  struct Variable : public Expression {
    string name;

    Variable(string p, size_t l, string n)
    : Expression(p, l), name(n)
    { }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////////////////////////////////////////
  // Textual (i.e., unevaluated) numeric data. Templated to avoid type-tags and
  // repetitive subclassing.
  /////////////////////////////////////////////////////////////////////////////
  enum Textual_Type { NUMBER, PERCENTAGE, DIMENSION, HEX };
  template <Textual_Type t>
  struct Textual : public Expression {
    string value;

    Textual(string p, size_t l, string val)
    : Expression(p, l), value(val)
    { }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////
  // Numbers, percentages, dimensions, and colors.
  ////////////////////////////////////////////////
  struct Numeric : public Expression {
    double value;
    Numeric(string p, size_t l, double val) : Expression(p, l), value(val) { }
    virtual ~Numeric() = 0;
    string type() { return "number"; }
  };
  inline Numeric::~Numeric() { }
  struct Number : public Numeric {
    Number(string p, size_t l, double val) : Numeric(p, l, val) { }
    ATTACH_OPERATIONS();
  };
  struct Percentage : public Numeric {
    Percentage(string p, size_t l, double val) : Numeric(p, l, val) { }
    ATTACH_OPERATIONS();
  };
  struct Dimension : public Numeric {
    vector<string> numerator_units;
    vector<string> denominator_units;
    Dimension(string p, size_t l, double val, string unit)
    : Numeric(p, l, val),
      numerator_units(vector<string>()),
      denominator_units(vector<string>())
    { numerator_units.push_back(unit); }
    ATTACH_OPERATIONS();
  };

  //////////
  // Colors.
  //////////
  struct Color : public Expression {
    double r, g, b, a;
    Color(string p, size_t l, double r, double g, double b, double a = 1)
    : Expression(p, l), r(r), g(g), b(b), a(a)
    { }
    string type() { return "color"; }
    ATTACH_OPERATIONS();
  };

  ////////////
  // Booleans.
  ////////////
  struct Boolean : public Expression {
    bool value;
    Boolean(string p, size_t l, bool val) : Expression(p, l), value(val) { }
    string type() { return "bool"; }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////////////////
  // Abstract base class for Sass string values. Includes interpolated and
  // "flat" strings.
  ////////////////////////////////////////////////////////////////////////
  struct String : public Expression {
    String(string p, size_t l) : Expression(p, l) { }
    virtual ~String() = 0;
  };
  inline String::~String() { };

  ///////////////////////////////////////////////////////////////////////
  // Interpolated strings. Meant to be reduced to flat strings during the
  // evaluation phase.
  ///////////////////////////////////////////////////////////////////////
  struct String_Schema : public String {
    vector<Expression*> fragments;

    String_Schema(string p, size_t l, size_t size = 0)
    : String(p, l), fragments(vector<Expression*>())
    { fragments.reserve(size); }

    size_t length() const
    { return fragments.size(); }
    Expression*& operator[](size_t i)
    { return fragments[i]; }
    String_Schema& operator<<(Expression* v)
    {
      fragments.push_back(v);
      return *this;
    }
    String_Schema& operator+=(String_Schema* s)
    {
      for (size_t i = 0, L = s->length(); i < L; ++i)
        fragments.push_back((*s)[i]);
      return *this;
    }
    string type() { return "string"; }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////
  // Flat strings -- the lowest level of raw textual data.
  ////////////////////////////////////////////////////////
  struct String_Constant : public String {
    string value;

    String_Constant(string p, size_t l, string val)
    : String(p, l), value(val)
    { }
    String_Constant(string p, size_t l, const char* beg)
    : String(p, l), value(string(beg))
    { }
    String_Constant(string p, size_t l, const char* beg, const char* end)
    : String(p, l), value(string(beg, end-beg))
    { }
    string type() { return "string"; }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////////////////////
  // Individual parameter objects for mixins and functions.
  /////////////////////////////////////////////////////////
  struct Parameter : public AST_Node {
    string name;
    Expression* default_value;
    bool is_rest_parameter;

    Parameter(string p, size_t l,
              string n, Expression* def = 0, bool rest = false)
    : AST_Node(p, l), name(n), default_value(def), is_rest_parameter(rest)
    { /* TO-DO: error if default_value && is_packed */ }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////////////////////////////////////
  // Parameter lists -- in their own class to facilitate context-sensitive
  // error checking (e.g., ensuring that all optional parameters follow all
  // required parameters).
  /////////////////////////////////////////////////////////////////////////
  struct Parameters : public AST_Node {
    vector<Parameter*> list;
    bool has_optional_parameters, has_rest_parameter;

    Parameters(string p, size_t l)
    : AST_Node(p, l),
      has_optional_parameters(false), has_rest_parameter(false)
    { }

    size_t length() { return list.size(); }
    Parameter*& operator[](size_t i) { return list[i]; }

    Parameters& operator<<(Parameter* p)
    {
      if (p->default_value) {
        if (has_rest_parameter)
          ; // error
        has_optional_parameters = true;
      }
      else if (p->is_rest_parameter) {
        if (has_rest_parameter)
          ; // error
        if (has_optional_parameters)
          ; // different error
        has_rest_parameter = true;
      }
      else {
        if (has_rest_parameter)
          ; // error
        if (has_optional_parameters)
          ; // different error
      }
      list.push_back(p);
      return *this;
    }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////
  // Individual argument objects for mixin and function calls.
  ////////////////////////////////////////////////////////////
  struct Argument : public AST_Node {
    Expression* value;
    string name;
    bool is_rest_argument;

    Argument(string p, size_t l, Expression* val, string n = "", bool rest = false)
    : AST_Node(p, l), value(val), name(n), is_rest_argument(rest)
    { if (name != "" && is_rest_argument) { /* error */ } }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////////////////
  // Argument lists -- in their own class to facilitate context-sensitive
  // error checking (e.g., ensuring that all ordinal arguments precede all
  // named arguments).
  ////////////////////////////////////////////////////////////////////////
  struct Arguments : public AST_Node {
    vector<Argument*> list;
    bool has_named_arguments, has_rest_argument;

    Arguments(string p, size_t l)
    : AST_Node(p, l),
      has_named_arguments(false), has_rest_argument(false)
    { }

    size_t length() { return list.size(); }
    Argument*& operator[](size_t i) { return list[i]; }

    Arguments& operator<<(Argument* a)
    {
      if (!a->name.empty()) {
        if (has_rest_argument)
          ; // error
        has_named_arguments = true;
      }
      else if (a->is_rest_argument) {
        if (has_rest_argument)
          ; // error
        if (has_named_arguments)
          ; // different error
        has_rest_argument = true;
      }
      else {
        if (has_rest_argument)
          ; // error
        if (has_named_arguments)
          ; // error
      }
      list.push_back(a);
      return *this;
    }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////
  // Abstract base class for CSS selectors.
  /////////////////////////////////////////
  struct Selector : public AST_Node {
    Selector(string p, size_t l) : AST_Node(p, l) { }
    virtual ~Selector() = 0;
  };
  inline Selector::~Selector() { }

  /////////////////////////////////////////////////////////////////////////
  // Interpolated selectors -- the interpolated String will be expanded and
  // re-parsed into a normal selector structure.
  /////////////////////////////////////////////////////////////////////////
  struct Interpolated : Selector {
    String* selector;

    Interpolated(string p, size_t l, String* cont)
    : Selector(p, l), selector(cont)
    { }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////
  // Abstract base class for atomic selectors.
  ////////////////////////////////////////////
  struct Simple_Base : public Selector {
    Simple_Base(string p, size_t l) : Selector(p, l) { }
    virtual ~Simple_Base() = 0;
  };
  inline Simple_Base::~Simple_Base() { }

  //////////////////////////////////////////////////////////////////////
  // Normal simple selectors (e.g., "div", ".foo", ":first-child", etc).
  //////////////////////////////////////////////////////////////////////
  struct Simple : public Simple_Base {
    string selector;

    Simple(string p, size_t l, string cont)
    : Simple_Base(p, l), selector(cont)
    { }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////
  // Parent references (i.e., the "&").
  /////////////////////////////////////
  struct Reference : public Simple_Base {
    Reference(string p, size_t l) : Simple_Base(p, l) { }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////////////////////////////////////
  // Placeholder selectors (e.g., "%foo") for use in extend-only selectors.
  /////////////////////////////////////////////////////////////////////////
  struct Placeholder : public Simple_Base {
    Placeholder(string p, size_t l) : Simple_Base(p, l) { }
    ATTACH_OPERATIONS();
  };

  //////////////////////////////////////////////////////////////////
  // Pseudo selectors -- e.g., :first-child, :nth-of-type(...), etc.
  //////////////////////////////////////////////////////////////////
  struct Pseudo : public Simple_Base {
    string name;
    Expression* expression;
    Pseudo(string p, size_t l, string n, Expression* expr = 0)
    : Simple_Base(p, l), name(n), expression(expr)
    { }
    ATTACH_OPERATIONS();
  };

  /////////////////////////////////////////////////
  // Negated selector -- e.g., :not(:first-of-type)
  /////////////////////////////////////////////////
  struct Negated : public Simple_Base {
    Simple_Base* selector;
    Negated(string p, size_t l, Simple_Base* sel)
    : Simple_Base(p, l), selector(sel)
    { }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////////////////////
  // Simple selector sequences. Maintains flags indicating whether it contains
  // any parent references or placeholders, to simplify expansion.
  ////////////////////////////////////////////////////////////////////////////
  struct Sequence : Selector {
    vector<Simple_Base*> selectors;
    bool                 has_reference;
    bool                 has_placeholder;

    Sequence(string p, size_t l, size_t s)
    : Selector(p, l),
      selectors(vector<Simple_Base*>()),
      has_reference(false),
      has_placeholder(false)
    { selectors.reserve(s); }

    size_t length()
    { return selectors.size(); }
    Simple_Base*& operator[](size_t i)
    { return selectors[i]; }
    Sequence& operator<<(Simple_Base* s)
    {
      selectors.push_back(s);
      return *this;
    }
    Sequence& operator<<(Reference* s)
    {
      has_reference = true;
      return (*this) << s;
    }
    Sequence& operator<<(Placeholder* p)
    {
      has_placeholder = true;
      return (*this) << p;
    }
    Sequence& operator+=(Sequence* seq)
    {
      for (size_t i = 0, L = seq->length(); i < L; ++i) *this << (*seq)[i];
      return *this;
    }
    ATTACH_OPERATIONS();
  };

  ////////////////////////////////////////////////////////////////////////////
  // General selectors -- i.e., simple sequences combined with one of the four
  // CSS selector combinators (">", "+", "~", and whitespace). Isomorphic to a
  // left-associative linked list.
  ////////////////////////////////////////////////////////////////////////////
  struct Combination : Selector {
    enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO };
    Combinator   combinator;
    Combination* context;
    Sequence*    selector;
    bool         has_reference;
    bool         has_placeholder;

    Combination(string p, size_t l,
                Combinator c, Combination* ctx, Sequence* sel)
    : Selector(p, l),
      combinator(c),
      context(ctx),
      selector(sel),
      has_reference(ctx && ctx->has_reference ||
                    sel && sel->has_reference),
      has_placeholder(ctx && ctx->has_placeholder ||
                      sel && sel->has_placeholder)
    { }
    ATTACH_OPERATIONS();
  };

  ///////////////////////////////////
  // Comma-separated selector groups.
  ///////////////////////////////////
  struct Group : Selector {
    vector<Combination*> selectors;
    bool                 has_reference;
    bool                 has_placeholder;

    Group(string p, size_t l, size_t s = 0)
    : Selector(p, l),
      selectors(vector<Combination*>()),
      has_reference(false),
      has_placeholder(false)
    { selectors.reserve(s); }

    size_t length()
    { return selectors.size(); }
    Combination*& operator[](size_t i)
    { return selectors[i]; }
    Group& operator<<(Combination* c)
    {
      selectors.push_back(c);
      has_reference   |= c->has_reference;
      has_placeholder |= c->has_placeholder;
      return *this;
    }
    Group& operator+=(Group* g)
    {
      for (size_t i = 0, L = g->length(); i < L; ++i) *this << (*g)[i];
      return *this;
    }
    ATTACH_OPERATIONS();
  };
}