@harmoniclabs/pebble 0.1.10 → 0.3.0
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/dist/IR/CompilationCtx.d.ts +40 -0
- package/dist/IR/CompilationCtx.js +54 -0
- package/dist/IR/IRHash.d.ts +23 -2
- package/dist/IR/IRHash.js +10 -60
- package/dist/IR/IRNodes/IRConst.js +35 -4
- package/dist/IR/IRNodes/IRHoisted.d.ts +0 -1
- package/dist/IR/IRNodes/IRHoisted.js +4 -6
- package/dist/IR/IRNodes/IRLetted.d.ts +0 -1
- package/dist/IR/IRNodes/IRLetted.js +4 -6
- package/dist/IR/IRNodes/IRNative/IRNativeTag.d.ts +22 -2
- package/dist/IR/IRNodes/IRNative/IRNativeTag.js +26 -2
- package/dist/IR/IRNodes/IRNative/index.d.ts +16 -1
- package/dist/IR/IRNodes/IRNative/index.js +31 -2
- package/dist/IR/IRNodes/utils/hashVarSym.d.ts +0 -1
- package/dist/IR/IRNodes/utils/hashVarSym.js +27 -33
- package/dist/IR/toUPLC/CompilerOptions.d.ts +34 -7
- package/dist/IR/toUPLC/CompilerOptions.js +19 -10
- package/dist/IR/toUPLC/compileIRToUPLC.js +39 -3
- package/dist/IR/toUPLC/subRoutines/inlineSingleUseLetBindingsAndReturnRoot.d.ts +23 -0
- package/dist/IR/toUPLC/subRoutines/inlineSingleUseLetBindingsAndReturnRoot.js +263 -0
- package/dist/IR/toUPLC/subRoutines/introduceCaseForDualHeadTailAndReturnRoot.d.ts +35 -0
- package/dist/IR/toUPLC/subRoutines/introduceCaseForDualHeadTailAndReturnRoot.js +169 -0
- package/dist/IR/toUPLC/subRoutines/replaceHoistedWithLetted.d.ts +0 -1
- package/dist/IR/toUPLC/subRoutines/replaceHoistedWithLetted.js +6 -6
- package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.d.ts +2 -3
- package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.js +106 -65
- package/dist/IR/toUPLC/subRoutines/rewriteHeadTailInCaseConsAndReturnRoot.d.ts +30 -0
- package/dist/IR/toUPLC/subRoutines/rewriteHeadTailInCaseConsAndReturnRoot.js +95 -0
- package/dist/IR/toUPLC/subRoutines/rewriteNativesAppliedToConstantsAndReturnRoot.js +36 -5
- package/dist/IR/toUPLC/subRoutines/rewriteToCaseOverConstAndReturnRoot.d.ts +35 -0
- package/dist/IR/toUPLC/subRoutines/rewriteToCaseOverConstAndReturnRoot.js +169 -0
- package/dist/IR/tree_utils/_ir_caseList.d.ts +15 -0
- package/dist/IR/tree_utils/_ir_caseList.js +19 -0
- package/dist/IR/tree_utils/bytesToHex.d.ts +8 -0
- package/dist/IR/tree_utils/bytesToHex.js +69 -0
- package/dist/ast/nodes/expr/functions/FuncExpr.d.ts +16 -2
- package/dist/ast/nodes/expr/functions/FuncExpr.js +17 -0
- package/dist/ast/nodes/expr/litteral/LitteralExpr.d.ts +2 -1
- package/dist/ast/nodes/expr/litteral/LitteralExpr.js +2 -0
- package/dist/ast/nodes/expr/litteral/TemplateStrExpr.d.ts +30 -0
- package/dist/ast/nodes/expr/litteral/TemplateStrExpr.js +35 -0
- package/dist/ast/nodes/statements/ExportStmt.d.ts +3 -3
- package/dist/ast/nodes/statements/PebbleStmt.d.ts +4 -3
- package/dist/ast/nodes/statements/PebbleStmt.js +6 -2
- package/dist/ast/nodes/statements/TestParam.d.ts +18 -0
- package/dist/ast/nodes/statements/TestParam.js +18 -0
- package/dist/ast/nodes/statements/TestStmt.d.ts +5 -3
- package/dist/ast/nodes/statements/TestStmt.js +3 -1
- package/dist/ast/nodes/statements/UsingStmt.d.ts +32 -2
- package/dist/ast/nodes/statements/UsingStmt.js +39 -3
- package/dist/ast/nodes/statements/declarations/NamespaceDecl.d.ts +21 -0
- package/dist/ast/nodes/statements/declarations/NamespaceDecl.js +31 -0
- package/dist/ast/nodes/statements/declarations/StructDecl.d.ts +16 -2
- package/dist/ast/nodes/statements/declarations/StructDecl.js +15 -1
- package/dist/compiler/AstCompiler/AstCompiler.d.ts +27 -0
- package/dist/compiler/AstCompiler/AstCompiler.js +244 -7
- package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +16 -5
- package/dist/compiler/AstCompiler/internal/exprs/_compileCallExpr.js +97 -6
- package/dist/compiler/AstCompiler/internal/exprs/_compileCaseExpr.js +31 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compileFuncExpr.js +12 -5
- package/dist/compiler/AstCompiler/internal/exprs/_compileIsExpr.js +12 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compileLitteralExpr.js +59 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.d.ts +2 -3
- package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +64 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compileUnaryPrefixExpr.js +13 -1
- package/dist/compiler/AstCompiler/internal/exprs/_compileVarAccessExpr.js +2 -0
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileAddExpr.js +18 -5
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileEqualExpr.js +3 -1
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanEqualExpr.js +2 -1
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanExpr.js +2 -1
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanEqualExpr.js +2 -1
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanExpr.js +2 -1
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileMultExpr.js +24 -6
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileNotEqualExpr.js +2 -1
- package/dist/compiler/AstCompiler/internal/exprs/binary/_compileSubExpr.js +16 -5
- package/dist/compiler/AstCompiler/internal/statements/_compileMatchStmt.js +33 -20
- package/dist/compiler/AstCompiler/internal/statements/_compileStatement.js +4 -1
- package/dist/compiler/AstCompiler/internal/statements/_compileTestStmt.d.ts +15 -1
- package/dist/compiler/AstCompiler/internal/statements/_compileTestStmt.js +70 -30
- package/dist/compiler/AstCompiler/internal/statements/_compileUsingAliasStmt.d.ts +11 -0
- package/dist/compiler/AstCompiler/internal/statements/_compileUsingAliasStmt.js +26 -0
- package/dist/compiler/AstCompiler/internal/statements/_compileUsingStmt.d.ts +9 -4
- package/dist/compiler/AstCompiler/internal/statements/_compileUsingStmt.js +51 -10
- package/dist/compiler/AstCompiler/internal/types/_compileDataEncodedConcreteType.js +21 -2
- package/dist/compiler/AstCompiler/internal/types/_compileSopEncodedConcreteType.js +17 -2
- package/dist/compiler/AstCompiler/scope/AstScope.d.ts +70 -1
- package/dist/compiler/AstCompiler/scope/AstScope.js +91 -0
- package/dist/compiler/AstCompiler/utils/getPropAccessReturnType.js +36 -1
- package/dist/compiler/AstCompiler/utils/monomorphizeGeneric.d.ts +36 -0
- package/dist/compiler/AstCompiler/utils/monomorphizeGeneric.js +123 -0
- package/dist/compiler/AstCompiler/utils/resolveNamespaceChain.d.ts +28 -0
- package/dist/compiler/AstCompiler/utils/resolveNamespaceChain.js +95 -0
- package/dist/compiler/AstCompiler/utils/resolveNamespacePath.d.ts +37 -0
- package/dist/compiler/AstCompiler/utils/resolveNamespacePath.js +93 -0
- package/dist/compiler/Compiler.d.ts +9 -1
- package/dist/compiler/Compiler.js +218 -30
- package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +1 -1
- package/dist/compiler/TirCompiler/expressify/expressify.js +30 -2
- package/dist/compiler/TirCompiler/expressify/expressifyForStmt.d.ts +2 -1
- package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +45 -7
- package/dist/compiler/TirCompiler/expressify/expressifyVars.d.ts +0 -1
- package/dist/compiler/TirCompiler/expressify/expressifyVars.js +49 -15
- package/dist/compiler/test/TestResult.d.ts +38 -0
- package/dist/compiler/test/TestResult.js +6 -0
- package/dist/compiler/test/fuzz/PRNG.d.ts +26 -0
- package/dist/compiler/test/fuzz/PRNG.js +59 -0
- package/dist/compiler/tir/expressions/TirCaseExpr.d.ts +9 -0
- package/dist/compiler/tir/expressions/TirCaseExpr.js +144 -122
- package/dist/compiler/tir/expressions/TirElemAccessExpr.js +2 -2
- package/dist/compiler/tir/expressions/TirExpr.d.ts +2 -1
- package/dist/compiler/tir/expressions/TirExpr.js +2 -0
- package/dist/compiler/tir/expressions/TirFromDataExpr.js +102 -67
- package/dist/compiler/tir/expressions/TirIsExpr.js +14 -1
- package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +18 -2
- package/dist/compiler/tir/expressions/TirNativeFunc.js +55 -118
- package/dist/compiler/tir/expressions/TirShowExpr.d.ts +52 -0
- package/dist/compiler/tir/expressions/TirShowExpr.js +199 -0
- package/dist/compiler/tir/expressions/TirToDataExpr.js +3 -0
- package/dist/compiler/tir/expressions/TirTraceExpr.js +11 -7
- package/dist/compiler/tir/expressions/TirTypeConversionExpr.js +10 -0
- package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +2 -3
- package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +1 -4
- package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +20 -3
- package/dist/compiler/tir/expressions/ToIRTermCtx.js +48 -3
- package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +2 -2
- package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +45 -8
- package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.d.ts +19 -0
- package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.js +24 -0
- package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.d.ts +2 -1
- package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.js +2 -0
- package/dist/compiler/tir/expressions/unary/TirUnaryMinus.js +4 -1
- package/dist/compiler/tir/program/TypedProgram.d.ts +101 -0
- package/dist/compiler/tir/program/TypedProgram.js +43 -0
- package/dist/compiler/tir/program/stdScope/populateBuiltinInterfaces.d.ts +17 -0
- package/dist/compiler/tir/program/stdScope/populateBuiltinInterfaces.js +70 -0
- package/dist/compiler/tir/program/stdScope/populateStdNamespace.d.ts +22 -0
- package/dist/compiler/tir/program/stdScope/populateStdNamespace.js +619 -0
- package/dist/compiler/tir/program/stdScope/prelude/preludeTypesSrc.js +35 -2
- package/dist/compiler/tir/program/stdScope/stdScope.d.ts +8 -0
- package/dist/compiler/tir/program/stdScope/stdScope.js +84 -41
- package/dist/compiler/tir/statements/TirStmt.js +0 -1
- package/dist/compiler/tir/statements/TirTestStmt.d.ts +46 -0
- package/dist/compiler/tir/statements/TirTestStmt.js +35 -0
- package/dist/compiler/tir/types/TirEnumType.d.ts +21 -0
- package/dist/compiler/tir/types/TirEnumType.js +36 -0
- package/dist/compiler/tir/types/TirNativeType/TirNativeType.d.ts +53 -2
- package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +58 -1
- package/dist/compiler/tir/types/TirNativeType/native/array.d.ts +16 -0
- package/dist/compiler/tir/types/TirNativeType/native/array.js +38 -0
- package/dist/compiler/tir/types/TirNativeType/native/index.d.ts +2 -0
- package/dist/compiler/tir/types/TirNativeType/native/index.js +2 -0
- package/dist/compiler/tir/types/TirNativeType/native/value.d.ts +18 -0
- package/dist/compiler/tir/types/TirNativeType/native/value.js +17 -0
- package/dist/compiler/tir/types/TirStructType.js +6 -1
- package/dist/compiler/tir/types/TirType.d.ts +3 -2
- package/dist/compiler/tir/types/TirType.js +7 -2
- package/dist/compiler/tir/types/utils/canAssignTo.js +36 -1
- package/dist/compiler/tir/types/utils/canCastTo.js +14 -1
- package/dist/compiler/tir/types/utils/getDeconstructableType.d.ts +2 -1
- package/dist/compiler/tir/types/utils/getDeconstructableType.js +2 -0
- package/dist/compiler/tir/types/utils/inferTypeArgs.d.ts +19 -0
- package/dist/compiler/tir/types/utils/inferTypeArgs.js +83 -0
- package/dist/compiler/tir/types/utils/normalizeEnumToInt.d.ts +10 -0
- package/dist/compiler/tir/types/utils/normalizeEnumToInt.js +17 -0
- package/dist/compiler/tir/types/utils/substituteTypeParams.d.ts +9 -0
- package/dist/compiler/tir/types/utils/substituteTypeParams.js +67 -0
- package/dist/diagnostics/diagnosticMessages.generated.d.ts +10 -0
- package/dist/diagnostics/diagnosticMessages.generated.js +20 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/parser/Parser.d.ts +73 -3
- package/dist/parser/Parser.js +362 -46
- package/dist/tokenizer/Token.d.ts +106 -102
- package/dist/tokenizer/Token.js +111 -109
- package/dist/tokenizer/utils/tokenFromKeyword.js +11 -6
- package/dist/utils/semverSatisfies.d.ts +1 -0
- package/dist/utils/semverSatisfies.js +161 -0
- package/dist/version.generated.d.ts +1 -0
- package/dist/version.generated.js +2 -0
- package/package.json +5 -4
- package/dist/IR/tree_utils/_ir_lazyChooseList.d.ts +0 -3
- package/dist/IR/tree_utils/_ir_lazyChooseList.js +0 -7
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When the same list `L` is used for BOTH `headList(L)` and `tailList(L)`
|
|
3
|
+
* within a single function body, those two builtin calls can be replaced
|
|
4
|
+
* by a single `case L of cons h t -> body[h/headList(L), t/tailList(L)] |
|
|
5
|
+
* nil -> error`. The trade-off (measured in `bench.headTailVsCase`):
|
|
6
|
+
*
|
|
7
|
+
* - one `headList` (or `tailList`) builtin call: 112,100 CPU / 800 mem
|
|
8
|
+
* - one `case L of cons h t -> h | nil -> error`: 128,100 CPU / 900 mem
|
|
9
|
+
*
|
|
10
|
+
* So for a single access the builtin wins; for dual access the case wins
|
|
11
|
+
* by a single dispatch (~96K CPU / 700 mem).
|
|
12
|
+
*
|
|
13
|
+
* This pass walks every `IRFunc` body bottom-up. For each body, it scans
|
|
14
|
+
* the top-level (without descending into nested `IRFunc`/`IRRecursive`,
|
|
15
|
+
* because nested scopes are processed independently). If a free list var
|
|
16
|
+
* `L` has both a `headList(L)` and a `tailList(L)` use in the body, the
|
|
17
|
+
* body is wrapped with `IRCase(IRVar(L), [IRFunc([h, t], body'), IRError])`
|
|
18
|
+
* — where `body'` has those calls replaced with `IRVar(h)` / `IRVar(t)`.
|
|
19
|
+
*
|
|
20
|
+
* Notes:
|
|
21
|
+
* - We only act on `IRFunc` bodies that are NOT immediate continuations
|
|
22
|
+
* of an `IRCase` whose scrutinee is `IRVar(L)` for the same L — that
|
|
23
|
+
* case-cons branch already binds head/tail and the prior
|
|
24
|
+
* `rewriteHeadTailInCaseConsAndReturnRoot` pass has already done the
|
|
25
|
+
* substitution. Wrapping again would be a no-op constructor pair.
|
|
26
|
+
* - The nil branch is `IRError`. Original code that calls `headList` or
|
|
27
|
+
* `tailList` on a nil list errors at evaluation; the new code errors
|
|
28
|
+
* at the case dispatch — same observable behavior whenever either
|
|
29
|
+
* call is actually reached.
|
|
30
|
+
* - The pass iterates: after introducing a case for L, the (now
|
|
31
|
+
* substituted) body might still contain a different L' with dual
|
|
32
|
+
* head/tail uses — handled by re-scanning until no more pairs.
|
|
33
|
+
*/
|
|
34
|
+
import { IRApp } from "../../IRNodes/IRApp.js";
|
|
35
|
+
import { IRCase } from "../../IRNodes/IRCase.js";
|
|
36
|
+
import { IRError } from "../../IRNodes/IRError.js";
|
|
37
|
+
import { IRFunc } from "../../IRNodes/IRFunc.js";
|
|
38
|
+
import { IRHoisted } from "../../IRNodes/IRHoisted.js";
|
|
39
|
+
import { IRLetted } from "../../IRNodes/IRLetted.js";
|
|
40
|
+
import { IRNative } from "../../IRNodes/IRNative/index.js";
|
|
41
|
+
import { IRNativeTag } from "../../IRNodes/IRNative/IRNativeTag.js";
|
|
42
|
+
import { IRRecursive } from "../../IRNodes/IRRecursive.js";
|
|
43
|
+
import { IRVar } from "../../IRNodes/IRVar.js";
|
|
44
|
+
import { _modifyChildFromTo } from "../_internal/_modifyChildFromTo.js";
|
|
45
|
+
function unwrap(t) {
|
|
46
|
+
while (t instanceof IRHoisted)
|
|
47
|
+
t = t.hoisted;
|
|
48
|
+
while (t instanceof IRLetted)
|
|
49
|
+
t = t.value;
|
|
50
|
+
return t;
|
|
51
|
+
}
|
|
52
|
+
export function introduceCaseForDualHeadTailAndReturnRoot(term) {
|
|
53
|
+
processNode(term);
|
|
54
|
+
return term;
|
|
55
|
+
}
|
|
56
|
+
function processNode(node) {
|
|
57
|
+
// Post-order: recurse into children first, then process this node.
|
|
58
|
+
for (const child of node.children())
|
|
59
|
+
processNode(child);
|
|
60
|
+
if (node instanceof IRFunc) {
|
|
61
|
+
// Avoid wrapping case-cons branches that the previous pass already
|
|
62
|
+
// optimized: if `node` is the cons continuation of an outer
|
|
63
|
+
// `IRCase(IRVar(L), [node, ...])`, then head(L)/tail(L) were
|
|
64
|
+
// already substituted; if any dual remains it's for a *different*
|
|
65
|
+
// list L', which we handle normally.
|
|
66
|
+
tryWrap(node);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function tryWrap(fn) {
|
|
70
|
+
while (true) {
|
|
71
|
+
const choice = findFirstDualHeadTailList(fn.body, new Set(fn.params));
|
|
72
|
+
if (choice === undefined)
|
|
73
|
+
return;
|
|
74
|
+
const listSym = choice;
|
|
75
|
+
const desc = listSym.description ?? "L";
|
|
76
|
+
const hSym = Symbol("h_" + desc);
|
|
77
|
+
const tSym = Symbol("t_" + desc);
|
|
78
|
+
// Substitute head(L)/tail(L) inside the current body (won't descend
|
|
79
|
+
// into nested scopes that re-bind L, h, or t — but we just minted
|
|
80
|
+
// h/t so they don't collide with anything).
|
|
81
|
+
substituteHeadTailInBody(fn.body, listSym, hSym, tSym);
|
|
82
|
+
// Wrap.
|
|
83
|
+
const oldBody = fn.body;
|
|
84
|
+
const consFn = new IRFunc([hSym, tSym], oldBody);
|
|
85
|
+
const wrapped = new IRCase(new IRVar(listSym), [consFn, new IRError()]);
|
|
86
|
+
fn.body = wrapped;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Scan `root` for free `headList(L)`/`tailList(L)` uses where `L` is NOT
|
|
91
|
+
* shadowed by an enclosing nested IRFunc/IRRecursive within `root`. Returns
|
|
92
|
+
* the first list symbol with at least one head AND one tail use.
|
|
93
|
+
*/
|
|
94
|
+
function findFirstDualHeadTailList(root, boundInOuterFunc) {
|
|
95
|
+
const heads = new Set();
|
|
96
|
+
const tails = new Set();
|
|
97
|
+
function walk(node, locallyBound) {
|
|
98
|
+
if (node instanceof IRFunc) {
|
|
99
|
+
const next = new Set(locallyBound);
|
|
100
|
+
for (const p of node.params)
|
|
101
|
+
next.add(p);
|
|
102
|
+
walk(node.body, next);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (node instanceof IRRecursive) {
|
|
106
|
+
const next = new Set(locallyBound);
|
|
107
|
+
next.add(node.name);
|
|
108
|
+
walk(node.body, next);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (node instanceof IRApp) {
|
|
112
|
+
const fn = unwrap(node.fn);
|
|
113
|
+
const arg = node.arg;
|
|
114
|
+
if (fn instanceof IRNative
|
|
115
|
+
&& arg instanceof IRVar
|
|
116
|
+
&& !locallyBound.has(arg.name)
|
|
117
|
+
&& (fn.tag === IRNativeTag.headList
|
|
118
|
+
|| fn.tag === IRNativeTag.tailList)) {
|
|
119
|
+
(fn.tag === IRNativeTag.headList ? heads : tails).add(arg.name);
|
|
120
|
+
// do not descend further — this is a leaf for our purposes
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// generic descent
|
|
124
|
+
}
|
|
125
|
+
for (const c of node.children())
|
|
126
|
+
walk(c, locallyBound);
|
|
127
|
+
}
|
|
128
|
+
walk(root, boundInOuterFunc);
|
|
129
|
+
for (const sym of heads) {
|
|
130
|
+
if (tails.has(sym))
|
|
131
|
+
return sym;
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* In-place: replace every `IRApp(unwrap=headList, IRVar(L))` /
|
|
137
|
+
* `IRApp(unwrap=tailList, IRVar(L))` inside `root` with `IRVar(h)` /
|
|
138
|
+
* `IRVar(t)`. Stops descending into any nested IRFunc/IRRecursive that
|
|
139
|
+
* shadows `L`, `h`, or `t`.
|
|
140
|
+
*/
|
|
141
|
+
function substituteHeadTailInBody(root, listSym, hSym, tSym) {
|
|
142
|
+
const stack = [root];
|
|
143
|
+
while (stack.length > 0) {
|
|
144
|
+
const t = stack.pop();
|
|
145
|
+
if (t instanceof IRFunc || t instanceof IRRecursive) {
|
|
146
|
+
const params = t instanceof IRFunc ? t.params : [t.name];
|
|
147
|
+
if (params.includes(listSym)
|
|
148
|
+
|| params.includes(hSym)
|
|
149
|
+
|| params.includes(tSym))
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (t instanceof IRApp) {
|
|
153
|
+
const fn = unwrap(t.fn);
|
|
154
|
+
const arg = t.arg;
|
|
155
|
+
if (fn instanceof IRNative
|
|
156
|
+
&& arg instanceof IRVar
|
|
157
|
+
&& arg.name === listSym
|
|
158
|
+
&& (fn.tag === IRNativeTag.headList || fn.tag === IRNativeTag.tailList)) {
|
|
159
|
+
const newSym = fn.tag === IRNativeTag.headList ? hSym : tSym;
|
|
160
|
+
const parent = t.parent;
|
|
161
|
+
if (parent !== undefined) {
|
|
162
|
+
_modifyChildFromTo(parent, t, new IRVar(newSym));
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
stack.push(...t.children());
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
import { currentCompilationCtx } from "../../CompilationCtx.js";
|
|
1
2
|
import { IRHoisted } from "../../IRNodes/IRHoisted.js";
|
|
2
3
|
import { IRLetted } from "../../IRNodes/IRLetted.js";
|
|
3
4
|
import { _modifyChildFromTo } from "../_internal/_modifyChildFromTo.js";
|
|
4
|
-
const _hoisted_cache = new Map();
|
|
5
|
-
export function __unsafe_clear_hoisted_cache() {
|
|
6
|
-
_hoisted_cache.clear();
|
|
7
|
-
}
|
|
8
5
|
export function replaceHoistedWithLetted(term) {
|
|
9
6
|
// children first
|
|
10
7
|
const children = term.children();
|
|
@@ -16,11 +13,14 @@ export function replaceHoistedWithLetted(term) {
|
|
|
16
13
|
const parent = term.parent;
|
|
17
14
|
if (!parent)
|
|
18
15
|
throw new Error("hoisted node has no parent");
|
|
19
|
-
|
|
16
|
+
// per-compilation cache: maps a hoisted term's content hash to the
|
|
17
|
+
// letted node it lowers to, so repeated occurrences share one binder.
|
|
18
|
+
const hoistedCache = currentCompilationCtx().hoistedCache;
|
|
19
|
+
const cached = hoistedCache.get(term.hash)?.deref();
|
|
20
20
|
const letted = (cached ??
|
|
21
21
|
new IRLetted(term.name, term.hoisted, { isClosed: true })).clone();
|
|
22
22
|
if (!cached)
|
|
23
|
-
|
|
23
|
+
hoistedCache.set(term.hash, new WeakRef(letted));
|
|
24
24
|
// replace hoisted with letted
|
|
25
25
|
_modifyChildFromTo(parent, term, letted);
|
|
26
26
|
}
|
|
@@ -8,20 +8,19 @@ export declare const hoisted_decr: IRHoisted;
|
|
|
8
8
|
export declare const hoisted_isZero: IRHoisted;
|
|
9
9
|
export declare const hoisted_isOne: IRHoisted;
|
|
10
10
|
export declare const hoisted_isTwo: IRHoisted;
|
|
11
|
+
export declare const hoisted_negateValue: IRHoisted;
|
|
12
|
+
export declare const hoisted_valueEq: IRHoisted;
|
|
11
13
|
export declare const hoisted_isThree: IRHoisted;
|
|
12
14
|
export declare const hoisted_addOne: IRHoisted;
|
|
13
15
|
export declare const hoisted_subOne: IRHoisted;
|
|
14
16
|
export declare const hoisted_negateInteger: IRHoisted;
|
|
15
17
|
export declare const hoisted_isPositive: IRHoisted;
|
|
16
18
|
export declare const hoisted_isNonNegative: IRHoisted;
|
|
17
|
-
export declare const hoisted_matchList: IRHoisted;
|
|
18
19
|
export declare const hoisted_recursiveList: IRHoisted;
|
|
19
20
|
export declare const hoisted_foldr: IRHoisted;
|
|
20
|
-
export declare const hosited_lazyChooseList: IRHoisted;
|
|
21
21
|
export declare const hoisted_isMoreThanOrEqualTo4: IRHoisted;
|
|
22
22
|
export declare const hoisted_sub4: IRHoisted;
|
|
23
23
|
export declare const hoisted_length: IRHoisted;
|
|
24
|
-
export declare const hoisted_dropList: IRHoisted;
|
|
25
24
|
export declare const hoisted_findSopOptional: IRHoisted;
|
|
26
25
|
export declare const hoisted_lookupLinearMap: IRHoisted;
|
|
27
26
|
export declare const hoisted_mkFindDataOptional: IRHoisted;
|
|
@@ -13,10 +13,9 @@ import { IRSelfCall } from "../../../IRNodes/IRSelfCall.js";
|
|
|
13
13
|
import { IRError } from "../../../IRNodes/IRError.js";
|
|
14
14
|
import { _ir_apps } from "../../../IRNodes/IRApp.js";
|
|
15
15
|
import { _ir_let, _ir_let_sym } from "../../../tree_utils/_ir_let.js";
|
|
16
|
-
import {
|
|
16
|
+
import { _ir_caseList } from "../../../tree_utils/_ir_caseList.js";
|
|
17
17
|
import { _ir_lazyIfThenElse } from "../../../tree_utils/_ir_lazyIfThenElse.js";
|
|
18
|
-
import {
|
|
19
|
-
import { IRConstr } from "../../../IRNodes/index.js";
|
|
18
|
+
import { IRCase, IRConstr } from "../../../IRNodes/index.js";
|
|
20
19
|
import { _ir_and, _ir_or } from "../../../../compiler/tir/expressions/binary/TirBinaryExpr.js";
|
|
21
20
|
function _ir_strictAnd(left, right) {
|
|
22
21
|
return _ir_apps(IRNative.strictIfThenElse, left, right, IRConst.bool(false));
|
|
@@ -39,6 +38,22 @@ export const hoisted_isOne = new IRHoisted(new IRApp(IRNative.equalsInteger, IRC
|
|
|
39
38
|
hoisted_isZero.hash;
|
|
40
39
|
export const hoisted_isTwo = new IRHoisted(new IRApp(IRNative.equalsInteger, IRConst.int(2)));
|
|
41
40
|
hoisted_isTwo.hash;
|
|
41
|
+
// negateValue = (scaleValue -1)
|
|
42
|
+
// the scaleValue builtin is `(int, Value) -> Value`; partially applying
|
|
43
|
+
// -1 yields a unary `Value -> Value` negation. Cheaper than running a
|
|
44
|
+
// user-level multiply over the entire map.
|
|
45
|
+
export const hoisted_negateValue = new IRHoisted(new IRApp(IRNative.scaleValue, IRConst.int(-1)));
|
|
46
|
+
hoisted_negateValue.hash;
|
|
47
|
+
// valueEq a b = if valueContains(a, b) then valueContains(b, a) else false
|
|
48
|
+
// Bidirectional containment is equality for canonical Values (the
|
|
49
|
+
// only form the runtime ever produces). Short-circuits on the first
|
|
50
|
+
// non-containment to save the second `valueContains` traversal.
|
|
51
|
+
export const hoisted_valueEq = new IRHoisted((() => {
|
|
52
|
+
const a = Symbol("valueEq_a");
|
|
53
|
+
const b = Symbol("valueEq_b");
|
|
54
|
+
return new IRFunc([a, b], _ir_lazyIfThenElse(_ir_apps(IRNative.valueContains, new IRVar(a), new IRVar(b)), _ir_apps(IRNative.valueContains, new IRVar(b), new IRVar(a)), IRConst.bool(false)));
|
|
55
|
+
})());
|
|
56
|
+
hoisted_valueEq.hash;
|
|
42
57
|
export const hoisted_isThree = new IRHoisted(new IRApp(IRNative.equalsInteger, IRConst.int(3)));
|
|
43
58
|
export const hoisted_addOne = new IRHoisted(new IRApp(IRNative.addInteger, IRConst.int(1)));
|
|
44
59
|
hoisted_addOne.hash;
|
|
@@ -50,22 +65,24 @@ export const hoisted_isPositive = new IRHoisted(new IRApp(IRNative.lessThanInteg
|
|
|
50
65
|
hoisted_isPositive.hash;
|
|
51
66
|
export const hoisted_isNonNegative = new IRHoisted(new IRApp(IRNative.lessThanEqualInteger, IRConst.int(0)));
|
|
52
67
|
hoisted_isNonNegative.hash;
|
|
53
|
-
export const hoisted_matchList = new IRHoisted((() => {
|
|
54
|
-
const delayed_matchNil = Symbol("delayed_matchNil");
|
|
55
|
-
const matchCons = Symbol("matchCons");
|
|
56
|
-
const list = Symbol("list");
|
|
57
|
-
return new IRFunc([delayed_matchNil, matchCons, list], new IRForced(new IRForced(_ir_apps(IRNative.strictChooseList, new IRVar(list), new IRVar(delayed_matchNil), new IRDelayed(_ir_apps(new IRVar(matchCons), new IRApp(IRNative.headList, new IRVar(list)), new IRApp(IRNative.tailList, new IRVar(list))))))));
|
|
58
|
-
})());
|
|
59
|
-
hoisted_matchList.hash;
|
|
60
|
-
//*
|
|
61
68
|
// hoisted_recursiveList (needed by hoisted_foldr)
|
|
69
|
+
// λ matchNil matchCons → recurse self → λ lst →
|
|
70
|
+
// case lst of
|
|
71
|
+
// cons h t -> (matchCons self) h t
|
|
72
|
+
// nil -> force (matchNil self)
|
|
73
|
+
// `matchNil` is expected to return a delayed value (so it can close over
|
|
74
|
+
// recursive state without forcing eagerly); the nil branch forces it.
|
|
62
75
|
const recList_matchNil = Symbol("matchNil");
|
|
63
76
|
const recList_matchCons = Symbol("matchCons");
|
|
64
77
|
const recList_self = Symbol("recursiveList_self");
|
|
65
78
|
const recList_lst = Symbol("lst");
|
|
66
|
-
|
|
79
|
+
const recList_h = Symbol("h");
|
|
80
|
+
const recList_t = Symbol("t");
|
|
81
|
+
export const hoisted_recursiveList = new IRHoisted(new IRFunc([recList_matchNil, recList_matchCons], new IRRecursive(recList_self, new IRFunc([recList_lst], new IRCase(new IRVar(recList_lst), [
|
|
82
|
+
new IRFunc([recList_h, recList_t], _ir_apps(new IRApp(new IRVar(recList_matchCons), new IRSelfCall(recList_self)), new IRVar(recList_h), new IRVar(recList_t))),
|
|
83
|
+
new IRForced(new IRApp(new IRVar(recList_matchNil), new IRSelfCall(recList_self)))
|
|
84
|
+
])))));
|
|
67
85
|
hoisted_recursiveList.hash;
|
|
68
|
-
//*/
|
|
69
86
|
// hoisted_foldr
|
|
70
87
|
const foldr_reducer = Symbol("reduceFunc");
|
|
71
88
|
const foldr_acc = Symbol("accumulator");
|
|
@@ -75,36 +92,49 @@ const foldr_head = Symbol("head");
|
|
|
75
92
|
const foldr_tail = Symbol("tail");
|
|
76
93
|
export const hoisted_foldr = new IRHoisted(new IRFunc([foldr_reducer, foldr_acc], _ir_apps(hoisted_recursiveList.clone(), new IRFunc([foldr__dummy], new IRDelayed(new IRVar(foldr_acc))), new IRFunc([foldr_self, foldr_head, foldr_tail], _ir_apps(new IRVar(foldr_reducer), new IRVar(foldr_head), new IRApp(new IRVar(foldr_self), new IRVar(foldr_tail)))))));
|
|
77
94
|
hoisted_foldr.hash;
|
|
78
|
-
export const hosited_lazyChooseList = new IRHoisted((() => {
|
|
79
|
-
const list = Symbol("list");
|
|
80
|
-
const delayed_caseNil = Symbol("delayed_caseNil");
|
|
81
|
-
const delayed_caseCons = Symbol("delayed_caseCons");
|
|
82
|
-
return new IRFunc([list, delayed_caseNil, delayed_caseCons], new IRForced(_ir_apps(IRNative.strictChooseList, new IRVar(list), new IRVar(delayed_caseNil), new IRVar(delayed_caseCons))));
|
|
83
|
-
})());
|
|
84
|
-
hosited_lazyChooseList.hash;
|
|
85
|
-
//*/
|
|
86
95
|
export const hoisted_isMoreThanOrEqualTo4 = new IRHoisted(_ir_apps(IRNative.lessThanInteger, IRConst.int(4)));
|
|
87
96
|
hoisted_isMoreThanOrEqualTo4.hash;
|
|
88
97
|
export const hoisted_sub4 = new IRHoisted(_ir_apps(IRNative.addInteger, IRConst.int(-4)));
|
|
89
98
|
hoisted_sub4.hash;
|
|
90
99
|
const self_length = Symbol("self_length");
|
|
91
100
|
const length_list_sym = Symbol("length_list_sym");
|
|
92
|
-
export const hoisted_length = new IRHoisted(
|
|
93
|
-
|
|
94
|
-
|
|
101
|
+
export const hoisted_length = new IRHoisted(
|
|
102
|
+
// new IRRecursive(
|
|
103
|
+
// self_length,
|
|
104
|
+
// new IRFunc(
|
|
105
|
+
// [ length_list_sym ],
|
|
106
|
+
// _ir_caseList(
|
|
107
|
+
// new IRVar( length_list_sym ),
|
|
108
|
+
// IRConst.int( 0 ),
|
|
109
|
+
// _ir_apps(
|
|
110
|
+
// hoisted_incr.clone(),
|
|
111
|
+
// new IRApp(
|
|
112
|
+
// new IRSelfCall( self_length ), // self
|
|
113
|
+
// new IRApp(
|
|
114
|
+
// IRNative.tailList,
|
|
115
|
+
// new IRVar( length_list_sym ) // list
|
|
116
|
+
// )
|
|
117
|
+
// )
|
|
118
|
+
// )
|
|
119
|
+
// )
|
|
120
|
+
// )
|
|
121
|
+
// )
|
|
122
|
+
new IRFunc([length_list_sym], _ir_apps(IRNative.lengthOfArray, _ir_apps(IRNative.listToArray, new IRVar(length_list_sym)))));
|
|
95
123
|
hoisted_length.hash;
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
export const hoisted_dropList = new IRHoisted(new IRRecursive(drop_self, new IRFunc([drop_n, drop_lst], _ir_lazyIfThenElse(_ir_apps(hoisted_isMoreThanOrEqualTo4.clone(), new IRVar(drop_n)), _ir_apps(new IRSelfCall(drop_self), _ir_apps(hoisted_sub4.clone(), new IRVar(drop_n)), _ir_apps(hoisted_drop4.clone(), new IRVar(drop_lst))), _ir_lazyIfThenElse(_ir_apps(hoisted_isZero.clone(), new IRVar(drop_n)), new IRVar(drop_lst), _ir_lazyIfThenElse(_ir_apps(hoisted_isOne.clone(), new IRVar(drop_n)), _ir_apps(IRNative.tailList, new IRVar(drop_lst)), _ir_lazyIfThenElse(_ir_apps(hoisted_isTwo.clone(), new IRVar(drop_n)), _ir_apps(hoisted_drop2.clone(), new IRVar(drop_lst)), _ir_apps(hoisted_drop3.clone(), new IRVar(drop_lst)))))))));
|
|
101
|
-
hoisted_dropList.hash;
|
|
124
|
+
// λ reduce → recurse self → λ acc → λ list →
|
|
125
|
+
// case list of
|
|
126
|
+
// cons h t -> self (reduce acc h) t
|
|
127
|
+
// nil -> acc
|
|
102
128
|
const foldl_reduce = Symbol("reduceFunc");
|
|
103
129
|
const foldl_self = Symbol("foldl_self");
|
|
104
130
|
const foldl_acc = Symbol("accum");
|
|
131
|
+
const foldl_list = Symbol("list");
|
|
105
132
|
const foldl_head = Symbol("head");
|
|
106
133
|
const foldl_tail = Symbol("tail");
|
|
107
|
-
const hoiseted_foldl = new IRHoisted(new IRFunc([foldl_reduce], new IRRecursive(foldl_self, new IRFunc([foldl_acc
|
|
134
|
+
const hoiseted_foldl = new IRHoisted(new IRFunc([foldl_reduce], new IRRecursive(foldl_self, new IRFunc([foldl_acc, foldl_list], new IRCase(new IRVar(foldl_list), [
|
|
135
|
+
new IRFunc([foldl_head, foldl_tail], _ir_apps(new IRSelfCall(foldl_self), _ir_apps(new IRVar(foldl_reduce), new IRVar(foldl_acc), new IRVar(foldl_head)), new IRVar(foldl_tail))),
|
|
136
|
+
new IRVar(foldl_acc)
|
|
137
|
+
])))));
|
|
108
138
|
hoiseted_foldl.hash;
|
|
109
139
|
// hoisted _findSopOptional
|
|
110
140
|
// (predicate: (a -> Bool)) -> (list: [a]) -> Optional<a>
|
|
@@ -112,7 +142,7 @@ const findSop_predicate = Symbol("predicate");
|
|
|
112
142
|
const findSop_self = Symbol("findOpt_self");
|
|
113
143
|
const findSop_list = Symbol("list");
|
|
114
144
|
const findSop_head = Symbol("head");
|
|
115
|
-
export const hoisted_findSopOptional = new IRHoisted(new IRFunc([findSop_predicate], new IRRecursive(findSop_self, new IRFunc([findSop_list],
|
|
145
|
+
export const hoisted_findSopOptional = new IRHoisted(new IRFunc([findSop_predicate], new IRRecursive(findSop_self, new IRFunc([findSop_list], _ir_caseList(new IRVar(findSop_list),
|
|
116
146
|
// case nil
|
|
117
147
|
new IRConstr(1, []), // None
|
|
118
148
|
// case cons
|
|
@@ -128,7 +158,7 @@ const lookup_key = Symbol("lookup_key");
|
|
|
128
158
|
const lookup_self = Symbol("lookup_self");
|
|
129
159
|
const lookup_map = Symbol("lookup_map");
|
|
130
160
|
const lookup_head = Symbol("lookup_head");
|
|
131
|
-
export const hoisted_lookupLinearMap = new IRHoisted(new IRFunc([lookup_key], new IRRecursive(lookup_self, new IRFunc([lookup_map],
|
|
161
|
+
export const hoisted_lookupLinearMap = new IRHoisted(new IRFunc([lookup_key], new IRRecursive(lookup_self, new IRFunc([lookup_map], _ir_caseList(new IRVar(lookup_map),
|
|
132
162
|
// case nil => None
|
|
133
163
|
new IRConstr(1, []),
|
|
134
164
|
// case cons
|
|
@@ -146,7 +176,11 @@ const mkFind_pred = Symbol("predicate");
|
|
|
146
176
|
const mkFind_self = Symbol("findOpt_self");
|
|
147
177
|
const mkFind_list = Symbol("list");
|
|
148
178
|
const mkFind_head = Symbol("head");
|
|
149
|
-
|
|
179
|
+
const mkFind_tail = Symbol("tail");
|
|
180
|
+
export const hoisted_mkFindDataOptional = new IRHoisted(new IRFunc([mkFind_elemToData, mkFind_pred], new IRRecursive(mkFind_self, new IRFunc([mkFind_list], new IRCase(new IRVar(mkFind_list), [
|
|
181
|
+
new IRFunc([mkFind_head, mkFind_tail], _ir_lazyIfThenElse(new IRApp(new IRVar(mkFind_pred), new IRVar(mkFind_head)), _ir_apps(IRNative.constrData, IRConst.int(0), new IRApp(new IRVar(mkFind_elemToData), new IRVar(mkFind_head))), new IRApp(new IRSelfCall(mkFind_self), new IRVar(mkFind_tail)))),
|
|
182
|
+
IRConst.data(new DataConstr(1, []))
|
|
183
|
+
])))));
|
|
150
184
|
hoisted_mkFindDataOptional.hash;
|
|
151
185
|
// hoisted strictAnd / strictOr
|
|
152
186
|
const strictAnd_a = Symbol("a");
|
|
@@ -161,7 +195,7 @@ hoisted_strictOr.hash;
|
|
|
161
195
|
const some_pred = Symbol("predicate");
|
|
162
196
|
const some_lst = Symbol("lst");
|
|
163
197
|
const some_self = Symbol("self");
|
|
164
|
-
export const hoisted_some = new IRHoisted(new IRFunc([some_pred], new IRRecursive(some_self, new IRFunc([some_lst],
|
|
198
|
+
export const hoisted_some = new IRHoisted(new IRFunc([some_pred], new IRRecursive(some_self, new IRFunc([some_lst], _ir_caseList(new IRVar(some_lst), IRConst.bool(false), // case nil => false
|
|
165
199
|
_ir_or(
|
|
166
200
|
// either predicate(head) is true
|
|
167
201
|
_ir_apps(new IRVar(some_pred), new IRApp(IRNative.headList, new IRVar(some_lst))),
|
|
@@ -172,7 +206,7 @@ hoisted_some.hash;
|
|
|
172
206
|
const every_pred = Symbol("predicate");
|
|
173
207
|
const every_self = Symbol("self");
|
|
174
208
|
const every_lst = Symbol("lst");
|
|
175
|
-
export const hoisted_every = new IRHoisted(new IRFunc([every_pred], new IRRecursive(every_self, new IRFunc([every_lst],
|
|
209
|
+
export const hoisted_every = new IRHoisted(new IRFunc([every_pred], new IRRecursive(every_self, new IRFunc([every_lst], _ir_caseList(new IRVar(every_lst), IRConst.bool(true), // case nil => true
|
|
176
210
|
_ir_and(
|
|
177
211
|
// both predicate(head) is true
|
|
178
212
|
_ir_apps(new IRVar(every_pred), new IRApp(IRNative.headList, new IRVar(every_lst))),
|
|
@@ -184,7 +218,7 @@ const filt_pred = Symbol("predicate");
|
|
|
184
218
|
const filt_self = Symbol("filter_self");
|
|
185
219
|
const filt_list = Symbol("list");
|
|
186
220
|
const filt_elem = Symbol("elem");
|
|
187
|
-
export const hoisted_filter = new IRHoisted(new IRFunc([filt_pred], new IRRecursive(filt_self, new IRFunc([filt_list],
|
|
221
|
+
export const hoisted_filter = new IRHoisted(new IRFunc([filt_pred], new IRRecursive(filt_self, new IRFunc([filt_list], _ir_caseList(new IRVar(filt_list),
|
|
188
222
|
// case nil
|
|
189
223
|
new IRVar(filt_list), // nil
|
|
190
224
|
// case cons
|
|
@@ -285,7 +319,7 @@ export function nativeToIR(native) {
|
|
|
285
319
|
case IRNativeTag._isZero: return hoisted_isZero.clone();
|
|
286
320
|
case IRNativeTag._sortedValueLovelaces: return hoisted_sortedValueLovelaces.clone();
|
|
287
321
|
case IRNativeTag._getCredentialsHash: return hoisted_getCredentialsHash.clone();
|
|
288
|
-
case IRNativeTag._dropList: return hoisted_dropList.clone();
|
|
322
|
+
// case IRNativeTag._dropList: return hoisted_dropList.clone();
|
|
289
323
|
case IRNativeTag._mkMapList: return hoisted_mkMapList.clone();
|
|
290
324
|
case IRNativeTag._increment: return hoisted_addOne.clone();
|
|
291
325
|
case IRNativeTag._decrement: return hoisted_subOne.clone();
|
|
@@ -295,6 +329,8 @@ export function nativeToIR(native) {
|
|
|
295
329
|
case IRNativeTag._mkEqualsList: return hoisted_mkEqualsList.clone();
|
|
296
330
|
case IRNativeTag._negateInt: return hoisted_negateInteger.clone();
|
|
297
331
|
case IRNativeTag._lookupLinearMap: return hoisted_lookupLinearMap.clone();
|
|
332
|
+
case IRNativeTag._negateValue: return hoisted_negateValue.clone();
|
|
333
|
+
case IRNativeTag._valueEq: return hoisted_valueEq.clone();
|
|
298
334
|
// case IRNativeTag._mkEqualsList: return hoisted_mkEqualsList.clone();
|
|
299
335
|
default:
|
|
300
336
|
throw new Error("unknown (negative) native calling 'nativeToIR'; " +
|
|
@@ -306,11 +342,11 @@ const eqList_eqFunc = Symbol("elemEq");
|
|
|
306
342
|
const eqList_self = Symbol("eqList_self");
|
|
307
343
|
const eqList_listA = Symbol("listA");
|
|
308
344
|
const eqList_listB = Symbol("listB");
|
|
309
|
-
export const hoisted_mkEqualsList = new IRHoisted(new IRFunc([eqList_eqFunc], new IRRecursive(eqList_self, new IRFunc([eqList_listA, eqList_listB],
|
|
345
|
+
export const hoisted_mkEqualsList = new IRHoisted(new IRFunc([eqList_eqFunc], new IRRecursive(eqList_self, new IRFunc([eqList_listA, eqList_listB], _ir_caseList(new IRVar(eqList_listA),
|
|
310
346
|
// case nil: check if listB is also nil
|
|
311
347
|
_ir_apps(IRNative.nullList, new IRVar(eqList_listB)),
|
|
312
348
|
// case cons
|
|
313
|
-
|
|
349
|
+
_ir_caseList(new IRVar(eqList_listB),
|
|
314
350
|
// listB is nil => false
|
|
315
351
|
IRConst.bool(false),
|
|
316
352
|
// both lists are cons
|
|
@@ -321,7 +357,7 @@ const mkMap_nil = Symbol("nilOfType");
|
|
|
321
357
|
const mkMap_mapFunc = Symbol("mapFunc");
|
|
322
358
|
const mkMap_map = Symbol("map_self");
|
|
323
359
|
const mkMap_list = Symbol("list");
|
|
324
|
-
export const hoisted_mkMapList = new IRHoisted(new IRFunc([mkMap_nil, mkMap_mapFunc], new IRRecursive(mkMap_map, new IRFunc([mkMap_list],
|
|
360
|
+
export const hoisted_mkMapList = new IRHoisted(new IRFunc([mkMap_nil, mkMap_mapFunc], new IRRecursive(mkMap_map, new IRFunc([mkMap_list], _ir_caseList(new IRVar(mkMap_list),
|
|
325
361
|
// case nil: return nil of type
|
|
326
362
|
new IRVar(mkMap_nil),
|
|
327
363
|
// case cons
|
|
@@ -348,28 +384,33 @@ const amount_tokenNameLoop = Symbol("tokenNameLoop_self");
|
|
|
348
384
|
const amount_tokenMap = Symbol("tokenMap");
|
|
349
385
|
export const hoisted_amountOfValue = new IRHoisted(new IRFunc([amount_isPolicy], // (policy => bool)
|
|
350
386
|
new IRRecursive(amount_policyLoop, new IRFunc([amount_value], // value
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
//
|
|
359
|
-
|
|
360
|
-
//
|
|
361
|
-
new
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
)
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
387
|
+
(() => {
|
|
388
|
+
const valHead = Symbol("valHead");
|
|
389
|
+
const valTail = Symbol("valTail");
|
|
390
|
+
const tokHead = Symbol("tokHead");
|
|
391
|
+
const tokTail = Symbol("tokTail");
|
|
392
|
+
return new IRCase(new IRVar(amount_value), [
|
|
393
|
+
new IRFunc([valHead, valTail], _ir_lazyIfThenElse(
|
|
394
|
+
// isPolicy( unBData( fst valHead ) )
|
|
395
|
+
_ir_apps(new IRVar(amount_isPolicy), _ir_apps(IRNative.unBData, _ir_apps(IRNative.fstPair, new IRVar(valHead)))),
|
|
396
|
+
// then: build (tokenName => amount)
|
|
397
|
+
new IRFunc([amount_isTokenName], _ir_apps(new IRRecursive(amount_tokenNameLoop, new IRFunc([amount_tokenMap], new IRCase(new IRVar(amount_tokenMap), [
|
|
398
|
+
new IRFunc([tokHead, tokTail], _ir_lazyIfThenElse(
|
|
399
|
+
// isTokenName( unBData( fst tokHead ) )
|
|
400
|
+
_ir_apps(new IRVar(amount_isTokenName), _ir_apps(IRNative.unBData, _ir_apps(IRNative.fstPair, new IRVar(tokHead)))),
|
|
401
|
+
// then: return amount
|
|
402
|
+
_ir_apps(IRNative.unIData, _ir_apps(IRNative.sndPair, new IRVar(tokHead))),
|
|
403
|
+
// else: recurse on tokTail
|
|
404
|
+
_ir_apps(new IRSelfCall(amount_tokenNameLoop), new IRVar(tokTail)))),
|
|
405
|
+
// token map empty => 0
|
|
406
|
+
IRConst.int(0)
|
|
407
|
+
]))),
|
|
408
|
+
// pass token map (unMapData( snd valHead ))
|
|
409
|
+
_ir_apps(IRNative.unMapData, _ir_apps(IRNative.sndPair, new IRVar(valHead))))),
|
|
410
|
+
// else: recurse policyLoop on valTail
|
|
411
|
+
_ir_apps(new IRSelfCall(amount_policyLoop), new IRVar(valTail)))),
|
|
412
|
+
// case nil: return (tokenName => 0)
|
|
413
|
+
new IRFunc([amount_isTokenName], IRConst.int(0))
|
|
414
|
+
]);
|
|
415
|
+
})()))));
|
|
375
416
|
hoisted_amountOfValue.hash;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `case L of cons h t -> body | nil -> ...` already binds the list's head
|
|
3
|
+
* and tail to `h` and `t` in the cons branch. If `body` then re-extracts
|
|
4
|
+
* them via `headList(L)` / `tailList(L)`, those calls are redundant — the
|
|
5
|
+
* values are already in scope. This pass walks every `IRCase` whose
|
|
6
|
+
* scrutinee is a plain `IRVar(L)` and substitutes those head/tail calls
|
|
7
|
+
* inside the cons branch with `IRVar(h)` / `IRVar(t)`.
|
|
8
|
+
*
|
|
9
|
+
* Concretely, this turns
|
|
10
|
+
*
|
|
11
|
+
* case body_xs of
|
|
12
|
+
* cons body_xs_head body_xs_tail ->
|
|
13
|
+
* ... headList(body_xs) ... tailList(body_xs) ...
|
|
14
|
+
*
|
|
15
|
+
* into
|
|
16
|
+
*
|
|
17
|
+
* case body_xs of
|
|
18
|
+
* cons body_xs_head body_xs_tail ->
|
|
19
|
+
* ... body_xs_head ... body_xs_tail ...
|
|
20
|
+
*
|
|
21
|
+
* which (combined with `removeUnusedVarsAndReturnRoot`) drops the
|
|
22
|
+
* `(force headList) body_xs` / `(force tailList) body_xs` builtin
|
|
23
|
+
* applications entirely when the originally-bound `h`/`t` were unused.
|
|
24
|
+
*
|
|
25
|
+
* Substitution stops at any nested `IRFunc`/`IRRecursive` whose params
|
|
26
|
+
* shadow `L`, `h`, or `t` — those re-bindings would otherwise let us
|
|
27
|
+
* silently substitute a stale outer scope.
|
|
28
|
+
*/
|
|
29
|
+
import { IRTerm } from "../../IRTerm.js";
|
|
30
|
+
export declare function rewriteHeadTailInCaseConsAndReturnRoot(term: IRTerm): IRTerm;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `case L of cons h t -> body | nil -> ...` already binds the list's head
|
|
3
|
+
* and tail to `h` and `t` in the cons branch. If `body` then re-extracts
|
|
4
|
+
* them via `headList(L)` / `tailList(L)`, those calls are redundant — the
|
|
5
|
+
* values are already in scope. This pass walks every `IRCase` whose
|
|
6
|
+
* scrutinee is a plain `IRVar(L)` and substitutes those head/tail calls
|
|
7
|
+
* inside the cons branch with `IRVar(h)` / `IRVar(t)`.
|
|
8
|
+
*
|
|
9
|
+
* Concretely, this turns
|
|
10
|
+
*
|
|
11
|
+
* case body_xs of
|
|
12
|
+
* cons body_xs_head body_xs_tail ->
|
|
13
|
+
* ... headList(body_xs) ... tailList(body_xs) ...
|
|
14
|
+
*
|
|
15
|
+
* into
|
|
16
|
+
*
|
|
17
|
+
* case body_xs of
|
|
18
|
+
* cons body_xs_head body_xs_tail ->
|
|
19
|
+
* ... body_xs_head ... body_xs_tail ...
|
|
20
|
+
*
|
|
21
|
+
* which (combined with `removeUnusedVarsAndReturnRoot`) drops the
|
|
22
|
+
* `(force headList) body_xs` / `(force tailList) body_xs` builtin
|
|
23
|
+
* applications entirely when the originally-bound `h`/`t` were unused.
|
|
24
|
+
*
|
|
25
|
+
* Substitution stops at any nested `IRFunc`/`IRRecursive` whose params
|
|
26
|
+
* shadow `L`, `h`, or `t` — those re-bindings would otherwise let us
|
|
27
|
+
* silently substitute a stale outer scope.
|
|
28
|
+
*/
|
|
29
|
+
import { IRApp } from "../../IRNodes/IRApp.js";
|
|
30
|
+
import { IRCase } from "../../IRNodes/IRCase.js";
|
|
31
|
+
import { IRFunc } from "../../IRNodes/IRFunc.js";
|
|
32
|
+
import { IRHoisted } from "../../IRNodes/IRHoisted.js";
|
|
33
|
+
import { IRLetted } from "../../IRNodes/IRLetted.js";
|
|
34
|
+
import { IRNative } from "../../IRNodes/IRNative/index.js";
|
|
35
|
+
import { IRNativeTag } from "../../IRNodes/IRNative/IRNativeTag.js";
|
|
36
|
+
import { IRRecursive } from "../../IRNodes/IRRecursive.js";
|
|
37
|
+
import { IRVar } from "../../IRNodes/IRVar.js";
|
|
38
|
+
import { _modifyChildFromTo } from "../_internal/_modifyChildFromTo.js";
|
|
39
|
+
function unwrap(t) {
|
|
40
|
+
while (t instanceof IRHoisted)
|
|
41
|
+
t = t.hoisted;
|
|
42
|
+
while (t instanceof IRLetted)
|
|
43
|
+
t = t.value;
|
|
44
|
+
return t;
|
|
45
|
+
}
|
|
46
|
+
export function rewriteHeadTailInCaseConsAndReturnRoot(term) {
|
|
47
|
+
const stack = [term];
|
|
48
|
+
while (stack.length > 0) {
|
|
49
|
+
const t = stack.pop();
|
|
50
|
+
if (t instanceof IRCase) {
|
|
51
|
+
const scrutinee = t.constrTerm;
|
|
52
|
+
const consBranch = t.continuations[0];
|
|
53
|
+
if (scrutinee instanceof IRVar
|
|
54
|
+
&& consBranch instanceof IRFunc
|
|
55
|
+
&& consBranch.params.length === 2) {
|
|
56
|
+
const listSym = scrutinee.name;
|
|
57
|
+
const [hSym, tSym] = consBranch.params;
|
|
58
|
+
substituteHeadTailInBody(consBranch.body, listSym, hSym, tSym);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
stack.push(...t.children());
|
|
62
|
+
}
|
|
63
|
+
return term;
|
|
64
|
+
}
|
|
65
|
+
function substituteHeadTailInBody(root, listSym, hSym, tSym) {
|
|
66
|
+
const stack = [root];
|
|
67
|
+
while (stack.length > 0) {
|
|
68
|
+
const t = stack.pop();
|
|
69
|
+
// Stop at a fresh binding that would shadow any of the symbols
|
|
70
|
+
// we're substituting for (extremely rare but cheap to guard).
|
|
71
|
+
if (t instanceof IRFunc || t instanceof IRRecursive) {
|
|
72
|
+
const params = t instanceof IRFunc ? t.params : [t.name];
|
|
73
|
+
if (params.includes(listSym)
|
|
74
|
+
|| params.includes(hSym)
|
|
75
|
+
|| params.includes(tSym))
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (t instanceof IRApp) {
|
|
79
|
+
const fn = unwrap(t.fn);
|
|
80
|
+
const arg = t.arg;
|
|
81
|
+
if (fn instanceof IRNative
|
|
82
|
+
&& (fn.tag === IRNativeTag.headList || fn.tag === IRNativeTag.tailList)
|
|
83
|
+
&& arg instanceof IRVar
|
|
84
|
+
&& arg.name === listSym) {
|
|
85
|
+
const newSym = fn.tag === IRNativeTag.headList ? hSym : tSym;
|
|
86
|
+
const parent = t.parent;
|
|
87
|
+
if (parent !== undefined) {
|
|
88
|
+
_modifyChildFromTo(parent, t, new IRVar(newSym));
|
|
89
|
+
}
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
stack.push(...t.children());
|
|
94
|
+
}
|
|
95
|
+
}
|