Relax parsing rules and fix minor issues
This commit is contained in:
parent
6bab8338f8
commit
e37f8efd6e
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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_;
|
||||||
|
|
||||||
|
@ -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,15 +43,13 @@ 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{
|
|
||||||
*move(expr),
|
|
||||||
context().warnings(),
|
|
||||||
context().errors()
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullopt;
|
return query_t{
|
||||||
|
move(expr),
|
||||||
|
context().warnings(),
|
||||||
|
context().errors()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<expression_t>
|
optional<expression_t>
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user