lemmascript 0.5.10 → 0.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/package.json +1 -1
- package/tools/dist/lsc.js +91 -14
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ See the external case studies:
|
|
|
45
45
|
**Install from npm:**
|
|
46
46
|
|
|
47
47
|
```sh
|
|
48
|
-
npm install lemmascript
|
|
48
|
+
npm install -g lemmascript
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
**Or from source:**
|
|
@@ -67,17 +67,21 @@ git clone https://github.com/namin/velvet.git -b lemma ../velvet
|
|
|
67
67
|
### Dafny backend
|
|
68
68
|
|
|
69
69
|
```sh
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
lsc gen --backend=dafny src/myModule.ts
|
|
71
|
+
lsc check --backend=dafny src/myModule.ts
|
|
72
|
+
lsc regen --backend=dafny src/myModule.ts
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
With no file argument, `lsc check` batches over `LemmaScript-files.txt` (one `filepath [timeout] [extra dafny flags…]` per line — the list `tools/check.sh` runs in CI).
|
|
76
|
+
|
|
77
|
+
From a sibling source checkout, the equivalent of `lsc` is `npx tsx ../LemmaScript/tools/src/lsc.ts` — no build step, toolchain edits apply immediately.
|
|
78
|
+
|
|
75
79
|
The Dafny backend generates two files per TS source: `foo.dfy.gen` (always regeneratable) and `foo.dfy` (source of truth, with LLM/user proof additions). The diff between them must be additions-only.
|
|
76
80
|
|
|
77
81
|
### Lean backend
|
|
78
82
|
|
|
79
83
|
```sh
|
|
80
|
-
|
|
84
|
+
lsc gen --backend=lean src/myModule.ts
|
|
81
85
|
lake build
|
|
82
86
|
```
|
|
83
87
|
|
package/package.json
CHANGED
package/tools/dist/lsc.js
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* Pipeline: extract → resolve → narrow → transform → peephole → emit
|
|
6
6
|
*/
|
|
7
7
|
import { Project, ScriptTarget } from "ts-morph";
|
|
8
|
-
import { existsSync } from "fs";
|
|
8
|
+
import { existsSync, readFileSync } from "fs";
|
|
9
|
+
import { execFileSync } from "child_process";
|
|
10
|
+
import { createRequire } from "module";
|
|
9
11
|
import path from "path";
|
|
10
12
|
import { extractModule } from "./extract.js";
|
|
11
13
|
import { resolveModule } from "./resolve.js";
|
|
@@ -20,20 +22,44 @@ import { leanGen, leanCheck } from "./lean-commands.js";
|
|
|
20
22
|
import { runInfo } from "./info-command.js";
|
|
21
23
|
function main() {
|
|
22
24
|
const args = process.argv.slice(2);
|
|
23
|
-
// `lsc claimcheck …` forwards verbatim to the lemmascript-claimcheck
|
|
24
|
-
// (a dependency; its cli reads the rewritten process.argv).
|
|
25
|
+
// `lsc claimcheck <file.ts> …` forwards verbatim to the lemmascript-claimcheck
|
|
26
|
+
// CLI (a dependency; its cli reads the rewritten process.argv). With no
|
|
27
|
+
// leading <file.ts>, batch: one satellite run per LemmaScript-files.txt entry,
|
|
28
|
+
// flags passed through unchanged — the loop is owned here, the satellite
|
|
29
|
+
// stays single-file.
|
|
25
30
|
if (args[0] === "claimcheck") {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
const rest = args.slice(1);
|
|
32
|
+
const missing = () => {
|
|
33
|
+
console.error("`lsc claimcheck` needs lemmascript-claimcheck >= 0.2.0; reinstall with: npm i -g lemmascript");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
};
|
|
36
|
+
if (rest[0] && !rest[0].startsWith("-")) {
|
|
37
|
+
process.argv = [process.argv[0], "lemmascript-claimcheck", ...rest];
|
|
38
|
+
import("lemmascript-claimcheck/cli").catch((err) => {
|
|
39
|
+
const code = err?.code;
|
|
40
|
+
if (code === "ERR_MODULE_NOT_FOUND" || code === "ERR_PACKAGE_PATH_NOT_EXPORTED")
|
|
41
|
+
missing();
|
|
33
42
|
console.error(err instanceof Error ? err.message : String(err));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let cli;
|
|
48
|
+
try {
|
|
49
|
+
cli = createRequire(import.meta.url).resolve("lemmascript-claimcheck/cli");
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
missing();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
for (const e of readEntries()) {
|
|
56
|
+
try {
|
|
57
|
+
execFileSync(process.execPath, [cli, e.file, ...rest], { stdio: "inherit" });
|
|
34
58
|
}
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
catch {
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
37
63
|
return;
|
|
38
64
|
}
|
|
39
65
|
const backendIdx = args.findIndex(a => a.startsWith("--backend="));
|
|
@@ -59,12 +85,63 @@ function main() {
|
|
|
59
85
|
extraFlags = args[extraFlagsIdx].split("=").slice(1).join("=");
|
|
60
86
|
args.splice(extraFlagsIdx, 1);
|
|
61
87
|
}
|
|
88
|
+
// --slow (batch mode only): verify every entry with its own timeout instead
|
|
89
|
+
// of degrading slow ones to gen-check.
|
|
90
|
+
let slow = false;
|
|
91
|
+
const slowIdx = args.indexOf("--slow");
|
|
92
|
+
if (slowIdx >= 0) {
|
|
93
|
+
slow = true;
|
|
94
|
+
args.splice(slowIdx, 1);
|
|
95
|
+
}
|
|
62
96
|
const [cmd, filePath] = args;
|
|
63
|
-
if (!cmd
|
|
97
|
+
if (!cmd) {
|
|
64
98
|
console.error("Usage: lsc <gen|check|regen|extract|info> [--backend=lean|dafny] <file.ts>");
|
|
65
|
-
console.error(" lsc
|
|
99
|
+
console.error(" lsc <gen|gen-check|check> [--backend=…] [--slow] (no file: batch over LemmaScript-files.txt)");
|
|
100
|
+
console.error(" lsc claimcheck [<file.ts>] [flags…] (forwards to lemmascript-claimcheck)");
|
|
66
101
|
process.exit(1);
|
|
67
102
|
}
|
|
103
|
+
if (!filePath) {
|
|
104
|
+
runBatch(cmd, backend, slow);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
runFile(cmd, filePath, backend, timeLimit, extraFlags);
|
|
108
|
+
}
|
|
109
|
+
// LemmaScript-files.txt, parsed: `filepath [timeout_in_seconds] [extra dafny
|
|
110
|
+
// flags…]` per line; no timeout = Dafny default. Exits if the file is absent.
|
|
111
|
+
function readEntries() {
|
|
112
|
+
if (!existsSync("LemmaScript-files.txt")) {
|
|
113
|
+
console.error("No file given and no LemmaScript-files.txt found.");
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
return readFileSync("LemmaScript-files.txt", "utf8")
|
|
117
|
+
.split("\n").map(s => s.trim()).filter(Boolean)
|
|
118
|
+
.map(entry => {
|
|
119
|
+
const [file, second, ...rest] = entry.split(/\s+/);
|
|
120
|
+
const timeout = second && /^[1-9]\d*$/.test(second) ? parseInt(second) : undefined;
|
|
121
|
+
const flags = (timeout === undefined ? [second, ...rest] : rest).filter(Boolean).join(" ") || undefined;
|
|
122
|
+
return { file, timeout, flags };
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// Batch over LemmaScript-files.txt. `check` entries with a timeout above 60s
|
|
126
|
+
// (the CI limit) are gen-check only, unless --slow. Fail-fast: the first
|
|
127
|
+
// failing entry exits. tools/check.sh drives this from source;
|
|
128
|
+
// installed-package consumers run `lsc check`.
|
|
129
|
+
function runBatch(cmd, backend, slow) {
|
|
130
|
+
if (cmd !== "gen" && cmd !== "gen-check" && cmd !== "check") {
|
|
131
|
+
console.error(`No file given, and batch mode supports gen|gen-check|check (not ${cmd}).`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
for (const e of readEntries()) {
|
|
135
|
+
if (cmd === "check" && backend === "dafny" && !slow && e.timeout !== undefined && e.timeout > 60) {
|
|
136
|
+
console.log(`=== ${path.basename(e.file)} (timeout ${e.timeout}s > 60s, gen-check only) ===`);
|
|
137
|
+
runFile("gen-check", e.file, backend, undefined, undefined);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
runFile(cmd, e.file, backend, e.timeout, e.flags);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function runFile(cmd, filePath, backend, timeLimit, extraFlags) {
|
|
68
145
|
const absPath = path.resolve(filePath);
|
|
69
146
|
if (!existsSync(absPath)) {
|
|
70
147
|
console.error(`File not found: ${absPath}`);
|