Skip to content

JML class-body predicate declarations (//@ instance predicate Pred(int i) = i > 0;) - #85

Open
wadoon wants to merge 10 commits into
mainfrom
weigl/predicate
Open

wadoon wants to merge 10 commits into
mainfrom
weigl/predicate

Conversation

@wadoon

@wadoon wadoon commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds JML class-body predicate declarations to the parser: //@ instance predicate Pred(int i) = i > 0;.

A predicate declares a named assertion formula over formal parameters that can be referenced from JML annotations. This PR implements the declaration itself (AST, grammar, printing, validation, resolution, tool backends). Proof scripts (use_lemma), script bodies and body type-checking are explicitly out of scope.

Implementation phases

Phase 0 — design (2669b52ca)

  • doc/design/predicate.md (design + language surface) and doc/design/predicate-impl.md (executable checklist, completed).

Phases 1–4 — core (3fdd6dbae)

  • New AST node JmlPredicateDeclaration in ast/jml/body/ extending JmlClassLevelDeclaration, implementing NodeWithSimpleName, NodeWithModifiers, NodeWithAccessModifiers; fields/ctor order (jmlTags, modifiers, name, parameters, body).
  • Grammar: <PREDICATE: "predicate"> lexer token (JML states only), JmlClassPredicate production (<PREDICATE> SimpleName() Parameters() "=" Expression() ";") dispatched via LOOKAHEAD(1) from JmlClassLevelInner; case PREDICATE: added to TokenTypes#getCategory.
  • JavaToken kinds + metamodel + all generated visitors regenerated.
  • Concrete syntax model entry (using the modifiers() list helper) and DefaultPrettyPrinterVisitor visit so toString() round-trips //@ instance predicate Pred(int i) = i > 0;.
  • ModifierValidator: allowed modifier set (access, static, final, model, instance, pure, math modes), parameter modifiers, duplicate parameter-name detection.
  • DefaultVisitorAdapter throwing stub so the whole project compiles.

Phase 5 — M1 tests (916272a56)

  • PredicateDeclarationTest (7 tests): parse + member assertions, toString() round-trip, lexical-preserving round-trip, CSM round-trip (modifier-less form), body/parameter AST, validator failures.
  • Fragment corpus decl_jml_predicate_pred.txt + full example fullexamples/tested/Predicates.java (both green in FragmentTest 1335 cases / FullExamplesTest).

Phase 6 — symbol resolution (4decfae3b)

  • JmlPredicateDeclarationContext resolves names in the predicate body against the formal parameters (JavaParserSymbolDeclaration.parameter), falling back to the enclosing class scope; registered in JavaParserFactory.
  • NameResolutionTest.jmlPredicate against JmlPredicateResolutionTest.java (//? markers) verifies parameter + field resolution and types.

Phase 7 — M3 tool backends (830a5fb3d)

  • stat: totalPredicates statistic + <predicate name="…"> XML element (modifier attrs + body expression stats).
  • wd: well-definedness of a predicate = wd(body).
  • lsp: DocumentSymbol (kind Method) per predicate; CodeActionCollector offers the well-definedness check on the predicate body.
  • Tests for all three tools.

Phase 8 — release (a6cd3a564)

  • gradle.properties → 1.2.0-SNAPSHOT (feature ⇒ minor bump; fork-local SemVer per AGENTS.md); jmltk-changelog.md documents the fork-local 1.x scheme mapping and an unreleased 1.2.0 section.

Phase 9 — QA (c7a192b3e)

  • Full corpus (:jmlparser-core:test :jmlparser-jml-tests:test :jmlparser-symbol-solver-testing:test :jmlparser-core-testing:test :jmlparser-core-serialization:test :tools:wd:test :tools:stat:test :tools:lsp:test) green; spotlessCheck + checkstyleMain green (pre-existing warnings only); generator drift check: regenerate (compileJavacc → metamodel generator → core generators) + spotlessApply → git diff --exit-code clean.
  • Implementation checklist ticked with deviations recorded.

Phase 10 — rename lemma → predicate (95581998c)

  • Renamed the construct throughout: keyword lemma → predicate, JmlLemmaDeclaration → JmlPredicateDeclaration, token LEMMA → PREDICATE, grammar production JmlClassLemma → JmlClassPredicate, stat totalLemmas → totalPredicates + <predicate> XML, and all tests/resources/doc prose.
  • ConcreteSyntaxModel set-comprehension entry qualified as ObservableProperty.PREDICATE to disambiguate the new token constant.
  • Resolution //? column markers updated (keyword grew 5 → 9 chars).
  • Full suite + spotlessCheck + checkstyleMain green; drift check clean after regeneration.
  • KeY ANTLR lexer (KeyDocumentHighlighter) and openjml/key corpus lemma uses are out of scope and untouched.

Notes

  • JML modifiers print as jml_instance via CSM (pre-existing PrintingHelper enum quirk, same as the reference branch); exact CSM round-trip uses the modifier-less form, toString() covers modifiers.
  • Generator gotcha recorded in the plan: run generators and spotlessApply as separate gradle invocations (single invocation can race and produce false-positive drift).

Design (predicate.md) and executable checklist (predicate-impl.md) for the
class-body `lemma` declaration (//@ instance lemma Pred(int i) = i > 0;):
AST node, grammar, concrete syntax, validation, symbol resolution, tool
backends and release steps.
…validation

- New node JmlLemmaDeclaration in ast/jml/body (modifiers, name, parameters,
  body, jmlTags) extending JmlClassLevelDeclaration, registered in the
  metamodel generator; all generated visitors, metamodel and JavaToken kinds
  regenerated (LEMMA token added).
- Grammar: <LEMMA: "lemma"> lexer token (JML states only), JmlClassLemma
  production and LOOKAHEAD(1) dispatch in JmlClassLevelInner; TokenTypes
  classification added.
- Concrete syntax model entry and DefaultPrettyPrinterVisitor visit so
  genericPrettyPrint and toString round-trip the declaration.
- ModifierValidator: allowed modifier set for lemmas (access, static, final,
  model, instance, pure, math modes), parameter modifiers and duplicate
  parameter-name detection.
- Symbol-solver DefaultVisitorAdapter gains the throwing visit stub so the
  whole project still compiles.
- LemmaDeclarationTest: parse the motivating example (//@ instance lemma
  Pred(int i) = i > 0;), assert members/modifiers/params/body, toString and
  lexical-preserving round-trips, CSM round-trip without modifiers, and
  validator failures (duplicate parameters, disallowed modifier).
- Fragment corpus: decl_jml_lemma_pred.txt (raw class-level JML).
- Full example: fullexamples/tested/Predicates.java (processJml=true).
- JmlLemmaDeclarationContext resolves names in the lemma body against the
  formal parameters (JavaParserSymbolDeclaration.parameter), falling back to
  the surrounding class scope; registered in JavaParserFactory.
- NameResolutionTest gains jmlLemma() against JmlLemmaResolutionTest.java,
  asserting body references (parameters lo/hi/i and a field) resolve with
  correct types.
- wd: WDVisitorExpr.visit(JmlLemmaDeclaration) delegates well-definedness to
  the lemma body expression.
- stat: totalLemmas statistic key, reporter increment, and a <lemma> XML
  element with name/modifiers/body expression in the statistics visitor.
- lsp: JmlCatchSymbols emits a Method DocumentSymbol for each lemma;
  CodeActionCollector offers the "Well-definedness Check" code action on the
  lemma body.
- Tests: statistics counting, wd delegation (SExpr compared via toString),
  LSP document-symbol hierarchy and code-action presence.
- gradle.properties: 1.1.0-SNAPSHOT → 1.2.0-SNAPSHOT (feature ⇒ minor bump,
  fork-local SemVer per AGENTS.md).
- jmltk-changelog.md: document the fork-local 1.x scheme with its mapping to
  the composite <JavaParser>-J<K>-K<KeY> releases, and add an unreleased
  1.2.0-SNAPSHOT section listing the lemma-declaration feature.
Mark all completed phase checkboxes, keep push/PR open. Document deviations
from the draft (NodeWithSimpleName, CSM modifiers() helper + no-modifier
round-trip, validation tests in Phase 5, LEMMA token placement, generator
ordering incl. the spotlessApply race, resolution context behavior, and the
out-of-scope items).
@github-code-quality

github-code-quality Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: Java

Java / code-coverage/jacoco-ubuntu-latest-21

main 5056020 weigl/predicate f225fe7 +/-
58% 58% 0%
View coverage of the 10 most impacted files.
File main 5056020 weigl/predicate f225fe7 +/-
com/github/java...ierVisitor.java 54% 53% -1%
com/github/java...odeVisitor.java 59% 58% -1%
com/github/java...JavaParser.java 76% 76% 0%
com/github/java...torAdapter.java 59% 59% 0%
com/github/java...kenManager.java 29% 29% 0%
com/github/java...odeVisitor.java 59% 59% 0%
io/github/jmlto...wd/WDVisitor.kt 0% 16% +16%
io/github/jmlto...ionCollector.kt 0% 38% +38%
com/github/java...eclaration.java 0% 49% +49%
com/github/java...ionContext.java 0% 100% +100%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated October 29, 2026 23:42 UTC

@wadoon wadoon self-assigned this Oct 28, 2026
Rename the JML class-body lemma declaration feature to 'predicate':
keyword 'lemma' -> 'predicate', JmlLemmaDeclaration ->
JmlPredicateDeclaration, token LEMMA -> PREDICATE, grammar
production JmlClassLemma -> JmlClassPredicate, stat totalLemmas ->
totalPredicates with <predicate> XML, and all tests/resources/doc
prose renamed accordingly.

- Regenerate grammar (compileJavacc), metamodel, visitors and
  concrete syntax (metamodel + core generators), spotless
- Qualify ObservableProperty.PREDICATE in ConcreteSyntaxModel to
  disambiguate the new token constant
- Update resolution test column markers (keyword grew 5 -> 9 chars)
- KeY lexer (KeyDocumentHighlighter) and openjml/key corpus lemma
  uses are out of scope and untouched
@wadoon wadoon changed the title JML class-body lemma declarations (//@ instance lemma Pred(int i) = i > 0;) JML class-body predicate declarations (//@ instance predicate Pred(int i) = i > 0;) Oct 29, 2026
The predicate child node carries no stored line-ending style, so the
default printer uses System.lineSeparator() (CRLF on Windows). Assert
against System.lineSeparator() instead of a hardcoded '\n'. Pre-existing
failure also present on the lemma version of the test.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant