lemmascript 0.5.11 → 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 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
- npx lsc gen --backend=dafny src/myModule.ts
71
- npx lsc check --backend=dafny src/myModule.ts
72
- npx lsc regen --backend=dafny src/myModule.ts
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
- npx lsc gen --backend=lean src/myModule.ts
84
+ lsc gen --backend=lean src/myModule.ts
81
85
  lake build
82
86
  ```
83
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lemmascript",
3
- "version": "0.5.11",
3
+ "version": "0.5.12",
4
4
  "description": "A verification toolchain for TypeScript — generates Lean 4 or Dafny from annotated TS",
5
5
  "type": "module",
6
6
  "engines": {
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 CLI
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
- process.argv = [process.argv[0], "lemmascript-claimcheck", ...args.slice(1)];
27
- import("lemmascript-claimcheck/cli").catch((err) => {
28
- const code = err?.code;
29
- if (code === "ERR_MODULE_NOT_FOUND" || code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
30
- console.error("`lsc claimcheck` needs lemmascript-claimcheck >= 0.2.0; reinstall with: npm i -g lemmascript");
31
- }
32
- else {
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
- process.exit(1);
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 || !filePath) {
97
+ if (!cmd) {
64
98
  console.error("Usage: lsc <gen|check|regen|extract|info> [--backend=lean|dafny] <file.ts>");
65
- console.error(" lsc claimcheck <file.ts> [flags…] (forwards to lemmascript-claimcheck)");
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}`);