summaryrefslogtreecommitdiff
path: root/src/core/CSSParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/CSSParser.cpp')
-rw-r--r--src/core/CSSParser.cpp103
1 files changed, 52 insertions, 51 deletions
diff --git a/src/core/CSSParser.cpp b/src/core/CSSParser.cpp
index 3a86f45..d239359 100644
--- a/src/core/CSSParser.cpp
+++ b/src/core/CSSParser.cpp
@@ -19,6 +19,8 @@
#include "CSSParser.hpp"
namespace ousia {
+namespace parser {
+namespace css {
// CSS code tokens
static const int CURLY_OPEN = 1;
@@ -76,19 +78,18 @@ static const std::map<int, CodeTokenDescriptor> CSS_DESCRIPTORS = {
{ESCAPE, {CodeTokenMode::ESCAPE, ESCAPE}},
{LINEBREAK, {CodeTokenMode::LINEBREAK, LINEBREAK}}};
-Rooted<SelectorNode> CSSParser::parse(BufferedCharReader &input)
+Rooted<Node> CSSParser::parse(std::istream &is, ParserContext &ctx)
{
+ BufferedCharReader input{is};
CodeTokenizer tokenizer{input, CSS_ROOT, CSS_DESCRIPTORS};
tokenizer.ignoreComments = true;
- // TODO: Is this the correct way to retrieve the Manager?
- Manager mgr;
- Rooted<SelectorNode> root = {new SelectorNode{mgr, "root"}};
- parseDocument(root, tokenizer);
+ Rooted<SelectorNode> root = {new SelectorNode{ctx.manager, "root"}};
+ parseDocument(root, tokenizer, ctx);
return root;
}
void CSSParser::parseDocument(Rooted<SelectorNode> root,
- CodeTokenizer &tokenizer)
+ CodeTokenizer &tokenizer, ParserContext &ctx)
{
Token t;
if (!tokenizer.peek(t)) {
@@ -96,16 +97,17 @@ void CSSParser::parseDocument(Rooted<SelectorNode> root,
}
tokenizer.resetPeek();
std::vector<Rooted<SelectorNode>> leafList;
- parseSelectors(root, tokenizer, leafList);
+ parseSelectors(root, tokenizer, leafList, ctx);
// TODO: Parse Ruleset
- parseDocument(root, tokenizer);
+ parseDocument(root, tokenizer, ctx);
}
void CSSParser::parseSelectors(Rooted<SelectorNode> root,
CodeTokenizer &tokenizer,
- std::vector<Rooted<SelectorNode>> &leafList)
+ std::vector<Rooted<SelectorNode>> &leafList,
+ ParserContext &ctx)
{
- auto tuple = parseSelector(tokenizer);
+ auto tuple = parseSelector(tokenizer, ctx);
// append the SelectorPath to the root node.
std::vector<Rooted<SelectorNode>> unmergedLeafs =
root->append(std::get<0>(tuple));
@@ -123,7 +125,7 @@ void CSSParser::parseSelectors(Rooted<SelectorNode> root,
case 2:
// as the parseSelector is supposed to parse only a SelectorPath
// there should not be more than one leaf.
- throw LoggableException{
+ throw ParserException{
"Internal Error: More than one leaf in SelectorPath!", "",
// TODO: Line handling?
// tokenizer.getInput().getLine(),
@@ -132,15 +134,15 @@ void CSSParser::parseSelectors(Rooted<SelectorNode> root,
}
// if we find a comma, we can proceed parsing selectors.
Token t;
- if (expect(COMMA, tokenizer, t, false)) {
- parseSelectors(root, tokenizer, leafList);
+ if (expect(COMMA, tokenizer, t, false, ctx)) {
+ parseSelectors(root, tokenizer, leafList, ctx);
}
}
std::tuple<Rooted<SelectorNode>, Rooted<SelectorNode>> CSSParser::parseSelector(
- CodeTokenizer &tokenizer)
+ CodeTokenizer &tokenizer, ParserContext &ctx)
{
- Rooted<SelectorNode> s = parsePrimitiveSelector(tokenizer);
+ Rooted<SelectorNode> s = parsePrimitiveSelector(tokenizer, ctx);
Token t;
if (!tokenizer.peek(t)) {
// if we are at the end the found selector is the immediate child as
@@ -153,12 +155,10 @@ std::tuple<Rooted<SelectorNode>, Rooted<SelectorNode>> CSSParser::parseSelector(
// relationship (A B)
tokenizer.resetPeek();
// so we parse the rest of the subsequent SelectorPath
- auto tuple = parseSelector(tokenizer);
+ auto tuple = parseSelector(tokenizer, ctx);
// then we establish the DESCENDANT relationship
- // TODO: Is this the correct way to retrieve the Manager?
- Manager mgr;
- s->getEdges().push_back(
- new SelectorNode::SelectorEdge(mgr, std::get<0>(tuple)));
+ s->getEdges().push_back(new SelectorNode::SelectorEdge(
+ ctx.manager, std::get<0>(tuple)));
// and we return this node as well as the leaf.
return std::make_tuple(s, std::get<1>(tuple));
}
@@ -167,12 +167,11 @@ std::tuple<Rooted<SelectorNode>, Rooted<SelectorNode>> CSSParser::parseSelector(
// if we find an arrow there is a next token in a CHILD
// relationship (A > B)
// so we parse the rest of the subsequent SelectorPath
- auto tuple = parseSelector(tokenizer);
+ auto tuple = parseSelector(tokenizer, ctx);
// then we establish the DESCENDANT relationship
- // TODO: Is this the correct way to retrieve the Manager?
- Manager mgr;
s->getEdges().push_back(new SelectorNode::SelectorEdge(
- mgr, std::get<0>(tuple), SelectionOperator::DIRECT_DESCENDANT));
+ ctx.manager, std::get<0>(tuple),
+ SelectionOperator::DIRECT_DESCENDANT));
// and we return this node as well as the leaf.
return std::make_tuple(s, std::get<1>(tuple));
}
@@ -183,17 +182,16 @@ std::tuple<Rooted<SelectorNode>, Rooted<SelectorNode>> CSSParser::parseSelector(
}
}
-Rooted<SelectorNode> CSSParser::parsePrimitiveSelector(CodeTokenizer &tokenizer)
+Rooted<SelectorNode> CSSParser::parsePrimitiveSelector(CodeTokenizer &tokenizer,
+ ParserContext &ctx)
{
// first and foremost we expect a class name.
Token t;
- expect(TOKEN_TEXT, tokenizer, t, true);
+ expect(TOKEN_TEXT, tokenizer, t, true, ctx);
const std::string name = t.content;
- // TODO: Is this the correct way to retrieve the Manager?
- Manager mgr;
if (!tokenizer.peek(t)) {
// if we are at the end, we just return this selector with its name.
- Rooted<SelectorNode> n{new SelectorNode(mgr, name)};
+ Rooted<SelectorNode> n{new SelectorNode(ctx.manager, name)};
return n;
}
@@ -203,33 +201,34 @@ Rooted<SelectorNode> CSSParser::parsePrimitiveSelector(CodeTokenizer &tokenizer)
case DOUBLE_COLON:
// if we find a double colon we have a generative PseudoSelector.
isGenerative = true;
+ // this is supposed to fall through; no missing break.
case COLON: {
// if we find a colon we have a restrictive PseudoSelector.
tokenizer.consumePeek();
// get the PseudoSelector name.
- expect(TOKEN_TEXT, tokenizer, t, true);
+ expect(TOKEN_TEXT, tokenizer, t, true, ctx);
const std::string pseudo_select_name = t.content;
// look for additional arguments.
- if (!expect(PAREN_OPEN, tokenizer, t, false)) {
+ if (!expect(PAREN_OPEN, tokenizer, t, false, ctx)) {
// if we don't have any, we return here.
Rooted<SelectorNode> n{new SelectorNode(
- mgr, name, {pseudo_select_name, isGenerative})};
+ ctx.manager, name, {pseudo_select_name, isGenerative})};
return n;
}
// parse the argument list.
std::vector<std::string> args;
// we require at least one argument, if parantheses are used
- expect(TOKEN_TEXT, tokenizer, t, true);
+ expect(TOKEN_TEXT, tokenizer, t, true, ctx);
args.push_back(t.content);
- while (expect(COMMA, tokenizer, t, false)) {
+ while (expect(COMMA, tokenizer, t, false, ctx)) {
// as long as we find commas we expect new arguments.
- expect(TOKEN_TEXT, tokenizer, t, true);
+ expect(TOKEN_TEXT, tokenizer, t, true, ctx);
args.push_back(t.content);
}
- expect(PAREN_CLOSE, tokenizer, t, true);
+ expect(PAREN_CLOSE, tokenizer, t, true, ctx);
// and we return with the finished Selector.
Rooted<SelectorNode> n{new SelectorNode(
- mgr, name, {pseudo_select_name, args, isGenerative})};
+ ctx.manager, name, {pseudo_select_name, args, isGenerative})};
return n;
}
case HASH: {
@@ -237,11 +236,11 @@ Rooted<SelectorNode> CSSParser::parsePrimitiveSelector(CodeTokenizer &tokenizer)
// :has_id(id)
// so we expect an ID now.
Token t;
- expect(TOKEN_TEXT, tokenizer, t, true);
+ expect(TOKEN_TEXT, tokenizer, t, true, ctx);
std::vector<std::string> args{t.content};
// and we return the finished Selector
Rooted<SelectorNode> n{
- new SelectorNode(mgr, name, {"has_id", args, false})};
+ new SelectorNode(ctx.manager, name, {"has_id", args, false})};
return n;
}
case BRACKET_OPEN: {
@@ -252,34 +251,34 @@ Rooted<SelectorNode> CSSParser::parsePrimitiveSelector(CodeTokenizer &tokenizer)
// has_value [attribute_name="value"]
// in both cases the attribute name comes first.
Token t;
- expect(TOKEN_TEXT, tokenizer, t, true);
+ expect(TOKEN_TEXT, tokenizer, t, true, ctx);
std::vector<std::string> args{t.content};
- if (!expect(EQUALS, tokenizer, t, false)) {
+ if (!expect(EQUALS, tokenizer, t, false, ctx)) {
// if no equals sign follows we have a has_attribute
// PseudoSelector
// we expect a closing bracket.
- expect(BRACKET_CLOSE, tokenizer, t, true);
+ expect(BRACKET_CLOSE, tokenizer, t, true, ctx);
// and then we can return the result.
Rooted<SelectorNode> n{new SelectorNode(
- mgr, name, {"has_attribute", args, false})};
+ ctx.manager, name, {"has_attribute", args, false})};
return n;
} else {
// with an equals sign we have a has_value PseudoSelector and
// expect the value next.
- expect(STRING, tokenizer, t, true);
+ expect(STRING, tokenizer, t, true, ctx);
args.push_back(t.content);
// then we expect a closing bracket.
- expect(BRACKET_CLOSE, tokenizer, t, true);
+ expect(BRACKET_CLOSE, tokenizer, t, true, ctx);
// and then we can return the result.
- Rooted<SelectorNode> n{
- new SelectorNode(mgr, name, {"has_value", args, false})};
+ Rooted<SelectorNode> n{new SelectorNode(
+ ctx.manager, name, {"has_value", args, false})};
return n;
}
}
default:
// everything else is not part of the Selector anymore.
tokenizer.resetPeek();
- Rooted<SelectorNode> n{new SelectorNode(mgr, name)};
+ Rooted<SelectorNode> n{new SelectorNode(ctx.manager, name)};
return n;
}
}
@@ -287,20 +286,20 @@ Rooted<SelectorNode> CSSParser::parsePrimitiveSelector(CodeTokenizer &tokenizer)
// TODO: Add RuleSet parsing methods.
bool CSSParser::expect(int expectedType, CodeTokenizer &tokenizer, Token &t,
- bool force)
+ bool force, ParserContext &ctx)
{
bool end = !tokenizer.peek(t);
if (end || t.tokenId != expectedType) {
if (force) {
if (end) {
- throw LoggableException{
+ throw ParserException{
"Unexpected end of file!", "",
// TODO: Line handling?
// tokenizer.getInput().getLine(),
// tokenizer.getInput().getColumn()
};
} else {
- throw LoggableException{
+ throw ParserException{
"Unexpected token!", "",
// TODO: Line handling?
// tokenizer.getInput().getLine(),
@@ -316,3 +315,5 @@ bool CSSParser::expect(int expectedType, CodeTokenizer &tokenizer, Token &t,
return true;
}
}
+}
+}