Initial commit
[yaffs-website] / node_modules / node-sass / src / libsass / src / node.cpp
1 #include "sass.hpp"
2 #include <vector>
3
4 #include "node.hpp"
5 #include "context.hpp"
6 #include "parser.hpp"
7
8 namespace Sass {
9
10
11   Node Node::createCombinator(const Complex_Selector::Combinator& combinator) {
12     NodeDequePtr null;
13     return Node(COMBINATOR, combinator, NULL /*pSelector*/, null /*pCollection*/);
14   }
15
16
17   Node Node::createSelector(Complex_Selector_Ptr pSelector, Context& ctx) {
18     NodeDequePtr null;
19
20     Complex_Selector_Ptr pStripped = SASS_MEMORY_COPY(pSelector);
21     pStripped->tail(NULL);
22     pStripped->combinator(Complex_Selector::ANCESTOR_OF);
23
24     Node n(SELECTOR, Complex_Selector::ANCESTOR_OF, pStripped, null /*pCollection*/);
25     if (pSelector) n.got_line_feed = pSelector->has_line_feed();
26     return n;
27   }
28
29
30   Node Node::createCollection() {
31     NodeDequePtr pEmptyCollection = std::make_shared<NodeDeque>();
32     return Node(COLLECTION, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, pEmptyCollection);
33   }
34
35
36   Node Node::createCollection(const NodeDeque& values) {
37     NodeDequePtr pShallowCopiedCollection = std::make_shared<NodeDeque>(values);
38     return Node(COLLECTION, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, pShallowCopiedCollection);
39   }
40
41
42   Node Node::createNil() {
43     NodeDequePtr null;
44     return Node(NIL, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, null /*pCollection*/);
45   }
46
47
48   Node::Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector_Ptr pSelector, NodeDequePtr& pCollection)
49   : got_line_feed(false), mType(type), mCombinator(combinator), mpSelector(pSelector), mpCollection(pCollection)
50   { if (pSelector) got_line_feed = pSelector->has_line_feed(); }
51
52
53   Node Node::klone(Context& ctx) const {
54     NodeDequePtr pNewCollection = std::make_shared<NodeDeque>();
55     if (mpCollection) {
56       for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) {
57         Node& toClone = *iter;
58         pNewCollection->push_back(toClone.klone(ctx));
59       }
60     }
61
62     Node n(mType, mCombinator, mpSelector ? SASS_MEMORY_COPY(mpSelector) : NULL, pNewCollection);
63     n.got_line_feed = got_line_feed;
64     return n;
65   }
66
67
68   bool Node::contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const {
69     bool found = false;
70
71     for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) {
72       Node& toTest = *iter;
73
74       if (toTest == potentialChild) {
75         found = true;
76         break;
77       }
78     }
79
80     return found;
81   }
82
83
84   bool Node::operator==(const Node& rhs) const {
85     if (this->type() != rhs.type()) {
86       return false;
87     }
88
89     if (this->isCombinator()) {
90
91       return this->combinator() == rhs.combinator();
92
93     } else if (this->isNil()) {
94
95       return true; // no state to check
96
97     } else if (this->isSelector()){
98
99       return *this->selector() == *rhs.selector();
100
101     } else if (this->isCollection()) {
102
103       if (this->collection()->size() != rhs.collection()->size()) {
104         return false;
105       }
106
107       for (NodeDeque::iterator lhsIter = this->collection()->begin(), lhsIterEnd = this->collection()->end(),
108            rhsIter = rhs.collection()->begin(); lhsIter != lhsIterEnd; lhsIter++, rhsIter++) {
109
110         if (*lhsIter != *rhsIter) {
111           return false;
112         }
113
114       }
115
116       return true;
117
118     }
119
120     // We shouldn't get here.
121     throw "Comparing unknown node types. A new type was probably added and this method wasn't implemented for it.";
122   }
123
124
125   void Node::plus(Node& rhs) {
126     if (!this->isCollection() || !rhs.isCollection()) {
127       throw "Both the current node and rhs must be collections.";
128     }
129     this->collection()->insert(this->collection()->end(), rhs.collection()->begin(), rhs.collection()->end());
130   }
131
132 #ifdef DEBUG
133   std::ostream& operator<<(std::ostream& os, const Node& node) {
134
135     if (node.isCombinator()) {
136
137       switch (node.combinator()) {
138         case Complex_Selector::ANCESTOR_OF: os << "\" \""; break;
139         case Complex_Selector::PARENT_OF:   os << "\">\""; break;
140         case Complex_Selector::PRECEDES:    os << "\"~\""; break;
141         case Complex_Selector::ADJACENT_TO: os << "\"+\""; break;
142         case Complex_Selector::REFERENCE: os    << "\"/\""; break;
143       }
144
145     } else if (node.isNil()) {
146
147       os << "nil";
148
149     } else if (node.isSelector()){
150
151       os << node.selector()->head()->to_string();
152
153     } else if (node.isCollection()) {
154
155       os << "[";
156
157       for (NodeDeque::iterator iter = node.collection()->begin(), iterBegin = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
158         if (iter != iterBegin) {
159           os << ", ";
160         }
161
162         os << (*iter);
163       }
164
165       os << "]";
166
167     }
168
169     return os;
170
171   }
172 #endif
173
174
175   Node complexSelectorToNode(Complex_Selector_Ptr pToConvert, Context& ctx) {
176     if (pToConvert == NULL) {
177       return Node::createNil();
178     }
179     Node node = Node::createCollection();
180     node.got_line_feed = pToConvert->has_line_feed();
181     bool has_lf = pToConvert->has_line_feed();
182
183     // unwrap the selector from parent ref
184     if (pToConvert->head() && pToConvert->head()->has_parent_ref()) {
185       Complex_Selector_Obj tail = pToConvert->tail();
186       if (tail) tail->has_line_feed(pToConvert->has_line_feed());
187       pToConvert = tail;
188     }
189
190     while (pToConvert) {
191
192       bool empty_parent_ref = pToConvert->head() && pToConvert->head()->is_empty_reference();
193
194       if (pToConvert->head() || empty_parent_ref) {
195       }
196
197       // the first Complex_Selector may contain a dummy head pointer, skip it.
198       if (pToConvert->head() && !empty_parent_ref) {
199         node.collection()->push_back(Node::createSelector(pToConvert, ctx));
200         if (has_lf) node.collection()->back().got_line_feed = has_lf;
201         has_lf = false;
202       }
203
204       if (pToConvert->combinator() != Complex_Selector::ANCESTOR_OF) {
205         node.collection()->push_back(Node::createCombinator(pToConvert->combinator()));
206         if (has_lf) node.collection()->back().got_line_feed = has_lf;
207         has_lf = false;
208       }
209
210       if (pToConvert && empty_parent_ref && pToConvert->tail()) {
211         // pToConvert->tail()->has_line_feed(pToConvert->has_line_feed());
212       }
213
214       pToConvert = pToConvert->tail();
215     }
216
217     return node;
218   }
219
220
221   Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert, Context& ctx) {
222     if (toConvert.isNil()) {
223       return NULL;
224     }
225
226
227     if (!toConvert.isCollection()) {
228       throw "The node to convert to a Complex_Selector_Ptr must be a collection type or nil.";
229     }
230
231
232     NodeDeque& childNodes = *toConvert.collection();
233
234     std::string noPath("");
235     Position noPosition(-1, -1, -1);
236     Complex_Selector_Obj pFirst = SASS_MEMORY_NEW(Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL);
237
238     Complex_Selector_Obj pCurrent = pFirst;
239
240     if (toConvert.isSelector()) pFirst->has_line_feed(toConvert.got_line_feed);
241     if (toConvert.isCombinator()) pFirst->has_line_feed(toConvert.got_line_feed);
242
243     for (NodeDeque::iterator childIter = childNodes.begin(), childIterEnd = childNodes.end(); childIter != childIterEnd; childIter++) {
244
245       Node& child = *childIter;
246
247       if (child.isSelector()) {
248         // JMA - need to clone the selector, because they can end up getting shared across Node
249         // collections, and can result in an infinite loop during the call to parentSuperselector()
250         pCurrent->tail(SASS_MEMORY_COPY(child.selector()));
251         // if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed);
252         pCurrent = pCurrent->tail();
253       } else if (child.isCombinator()) {
254         pCurrent->combinator(child.combinator());
255         if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed);
256
257         // if the next node is also a combinator, create another Complex_Selector to hold it so it doesn't replace the current combinator
258         if (childIter+1 != childIterEnd) {
259           Node& nextNode = *(childIter+1);
260           if (nextNode.isCombinator()) {
261             pCurrent->tail(SASS_MEMORY_NEW(Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL));
262             if (nextNode.got_line_feed) pCurrent->tail()->has_line_feed(nextNode.got_line_feed);
263             pCurrent = pCurrent->tail();
264           }
265         }
266       } else {
267         throw "The node to convert's children must be only combinators or selectors.";
268       }
269     }
270
271     // Put the dummy Compound_Selector in the first position, for consistency with the rest of libsass
272     Compound_Selector_Ptr fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[NODE]"), 1);
273     Parent_Selector_Ptr selectorRef = SASS_MEMORY_NEW(Parent_Selector, ParserState("[NODE]"));
274     fakeHead->elements().push_back(selectorRef);
275     if (toConvert.got_line_feed) pFirst->has_line_feed(toConvert.got_line_feed);
276     // pFirst->has_line_feed(pFirst->has_line_feed() || pFirst->tail()->has_line_feed() || toConvert.got_line_feed);
277     pFirst->head(fakeHead);
278     return SASS_MEMORY_COPY(pFirst);
279   }
280
281   // A very naive trim function, which removes duplicates in a node
282   // This is only used in Complex_Selector::unify_with for now, may need modifications to fit other needs
283   Node Node::naiveTrim(Node& seqses, Context& ctx) {
284
285     std::vector<Node*> res;
286     std::vector<Complex_Selector_Obj> known;
287
288     NodeDeque::reverse_iterator seqsesIter = seqses.collection()->rbegin(),
289                                 seqsesIterEnd = seqses.collection()->rend();
290
291     for (; seqsesIter != seqsesIterEnd; ++seqsesIter)
292     {
293       Node& seqs1 = *seqsesIter;
294       if( seqs1.isSelector() ) {
295         Complex_Selector_Obj sel = seqs1.selector();
296         std::vector<Complex_Selector_Obj>::iterator it;
297         bool found = false;
298         for (it = known.begin(); it != known.end(); ++it) {
299           if (**it == *sel) { found = true; break; }
300         }
301         if( !found ) {
302           known.push_back(seqs1.selector());
303           res.push_back(&seqs1);
304         }
305       } else {
306         res.push_back(&seqs1);
307       }
308     }
309
310     Node result = Node::createCollection();
311
312     for (size_t i = res.size() - 1; i != std::string::npos; --i) {
313       result.collection()->push_back(*res[i]);
314     }
315
316     return result;
317   }
318 }