Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
8938cdd
first steps to allow scripts in jml
mattulbrich Sep 8, 2025
9d4e01b
first working example of a proof script in Java code (albeit with Jav…
mattulbrich Sep 8, 2025
b4e9cb1
added missing files for script aware macros
mattulbrich Jan 30, 2023
62319c7
more infrastructure for proof scripts
mattulbrich Sep 8, 2025
5f0e7d2
more infrastructure for proof scripts
mattulbrich Feb 4, 2023
8caad23
more infrastructure for proof scripts
mattulbrich Sep 8, 2025
f2a3716
adapting to new Script AST nodes
mattulbrich Sep 8, 2025
fd6ae2d
renaming AssertCommand to FailUnlessCommand
mattulbrich Sep 8, 2025
4eebfa9
correcting the grammar for nested \by clauses
mattulbrich Sep 8, 2025
a8cd36e
improving the value injector
mattulbrich Sep 10, 2025
27f86c3
renaming a deprecated command "assert" --> "assertOpenGoals"
mattulbrich Sep 10, 2025
e6649ef
spotless
mattulbrich Sep 12, 2025
414607a
working version of scripts
mattulbrich Sep 24, 2025
a2f5f2d
Position info for scripts with url=null, run scripted goals before ot…
mattulbrich Sep 24, 2025
3762ca2
Use AutoPilotPrepareProofMacro instead of FinishSymbolicExecutionMacr…
mattulbrich Sep 24, 2025
7eaed81
working on improved script commands
mattulbrich Sep 24, 2025
3acf95f
advancing the immutable list interface
mattulbrich May 26, 2023
291d00a
reorganisation of proof script commands
mattulbrich Sep 24, 2025
ccf4441
advancing for scripts from JML
mattulbrich May 26, 2023
c941c61
slight adaptation of the macro used for scripting
mattulbrich May 26, 2023
235bb0c
more script commands
mattulbrich Jun 2, 2023
fd92326
improving/correcting script commands
mattulbrich Jun 5, 2023
6fde8b1
settings for the auto command
mattulbrich Jun 8, 2023
4abbb65
propagating strategy settings to the strategy to be used
mattulbrich Jun 9, 2023
f75a812
proof scripts: adding a CHEAT command
mattulbrich Jun 15, 2023
f72da9a
updating a few of the script commands
mattulbrich Jun 17, 2023
078115e
introducing the script-aware prep macro
mattulbrich Jun 19, 2023
8e57525
issue dialog: skip spaces for squiggly lines
mattulbrich Jun 19, 2023
26e9e4c
value injector: towards reporting unknown arguments
mattulbrich Jun 19, 2023
874948d
improved script error reporting
mattulbrich Jun 19, 2023
40af0b6
documentation for script commands
mattulbrich Jun 23, 2023
8c751cf
better error messaging in ScriptLineParser
mattulbrich Jun 30, 2023
60f646c
implement a recall mechanism
mattulbrich Jun 30, 2023
ea660cc
allow let commands without "@"
mattulbrich Jul 7, 2023
a678f9f
a formula parameter for the expand command
mattulbrich Jul 22, 2023
00f91ae
spotlessing
mattulbrich Sep 27, 2025
6fe9a38
towards 'obtain' in JML scripts
mattulbrich Oct 1, 2025
7179e81
update ProofScriptEngine's workflow
mattulbrich Oct 1, 2025
fb770b9
consolidating, introducing test cases for jml scripts
mattulbrich Oct 1, 2025
5dcb779
first working obtain scripts
mattulbrich Oct 1, 2025
6ca05d6
pimping the document generation for proof script commands
mattulbrich Oct 2, 2025
d666b66
lots of script documentation
mattulbrich Oct 2, 2025
d5ef8d9
fixing a bug regarding proof script application
mattulbrich Oct 3, 2025
59ab830
repairing some weird self variable treatment in SpecStatement
mattulbrich Oct 3, 2025
1cd5434
introducing "auto add_*" to scripts.
mattulbrich Jul 19, 2024
16215c8
smaller fixes in proof script treatment
mattulbrich Oct 3, 2025
2dfda8a
The Boyer-Moore example now runs on scripts
mattulbrich Oct 3, 2025
4cdfdd9
improved document generation
mattulbrich Oct 3, 2025
f052e35
more proof script power, update inlining.
mattulbrich Oct 3, 2025
3655415
making sure that cuts work with boolean terms instead of formulas.
mattulbrich Oct 4, 2025
c947f7b
better symbex-only machine
mattulbrich Oct 5, 2025
265319c
Allowing "auto only: ..."
mattulbrich Oct 5, 2025
e72aaa6
quicksort example with JML scripts (partially)
mattulbrich Oct 5, 2025
cb5dcea
enabling the quicksort example with JML proof scripts!
mattulbrich Oct 5, 2025
331e0e6
limiting the symbex only macro a bit
mattulbrich Oct 6, 2025
8e5e576
introducing hole placeholders for terms and for formulas
mattulbrich Jul 18, 2024
ed0c89c
introducing witness command
mattulbrich Aug 11, 2024
f1e5e3e
adapting the cherry-picked commits
mattulbrich Oct 6, 2025
88ea9a2
allowing switching off rules in auto
mattulbrich Oct 6, 2025
393fe12
a more robust term-with-holes implementation
mattulbrich Oct 9, 2025
4066f7c
improved treatment of terms with holes
mattulbrich Oct 10, 2025
a46208f
introduce match identifiers with leading '?'
mattulbrich Oct 10, 2025
3f30627
introducing sort::FOCUS for usage in scripts
mattulbrich Jul 18, 2024
607f47c
introducing sort::ELLIP for ellipsis search patterns
mattulbrich Jul 18, 2024
f5c1d23
improving sophisticated term matching
mattulbrich Oct 10, 2025
ad9fe1a
accomodating "focus inside find"
mattulbrich Oct 10, 2025
39ab2d2
add "assumes" parameter to rule command
mattulbrich Jul 19, 2024
f2a76d7
bugfixing matching with program variables
mattulbrich Oct 10, 2025
d7d8268
updating the focus rule
mattulbrich Oct 10, 2025
e1eb8c1
allow terms with holes in expand command
WolframPfeifer Aug 13, 2024
25b1ca5
added convenience macro to close all NPE and Out-of-bounds branches
WolframPfeifer Aug 28, 2024
1115331
bug fixes in script engine
mattulbrich Oct 11, 2025
af4df50
repairing JML script tests
mattulbrich Oct 11, 2025
adb3c31
fixing a NPE bug in JavaProfile
mattulbrich Oct 15, 2025
cc29e81
improving symbex only macro
mattulbrich Oct 24, 2025
3332915
adding an infinity catch on "throw null" in symb ex.
mattulbrich Oct 24, 2025
a7cc2ff
making the assume command use a local taclet.
mattulbrich Feb 17, 2026
5189bd1
correcting conversion in JML scripts
mattulbrich Feb 17, 2026
3de59bb
adapting taclets.old.txt to changed throws treatment
mattulbrich Feb 17, 2026
43f04ab
Repaired a merge test case
mattulbrich Feb 17, 2026
aebcce2
missing sameUpdateLevel for tryCatchThrow
mattulbrich Feb 17, 2026
f8f38d0
spotless
wadoon Feb 23, 2026
0d62fa7
fix regression fixtures taclets.old.txt
wadoon Feb 23, 2026
95db885
fix rebasing
wadoon Apr 9, 2026
2fa2276
fix tests
wadoon Apr 9, 2026
678b53e
fixes
wadoon Apr 9, 2026
ce4ba72
remove codecov
wadoon Apr 9, 2026
5b8d065
spotless
wadoon Apr 12, 2026
331b533
add converter
wadoon Apr 17, 2026
0e8c008
make userData type safe
wadoon Apr 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@ jobs:
**/build/reports/
!**/jacocoTestReport.xml

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v6

integration-tests:
env:
GH_TOKEN: ${{ github.token }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public Strategy<Goal> create(Proof proof, StrategyProperties sp) {
*/
@Override
public StrategySettingsDefinition getSettingsDefinition() {
return JavaProfile.DEFAULT.getSettingsDefinition();
return JavaProfile.getDefault().getSettingsDefinition();
}
}
}
9 changes: 9 additions & 0 deletions key.core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ dependencies {

api project(':key.util')

// Make Javadoc accessible at runtime
annotationProcessor 'com.github.therapi:therapi-runtime-javadoc-scribe:0.13.0'
implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0'

def JP_VERSION = "3.28.0-K13.5"
api "org.key-project.proofjava:javaparser-core:$JP_VERSION"
api "org.key-project.proofjava:javaparser-core-serialization:$JP_VERSION"
Expand All @@ -31,6 +35,10 @@ dependencies {
testFixturesApi(testFixtures(project(":key.util")))
}

tasks.withType(JavaCompile) {
options.compilerArgs << "-Ajavadoc.packages=de.uka.ilkd.key.scripts"
}

// The target directory for JavaCC (parser generation)
//def javaCCOutputDir = layout.buildDirectory.dir("generated-src/javacc").getOrNull()
//def javaCCOutputDirMain = file("$javaCCOutputDir/main")
Expand Down Expand Up @@ -97,6 +105,7 @@ classes.dependsOn << generateSolverPropsList

tasks.withType(Test) {
enableAssertions = true
systemProperties(System.properties.findAll { key, value -> key.startsWith("key.") })
}


Expand Down
3 changes: 3 additions & 0 deletions key.core/src/main/antlr4/JmlLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ mode expr;
/* Java keywords */
BOOLEAN: 'boolean';
BYTE: 'byte';
CASE: 'case';
DEFAULT: 'default';
FALSE: 'false';
INSTANCEOF: 'instanceof';
INT: 'int';
Expand Down Expand Up @@ -244,6 +246,7 @@ FP_SUBNORMAL: '\\fp_subnormal'; //KeY extension, not official JML
FP_ZERO: '\\fp_zero'; //KeY extension, not official JML
FREE: '\\free'; //KeY extension, not official JML
FRESH: '\\fresh';
FROM_GOAL: '\\from_goal'; //KeY extension, not official JML
INDEX: '\\index';
INDEXOF: '\\seq_indexOf'; //KeY extension, not official JML
INTERSECT: '\\intersect'; //KeY extension, not official JML
Expand Down
28 changes: 27 additions & 1 deletion key.core/src/main/antlr4/JmlParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ options { tokenVocab=JmlLexer; }
@members {
private SyntaxErrorReporter errorReporter = new SyntaxErrorReporter(getClass());
public SyntaxErrorReporter getErrorReporter() { return errorReporter;}
private boolean isNextToken(String tokenText) {
return _input.LA(1) != Token.EOF && tokenText.equals(_input.LT(1).getText());
}
}

modifiersEOF: modifiers EOF;
Expand Down Expand Up @@ -203,12 +206,35 @@ block_specification: method_specification;
block_loop_specification:
loop_contract_keyword spec_case ((also_keyword)+ loop_contract_keyword spec_case)*;
loop_contract_keyword: LOOP_CONTRACT;
assert_statement: (ASSERT expression | UNREACHABLE) SEMI_TOPLEVEL;
assert_statement: (ASSERT (label=IDENT COLON)? expression | UNREACHABLE) (assertionProof SEMI_TOPLEVEL? | SEMI_TOPLEVEL);
//breaks_clause: BREAKS expression;
//continues_clause: CONTINUES expression;
//returns_clause: RETURNS expression;


// --- proof scripts in JML
assertionProof: BY (proofCmd | LBRACE ( proofCmd )+ RBRACE) ;
proofCmd:
// TODO allow more than one var in obtain
{ isNextToken("obtain") }? obtain=IDENT typespec var=IDENT
( obtKind=EQUAL_SINGLE expression SEMI
| obtKind=SUCH_THAT expression proofCmdSuffix
| obtKind=FROM_GOAL SEMI
)
| cmd=IDENT ( proofArg )* proofCmdSuffix
;

proofCmdSuffix:
SEMI | BY ( proofCmd | LBRACE (proofCmd+ | proofCmdCase+) RBRACE )
;

proofCmdCase:
CASE ( label=STRING_LITERAL )? COLON ( proofCmd )*
| DEFAULT COLON ( proofCmd )*
;
proofArg: (argLabel=IDENT COLON)? expression;
Comment thread
wadoon marked this conversation as resolved.
// ---

mergeparamsspec:
MERGE_PARAMS
LBRACE
Expand Down
3 changes: 3 additions & 0 deletions key.core/src/main/antlr4/KeYLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ lexer grammar KeYLexer;
}

private Token tokenBackStorage = null;
// see: https://keyproject.github.io/key-docs/devel/NewKeyParser/#why-does-the-lexer-required-some-pieces-of-java-code
@Override
public void emit(Token token) {
int MAX_K = 10;
Expand Down Expand Up @@ -220,6 +221,7 @@ AXIOMS : '\\axioms';
PROBLEM : '\\problem';
CHOOSECONTRACT : '\\chooseContract';
PROOFOBLIGATION : '\\proofObligation';
// for PROOF see: https://keyproject.github.io/key-docs/devel/NewKeyParser/#why-does-the-lexer-required-some-pieces-of-java-code
PROOF : '\\proof';
PROOFSCRIPT : '\\proofScript';
CONTRACTS : '\\contracts';
Expand Down Expand Up @@ -392,6 +394,7 @@ LESSEQUAL: '<' '=' | '\u2264';
LGUILLEMETS: '<' '<' | '«' | '‹';
RGUILLEMETS: '>''>' | '»' | '›';
IMPLICIT_IDENT: '<' '$'? (LETTER)+ '>' ('$lmtd')? -> type(IDENT);
MATCH_IDENT: '?' IDENT?;

EQV: '<->' | '\u2194';
CHAR_LITERAL
Expand Down
4 changes: 3 additions & 1 deletion key.core/src/main/antlr4/KeYParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ parser grammar KeYParser;
@members {
private SyntaxErrorReporter errorReporter = new SyntaxErrorReporter(getClass());
public SyntaxErrorReporter getErrorReporter() { return errorReporter;}
public boolean allowMatchId = false; // used in proof script parsing
}

options { tokenVocab=KeYLexer; } // use tokens from STLexer.g4
Expand Down Expand Up @@ -154,6 +155,7 @@ string_value: STRING_LITERAL;
simple_ident
:
id=IDENT
| {allowMatchId}? id=MATCH_IDENT
;

simple_ident_comma_list
Expand Down Expand Up @@ -901,7 +903,7 @@ proofScriptExpression:
| integer
| floatnum
| string_literal
| LPAREN (term | seq) RPAREN
| LPAREN {allowMatchId=true;} (term | seq) {allowMatchId=false;} RPAREN
| simple_ident
| abbreviation
| literals
Expand Down
2 changes: 1 addition & 1 deletion key.core/src/main/java/de/uka/ilkd/key/java/JavaInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ public static boolean isVisibleTo(SpecificationElement ax, KeYJavaType visibleTo
/**
* returns a KeYJavaType having the given sort
*/
public KeYJavaType getKeYJavaType(Sort sort) {
public @Nullable KeYJavaType getKeYJavaType(Sort sort) {
List<KeYJavaType> l = lookupSort2KJTCache(sort);
if (l != null && l.size() > 0) {
// Return first KeYJavaType found for sort.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@
import de.uka.ilkd.key.java.ast.PositionInfo;
import de.uka.ilkd.key.java.ast.ProgramElement;
import de.uka.ilkd.key.java.visitor.Visitor;
import de.uka.ilkd.key.logic.op.LocationVariable;
import de.uka.ilkd.key.nparser.KeyAst;
import de.uka.ilkd.key.speclang.jml.pretranslation.TextualJMLAssertStatement;
import de.uka.ilkd.key.speclang.njml.JmlIO;
import de.uka.ilkd.key.speclang.njml.JmlParser;

import org.key_project.util.ExtList;
import org.key_project.util.collection.ImmutableList;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

/**
* A JML assert statement.
Expand All @@ -29,24 +36,36 @@ public class JmlAssert extends JavaStatement {
*/
private final TextualJMLAssertStatement.Kind kind;

/*
* Temporary solution until full jml labels are there ...
* (To be clarified if compatible still)
*/
private final String optLabel;

/**
* the condition in parse tree form
*/
private KeyAst.Expression condition;
private final KeyAst.Expression condition;

/**
* the assertion proof in parse tree form
*/
private final KeyAst.@Nullable JMLProofScript assertionProof;

/**
* @param kind
* assert or assume
* @param condition
* the condition of this statement
* @param positionInfo
* the position information for this statement
* @param kind assert or assume
* @param condition the condition of this statement
* @param assertionProof the optional proof for an assert statement (not for assume)
* @param positionInfo the position information for this statement
*/
public JmlAssert(TextualJMLAssertStatement.Kind kind, KeyAst.Expression condition,
public JmlAssert(TextualJMLAssertStatement.Kind kind, String label, KeyAst.Expression condition,
KeyAst.@Nullable JMLProofScript assertionProof,
PositionInfo positionInfo) {
super(positionInfo);
this.kind = kind;
this.optLabel = label;
this.condition = condition;
this.assertionProof = assertionProof;
}

/**
Expand All @@ -56,11 +75,25 @@ public JmlAssert(TextualJMLAssertStatement.Kind kind, KeyAst.Expression conditio
public JmlAssert(ExtList children) {
super(children);
this.kind = Objects.requireNonNull(children.get(TextualJMLAssertStatement.Kind.class));
this.optLabel = children.get(String.class);
this.condition = Objects.requireNonNull(children.get(KeyAst.Expression.class));
// script may be null
this.assertionProof = children.get(KeyAst.JMLProofScript.class);
}

public JmlAssert(JmlAssert other) {
this(other.kind, other.condition, other.getPositionInfo());
this(other.kind, other.optLabel, other.condition, other.assertionProof,
other.getPositionInfo());
}

public JmlAssert(TextualJMLAssertStatement.Kind kind, TextualJMLAssertStatement construct,
PositionInfo pi) {
super(pi);
this.kind = kind;
this.optLabel = construct.getOptLabel();
this.condition = construct.getContext();
// script may be null
this.assertionProof = construct.getAssertionProof();
}

public TextualJMLAssertStatement.Kind getKind() {
Expand Down Expand Up @@ -152,6 +185,10 @@ protected int computeHashCode() {
return System.identityHashCode(this);
}

public KeyAst.@Nullable JMLProofScript getAssertionProof() {
return assertionProof;
}

@Override
public int getChildCount() {
return 0;
Expand All @@ -166,4 +203,30 @@ public ProgramElement getChildAt(int index) {
public void visit(Visitor v) {
v.performActionOnJmlAssert(this);
}

/**
* This method collects all terms contained in this assertion. This is at least the condition.
* If there is a proof script, all terms in the proof script are collected as well.
*
* @return a freshly created list of at least one term
*/
public @NonNull ImmutableList<JmlParser.ExpressionContext> collectTerms() {
ImmutableList<JmlParser.ExpressionContext> result = ImmutableList.of();
if (assertionProof != null) {
result = result.prepend(assertionProof.collectTerms());
}
result = result.prepend(condition.ctx);
return result;
}

public ImmutableList<LocationVariable> collectVariablesInProof(JmlIO io) {
if (assertionProof != null) {
return assertionProof.getObtainedProgramVars(io);
}
return ImmutableList.of();
}

public String getOptLabel() {
return optLabel;
}
}
Loading