Initial commit
[yaffs-website] / node_modules / node-sass / src / libsass / src / node.hpp
1 #ifndef SASS_NODE_H
2 #define SASS_NODE_H
3
4 #include <deque>
5 #include <memory>
6
7 #include "ast.hpp"
8
9
10 namespace Sass {
11
12
13
14
15   class Context;
16
17   /*
18    There are a lot of stumbling blocks when trying to port the ruby extend code to C++. The biggest is the choice of
19    data type. The ruby code will pretty seamlessly switch types between an Array<SimpleSequence or Op> (libsass'
20    equivalent is the Complex_Selector) to a Sequence, which contains more metadata about the sequence than just the
21    selector info. They also have the ability to have arbitrary nestings of arrays like [1, [2]], which is hard to
22    implement using Array equivalents in C++ (like the deque or vector). They also have the ability to include nil
23    in the arrays, like [1, nil, 3], which has potential semantic differences than an empty array [1, [], 3]. To be
24    able to represent all of these as unique cases, we need to create a tree of variant objects. The tree nature allows
25    the inconsistent nesting levels. The variant nature (while making some of the C++ code uglier) allows the code to
26    more closely match the ruby code, which is a huge benefit when attempting to implement an complex algorithm like
27    the Extend operator.
28
29    Note that the current libsass data model also pairs the combinator with the Complex_Selector that follows it, but
30    ruby sass has no such restriction, so we attempt to create a data structure that can handle them split apart.
31    */
32
33   class Node;
34   typedef std::deque<Node> NodeDeque;
35   typedef std::shared_ptr<NodeDeque> NodeDequePtr;
36
37   class Node {
38   public:
39     enum TYPE {
40       SELECTOR,
41       COMBINATOR,
42       COLLECTION,
43       NIL
44     };
45
46     TYPE type() const { return mType; }
47     bool isCombinator() const { return mType == COMBINATOR; }
48     bool isSelector() const { return mType == SELECTOR; }
49     bool isCollection() const { return mType == COLLECTION; }
50     bool isNil() const { return mType == NIL; }
51     bool got_line_feed;
52
53     Complex_Selector::Combinator combinator() const { return mCombinator; }
54
55     Complex_Selector_Obj selector() { return mpSelector; }
56     Complex_Selector_Obj selector() const { return mpSelector; }
57
58     NodeDequePtr collection() { return mpCollection; }
59     const NodeDequePtr collection() const { return mpCollection; }
60
61     static Node createCombinator(const Complex_Selector::Combinator& combinator);
62
63     // This method will klone the selector, stripping off the tail and combinator
64     static Node createSelector(Complex_Selector_Ptr pSelector, Context& ctx);
65
66     static Node createCollection();
67     static Node createCollection(const NodeDeque& values);
68
69     static Node createNil();
70     static Node naiveTrim(Node& seqses, Context& ctx);
71
72     Node klone(Context& ctx) const;
73
74     bool operator==(const Node& rhs) const;
75     inline bool operator!=(const Node& rhs) const { return !(*this == rhs); }
76
77
78     /*
79     COLLECTION FUNCTIONS
80
81     Most types don't need any helper methods (nil and combinator due to their simplicity and
82     selector due to the fact that we leverage the non-node selector code on the Complex_Selector
83     whereever possible). The following methods are intended to be called on Node objects whose
84     type is COLLECTION only.
85     */
86
87     // rhs and this must be node collections. Shallow copy the nodes from rhs to the end of this.
88     // This function DOES NOT remove the nodes from rhs.
89     void plus(Node& rhs);
90
91     // potentialChild must be a node collection of selectors/combinators. this must be a collection
92     // of collections of nodes/combinators. This method checks if potentialChild is a child of this
93     // Node.
94     bool contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const;
95
96   private:
97     // Private constructor; Use the static methods (like createCombinator and createSelector)
98     // to instantiate this object. This is more expressive, and it allows us to break apart each
99     // case into separate functions.
100     Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector_Ptr pSelector, NodeDequePtr& pCollection);
101
102     TYPE mType;
103
104     // TODO: can we union these to save on memory?
105     Complex_Selector::Combinator mCombinator;
106     Complex_Selector_Obj mpSelector;
107     NodeDequePtr mpCollection;
108   };
109
110 #ifdef DEBUG
111   std::ostream& operator<<(std::ostream& os, const Node& node);
112 #endif
113   Node complexSelectorToNode(Complex_Selector_Ptr pToConvert, Context& ctx);
114   Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert, Context& ctx);
115
116 }
117
118 #endif