Header lexy/dsl/parse_tree_node.hpp Experimental

Example 1. Re-parse a parse tree
// A simple grammar for a single key-value pair.
namespace grammar
{
struct key
{
    static constexpr auto rule = dsl::identifier(dsl::ascii::alnum);
};

struct integer
{
    static constexpr auto rule = dsl::digits<>;
};

struct key_value_pair
{
    static constexpr auto whitespace = dsl::ascii::space;
    static constexpr auto rule       = dsl::p<key> + dsl::lit_c<'='> + dsl::p<integer>;
};
} // namespace grammar

namespace tree_grammar
{
struct integer
{
    // Match the digits token and extract their integer value.
    static constexpr auto rule  = dsl::tnode<lexy::digits_token_kind>(dsl::integer<int>);
    static constexpr auto value = lexy::as_integer<int>;
};

struct key_value_pair
{
    // Skip over literal and whitespace tokens automatically.
    static constexpr auto whitespace
        = dsl::tnode<lexy::literal_token_kind> | dsl::tnode<lexy::whitespace_token_kind>;

    // Skip the key production but parse the children of the integer production.
    static constexpr auto rule = [] {
        auto key   = dsl::pnode<grammar::key>;
        auto value = dsl::pnode<grammar::integer>(dsl::p<integer>);
        return key + value;
    }();

    static constexpr auto value = lexy::forward<int>;
};
} // namespace tree_grammar

int main()
{
    auto input = lexy_ext::compiler_explorer_input();

    // Parse the string into a tree.
    lexy::parse_tree_for<lexy::buffer<lexy::utf8_encoding>> tree;
    if (!lexy::parse_as_tree<grammar::key_value_pair>(tree, input, lexy_ext::report_error))
        return 1;

    // Parse the tree to extract the value (we ignore error reporting here since it's a bug for the
    // parse tree grammar to fail).
    auto result
        = lexy::parse<tree_grammar::key_value_pair>(lexy::parse_tree_input(tree), lexy::noop);
    if (!result)
        return 2;

    std::printf("Value: %d\n", result.value());
}

Rule DSL lexy::dsl::tnode Experimental

lexy/dsl/parse_tree_node.hpp
namespace lexy
{
    struct expected_token_end {};
}

namespace lexy::dsl
{
    class tnode-dsl // models token-rule
    {
    public:
        constexpr branch-rule operator()(rule auto lexeme_rule) const;
    };

    template <auto TokenKind>
    constexpr auto tnode = tnode-dsl{};
}

tnode is a token rule and DSL to match a token node in a lexy::parse_tree_input Experimental .

If used in the form tnode<TokenKind>, it is a token rule that matches a token node with the given kind. If used in the form tnode<TokenKind>(lexeme_rule), it is a branch rule that also matches the lexeme.

Token rule lexy::dsl::tnode

lexy/dsl/parse_tree_node.hpp
template <auto TokenKind>
constexpr auto tnode = tnode-dsl{};
Matching

If the current parse tree node in the input is a token node with the specified TokenKind, consumes it. Otherwise, fails.

Errors

lexy::expected_char_class  with the name of the token kind, at the starting reader position.

Parse tree

A single token node that contains the node of the input parse tree with the same token kind.

Branch rule lexy::dsl::tnode(lexeme_rule)

lexy/dsl/parse_tree_node.hpp
constexpr branch-rule operator()(rule auto lexeme_rule) const;
Parsing

Parses the corresponding lexy::dsl::tnode token rule, then lexeme_rule on the lexeme of that token node.

Branch parsing

Tries to parse the corresponding lexy::dsl::tnode token rule and backtracks if that backtracks. Then parses lexeme_rule on the lexeme of that token node.

Errors
  • lexy::expected_char_class  with the name of the token kind, at the starting reader position during non-branch parsing when the node did not match. The rule then fails.

  • All errors raised when parsing lexeme_rule on the lexeme. The rule then recovers by doing nothing, as the lexeme of the node is not part of the input anyway.

  • lexy::expected_token_end if lexeme_rule did not consume the entire lexeme of the node. The rule then recovers by doing nothing.

Note
lexeme_rule matches characters, not other nodes.

Rule DSL lexy::dsl::pnode Experimental

lexy/dsl/parse_tree_node.hpp
namespace lexy
{
    struct expected_production_end {};
}

namespace lexy::dsl
{
    class pnode-dsl // models token-rule
    {
    public:
        constexpr branch-rule operator()(rule auto child_rule) const;
    };

    template <production Production>
    constexpr auto pnode = pnode-dsl{};
}

pnode is a token rule and DSL to match a production node in a lexy::parse_tree_input Experimental .

If used in the form pnode<Production>, it is a token rule that matches a Production node. If used in the form pnode<Production>(child_rule), it is a branch rule that also matches the children of the node.

Token rule lexy::dsl::pnode

lexy/dsl/parse_tree_node.hpp
template <typename Production>
constexpr auto pnode = pnode-dsl{};
Matching

If the current parse tree node in the input is a production node for Production, consumes it. Otherwise, fails.

Errors

lexy::expected_char_class  with the name of the production, at the starting reader position.

Branch rule lexy::dsl::pnode(child_rule)

lexy/dsl/parse_tree_node.hpp
constexpr branch-rule operator()(rule auto child_rule) const;
Parsing

Parses the corresponding lexy::dsl::pnode token rule, then child_rule on the children of that production node.

Branch parsing

Tries to parse the corresponding lexy::dsl::pnode token rule and backtracks if that backtracks. Then parses child_rule on the children of that production node.

Errors
  • lexy::expected_char_class  with the name of the production, at the starting reader position during non-branch parsing when the node did not match. The rule then fails.

  • All errors raised when parsing child_rule on the children. The rule then recovers by doing nothing, as the children of the node are not part of the input anyway.

  • lexy::expected_production_end if child_rule did not consume all children of the node. The rule then recovers by doing nothing.

Note
child_rule is executed on another lexy::parse_tree_input with the matched node as root.

See also