Header lexy/dsl/production.hpp
The inline_, p, and recurse rules.
Rule lexy::dsl::inline_
lexy/dsl/production.hppnamespace lexy::dsl
{
template <production P>
constexpr rule auto inline_;
template <production P>
requires token-rule<production_rule<P>>
constexpr token-rule auto inline_;
template <production P>
requires branch-rule<production_rule<P>>
constexpr branch-rule auto inline_;
}inline_ is a rule that parses the rule of production P as part of the current production.
- Requires
Pis a complete type, i.e.pcannot be used for recursion.- Matching
Matches
P::rule.- (Branch) Parsing
Parses
P::rule.- Errors
All errors raised by
P::rule. The rule then fails ifP::rulehas failed.- Values
All values produced by
P::rule.
struct name
{
static constexpr auto rule
// One or more alpha numeric characters, underscores or hyphens.
= dsl::identifier(dsl::unicode::alnum / dsl::lit_c<'_'> / dsl::lit_c<'-'>);
};
struct production
{
// Allow arbitrary spaces between individual tokens.
// Note that this includes the individual characters of the name.
static constexpr auto whitespace = dsl::ascii::space;
static constexpr auto rule = [] {
auto greeting = LEXY_LIT("Hello");
return greeting + dsl::inline_<name> + dsl::exclamation_mark + dsl::eof;
}();
};Tip | Use inline_ when you need to parse a production as part of the whitespace rule. |
Rule lexy::dsl::p
lexy/dsl/production.hppnamespace lexy::dsl
{
template <production P>
constexpr rule auto p;
template <production P>
requires branch-rule<production_rule<P>> && !defines-whitespace<P>`
constexpr branch-rule auto p;
}p is a rule that parses the production P.
- Requires
Pis a complete type, i.e.pcannot be used for recursion.- (Branch) Parsing
Parses
P::rulein a new context forP, potentially after skipping initialwhitespaceifP::whitespacehas been defined.- Errors
All errors raised by parsing
P::rule, but forwarded to the new context forP. The rule fails ifP::rulehas failed.- Values
All values produced by
P::ruleare forwarded to the new context, e.g. toP::value. The final value of the context is produced as the single value forp.- Parse tree
If
Pinherits fromlexy::transparent_production, the nodes generated byP::ruleare added to the parse tree as if they were added bypitself.Otherwise, it creates a single production node for
P. Its children are all the nodes generated byP::rule.
struct name
{
static constexpr auto rule
// One or more alpha numeric characters, underscores or hyphens.
= dsl::identifier(dsl::unicode::alnum / dsl::lit_c<'_'> / dsl::lit_c<'-'>);
};
struct production
{
// Allow arbitrary spaces between individual tokens.
static constexpr auto whitespace = dsl::ascii::space;
static constexpr auto rule = [] {
auto greeting = LEXY_LIT("Hello");
return greeting + dsl::p<name> + dsl::exclamation_mark + dsl::eof;
}();
};constexpr auto id = dsl::identifier(dsl::ascii::alpha);
constexpr auto kw_function = LEXY_KEYWORD("function", id);
constexpr auto kw_type = LEXY_KEYWORD("type", id);
struct function_decl
{
static constexpr auto rule = [] {
auto arguments = dsl::parenthesized(LEXY_LIT("..."));
auto body = dsl::curly_bracketed(LEXY_LIT("..."));
return kw_function >> id + arguments + body;
}();
};
struct type_decl
{
static constexpr auto rule //
= kw_type >> id + dsl::lit_c<'='> + id + dsl::semicolon;
};
struct production
{
static constexpr auto whitespace = dsl::ascii::space;
static constexpr auto rule = dsl::p<function_decl> | dsl::p<type_decl>;
};Note | The p rule cannot handle direct or indirect recursion, as P must be a complete type. |
Caution | While parsing P::rule, the current whitespace rule can be different.
If whitespace parsing has been disabled using lexy::dsl::no_whitespace,
it is temporarily re-enabled while parsing P::rule.
If whitespace parsing has been disabled because the current production inherits from lexy::token_production,
it is still disabled, unless the current production explicitly defines a new whitespace rule. |
Rule lexy::dsl::recurse
lexy/dsl/production.hppnamespace lexy
{
struct max_recursion_depth_exceeded {};
}
namespace lexy::dsl
{
struct recurse // models rule or branch-rule
{
template <typename Tag>
static constexpr recurse max_depth_error;
};
template <production P>
constexpr recurse auto recurse; // rule
template <production P>
constexpr recurse auto recurse_branch; // branch-rule
}recurse is a rule that parses the production P but supports recursion.
It behaves similar to the p rule, but P does not need to a be a complete type, which allows recursion.
For the same reason, recurse<P> is never a branch rule: it can’t know whether P is a branch.
Use recurse_branch<P> if you know that P is a branch; it will cause a delayed static_assert if it isn’t.
- Parsing
Checks whether the current depth of recursive production call exceeds the maximum parse depth, which is determined by
lexy::max_recursion_depth. Fails, if that is the case. Otherwise, parsesp<P>, i.e. the productionP.- Branch parsing
Branch parses
p<P>, i.e. the productionP. The recursive depth check is done after the branch condition has matched. It will not backtrack if the condition matches but the depth is exceeded.- Errors
A generic error with the specified
Tagorlexy::max_recursion_depth_exceededif the recursive depth is exceeded, at the position where it would have started to match the production. It then fails without recovering.All errors raised by parsing
p<P>.
struct production
{
// We define a (tiny) maximum recursion depth.
// This prevents unbounded recursion which can cause a stack overflow.
static constexpr auto max_recursion_depth = 3;
static constexpr auto rule
// Either we parse ourselves surrounded by expressions, or an atom.
= dsl::parenthesized(dsl::recurse<production>) | LEXY_LIT("atom");
};Warning | Left recursion will create a max recursion error.
Use lexy::dsl::loop or lexy::dsl::list instead. |
Note | The recursion depth only counts productions parsed by recurse; intermediate productions parsed using p are ignored.
In particular, the nesting level of p rules, which is statically determined by the grammar and not by the input, is allowed to exceed the maximum recursion depth. |