Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
d102fbe
first steps to allow scripts in jml
mattulbrich Sep 8, 2025
740b046
first working example of a proof script in Java code (albeit with Jav…
mattulbrich Sep 8, 2025
0527387
added missing files for script aware macros
mattulbrich Jan 30, 2023
210c0ca
more infrastructure for proof scripts
mattulbrich Sep 8, 2025
751d117
more infrastructure for proof scripts
mattulbrich Feb 4, 2023
0a401af
more infrastructure for proof scripts
mattulbrich Sep 8, 2025
c00284e
adapting to new Script AST nodes
mattulbrich Sep 8, 2025
ca3711b
renaming AssertCommand to FailUnlessCommand
mattulbrich Sep 8, 2025
e6c2ed9
correcting the grammar for nested \by clauses
mattulbrich Sep 8, 2025
dc898e8
improving the value injector
mattulbrich Sep 10, 2025
11672e5
renaming a deprecated command "assert" --> "assertOpenGoals"
mattulbrich Sep 10, 2025
a0a225a
spotless
mattulbrich Sep 12, 2025
c506ab6
working version of scripts
mattulbrich Sep 24, 2025
731ac74
Position info for scripts with url=null, run scripted goals before ot…
mattulbrich Sep 24, 2025
66c4056
Use AutoPilotPrepareProofMacro instead of FinishSymbolicExecutionMacr…
mattulbrich Sep 24, 2025
8c416b1
working on improved script commands
mattulbrich Sep 24, 2025
5e15b3e
advancing the immutable list interface
mattulbrich May 26, 2023
5ae4c95
reorganisation of proof script commands
mattulbrich Sep 24, 2025
a825b96
advancing for scripts from JML
mattulbrich May 26, 2023
94dac2f
slight adaptation of the macro used for scripting
mattulbrich May 26, 2023
798f2c3
more script commands
mattulbrich Jun 2, 2023
e1086d1
improving/correcting script commands
mattulbrich Jun 5, 2023
428e7d1
settings for the auto command
mattulbrich Jun 8, 2023
64f6f7f
propagating strategy settings to the strategy to be used
mattulbrich Jun 9, 2023
e4377b8
proof scripts: adding a CHEAT command
mattulbrich Jun 15, 2023
cdf6035
updating a few of the script commands
mattulbrich Jun 17, 2023
5cad3f1
introducing the script-aware prep macro
mattulbrich Jun 19, 2023
bd0ec85
issue dialog: skip spaces for squiggly lines
mattulbrich Jun 19, 2023
dfc97ce
value injector: towards reporting unknown arguments
mattulbrich Jun 19, 2023
03496d5
improved script error reporting
mattulbrich Jun 19, 2023
93a9e12
documentation for script commands
mattulbrich Jun 23, 2023
50a7d88
better error messaging in ScriptLineParser
mattulbrich Jun 30, 2023
c3caa44
implement a recall mechanism
mattulbrich Jun 30, 2023
bd88fe9
allow let commands without "@"
mattulbrich Jul 7, 2023
d2e3b34
generalising EqualsModProperty
mattulbrich Sep 27, 2025
d824b15
a formula parameter for the expand command
mattulbrich Jul 22, 2023
6bdbf78
spotlessing
mattulbrich Sep 27, 2025
cde4321
towards 'obtain' in JML scripts
mattulbrich Oct 1, 2025
bd35ba0
update ProofScriptEngine's workflow
mattulbrich Oct 1, 2025
31f73cb
consolidating, introducing test cases for jml scripts
mattulbrich Oct 1, 2025
6b49d28
first working obtain scripts
mattulbrich Oct 1, 2025
2710c8e
pimping the document generation for proof script commands
mattulbrich Oct 2, 2025
5d3fcc1
lots of script documentation
mattulbrich Oct 2, 2025
382f4ce
fixing a bug regarding proof script application
mattulbrich Oct 3, 2025
835497a
repairing some weird self variable treatment in SpecStatement
mattulbrich Oct 3, 2025
1209847
introducing "auto add_*" to scripts.
mattulbrich Jul 19, 2024
0dac525
smaller fixes in proof script treatment
mattulbrich Oct 3, 2025
688c13f
The Boyer-Moore example now runs on scripts
mattulbrich Oct 3, 2025
eeaf1f3
improved document generation
mattulbrich Oct 3, 2025
15bd146
more proof script power, update inlining.
mattulbrich Oct 3, 2025
2382655
making sure that cuts work with boolean terms instead of formulas.
mattulbrich Oct 4, 2025
5e8810d
better symbex-only machine
mattulbrich Oct 5, 2025
4024d29
Allowing "auto only: ..."
mattulbrich Oct 5, 2025
5b3311e
quicksort example with JML scripts (partially)
mattulbrich Oct 5, 2025
4579ddf
enabling the quicksort example with JML proof scripts!
mattulbrich Oct 5, 2025
dc725a0
limiting the symbex only macro a bit
mattulbrich Oct 6, 2025
080dfc6
introducing hole placeholders for terms and for formulas
mattulbrich Jul 18, 2024
583e9af
introducing witness command
mattulbrich Aug 11, 2024
cbfcc76
adapting the cherry-picked commits
mattulbrich Oct 6, 2025
dbd0d1d
allowing switching off rules in auto
mattulbrich Oct 6, 2025
5d4196a
a more robust term-with-holes implementation
mattulbrich Oct 9, 2025
453082f
improved treatment of terms with holes
mattulbrich Oct 10, 2025
3f67048
introduce match identifiers with leading '?'
mattulbrich Oct 10, 2025
e448592
introducing sort::FOCUS for usage in scripts
mattulbrich Jul 18, 2024
86472e6
introducing sort::ELLIP for ellipsis search patterns
mattulbrich Jul 18, 2024
07f8cda
improving sophisticated term matching
mattulbrich Oct 10, 2025
4f9ef7e
accomodating "focus inside find"
mattulbrich Oct 10, 2025
900ec89
add "assumes" parameter to rule command
mattulbrich Jul 19, 2024
aacfba1
bugfixing matching with program variables
mattulbrich Oct 10, 2025
77e361f
updating the focus rule
mattulbrich Oct 10, 2025
25d2b79
allow terms with holes in expand command
WolframPfeifer Aug 13, 2024
ae8b141
added convenience macro to close all NPE and Out-of-bounds branches
WolframPfeifer Aug 28, 2024
a09d684
bug fixes in script engine
mattulbrich Oct 11, 2025
3bb4332
repairing JML script tests
mattulbrich Oct 11, 2025
2bc3a36
fixing a NPE bug in JavaProfile
mattulbrich Oct 15, 2025
46567da
improving symbex only macro
mattulbrich Oct 24, 2025
ec5929d
adding an infinity catch on "throw null" in symb ex.
mattulbrich Oct 24, 2025
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
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();
}
}
}
1 change: 1 addition & 0 deletions key.core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,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
29 changes: 27 additions & 2 deletions key.core/src/main/antlr4/JmlParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ 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());
}
}


classlevel_comments: classlevel_comment* EOF;
classlevel_comment: classlevel_element | modifiers | set_statement;
classlevel_element0: modifiers? (classlevel_element modifiers?);
Expand Down Expand Up @@ -202,12 +204,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;
// ---

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 @@ -219,6 +220,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 @@ -389,6 +391,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 @@ -147,6 +148,7 @@ string_value: STRING_LITERAL;
simple_ident
:
id=IDENT
| {allowMatchId}? id=MATCH_IDENT
;

simple_ident_comma_list
Expand Down Expand Up @@ -873,7 +875,7 @@ proofScriptExpression:
| integer
| floatnum
| string_literal
| LPAREN (term | seq) RPAREN
| LPAREN {allowMatchId=true;} (term | seq) {allowMatchId=false;} RPAREN
| simple_ident
| abbreviation
| literals
Expand Down
3 changes: 2 additions & 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 @@ -18,6 +18,7 @@
import de.uka.ilkd.key.speclang.SpecificationElement;
import de.uka.ilkd.key.util.Debug;

import org.jspecify.annotations.Nullable;
import org.key_project.logic.Name;
import org.key_project.logic.Namespace;
import org.key_project.logic.sort.Sort;
Expand Down Expand Up @@ -430,7 +431,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 @@ -964,7 +964,9 @@ public CatchAllStatement convert(de.uka.ilkd.key.java.recoderext.CatchAllStateme
* @return the converted statement
*/
public JmlAssert convert(de.uka.ilkd.key.java.recoderext.JmlAssert ja) {
return new JmlAssert(ja.getKind(), ja.getCondition(), positionInfo(ja));
return new JmlAssert(ja.getKind(), ja.getOptLabel(), ja.getCondition(),
ja.getAssertionProof(),
positionInfo(ja));
}

// ------------------- declaration ---------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ public interface SourceElement extends SyntaxElement, EqualsModProperty<SourceEl
* These are not syntactical equal, therefore false is returned.
*/
@Override
default <V> boolean equalsModProperty(Object o, Property<SourceElement> property, V... v) {
default <V> boolean equalsModProperty(Object o, Property<? super SourceElement> property,
V... v) {
if (!(o instanceof SourceElement)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,8 @@ private void transformAssertStatement(TextualJMLAssertStatement stat,

de.uka.ilkd.key.java.Position pos = ctx.getStartLocation().getPosition();
final Kind kind = stat.getKind();
JmlAssert jmlAssert = new JmlAssert(kind, ctx);
JmlAssert jmlAssert =
new JmlAssert(kind, ctx, stat.getAssertionProof(), stat.getOptLabel());
try {
updatePositionInformation(jmlAssert, pos);
doAttach(jmlAssert, astParent, childIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import de.uka.ilkd.key.nparser.KeyAst;
import de.uka.ilkd.key.speclang.jml.pretranslation.TextualJMLAssertStatement;

import org.jspecify.annotations.Nullable;
import recoder.java.ProgramElement;
import recoder.java.SourceVisitor;
import recoder.java.Statement;
Expand All @@ -23,6 +24,10 @@ public class JmlAssert extends JavaStatement {
*/
private final TextualJMLAssertStatement.Kind kind;

/**
* The optional proof for an assert statement (not for assume)
*/
private final KeyAst.@Nullable JMLProofScript assertionProof;

/**
* The condition of this statement in parse tree form
Expand All @@ -31,12 +36,21 @@ public class JmlAssert extends JavaStatement {
private final KeyAst.Expression condition;

/**
* @param kind the kind of this statement
* @param condition the condition for this statement
* The optional label for this assertion (may be null)
*/
public JmlAssert(TextualJMLAssertStatement.Kind kind, KeyAst.Expression condition) {
private final @Nullable String optLabel;

public JmlAssert(TextualJMLAssertStatement.Kind kind, KeyAst.Expression condition,
String optLabel) {
this(kind, condition, null, optLabel);
}

public JmlAssert(TextualJMLAssertStatement.Kind kind, KeyAst.Expression condition,
KeyAst.@Nullable JMLProofScript assertionProof, String optLabel) {
this.kind = kind;
this.condition = condition;
this.assertionProof = assertionProof;
this.optLabel = optLabel;
}

/**
Expand All @@ -48,6 +62,8 @@ public JmlAssert(JmlAssert proto) {
super(proto);
this.kind = proto.kind;
this.condition = proto.condition;
this.assertionProof = proto.assertionProof;
this.optLabel = proto.optLabel;
}

public TextualJMLAssertStatement.Kind getKind() {
Expand All @@ -58,6 +74,10 @@ public KeyAst.Expression getCondition() {
return condition;
}

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

@Override
public int getChildCount() {
return 0;
Expand Down Expand Up @@ -87,4 +107,8 @@ public void accept(SourceVisitor sourceVisitor) {
public Statement deepClone() {
return new JmlAssert(this);
}

public String getOptLabel() {
return optLabel;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@
import de.uka.ilkd.key.java.PositionInfo;
import de.uka.ilkd.key.java.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,21 +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 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 @@ -52,11 +74,15 @@ 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 TextualJMLAssertStatement.Kind getKind() {
Expand Down Expand Up @@ -148,6 +174,10 @@ protected int computeHashCode() {
return System.identityHashCode(this);
}

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

@Override
public int getChildCount() {
return 0;
Expand All @@ -162,4 +192,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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,8 @@ public void performActionOnJmlAssert(JmlAssert x) {
ProgramElement createNewElement(ExtList changeList) {
changeList.add(x.getKind());
changeList.add(x.getCondition());
changeList.add(x.getAssertionProof());
changeList.add(x.getOptLabel());
return new JmlAssert(changeList);
}
};
Expand Down
2 changes: 1 addition & 1 deletion key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ protected int computeHashCode() {
}

@Override
public <V> boolean equalsModProperty(Object o, Property<JTerm> property, V... v) {
public <V> boolean equalsModProperty(Object o, Property<? super JTerm> property, V... v) {
if (!(o instanceof JTerm other)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public interface EqualsModProperty<T> {
* @param <V> the type of the additional parameters needed by {@code property} for the
* comparison
*/
<V> boolean equalsModProperty(Object o, Property<T> property, V... v);
<V> boolean equalsModProperty(Object o, Property<? super T> property, V... v);

/**
* Computes the hash code according to the given ignored {@code property}.
Expand Down
Loading
Loading