lemmascript 0.3.0 → 0.3.1
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/package.json +1 -1
- package/tools/dist/dafny-commands.js +3 -2
- package/tools/dist/dafny-emit.js +87 -155
- package/tools/dist/extract.js +3 -1
- package/tools/dist/lsc.js +7 -1
- package/tools/dist/resolve.js +218 -178
- package/tools/dist/transform.js +217 -147
package/package.json
CHANGED
|
@@ -31,13 +31,14 @@ export function dafnyCheckDiff(genPath, dfyPath) {
|
|
|
31
31
|
catch { /* diff not available */ }
|
|
32
32
|
return true;
|
|
33
33
|
}
|
|
34
|
-
export function dafnyVerify(dfyPath, dir, timeLimit) {
|
|
34
|
+
export function dafnyVerify(dfyPath, dir, timeLimit, extraFlags) {
|
|
35
35
|
console.log("Running dafny verify...");
|
|
36
36
|
try {
|
|
37
37
|
const content = readFileSync(dfyPath, "utf-8");
|
|
38
38
|
const stdLibFlag = content.includes("Std.") ? " --standard-libraries" : "";
|
|
39
39
|
const timeLimitFlag = timeLimit ? ` --verification-time-limit ${timeLimit}` : "";
|
|
40
|
-
|
|
40
|
+
const extra = extraFlags ? ` ${extraFlags}` : "";
|
|
41
|
+
execSync(`dafny verify${stdLibFlag}${timeLimitFlag}${extra} "${dfyPath}"`, { cwd: dir, stdio: "inherit" });
|
|
41
42
|
return true;
|
|
42
43
|
}
|
|
43
44
|
catch {
|
package/tools/dist/dafny-emit.js
CHANGED
|
@@ -14,7 +14,7 @@ function tyToDafny(ty) {
|
|
|
14
14
|
case "map": return `map<${tyToDafny(ty.key)}, ${tyToDafny(ty.value)}>`;
|
|
15
15
|
case "set": return `set<${tyToDafny(ty.elem)}>`;
|
|
16
16
|
case "optional": {
|
|
17
|
-
|
|
17
|
+
needPreamble("OptionType");
|
|
18
18
|
return `Option<${tyToDafny(ty.inner)}>`;
|
|
19
19
|
}
|
|
20
20
|
case "user": return ty.name;
|
|
@@ -55,6 +55,22 @@ const OP_MAP = {
|
|
|
55
55
|
};
|
|
56
56
|
function mapOp(op) { return OP_MAP[op] ?? op; }
|
|
57
57
|
// ── Expression emission ─────────────────────────────────────
|
|
58
|
+
/** Emit a match scrutinee — either a variable name (string) or an expression. */
|
|
59
|
+
function emitScrutinee(s) {
|
|
60
|
+
return typeof s === "string" ? escapeName(s) : emitExpr(s);
|
|
61
|
+
}
|
|
62
|
+
/** Collapse nested forall/exists into a single quantifier with multiple bound vars. */
|
|
63
|
+
function emitQuantifier(e, keyword) {
|
|
64
|
+
const vars = [];
|
|
65
|
+
let body = e;
|
|
66
|
+
while (body.kind === e.kind) {
|
|
67
|
+
const dty = tyToDafny(body.type);
|
|
68
|
+
const ann = dty === "string" ? "" : `: ${dty}`;
|
|
69
|
+
vars.push(`${body.var}${ann}`);
|
|
70
|
+
body = body.body;
|
|
71
|
+
}
|
|
72
|
+
return `${keyword} ${vars.join(", ")} :: ${emitExpr(body)}`;
|
|
73
|
+
}
|
|
58
74
|
function emitExpr(e) {
|
|
59
75
|
switch (e.kind) {
|
|
60
76
|
case "var": return e.name === "undefined" ? "None" : escapeName(e.name);
|
|
@@ -106,25 +122,25 @@ function emitExpr(e) {
|
|
|
106
122
|
// String methods
|
|
107
123
|
if (ty === "string") {
|
|
108
124
|
if (e.method === "indexOf") {
|
|
109
|
-
|
|
125
|
+
needPreamble("StringIndexOf");
|
|
110
126
|
return `StringIndexOf(${obj}, ${args[0]})`;
|
|
111
127
|
}
|
|
112
128
|
if (e.method === "slice")
|
|
113
129
|
return `${obj}[${args[0]}..${args[1]}]`;
|
|
114
130
|
if (e.method === "trim") {
|
|
115
|
-
|
|
131
|
+
needPreamble("StringTrim");
|
|
116
132
|
return `StringTrim(${obj})`;
|
|
117
133
|
}
|
|
118
134
|
if (e.method === "toLowerCase") {
|
|
119
|
-
|
|
135
|
+
needPreamble("StringToLower");
|
|
120
136
|
return `StringToLower(${obj})`;
|
|
121
137
|
}
|
|
122
138
|
if (e.method === "toUpperCase") {
|
|
123
|
-
|
|
139
|
+
needPreamble("StringToUpper");
|
|
124
140
|
return `StringToUpper(${obj})`;
|
|
125
141
|
}
|
|
126
142
|
if (e.method === "includes") {
|
|
127
|
-
|
|
143
|
+
needPreamble("StringIndexOf");
|
|
128
144
|
return `(StringIndexOf(${obj}, ${args[0]}) >= 0)`;
|
|
129
145
|
}
|
|
130
146
|
if (e.method === "charCodeAt")
|
|
@@ -135,7 +151,7 @@ function emitExpr(e) {
|
|
|
135
151
|
if (e.method === "getDirect")
|
|
136
152
|
return `${obj}[${args[0]}]`;
|
|
137
153
|
if (e.method === "get") {
|
|
138
|
-
|
|
154
|
+
needPreamble("OptionType");
|
|
139
155
|
return `(if ${args[0]} in ${obj} then Some(${obj}[${args[0]}]) else None)`;
|
|
140
156
|
}
|
|
141
157
|
if (e.method === "set")
|
|
@@ -187,14 +203,14 @@ function emitExpr(e) {
|
|
|
187
203
|
if (e.right.kind === "num") {
|
|
188
204
|
return `(${emitExpr(e.left)} / ${Math.pow(2, e.right.value)})`;
|
|
189
205
|
}
|
|
190
|
-
|
|
206
|
+
needPreamble("Pow2");
|
|
191
207
|
return `(${emitExpr(e.left)} / Pow2(${emitExpr(e.right)}))`;
|
|
192
208
|
}
|
|
193
209
|
if (e.op === "<<") {
|
|
194
210
|
if (e.right.kind === "num") {
|
|
195
211
|
return `(${emitExpr(e.left)} * ${Math.pow(2, e.right.value)})`;
|
|
196
212
|
}
|
|
197
|
-
|
|
213
|
+
needPreamble("Pow2");
|
|
198
214
|
return `(${emitExpr(e.left)} * Pow2(${emitExpr(e.right)}))`;
|
|
199
215
|
}
|
|
200
216
|
// x & mask → x % (mask + 1) for literal masks of form 2^n - 1, else BitAnd
|
|
@@ -206,7 +222,7 @@ function emitExpr(e) {
|
|
|
206
222
|
return `(${emitExpr(e.left)} % ${modulus})`;
|
|
207
223
|
}
|
|
208
224
|
}
|
|
209
|
-
|
|
225
|
+
needPreamble("BitAnd");
|
|
210
226
|
return `BitAnd(${emitExpr(e.left)}, ${emitExpr(e.right)})`;
|
|
211
227
|
}
|
|
212
228
|
// int * real coercion: wrap int side with "as real"
|
|
@@ -228,7 +244,7 @@ function emitExpr(e) {
|
|
|
228
244
|
case "app": {
|
|
229
245
|
const args = e.args.map(emitExpr);
|
|
230
246
|
if (e.fn === "SetToSeq") {
|
|
231
|
-
|
|
247
|
+
needPreamble("SetToSeq");
|
|
232
248
|
return `SetToSeq(${args.join(", ")})`;
|
|
233
249
|
}
|
|
234
250
|
if (e.fn === "BigInt" || e.fn === "Number")
|
|
@@ -237,19 +253,19 @@ function emitExpr(e) {
|
|
|
237
253
|
if (e.fn === "SetLiteral")
|
|
238
254
|
return `{${args.join(", ")}}`;
|
|
239
255
|
if (e.fn === "JSFloorDiv")
|
|
240
|
-
|
|
256
|
+
needPreamble("JSFloorDiv");
|
|
241
257
|
if (e.fn === "CeilReal")
|
|
242
|
-
|
|
258
|
+
needPreamble("CeilReal");
|
|
243
259
|
if (e.fn === "FloorReal")
|
|
244
|
-
|
|
260
|
+
needPreamble("FloorReal");
|
|
245
261
|
if (e.fn === "NatToString")
|
|
246
|
-
|
|
262
|
+
needPreamble("NatToString");
|
|
247
263
|
if (e.fn === "MathAbs")
|
|
248
|
-
|
|
264
|
+
needPreamble("MathAbs");
|
|
249
265
|
if (e.fn === "MathMin")
|
|
250
|
-
|
|
266
|
+
needPreamble("MathMin");
|
|
251
267
|
if (e.fn === "MathMax")
|
|
252
|
-
|
|
268
|
+
needPreamble("MathMax");
|
|
253
269
|
return `${escapeName(e.fn)}(${args.join(", ")})`;
|
|
254
270
|
}
|
|
255
271
|
case "field": {
|
|
@@ -295,7 +311,7 @@ function emitExpr(e) {
|
|
|
295
311
|
if (f)
|
|
296
312
|
return emitExpr(f.value);
|
|
297
313
|
if (sf.type.kind === "optional") {
|
|
298
|
-
|
|
314
|
+
needPreamble("OptionType");
|
|
299
315
|
return "None";
|
|
300
316
|
}
|
|
301
317
|
return `/* missing: ${sf.name} */`;
|
|
@@ -311,34 +327,12 @@ function emitExpr(e) {
|
|
|
311
327
|
case "if":
|
|
312
328
|
return `if ${emitExpr(e.cond)} then ${emitExpr(e.then)} else ${emitExpr(e.else)}`;
|
|
313
329
|
case "match": {
|
|
314
|
-
const scrut =
|
|
330
|
+
const scrut = emitScrutinee(e.scrutinee);
|
|
315
331
|
const arms = e.arms.map(a => `case ${translatePattern(a.pattern)} => ${emitExpr(a.body)}`);
|
|
316
332
|
return `(match ${scrut} { ${arms.join(" ")} })`;
|
|
317
333
|
}
|
|
318
|
-
case "forall":
|
|
319
|
-
|
|
320
|
-
const vars = [];
|
|
321
|
-
let body = e;
|
|
322
|
-
while (body.kind === "forall") {
|
|
323
|
-
const dty = tyToDafny(body.type);
|
|
324
|
-
const ann = dty === "string" ? "" : `: ${dty}`;
|
|
325
|
-
vars.push(`${body.var}${ann}`);
|
|
326
|
-
body = body.body;
|
|
327
|
-
}
|
|
328
|
-
return `forall ${vars.join(", ")} :: ${emitExpr(body)}`;
|
|
329
|
-
}
|
|
330
|
-
case "exists": {
|
|
331
|
-
// Collapse nested exists: exists x :: exists y :: P → exists x, y :: P
|
|
332
|
-
const vars = [];
|
|
333
|
-
let body = e;
|
|
334
|
-
while (body.kind === "exists") {
|
|
335
|
-
const dty = tyToDafny(body.type);
|
|
336
|
-
const ann = dty === "string" ? "" : `: ${dty}`;
|
|
337
|
-
vars.push(`${body.var}${ann}`);
|
|
338
|
-
body = body.body;
|
|
339
|
-
}
|
|
340
|
-
return `exists ${vars.join(", ")} :: ${emitExpr(body)}`;
|
|
341
|
-
}
|
|
334
|
+
case "forall": return emitQuantifier(e, "forall");
|
|
335
|
+
case "exists": return emitQuantifier(e, "exists");
|
|
342
336
|
case "let": return `var ${escapeName(e.name)} := ${emitExpr(e.value)}; ${emitExpr(e.body)}`;
|
|
343
337
|
case "havoc": return "*";
|
|
344
338
|
}
|
|
@@ -350,7 +344,7 @@ function emitPureExpr(e, indent) {
|
|
|
350
344
|
case "if":
|
|
351
345
|
return `${pad}if ${emitExpr(e.cond)} then\n${emitPureExpr(e.then, indent + 1)}\n${pad}else\n${emitPureExpr(e.else, indent + 1)}`;
|
|
352
346
|
case "match": {
|
|
353
|
-
const scrut =
|
|
347
|
+
const scrut = emitScrutinee(e.scrutinee);
|
|
354
348
|
const lines = [`${pad}match ${scrut} {`];
|
|
355
349
|
for (const arm of e.arms) {
|
|
356
350
|
lines.push(`${pad} case ${translatePattern(arm.pattern)} =>`);
|
|
@@ -415,7 +409,7 @@ function emitStmt(s, indent) {
|
|
|
415
409
|
return out;
|
|
416
410
|
}
|
|
417
411
|
case "match": {
|
|
418
|
-
const scrut =
|
|
412
|
+
const scrut = emitScrutinee(s.scrutinee);
|
|
419
413
|
const lines = [`${pad}match ${scrut} {`];
|
|
420
414
|
for (const arm of s.arms) {
|
|
421
415
|
lines.push(`${pad} case ${translatePattern(arm.pattern)} =>`);
|
|
@@ -480,8 +474,10 @@ function emitDecl(d) {
|
|
|
480
474
|
lines.push(`}`);
|
|
481
475
|
// Companion lemma for ensures (proof target for LLM)
|
|
482
476
|
if (d.ensures.length > 0) {
|
|
477
|
+
// Strip constraints like (==) from type params — ghost lemmas don't need them
|
|
478
|
+
const lemmaTP = d.typeParams.length > 0 ? `<${d.typeParams.map(t => t.replace(/\(.*\)/, '')).join(", ")}>` : "";
|
|
483
479
|
lines.push("");
|
|
484
|
-
lines.push(`lemma ${d.name}_ensures${
|
|
480
|
+
lines.push(`lemma ${d.name}_ensures${lemmaTP}(${paramList(d.params)})`);
|
|
485
481
|
for (const r of d.requires)
|
|
486
482
|
lines.push(` requires ${emitExpr(r)}`);
|
|
487
483
|
for (const e of d.ensures)
|
|
@@ -534,21 +530,9 @@ function emitDecl(d) {
|
|
|
534
530
|
}
|
|
535
531
|
// ── File emission ───────────────────────────────────────────
|
|
536
532
|
// ── Preamble helpers ────────────────────────────────────────
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
let needsStringToUpper = false;
|
|
541
|
-
let needsJSFloorDiv = false;
|
|
542
|
-
let needsCeilReal = false;
|
|
543
|
-
let needsFloorReal = false;
|
|
544
|
-
let needsOptionType = false;
|
|
545
|
-
let needsSetToSeq = false;
|
|
546
|
-
let needsBitAnd = false;
|
|
547
|
-
let needsPow2 = false;
|
|
548
|
-
let needsNatToString = false;
|
|
549
|
-
let needsMathAbs = false;
|
|
550
|
-
let needsMathMin = false;
|
|
551
|
-
let needsMathMax = false;
|
|
533
|
+
/** Preamble tracking — emitters add keys via `needPreamble(key)`, emitDafnyFile emits them. */
|
|
534
|
+
const _neededPreambles = new Set();
|
|
535
|
+
function needPreamble(key) { _neededPreambles.add(key); }
|
|
552
536
|
const POW2 = `function Pow2(n: int): int
|
|
553
537
|
requires n >= 0
|
|
554
538
|
decreases n
|
|
@@ -646,6 +630,41 @@ const NAT_TO_STRING = `function NatToString(n: nat): string
|
|
|
646
630
|
else NatToString(n / 10) + [digit]
|
|
647
631
|
}`;
|
|
648
632
|
const MATH_ABS = `function MathAbs(x: int): nat { if x >= 0 then x else -x }`;
|
|
633
|
+
const SET_TO_SEQ = `method SetToSeq<T>(s: set<T>) returns (res: seq<T>)
|
|
634
|
+
ensures forall x :: x in s <==> x in res
|
|
635
|
+
ensures |res| == |s|
|
|
636
|
+
{
|
|
637
|
+
var remaining := s;
|
|
638
|
+
res := [];
|
|
639
|
+
while remaining != {}
|
|
640
|
+
invariant remaining <= s
|
|
641
|
+
invariant forall x :: x in res <==> (x in s && x !in remaining)
|
|
642
|
+
invariant |res| + |remaining| == |s|
|
|
643
|
+
decreases remaining
|
|
644
|
+
{
|
|
645
|
+
var x :| x in remaining;
|
|
646
|
+
res := res + [x];
|
|
647
|
+
remaining := remaining - {x};
|
|
648
|
+
}
|
|
649
|
+
}`;
|
|
650
|
+
/** Preamble code keyed by name. Emitted in this order when needed. */
|
|
651
|
+
const PREAMBLE_CODE = [
|
|
652
|
+
["OptionType", "datatype Option<T> = None | Some(value: T)"],
|
|
653
|
+
["SetToSeq", SET_TO_SEQ],
|
|
654
|
+
["Pow2", POW2],
|
|
655
|
+
["BitAnd", BIT_AND],
|
|
656
|
+
["JSFloorDiv", JS_FLOOR_DIV],
|
|
657
|
+
["CeilReal", CEIL_REAL],
|
|
658
|
+
["FloorReal", FLOOR_REAL],
|
|
659
|
+
["StringIndexOf", STRING_INDEX_OF],
|
|
660
|
+
["StringTrim", STRING_TRIM],
|
|
661
|
+
["StringToLower", STRING_TO_LOWER],
|
|
662
|
+
["StringToUpper", STRING_TO_UPPER],
|
|
663
|
+
["NatToString", NAT_TO_STRING],
|
|
664
|
+
["MathAbs", MATH_ABS],
|
|
665
|
+
["MathMin", MATH_MIN],
|
|
666
|
+
["MathMax", MATH_MAX],
|
|
667
|
+
];
|
|
649
668
|
// ── Constructor and record helpers ───────────────────────────
|
|
650
669
|
let _recordCtors = new Map();
|
|
651
670
|
let _structureDecls = new Map();
|
|
@@ -714,26 +733,9 @@ function translatePattern(pattern) {
|
|
|
714
733
|
const fieldNames = fields.split(/\s+/).map(escapeName);
|
|
715
734
|
return `${ctorName}(${fieldNames.join(", ")})`;
|
|
716
735
|
}
|
|
717
|
-
const PREAMBLES = {
|
|
718
|
-
StringIndexOf: STRING_INDEX_OF,
|
|
719
|
-
};
|
|
720
736
|
export function emitDafnyFile(file, tsFileName) {
|
|
721
737
|
buildRecordCtorMap(file.decls);
|
|
722
|
-
|
|
723
|
-
needsStringTrim = false;
|
|
724
|
-
needsStringToLower = false;
|
|
725
|
-
needsStringToUpper = false;
|
|
726
|
-
needsJSFloorDiv = false;
|
|
727
|
-
needsCeilReal = false;
|
|
728
|
-
needsFloorReal = false;
|
|
729
|
-
needsOptionType = false;
|
|
730
|
-
needsSetToSeq = false;
|
|
731
|
-
needsBitAnd = false;
|
|
732
|
-
needsPow2 = false;
|
|
733
|
-
needsNatToString = false;
|
|
734
|
-
needsMathAbs = false;
|
|
735
|
-
needsMathMin = false;
|
|
736
|
-
needsMathMax = false;
|
|
738
|
+
_neededPreambles.clear();
|
|
737
739
|
// Collect pure def names so we can skip their method wrappers
|
|
738
740
|
const pureDefs = new Set();
|
|
739
741
|
for (const d of file.decls) {
|
|
@@ -770,81 +772,11 @@ export function emitDafnyFile(file, tsFileName) {
|
|
|
770
772
|
const lines = [];
|
|
771
773
|
if (tsFileName)
|
|
772
774
|
lines.push(`// Generated by lsc from ${tsFileName}`);
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
lines.push("");
|
|
779
|
-
lines.push(`method SetToSeq<T>(s: set<T>) returns (res: seq<T>)
|
|
780
|
-
ensures forall x :: x in s <==> x in res
|
|
781
|
-
ensures |res| == |s|
|
|
782
|
-
{
|
|
783
|
-
var remaining := s;
|
|
784
|
-
res := [];
|
|
785
|
-
while remaining != {}
|
|
786
|
-
invariant remaining <= s
|
|
787
|
-
invariant forall x :: x in res <==> (x in s && x !in remaining)
|
|
788
|
-
invariant |res| + |remaining| == |s|
|
|
789
|
-
decreases remaining
|
|
790
|
-
{
|
|
791
|
-
var x :| x in remaining;
|
|
792
|
-
res := res + [x];
|
|
793
|
-
remaining := remaining - {x};
|
|
794
|
-
}
|
|
795
|
-
}`);
|
|
796
|
-
}
|
|
797
|
-
if (needsPow2) {
|
|
798
|
-
lines.push("");
|
|
799
|
-
lines.push(POW2);
|
|
800
|
-
}
|
|
801
|
-
if (needsBitAnd) {
|
|
802
|
-
lines.push("");
|
|
803
|
-
lines.push(BIT_AND);
|
|
804
|
-
}
|
|
805
|
-
if (needsJSFloorDiv) {
|
|
806
|
-
lines.push("");
|
|
807
|
-
lines.push(JS_FLOOR_DIV);
|
|
808
|
-
}
|
|
809
|
-
if (needsCeilReal) {
|
|
810
|
-
lines.push("");
|
|
811
|
-
lines.push(CEIL_REAL);
|
|
812
|
-
}
|
|
813
|
-
if (needsFloorReal) {
|
|
814
|
-
lines.push("");
|
|
815
|
-
lines.push(FLOOR_REAL);
|
|
816
|
-
}
|
|
817
|
-
if (needsStringIndexOf) {
|
|
818
|
-
lines.push("");
|
|
819
|
-
lines.push(PREAMBLES.StringIndexOf);
|
|
820
|
-
}
|
|
821
|
-
if (needsStringTrim) {
|
|
822
|
-
lines.push("");
|
|
823
|
-
lines.push(STRING_TRIM);
|
|
824
|
-
}
|
|
825
|
-
if (needsStringToLower) {
|
|
826
|
-
lines.push("");
|
|
827
|
-
lines.push(STRING_TO_LOWER);
|
|
828
|
-
}
|
|
829
|
-
if (needsStringToUpper) {
|
|
830
|
-
lines.push("");
|
|
831
|
-
lines.push(STRING_TO_UPPER);
|
|
832
|
-
}
|
|
833
|
-
if (needsNatToString) {
|
|
834
|
-
lines.push("");
|
|
835
|
-
lines.push(NAT_TO_STRING);
|
|
836
|
-
}
|
|
837
|
-
if (needsMathAbs) {
|
|
838
|
-
lines.push("");
|
|
839
|
-
lines.push(MATH_ABS);
|
|
840
|
-
}
|
|
841
|
-
if (needsMathMin) {
|
|
842
|
-
lines.push("");
|
|
843
|
-
lines.push(MATH_MIN);
|
|
844
|
-
}
|
|
845
|
-
if (needsMathMax) {
|
|
846
|
-
lines.push("");
|
|
847
|
-
lines.push(MATH_MAX);
|
|
775
|
+
for (const [key, code] of PREAMBLE_CODE) {
|
|
776
|
+
if (_neededPreambles.has(key)) {
|
|
777
|
+
lines.push("");
|
|
778
|
+
lines.push(code);
|
|
779
|
+
}
|
|
848
780
|
}
|
|
849
781
|
lines.push(...declLines);
|
|
850
782
|
return lines.join("\n") + "\n";
|
package/tools/dist/extract.js
CHANGED
|
@@ -558,7 +558,9 @@ function extractStmts(stmts) {
|
|
|
558
558
|
const nameNode = decl?.getNameNode();
|
|
559
559
|
if (nameNode && Node.isArrayBindingPattern(nameNode)) {
|
|
560
560
|
for (const elem of nameNode.getElements()) {
|
|
561
|
-
if (Node.
|
|
561
|
+
if (Node.isOmittedExpression(elem))
|
|
562
|
+
names.push("_");
|
|
563
|
+
else if (Node.isBindingElement(elem))
|
|
562
564
|
names.push(elem.getNameNode().getText());
|
|
563
565
|
}
|
|
564
566
|
}
|
package/tools/dist/lsc.js
CHANGED
|
@@ -33,6 +33,12 @@ function main() {
|
|
|
33
33
|
timeLimit = parseInt(args[timeLimitIdx].split("=")[1]);
|
|
34
34
|
args.splice(timeLimitIdx, 1);
|
|
35
35
|
}
|
|
36
|
+
const extraFlagsIdx = args.findIndex(a => a.startsWith("--extra-flags="));
|
|
37
|
+
let extraFlags;
|
|
38
|
+
if (extraFlagsIdx >= 0) {
|
|
39
|
+
extraFlags = args[extraFlagsIdx].split("=").slice(1).join("=");
|
|
40
|
+
args.splice(extraFlagsIdx, 1);
|
|
41
|
+
}
|
|
36
42
|
const [cmd, filePath] = args;
|
|
37
43
|
if (!cmd || !filePath) {
|
|
38
44
|
console.error("Usage: lsc <gen|check|regen|extract> [--backend=lean|dafny] <file.ts>");
|
|
@@ -101,7 +107,7 @@ function main() {
|
|
|
101
107
|
dafnyGen(genPath, dfyPath, text);
|
|
102
108
|
if (!dafnyCheckDiff(genPath, dfyPath))
|
|
103
109
|
process.exit(1);
|
|
104
|
-
if (!dafnyVerify(dfyPath, dir, timeLimit))
|
|
110
|
+
if (!dafnyVerify(dfyPath, dir, timeLimit, extraFlags))
|
|
105
111
|
process.exit(1);
|
|
106
112
|
return;
|
|
107
113
|
}
|