Why do I need a peek if I have a LEXY_LIT in a branch condition? #160
-
I am not quite sure why I need an dsl::peek in Statement if the first check StaticQualifiedPoint does is against the literal "static". Similarly for Point it checks against an identifier that then has an equal sign. Maybe I am getting confused with the Parsec library for Haskell where errors are propagated as far as needed up the call chain until something succeeds. struct Statement : lexy::token_production {
struct InvalidStatement {
static LEXY_CONSTEVAL auto name() { return "statement is not point, qualifier or graphical element"; }
};
static constexpr auto rule = []{
return dsl::p<StaticQualifiedPoint>
| dsl::p<Point>
| dsl::error<InvalidStatement>;
}();
static constexpr auto value = lexy::construct<ast::Statement>;
}; Full code: namespace input_reader::internal {
namespace ast {
using Identifier = std::string;
struct Static {};
struct Decimal {
int integer;
std::optional<std::string> fraction;
};
struct Point {
Identifier identifier;
Decimal xCoordinate;
Decimal yCoordinate;
};
struct StaticQualifiedPoint {
Identifier identifier;
};
struct Statement {
std::variant<Point, StaticQualifiedPoint> value;
template <typename T>
explicit Statement(T specificValue)
: value(std::move(specificValue)) {}
};
using SimulationState = std::vector<Statement>;
} // ast
namespace grammar {
namespace dsl = lexy::dsl;
struct Identifier : lexy::token_production {
static constexpr auto rule = [] {
auto head = dsl::ascii::alpha_underscore;
auto tail = dsl::ascii::alpha_digit_underscore;
return dsl::identifier(head, tail).reserve(LEXY_LIT("static"));
}();
static constexpr auto value = lexy::as_string<ast::Identifier, lexy::utf8_encoding>;
};
struct Static : lexy::token_production {
static constexpr auto rule = LEXY_LIT("static");
static constexpr auto value = lexy::construct<ast::Static>;
};
struct Decimal : lexy::token_production {
struct IntegerPart : lexy::transparent_production {
static constexpr auto rule =
dsl::minus_sign + dsl::integer<int>(dsl::digits<>.no_leading_zero());
static constexpr auto value = lexy::as_integer<int>;
};
struct DecimalPart : lexy::transparent_production {
static constexpr auto rule = dsl::lit_c<'.'> >> dsl::capture(dsl::digits<>);
static constexpr auto value = lexy::as_string<std::string>;
};
static constexpr auto rule = dsl::peek(dsl::lit_c<'-'> / dsl::digit<>)
>> (dsl::p<IntegerPart> + dsl::opt(dsl::p<DecimalPart>));
static constexpr auto value = lexy::construct<ast::Decimal>;
};
struct Point : lexy::token_production {
static constexpr auto whitespace = dsl::ascii::blank;
static constexpr auto rule = [] {
auto identifier = (dsl::member<& ast::Point::identifier> = dsl::p<Identifier>);
auto xCoordinate = (dsl::member<& ast::Point::xCoordinate> = dsl::p<Decimal>);
auto yCoordinate = (dsl::member<& ast::Point::yCoordinate> = dsl::p<Decimal>);
return identifier + dsl::equal_sign + dsl::parenthesized(xCoordinate + dsl::comma + yCoordinate);
}();
static constexpr auto value = lexy::as_aggregate<ast::Point>;
};
struct StaticQualifiedPoint : lexy::token_production {
static constexpr auto whitespace = dsl::ascii::blank;
static constexpr auto rule = dsl::p<Static> + dsl::p<Identifier>;
static constexpr auto value = lexy::construct<ast::StaticQualifiedPoint>; // TODO correct
};
struct Statement : lexy::token_production {
struct InvalidStatement {
static LEXY_CONSTEVAL auto name() { return "statement is not point, qualifier or graphical element"; }
};
static constexpr auto rule = []{
return dsl::p<StaticQualifiedPoint>
| dsl::p<Point>
| dsl::error<InvalidStatement>;
}();
static constexpr auto value = lexy::construct<ast::Statement>;
};
/**
* Entrypoint
*/
struct SimulationState {
static constexpr auto whitespace = dsl::ascii::blank / dsl::ascii::newline;
static constexpr auto rule = dsl::terminator(dsl::eof).opt_list(dsl::p<Statement>);
static constexpr auto value = lexy::as_list<ast::SimulationState>;
};
} // grammar
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Yes, that is not how lexy works. In lexy backtracking is explicit, it will not just try a rule and hope for the best. You need to tell lexy how it should decide which rule to take. That is accomplished with the As an aside, if you have a new whitespace rule, you shouldn't need to use |
Beta Was this translation helpful? Give feedback.
Yes, that is not how lexy works. In lexy backtracking is explicit, it will not just try a rule and hope for the best. You need to tell lexy how it should decide which rule to take. That is accomplished with the
>>
operator. In the case ofStaticQualifiedPoint
, you want that rule to be taken whenStatic
is encountered, so change the rule todsl::p<Static> >> dsl::p<Identifier>
. Further reading: https://lexy.foonathan.net/learn/branching/As an aside, if you have a new whitespace rule, you shouldn't need to use
lexy::token_production
.