@harmoniclabs/pebble 0.2.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/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 +22 -2
- 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 +27 -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 +12 -0
- package/dist/IR/toUPLC/CompilerOptions.js +14 -9
- 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/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 +1 -0
- package/dist/compiler/AstCompiler/AstCompiler.js +41 -4
- package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +3 -3
- package/dist/compiler/AstCompiler/internal/exprs/_compileCallExpr.js +57 -10
- package/dist/compiler/AstCompiler/internal/exprs/_compileCaseExpr.js +31 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compileIsExpr.js +12 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +36 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compileUnaryPrefixExpr.js +13 -1
- 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/utils/getPropAccessReturnType.js +11 -0
- package/dist/compiler/Compiler.js +20 -27
- 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 +23 -8
- 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/TirFromDataExpr.js +102 -67
- package/dist/compiler/tir/expressions/TirIsExpr.js +14 -1
- package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +1 -2
- package/dist/compiler/tir/expressions/TirNativeFunc.js +2 -12
- package/dist/compiler/tir/expressions/TirToDataExpr.js +3 -0
- 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/stdScope/populateStdNamespace.js +49 -4
- package/dist/compiler/tir/program/stdScope/prelude/preludeTypesSrc.js +35 -2
- package/dist/compiler/tir/program/stdScope/stdScope.d.ts +7 -0
- package/dist/compiler/tir/program/stdScope/stdScope.js +83 -40
- 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 +4 -2
- package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +5 -0
- 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 +4 -1
- package/dist/compiler/tir/types/utils/canAssignTo.js +28 -0
- 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.js +4 -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.js +5 -0
- package/dist/diagnostics/diagnosticMessages.generated.d.ts +5 -0
- package/dist/diagnostics/diagnosticMessages.generated.js +10 -0
- package/dist/parser/Parser.js +29 -13
- package/dist/tokenizer/Token.d.ts +8 -7
- package/dist/tokenizer/Token.js +8 -7
- package/dist/tokenizer/utils/tokenFromKeyword.js +2 -0
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/package.json +3 -3
- package/dist/IR/tree_utils/_ir_lazyChooseList.d.ts +0 -3
- package/dist/IR/tree_utils/_ir_lazyChooseList.js +0 -7
|
@@ -5,6 +5,7 @@ import { TirLitFailExpr } from "../../tir/expressions/litteral/TirLitFailExpr.js
|
|
|
5
5
|
import { TirLitFalseExpr } from "../../tir/expressions/litteral/TirLitFalseExpr.js";
|
|
6
6
|
import { TirLitHexBytesExpr } from "../../tir/expressions/litteral/TirLitHexBytesExpr.js";
|
|
7
7
|
import { TirLitIntExpr } from "../../tir/expressions/litteral/TirLitIntExpr.js";
|
|
8
|
+
import { TirLitEnumMemberExpr } from "../../tir/expressions/litteral/TirLitEnumMemberExpr.js";
|
|
8
9
|
import { TirLitNamedObjExpr } from "../../tir/expressions/litteral/TirLitNamedObjExpr.js";
|
|
9
10
|
import { TirLitObjExpr } from "../../tir/expressions/litteral/TirLitObjExpr.js";
|
|
10
11
|
import { TirLitStrExpr } from "../../tir/expressions/litteral/TirLitStrExpr.js";
|
|
@@ -38,8 +39,9 @@ import { TirUnaryMinus } from "../../tir/expressions/unary/TirUnaryMinus.js";
|
|
|
38
39
|
import { TirUnaryPlus } from "../../tir/expressions/unary/TirUnaryPlus.js";
|
|
39
40
|
import { isTirUnaryPrefixExpr } from "../../tir/expressions/unary/TirUnaryPrefixExpr.js";
|
|
40
41
|
import { TirUnaryTilde } from "../../tir/expressions/unary/TirUnaryTilde.js";
|
|
41
|
-
import { bool_t, bytes_t, data_t, int_t,
|
|
42
|
+
import { bool_t, bytes_t, data_t, int_t, valueMapAmountOfName } from "../../tir/program/stdScope/stdScope.js";
|
|
42
43
|
import { IRNativeTag } from "../../../IR/IRNodes/IRNative/IRNativeTag.js";
|
|
44
|
+
import { currentCompilationCtx } from "../../../IR/CompilationCtx.js";
|
|
43
45
|
import { TirReturnStmt } from "../../tir/statements/TirReturnStmt.js";
|
|
44
46
|
import { TirArrayLikeDeconstr } from "../../tir/statements/TirVarDecl/TirArrayLikeDeconstr.js";
|
|
45
47
|
import { TirNamedDeconstructVarDecl } from "../../tir/statements/TirVarDecl/TirNamedDeconstructVarDecl.js";
|
|
@@ -76,6 +78,7 @@ export function expressifyVars(ctx, expr) {
|
|
|
76
78
|
|| expr instanceof TirLitThisExpr
|
|
77
79
|
|| expr instanceof TirLitStrExpr
|
|
78
80
|
|| expr instanceof TirLitIntExpr
|
|
81
|
+
|| expr instanceof TirLitEnumMemberExpr
|
|
79
82
|
|| expr instanceof TirLitHexBytesExpr
|
|
80
83
|
|| expr instanceof TirNativeFunc
|
|
81
84
|
// hoisted expressions are necessarily closed, so no external variables
|
|
@@ -266,6 +269,7 @@ function expressifyPropAccess(ctx, propAccessExpr) {
|
|
|
266
269
|
|| expr instanceof TirLitArrExpr
|
|
267
270
|
|| expr instanceof TirLitStrExpr
|
|
268
271
|
|| expr instanceof TirLitIntExpr
|
|
272
|
+
|| expr instanceof TirLitEnumMemberExpr
|
|
269
273
|
|| expr instanceof TirLitHexBytesExpr
|
|
270
274
|
|| expr instanceof TirNativeFunc
|
|
271
275
|
|| expr instanceof TirPropAccessExpr // `expressifyVars` is called recursively on the object before this check
|
|
@@ -372,6 +376,20 @@ function expressifyPropAccess(ctx, propAccessExpr) {
|
|
|
372
376
|
throw new Error(`Property '${prop}' does not exist on type '${objType.toString()}'`);
|
|
373
377
|
const fName = ctor.fields[fIdx].name;
|
|
374
378
|
const fType = ctor.fields[fIdx].type;
|
|
379
|
+
// Untagged data structs encode as `listData(fields)` rather than
|
|
380
|
+
// `constrData(0, fields)`. Field access lowers directly to
|
|
381
|
+
// `unIData (or _inlineFromData) <$> headList (dropList idx (unListData v))`
|
|
382
|
+
// — no case-rewrite needed, no constructor index to check.
|
|
383
|
+
if (objType instanceof TirDataStructType
|
|
384
|
+
&& objType.untagged) {
|
|
385
|
+
const fieldsListT = new TirListT(data_t);
|
|
386
|
+
return new TirFromDataExpr(new TirCallExpr(TirNativeFunc.headList(data_t), [
|
|
387
|
+
new TirCallExpr(TirNativeFunc.dropList(data_t), [
|
|
388
|
+
new TirLitIntExpr(BigInt(fIdx), propAccessExpr.range),
|
|
389
|
+
new TirCallExpr(TirNativeFunc.unListData, [expr], fieldsListT, propAccessExpr.range)
|
|
390
|
+
], fieldsListT, propAccessExpr.range)
|
|
391
|
+
], data_t, propAccessExpr.range), fType, propAccessExpr.range);
|
|
392
|
+
}
|
|
375
393
|
return new TirCaseExpr(expr, [
|
|
376
394
|
new TirCaseMatcher(new TirNamedDeconstructVarDecl(ctor.name, new Map([
|
|
377
395
|
[fName, new TirSimpleVarDecl(fName, fType, undefined, true, propAccessExpr.range)]
|
|
@@ -412,7 +430,7 @@ function expressifyMethodCall(ctx, methodCall) {
|
|
|
412
430
|
// fast-path: `Value.amountOf(policy, name)` compiles directly to
|
|
413
431
|
// `_amountOfValue(eqByteString(policy))(value)(eqByteString(name))`
|
|
414
432
|
// skipping the wrapper function indirection.
|
|
415
|
-
if (tirMethodName ===
|
|
433
|
+
if (tirMethodName === valueMapAmountOfName
|
|
416
434
|
&& methodCall.args.length === 2) {
|
|
417
435
|
const [policyArg, nameArg] = methodCall.args;
|
|
418
436
|
const bytesToBoolT = new TirFuncT([bytes_t], bool_t);
|
|
@@ -582,7 +600,8 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
|
|
|
582
600
|
throw new Error(`Argument 1 of method 'map' of type 'list' must be a function, got '${arg.type.toString()}'`);
|
|
583
601
|
const mapReturnT = argFuncType.returnType;
|
|
584
602
|
const elemTypeTirName = elemsType.toTirTypeKey();
|
|
585
|
-
|
|
603
|
+
const mapToTypeCache = currentCompilationCtx().mapToTypeCache;
|
|
604
|
+
let base_mapToType = mapToTypeCache.get(elemTypeTirName)?.clone();
|
|
586
605
|
if (!base_mapToType) {
|
|
587
606
|
base_mapToType = new TirHoistedExpr("_map_to_list_of_" + elemTypeTirName, new TirCallExpr(TirNativeFunc._mkMap(elemsType, mapReturnT), [new TirLitArrExpr([], new TirListT(mapReturnT), SourceRange.unknown)], new TirFuncT([
|
|
588
607
|
// mapping function
|
|
@@ -593,7 +612,7 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
|
|
|
593
612
|
new TirListT(elemsType)
|
|
594
613
|
], new TirListT(mapReturnT)), SourceRange.unknown));
|
|
595
614
|
base_mapToType.varName; // precompute hash and symbol
|
|
596
|
-
|
|
615
|
+
mapToTypeCache.set(elemTypeTirName, base_mapToType.clone());
|
|
597
616
|
}
|
|
598
617
|
return new TirCallExpr(base_mapToType, [methodCall.args[0], objectExpr], methodCall.type, exprRange);
|
|
599
618
|
}
|
|
@@ -605,7 +624,3 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
|
|
|
605
624
|
};
|
|
606
625
|
*/
|
|
607
626
|
}
|
|
608
|
-
const _base_mapToType_cache = new Map();
|
|
609
|
-
export function __unsafe_clear_mapToType_cache() {
|
|
610
|
-
_base_mapToType_cache.clear();
|
|
611
|
-
}
|
|
@@ -20,6 +20,15 @@ export declare class TirCaseExpr implements ITirExpr {
|
|
|
20
20
|
deps(): string[];
|
|
21
21
|
get isConstant(): boolean;
|
|
22
22
|
toIR(ctx: ToIRTermCtx): IRTerm;
|
|
23
|
+
/**
|
|
24
|
+
* Lowers a `case` over an untagged data struct (single constructor;
|
|
25
|
+
* runtime form is `listData(fields)`). No constructor dispatch is
|
|
26
|
+
* needed — there's only one possible ctor — so the lowering is just
|
|
27
|
+
* "find the matching arm (or wildcard), extract any bound fields, run
|
|
28
|
+
* the body".
|
|
29
|
+
*/
|
|
30
|
+
private _untaggedDataStructToIR;
|
|
31
|
+
private _enumToIR;
|
|
23
32
|
private _sopStructToIR;
|
|
24
33
|
private _dataStructToIR;
|
|
25
34
|
}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { IRApp, _ir_apps } from "../../../IR/IRNodes/IRApp.js";
|
|
2
2
|
import { IRCase } from "../../../IR/IRNodes/IRCase.js";
|
|
3
3
|
import { IRConst } from "../../../IR/IRNodes/IRConst.js";
|
|
4
|
-
import { IRDelayed } from "../../../IR/IRNodes/IRDelayed.js";
|
|
5
4
|
import { IRError } from "../../../IR/IRNodes/IRError.js";
|
|
6
5
|
import { IRFunc } from "../../../IR/IRNodes/IRFunc.js";
|
|
6
|
+
import { IRLetted } from "../../../IR/IRNodes/IRLetted.js";
|
|
7
7
|
import { IRNative } from "../../../IR/IRNodes/IRNative/index.js";
|
|
8
8
|
import { IRVar } from "../../../IR/IRNodes/IRVar.js";
|
|
9
|
-
import {
|
|
10
|
-
import { _ir_let, _ir_let_sym } from "../../../IR/tree_utils/_ir_let.js";
|
|
9
|
+
import { _ir_let_sym } from "../../../IR/tree_utils/_ir_let.js";
|
|
11
10
|
import { filterSortedStrArrInplace } from "../../../utils/array/filterSortedStrArrInplace.js";
|
|
12
11
|
import { mergeSortedStrArrInplace } from "../../../utils/array/mergeSortedStrArrInplace.js";
|
|
13
12
|
import { TirSimpleVarDecl } from "../statements/TirVarDecl/TirSimpleVarDecl.js";
|
|
14
13
|
import { TirDataOptT } from "../types/TirNativeType/native/Optional/data.js";
|
|
15
14
|
import { TirSopOptT } from "../types/TirNativeType/native/Optional/sop.js";
|
|
16
15
|
import { TirDataStructType, TirSoPStructType } from "../types/TirStructType.js";
|
|
17
|
-
import {
|
|
16
|
+
import { TirEnumType } from "../types/TirEnumType.js";
|
|
18
17
|
import { getUnaliased } from "../types/utils/getUnaliased.js";
|
|
19
18
|
import { _inlineFromData } from "./TirFromDataExpr.js";
|
|
20
19
|
export class TirCaseExpr {
|
|
@@ -73,13 +72,83 @@ export class TirCaseExpr {
|
|
|
73
72
|
if (matchExprType instanceof TirSoPStructType
|
|
74
73
|
|| matchExprType instanceof TirSopOptT)
|
|
75
74
|
return this._sopStructToIR(matchExprType, ctx);
|
|
75
|
+
if (matchExprType instanceof TirDataStructType
|
|
76
|
+
&& matchExprType.untagged)
|
|
77
|
+
return this._untaggedDataStructToIR(matchExprType, ctx);
|
|
76
78
|
if (matchExprType instanceof TirDataStructType
|
|
77
79
|
|| matchExprType instanceof TirDataOptT)
|
|
78
80
|
return this._dataStructToIR(matchExprType, ctx);
|
|
81
|
+
if (matchExprType instanceof TirEnumType)
|
|
82
|
+
return this._enumToIR(matchExprType, ctx);
|
|
79
83
|
console.error(this);
|
|
80
84
|
throw new Error("`case` expressions are only supported on Sum-of-Products or Data Struct types; got: "
|
|
81
85
|
+ this.matchExpr.type.toString());
|
|
82
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Lowers a `case` over an untagged data struct (single constructor;
|
|
89
|
+
* runtime form is `listData(fields)`). No constructor dispatch is
|
|
90
|
+
* needed — there's only one possible ctor — so the lowering is just
|
|
91
|
+
* "find the matching arm (or wildcard), extract any bound fields, run
|
|
92
|
+
* the body".
|
|
93
|
+
*/
|
|
94
|
+
_untaggedDataStructToIR(matchExprType, ctx) {
|
|
95
|
+
if (matchExprType.constructors.length !== 1) {
|
|
96
|
+
throw new Error("untagged data struct must have exactly one constructor");
|
|
97
|
+
}
|
|
98
|
+
const ctor = matchExprType.constructors[0];
|
|
99
|
+
const wildcardBodyIR = this.wildcardCase?.body.toIR(ctx) ?? new IRError();
|
|
100
|
+
const matchedArm = this.cases.find(c => c.pattern.constrName === ctor.name);
|
|
101
|
+
if (!matchedArm) {
|
|
102
|
+
// no matching arm: just run the wildcard body (the scrutinee is
|
|
103
|
+
// evaluated for side-effects via `unListData` only if any field
|
|
104
|
+
// would have been bound; here, nothing).
|
|
105
|
+
return wildcardBodyIR;
|
|
106
|
+
}
|
|
107
|
+
const pattern = matchedArm.pattern;
|
|
108
|
+
const usedFields = ctor.fields
|
|
109
|
+
.map((f, idx) => ({ name: f.name, type: f.type, idx }))
|
|
110
|
+
.filter(f => pattern.fields.has(f.name));
|
|
111
|
+
// 0 bound fields → just run the body; no extraction.
|
|
112
|
+
if (usedFields.length === 0)
|
|
113
|
+
return matchedArm.body.toIR(ctx);
|
|
114
|
+
// fields-list = unListData(scrutinee), bound once and reused via
|
|
115
|
+
// IRLetted so the let-handling pass elides or shares as appropriate.
|
|
116
|
+
const fieldsListLetted = new IRLetted(Symbol("untaggedFields"), _ir_apps(IRNative.unListData, this.matchExpr.toIR(ctx)));
|
|
117
|
+
const branchCtx = ctx.newChild();
|
|
118
|
+
// bind each used field with a let in declaration order.
|
|
119
|
+
// sort by ctor field index so earlier extractions don't need to
|
|
120
|
+
// re-drop past already-bound fields.
|
|
121
|
+
usedFields.sort((a, b) => a.idx - b.idx);
|
|
122
|
+
const bindings = usedFields.map(f => {
|
|
123
|
+
const varDecl = pattern.fields.get(f.name);
|
|
124
|
+
if (!(varDecl instanceof TirSimpleVarDecl))
|
|
125
|
+
throw new Error("case pattern not expressified.");
|
|
126
|
+
const sym = branchCtx.defineVar(varDecl.name);
|
|
127
|
+
return {
|
|
128
|
+
sym,
|
|
129
|
+
extract: _inlineFromData(f.type, _ir_apps(IRNative.headList, _ir_apps(IRNative.dropList, IRConst.int(f.idx), fieldsListLetted.clone())))
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
// build nested let-bindings around the body
|
|
133
|
+
let result = matchedArm.body.toIR(branchCtx);
|
|
134
|
+
for (let i = bindings.length - 1; i >= 0; i--) {
|
|
135
|
+
const { sym, extract } = bindings[i];
|
|
136
|
+
result = _ir_let_sym(sym, extract, result);
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
_enumToIR(enumType, ctx) {
|
|
141
|
+
const wildcardBodyIR = this.wildcardCase?.body.toIR(ctx) ?? new IRError();
|
|
142
|
+
const branches = enumType.members.map(memberName => {
|
|
143
|
+
const branch = this.cases.find(c => c.pattern.constrName === memberName);
|
|
144
|
+
return branch ? branch.body.toIR(ctx) : wildcardBodyIR;
|
|
145
|
+
});
|
|
146
|
+
while (branches.length > 0 && branches[branches.length - 1] instanceof IRError)
|
|
147
|
+
branches.pop();
|
|
148
|
+
return branches.length > 0
|
|
149
|
+
? new IRCase(this.matchExpr.toIR(ctx), branches)
|
|
150
|
+
: new IRError();
|
|
151
|
+
}
|
|
83
152
|
_sopStructToIR(matchExprType, ctx) {
|
|
84
153
|
if (matchExprType instanceof TirSopOptT) {
|
|
85
154
|
const wildcardBodyIR = this.wildcardCase?.body.toIR(ctx) ?? new IRError();
|
|
@@ -172,134 +241,87 @@ export class TirCaseExpr {
|
|
|
172
241
|
return branches.length > 0 ? new IRCase(this.matchExpr.toIR(ctx), branches) : new IRError(); // all branches fail, so the whole expression fails
|
|
173
242
|
}
|
|
174
243
|
_dataStructToIR(matchExprType, ctx) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
)),
|
|
197
|
-
// then Just{ value }
|
|
198
|
-
someBranchIR(unConstrMatchSym),
|
|
199
|
-
// else None
|
|
200
|
-
noneBranchIR));
|
|
201
|
-
}
|
|
202
|
-
// TirDataStructType
|
|
203
|
-
const stmtCtx = ctx.newChild();
|
|
204
|
-
const unConstrStructSym = stmtCtx.pushUnusedVar("unconstrStruct"); // unconstrStruct
|
|
205
|
-
const isConstrIdxSym = stmtCtx.pushUnusedVar("isConstrIdx"); // isConstrIdx
|
|
206
|
-
const noVarsWildcardBodyIR = (this.wildcardCase?.body.toIR(stmtCtx)
|
|
207
|
-
?? new IRError());
|
|
208
|
-
const delayedNoVarWildcardBodyIR = new IRDelayed(noVarsWildcardBodyIR);
|
|
209
|
-
let ifThenElseMatchingStatements = noVarsWildcardBodyIR;
|
|
244
|
+
// TirDataOptT extends TirDataStructType (constructors Some{value}, None{}),
|
|
245
|
+
// so the same logic handles it.
|
|
246
|
+
//
|
|
247
|
+
// Lowering structure (UPLC `Case` accepts pair / int scrutinees
|
|
248
|
+
// as untagged constructors):
|
|
249
|
+
//
|
|
250
|
+
// Case (unConstrData scrutinee) [
|
|
251
|
+
// \idxSym fieldsSym ->
|
|
252
|
+
// Case idxSym [body_0, body_1, ..., body_(maxParent)]
|
|
253
|
+
// ]
|
|
254
|
+
//
|
|
255
|
+
// - The outer `Case` over the `pair(int, list<data>)` returned by
|
|
256
|
+
// `unConstrData` extracts both halves via a single 2-arg branch
|
|
257
|
+
// (pair is treated as `constr 0 [fst, snd]`).
|
|
258
|
+
// - The inner `Case` over `idxSym` dispatches by tag in O(1) —
|
|
259
|
+
// no `equalsInteger` chain, no `lazyIfThenElse`.
|
|
260
|
+
// - Each inner branch takes 0 args (an int N is treated as
|
|
261
|
+
// `constr N []`). The branch body extracts fields lazily from
|
|
262
|
+
// `fieldsSym` via deferred access on `thenCtx`, wrapped in
|
|
263
|
+
// `IRLetted` so the letted-handling pass dedups, inlines or
|
|
264
|
+
// elides as appropriate.
|
|
210
265
|
if (this.cases.some(({ pattern }) => matchExprType.constructors.findIndex(ctor => ctor.name === pattern.constrName) < 0))
|
|
211
266
|
throw new Error("case expression includes unknown constructor.");
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
267
|
+
const stmtCtx = ctx.newChild();
|
|
268
|
+
const wildcardBodyIR = this.wildcardCase?.body.toIR(stmtCtx) ?? new IRError();
|
|
269
|
+
// outer destructuring binders — symbols allocated up-front so
|
|
270
|
+
// per-arm deferred accesses (closures) reference the same syms
|
|
271
|
+
const idxSym = Symbol("ctorIdx");
|
|
272
|
+
const fieldsListSym = Symbol("fieldsList");
|
|
273
|
+
// The runtime value's ctor tag spans all parent indices known to
|
|
274
|
+
// this type — not just the indices that appear as arm patterns.
|
|
275
|
+
// Size the inner-Case branch array to cover all of them and fill
|
|
276
|
+
// missing slots with the wildcard.
|
|
277
|
+
const armsByParentIdx = new Map();
|
|
278
|
+
// TirDataOptT extends TirDataStructType, so both have parentCtorIdx
|
|
279
|
+
const allParentIdxs = matchExprType.constructors.map((_, i) => matchExprType.parentCtorIdx(i));
|
|
280
|
+
let maxParentIdx = allParentIdxs.reduce((m, x) => x > m ? x : m, -1);
|
|
281
|
+
for (const matchCase of this.cases) {
|
|
282
|
+
const { pattern, body } = matchCase;
|
|
219
283
|
const ctorIdx = matchExprType.constructors.findIndex(ctor => ctor.name === pattern.constrName);
|
|
220
|
-
if (ctorIdx < 0)
|
|
221
|
-
throw new Error("case expression includes unknown constructor."); // unreachable
|
|
222
284
|
const ctor = matchExprType.constructors[ctorIdx];
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
body.toIR(stmtCtx),
|
|
235
|
-
// else
|
|
236
|
-
ifThenElseMatchingStatements);
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
function indexOfField(fieldName) {
|
|
240
|
-
const idx = ctor.fields.findIndex(f => f.name === fieldName);
|
|
241
|
-
if (idx < 0)
|
|
242
|
-
throw new Error("case pattern not expressified.");
|
|
243
|
-
return idx;
|
|
244
|
-
}
|
|
245
|
-
if (usedFieldsCtorNames.length === 1) {
|
|
246
|
-
const thenCtx = stmtCtx.newChild();
|
|
247
|
-
const fName = usedFieldsCtorNames[0];
|
|
285
|
+
const parentCtorIdx = matchExprType instanceof TirDataStructType
|
|
286
|
+
? matchExprType.parentCtorIdx(ctorIdx)
|
|
287
|
+
: ctorIdx;
|
|
288
|
+
// bind each pattern-named field as a deferred access on
|
|
289
|
+
// `fieldsListSym`. Each access produces an `IRLetted`
|
|
290
|
+
// wrapping `_inlineFromData(type, headList(_dropList(idx, fields)))`.
|
|
291
|
+
const armCtx = stmtCtx.newChild();
|
|
292
|
+
const usedFieldsCtorNames = ctor.fields
|
|
293
|
+
.map(f => f.name)
|
|
294
|
+
.filter(fName => pattern.fields.has(fName));
|
|
295
|
+
for (const fName of usedFieldsCtorNames) {
|
|
248
296
|
const patternVarDecl = pattern.fields.get(fName);
|
|
249
297
|
if (!(patternVarDecl instanceof TirSimpleVarDecl))
|
|
250
298
|
throw new Error("case pattern not expressified.");
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
_ir_apps(// fileds as data list
|
|
254
|
-
IRNative.sndPair, new IRVar(unConstrStructSym) // unconstrStruct
|
|
255
|
-
)))), body.toIR(thenCtx));
|
|
256
|
-
ifThenElseMatchingStatements = _ir_lazyIfThenElse(
|
|
257
|
-
// condition (compare against the PARENT ctor index — the
|
|
258
|
-
// value's runtime tag is unaffected by narrowing)
|
|
259
|
-
_ir_apps(new IRVar(isConstrIdxSym), // isConstrIdx
|
|
260
|
-
IRConst.int(matchExprType instanceof TirDataStructType
|
|
261
|
-
? matchExprType.parentCtorIdx(ctorIdx)
|
|
262
|
-
: ctorIdx)),
|
|
263
|
-
// then
|
|
264
|
-
thenCase,
|
|
265
|
-
// else
|
|
266
|
-
ifThenElseMatchingStatements);
|
|
267
|
-
continue;
|
|
268
|
-
} // single field used edge case
|
|
269
|
-
// multiple fields used
|
|
270
|
-
const thenCtx = stmtCtx.newChild();
|
|
271
|
-
const fieldsAsDataList = thenCtx.pushUnusedVar(); // fileds as data list
|
|
272
|
-
const sortedUsedFields = [...usedFieldsCtorNames].sort((a, b) => indexOfField(a) - indexOfField(b));
|
|
273
|
-
const introducedVars = new Array(sortedUsedFields.length);
|
|
274
|
-
for (let fIdx = 0; fIdx < sortedUsedFields.length; fIdx++) {
|
|
275
|
-
const fName = sortedUsedFields[fIdx];
|
|
276
|
-
const patternVarDecl = pattern.fields.get(fName);
|
|
277
|
-
if (!(patternVarDecl instanceof TirSimpleVarDecl))
|
|
299
|
+
const fieldIdx = ctor.fields.findIndex(f => f.name === fName);
|
|
300
|
+
if (fieldIdx < 0)
|
|
278
301
|
throw new Error("case pattern not expressified.");
|
|
279
|
-
|
|
302
|
+
const fieldType = patternVarDecl.type;
|
|
303
|
+
armCtx.defineDeferredAccess(patternVarDecl.name, () => new IRLetted(Symbol(`${ctor.name}_${fName}`), _inlineFromData(fieldType, _ir_apps(IRNative.headList, _ir_apps(IRNative.dropList, IRConst.int(fieldIdx), new IRVar(fieldsListSym))))));
|
|
280
304
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
// condition (compare against the PARENT ctor index — the
|
|
289
|
-
// value's runtime tag is unaffected by narrowing)
|
|
290
|
-
_ir_apps(new IRVar(isConstrIdxSym), // isConstrIdx
|
|
291
|
-
IRConst.int(matchExprType instanceof TirDataStructType
|
|
292
|
-
? matchExprType.parentCtorIdx(ctorIdx)
|
|
293
|
-
: ctorIdx)),
|
|
294
|
-
// then
|
|
295
|
-
thenCase,
|
|
296
|
-
// else
|
|
297
|
-
ifThenElseMatchingStatements);
|
|
305
|
+
armsByParentIdx.set(parentCtorIdx, body.toIR(armCtx));
|
|
306
|
+
}
|
|
307
|
+
// build inner-Case branches sized to `maxParentIdx + 1`, filling
|
|
308
|
+
// missing slots with the wildcard body
|
|
309
|
+
const innerBranches = new Array(maxParentIdx + 1);
|
|
310
|
+
for (let i = 0; i < innerBranches.length; i++) {
|
|
311
|
+
innerBranches[i] = armsByParentIdx.get(i) ?? wildcardBodyIR;
|
|
298
312
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
313
|
+
// trailing `IRError` branches can be omitted — the CEK machine
|
|
314
|
+
// fails naturally if no branch exists for the runtime tag
|
|
315
|
+
while (innerBranches.length > 0
|
|
316
|
+
&& innerBranches[innerBranches.length - 1] instanceof IRError)
|
|
317
|
+
innerBranches.pop();
|
|
318
|
+
const innerCase = innerBranches.length > 0
|
|
319
|
+
? new IRCase(new IRVar(idxSym), innerBranches)
|
|
320
|
+
: new IRError();
|
|
321
|
+
// outer Case over the pair: single branch destructures (idx, fields)
|
|
322
|
+
return new IRCase(_ir_apps(IRNative.unConstrData, this.matchExpr.toIR(ctx)), [
|
|
323
|
+
new IRFunc([idxSym, fieldsListSym], innerCase)
|
|
324
|
+
]);
|
|
303
325
|
}
|
|
304
326
|
}
|
|
305
327
|
export class TirCaseMatcher {
|
|
@@ -44,8 +44,8 @@ export class TirElemAccessExpr {
|
|
|
44
44
|
const result = Machine.evalSimple(compileIRToUPLC(irIndex));
|
|
45
45
|
if ((result instanceof CEKConst)
|
|
46
46
|
&& (typeof result.value === "number" || typeof result.value === "bigint"))
|
|
47
|
-
return _ir_apps(IRNative.headList, _ir_apps(IRNative.
|
|
47
|
+
return _ir_apps(IRNative.headList, _ir_apps(IRNative.dropList, IRConst.int(result.value), irArr));
|
|
48
48
|
}
|
|
49
|
-
return _ir_apps(IRNative.headList, _ir_apps(IRNative.
|
|
49
|
+
return _ir_apps(IRNative.headList, _ir_apps(IRNative.dropList, irIndex, irArr));
|
|
50
50
|
}
|
|
51
51
|
}
|