|
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
|