Skip to content

Commit 1b7fff9

Browse files
authored
Replace custom Call/Procedure formatters with DDM printer (#997)
Fixes #994 Removes the custom `ToFormat` instances for `CmdExt` (call statements) and `Procedure` in Core, replacing them with DDM-based pretty-printer functions so the DDM formatter is the sole formatter for these types. To break the circular dependency that prevented removing the old instances, `ASTtoCST.lean` is split into `FormatCore.lean` (expression/statement/procedure formatting) and `ASTtoCST.lean` (program-level conversion only). `Program.lean` imports `FormatCore.lean`, making DDM formatting available to all downstream code. Additional fixes included along the way: - **Grammar:** Removes trailing `\n` from statement format strings and uses `NewlineSepBy Statement` for blocks, eliminating extra blank lines. Closing `}` is placed on its own line. Adds `:0` precedence annotation to `while_statement` body to prevent spurious `({...})` wrapping. - **Call formatting:** Empty-LHS calls now emit `call_unit_statement` (`call foo(1, 2);`) instead of `call_statement` which would produce `call := foo(1, 2);`. - **Lambda support:** Adds a `lambda` construct to the CoreDDM grammar and implements conversion of Lambda `.abs` expressions into DDM `lambda d :: body` syntax, reusing `prettyName` as the bound variable name. - **Extra-arg formatting:** When a declared function is applied to more arguments than it declares (e.g. a function returning a function type via `funMacro`), the formatter now renders the declared args with the function's syntax and wraps extra args in call syntax. Uses `Array.take`/`Array.drop` directly instead of `Array→List→Array` round-trips. - **Deduplication:** Extracts `mkTypeArgsAnn` helper to eliminate repeated type-args conversion patterns. `extractFromExpr` now recurses into `.abs` bodies. Tested: all existing tests pass, new lambda formatting tests added.
1 parent 9a87687 commit 1b7fff9

78 files changed

Lines changed: 1960 additions & 1888 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Examples/expected/DoubleTwice.callElim.core.st

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ spec {
55
ensures [double_correct]: result == n * 2;
66
} {
77
result := n + n;
8-
};
8+
};
99
procedure TestProc (x : int) returns (output : int)
1010
spec {
1111
ensures [testProc_result]: output == x * 4;
@@ -18,4 +18,4 @@ spec {
1818
var tmp_output_1 : int := output;
1919
havoc output;
2020
assume [callElimAssume_double_correct_2]: output == tmp_arg_0 * 2;
21-
};
21+
};

Examples/expected/DoubleTwice.inlineProcedures.core.st

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ spec {
55
ensures [double_correct]: result == n * 2;
66
} {
77
result := n + n;
8-
};
8+
};
99
procedure TestProc (x : int) returns (output : int)
1010
spec {
1111
ensures [testProc_result]: output == x * 4;
@@ -15,11 +15,11 @@ spec {
1515
var Double_result_4 : int;
1616
Double_result_4 := Double_n_3 + Double_n_3;
1717
output := Double_result_4;
18-
}
18+
}
1919
Double$inlined: {
2020
var Double_n_0 : int := output;
2121
var Double_result_1 : int;
2222
Double_result_1 := Double_n_0 + Double_n_0;
2323
output := Double_result_1;
24-
}
25-
};
24+
}
25+
};

Examples/expected/DoubleTwice.inlineProcedures.filterProcedures.core.st

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ spec {
99
var Double_result_4 : int;
1010
Double_result_4 := Double_n_3 + Double_n_3;
1111
output := Double_result_4;
12-
}
12+
}
1313
Double$inlined: {
1414
var Double_n_0 : int := output;
1515
var Double_result_1 : int;
1616
Double_result_1 := Double_n_0 + Double_n_0;
1717
output := Double_result_1;
18-
}
19-
};
18+
}
19+
};

Examples/expected/IrrelevantAxioms.removeIrrelevantAxioms.core.st

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ spec {
1111
ensures [result_positive]: result > 0;
1212
} {
1313
result := f(x);
14-
};
14+
};

Examples/expected/LoopSimple.loopElim.core.st

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ spec {
1414
assert [entry_invariant_0_1]: i * (i - 1) div 2 == sum;
1515
assume [assume_entry_invariant_0_0]: i <= n;
1616
assume [assume_entry_invariant_0_1]: i * (i - 1) div 2 == sum;
17-
}
17+
}
1818
if (i < n) {
1919
arbitrary_iter_facts_0: {
2020
loop_havoc_0: {
2121
havoc sum;
2222
havoc i;
23-
}
23+
}
2424
arbitrary_iter_assumes_0: {
2525
assume [assume_guard_0]: i < n;
2626
assume [assume_invariant_0_0]: i <= n;
2727
assume [assume_invariant_0_1]: i * (i - 1) div 2 == sum;
28-
}
28+
}
2929
var $__loop_measure_0 : int;
3030
assume [assume_measure_0]: $__loop_measure_0 == n - i;
3131
assert [measure_lb_0]: !($__loop_measure_0 < 0);
@@ -34,17 +34,17 @@ spec {
3434
assert [arbitrary_iter_maintain_invariant_0_0]: i <= n;
3535
assert [arbitrary_iter_maintain_invariant_0_1]: i * (i - 1) div 2 == sum;
3636
assert [measure_decrease_0]: n - i < $__loop_measure_0;
37-
}
37+
}
3838
loop_havoc_0: {
3939
havoc sum;
4040
havoc i;
41-
}
41+
}
4242
assume [not_guard_0]: !(i < n);
4343
assume [invariant_0_0]: i <= n;
4444
assume [invariant_0_1]: i * (i - 1) div 2 == sum;
45-
}
4645
}
46+
}
4747
assert [sum_assert]: n * (n - 1) div 2 == sum;
4848
assert [neg_cond]: i == n;
4949
r := sum;
50-
};
50+
};

Examples/expected/SafeBvOps.callElim.core.st

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ procedure safe_bv_ops (x : bv32, y : bv32) returns (r : bv32)
1515
e := x safesdiv y;
1616
f := x safesmod y;
1717
r := a;
18-
};
18+
};

Examples/expected/TwoLoops.loopElim.core.st

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,49 @@ procedure TwoLoops () returns ()
1111
first_iter_asserts_0: {
1212
assert [entry_invariant_0_0]: 0 <= i && i <= N;
1313
assume [assume_entry_invariant_0_0]: 0 <= i && i <= N;
14-
}
14+
}
1515
if (i < N) {
1616
arbitrary_iter_facts_0: {
1717
loop_havoc_0: {
1818
havoc i;
19-
}
19+
}
2020
arbitrary_iter_assumes_0: {
2121
assume [assume_guard_0]: i < N;
2222
assume [assume_invariant_0_0]: 0 <= i && i <= N;
23-
}
23+
}
2424
i := i + 1;
2525
assert [arbitrary_iter_maintain_invariant_0_0]: 0 <= i && i <= N;
26-
}
26+
}
2727
loop_havoc_0: {
2828
havoc i;
29-
}
29+
}
3030
assume [not_guard_0]: !(i < N);
3131
assume [invariant_0_0]: 0 <= i && i <= N;
32-
}
3332
}
33+
}
3434
j := 0;
3535
loop_1: {
3636
first_iter_asserts_1: {
3737
assert [entry_invariant_1_0]: 0 <= j && j <= N;
3838
assume [assume_entry_invariant_1_0]: 0 <= j && j <= N;
39-
}
39+
}
4040
if (j < N) {
4141
arbitrary_iter_facts_1: {
4242
loop_havoc_1: {
4343
havoc j;
44-
}
44+
}
4545
arbitrary_iter_assumes_1: {
4646
assume [assume_guard_1]: j < N;
4747
assume [assume_invariant_1_0]: 0 <= j && j <= N;
48-
}
48+
}
4949
j := j + 1;
5050
assert [arbitrary_iter_maintain_invariant_1_0]: 0 <= j && j <= N;
51-
}
51+
}
5252
loop_havoc_1: {
5353
havoc j;
54-
}
54+
}
5555
assume [not_guard_1]: !(j < N);
5656
assume [invariant_1_0]: 0 <= j && j <= N;
57-
}
5857
}
59-
};
58+
}
59+
};

Strata/DDM/Format.lean

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,28 @@ private partial def ExprF.mformatM (e : ExprF α) (rargs : Array (ArgF α) := #
374374
let args := rargs.reverse
375375
let bindings := op.argDecls
376376
let .isTrue bsize := decEq args.size bindings.size
377-
| return panic! "Mismatch betweeen binding and arg size"
377+
| do
378+
-- When a function is applied to more arguments than it declares
379+
-- (e.g. a function returning a function type via funMacro),
380+
-- format it with its declared args, then apply the remaining
381+
-- args with call syntax.
382+
let declArgCount := bindings.size
383+
if rargs.size > declArgCount then
384+
let fnArgs := args.take declArgCount
385+
let extraArgs := args.drop declArgCount
386+
let .isTrue bsize' := decEq fnArgs.size bindings.size
387+
| return panic! "Mismatch betweeen binding and arg size" -- nopanic:ok
388+
let argResults ← do
389+
match formatArguments (← read) (← get) bindings ⟨fnArgs, bsize'⟩ with
390+
| .ok r => pure r
391+
| .error e => return panic! e -- nopanic:ok
392+
let fnFmt := ppOp (← read).opts op.syntaxDef (Prod.fst <$> argResults)
393+
let extraFmts := (← extraArgs.mapM (·.mformatM)) |>.map (·.format)
394+
let extraFmts := Format.joinSep extraFmts.toList f!", "
395+
return .mk f!"({fnFmt.format})({extraFmts})" callPrec
396+
else
397+
-- Fewer args than expected: format as name(args)
398+
ppArgs f.fullName
378399
let argResults ← do
379400
match formatArguments (← read) (← get) bindings ⟨args, bsize⟩ with
380401
| .ok r => pure r

Strata/Languages/Core/Core.lean

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,6 @@ def typeCheckAndEval (options : VerifyOptions) (program : Program)
111111
dbg_trace f!"{formatProofObligations E.deferred}"
112112
return (pEs, stats)
113113

114-
instance instCoreProgramString : ToString (Program) where
115-
toString p := toString (Core.formatProgram p)
116-
117-
instance instCoreProgramFormat : Std.ToFormat Program where
118-
format := Core.formatProgram
119-
120-
/-- Format a single `Core.Expression.Expr` using the DDM pretty-printer.
121-
This instance shadows the generic `ToFormat (LExpr T)` from `LExpr.lean`. -/
122-
instance instCoreExprFormat : Std.ToFormat Expression.Expr where
123-
format e := Core.formatExprs [e]
124-
125114
end -- public section
126115

127116
end Core

0 commit comments

Comments
 (0)