Relax parsing rules and fix minor issues

This commit is contained in:
G.H.O.S.T 2024-12-30 14:30:15 +01:00
parent 6bab8338f8
commit e37f8efd6e
Signed by: G.H.O.S.T
GPG Key ID: 3BD93EABD1407B82
12 changed files with 141 additions and 36 deletions

View File

@ -23,11 +23,11 @@ public:
friend friend
void void
accept(expression_t const& e, visitor_t& v); accept(expression_t const&, visitor_t&);
friend friend
string string
to_string(expression_t const& e); to_string(expression_t const&);
private: private:
struct abstract_t struct abstract_t

View File

@ -32,7 +32,7 @@ namespace code::query
}; };
string string
to_string(logical_and_t const); to_string(logical_and_t const&);
} // namespace code::query } // namespace code::query

View File

@ -32,7 +32,7 @@ namespace code::query
}; };
string string
to_string(logical_or_t const); to_string(logical_or_t const&);
} // namespace code::query } // namespace code::query

View File

@ -25,10 +25,14 @@ namespace code::query
public: public:
static static
bool bool
match(expression_t const& e, predicate_t const& p) match(optional<expression_t> const& e, predicate_t const& p)
{ {
matcher_t m{p}; matcher_t m{p};
accept(e, m);
if (e) {
accept(*e, m);
}
return m.result; return m.result;
} }

View File

@ -6,11 +6,10 @@
namespace code::query namespace code::query
{ {
optional<query_t> query_t
try_parse(string const& q, parse_context_t& context) try_parse(string const& q, parse_context_t& context)
{ {
string_lexical_analyzer_t lexer{q.begin(), q.end()}; string_lexical_analyzer_t lexer{q.begin(), q.end()};
return syntactical_analyzer_t{lexer, context}.try_parse(); return syntactical_analyzer_t{lexer, context}.try_parse();
} }

View File

@ -8,7 +8,7 @@
namespace code::query namespace code::query
{ {
optional<query_t> query_t
try_parse(string const&, parse_context_t&); try_parse(string const&, parse_context_t&);
} // namespace code::query } // namespace code::query

View File

@ -4,7 +4,7 @@ namespace code::query
{ {
query_t:: query_t::
query_t(expression_t e, query_t(optional<expression_t> e,
vector<warning_t> warnings, vector<warning_t> warnings,
vector<error_t> errors) vector<error_t> errors)
: expr_{move(e)}, : expr_{move(e)},
@ -12,7 +12,7 @@ namespace code::query
errors_{move(errors)} errors_{move(errors)}
{} {}
expression_t const& optional<expression_t> const&
query_t:: query_t::
expr() const expr() const
{ {
@ -36,13 +36,19 @@ namespace code::query
void void
accept(query_t const& q, visitor_t& v) accept(query_t const& q, visitor_t& v)
{ {
accept(q.expr(), v); if (q.expr()) {
accept(*q.expr(), v);
}
} }
string string
to_string(query_t const& q) to_string(query_t const& q)
{ {
return to_string(q.expr()); if (q.expr()) {
return to_string(*q.expr());
}
return string{};
} }
} // namespace code::query } // namespace code::query

View File

@ -12,11 +12,11 @@ namespace code::query
class query_t class query_t
{ {
public: public:
query_t(expression_t e, query_t(optional<expression_t> e,
vector<warning_t> warnings, vector<warning_t> warnings,
vector<error_t> errors); vector<error_t> errors);
expression_t const& optional<expression_t> const&
expr() const; expr() const;
vector<warning_t> const& vector<warning_t> const&
@ -26,7 +26,7 @@ namespace code::query
errors() const; errors() const;
private: private:
expression_t expr_; optional<expression_t> expr_;
vector<warning_t> warnings_; vector<warning_t> warnings_;
vector<error_t> errors_; vector<error_t> errors_;

View File

@ -31,7 +31,7 @@ namespace code::query
return context_; return context_;
} }
optional<query_t> query_t
syntactical_analyzer_t:: syntactical_analyzer_t::
try_parse() try_parse()
{ {
@ -43,17 +43,15 @@ namespace code::query
if (last.type() != token_type_t::end) { if (last.type() != token_type_t::end) {
context().report_warning({{}, "trailing token at end of query"}); context().report_warning({{}, "trailing token at end of query"});
} }
}
return query_t{ return query_t{
*move(expr), move(expr),
context().warnings(), context().warnings(),
context().errors() context().errors()
}; };
} }
return nullopt;
}
optional<expression_t> optional<expression_t>
syntactical_analyzer_t:: syntactical_analyzer_t::
try_parse_primary_expression() try_parse_primary_expression()
@ -63,7 +61,11 @@ namespace code::query
for (;;) { for (;;) {
auto t = lexer().peek(); auto t = lexer().peek();
if (t.type() == token_type_t::logical_not) { if (t.type() == token_type_t::end) {
break;
}
else if (t.type() == token_type_t::logical_not) {
lexer().consume(); lexer().consume();
auto rhs = try_parse_primary_expression(); auto rhs = try_parse_primary_expression();
@ -75,7 +77,7 @@ namespace code::query
if (expr) { if (expr) {
expr = logical_and_t{ expr = logical_and_t{
source_location_t{}, *expr, logical_not_t{{}, *rhs} {}, *expr, logical_not_t{{}, *rhs}
}; };
} }
else { else {
@ -91,6 +93,12 @@ namespace code::query
if (lexer().peek().type() == token_type_t::colon) { if (lexer().peek().type() == token_type_t::colon) {
lexer().consume(); lexer().consume();
// consume trailing colons as well.
//
while (lexer().peek().type() == token_type_t::colon) {
lexer().consume();
}
auto identifier = *t.value(); auto identifier = *t.value();
// Next expect a term or quoted term. // Next expect a term or quoted term.
@ -100,7 +108,8 @@ namespace code::query
if (t.type() != token_type_t::simple_term && if (t.type() != token_type_t::simple_term &&
t.type() != token_type_t::quoted_term) { t.type() != token_type_t::quoted_term) {
context().report_warning({{}, "expected simple-term or quoted-term after tag" }); context().report_warning({{}, "expected simple-term or quoted-term after tag" });
break; lexer().consume();
continue;
} }
lexer().consume(); lexer().consume();
@ -114,7 +123,7 @@ namespace code::query
}; };
if (expr) { if (expr) {
expr = logical_and_t{ expr = logical_or_t{
{}, *expr, tag_t{{}, move(identifier), move(term)} {}, *expr, tag_t{{}, move(identifier), move(term)}
}; };
} }
@ -123,7 +132,7 @@ namespace code::query
} }
} }
else if (expr) { else if (expr) {
expr = logical_and_t{ expr = logical_or_t{
{}, *expr, term_t{{}, term_t::simple, *t.value()} {}, *expr, term_t{{}, term_t::simple, *t.value()}
}; };
} }
@ -134,7 +143,7 @@ namespace code::query
else if (t.type() == token_type_t::quoted_term) { else if (t.type() == token_type_t::quoted_term) {
if (expr) { if (expr) {
expr = logical_and_t{ expr = logical_or_t{
{}, *expr, term_t{{}, term_t::quoted, *t.value()} {}, *expr, term_t{{}, term_t::quoted, *t.value()}
}; };
} }
@ -159,23 +168,24 @@ namespace code::query
if (!next_expr) { if (!next_expr) {
context().report_warning({{}, "expected expression inside parenthesis"}); context().report_warning({{}, "expected expression inside parenthesis"});
break; lexer().consume();
continue;
} }
next_expr = parenthesized_t{{}, *next_expr}; next_expr = parenthesized_t{{}, *next_expr};
if (expr) { if (expr) {
expr = logical_and_t{{}, *expr, *next_expr}; expr = logical_or_t{{}, *expr, *next_expr};
} }
else { else {
expr = next_expr; expr = next_expr;
} }
t = lexer().peek(); t = lexer().peek();
if (t.type() != token_type_t::close_parens) { if (t.type() != token_type_t::close_parens) {
context().report_warning({{}, "expected end parenthesis"}); context().report_warning({{}, "expected end parenthesis"});
break; lexer().consume();
continue;
} }
lexer().consume(); lexer().consume();
@ -195,8 +205,9 @@ namespace code::query
{ {
auto lhs = try_parse_primary_expression(); auto lhs = try_parse_primary_expression();
if (!lhs) if (!lhs) {
return nullopt; return nullopt;
}
while (lexer().peek().type() == token_type_t::logical_and) { while (lexer().peek().type() == token_type_t::logical_and) {
lexer().consume(); lexer().consume();
@ -239,6 +250,34 @@ namespace code::query
syntactical_analyzer_t:: syntactical_analyzer_t::
try_parse_expression() try_parse_expression()
{ {
auto invalid = [](token_t const& token)
{
if (token.type() == token_type_t::end) {
return false;
}
if (token.type() == token_type_t::simple_term) {
return false;
}
if (token.type() == token_type_t::quoted_term) {
return false;
}
if (token.type() == token_type_t::open_parens) {
return false;
}
return true;
};
// filter leading invalid tokens.
//
while (invalid(lexer().peek())) {
context().report_warning({{}, "invalid leading token"});
lexer().consume();
}
return try_parse_logical_or(); return try_parse_logical_or();
} }

View File

@ -21,7 +21,7 @@ namespace code::query
parse_context_t& parse_context_t&
context(); context();
optional<query_t> query_t
try_parse(); try_parse();
private: private:

View File

@ -23,4 +23,56 @@ namespace code::query
return value_; return value_;
} }
std::ostream&
operator<<(std::ostream& o, token_t const& token)
{
switch (token.type()) {
case token_type_t::end:
o << "end";
break;
case token_type_t::simple_term:
o << "simple-term";
break;
case token_type_t::quoted_term:
o << "quoted-term";
break;
case token_type_t::colon:
o << "colon";
break;
case token_type_t::logical_and:
o << "logical-and";
break;
case token_type_t::logical_not:
o << "logical-not";
break;
case token_type_t::logical_or:
o << "logical-or";
break;
case token_type_t::open_parens:
o << "open-parens";
break;
case token_type_t::close_parens:
o << "close-parens";
break;
}
if (auto v = token.value(); v) {
o << ": " << *v;
}
o << '\n';
return o;
}
} // namespace code::query } // namespace code::query

View File

@ -3,6 +3,8 @@
#include <code/query/types.hxx> #include <code/query/types.hxx>
#include <iostream>
namespace code::query namespace code::query
{ {
@ -42,6 +44,9 @@ namespace code::query
}; };
std::ostream&
operator<<(std::ostream&, token_t const&);
} // namespace code::query } // namespace code::query
#endif #endif