Blame src/node.hpp

Packit bfcc33
#ifndef SASS_NODE_H
Packit bfcc33
#define SASS_NODE_H
Packit bfcc33
Packit bfcc33
#include <deque>
Packit bfcc33
#include <memory>
Packit bfcc33
Packit bfcc33
#include "ast.hpp"
Packit bfcc33
Packit bfcc33
Packit bfcc33
namespace Sass {
Packit bfcc33
Packit bfcc33
Packit bfcc33
Packit bfcc33
Packit bfcc33
  class Context;
Packit bfcc33
Packit bfcc33
  /*
Packit bfcc33
   There are a lot of stumbling blocks when trying to port the ruby extend code to C++. The biggest is the choice of
Packit bfcc33
   data type. The ruby code will pretty seamlessly switch types between an Array<SimpleSequence or Op> (libsass'
Packit bfcc33
   equivalent is the Complex_Selector) to a Sequence, which contains more metadata about the sequence than just the
Packit bfcc33
   selector info. They also have the ability to have arbitrary nestings of arrays like [1, [2]], which is hard to
Packit bfcc33
   implement using Array equivalents in C++ (like the deque or vector). They also have the ability to include nil
Packit bfcc33
   in the arrays, like [1, nil, 3], which has potential semantic differences than an empty array [1, [], 3]. To be
Packit bfcc33
   able to represent all of these as unique cases, we need to create a tree of variant objects. The tree nature allows
Packit bfcc33
   the inconsistent nesting levels. The variant nature (while making some of the C++ code uglier) allows the code to
Packit bfcc33
   more closely match the ruby code, which is a huge benefit when attempting to implement an complex algorithm like
Packit bfcc33
   the Extend operator.
Packit bfcc33
Packit bfcc33
   Note that the current libsass data model also pairs the combinator with the Complex_Selector that follows it, but
Packit bfcc33
   ruby sass has no such restriction, so we attempt to create a data structure that can handle them split apart.
Packit bfcc33
   */
Packit bfcc33
Packit bfcc33
  class Node;
Packit bfcc33
  typedef std::deque<Node> NodeDeque;
Packit bfcc33
  typedef std::shared_ptr<NodeDeque> NodeDequePtr;
Packit bfcc33
Packit bfcc33
  class Node {
Packit bfcc33
  public:
Packit bfcc33
    enum TYPE {
Packit bfcc33
      SELECTOR,
Packit bfcc33
      COMBINATOR,
Packit bfcc33
      COLLECTION,
Packit bfcc33
      NIL
Packit bfcc33
    };
Packit bfcc33
Packit bfcc33
    TYPE type() const { return mType; }
Packit bfcc33
    bool isCombinator() const { return mType == COMBINATOR; }
Packit bfcc33
    bool isSelector() const { return mType == SELECTOR; }
Packit bfcc33
    bool isCollection() const { return mType == COLLECTION; }
Packit bfcc33
    bool isNil() const { return mType == NIL; }
Packit bfcc33
    bool got_line_feed;
Packit bfcc33
Packit bfcc33
    Complex_Selector::Combinator combinator() const { return mCombinator; }
Packit bfcc33
Packit bfcc33
    Complex_Selector_Obj selector() { return mpSelector; }
Packit bfcc33
    Complex_Selector_Obj selector() const { return mpSelector; }
Packit bfcc33
Packit bfcc33
    NodeDequePtr collection() { return mpCollection; }
Packit bfcc33
    const NodeDequePtr collection() const { return mpCollection; }
Packit bfcc33
Packit bfcc33
    static Node createCombinator(const Complex_Selector::Combinator& combinator);
Packit bfcc33
Packit bfcc33
    // This method will klone the selector, stripping off the tail and combinator
Packit bfcc33
    static Node createSelector(const Complex_Selector& pSelector);
Packit bfcc33
Packit bfcc33
    static Node createCollection();
Packit bfcc33
    static Node createCollection(const NodeDeque& values);
Packit bfcc33
Packit bfcc33
    static Node createNil();
Packit bfcc33
    static Node naiveTrim(Node& seqses);
Packit bfcc33
Packit bfcc33
    Node klone() const;
Packit bfcc33
Packit bfcc33
    bool operator==(const Node& rhs) const;
Packit bfcc33
    inline bool operator!=(const Node& rhs) const { return !(*this == rhs); }
Packit bfcc33
Packit bfcc33
Packit bfcc33
    /*
Packit bfcc33
    COLLECTION FUNCTIONS
Packit bfcc33
Packit bfcc33
    Most types don't need any helper methods (nil and combinator due to their simplicity and
Packit bfcc33
    selector due to the fact that we leverage the non-node selector code on the Complex_Selector
Packit bfcc33
    whereever possible). The following methods are intended to be called on Node objects whose
Packit bfcc33
    type is COLLECTION only.
Packit bfcc33
    */
Packit bfcc33
Packit bfcc33
    // rhs and this must be node collections. Shallow copy the nodes from rhs to the end of this.
Packit bfcc33
    // This function DOES NOT remove the nodes from rhs.
Packit bfcc33
    void plus(Node& rhs);
Packit bfcc33
Packit bfcc33
    // potentialChild must be a node collection of selectors/combinators. this must be a collection
Packit bfcc33
    // of collections of nodes/combinators. This method checks if potentialChild is a child of this
Packit bfcc33
    // Node.
Packit bfcc33
    bool contains(const Node& potentialChild) const;
Packit bfcc33
Packit bfcc33
  private:
Packit bfcc33
    // Private constructor; Use the static methods (like createCombinator and createSelector)
Packit bfcc33
    // to instantiate this object. This is more expressive, and it allows us to break apart each
Packit bfcc33
    // case into separate functions.
Packit bfcc33
    Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector_Ptr pSelector, NodeDequePtr& pCollection);
Packit bfcc33
Packit bfcc33
    TYPE mType;
Packit bfcc33
Packit bfcc33
    // TODO: can we union these to save on memory?
Packit bfcc33
    Complex_Selector::Combinator mCombinator;
Packit bfcc33
    Complex_Selector_Obj mpSelector;
Packit bfcc33
    NodeDequePtr mpCollection;
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
#ifdef DEBUG
Packit bfcc33
  std::ostream& operator<<(std::ostream& os, const Node& node);
Packit bfcc33
#endif
Packit bfcc33
  Node complexSelectorToNode(Complex_Selector_Ptr pToConvert);
Packit bfcc33
  Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert);
Packit bfcc33
Packit bfcc33
}
Packit bfcc33
Packit bfcc33
#endif