Skip to content

Spec EBNF and Lark grammar have nominal rule-name drift (assert_stmt/assert_expr, module_call/qualified_call) #683

@aallan

Description

@aallan

Finding

Rule names in spec/10-grammar.md EBNF blocks and vera/grammar.lark have nominal drift. Live state at HEAD 08c1197:

  • Spec EBNF rules: 82
  • Lark rules: 65
  • Common: 59

The bulk of "spec-only" rules are expression-precedence ladders (add_expr, cmp_expr, or_expr, unary_expr, primary_expr, etc.) that Lark inlines via alternation. Those are a deliberate notational choice each tool optimises for; they should be documented in the spec as "represented inline in Lark" but not renamed.

The genuine drift is a small subset of names:

Spec-only Lark equivalent Note
assert_stmt assert_expr assert/assume return values; the implementation chose _expr. Spec should follow.
assume_stmt assume_expr Same.
module_call (no rule) Same construct as qualified_call; spec uses both names.
qualified_call (no rule) Same.
(no rule) effect_set, pure_effect, with_clause Lark sub-rules with no spec counterpart. Either inline in spec or add to spec EBNF.
program start Lark requires start; spec name is conventional. Document as known allowlist exception.

Suggested fix

A one-pass reconciliation:

  1. Decide on _expr vs _stmt for assert/assume and update the spec to match the implementation (the grammar uses _expr, and they return values, so this is the right call)
  2. Rename qualified_callmodule_call throughout the Lark grammar (DESIGN.md text uses "module-qualified", so module_call is the more natural name)
  3. Either inline the Lark-only sub-rules (effect_set, pure_effect, with_clause) into their parents or add them as sub-rules in the spec EBNF
  4. Add scripts/check_grammar_alignment.py that re-extracts the rule sets from both files and asserts they agree modulo a documented allowlist (currently {program ↔ start} and the inline-expression-precedence convention)

Scope decision

This issue is scoped to the nominal renames + check script. The expression-precedence "drift" (add_expr / cmp_expr / etc. existing in spec but not Lark) is a deliberate notational choice and out of scope — Lark uses operator-precedence inlining; spec uses precedence ladders. Both notations are correct; reconciling them would be a notational ideology change, not a hygiene fix.

Acceptance criteria

  1. python scripts/check_grammar_alignment.py returns zero with no allowlist exceptions other than program ↔ start and the documented expression-precedence convention
  2. Script runs as a pre-commit hook and in CI
  3. Spec and Lark agree on assert/assume naming (use _expr)
  4. Spec and Lark agree on module-qualified-call naming (use module_call)
  5. Lark-only sub-rules (effect_set, pure_effect, with_clause) either appear in the spec or are inlined in Lark

Estimated effort

Half a day for the renames + check script.

Origin

Surfaced by a strategic compiler review on 2026-05-18 (v0.0.155). Marked P2 (hygiene). Counts independently verified before filing: 82 spec rules / 65 Lark rules with 59 in common; the headline numerical gap is dominated by the precedence-ladder notational difference rather than genuine drift.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions