@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.
Files changed (182) hide show
  1. package/dist/IR/CompilationCtx.d.ts +40 -0
  2. package/dist/IR/CompilationCtx.js +54 -0
  3. package/dist/IR/IRHash.d.ts +23 -2
  4. package/dist/IR/IRHash.js +10 -60
  5. package/dist/IR/IRNodes/IRConst.js +35 -4
  6. package/dist/IR/IRNodes/IRHoisted.d.ts +0 -1
  7. package/dist/IR/IRNodes/IRHoisted.js +4 -6
  8. package/dist/IR/IRNodes/IRLetted.d.ts +0 -1
  9. package/dist/IR/IRNodes/IRLetted.js +4 -6
  10. package/dist/IR/IRNodes/IRNative/IRNativeTag.d.ts +22 -2
  11. package/dist/IR/IRNodes/IRNative/IRNativeTag.js +26 -2
  12. package/dist/IR/IRNodes/IRNative/index.d.ts +16 -1
  13. package/dist/IR/IRNodes/IRNative/index.js +31 -2
  14. package/dist/IR/IRNodes/utils/hashVarSym.d.ts +0 -1
  15. package/dist/IR/IRNodes/utils/hashVarSym.js +27 -33
  16. package/dist/IR/toUPLC/CompilerOptions.d.ts +34 -7
  17. package/dist/IR/toUPLC/CompilerOptions.js +19 -10
  18. package/dist/IR/toUPLC/compileIRToUPLC.js +39 -3
  19. package/dist/IR/toUPLC/subRoutines/inlineSingleUseLetBindingsAndReturnRoot.d.ts +23 -0
  20. package/dist/IR/toUPLC/subRoutines/inlineSingleUseLetBindingsAndReturnRoot.js +263 -0
  21. package/dist/IR/toUPLC/subRoutines/introduceCaseForDualHeadTailAndReturnRoot.d.ts +35 -0
  22. package/dist/IR/toUPLC/subRoutines/introduceCaseForDualHeadTailAndReturnRoot.js +169 -0
  23. package/dist/IR/toUPLC/subRoutines/replaceHoistedWithLetted.d.ts +0 -1
  24. package/dist/IR/toUPLC/subRoutines/replaceHoistedWithLetted.js +6 -6
  25. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.d.ts +2 -3
  26. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.js +106 -65
  27. package/dist/IR/toUPLC/subRoutines/rewriteHeadTailInCaseConsAndReturnRoot.d.ts +30 -0
  28. package/dist/IR/toUPLC/subRoutines/rewriteHeadTailInCaseConsAndReturnRoot.js +95 -0
  29. package/dist/IR/toUPLC/subRoutines/rewriteNativesAppliedToConstantsAndReturnRoot.js +36 -5
  30. package/dist/IR/toUPLC/subRoutines/rewriteToCaseOverConstAndReturnRoot.d.ts +35 -0
  31. package/dist/IR/toUPLC/subRoutines/rewriteToCaseOverConstAndReturnRoot.js +169 -0
  32. package/dist/IR/tree_utils/_ir_caseList.d.ts +15 -0
  33. package/dist/IR/tree_utils/_ir_caseList.js +19 -0
  34. package/dist/IR/tree_utils/bytesToHex.d.ts +8 -0
  35. package/dist/IR/tree_utils/bytesToHex.js +69 -0
  36. package/dist/ast/nodes/expr/functions/FuncExpr.d.ts +16 -2
  37. package/dist/ast/nodes/expr/functions/FuncExpr.js +17 -0
  38. package/dist/ast/nodes/expr/litteral/LitteralExpr.d.ts +2 -1
  39. package/dist/ast/nodes/expr/litteral/LitteralExpr.js +2 -0
  40. package/dist/ast/nodes/expr/litteral/TemplateStrExpr.d.ts +30 -0
  41. package/dist/ast/nodes/expr/litteral/TemplateStrExpr.js +35 -0
  42. package/dist/ast/nodes/statements/ExportStmt.d.ts +3 -3
  43. package/dist/ast/nodes/statements/PebbleStmt.d.ts +4 -3
  44. package/dist/ast/nodes/statements/PebbleStmt.js +6 -2
  45. package/dist/ast/nodes/statements/TestParam.d.ts +18 -0
  46. package/dist/ast/nodes/statements/TestParam.js +18 -0
  47. package/dist/ast/nodes/statements/TestStmt.d.ts +5 -3
  48. package/dist/ast/nodes/statements/TestStmt.js +3 -1
  49. package/dist/ast/nodes/statements/UsingStmt.d.ts +32 -2
  50. package/dist/ast/nodes/statements/UsingStmt.js +39 -3
  51. package/dist/ast/nodes/statements/declarations/NamespaceDecl.d.ts +21 -0
  52. package/dist/ast/nodes/statements/declarations/NamespaceDecl.js +31 -0
  53. package/dist/ast/nodes/statements/declarations/StructDecl.d.ts +16 -2
  54. package/dist/ast/nodes/statements/declarations/StructDecl.js +15 -1
  55. package/dist/compiler/AstCompiler/AstCompiler.d.ts +27 -0
  56. package/dist/compiler/AstCompiler/AstCompiler.js +244 -7
  57. package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +16 -5
  58. package/dist/compiler/AstCompiler/internal/exprs/_compileCallExpr.js +97 -6
  59. package/dist/compiler/AstCompiler/internal/exprs/_compileCaseExpr.js +31 -0
  60. package/dist/compiler/AstCompiler/internal/exprs/_compileFuncExpr.js +12 -5
  61. package/dist/compiler/AstCompiler/internal/exprs/_compileIsExpr.js +12 -0
  62. package/dist/compiler/AstCompiler/internal/exprs/_compileLitteralExpr.js +59 -0
  63. package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.d.ts +2 -3
  64. package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +64 -0
  65. package/dist/compiler/AstCompiler/internal/exprs/_compileUnaryPrefixExpr.js +13 -1
  66. package/dist/compiler/AstCompiler/internal/exprs/_compileVarAccessExpr.js +2 -0
  67. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileAddExpr.js +18 -5
  68. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileEqualExpr.js +3 -1
  69. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanEqualExpr.js +2 -1
  70. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanExpr.js +2 -1
  71. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanEqualExpr.js +2 -1
  72. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanExpr.js +2 -1
  73. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileMultExpr.js +24 -6
  74. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileNotEqualExpr.js +2 -1
  75. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileSubExpr.js +16 -5
  76. package/dist/compiler/AstCompiler/internal/statements/_compileMatchStmt.js +33 -20
  77. package/dist/compiler/AstCompiler/internal/statements/_compileStatement.js +4 -1
  78. package/dist/compiler/AstCompiler/internal/statements/_compileTestStmt.d.ts +15 -1
  79. package/dist/compiler/AstCompiler/internal/statements/_compileTestStmt.js +70 -30
  80. package/dist/compiler/AstCompiler/internal/statements/_compileUsingAliasStmt.d.ts +11 -0
  81. package/dist/compiler/AstCompiler/internal/statements/_compileUsingAliasStmt.js +26 -0
  82. package/dist/compiler/AstCompiler/internal/statements/_compileUsingStmt.d.ts +9 -4
  83. package/dist/compiler/AstCompiler/internal/statements/_compileUsingStmt.js +51 -10
  84. package/dist/compiler/AstCompiler/internal/types/_compileDataEncodedConcreteType.js +21 -2
  85. package/dist/compiler/AstCompiler/internal/types/_compileSopEncodedConcreteType.js +17 -2
  86. package/dist/compiler/AstCompiler/scope/AstScope.d.ts +70 -1
  87. package/dist/compiler/AstCompiler/scope/AstScope.js +91 -0
  88. package/dist/compiler/AstCompiler/utils/getPropAccessReturnType.js +36 -1
  89. package/dist/compiler/AstCompiler/utils/monomorphizeGeneric.d.ts +36 -0
  90. package/dist/compiler/AstCompiler/utils/monomorphizeGeneric.js +123 -0
  91. package/dist/compiler/AstCompiler/utils/resolveNamespaceChain.d.ts +28 -0
  92. package/dist/compiler/AstCompiler/utils/resolveNamespaceChain.js +95 -0
  93. package/dist/compiler/AstCompiler/utils/resolveNamespacePath.d.ts +37 -0
  94. package/dist/compiler/AstCompiler/utils/resolveNamespacePath.js +93 -0
  95. package/dist/compiler/Compiler.d.ts +9 -1
  96. package/dist/compiler/Compiler.js +218 -30
  97. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +1 -1
  98. package/dist/compiler/TirCompiler/expressify/expressify.js +30 -2
  99. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.d.ts +2 -1
  100. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +45 -7
  101. package/dist/compiler/TirCompiler/expressify/expressifyVars.d.ts +0 -1
  102. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +49 -15
  103. package/dist/compiler/test/TestResult.d.ts +38 -0
  104. package/dist/compiler/test/TestResult.js +6 -0
  105. package/dist/compiler/test/fuzz/PRNG.d.ts +26 -0
  106. package/dist/compiler/test/fuzz/PRNG.js +59 -0
  107. package/dist/compiler/tir/expressions/TirCaseExpr.d.ts +9 -0
  108. package/dist/compiler/tir/expressions/TirCaseExpr.js +144 -122
  109. package/dist/compiler/tir/expressions/TirElemAccessExpr.js +2 -2
  110. package/dist/compiler/tir/expressions/TirExpr.d.ts +2 -1
  111. package/dist/compiler/tir/expressions/TirExpr.js +2 -0
  112. package/dist/compiler/tir/expressions/TirFromDataExpr.js +102 -67
  113. package/dist/compiler/tir/expressions/TirIsExpr.js +14 -1
  114. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +18 -2
  115. package/dist/compiler/tir/expressions/TirNativeFunc.js +55 -118
  116. package/dist/compiler/tir/expressions/TirShowExpr.d.ts +52 -0
  117. package/dist/compiler/tir/expressions/TirShowExpr.js +199 -0
  118. package/dist/compiler/tir/expressions/TirToDataExpr.js +3 -0
  119. package/dist/compiler/tir/expressions/TirTraceExpr.js +11 -7
  120. package/dist/compiler/tir/expressions/TirTypeConversionExpr.js +10 -0
  121. package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +2 -3
  122. package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +1 -4
  123. package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +20 -3
  124. package/dist/compiler/tir/expressions/ToIRTermCtx.js +48 -3
  125. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +2 -2
  126. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +45 -8
  127. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.d.ts +19 -0
  128. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.js +24 -0
  129. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.d.ts +2 -1
  130. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.js +2 -0
  131. package/dist/compiler/tir/expressions/unary/TirUnaryMinus.js +4 -1
  132. package/dist/compiler/tir/program/TypedProgram.d.ts +101 -0
  133. package/dist/compiler/tir/program/TypedProgram.js +43 -0
  134. package/dist/compiler/tir/program/stdScope/populateBuiltinInterfaces.d.ts +17 -0
  135. package/dist/compiler/tir/program/stdScope/populateBuiltinInterfaces.js +70 -0
  136. package/dist/compiler/tir/program/stdScope/populateStdNamespace.d.ts +22 -0
  137. package/dist/compiler/tir/program/stdScope/populateStdNamespace.js +619 -0
  138. package/dist/compiler/tir/program/stdScope/prelude/preludeTypesSrc.js +35 -2
  139. package/dist/compiler/tir/program/stdScope/stdScope.d.ts +8 -0
  140. package/dist/compiler/tir/program/stdScope/stdScope.js +84 -41
  141. package/dist/compiler/tir/statements/TirStmt.js +0 -1
  142. package/dist/compiler/tir/statements/TirTestStmt.d.ts +46 -0
  143. package/dist/compiler/tir/statements/TirTestStmt.js +35 -0
  144. package/dist/compiler/tir/types/TirEnumType.d.ts +21 -0
  145. package/dist/compiler/tir/types/TirEnumType.js +36 -0
  146. package/dist/compiler/tir/types/TirNativeType/TirNativeType.d.ts +53 -2
  147. package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +58 -1
  148. package/dist/compiler/tir/types/TirNativeType/native/array.d.ts +16 -0
  149. package/dist/compiler/tir/types/TirNativeType/native/array.js +38 -0
  150. package/dist/compiler/tir/types/TirNativeType/native/index.d.ts +2 -0
  151. package/dist/compiler/tir/types/TirNativeType/native/index.js +2 -0
  152. package/dist/compiler/tir/types/TirNativeType/native/value.d.ts +18 -0
  153. package/dist/compiler/tir/types/TirNativeType/native/value.js +17 -0
  154. package/dist/compiler/tir/types/TirStructType.js +6 -1
  155. package/dist/compiler/tir/types/TirType.d.ts +3 -2
  156. package/dist/compiler/tir/types/TirType.js +7 -2
  157. package/dist/compiler/tir/types/utils/canAssignTo.js +36 -1
  158. package/dist/compiler/tir/types/utils/canCastTo.js +14 -1
  159. package/dist/compiler/tir/types/utils/getDeconstructableType.d.ts +2 -1
  160. package/dist/compiler/tir/types/utils/getDeconstructableType.js +2 -0
  161. package/dist/compiler/tir/types/utils/inferTypeArgs.d.ts +19 -0
  162. package/dist/compiler/tir/types/utils/inferTypeArgs.js +83 -0
  163. package/dist/compiler/tir/types/utils/normalizeEnumToInt.d.ts +10 -0
  164. package/dist/compiler/tir/types/utils/normalizeEnumToInt.js +17 -0
  165. package/dist/compiler/tir/types/utils/substituteTypeParams.d.ts +9 -0
  166. package/dist/compiler/tir/types/utils/substituteTypeParams.js +67 -0
  167. package/dist/diagnostics/diagnosticMessages.generated.d.ts +10 -0
  168. package/dist/diagnostics/diagnosticMessages.generated.js +20 -0
  169. package/dist/index.d.ts +2 -0
  170. package/dist/index.js +2 -0
  171. package/dist/parser/Parser.d.ts +73 -3
  172. package/dist/parser/Parser.js +362 -46
  173. package/dist/tokenizer/Token.d.ts +106 -102
  174. package/dist/tokenizer/Token.js +111 -109
  175. package/dist/tokenizer/utils/tokenFromKeyword.js +11 -6
  176. package/dist/utils/semverSatisfies.d.ts +1 -0
  177. package/dist/utils/semverSatisfies.js +161 -0
  178. package/dist/version.generated.d.ts +1 -0
  179. package/dist/version.generated.js +2 -0
  180. package/package.json +5 -4
  181. package/dist/IR/tree_utils/_ir_lazyChooseList.d.ts +0 -3
  182. 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";
@@ -30,6 +31,7 @@ import { TirTernaryExpr } from "../../tir/expressions/TirTernaryExpr.js";
30
31
  import { TirToDataExpr } from "../../tir/expressions/TirToDataExpr.js";
31
32
  import { TirTraceIfFalseExpr } from "../../tir/expressions/TirTraceIfFalseExpr.js";
32
33
  import { TirTraceExpr } from "../../tir/expressions/TirTraceExpr.js";
34
+ import { TirShowExpr } from "../../tir/expressions/TirShowExpr.js";
33
35
  import { TirTypeConversionExpr } from "../../tir/expressions/TirTypeConversionExpr.js";
34
36
  import { TirVariableAccessExpr } from "../../tir/expressions/TirVariableAccessExpr.js";
35
37
  import { TirUnaryExclamation } from "../../tir/expressions/unary/TirUnaryExclamation.js";
@@ -37,8 +39,9 @@ import { TirUnaryMinus } from "../../tir/expressions/unary/TirUnaryMinus.js";
37
39
  import { TirUnaryPlus } from "../../tir/expressions/unary/TirUnaryPlus.js";
38
40
  import { isTirUnaryPrefixExpr } from "../../tir/expressions/unary/TirUnaryPrefixExpr.js";
39
41
  import { TirUnaryTilde } from "../../tir/expressions/unary/TirUnaryTilde.js";
40
- import { bool_t, bytes_t, data_t, int_t, valueAmountOfName } from "../../tir/program/stdScope/stdScope.js";
42
+ import { bool_t, bytes_t, data_t, int_t, valueMapAmountOfName } from "../../tir/program/stdScope/stdScope.js";
41
43
  import { IRNativeTag } from "../../../IR/IRNodes/IRNative/IRNativeTag.js";
44
+ import { currentCompilationCtx } from "../../../IR/CompilationCtx.js";
42
45
  import { TirReturnStmt } from "../../tir/statements/TirReturnStmt.js";
43
46
  import { TirArrayLikeDeconstr } from "../../tir/statements/TirVarDecl/TirArrayLikeDeconstr.js";
44
47
  import { TirNamedDeconstructVarDecl } from "../../tir/statements/TirVarDecl/TirNamedDeconstructVarDecl.js";
@@ -75,6 +78,7 @@ export function expressifyVars(ctx, expr) {
75
78
  || expr instanceof TirLitThisExpr
76
79
  || expr instanceof TirLitStrExpr
77
80
  || expr instanceof TirLitIntExpr
81
+ || expr instanceof TirLitEnumMemberExpr
78
82
  || expr instanceof TirLitHexBytesExpr
79
83
  || expr instanceof TirNativeFunc
80
84
  // hoisted expressions are necessarily closed, so no external variables
@@ -242,6 +246,11 @@ export function expressifyVars(ctx, expr) {
242
246
  }
243
247
  if (expr instanceof TirInlineClosedIR)
244
248
  return expr;
249
+ if (expr instanceof TirShowExpr) {
250
+ // recurse into inner so any nested variables / casts get expressified;
251
+ // the show-bytes lowering happens at IR-emit time inside TirShowExpr.toIR.
252
+ return new TirShowExpr(expressifyVars(ctx, expr.inner), expr.range);
253
+ }
245
254
  const tsEnsureExhautstiveCheck = expr;
246
255
  console.error(expr);
247
256
  throw new Error("unreachable::expressifyVars");
@@ -260,6 +269,7 @@ function expressifyPropAccess(ctx, propAccessExpr) {
260
269
  || expr instanceof TirLitArrExpr
261
270
  || expr instanceof TirLitStrExpr
262
271
  || expr instanceof TirLitIntExpr
272
+ || expr instanceof TirLitEnumMemberExpr
263
273
  || expr instanceof TirLitHexBytesExpr
264
274
  || expr instanceof TirNativeFunc
265
275
  || expr instanceof TirPropAccessExpr // `expressifyVars` is called recursively on the object before this check
@@ -276,7 +286,9 @@ function expressifyPropAccess(ctx, propAccessExpr) {
276
286
  || expr instanceof TirAssertAndContinueExpr
277
287
  || expr instanceof TirTraceIfFalseExpr
278
288
  || expr instanceof TirTraceExpr
279
- || expr instanceof TirInlineClosedIR)
289
+ || expr instanceof TirInlineClosedIR
290
+ || expr instanceof TirShowExpr // result is bytes, properties already handled via .show() returning bytes_t
291
+ )
280
292
  throw new Error("Invalid property access expression");
281
293
  if (expr instanceof TirLitThisExpr) {
282
294
  let varName = ctx.properties.get("this")?.get(prop);
@@ -364,6 +376,20 @@ function expressifyPropAccess(ctx, propAccessExpr) {
364
376
  throw new Error(`Property '${prop}' does not exist on type '${objType.toString()}'`);
365
377
  const fName = ctor.fields[fIdx].name;
366
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
+ }
367
393
  return new TirCaseExpr(expr, [
368
394
  new TirCaseMatcher(new TirNamedDeconstructVarDecl(ctor.name, new Map([
369
395
  [fName, new TirSimpleVarDecl(fName, fType, undefined, true, propAccessExpr.range)]
@@ -404,7 +430,7 @@ function expressifyMethodCall(ctx, methodCall) {
404
430
  // fast-path: `Value.amountOf(policy, name)` compiles directly to
405
431
  // `_amountOfValue(eqByteString(policy))(value)(eqByteString(name))`
406
432
  // skipping the wrapper function indirection.
407
- if (tirMethodName === valueAmountOfName
433
+ if (tirMethodName === valueMapAmountOfName
408
434
  && methodCall.args.length === 2) {
409
435
  const [policyArg, nameArg] = methodCall.args;
410
436
  const bytesToBoolT = new TirFuncT([bytes_t], bool_t);
@@ -445,12 +471,15 @@ function expressifyMethodCall(ctx, methodCall) {
445
471
  }
446
472
  const structMethods = objectType.methodNamesPtr;
447
473
  const tirMethodName = structMethods.get(methodName);
448
- if (!tirMethodName)
449
- throw new Error(`Method '${methodName}' does not exist on type '${objectType.toString()}'`);
450
- const funcExpr = ctx.program.functions.get(tirMethodName);
451
- if (!funcExpr)
452
- throw new Error(`Definition of method '${methodName}' on type '${objectType.toString()}' is missing.`);
453
- return new TirCallExpr(funcExpr, [objectExpr, ...methodCall.args], methodCall.type, SourceRange.join(methodIdentifierProp.range, methodCall.range.atEnd()));
474
+ if (tirMethodName) {
475
+ const funcExpr = ctx.program.functions.get(tirMethodName);
476
+ if (!funcExpr)
477
+ throw new Error(`Definition of method '${methodName}' on type '${objectType.toString()}' is missing.`);
478
+ return new TirCallExpr(funcExpr, [objectExpr, ...methodCall.args], methodCall.type, SourceRange.join(methodIdentifierProp.range, methodCall.range.atEnd()));
479
+ }
480
+ // No user impl — fall through to the generic `.show()` fallback at the
481
+ // end of expressifyMethodCall (which auto-derives via _showIR for
482
+ // data-encoded structs).
454
483
  }
455
484
  if (objectType instanceof TirListT) {
456
485
  const result = expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, objectType, SourceRange.join(methodIdentifierProp.range, methodCall.range.atEnd()));
@@ -491,6 +520,14 @@ function expressifyMethodCall(ctx, methodCall) {
491
520
  return new TirCallExpr(TirNativeFunc.consByteString, [methodCall.args[0], objectExpr], bytes_t, exprRange);
492
521
  }
493
522
  }
523
+ // Generic `.show()` fallback: any value whose type has a built-in
524
+ // `_showIR` impl can be shown by emitting a TirShowExpr. User types
525
+ // override this by declaring `type X implements Show { show(self): bytes
526
+ // { ... } }` — that path is taken earlier (alias/struct method-table
527
+ // dispatch) and never reaches here.
528
+ if (methodName === "show" && methodCall.args.length === 0) {
529
+ return new TirShowExpr(objectExpr, SourceRange.join(methodIdentifierProp.range, methodCall.range.atEnd())); // TirShowExpr is in TirExpr union, cast for return-type compat
530
+ }
494
531
  throw new Error(`not implemented::expressifyMethodCall for type '${objectType.toString()}' (method name: '${methodName}')`);
495
532
  // const tsEnsureExhautstiveCheck: never = objectType;
496
533
  throw new Error(`Cannot call method '${methodName}' on non-struct type '${objectType.toString()}'`);
@@ -563,7 +600,8 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
563
600
  throw new Error(`Argument 1 of method 'map' of type 'list' must be a function, got '${arg.type.toString()}'`);
564
601
  const mapReturnT = argFuncType.returnType;
565
602
  const elemTypeTirName = elemsType.toTirTypeKey();
566
- let base_mapToType = _base_mapToType_cache.get(elemTypeTirName)?.clone();
603
+ const mapToTypeCache = currentCompilationCtx().mapToTypeCache;
604
+ let base_mapToType = mapToTypeCache.get(elemTypeTirName)?.clone();
567
605
  if (!base_mapToType) {
568
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([
569
607
  // mapping function
@@ -574,7 +612,7 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
574
612
  new TirListT(elemsType)
575
613
  ], new TirListT(mapReturnT)), SourceRange.unknown));
576
614
  base_mapToType.varName; // precompute hash and symbol
577
- _base_mapToType_cache.set(elemTypeTirName, base_mapToType.clone());
615
+ mapToTypeCache.set(elemTypeTirName, base_mapToType.clone());
578
616
  }
579
617
  return new TirCallExpr(base_mapToType, [methodCall.args[0], objectExpr], methodCall.type, exprRange);
580
618
  }
@@ -586,7 +624,3 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
586
624
  };
587
625
  */
588
626
  }
589
- const _base_mapToType_cache = new Map();
590
- export function __unsafe_clear_mapToType_cache() {
591
- _base_mapToType_cache.clear();
592
- }
@@ -0,0 +1,38 @@
1
+ import { SourceRange } from "../../ast/Source/SourceRange.js";
2
+ export type TestKind = "unit" | "property";
3
+ export interface TestBudget {
4
+ cpu: bigint;
5
+ mem: bigint;
6
+ }
7
+ export interface TestInput {
8
+ name: string;
9
+ value: unknown;
10
+ }
11
+ export interface TestIterationResult {
12
+ passed: boolean;
13
+ budgetSpent: TestBudget;
14
+ logs: string[];
15
+ error?: {
16
+ msg?: string;
17
+ };
18
+ /** the fuzzed input tuple for this iteration; undefined for unit tests */
19
+ inputs?: TestInput[];
20
+ }
21
+ export interface TestResult {
22
+ name: string;
23
+ sourceFile: string;
24
+ range: SourceRange;
25
+ kind: TestKind;
26
+ /** aggregate pass/fail across all iterations */
27
+ passed: boolean;
28
+ /** length 1 for unit tests, N for property tests */
29
+ iterations: TestIterationResult[];
30
+ /** sum of `budgetSpent` across iterations */
31
+ totalBudget: TestBudget;
32
+ /** non-empty when the test could not be executed at all (e.g. unsupported feature) */
33
+ skippedReason?: string;
34
+ /** seed used by the property runner (only set for property tests) */
35
+ seed?: number;
36
+ }
37
+ export declare function zeroBudget(): TestBudget;
38
+ export declare function addBudget(a: TestBudget, b: TestBudget): TestBudget;
@@ -0,0 +1,6 @@
1
+ export function zeroBudget() {
2
+ return { cpu: 0n, mem: 0n };
3
+ }
4
+ export function addBudget(a, b) {
5
+ return { cpu: a.cpu + b.cpu, mem: a.mem + b.mem };
6
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Tiny seedable PRNG (mulberry32).
3
+ *
4
+ * Single-purpose, deterministic, no dependencies. Used by the Phase 1
5
+ * property-test runner to sample primitive values for parameters whose
6
+ * type has a built-in TS-side fuzzer (`int`, `bool`).
7
+ *
8
+ * Phase 2 will replace this with a Pebble-side fuzzer pipeline that runs
9
+ * on the CEK machine; that will let user-defined fuzzers (`via <expr>`)
10
+ * compose deterministically with the built-in ones.
11
+ */
12
+ export declare class PRNG {
13
+ private state;
14
+ constructor(seed: number);
15
+ /** Returns an unsigned 32-bit integer. */
16
+ next32(): number;
17
+ /** Returns a boolean (uniform). */
18
+ nextBool(): boolean;
19
+ /**
20
+ * Returns a random bigint, biased toward edge values.
21
+ *
22
+ * 1 in 16 returns one of: 0, 1, -1, INT64_MAX, INT64_MIN, INT32_MAX, INT32_MIN.
23
+ * Otherwise samples uniformly across signed 64-bit range.
24
+ */
25
+ nextIntBiased(): bigint;
26
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Tiny seedable PRNG (mulberry32).
3
+ *
4
+ * Single-purpose, deterministic, no dependencies. Used by the Phase 1
5
+ * property-test runner to sample primitive values for parameters whose
6
+ * type has a built-in TS-side fuzzer (`int`, `bool`).
7
+ *
8
+ * Phase 2 will replace this with a Pebble-side fuzzer pipeline that runs
9
+ * on the CEK machine; that will let user-defined fuzzers (`via <expr>`)
10
+ * compose deterministically with the built-in ones.
11
+ */
12
+ export class PRNG {
13
+ state;
14
+ constructor(seed) {
15
+ // ensure non-zero, fits in u32
16
+ this.state = (seed | 0) || 1;
17
+ }
18
+ /** Returns an unsigned 32-bit integer. */
19
+ next32() {
20
+ // mulberry32
21
+ let t = (this.state = (this.state + 0x6D2B79F5) | 0);
22
+ t = Math.imul(t ^ (t >>> 15), t | 1);
23
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
24
+ return (t ^ (t >>> 14)) >>> 0;
25
+ }
26
+ /** Returns a boolean (uniform). */
27
+ nextBool() {
28
+ return (this.next32() & 1) === 1;
29
+ }
30
+ /**
31
+ * Returns a random bigint, biased toward edge values.
32
+ *
33
+ * 1 in 16 returns one of: 0, 1, -1, INT64_MAX, INT64_MIN, INT32_MAX, INT32_MIN.
34
+ * Otherwise samples uniformly across signed 64-bit range.
35
+ */
36
+ nextIntBiased() {
37
+ const edgeRoll = this.next32() & 0xF; // 0..15
38
+ if (edgeRoll === 0) {
39
+ const edges = [
40
+ 0n,
41
+ 1n,
42
+ -1n,
43
+ (1n << 63n) - 1n,
44
+ -(1n << 63n),
45
+ (1n << 31n) - 1n,
46
+ -(1n << 31n),
47
+ ];
48
+ return edges[this.next32() % edges.length];
49
+ }
50
+ // assemble a 64-bit signed value from two u32 samples
51
+ const hi = BigInt(this.next32());
52
+ const lo = BigInt(this.next32());
53
+ let v = (hi << 32n) | lo;
54
+ // interpret as signed (sign bit is bit 63)
55
+ if (v & (1n << 63n))
56
+ v -= (1n << 64n);
57
+ return v;
58
+ }
59
+ }
@@ -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 { _ir_lazyIfThenElse } from "../../../IR/tree_utils/_ir_lazyIfThenElse.js";
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 { getOptTypeArg } from "../types/utils/getOptTypeArg.js";
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
- if (matchExprType instanceof TirDataOptT) {
176
- const stmtCtx = ctx.newChild();
177
- stmtCtx.pushUnusedVar(); // debrujin un constr data result
178
- const wildcardBodyIR = this.wildcardCase?.body.toIR(stmtCtx) ?? new IRError();
179
- const someBranch = this.cases.find(c => c.pattern.constrName === "Some");
180
- let someBranchIR = () => new IRFunc([Symbol("unused_some_value")], wildcardBodyIR);
181
- if (someBranch) {
182
- const pattern = someBranch.pattern;
183
- const valueDecl = pattern.fields.get("value");
184
- if (valueDecl
185
- && !(valueDecl instanceof TirSimpleVarDecl))
186
- throw new Error("case pattern not expressified.");
187
- const someBranchCtx = stmtCtx.newChild();
188
- const someBranchVarSym = valueDecl ? someBranchCtx.defineVar(valueDecl.name) : Symbol("some_value_unused");
189
- someBranchIR = (unConstrMatchSym) => new IRApp(new IRFunc([someBranchVarSym], someBranch.body.toIR(someBranchCtx)), _inlineFromData(getOptTypeArg(matchExprType), _ir_apps(IRNative.sndPair, new IRVar(unConstrMatchSym) // unConstrData result
190
- )));
191
- }
192
- const noneBranchIR = this.cases.find(c => c.pattern.constrName === "None")?.body.toIR(stmtCtx) ?? wildcardBodyIR;
193
- return _ir_let(_ir_apps(IRNative.unConstrData, this.matchExpr.toIR(ctx)), unConstrMatchSym => _ir_lazyIfThenElse(
194
- // condition
195
- _ir_apps(IRNative.equalsInteger, IRConst.int(0), _ir_apps(IRNative.fstPair, new IRVar(unConstrMatchSym) // unConstrData result
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 cases = this.cases.sort((a, b) => {
213
- const a_idx = matchExprType.constructors.findIndex(ctor => ctor.name === a.pattern.constrName);
214
- const b_idx = matchExprType.constructors.findIndex(ctor => ctor.name === b.pattern.constrName);
215
- return a_idx - b_idx;
216
- });
217
- for (let i = cases.length - 1; i >= 0; i--) {
218
- const { pattern, body } = cases[i];
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 usedFieldsCtorNames = (ctor.fields.map(f => f.name)
224
- .filter(fName => pattern.fields.has(fName)));
225
- if (usedFieldsCtorNames.length <= 0) {
226
- ifThenElseMatchingStatements = _ir_lazyIfThenElse(
227
- // condition (compare against the PARENT ctor index — the
228
- // value's runtime tag is unaffected by narrowing)
229
- _ir_apps(new IRVar(isConstrIdxSym), // isConstrIdx
230
- IRConst.int(matchExprType instanceof TirDataStructType
231
- ? matchExprType.parentCtorIdx(ctorIdx)
232
- : ctorIdx)),
233
- // then
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 introVar = thenCtx.defineVar(patternVarDecl.name);
252
- const thenCase = _ir_let_sym(introVar, _inlineFromData(patternVarDecl.type, _ir_apps(IRNative.headList, _ir_apps(IRNative._dropList, IRConst.int(indexOfField(fName)), // constr field index
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
- introducedVars[fIdx] = thenCtx.defineVar(patternVarDecl.name);
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
- const extractedFields = sortedUsedFields.map(fName => _inlineFromData(ctor.fields.find(f => f.name === fName).type, _ir_apps(IRNative.headList, _ir_apps(IRNative._dropList, IRConst.int(indexOfField(fName)), // constr field index
282
- new IRVar(fieldsAsDataList) // fileds as data list
283
- ))));
284
- const thenCase = _ir_let_sym(fieldsAsDataList, _ir_apps(IRNative.sndPair, new IRVar(unConstrStructSym) // unconstrStruct
285
- ), // fileds as data list
286
- _ir_apps(new IRFunc(introducedVars, body.toIR(thenCtx)), ...extractedFields));
287
- ifThenElseMatchingStatements = _ir_lazyIfThenElse(
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
- return _ir_let_sym(unConstrStructSym, _ir_apps(IRNative.unConstrData, this.matchExpr.toIR(ctx)), // unconstrStruct
300
- _ir_let_sym(isConstrIdxSym, _ir_apps(IRNative.equalsInteger, _ir_apps(IRNative.fstPair, new IRVar(unConstrStructSym) // unConstrData result
301
- )), // isConstrIdx
302
- ifThenElseMatchingStatements));
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._dropList, IRConst.int(result.value), irArr));
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._dropList, irIndex, irArr));
49
+ return _ir_apps(IRNative.headList, _ir_apps(IRNative.dropList, irIndex, irArr));
50
50
  }
51
51
  }