@harmoniclabs/pebble 0.2.0 → 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 (116) 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 +22 -2
  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 +27 -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 +12 -0
  17. package/dist/IR/toUPLC/CompilerOptions.js +14 -9
  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/ast/nodes/statements/declarations/StructDecl.d.ts +16 -2
  35. package/dist/ast/nodes/statements/declarations/StructDecl.js +15 -1
  36. package/dist/compiler/AstCompiler/AstCompiler.d.ts +1 -0
  37. package/dist/compiler/AstCompiler/AstCompiler.js +41 -4
  38. package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +3 -3
  39. package/dist/compiler/AstCompiler/internal/exprs/_compileCaseExpr.js +31 -0
  40. package/dist/compiler/AstCompiler/internal/exprs/_compileIsExpr.js +12 -0
  41. package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +36 -0
  42. package/dist/compiler/AstCompiler/internal/exprs/_compileUnaryPrefixExpr.js +13 -1
  43. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileAddExpr.js +18 -5
  44. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileEqualExpr.js +3 -1
  45. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanEqualExpr.js +2 -1
  46. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanExpr.js +2 -1
  47. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanEqualExpr.js +2 -1
  48. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanExpr.js +2 -1
  49. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileMultExpr.js +24 -6
  50. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileNotEqualExpr.js +2 -1
  51. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileSubExpr.js +16 -5
  52. package/dist/compiler/AstCompiler/internal/statements/_compileMatchStmt.js +33 -20
  53. package/dist/compiler/AstCompiler/utils/getPropAccessReturnType.js +11 -0
  54. package/dist/compiler/Compiler.js +20 -27
  55. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +1 -1
  56. package/dist/compiler/TirCompiler/expressify/expressify.js +30 -2
  57. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.d.ts +2 -1
  58. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +45 -7
  59. package/dist/compiler/TirCompiler/expressify/expressifyVars.d.ts +0 -1
  60. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +23 -8
  61. package/dist/compiler/tir/expressions/TirCaseExpr.d.ts +9 -0
  62. package/dist/compiler/tir/expressions/TirCaseExpr.js +144 -122
  63. package/dist/compiler/tir/expressions/TirElemAccessExpr.js +2 -2
  64. package/dist/compiler/tir/expressions/TirFromDataExpr.js +102 -67
  65. package/dist/compiler/tir/expressions/TirIsExpr.js +14 -1
  66. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +1 -2
  67. package/dist/compiler/tir/expressions/TirNativeFunc.js +2 -12
  68. package/dist/compiler/tir/expressions/TirToDataExpr.js +3 -0
  69. package/dist/compiler/tir/expressions/TirTypeConversionExpr.js +10 -0
  70. package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +2 -3
  71. package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +1 -4
  72. package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +20 -3
  73. package/dist/compiler/tir/expressions/ToIRTermCtx.js +48 -3
  74. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +2 -2
  75. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +45 -8
  76. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.d.ts +19 -0
  77. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.js +24 -0
  78. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.d.ts +2 -1
  79. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.js +2 -0
  80. package/dist/compiler/tir/expressions/unary/TirUnaryMinus.js +4 -1
  81. package/dist/compiler/tir/program/stdScope/populateStdNamespace.js +49 -4
  82. package/dist/compiler/tir/program/stdScope/prelude/preludeTypesSrc.js +35 -2
  83. package/dist/compiler/tir/program/stdScope/stdScope.d.ts +7 -0
  84. package/dist/compiler/tir/program/stdScope/stdScope.js +83 -40
  85. package/dist/compiler/tir/types/TirEnumType.d.ts +21 -0
  86. package/dist/compiler/tir/types/TirEnumType.js +36 -0
  87. package/dist/compiler/tir/types/TirNativeType/TirNativeType.d.ts +4 -2
  88. package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +5 -0
  89. package/dist/compiler/tir/types/TirNativeType/native/array.d.ts +16 -0
  90. package/dist/compiler/tir/types/TirNativeType/native/array.js +38 -0
  91. package/dist/compiler/tir/types/TirNativeType/native/index.d.ts +2 -0
  92. package/dist/compiler/tir/types/TirNativeType/native/index.js +2 -0
  93. package/dist/compiler/tir/types/TirNativeType/native/value.d.ts +18 -0
  94. package/dist/compiler/tir/types/TirNativeType/native/value.js +17 -0
  95. package/dist/compiler/tir/types/TirStructType.js +6 -1
  96. package/dist/compiler/tir/types/TirType.d.ts +3 -2
  97. package/dist/compiler/tir/types/TirType.js +4 -1
  98. package/dist/compiler/tir/types/utils/canAssignTo.js +28 -0
  99. package/dist/compiler/tir/types/utils/canCastTo.js +14 -1
  100. package/dist/compiler/tir/types/utils/getDeconstructableType.d.ts +2 -1
  101. package/dist/compiler/tir/types/utils/getDeconstructableType.js +2 -0
  102. package/dist/compiler/tir/types/utils/inferTypeArgs.js +4 -0
  103. package/dist/compiler/tir/types/utils/normalizeEnumToInt.d.ts +10 -0
  104. package/dist/compiler/tir/types/utils/normalizeEnumToInt.js +17 -0
  105. package/dist/compiler/tir/types/utils/substituteTypeParams.js +5 -0
  106. package/dist/diagnostics/diagnosticMessages.generated.d.ts +5 -0
  107. package/dist/diagnostics/diagnosticMessages.generated.js +10 -0
  108. package/dist/parser/Parser.js +29 -13
  109. package/dist/tokenizer/Token.d.ts +8 -7
  110. package/dist/tokenizer/Token.js +8 -7
  111. package/dist/tokenizer/utils/tokenFromKeyword.js +2 -0
  112. package/dist/version.generated.d.ts +1 -1
  113. package/dist/version.generated.js +1 -1
  114. package/package.json +3 -3
  115. package/dist/IR/tree_utils/_ir_lazyChooseList.d.ts +0 -3
  116. package/dist/IR/tree_utils/_ir_lazyChooseList.js +0 -7
@@ -0,0 +1,40 @@
1
+ import type { IRHash } from "./IRHash.js";
2
+ /**
3
+ * Per-compilation mutable state.
4
+ *
5
+ * Everything here is scoped to a single compile so that compilations are
6
+ * hermetic: one compile can never observe or mutate another's caches.
7
+ * Combined with content-addressed `IRHash` (which has no global state at
8
+ * all), this makes the whole pipeline free of cross-compilation leakage.
9
+ *
10
+ * The maps hold (or name) IR nodes that belong to *this* compile's tree —
11
+ * `hoistedCache` in particular references live nodes that later passes
12
+ * mutate in place, which is exactly why it must not outlive the compile.
13
+ *
14
+ * Node value types are kept as `unknown`/`any` here to avoid an
15
+ * `IR/IRNodes` import cycle; the consumers cast at the use site.
16
+ */
17
+ export declare class CompilationCtx {
18
+ /** hoisted-term hash -> the letted node it was lowered to (live tree node). */
19
+ readonly hoistedCache: Map<IRHash, WeakRef<any>>;
20
+ /** hoisted-term hash -> the stable binder symbol used to name it. */
21
+ readonly hoistedHashToSymbol: Map<IRHash, WeakRef<Symbol>>;
22
+ /** letted-term hash -> the stable binder symbol used to name it. */
23
+ readonly lettedHashToSymbol: Map<IRHash, WeakRef<Symbol>>;
24
+ /** element-type name -> cached `mapToType` TIR helper (clones only). */
25
+ readonly mapToTypeCache: Map<string, any>;
26
+ }
27
+ /**
28
+ * The context for the compilation currently in flight. If none is active
29
+ * (e.g. an `IRTerm.name` access from a debug/`showIR` path outside a
30
+ * compile) a process-wide default is used — safe because, with
31
+ * content-addressed hashing, sharing these caches can no longer cause a
32
+ * miscompile; it only affects one-off naming.
33
+ */
34
+ export declare function currentCompilationCtx(): CompilationCtx;
35
+ /**
36
+ * Run `fn` with `ctx` as the active compilation context, restoring the
37
+ * previous one afterwards (so nested compiles are well-behaved). The
38
+ * `finally` guarantees the context is cleared even if `fn` throws.
39
+ */
40
+ export declare function withCompilationCtx<T>(ctx: CompilationCtx, fn: () => T): T;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Per-compilation mutable state.
3
+ *
4
+ * Everything here is scoped to a single compile so that compilations are
5
+ * hermetic: one compile can never observe or mutate another's caches.
6
+ * Combined with content-addressed `IRHash` (which has no global state at
7
+ * all), this makes the whole pipeline free of cross-compilation leakage.
8
+ *
9
+ * The maps hold (or name) IR nodes that belong to *this* compile's tree —
10
+ * `hoistedCache` in particular references live nodes that later passes
11
+ * mutate in place, which is exactly why it must not outlive the compile.
12
+ *
13
+ * Node value types are kept as `unknown`/`any` here to avoid an
14
+ * `IR/IRNodes` import cycle; the consumers cast at the use site.
15
+ */
16
+ export class CompilationCtx {
17
+ /** hoisted-term hash -> the letted node it was lowered to (live tree node). */
18
+ hoistedCache = new Map();
19
+ /** hoisted-term hash -> the stable binder symbol used to name it. */
20
+ hoistedHashToSymbol = new Map();
21
+ /** letted-term hash -> the stable binder symbol used to name it. */
22
+ lettedHashToSymbol = new Map();
23
+ /** element-type name -> cached `mapToType` TIR helper (clones only). */
24
+ mapToTypeCache = new Map();
25
+ }
26
+ let _current = undefined;
27
+ let _default = undefined;
28
+ /**
29
+ * The context for the compilation currently in flight. If none is active
30
+ * (e.g. an `IRTerm.name` access from a debug/`showIR` path outside a
31
+ * compile) a process-wide default is used — safe because, with
32
+ * content-addressed hashing, sharing these caches can no longer cause a
33
+ * miscompile; it only affects one-off naming.
34
+ */
35
+ export function currentCompilationCtx() {
36
+ if (_current !== undefined)
37
+ return _current;
38
+ return (_default ??= new CompilationCtx());
39
+ }
40
+ /**
41
+ * Run `fn` with `ctx` as the active compilation context, restoring the
42
+ * previous one afterwards (so nested compiles are well-behaved). The
43
+ * `finally` guarantees the context is cleared even if `fn` throws.
44
+ */
45
+ export function withCompilationCtx(ctx, fn) {
46
+ const prev = _current;
47
+ _current = ctx;
48
+ try {
49
+ return fn();
50
+ }
51
+ finally {
52
+ _current = prev;
53
+ }
54
+ }
@@ -1,5 +1,26 @@
1
- export type IRHash = number;
2
- export declare function __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION(): void;
1
+ /**
2
+ * Content-addressed IR hash.
3
+ *
4
+ * An `IRHash` is the lowercase-hex blake2b-128 digest of a node's
5
+ * structural *preimage* — its tag byte(s) concatenated with the digests
6
+ * of its children (a Merkle hash over the IR tree). Because it is a pure
7
+ * function of the node's content, the same term always hashes to the
8
+ * same value for the entire life of the process: there is no global
9
+ * counter and no interning table, and therefore **nothing to reset
10
+ * between compilations**.
11
+ *
12
+ * This is what makes compilation hermetic. The previous implementation
13
+ * interned preimages to a sequential integer and reset the counter at
14
+ * the end of every compile; long-lived nodes (the module-level
15
+ * `hoisted_*` singletons) cached integer hashes from the pre-reset
16
+ * numbering, so after the first reset freshly-minted nodes collided with
17
+ * those stale hashes and the hoist/let dedup merged unrelated terms.
18
+ * Content addressing removes the failure mode by construction.
19
+ *
20
+ * Memory: there is no central table that accumulates across compiles —
21
+ * each node memoizes its own digest and is collected normally.
22
+ */
23
+ export type IRHash = string;
3
24
  export declare function hashIrData(data: Uint8Array): IRHash;
4
25
  export declare function isIRHash(hash: any): hash is IRHash;
5
26
  export declare function equalIrHash(a: IRHash, b: IRHash): boolean;
package/dist/IR/IRHash.js CHANGED
@@ -1,73 +1,23 @@
1
- import { fromHex, toBase64 } from "@harmoniclabs/uint8array-utils";
2
- // HASH GENERATOR
3
- const MAX_SAFE_INTEGER = Number(globalThis.Number?.MAX_SAFE_INTEGER ?? ((2 ** 53) - 1));
4
- const MIN_SAFE_INTEGER = Number(globalThis.Number?.MIN_SAFE_INTEGER ?? -MAX_SAFE_INTEGER);
5
- let _preimage_to_hash = {};
6
- let _next_hash = MIN_SAFE_INTEGER;
7
- function _getNextHash() {
8
- if (_next_hash >= MAX_SAFE_INTEGER)
9
- throw new Error("ran out of IR hashes");
10
- return _next_hash++;
11
- }
12
- export function __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION() {
13
- _preimage_to_hash = {};
14
- _next_hash = MIN_SAFE_INTEGER;
15
- }
16
- // HASH UTILS
17
- function _positiveHash(hash) {
18
- return BigInt(hash) + BigInt(MAX_SAFE_INTEGER) + BigInt(1);
19
- }
20
- function _fromPositiveHash(posHash) {
21
- const res = Number(posHash - BigInt(MAX_SAFE_INTEGER) - BigInt(1));
22
- if (!isIRHash(res))
23
- throw new Error("internal error: invalid hash generated");
24
- return res;
25
- }
26
- // END HASH GENERATOR
1
+ import { blake2b_128 } from "@harmoniclabs/crypto";
2
+ import { fromHex, toHex } from "@harmoniclabs/uint8array-utils";
3
+ /** 16 bytes (blake2b-128) -> 32 lowercase hex chars. */
4
+ const IR_HASH_HEX_LEN = 32;
27
5
  export function hashIrData(data) {
28
- const preimage = toBase64(data);
29
- const exsisting = _preimage_to_hash[preimage];
30
- if (typeof exsisting === "number")
31
- return exsisting;
32
- const nextHash = _getNextHash();
33
- _preimage_to_hash[preimage] = nextHash;
34
- return nextHash;
6
+ return toHex(blake2b_128(data));
35
7
  }
36
8
  export function isIRHash(hash) {
37
- return (typeof hash === "number"
38
- && hash === hash // not NaN
39
- && hash <= MAX_SAFE_INTEGER
40
- && hash >= MIN_SAFE_INTEGER
41
- && BigInt(hash) <= hash
42
- && BigInt(hash) >= hash);
9
+ return (typeof hash === "string"
10
+ && hash.length === IR_HASH_HEX_LEN);
43
11
  }
44
12
  export function equalIrHash(a, b) {
45
- // we can allow ourselves to use standard equality
46
- // only because we always return the same object for the same hash
47
13
  return a === b;
48
- /*
49
- return (
50
- // a instanceof Uint32Array &&
51
- // b instanceof Uint32Array &&
52
- // a.length === 4 &&
53
- // b.length === 4 &&
54
- a[0] === b[0] &&
55
- a[1] === b[1] &&
56
- a[2] === b[2] &&
57
- a[3] === b[3]
58
- );
59
- //*/
60
14
  }
61
15
  export function irHashToHex(hash) {
62
- return _positiveHash(hash)
63
- .toString(16)
64
- // we MUST pad to 16 chars
65
- // otherwise, hash concatenation could be ambiguous
66
- .padStart(16, "0");
16
+ return hash;
67
17
  }
68
18
  export function irHashFromHex(hex) {
69
- return _fromPositiveHash(BigInt("0x" + hex));
19
+ return hex;
70
20
  }
71
21
  export function irHashToBytes(hash) {
72
- return fromHex(irHashToHex(hash));
22
+ return fromHex(hash);
73
23
  }
@@ -8,6 +8,7 @@ import { IRNodeKind } from "../IRNodeKind.js";
8
8
  import { getUnaliased } from "../../compiler/tir/types/utils/getUnaliased.js";
9
9
  import { TirAliasType } from "../../compiler/tir/types/TirAliasType.js";
10
10
  import { TirDataStructType, TirSoPStructType } from "../../compiler/tir/types/TirStructType.js";
11
+ import { TirEnumType } from "../../compiler/tir/types/TirEnumType.js";
11
12
  import { getListTypeArg } from "../../compiler/tir/types/utils/getListTypeArg.js";
12
13
  import { TirTypeParam } from "../../compiler/tir/types/TirTypeParam.js";
13
14
  import { constT, isPair, UPLCConst } from "@harmoniclabs/uplc";
@@ -17,6 +18,8 @@ import { TirBytesT } from "../../compiler/tir/types/TirNativeType/native/bytes.j
17
18
  import { TirDataT } from "../../compiler/tir/types/TirNativeType/native/data.js";
18
19
  import { TirFuncT } from "../../compiler/tir/types/TirNativeType/native/function.js";
19
20
  import { TirIntT } from "../../compiler/tir/types/TirNativeType/native/int.js";
21
+ import { TirArrayT } from "../../compiler/tir/types/TirNativeType/native/array.js";
22
+ import { TirValueT } from "../../compiler/tir/types/TirNativeType/native/value.js";
20
23
  import { TirLinearMapT } from "../../compiler/tir/types/TirNativeType/native/linearMap.js";
21
24
  import { TirLinearMapEntryT } from "../../compiler/tir/types/TirNativeType/native/linearMapEntry.js";
22
25
  import { TirListT } from "../../compiler/tir/types/TirNativeType/native/list.js";
@@ -142,6 +145,8 @@ function isValueAssignableToType(value, type) {
142
145
  return typeof value === "boolean";
143
146
  if (type instanceof TirIntT)
144
147
  return typeof value === "bigint";
148
+ if (type instanceof TirEnumType)
149
+ return typeof value === "bigint";
145
150
  if (type instanceof TirBytesT)
146
151
  return value instanceof Uint8Array;
147
152
  if (type instanceof TirStringT)
@@ -174,6 +179,11 @@ function isValueAssignableToType(value, type) {
174
179
  || type instanceof TirBlsG2T
175
180
  || type instanceof TirMlResultT)
176
181
  return false;
182
+ // Native `Value` and `Array<T>` are never IRConst literals — they
183
+ // only appear at runtime as results of builtins.
184
+ if (type instanceof TirValueT
185
+ || type instanceof TirArrayT)
186
+ return false;
177
187
  const tsEnsureExsaustiveCheck = type;
178
188
  return false;
179
189
  }
@@ -193,7 +203,7 @@ function serializeIRConstValue(value, type) {
193
203
  throw new Error("unreachable");
194
204
  if (type instanceof TirVoidT)
195
205
  return new Uint8Array(0);
196
- if (type instanceof TirIntT) {
206
+ if (type instanceof TirIntT || type instanceof TirEnumType) {
197
207
  return positiveBigIntAsBytes(UPLCFlatUtils.zigzagBigint(BigInt(value)));
198
208
  }
199
209
  if (type instanceof TirStringT)
@@ -229,7 +239,9 @@ function serializeIRConstValue(value, type) {
229
239
  || type instanceof TirTypeParam
230
240
  || type instanceof TirBlsG1T
231
241
  || type instanceof TirBlsG2T
232
- || type instanceof TirMlResultT)
242
+ || type instanceof TirMlResultT
243
+ || type instanceof TirValueT
244
+ || type instanceof TirArrayT)
233
245
  throw new Error("invalid uplc const type");
234
246
  const tsEnsureExsaustiveCheck = type;
235
247
  throw new Error("unreachable");
@@ -264,6 +276,8 @@ export function tirTypeToUplcType(t) {
264
276
  return constT.bool;
265
277
  if (t instanceof TirIntT)
266
278
  return constT.int;
279
+ if (t instanceof TirEnumType)
280
+ return constT.int;
267
281
  if (t instanceof TirBytesT)
268
282
  return constT.byteStr;
269
283
  if (t instanceof TirStringT)
@@ -272,6 +286,12 @@ export function tirTypeToUplcType(t) {
272
286
  const elemsT = tirTypeToUplcType(getListTypeArg(t));
273
287
  return constT.listOf(elemsT);
274
288
  }
289
+ if (t instanceof TirArrayT) {
290
+ const elemsT = tirTypeToUplcType(t.typeArg);
291
+ return constT.arrayOf(elemsT);
292
+ }
293
+ if (t instanceof TirValueT)
294
+ return constT.value;
275
295
  if (t instanceof TirDataT
276
296
  || t instanceof TirDataOptT
277
297
  || t instanceof TirDataStructType)
@@ -24,7 +24,6 @@ export interface IRHoistedMeta {
24
24
  export interface IRHoistedMetadata extends IRMetadata {
25
25
  meta: IRHoistedMeta;
26
26
  }
27
- export declare function __unsafe_clear_hoisted_hash_to_symbol(): void;
28
27
  export declare class IRHoisted implements IIRTerm, Cloneable<IRHoisted>, IIRParent, ToJson, IRHoistedMetadata {
29
28
  readonly meta: IRHoistedMeta;
30
29
  get name(): symbol;
@@ -13,25 +13,23 @@ import { IRCase } from "./IRCase.js";
13
13
  import { IRNodeKind } from "../IRNodeKind.js";
14
14
  import { IRRecursive } from "./IRRecursive.js";
15
15
  import { isIRHash, hashIrData, irHashToBytes, equalIrHash, irHashToHex } from "../IRHash.js";
16
+ import { currentCompilationCtx } from "../CompilationCtx.js";
16
17
  import { IRNative } from "./IRNative/index.js";
17
18
  import { nativeTagToString } from "./IRNative/IRNativeTag.js";
18
19
  const defaultHoistedMeta = freezeAll({
19
20
  forceHoist: false
20
21
  });
21
- const _hoisted_hash_to_symbol = new Map();
22
- export function __unsafe_clear_hoisted_hash_to_symbol() {
23
- _hoisted_hash_to_symbol.clear();
24
- }
25
22
  export class IRHoisted {
26
23
  meta;
27
24
  get name() {
28
25
  const hash = this.hash;
29
- const cached = _hoisted_hash_to_symbol.get(hash)?.deref();
26
+ const hashToSymbol = currentCompilationCtx().hoistedHashToSymbol;
27
+ const cached = hashToSymbol.get(hash)?.deref();
30
28
  if (typeof cached === "symbol")
31
29
  return cached;
32
30
  const sym = Symbol(tryInferName(this.hoisted) ?? "hoisted_" + irHashToHex(hash));
33
31
  /// @ts-ignore Argument of type 'WeakRef<object>' is not assignable to parameter of type 'WeakRef<Symbol>'
34
- _hoisted_hash_to_symbol.set(hash, new WeakRef(sym));
32
+ hashToSymbol.set(hash, new WeakRef(sym));
35
33
  return sym;
36
34
  }
37
35
  constructor(hoisted, metadata = {}, _unsafeHash) {
@@ -34,7 +34,6 @@ export interface IRLettedMeta extends BaseIRMetadata {
34
34
  export interface IRLettedMetadata extends IRMetadata {
35
35
  meta: IRLettedMeta;
36
36
  }
37
- export declare function __unsafe_clear_letted_hash_to_symbol(): void;
38
37
  export declare class IRLetted implements IIRTerm, Cloneable<IRLetted>, IIRParent, ToJson, IRLettedMetadata {
39
38
  private _name;
40
39
  readonly meta: IRLettedMeta;
@@ -5,6 +5,7 @@ import { isIRTerm } from "../utils/isIRTerm.js";
5
5
  import { IRHoisted } from "./IRHoisted.js";
6
6
  import { isIRParentTerm } from "../utils/isIRParentTerm.js";
7
7
  import { hashIrData, irHashToBytes, isIRHash } from "../IRHash.js";
8
+ import { currentCompilationCtx } from "../CompilationCtx.js";
8
9
  import { IRNodeKind } from "../IRNodeKind.js";
9
10
  import { prettyIR } from "../utils/showIR.js";
10
11
  export function jsonLettedSetEntry(entry) {
@@ -25,23 +26,20 @@ const defaultLettedMeta = freezeAll({
25
26
  __src__: undefined,
26
27
  isClosed: false
27
28
  });
28
- const _letted_hash_to_symbol = new Map();
29
- export function __unsafe_clear_letted_hash_to_symbol() {
30
- _letted_hash_to_symbol.clear();
31
- }
32
29
  export class IRLetted {
33
30
  _name;
34
31
  meta;
35
32
  get name() {
36
33
  const hash = this.hash;
37
- const cached = _letted_hash_to_symbol.get(hash)?.deref();
34
+ const hashToSymbol = currentCompilationCtx().lettedHashToSymbol;
35
+ const cached = hashToSymbol.get(hash)?.deref();
38
36
  if (typeof cached === "symbol")
39
37
  return cached;
40
38
  if (typeof this._name !== "symbol")
41
39
  throw new Error("IRLetted had invalid name");
42
40
  const sym = this._name;
43
41
  /// @ts-ignore Argument of type 'WeakRef<object>' is not assignable to parameter of type 'WeakRef<Symbol>'
44
- _letted_hash_to_symbol.set(hash, new WeakRef(sym));
42
+ hashToSymbol.set(hash, new WeakRef(sym));
45
43
  return sym;
46
44
  }
47
45
  constructor(name, toLet, metadata = {}, _unsafeHash) {
@@ -93,7 +93,20 @@ export declare enum IRNativeTag {
93
93
  countSetBits = 84,
94
94
  findFirstSetBit = 85,
95
95
  ripemd_160 = 86,
96
- _dropList = -4,
96
+ expModInteger = 87,
97
+ dropList = 88,
98
+ lengthOfArray = 89,
99
+ listToArray = 90,
100
+ indexArray = 91,
101
+ bls12_381_G1_multiScalarMul = 92,
102
+ bls12_381_G2_multiScalarMul = 93,
103
+ insertCoin = 94,
104
+ lookupCoin = 95,
105
+ unionValue = 96,
106
+ valueContains = 97,
107
+ valueData = 98,
108
+ unValueData = 99,
109
+ scaleValue = 100,
97
110
  _foldr = -6,
98
111
  _foldl = -7,
99
112
  _length = -9,
@@ -135,6 +148,13 @@ export declare enum IRNativeTag {
135
148
  _findSopOptional = -45,
136
149
  _increment = -46,
137
150
  _decrement = -47,
138
- _lookupLinearMap = -48
151
+ _lookupLinearMap = -48,
152
+ /** partial application of `scaleValue` with -1 — negates a native Value. */
153
+ _negateValue = -49,
154
+ /**
155
+ * `\a b -> valueContains(a, b) && valueContains(b, a)` — equality on
156
+ * canonical Values. Short-circuits on the first inequality.
157
+ */
158
+ _valueEq = -50
139
159
  }
140
160
  export declare function nativeTagToString(nativeTag: IRNativeTag): string;
@@ -108,12 +108,27 @@ export var IRNativeTag;
108
108
  IRNativeTag[IRNativeTag["countSetBits"] = 84] = "countSetBits";
109
109
  IRNativeTag[IRNativeTag["findFirstSetBit"] = 85] = "findFirstSetBit";
110
110
  IRNativeTag[IRNativeTag["ripemd_160"] = 86] = "ripemd_160";
111
+ // Chang2
112
+ IRNativeTag[IRNativeTag["expModInteger"] = 87] = "expModInteger";
113
+ IRNativeTag[IRNativeTag["dropList"] = 88] = "dropList";
114
+ IRNativeTag[IRNativeTag["lengthOfArray"] = 89] = "lengthOfArray";
115
+ IRNativeTag[IRNativeTag["listToArray"] = 90] = "listToArray";
116
+ IRNativeTag[IRNativeTag["indexArray"] = 91] = "indexArray";
117
+ IRNativeTag[IRNativeTag["bls12_381_G1_multiScalarMul"] = 92] = "bls12_381_G1_multiScalarMul";
118
+ IRNativeTag[IRNativeTag["bls12_381_G2_multiScalarMul"] = 93] = "bls12_381_G2_multiScalarMul";
119
+ IRNativeTag[IRNativeTag["insertCoin"] = 94] = "insertCoin";
120
+ IRNativeTag[IRNativeTag["lookupCoin"] = 95] = "lookupCoin";
121
+ IRNativeTag[IRNativeTag["unionValue"] = 96] = "unionValue";
122
+ IRNativeTag[IRNativeTag["valueContains"] = 97] = "valueContains";
123
+ IRNativeTag[IRNativeTag["valueData"] = 98] = "valueData";
124
+ IRNativeTag[IRNativeTag["unValueData"] = 99] = "unValueData";
125
+ IRNativeTag[IRNativeTag["scaleValue"] = 100] = "scaleValue";
111
126
  ////////////////////////////////////////////////////////////////////////////////
112
127
  // -------------------------------------------------------------------------- //
113
128
  // -------------------------- here starts the fun -------------------------- //
114
129
  // -------------------------------------------------------------------------- //
115
130
  ////////////////////////////////////////////////////////////////////////////////
116
- IRNativeTag[IRNativeTag["_dropList"] = -4] = "_dropList";
131
+ // _dropList = -4,
117
132
  IRNativeTag[IRNativeTag["_foldr"] = -6] = "_foldr";
118
133
  IRNativeTag[IRNativeTag["_foldl"] = -7] = "_foldl";
119
134
  // _mkFindDataOptional = -8,
@@ -159,13 +174,20 @@ export var IRNativeTag;
159
174
  IRNativeTag[IRNativeTag["_increment"] = -46] = "_increment";
160
175
  IRNativeTag[IRNativeTag["_decrement"] = -47] = "_decrement";
161
176
  IRNativeTag[IRNativeTag["_lookupLinearMap"] = -48] = "_lookupLinearMap";
177
+ /** partial application of `scaleValue` with -1 — negates a native Value. */
178
+ IRNativeTag[IRNativeTag["_negateValue"] = -49] = "_negateValue";
179
+ /**
180
+ * `\a b -> valueContains(a, b) && valueContains(b, a)` — equality on
181
+ * canonical Values. Short-circuits on the first inequality.
182
+ */
183
+ IRNativeTag[IRNativeTag["_valueEq"] = -50] = "_valueEq";
162
184
  })(IRNativeTag || (IRNativeTag = {}));
163
185
  Object.freeze(IRNativeTag);
164
186
  export function nativeTagToString(nativeTag) {
165
187
  if (nativeTag >= 0)
166
188
  return builtinTagToString(nativeTag);
167
189
  switch (nativeTag) {
168
- case IRNativeTag._dropList: return "dropList";
190
+ // case IRNativeTag._dropList : return "dropList";
169
191
  case IRNativeTag._foldr: return "foldr";
170
192
  case IRNativeTag._foldl: return "foldl";
171
193
  // case IRNativeTag._mkFindDataOptional : return "mkFind";
@@ -205,6 +227,8 @@ export function nativeTagToString(nativeTag) {
205
227
  case IRNativeTag._increment: return "increment";
206
228
  case IRNativeTag._decrement: return "decrement";
207
229
  case IRNativeTag._lookupLinearMap: return "lookupLinearMap";
230
+ case IRNativeTag._negateValue: return "negateValue";
231
+ case IRNativeTag._valueEq: return "valueEq";
208
232
  default: return "";
209
233
  }
210
234
  }
@@ -128,7 +128,20 @@ export declare class IRNative implements IIRTerm, Cloneable<IRNative>, IIRParent
128
128
  static get countSetBits(): IRNative;
129
129
  static get findFirstSetBit(): IRNative;
130
130
  static get ripemd_160(): IRNative;
131
- static get _dropList(): IRNative;
131
+ static get expModInteger(): IRNative;
132
+ static get dropList(): IRNative;
133
+ static get lengthOfArray(): IRNative;
134
+ static get listToArray(): IRNative;
135
+ static get indexArray(): IRNative;
136
+ static get bls12_381_G1_multiScalarMul(): IRNative;
137
+ static get bls12_381_G2_multiScalarMul(): IRNative;
138
+ static get insertCoin(): IRNative;
139
+ static get lookupCoin(): IRNative;
140
+ static get unionValue(): IRNative;
141
+ static get valueContains(): IRNative;
142
+ static get valueData(): IRNative;
143
+ static get unValueData(): IRNative;
144
+ static get scaleValue(): IRNative;
132
145
  static get _foldr(): IRNative;
133
146
  static get _foldl(): IRNative;
134
147
  static get _length(): IRNative;
@@ -164,6 +177,8 @@ export declare class IRNative implements IIRTerm, Cloneable<IRNative>, IIRParent
164
177
  static get _increment(): IRNative;
165
178
  static get _decrement(): IRNative;
166
179
  static get _isZero(): IRNative;
180
+ static get _negateValue(): IRNative;
181
+ static get _valueEq(): IRNative;
167
182
  static equals(type: TirType): IRTerm;
168
183
  static equalListOf(type: TirType): IRHoisted;
169
184
  }
@@ -6,6 +6,7 @@ import { isObject } from "@harmoniclabs/obj-utils";
6
6
  import { IRNodeKind } from "../../IRNodeKind.js";
7
7
  import { getUnaliased } from "../../../compiler/tir/types/utils/getUnaliased.js";
8
8
  import { TirDataStructType } from "../../../compiler/tir/types/TirStructType.js";
9
+ import { TirEnumType } from "../../../compiler/tir/types/TirEnumType.js";
9
10
  import { TirAliasType } from "../../../compiler/tir/types/TirAliasType.js";
10
11
  import { getListTypeArg } from "../../../compiler/tir/types/utils/getListTypeArg.js";
11
12
  import { TirBlsG1T, TirBlsG2T, TirMlResultT, TirPairDataT, TirUnConstrDataResultT } from "../../../compiler/tir/types/TirNativeType/index.js";
@@ -13,6 +14,8 @@ import { TirBoolT } from "../../../compiler/tir/types/TirNativeType/native/bool.
13
14
  import { TirBytesT } from "../../../compiler/tir/types/TirNativeType/native/bytes.js";
14
15
  import { TirDataT } from "../../../compiler/tir/types/TirNativeType/native/data.js";
15
16
  import { TirIntT } from "../../../compiler/tir/types/TirNativeType/native/int.js";
17
+ import { TirArrayT } from "../../../compiler/tir/types/TirNativeType/native/array.js";
18
+ import { TirValueT } from "../../../compiler/tir/types/TirNativeType/native/value.js";
16
19
  import { TirLinearMapT } from "../../../compiler/tir/types/TirNativeType/native/linearMap.js";
17
20
  import { TirLinearMapEntryT } from "../../../compiler/tir/types/TirNativeType/native/linearMapEntry.js";
18
21
  import { TirListT } from "../../../compiler/tir/types/TirNativeType/native/list.js";
@@ -182,7 +185,21 @@ export class IRNative {
182
185
  static get countSetBits() { return new IRNative(IRNativeTag.countSetBits); }
183
186
  static get findFirstSetBit() { return new IRNative(IRNativeTag.findFirstSetBit); }
184
187
  static get ripemd_160() { return new IRNative(IRNativeTag.ripemd_160); }
185
- static get _dropList() { return new IRNative(IRNativeTag._dropList); }
188
+ // Chang2
189
+ static get expModInteger() { return new IRNative(IRNativeTag.expModInteger); }
190
+ static get dropList() { return new IRNative(IRNativeTag.dropList); }
191
+ static get lengthOfArray() { return new IRNative(IRNativeTag.lengthOfArray); }
192
+ static get listToArray() { return new IRNative(IRNativeTag.listToArray); }
193
+ static get indexArray() { return new IRNative(IRNativeTag.indexArray); }
194
+ static get bls12_381_G1_multiScalarMul() { return new IRNative(IRNativeTag.bls12_381_G1_multiScalarMul); }
195
+ static get bls12_381_G2_multiScalarMul() { return new IRNative(IRNativeTag.bls12_381_G2_multiScalarMul); }
196
+ static get insertCoin() { return new IRNative(IRNativeTag.insertCoin); }
197
+ static get lookupCoin() { return new IRNative(IRNativeTag.lookupCoin); }
198
+ static get unionValue() { return new IRNative(IRNativeTag.unionValue); }
199
+ static get valueContains() { return new IRNative(IRNativeTag.valueContains); }
200
+ static get valueData() { return new IRNative(IRNativeTag.valueData); }
201
+ static get unValueData() { return new IRNative(IRNativeTag.unValueData); }
202
+ static get scaleValue() { return new IRNative(IRNativeTag.scaleValue); }
186
203
  static get _foldr() { return new IRNative(IRNativeTag._foldr); }
187
204
  static get _foldl() { return new IRNative(IRNativeTag._foldl); }
188
205
  // static get _mkFindDataOptional() { return new IRNative( IRNativeTag._mkFindDataOptional ); }
@@ -221,12 +238,16 @@ export class IRNative {
221
238
  static get _increment() { return new IRNative(IRNativeTag._increment); }
222
239
  static get _decrement() { return new IRNative(IRNativeTag._decrement); }
223
240
  static get _isZero() { return new IRNative(IRNativeTag._isZero); }
241
+ static get _negateValue() { return new IRNative(IRNativeTag._negateValue); }
242
+ static get _valueEq() { return new IRNative(IRNativeTag._valueEq); }
224
243
  static equals(type) {
225
244
  type = getUnaliased(type);
226
245
  if (type instanceof TirAliasType)
227
246
  throw new Error("unreachable");
228
247
  if (type instanceof TirIntT)
229
248
  return IRNative.equalsInteger;
249
+ if (type instanceof TirEnumType)
250
+ return IRNative.equalsInteger;
230
251
  if (type instanceof TirBytesT)
231
252
  return IRNative.equalsByteString;
232
253
  if (type instanceof TirStringT)
@@ -249,9 +270,13 @@ export class IRNative {
249
270
  return getEqUnConstr();
250
271
  if (type instanceof TirVoidT)
251
272
  return getEqVoid();
273
+ // Native Value: equality via bidirectional valueContains
274
+ if (type instanceof TirValueT)
275
+ return IRNative._valueEq;
252
276
  if (type instanceof TirBlsG1T
253
277
  || type instanceof TirBlsG2T
254
- || type instanceof TirMlResultT)
278
+ || type instanceof TirMlResultT
279
+ || type instanceof TirArrayT)
255
280
  throw new Error("invalid type for std equality");
256
281
  const tsEnsureExsaustiveCheck = type;
257
282
  throw new Error("invalid type for std equality");
@@ -1,2 +1 @@
1
- export declare function __VERY_UNSAFE_FORGET_VAR_SYM_HASHES_ONLY_USE_AT_END_OF_UPLC_COMPILATION(): void;
2
1
  export declare function hashVarSym(s: symbol): Uint8Array;
@@ -1,36 +1,30 @@
1
- // HASH GENERATOR
2
1
  import { fromHex } from "@harmoniclabs/uint8array-utils";
3
- const MAX_SAFE_INTEGER = Number(globalThis.Number?.MAX_SAFE_INTEGER ?? ((2 ** 53) - 1));
4
- const MIN_SAFE_INTEGER = Number(globalThis.Number?.MIN_SAFE_INTEGER ?? -MAX_SAFE_INTEGER);
5
- const _sym_to_hash = new Map();
6
- const _hash_to_sym = new Map();
7
- let _next_hash = MIN_SAFE_INTEGER;
8
- const unusedHashes = [];
9
- function _collectUnusedHashes() {
10
- for (const [h, s] of _hash_to_sym) {
11
- if (!_sym_to_hash.has(s)) {
12
- _hash_to_sym.delete(h);
13
- unusedHashes.push(h);
14
- }
15
- }
16
- }
17
- export function __VERY_UNSAFE_FORGET_VAR_SYM_HASHES_ONLY_USE_AT_END_OF_UPLC_COMPILATION() {
18
- _hash_to_sym.clear();
19
- unusedHashes.length = 0;
20
- _next_hash = MIN_SAFE_INTEGER;
21
- }
2
+ /**
3
+ * Stable per-symbol bytes used as the preimage contribution of an
4
+ * `IRVar` / self-reference when hashing.
5
+ *
6
+ * Each distinct symbol is assigned a unique 8-byte id the first time it
7
+ * is hashed; subsequent calls for the same symbol return the same bytes.
8
+ * This makes hashing a pure function of the (symbol-identity) content,
9
+ * so a term's hash is stable for the life of the process — exactly what
10
+ * content-addressed `IRHash` requires.
11
+ *
12
+ * No global state needs resetting:
13
+ * - the map is a `WeakMap`, so a symbol's entry is collected once the
14
+ * symbol itself is unreachable (no unbounded growth);
15
+ * - the counter is monotonic and never rewinds, so a symbol can never
16
+ * be reassigned a colliding id (the bug that the old reset-based
17
+ * scheme introduced).
18
+ */
19
+ // `any` key: non-registered symbols are valid WeakMap keys at runtime
20
+ // (ES2023 / Node 20+), but older `lib` typings don't model symbol keys.
21
+ const _sym_to_bytes = new WeakMap();
22
+ let _next_id = 0n;
22
23
  export function hashVarSym(s) {
23
- const limitReached = _next_hash >= MAX_SAFE_INTEGER;
24
- if (_next_hash % 0xffff === 0
25
- || limitReached)
26
- _collectUnusedHashes();
27
- if (limitReached
28
- && unusedHashes.length <= 0)
29
- throw new Error("ran out of IR hashes");
30
- const result_hash = unusedHashes.shift() ?? _next_hash++;
31
- _sym_to_hash.set(s, result_hash);
32
- _hash_to_sym.set(result_hash, s);
33
- return fromHex((BigInt(result_hash) + BigInt(MAX_SAFE_INTEGER))
34
- .toString(16)
35
- .padStart(16, "0"));
24
+ let bytes = _sym_to_bytes.get(s);
25
+ if (bytes !== undefined)
26
+ return bytes;
27
+ bytes = fromHex((_next_id++).toString(16).padStart(16, "0"));
28
+ _sym_to_bytes.set(s, bytes);
29
+ return bytes;
36
30
  }