From 5d500ea305db7185314cc2b500257529e9e9696a Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Fri, 5 Dec 2014 17:09:34 +0100 Subject: Successfully (hopefully) implemented CSS Parsing and the respective test. --- src/core/CSS.cpp | 6 ++ src/core/CSS.hpp | 9 +-- src/core/Tokenizer.hpp | 2 + src/plugins/css/CSSParser.cpp | 6 +- test/plugins/css/CSSParserTest.cpp | 112 ++++++++++++++++++++++++++++++++++++- 5 files changed, 126 insertions(+), 9 deletions(-) diff --git a/src/core/CSS.cpp b/src/core/CSS.cpp index c3900e8..d131fec 100644 --- a/src/core/CSS.cpp +++ b/src/core/CSS.cpp @@ -20,6 +20,12 @@ namespace ousia { +void RuleSet::merge(Rooted other){ + for(auto& o : other->rules){ + rules[o.first] = o.second; + } +} + /* * different versions of "getChildren". */ diff --git a/src/core/CSS.hpp b/src/core/CSS.hpp index 4cf15be..aa701b5 100644 --- a/src/core/CSS.hpp +++ b/src/core/CSS.hpp @@ -85,10 +85,11 @@ public: return rules; } - void merge(Rooted other) - { - rules.insert(other->rules.begin(), other->rules.end()); - } + /** + * This implements an overriding "insert all" of all rules in the other + * RuleSet to the rules in this RuleSet. + */ + void merge(Rooted other); }; /** diff --git a/src/core/Tokenizer.hpp b/src/core/Tokenizer.hpp index 4aebf56..8f80150 100644 --- a/src/core/Tokenizer.hpp +++ b/src/core/Tokenizer.hpp @@ -225,6 +225,8 @@ public: void consumePeek(); const BufferedCharReader &getInput() const { return input; } + + BufferedCharReader &getInput() { return input; } }; } diff --git a/src/plugins/css/CSSParser.cpp b/src/plugins/css/CSSParser.cpp index 82ed7e1..fc37184 100644 --- a/src/plugins/css/CSSParser.cpp +++ b/src/plugins/css/CSSParser.cpp @@ -18,6 +18,8 @@ #include "CSSParser.hpp" +#include + namespace ousia { namespace parser { namespace css { @@ -330,8 +332,8 @@ bool CSSParser::parseRule(CodeTokenizer &tokenizer, ParserContext &ctx, expect(COLON, tokenizer, t, true, ctx); // then the value // TODO: Resolve key for appropriate parsing function here. - expect(STRING, tokenizer, t, true, ctx); - value = variant::Variant(t.content.c_str()); + value = variant::Reader::parseGeneric(tokenizer.getInput(), ctx.logger, + {';'}).second; // and a ; expect(SEMICOLON, tokenizer, t, true, ctx); return true; diff --git a/test/plugins/css/CSSParserTest.cpp b/test/plugins/css/CSSParserTest.cpp index 8880fc5..8873673 100644 --- a/test/plugins/css/CSSParserTest.cpp +++ b/test/plugins/css/CSSParserTest.cpp @@ -59,6 +59,7 @@ TEST(CSSParser, testParseSelectors) } ASSERT_EQ(2, A->getEdges().size()); ASSERT_FALSE(A->isAccepting()); + ASSERT_EQ(0, A->getRuleSet()->getRules().size()); { // assert A > B std::vector> Achildren = @@ -72,6 +73,7 @@ TEST(CSSParser, testParseSelectors) } ASSERT_EQ(0, B->getEdges().size()); ASSERT_TRUE(B->isAccepting()); + ASSERT_EQ(0, B->getRuleSet()->getRules().size()); // assert A B:r Achildren = A->getChildren(SelectionOperator::DESCENDANT, "B"); ASSERT_EQ(1, Achildren.size()); @@ -83,6 +85,7 @@ TEST(CSSParser, testParseSelectors) } ASSERT_EQ(0, Br->getEdges().size()); ASSERT_TRUE(Br->isAccepting()); + ASSERT_EQ(0, Br->getRuleSet()->getRules().size()); } // assert C#a children = root->getChildren("C"); @@ -95,6 +98,7 @@ TEST(CSSParser, testParseSelectors) } ASSERT_EQ(1, C->getEdges().size()); ASSERT_FALSE(C->isAccepting()); + ASSERT_EQ(0, C->getRuleSet()->getRules().size()); { // assert C#a A[bla=\"blub\"] std::vector> Cchildren = @@ -108,6 +112,7 @@ TEST(CSSParser, testParseSelectors) } ASSERT_EQ(0, A->getEdges().size()); ASSERT_TRUE(A->isAccepting()); + ASSERT_EQ(0, A->getRuleSet()->getRules().size()); } // assert A::g(4,2,3) children = root->getChildren("A"); @@ -120,10 +125,12 @@ TEST(CSSParser, testParseSelectors) } ASSERT_EQ(0, Ag->getEdges().size()); ASSERT_TRUE(Ag->isAccepting()); + ASSERT_EQ(0, Ag->getRuleSet()->getRules().size()); } TEST(CSSParser, testParseCSS) { + // create the CSS input std::stringstream input; input << "A, B A {\n"; @@ -140,18 +147,117 @@ TEST(CSSParser, testParseCSS) input << "A {\n"; input << "\t ident1 : \"val4\";\n"; input << "}\n"; - - + // initialize an empty parser context. StandaloneParserContext ctx; // parse the input. CSSParser instance; Rooted root = instance.parse(input, ctx).cast(); + + // we expect three children of the root node overall. + ASSERT_EQ(3, root->getEdges().size()); + // get all "A" children, which should be two. + std::vector> children = root->getChildren("A"); + ASSERT_EQ(2, children.size()); + // assert A + /* + * A { + * ident1 : "val1"; + * ident2 : "val2"; + * } + * + * and + * + * A { + * ident1 : "val4"; + * } + * + * should be merged. + */ + Rooted A = children[0]; + ASSERT_EQ("A", A->getName()); + { + PseudoSelector select{"true", false}; + ASSERT_EQ(select, A->getPseudoSelector()); + } + ASSERT_EQ(0, A->getEdges().size()); + ASSERT_TRUE(A->isAccepting()); + { + Rooted ruleSet = A->getRuleSet(); + ASSERT_EQ(2, ruleSet->getRules().size()); + variant::Variant v = ruleSet->getRules()["ident1"]; + ASSERT_EQ(variant::Variant::Type::STRING, v.getType()); + ASSERT_EQ("val4", v.asString()); + v = ruleSet->getRules()["ident2"]; + ASSERT_EQ(variant::Variant::Type::STRING, v.getType()); + ASSERT_EQ("val2", v.asString()); + } + /* + * For this part of the SelectorTree we only have + * + * A:select(a,b) { + * ident3 : val3; + * } + */ + Rooted Aselect = children[1]; + ASSERT_EQ("A", Aselect->getName()); + { + PseudoSelector select{"select",{"a","b"}, false}; + ASSERT_EQ(select, Aselect->getPseudoSelector()); + } + ASSERT_EQ(0, Aselect->getEdges().size()); + ASSERT_TRUE(Aselect->isAccepting()); + { + Rooted ruleSet = Aselect->getRuleSet(); + ASSERT_EQ(1, ruleSet->getRules().size()); + variant::Variant v = ruleSet->getRules()["ident3"]; + ASSERT_EQ(variant::Variant::Type::STRING, v.getType()); + ASSERT_EQ("val3", v.asString()); + } + /* + * The remaining part of the SelectorTree is + * + * B A { + * ident1 : val1; + * ident2 : val2; + * } + */ + children = root->getChildren("B"); + ASSERT_EQ(1, children.size()); + Rooted B = children[0]; + ASSERT_EQ("B", B->getName()); + { + PseudoSelector select{"true", false}; + ASSERT_EQ(select, B->getPseudoSelector()); + } + ASSERT_EQ(1, B->getEdges().size()); + ASSERT_FALSE(B->isAccepting()); + ASSERT_EQ(0, B->getRuleSet()->getRules().size()); + + children = B->getChildren("A"); + ASSERT_EQ(1, children.size()); + Rooted BA = children[0]; + ASSERT_EQ("A", BA->getName()); + { + PseudoSelector select{"true", false}; + ASSERT_EQ(select, BA->getPseudoSelector()); + } + ASSERT_EQ(0, BA->getEdges().size()); + ASSERT_TRUE(BA->isAccepting()); + { + Rooted ruleSet = BA->getRuleSet(); + ASSERT_EQ(2, ruleSet->getRules().size()); + variant::Variant v = ruleSet->getRules()["ident1"]; + ASSERT_EQ(variant::Variant::Type::STRING, v.getType()); + ASSERT_EQ("val1", v.asString()); + v = ruleSet->getRules()["ident2"]; + ASSERT_EQ(variant::Variant::Type::STRING, v.getType()); + ASSERT_EQ("val2", v.asString()); + } } - } } } -- cgit v1.2.3 From c2e5a26f355a7b51743740323c8e28156c0deee5 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Fri, 5 Dec 2014 17:14:55 +0100 Subject: replaced tuple handling by pair handling for nicer reading. --- src/plugins/css/CSSParser.cpp | 18 +++++++++--------- src/plugins/css/CSSParser.hpp | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/plugins/css/CSSParser.cpp b/src/plugins/css/CSSParser.cpp index fc37184..51b2fd2 100644 --- a/src/plugins/css/CSSParser.cpp +++ b/src/plugins/css/CSSParser.cpp @@ -123,13 +123,13 @@ void CSSParser::parseSelectors(Rooted root, auto tuple = parseSelector(tokenizer, ctx); // append the SelectorPath to the root node. std::vector> unmergedLeafs = - root->append(std::get<0>(tuple)); + root->append(tuple.first); // append the leaf to the leafList. switch (unmergedLeafs.size()) { case 0: // if the leaf could be merged we take the leaf reference from the // parseSelector method. - leafList.push_back(std::get<1>(tuple)); + leafList.push_back(tuple.second); break; case 1: // if the leaf could not be merged we take the existing leaf. @@ -149,7 +149,7 @@ void CSSParser::parseSelectors(Rooted root, } } -std::tuple, Rooted> CSSParser::parseSelector( +std::pair, Rooted> CSSParser::parseSelector( CodeTokenizer &tokenizer, ParserContext &ctx) { Rooted s = parsePrimitiveSelector(tokenizer, ctx); @@ -157,7 +157,7 @@ std::tuple, Rooted> CSSParser::parseSelector( if (!tokenizer.peek(t)) { // if we are at the end the found selector is the immediate child as // well as the leaf. - return std::make_tuple(s, s); + return std::make_pair(s, s); } switch (t.tokenId) { case TOKEN_TEXT: { @@ -168,9 +168,9 @@ std::tuple, Rooted> CSSParser::parseSelector( auto tuple = parseSelector(tokenizer, ctx); // then we establish the DESCENDANT relationship s->getEdges().push_back(new SelectorNode::SelectorEdge( - ctx.manager, std::get<0>(tuple))); + ctx.manager, tuple.first)); // and we return this node as well as the leaf. - return std::make_tuple(s, std::get<1>(tuple)); + return std::make_pair(s, tuple.second); } case ARROW: { tokenizer.consumePeek(); @@ -180,15 +180,15 @@ std::tuple, Rooted> CSSParser::parseSelector( auto tuple = parseSelector(tokenizer, ctx); // then we establish the DESCENDANT relationship s->getEdges().push_back(new SelectorNode::SelectorEdge( - ctx.manager, std::get<0>(tuple), + ctx.manager, tuple.first, SelectionOperator::DIRECT_DESCENDANT)); // and we return this node as well as the leaf. - return std::make_tuple(s, std::get<1>(tuple)); + return std::make_pair(s, tuple.second); } default: // everything else is not part of the SelectorPath anymore. tokenizer.resetPeek(); - return std::make_tuple(s, s); + return std::make_pair(s, s); } } diff --git a/src/plugins/css/CSSParser.hpp b/src/plugins/css/CSSParser.hpp index 27a483d..a4d8cdc 100644 --- a/src/plugins/css/CSSParser.hpp +++ b/src/plugins/css/CSSParser.hpp @@ -20,7 +20,7 @@ #define _OUSIA_CSS_PARSER_HPP_ #include -#include +#include #include #include @@ -79,7 +79,7 @@ private: * of the SelectorTree and returns the beginning node of the path as first * element as well as the leaf of the path as second tuple element. */ - std::tuple, Rooted> parseSelector( + std::pair, Rooted> parseSelector( CodeTokenizer &tokenizer, ParserContext &ctx); /** -- cgit v1.2.3 From b7c2dd440523948bebca54a91a4ba06451b473f0 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Fri, 5 Dec 2014 17:38:05 +0100 Subject: transformed the last enum to uppercase. --- src/core/Managed.cpp | 12 ++++++------ src/core/Managed.hpp | 2 +- test/core/ManagedTest.cpp | 42 +++++++++++++++++++++--------------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/core/Managed.cpp b/src/core/Managed.cpp index 8cbbb17..f3a68a3 100644 --- a/src/core/Managed.cpp +++ b/src/core/Managed.cpp @@ -101,7 +101,7 @@ void ObjectDescriptor::incrDegree(RefDir dir, Managed *o) } // Fetch a reference to either the input or the output reference map - auto &m = dir == RefDir::in ? refIn : refOut; + auto &m = dir == RefDir::IN ? refIn : refOut; // Insert a new entry or increment the corresponding reference counter auto it = m.find(o); @@ -128,7 +128,7 @@ bool ObjectDescriptor::decrDegree(RefDir dir, Managed *o, bool all) } // Fetch a reference to either the input or the output reference map - auto &m = dir == RefDir::in ? refIn : refOut; + auto &m = dir == RefDir::IN ? refIn : refOut; // Decrement corresponding reference counter, delete the entry if the // reference counter reaches zero @@ -187,11 +187,11 @@ void Manager::addRef(Managed *tar, Managed *src) // Store the tar <- src reference assert(dTar); - dTar->incrDegree(RefDir::in, src); + dTar->incrDegree(RefDir::IN, src); if (src) { // Store the src -> tar reference assert(dSrc); - dSrc->incrDegree(RefDir::out, tar); + dSrc->incrDegree(RefDir::OUT, tar); } else { // We have just added a root reference, remove the element from the // list of marked objects @@ -207,11 +207,11 @@ void Manager::deleteRef(Managed *tar, Managed *src, bool all) // Decrement the output degree of the source Managed first if (dSrc) { - dSrc->decrDegree(RefDir::out, tar, all); + dSrc->decrDegree(RefDir::OUT, tar, all); } // Decrement the input degree of the input Managed - if (dTar && dTar->decrDegree(RefDir::in, src, all)) { + if (dTar && dTar->decrDegree(RefDir::IN, src, all)) { // If the Managed has a zero in degree, it can be safely deleted, otherwise // if it has no root reference, add it to the "marked" set which is // subject to tracing garbage collection diff --git a/src/core/Managed.hpp b/src/core/Managed.hpp index 6199e33..25fa14b 100644 --- a/src/core/Managed.hpp +++ b/src/core/Managed.hpp @@ -45,7 +45,7 @@ class Owned; * Enum used to specify the direction of a object reference (inbound or * outbound). */ -enum class RefDir { in, out }; +enum class RefDir { IN, OUT }; /** * The ObjectDescriptor struct is used by the Manager for reference counting and diff --git a/test/core/ManagedTest.cpp b/test/core/ManagedTest.cpp index a52ba88..a4011f1 100644 --- a/test/core/ManagedTest.cpp +++ b/test/core/ManagedTest.cpp @@ -42,49 +42,49 @@ TEST(ObjectDescriptor, Degree) ASSERT_EQ(0, nd.refIn.size()); ASSERT_EQ(0, nd.refInCount(n1)); - nd.incrDegree(RefDir::in, n1); + nd.incrDegree(RefDir::IN, n1); ASSERT_EQ(1, nd.refInCount()); ASSERT_EQ(1, nd.refInCount(n1)); ASSERT_EQ(0, nd.refInCount(n2)); ASSERT_EQ(1, nd.refIn.size()); - nd.incrDegree(RefDir::in, n1); + nd.incrDegree(RefDir::IN, n1); ASSERT_EQ(2, nd.refInCount()); ASSERT_EQ(2, nd.refInCount(n1)); ASSERT_EQ(0, nd.refInCount(n2)); ASSERT_EQ(1, nd.refIn.size()); - nd.incrDegree(RefDir::in, n2); + nd.incrDegree(RefDir::IN, n2); ASSERT_EQ(3, nd.refInCount()); ASSERT_EQ(2, nd.refInCount(n1)); ASSERT_EQ(1, nd.refInCount(n2)); ASSERT_EQ(2, nd.refIn.size()); - nd.incrDegree(RefDir::in, nullptr); + nd.incrDegree(RefDir::IN, nullptr); ASSERT_EQ(4, nd.refInCount()); ASSERT_EQ(2, nd.refInCount(n1)); ASSERT_EQ(1, nd.refInCount(n2)); ASSERT_EQ(2, nd.refIn.size()); - ASSERT_TRUE(nd.decrDegree(RefDir::in, n1)); + ASSERT_TRUE(nd.decrDegree(RefDir::IN, n1)); ASSERT_EQ(3, nd.refInCount()); ASSERT_EQ(1, nd.refInCount(n1)); ASSERT_EQ(1, nd.refInCount(n2)); ASSERT_EQ(2, nd.refIn.size()); - ASSERT_TRUE(nd.decrDegree(RefDir::in, n1)); + ASSERT_TRUE(nd.decrDegree(RefDir::IN, n1)); ASSERT_EQ(2, nd.refInCount()); ASSERT_EQ(0, nd.refInCount(n1)); ASSERT_EQ(1, nd.refInCount(n2)); ASSERT_EQ(1, nd.refIn.size()); - ASSERT_TRUE(nd.decrDegree(RefDir::in, n2)); + ASSERT_TRUE(nd.decrDegree(RefDir::IN, n2)); ASSERT_EQ(1, nd.refInCount()); ASSERT_EQ(0, nd.refInCount(n1)); ASSERT_EQ(0, nd.refInCount(n2)); ASSERT_EQ(0, nd.refIn.size()); - ASSERT_TRUE(nd.decrDegree(RefDir::in, nullptr)); + ASSERT_TRUE(nd.decrDegree(RefDir::IN, nullptr)); ASSERT_EQ(0, nd.refInCount()); ASSERT_EQ(0, nd.refInCount(n1)); ASSERT_EQ(0, nd.refInCount(n2)); @@ -94,49 +94,49 @@ TEST(ObjectDescriptor, Degree) ASSERT_EQ(0, nd.refOut.size()); ASSERT_EQ(0, nd.refOutCount(n1)); - nd.incrDegree(RefDir::out, n1); + nd.incrDegree(RefDir::OUT, n1); ASSERT_EQ(1, nd.refOutCount()); ASSERT_EQ(1, nd.refOutCount(n1)); ASSERT_EQ(0, nd.refOutCount(n2)); ASSERT_EQ(1, nd.refOut.size()); - nd.incrDegree(RefDir::out, n1); + nd.incrDegree(RefDir::OUT, n1); ASSERT_EQ(2, nd.refOutCount()); ASSERT_EQ(2, nd.refOutCount(n1)); ASSERT_EQ(0, nd.refOutCount(n2)); ASSERT_EQ(1, nd.refOut.size()); - nd.incrDegree(RefDir::out, n2); + nd.incrDegree(RefDir::OUT, n2); ASSERT_EQ(3, nd.refOutCount()); ASSERT_EQ(2, nd.refOutCount(n1)); ASSERT_EQ(1, nd.refOutCount(n2)); ASSERT_EQ(2, nd.refOut.size()); - nd.incrDegree(RefDir::out, nullptr); + nd.incrDegree(RefDir::OUT, nullptr); ASSERT_EQ(3, nd.refOutCount()); ASSERT_EQ(2, nd.refOutCount(n1)); ASSERT_EQ(1, nd.refOutCount(n2)); ASSERT_EQ(2, nd.refOut.size()); - ASSERT_TRUE(nd.decrDegree(RefDir::out, n1)); + ASSERT_TRUE(nd.decrDegree(RefDir::OUT, n1)); ASSERT_EQ(2, nd.refOutCount()); ASSERT_EQ(1, nd.refOutCount(n1)); ASSERT_EQ(1, nd.refOutCount(n2)); ASSERT_EQ(2, nd.refOut.size()); - ASSERT_TRUE(nd.decrDegree(RefDir::out, n1)); + ASSERT_TRUE(nd.decrDegree(RefDir::OUT, n1)); ASSERT_EQ(1, nd.refOutCount()); ASSERT_EQ(0, nd.refOutCount(n1)); ASSERT_EQ(1, nd.refOutCount(n2)); ASSERT_EQ(1, nd.refOut.size()); - ASSERT_TRUE(nd.decrDegree(RefDir::out, n2)); + ASSERT_TRUE(nd.decrDegree(RefDir::OUT, n2)); ASSERT_EQ(0, nd.refOutCount()); ASSERT_EQ(0, nd.refOutCount(n1)); ASSERT_EQ(0, nd.refOutCount(n2)); ASSERT_EQ(0, nd.refOut.size()); - ASSERT_TRUE(nd.decrDegree(RefDir::out, nullptr)); + ASSERT_TRUE(nd.decrDegree(RefDir::OUT, nullptr)); ASSERT_EQ(0, nd.refOutCount()); ASSERT_EQ(0, nd.refOutCount(n1)); ASSERT_EQ(0, nd.refOutCount(n2)); @@ -148,10 +148,10 @@ TEST(ObjectDescriptor, rootRefCount) ObjectDescriptor nd; ASSERT_EQ(0, nd.rootRefCount); - nd.incrDegree(RefDir::in, nullptr); + nd.incrDegree(RefDir::IN, nullptr); ASSERT_EQ(1, nd.rootRefCount); - nd.incrDegree(RefDir::out, nullptr); + nd.incrDegree(RefDir::OUT, nullptr); ASSERT_EQ(2, nd.rootRefCount); ASSERT_EQ(2, nd.refInCount(nullptr)); @@ -159,13 +159,13 @@ TEST(ObjectDescriptor, rootRefCount) ASSERT_EQ(0, nd.refOutCount(nullptr)); ASSERT_EQ(0, nd.refOutCount()); - ASSERT_TRUE(nd.decrDegree(RefDir::out, nullptr)); + ASSERT_TRUE(nd.decrDegree(RefDir::OUT, nullptr)); ASSERT_EQ(1, nd.rootRefCount); - ASSERT_TRUE(nd.decrDegree(RefDir::in, nullptr)); + ASSERT_TRUE(nd.decrDegree(RefDir::IN, nullptr)); ASSERT_EQ(0, nd.rootRefCount); - ASSERT_FALSE(nd.decrDegree(RefDir::in, nullptr)); + ASSERT_FALSE(nd.decrDegree(RefDir::IN, nullptr)); ASSERT_EQ(0, nd.rootRefCount); } -- cgit v1.2.3