|
Packit |
bfcc33 |
#include "sass.hpp"
|
|
Packit |
bfcc33 |
#include <vector>
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
#include "node.hpp"
|
|
Packit |
bfcc33 |
#include "context.hpp"
|
|
Packit |
bfcc33 |
#include "parser.hpp"
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
namespace Sass {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node Node::createCombinator(const Complex_Selector::Combinator& combinator) {
|
|
Packit |
bfcc33 |
NodeDequePtr null;
|
|
Packit |
bfcc33 |
return Node(COMBINATOR, combinator, NULL /*pSelector*/, null /*pCollection*/);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node Node::createSelector(const Complex_Selector& pSelector) {
|
|
Packit |
bfcc33 |
NodeDequePtr null;
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Complex_Selector_Ptr pStripped = SASS_MEMORY_COPY(&pSelector);
|
|
Packit |
bfcc33 |
pStripped->tail(NULL);
|
|
Packit |
bfcc33 |
pStripped->combinator(Complex_Selector::ANCESTOR_OF);
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node n(SELECTOR, Complex_Selector::ANCESTOR_OF, pStripped, null /*pCollection*/);
|
|
Packit |
bfcc33 |
n.got_line_feed = pSelector.has_line_feed();
|
|
Packit |
bfcc33 |
return n;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node Node::createCollection() {
|
|
Packit |
bfcc33 |
NodeDequePtr pEmptyCollection = std::make_shared<NodeDeque>();
|
|
Packit |
bfcc33 |
return Node(COLLECTION, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, pEmptyCollection);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node Node::createCollection(const NodeDeque& values) {
|
|
Packit |
bfcc33 |
NodeDequePtr pShallowCopiedCollection = std::make_shared<NodeDeque>(values);
|
|
Packit |
bfcc33 |
return Node(COLLECTION, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, pShallowCopiedCollection);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node Node::createNil() {
|
|
Packit |
bfcc33 |
NodeDequePtr null;
|
|
Packit |
bfcc33 |
return Node(NIL, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, null /*pCollection*/);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node::Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector_Ptr pSelector, NodeDequePtr& pCollection)
|
|
Packit |
bfcc33 |
: got_line_feed(false), mType(type), mCombinator(combinator), mpSelector(pSelector), mpCollection(pCollection)
|
|
Packit |
bfcc33 |
{ if (pSelector) got_line_feed = pSelector->has_line_feed(); }
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node Node::klone() const {
|
|
Packit |
bfcc33 |
NodeDequePtr pNewCollection = std::make_shared<NodeDeque>();
|
|
Packit |
bfcc33 |
if (mpCollection) {
|
|
Packit |
bfcc33 |
for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) {
|
|
Packit |
bfcc33 |
Node& toClone = *iter;
|
|
Packit |
bfcc33 |
pNewCollection->push_back(toClone.klone());
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node n(mType, mCombinator, mpSelector ? SASS_MEMORY_COPY(mpSelector) : NULL, pNewCollection);
|
|
Packit |
bfcc33 |
n.got_line_feed = got_line_feed;
|
|
Packit |
bfcc33 |
return n;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
bool Node::contains(const Node& potentialChild) const {
|
|
Packit |
bfcc33 |
bool found = false;
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) {
|
|
Packit |
bfcc33 |
Node& toTest = *iter;
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (toTest == potentialChild) {
|
|
Packit |
bfcc33 |
found = true;
|
|
Packit |
bfcc33 |
break;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
return found;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
bool Node::operator==(const Node& rhs) const {
|
|
Packit |
bfcc33 |
if (this->type() != rhs.type()) {
|
|
Packit |
bfcc33 |
return false;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (this->isCombinator()) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
return this->combinator() == rhs.combinator();
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
} else if (this->isNil()) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
return true; // no state to check
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
} else if (this->isSelector()){
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
return *this->selector() == *rhs.selector();
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
} else if (this->isCollection()) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (this->collection()->size() != rhs.collection()->size()) {
|
|
Packit |
bfcc33 |
return false;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
for (NodeDeque::iterator lhsIter = this->collection()->begin(), lhsIterEnd = this->collection()->end(),
|
|
Packit |
bfcc33 |
rhsIter = rhs.collection()->begin(); lhsIter != lhsIterEnd; lhsIter++, rhsIter++) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (*lhsIter != *rhsIter) {
|
|
Packit |
bfcc33 |
return false;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
return true;
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
// We shouldn't get here.
|
|
Packit |
bfcc33 |
throw "Comparing unknown node types. A new type was probably added and this method wasn't implemented for it.";
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
void Node::plus(Node& rhs) {
|
|
Packit |
bfcc33 |
if (!this->isCollection() || !rhs.isCollection()) {
|
|
Packit |
bfcc33 |
throw "Both the current node and rhs must be collections.";
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
this->collection()->insert(this->collection()->end(), rhs.collection()->begin(), rhs.collection()->end());
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
#ifdef DEBUG
|
|
Packit |
bfcc33 |
std::ostream& operator<<(std::ostream& os, const Node& node) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (node.isCombinator()) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
switch (node.combinator()) {
|
|
Packit |
bfcc33 |
case Complex_Selector::ANCESTOR_OF: os << "\" \""; break;
|
|
Packit |
bfcc33 |
case Complex_Selector::PARENT_OF: os << "\">\""; break;
|
|
Packit |
bfcc33 |
case Complex_Selector::PRECEDES: os << "\"~\""; break;
|
|
Packit |
bfcc33 |
case Complex_Selector::ADJACENT_TO: os << "\"+\""; break;
|
|
Packit |
bfcc33 |
case Complex_Selector::REFERENCE: os << "\"/\""; break;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
} else if (node.isNil()) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
os << "nil";
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
} else if (node.isSelector()){
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
os << node.selector()->head()->to_string();
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
} else if (node.isCollection()) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
os << "[";
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
for (NodeDeque::iterator iter = node.collection()->begin(), iterBegin = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
|
|
Packit |
bfcc33 |
if (iter != iterBegin) {
|
|
Packit |
bfcc33 |
os << ", ";
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
os << (*iter);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
os << "]";
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
return os;
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
#endif
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node complexSelectorToNode(Complex_Selector_Ptr pToConvert) {
|
|
Packit |
bfcc33 |
if (pToConvert == NULL) {
|
|
Packit |
bfcc33 |
return Node::createNil();
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
Node node = Node::createCollection();
|
|
Packit |
bfcc33 |
node.got_line_feed = pToConvert->has_line_feed();
|
|
Packit |
bfcc33 |
bool has_lf = pToConvert->has_line_feed();
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
// unwrap the selector from parent ref
|
|
Packit |
bfcc33 |
if (pToConvert->head() && pToConvert->head()->has_parent_ref()) {
|
|
Packit |
bfcc33 |
Complex_Selector_Obj tail = pToConvert->tail();
|
|
Packit |
bfcc33 |
if (tail) tail->has_line_feed(pToConvert->has_line_feed());
|
|
Packit |
bfcc33 |
pToConvert = tail;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
while (pToConvert) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
bool empty_parent_ref = pToConvert->head() && pToConvert->head()->is_empty_reference();
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (pToConvert->head() || empty_parent_ref) {
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
// the first Complex_Selector may contain a dummy head pointer, skip it.
|
|
Packit |
bfcc33 |
if (pToConvert->head() && !empty_parent_ref) {
|
|
Packit |
bfcc33 |
node.collection()->push_back(Node::createSelector(*pToConvert));
|
|
Packit |
bfcc33 |
if (has_lf) node.collection()->back().got_line_feed = has_lf;
|
|
Packit |
bfcc33 |
has_lf = false;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (pToConvert->combinator() != Complex_Selector::ANCESTOR_OF) {
|
|
Packit |
bfcc33 |
node.collection()->push_back(Node::createCombinator(pToConvert->combinator()));
|
|
Packit |
bfcc33 |
if (has_lf) node.collection()->back().got_line_feed = has_lf;
|
|
Packit |
bfcc33 |
has_lf = false;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (pToConvert && empty_parent_ref && pToConvert->tail()) {
|
|
Packit |
bfcc33 |
// pToConvert->tail()->has_line_feed(pToConvert->has_line_feed());
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
pToConvert = pToConvert->tail();
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
return node;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert) {
|
|
Packit |
bfcc33 |
if (toConvert.isNil()) {
|
|
Packit |
bfcc33 |
return NULL;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (!toConvert.isCollection()) {
|
|
Packit |
bfcc33 |
throw "The node to convert to a Complex_Selector_Ptr must be a collection type or nil.";
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
NodeDeque& childNodes = *toConvert.collection();
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
std::string noPath("");
|
|
Packit |
bfcc33 |
Complex_Selector_Obj pFirst = SASS_MEMORY_NEW(Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL);
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Complex_Selector_Obj pCurrent = pFirst;
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (toConvert.isSelector()) pFirst->has_line_feed(toConvert.got_line_feed);
|
|
Packit |
bfcc33 |
if (toConvert.isCombinator()) pFirst->has_line_feed(toConvert.got_line_feed);
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
for (NodeDeque::iterator childIter = childNodes.begin(), childIterEnd = childNodes.end(); childIter != childIterEnd; childIter++) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node& child = *childIter;
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
if (child.isSelector()) {
|
|
Packit |
bfcc33 |
// JMA - need to clone the selector, because they can end up getting shared across Node
|
|
Packit |
bfcc33 |
// collections, and can result in an infinite loop during the call to parentSuperselector()
|
|
Packit |
bfcc33 |
pCurrent->tail(SASS_MEMORY_COPY(child.selector()));
|
|
Packit |
bfcc33 |
// if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed);
|
|
Packit |
bfcc33 |
pCurrent = pCurrent->tail();
|
|
Packit |
bfcc33 |
} else if (child.isCombinator()) {
|
|
Packit |
bfcc33 |
pCurrent->combinator(child.combinator());
|
|
Packit |
bfcc33 |
if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed);
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
// if the next node is also a combinator, create another Complex_Selector to hold it so it doesn't replace the current combinator
|
|
Packit |
bfcc33 |
if (childIter+1 != childIterEnd) {
|
|
Packit |
bfcc33 |
Node& nextNode = *(childIter+1);
|
|
Packit |
bfcc33 |
if (nextNode.isCombinator()) {
|
|
Packit |
bfcc33 |
pCurrent->tail(SASS_MEMORY_NEW(Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL));
|
|
Packit |
bfcc33 |
if (nextNode.got_line_feed) pCurrent->tail()->has_line_feed(nextNode.got_line_feed);
|
|
Packit |
bfcc33 |
pCurrent = pCurrent->tail();
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
} else {
|
|
Packit |
bfcc33 |
throw "The node to convert's children must be only combinators or selectors.";
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
// Put the dummy Compound_Selector in the first position, for consistency with the rest of libsass
|
|
Packit |
bfcc33 |
Compound_Selector_Ptr fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[NODE]"), 1);
|
|
Packit |
bfcc33 |
Parent_Selector_Ptr selectorRef = SASS_MEMORY_NEW(Parent_Selector, ParserState("[NODE]"));
|
|
Packit |
bfcc33 |
fakeHead->elements().push_back(selectorRef);
|
|
Packit |
bfcc33 |
if (toConvert.got_line_feed) pFirst->has_line_feed(toConvert.got_line_feed);
|
|
Packit |
bfcc33 |
// pFirst->has_line_feed(pFirst->has_line_feed() || pFirst->tail()->has_line_feed() || toConvert.got_line_feed);
|
|
Packit |
bfcc33 |
pFirst->head(fakeHead);
|
|
Packit |
bfcc33 |
return SASS_MEMORY_COPY(pFirst);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
// A very naive trim function, which removes duplicates in a node
|
|
Packit |
bfcc33 |
// This is only used in Complex_Selector::unify_with for now, may need modifications to fit other needs
|
|
Packit |
bfcc33 |
Node Node::naiveTrim(Node& seqses) {
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
std::vector<Node*> res;
|
|
Packit |
bfcc33 |
std::vector<Complex_Selector_Obj> known;
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
NodeDeque::reverse_iterator seqsesIter = seqses.collection()->rbegin(),
|
|
Packit |
bfcc33 |
seqsesIterEnd = seqses.collection()->rend();
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
for (; seqsesIter != seqsesIterEnd; ++seqsesIter)
|
|
Packit |
bfcc33 |
{
|
|
Packit |
bfcc33 |
Node& seqs1 = *seqsesIter;
|
|
Packit |
bfcc33 |
if( seqs1.isSelector() ) {
|
|
Packit |
bfcc33 |
Complex_Selector_Obj sel = seqs1.selector();
|
|
Packit |
bfcc33 |
std::vector<Complex_Selector_Obj>::iterator it;
|
|
Packit |
bfcc33 |
bool found = false;
|
|
Packit |
bfcc33 |
for (it = known.begin(); it != known.end(); ++it) {
|
|
Packit |
bfcc33 |
if (**it == *sel) { found = true; break; }
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
if( !found ) {
|
|
Packit |
bfcc33 |
known.push_back(seqs1.selector());
|
|
Packit |
bfcc33 |
res.push_back(&seqs1);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
} else {
|
|
Packit |
bfcc33 |
res.push_back(&seqs1);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
Node result = Node::createCollection();
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
for (size_t i = res.size() - 1; i != std::string::npos; --i) {
|
|
Packit |
bfcc33 |
result.collection()->push_back(*res[i]);
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
|
|
Packit |
bfcc33 |
return result;
|
|
Packit |
bfcc33 |
}
|
|
Packit |
bfcc33 |
}
|