* Make the grammar less ambiguous by changing the syntax of the lexer's
forward declartion from `Foo` to `Foo <- null`
* This in turn allows the sharing of the `decl` grammar rule in the
grammar, simplifying the grammar and allowing the production of better
error messages.
* The lexer_decl rule is simplified (lexer_family_decl occured twice)
* GrammarNull is allowed to not have a type suffix
Introduce a new node (`BlockExprClause`) so that:
1. The `;` token belongs to list items in block expressions rather than
being a separator for that list.
2. The inner expression in block exprs belongs to that list, so that
there is no `;` token parser that follows the parser for that list.
The conjunction of both points allows us to introduce `skip`/`dont_skip`
parser for error recovery in the parsing of block expressions. The extra
sources that are accepted by the new parser are rejected by the Lkt
frontend.
Note that, due to a Langkit parser bug (likely
eng/libadalang/langkit#652), sometimes there is no parsing error even
though the parse tree contains an error node. This should be addressed
later.
The first iteration was just a relatively basic copy&paste from the LKQL
grammar, that carries a lot of cruft and legacy at this stage. Following
the comments on the initial review for the merge request, it was decided
to take the opportunity to clean the grammar.
* Rename "BasePattern" into "Pattern"
* Remove every pattern abstract intermediate class (ValuePattern and
NodePattern). The categorizations they introduce is not very useful,
and they introduce a lot of complexity.
* Rename pattern details
* Remove mentions of "node" patterns, since we want to make the notion
of matching on a given type more general than just for node types.
* Rename ExtendedNodePattern -> ExtendedPattern, since we might want to
generalize the notion, and NodeKindPattern was renamed into
TypePattern already.
* Rewrite most of the docstrings
* Rename Splat -> Ellipsis
* Unify the naming of sub pattern fields (call them all
`sub_pattern`/`sub_patterns`.
`a?.as[T]` would be equivalent to `a.as[T]`, and `a?.as[T].foo` would be
equivalent to `a.as[T]?.foo`, so allowing `a?.as[T]` is not particularly
useful, and is even confusing when combined with the `a.as![T]` form
(semantic of `!` opposed to the one of `?`). Fix the parser to still
correctly analyze this form, but disallow it during the lowering.
Modify the Lkt KeepExpr node and related parser to correctly parse
`a?.keep[T]` and adapt lowering logic to implement the null-conditional
behavior correctly.
Keep track of whether some expression has null-conditional behavior with
`f_null_cond` fields (to note whether `?` is present) rather than
alternative subclasses (`DotExpr`/`NullCondDotExpr`,
`SubscriptExpr`/`NullCondSubscriptExpr`).