@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.
Files changed (117) 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/_compileCallExpr.js +57 -10
  40. package/dist/compiler/AstCompiler/internal/exprs/_compileCaseExpr.js +31 -0
  41. package/dist/compiler/AstCompiler/internal/exprs/_compileIsExpr.js +12 -0
  42. package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +36 -0
  43. package/dist/compiler/AstCompiler/internal/exprs/_compileUnaryPrefixExpr.js +13 -1
  44. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileAddExpr.js +18 -5
  45. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileEqualExpr.js +3 -1
  46. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanEqualExpr.js +2 -1
  47. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanExpr.js +2 -1
  48. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanEqualExpr.js +2 -1
  49. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanExpr.js +2 -1
  50. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileMultExpr.js +24 -6
  51. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileNotEqualExpr.js +2 -1
  52. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileSubExpr.js +16 -5
  53. package/dist/compiler/AstCompiler/internal/statements/_compileMatchStmt.js +33 -20
  54. package/dist/compiler/AstCompiler/utils/getPropAccessReturnType.js +11 -0
  55. package/dist/compiler/Compiler.js +20 -27
  56. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +1 -1
  57. package/dist/compiler/TirCompiler/expressify/expressify.js +30 -2
  58. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.d.ts +2 -1
  59. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +45 -7
  60. package/dist/compiler/TirCompiler/expressify/expressifyVars.d.ts +0 -1
  61. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +23 -8
  62. package/dist/compiler/tir/expressions/TirCaseExpr.d.ts +9 -0
  63. package/dist/compiler/tir/expressions/TirCaseExpr.js +144 -122
  64. package/dist/compiler/tir/expressions/TirElemAccessExpr.js +2 -2
  65. package/dist/compiler/tir/expressions/TirFromDataExpr.js +102 -67
  66. package/dist/compiler/tir/expressions/TirIsExpr.js +14 -1
  67. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +1 -2
  68. package/dist/compiler/tir/expressions/TirNativeFunc.js +2 -12
  69. package/dist/compiler/tir/expressions/TirToDataExpr.js +3 -0
  70. package/dist/compiler/tir/expressions/TirTypeConversionExpr.js +10 -0
  71. package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +2 -3
  72. package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +1 -4
  73. package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +20 -3
  74. package/dist/compiler/tir/expressions/ToIRTermCtx.js +48 -3
  75. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +2 -2
  76. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +45 -8
  77. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.d.ts +19 -0
  78. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.js +24 -0
  79. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.d.ts +2 -1
  80. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.js +2 -0
  81. package/dist/compiler/tir/expressions/unary/TirUnaryMinus.js +4 -1
  82. package/dist/compiler/tir/program/stdScope/populateStdNamespace.js +49 -4
  83. package/dist/compiler/tir/program/stdScope/prelude/preludeTypesSrc.js +35 -2
  84. package/dist/compiler/tir/program/stdScope/stdScope.d.ts +7 -0
  85. package/dist/compiler/tir/program/stdScope/stdScope.js +83 -40
  86. package/dist/compiler/tir/types/TirEnumType.d.ts +21 -0
  87. package/dist/compiler/tir/types/TirEnumType.js +36 -0
  88. package/dist/compiler/tir/types/TirNativeType/TirNativeType.d.ts +4 -2
  89. package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +5 -0
  90. package/dist/compiler/tir/types/TirNativeType/native/array.d.ts +16 -0
  91. package/dist/compiler/tir/types/TirNativeType/native/array.js +38 -0
  92. package/dist/compiler/tir/types/TirNativeType/native/index.d.ts +2 -0
  93. package/dist/compiler/tir/types/TirNativeType/native/index.js +2 -0
  94. package/dist/compiler/tir/types/TirNativeType/native/value.d.ts +18 -0
  95. package/dist/compiler/tir/types/TirNativeType/native/value.js +17 -0
  96. package/dist/compiler/tir/types/TirStructType.js +6 -1
  97. package/dist/compiler/tir/types/TirType.d.ts +3 -2
  98. package/dist/compiler/tir/types/TirType.js +4 -1
  99. package/dist/compiler/tir/types/utils/canAssignTo.js +28 -0
  100. package/dist/compiler/tir/types/utils/canCastTo.js +14 -1
  101. package/dist/compiler/tir/types/utils/getDeconstructableType.d.ts +2 -1
  102. package/dist/compiler/tir/types/utils/getDeconstructableType.js +2 -0
  103. package/dist/compiler/tir/types/utils/inferTypeArgs.js +4 -0
  104. package/dist/compiler/tir/types/utils/normalizeEnumToInt.d.ts +10 -0
  105. package/dist/compiler/tir/types/utils/normalizeEnumToInt.js +17 -0
  106. package/dist/compiler/tir/types/utils/substituteTypeParams.js +5 -0
  107. package/dist/diagnostics/diagnosticMessages.generated.d.ts +5 -0
  108. package/dist/diagnostics/diagnosticMessages.generated.js +10 -0
  109. package/dist/parser/Parser.js +29 -13
  110. package/dist/tokenizer/Token.d.ts +8 -7
  111. package/dist/tokenizer/Token.js +8 -7
  112. package/dist/tokenizer/utils/tokenFromKeyword.js +2 -0
  113. package/dist/version.generated.d.ts +1 -1
  114. package/dist/version.generated.js +1 -1
  115. package/package.json +3 -3
  116. package/dist/IR/tree_utils/_ir_lazyChooseList.d.ts +0 -3
  117. package/dist/IR/tree_utils/_ir_lazyChooseList.js +0 -7
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Case-over-Const lowering pass.
3
+ *
4
+ * The UPLC `Case` term accepts a constant scrutinee and reinterprets it
5
+ * as a tag-untagged constructor (bool → 0/1, int N → N, unit → 0,
6
+ * pair → constr 0 [fst, snd], list → constr 1 [] for `[]` or
7
+ * constr 0 [head, tail] for cons).
8
+ *
9
+ * This pass replaces canonical `strictIfThenElse(cond, then, else)`
10
+ * sequences with the equivalent `IRCase(cond, [else, then])` form. The
11
+ * machine resolves bool=false → constr 0, bool=true → constr 1.
12
+ * This subsumes the strict boolean helpers (`_not`, `_strictAnd`,
13
+ * `_strictOr`) whose hoisted bodies are themselves `strictIfThenElse`
14
+ * triple-apps — they get lowered inside their hoisted definitions.
15
+ *
16
+ * It also replaces the LAZY pattern emitted by `_ir_lazyIfThenElse`:
17
+ *
18
+ * IRForced( strictIfThenElse cond (delay t) (delay e) )
19
+ *
20
+ * — which is how `&&`, `||` and pebble `if/else` are encoded today —
21
+ * with `IRCase(cond, [e, t])`. Branches under `Case` are naturally
22
+ * lazy, so the surrounding `force`/`delay` indirection is dropped.
23
+ *
24
+ * It also prunes trailing IRError continuations: a missing branch is
25
+ * semantically equivalent to an evaluation-failure branch, so dropping a
26
+ * trailing `IRError` reduces script size while preserving meaning.
27
+ *
28
+ * NOTE: `getApplicationTerms` sees through both raw `IRApp` chains AND
29
+ * the case-constr-app encoding produced earlier in `performUplc…`
30
+ * (i.e. `IRCase(IRConstr(0, [args]), [func])`). We therefore check the
31
+ * app-pattern *before* the IRCase trailing-error pruning so that a case
32
+ * that's really a function call gets unwrapped first.
33
+ */
34
+ import { IRCase } from "../../IRNodes/IRCase.js";
35
+ import { IRDelayed } from "../../IRNodes/IRDelayed.js";
36
+ import { IRError } from "../../IRNodes/IRError.js";
37
+ import { IRForced } from "../../IRNodes/IRForced.js";
38
+ import { IRHoisted } from "../../IRNodes/IRHoisted.js";
39
+ import { IRLetted } from "../../IRNodes/IRLetted.js";
40
+ import { IRNative } from "../../IRNodes/IRNative/index.js";
41
+ import { IRNativeTag } from "../../IRNodes/IRNative/IRNativeTag.js";
42
+ import { IRFunc } from "../../IRNodes/IRFunc.js";
43
+ import { _modifyChildFromTo } from "../_internal/_modifyChildFromTo.js";
44
+ import { getApplicationTerms } from "../utils/getApplicationTerms.js";
45
+ /**
46
+ * `_makeAllNegativeNativesHoisted` wraps every `IRNative` reference in
47
+ * an `IRHoisted` (despite the name, it touches positive tags too), and
48
+ * subsequent sharing passes may further wrap in `IRLetted`. Unwrap so
49
+ * the pattern detector can see the underlying native tag.
50
+ */
51
+ function unwrapToNative(t) {
52
+ while (t instanceof IRHoisted)
53
+ t = t.hoisted;
54
+ while (t instanceof IRLetted)
55
+ t = t.value;
56
+ return t;
57
+ }
58
+ export function rewriteToCaseOverConstAndReturnRoot(term) {
59
+ const stack = [term];
60
+ function modifyTermAndPushToReprocess(current, newTerm) {
61
+ const parent = current.parent;
62
+ if (parent) {
63
+ _modifyChildFromTo(parent, current, newTerm);
64
+ }
65
+ else {
66
+ term = newTerm;
67
+ term.parent = undefined;
68
+ }
69
+ stack.unshift(newTerm);
70
+ }
71
+ while (stack.length > 0) {
72
+ const current = stack.pop();
73
+ // LAZY pattern emitted by `_ir_lazyIfThenElse`:
74
+ // force( strictIfThenElse cond (delay t) (delay e) )
75
+ // Rewrite to a bare `case cond [e, t]` (Case branches are lazy).
76
+ if (current instanceof IRForced) {
77
+ const innerApp = getApplicationTerms(current.forced);
78
+ const innerFunc = innerApp ? unwrapToNative(innerApp.func) : undefined;
79
+ if (innerApp
80
+ && innerFunc instanceof IRNative
81
+ && innerFunc.tag === IRNativeTag.strictIfThenElse
82
+ && innerApp.args.length === 3
83
+ && innerApp.args[1] instanceof IRDelayed
84
+ && innerApp.args[2] instanceof IRDelayed) {
85
+ const cond = innerApp.args[0];
86
+ const tBranch = innerApp.args[1].delayed;
87
+ const eBranch = innerApp.args[2].delayed;
88
+ const newTerm = new IRCase(cond, [eBranch, tBranch]);
89
+ modifyTermAndPushToReprocess(current, newTerm);
90
+ continue;
91
+ }
92
+ // `IRForced(IRCase(s, [b0, b1, …]))` where every branch is
93
+ // either `IRDelayed(v)` or `IRFunc(params, IRDelayed(v))` can
94
+ // be simplified by stripping the force/delay pair: case
95
+ // branches are naturally lazy in UPLC `case`. The
96
+ // wrap typically comes from `_ir_lazyIfThenElse` lowering an
97
+ // `if/else` whose condition then got rewritten to a list-case
98
+ // (e.g. `if(nullList(L)) ...`) — the outer force is left
99
+ // dangling around the resulting IRCase.
100
+ if (current.forced instanceof IRCase) {
101
+ const caseTerm = current.forced;
102
+ const conts = caseTerm.continuations;
103
+ const stripped = [];
104
+ let allOk = true;
105
+ for (let i = 0; i < conts.length; i++) {
106
+ const c = conts[i];
107
+ if (c instanceof IRDelayed) {
108
+ stripped.push(c.delayed);
109
+ }
110
+ else if (c instanceof IRFunc
111
+ && c.body instanceof IRDelayed) {
112
+ stripped.push(new IRFunc(c.params.slice(), c.body.delayed));
113
+ }
114
+ else {
115
+ allOk = false;
116
+ break;
117
+ }
118
+ }
119
+ if (allOk) {
120
+ const newCase = new IRCase(caseTerm.constrTerm.clone(), stripped);
121
+ modifyTermAndPushToReprocess(current, newCase);
122
+ continue;
123
+ }
124
+ }
125
+ stack.unshift(...current.children());
126
+ continue;
127
+ }
128
+ // Application-pattern rewrites (raw IRApp chain OR case-constr-app
129
+ // encoding produced by `performUplcOptimizationsAndReturnRoot`).
130
+ const appTerms = getApplicationTerms(current);
131
+ if (appTerms) {
132
+ const { func, args } = appTerms;
133
+ const unwrappedFunc = unwrapToNative(func);
134
+ // strictIfThenElse cond then else → case cond [else, then]
135
+ if (unwrappedFunc instanceof IRNative
136
+ && unwrappedFunc.tag === IRNativeTag.strictIfThenElse
137
+ && args.length === 3) {
138
+ const [cond, thenBranch, elseBranch] = args;
139
+ const newTerm = new IRCase(cond, [elseBranch, thenBranch]);
140
+ modifyTermAndPushToReprocess(current, newTerm);
141
+ continue;
142
+ }
143
+ // No app-pattern match — but if the node is itself an IRCase
144
+ // (a case-constr-app encoding), we still want trailing-error
145
+ // pruning on the original case, so don't `continue` yet.
146
+ if (!(current instanceof IRCase)) {
147
+ stack.unshift(...current.children());
148
+ continue;
149
+ }
150
+ }
151
+ // Trailing-error pruning on any IRCase node we encounter.
152
+ if (current instanceof IRCase) {
153
+ const conts = current.continuations;
154
+ let lastNonError = conts.length;
155
+ while (lastNonError > 0 && conts[lastNonError - 1] instanceof IRError) {
156
+ lastNonError--;
157
+ }
158
+ if (lastNonError < conts.length && lastNonError > 0) {
159
+ const pruned = new IRCase(current.constrTerm.clone(), Array.from({ length: lastNonError }, (_, i) => conts[i].clone()));
160
+ modifyTermAndPushToReprocess(current, pruned);
161
+ continue;
162
+ }
163
+ stack.unshift(...current.children());
164
+ continue;
165
+ }
166
+ stack.unshift(...current.children());
167
+ }
168
+ return term;
169
+ }
@@ -0,0 +1,15 @@
1
+ import { IRCase } from "../IRNodes/IRCase.js";
2
+ import type { IRTerm } from "../IRTerm.js";
3
+ /**
4
+ * case list of
5
+ * h::t -> caseCons (h, t are bound only if `consParams` is provided)
6
+ * [] -> caseNil
7
+ *
8
+ * Lowers to UPLC `Case`. Branches are naturally lazy, so callers
9
+ * should pass plain (un-delayed) expressions — no `force` is needed around
10
+ * the result.
11
+ */
12
+ export declare function _ir_caseList(listTerm: IRTerm, caseNil: IRTerm, caseCons: IRTerm, consParams?: {
13
+ head: symbol;
14
+ tail: symbol;
15
+ }): IRCase;
@@ -0,0 +1,19 @@
1
+ import { IRCase } from "../IRNodes/IRCase.js";
2
+ import { IRFunc } from "../IRNodes/IRFunc.js";
3
+ /**
4
+ * case list of
5
+ * h::t -> caseCons (h, t are bound only if `consParams` is provided)
6
+ * [] -> caseNil
7
+ *
8
+ * Lowers to UPLC `Case`. Branches are naturally lazy, so callers
9
+ * should pass plain (un-delayed) expressions — no `force` is needed around
10
+ * the result.
11
+ */
12
+ export function _ir_caseList(listTerm, caseNil, caseCons, consParams) {
13
+ const h = consParams?.head ?? Symbol("_caseList_h");
14
+ const t = consParams?.tail ?? Symbol("_caseList_t");
15
+ return new IRCase(listTerm, [
16
+ new IRFunc([h, t], caseCons),
17
+ caseNil
18
+ ]);
19
+ }
@@ -4,9 +4,23 @@ import { HasSourceRange } from "../../HasSourceRange.js";
4
4
  import { SimpleVarDecl } from "./VarDecl/SimpleVarDecl.js";
5
5
  export declare enum StructDeclAstFlags {
6
6
  none = 0,
7
- untaggedSingleConstructor = 1,
7
+ /**
8
+ * Hint that the user used the shortcut single-constructor syntax
9
+ * (`struct Foo { x: int }` rather than `struct Foo { Foo { x: int } }`).
10
+ * Whether the resulting Data encoding is tagged (`constrData(0, ...)`)
11
+ * or untagged (`listData(...)`) is decided by the compiler's
12
+ * `encodingStrategy` option — `"default"` keeps the tagged form for
13
+ * backwards compatibility; `"minimal"` opts shortcut forms in to the
14
+ * untagged form.
15
+ */
16
+ shortcutSingleConstructor = 1,
8
17
  onlyDataEncoding = 2,
9
- onlySopEncoding = 4
18
+ onlySopEncoding = 4,
19
+ /**
20
+ * Explicit `untagged` modifier. Forces the untagged listData encoding
21
+ * regardless of `encodingStrategy`. Requires a single constructor.
22
+ */
23
+ untagged = 8
10
24
  }
11
25
  export declare class StructDecl implements HasSourceRange {
12
26
  readonly name: Identifier;
@@ -1,9 +1,23 @@
1
1
  export var StructDeclAstFlags;
2
2
  (function (StructDeclAstFlags) {
3
3
  StructDeclAstFlags[StructDeclAstFlags["none"] = 0] = "none";
4
- StructDeclAstFlags[StructDeclAstFlags["untaggedSingleConstructor"] = 1] = "untaggedSingleConstructor";
4
+ /**
5
+ * Hint that the user used the shortcut single-constructor syntax
6
+ * (`struct Foo { x: int }` rather than `struct Foo { Foo { x: int } }`).
7
+ * Whether the resulting Data encoding is tagged (`constrData(0, ...)`)
8
+ * or untagged (`listData(...)`) is decided by the compiler's
9
+ * `encodingStrategy` option — `"default"` keeps the tagged form for
10
+ * backwards compatibility; `"minimal"` opts shortcut forms in to the
11
+ * untagged form.
12
+ */
13
+ StructDeclAstFlags[StructDeclAstFlags["shortcutSingleConstructor"] = 1] = "shortcutSingleConstructor";
5
14
  StructDeclAstFlags[StructDeclAstFlags["onlyDataEncoding"] = 2] = "onlyDataEncoding";
6
15
  StructDeclAstFlags[StructDeclAstFlags["onlySopEncoding"] = 4] = "onlySopEncoding";
16
+ /**
17
+ * Explicit `untagged` modifier. Forces the untagged listData encoding
18
+ * regardless of `encodingStrategy`. Requires a single constructor.
19
+ */
20
+ StructDeclAstFlags[StructDeclAstFlags["untagged"] = 8] = "untagged";
7
21
  })(StructDeclAstFlags || (StructDeclAstFlags = {}));
8
22
  export class StructDecl {
9
23
  name;
@@ -117,6 +117,7 @@ export declare class AstCompiler extends DiagnosticEmitter {
117
117
  private _collectTypeDeclarations;
118
118
  private _compileStructDecl;
119
119
  private _compileTypeAliasDecl;
120
+ private _compileEnumDecl;
120
121
  private _consumeImportsAddSymsInScope;
121
122
  private _readFile;
122
123
  /** MUST NOT be used as a "seen" log */
@@ -1,5 +1,6 @@
1
1
  import { StructDecl, StructDeclAstFlags } from "../../ast/nodes/statements/declarations/StructDecl.js";
2
2
  import { TypeAliasDecl } from "../../ast/nodes/statements/declarations/TypeAliasDecl.js";
3
+ import { EnumDecl } from "../../ast/nodes/statements/declarations/EnumDecl.js";
3
4
  import { ExportStarStmt } from "../../ast/nodes/statements/ExportStarStmt.js";
4
5
  import { ImportStarStmt } from "../../ast/nodes/statements/ImportStarStmt.js";
5
6
  import { ImportStmt } from "../../ast/nodes/statements/ImportStmt.js";
@@ -12,6 +13,7 @@ import { createMemoryCompilerIoApi } from "../io/CompilerIoApi.js";
12
13
  import { TypedProgram } from "../tir/program/TypedProgram.js";
13
14
  import { TirAliasType } from "../tir/types/TirAliasType.js";
14
15
  import { TirDataStructType, TirSoPStructType, TirStructConstr, TirStructField } from "../tir/types/TirStructType.js";
16
+ import { TirEnumType } from "../tir/types/TirEnumType.js";
15
17
  import { ExportStmt } from "../../ast/nodes/statements/ExportStmt.js";
16
18
  import { ResolveStackNode } from "./utils/deps/ResolveStackNode.js";
17
19
  import { AstCompilationCtx } from "./AstCompilationCtx.js";
@@ -675,12 +677,15 @@ export class AstCompiler extends DiagnosticEmitter {
675
677
  stmt = stmt.stmt;
676
678
  }
677
679
  if (!(stmt instanceof StructDecl
678
- || stmt instanceof TypeAliasDecl))
680
+ || stmt instanceof TypeAliasDecl
681
+ || stmt instanceof EnumDecl))
679
682
  continue;
680
- const isGeneric = stmt.typeParams.length > 0;
683
+ const isGeneric = stmt instanceof EnumDecl ? false : stmt.typeParams.length > 0;
681
684
  const tirTypes = stmt instanceof StructDecl
682
685
  ? this._compileStructDecl(stmt, srcUid, topLevelScope)
683
- : this._compileTypeAliasDecl(stmt, srcUid, topLevelScope);
686
+ : stmt instanceof EnumDecl
687
+ ? this._compileEnumDecl(stmt, srcUid, topLevelScope)
688
+ : this._compileTypeAliasDecl(stmt, srcUid, topLevelScope);
684
689
  if (!tirTypes // undefined
685
690
  || !(tirTypes.sop || tirTypes.data) // or both undefined
686
691
  )
@@ -743,6 +748,16 @@ export class AstCompiler extends DiagnosticEmitter {
743
748
  // data encoded type
744
749
  if (!stmt.hasFlag(StructDeclAstFlags.onlySopEncoding)) {
745
750
  let canEncodeToData = true;
751
+ // Untagged Data encoding (`listData(...)`) instead of
752
+ // `constrData(0, ...)`. Requires exactly one constructor and is
753
+ // enabled by either the explicit `untagged` keyword or the
754
+ // shortcut-form syntax when `encodingStrategy === "minimal"`.
755
+ const isUntagged = stmt.constrs.length === 1 && (stmt.hasFlag(StructDeclAstFlags.untagged)
756
+ || (stmt.hasFlag(StructDeclAstFlags.shortcutSingleConstructor)
757
+ && this.cfg.encodingStrategy === "minimal"));
758
+ if (stmt.hasFlag(StructDeclAstFlags.untagged) && stmt.constrs.length !== 1) {
759
+ this.error(DiagnosticCode.Not_implemented_0, stmt.name.range, "`untagged` struct must have exactly one constructor");
760
+ }
746
761
  const dataType = new TirDataStructType(stmt.name.text, srcUid, stmt.constrs.map(ctor => new TirStructConstr(ctor.name.text, ctor.fields.map(field => {
747
762
  if (!field.type)
748
763
  return compiler.error(DiagnosticCode.Type_expected, field.name.range.atEnd());
@@ -756,7 +771,7 @@ export class AstCompiler extends DiagnosticEmitter {
756
771
  }
757
772
  return new TirStructField(field.name.text, fieldType);
758
773
  })
759
- .filter(f => f instanceof TirStructField))), methodsNames);
774
+ .filter(f => f instanceof TirStructField))), methodsNames, isUntagged);
760
775
  if (canEncodeToData)
761
776
  data = dataType;
762
777
  else if (stmt.hasFlag(StructDeclAstFlags.onlyDataEncoding))
@@ -779,6 +794,28 @@ export class AstCompiler extends DiagnosticEmitter {
779
794
  ) : undefined;
780
795
  return sop || data ? { sop, data, methodsNames } : undefined;
781
796
  }
797
+ _compileEnumDecl(stmt, srcUid, _topLevelScope) {
798
+ if (stmt.members.length === 0) {
799
+ this.error(DiagnosticCode.Enum_must_have_at_least_one_member, stmt.name.range);
800
+ return undefined;
801
+ }
802
+ const seen = new Set();
803
+ const memberNames = [];
804
+ for (const m of stmt.members) {
805
+ if (m.value !== undefined) {
806
+ this.error(DiagnosticCode.Enum_members_cannot_have_explicit_values, m.range);
807
+ }
808
+ if (seen.has(m.name.text)) {
809
+ this.error(DiagnosticCode.Duplicate_enum_member_0, m.name.range, m.name.text);
810
+ continue;
811
+ }
812
+ seen.add(m.name.text);
813
+ memberNames.push(m.name.text);
814
+ }
815
+ const methodsNames = new Map();
816
+ const enumType = new TirEnumType(stmt.name.text, srcUid, memberNames, methodsNames);
817
+ return { sop: enumType, data: enumType, methodsNames };
818
+ }
782
819
  _consumeImportsAddSymsInScope(stmts, srcAbsPath, srcImportsScope) {
783
820
  for (let i = 0; i < stmts.length; i++) {
784
821
  const stmt = stmts[i];
@@ -784,7 +784,7 @@ function _exprReplaceParamsAndAssertNoLitContext(compiler, expr, paramsInternalN
784
784
  function _deriveContractDatumTypeDef(contractName, stateDecls, contractRange) {
785
785
  let defFlags = StructDeclAstFlags.onlyDataEncoding;
786
786
  if (stateDecls.length <= 1)
787
- defFlags |= StructDeclAstFlags.untaggedSingleConstructor;
787
+ defFlags |= StructDeclAstFlags.shortcutSingleConstructor;
788
788
  return new StructDecl(new Identifier(contractName, contractRange), [], // typeParams
789
789
  stateDecls.map(s => new StructConstrDecl(new Identifier(s.name.text, s.name.range), s.fields, s.range)), defFlags, contractRange);
790
790
  }
@@ -855,7 +855,7 @@ function _buildSpendCaseBlock(compiler, contractDecl, paramsInternalNamesMap, ba
855
855
  const perStateStructDecl = new StructDecl(new Identifier(getUniqueInternalName(`${contractDecl.name.text}_${stateDecl.name.text}`), mockRange), [], // typeParams
856
856
  [
857
857
  new StructConstrDecl(new Identifier(stateDecl.name.text, mockRange), stateDecl.fields, stateDecl.range)
858
- ], StructDeclAstFlags.onlyDataEncoding | StructDeclAstFlags.untaggedSingleConstructor, stateDecl.range);
858
+ ], StructDeclAstFlags.onlyDataEncoding | StructDeclAstFlags.shortcutSingleConstructor, stateDecl.range);
859
859
  compiler.registerInternalTypeDecl(perStateStructDecl);
860
860
  const perStateStructName = perStateStructDecl.name.text;
861
861
  // synthesize: const state = StateStruct{ field1: _f1, ... };
@@ -921,7 +921,7 @@ function _buildSpendCaseBlock(compiler, contractDecl, paramsInternalNamesMap, ba
921
921
  function _deriveRedeemerTypeDef(redeemerName, methods, contractRange) {
922
922
  let defFlags = StructDeclAstFlags.onlyDataEncoding;
923
923
  if (methods.length <= 1)
924
- defFlags |= StructDeclAstFlags.untaggedSingleConstructor;
924
+ defFlags |= StructDeclAstFlags.shortcutSingleConstructor;
925
925
  const uniqueName = getUniqueInternalName(redeemerName);
926
926
  return new StructDecl(new Identifier(uniqueName, SourceRange.mock), [], // typeParams
927
927
  methods.map(m => {
@@ -1,3 +1,4 @@
1
+ import { FuncExpr } from "../../../../ast/nodes/expr/functions/FuncExpr.js";
1
2
  import { DiagnosticCode } from "../../../../diagnostics/diagnosticMessages.generated.js";
2
3
  import { TirCallExpr } from "../../../tir/expressions/TirCallExpr.js";
3
4
  import { TirFuncT } from "../../../tir/types/TirNativeType/native/function.js";
@@ -48,15 +49,62 @@ export function _compileCallExpr(ctx, expr, typeHint) {
48
49
  }
49
50
  // 2) Compile arguments. We need them anyway, and they're used for
50
51
  // inference when no explicit args were given.
51
- const tirArgs = expr.args.map((arg, i) => {
52
- const expected = explicitArgs
53
- ? substituteTypeParams(funcType.argTypes[i], new Map(template.typeParams.map((tp, idx) => [tp.symbol, explicitArgs[idx]])))
54
- : undefined;
55
- return _compileExpr(ctx, arg, expected);
56
- });
57
- for (const a of tirArgs)
58
- if (!a)
59
- return undefined;
52
+ //
53
+ // For inferred-type-args calls, lambda arguments cannot be compiled
54
+ // without an expected function type (their param types would be
55
+ // unannotated). So we compile non-lambda args first, build an
56
+ // inference environment from them, then compile lambda args with
57
+ // the substituted expected type from `funcType.argTypes[i]`.
58
+ const tirArgs = new Array(expr.args.length);
59
+ const usable = Math.min(expr.args.length, funcType.argTypes.length);
60
+ if (explicitArgs) {
61
+ const explicitSubst = new Map(template.typeParams.map((tp, idx) => [tp.symbol, explicitArgs[idx]]));
62
+ for (let i = 0; i < expr.args.length; i++) {
63
+ const expected = i < funcType.argTypes.length
64
+ ? substituteTypeParams(funcType.argTypes[i], explicitSubst)
65
+ : undefined;
66
+ const compiled = _compileExpr(ctx, expr.args[i], expected);
67
+ if (!compiled)
68
+ return undefined;
69
+ tirArgs[i] = compiled;
70
+ }
71
+ }
72
+ else {
73
+ const env = new Map();
74
+ // Pass 1: compile non-FuncExpr args (no type hint needed) and
75
+ // populate `env` from each arg's resolved type.
76
+ for (let i = 0; i < expr.args.length; i++) {
77
+ if (expr.args[i] instanceof FuncExpr)
78
+ continue;
79
+ const compiled = _compileExpr(ctx, expr.args[i], undefined);
80
+ if (!compiled)
81
+ return undefined;
82
+ tirArgs[i] = compiled;
83
+ if (i < usable) {
84
+ if (!inferTypeArgs(funcType.argTypes[i], compiled.type, env))
85
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.args[i].range, compiled.type.toString(), funcType.argTypes[i].toString());
86
+ }
87
+ }
88
+ // Pass 2: compile FuncExpr args with the substituted expected
89
+ // type so lambda param types can be inferred from context.
90
+ for (let i = 0; i < expr.args.length; i++) {
91
+ if (!(expr.args[i] instanceof FuncExpr))
92
+ continue;
93
+ const expected = i < funcType.argTypes.length
94
+ ? substituteTypeParams(funcType.argTypes[i], env)
95
+ : undefined;
96
+ const compiled = _compileExpr(ctx, expr.args[i], expected);
97
+ if (!compiled)
98
+ return undefined;
99
+ tirArgs[i] = compiled;
100
+ if (i < usable) {
101
+ // re-run to capture type params bound only via the
102
+ // lambda's return type (e.g. `map<T, A>(f: (T) -> A, ...)`)
103
+ if (!inferTypeArgs(funcType.argTypes[i], compiled.type, env))
104
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.args[i].range, compiled.type.toString(), funcType.argTypes[i].toString());
105
+ }
106
+ }
107
+ }
60
108
  // 3) Determine final type arguments
61
109
  let resolvedArgs;
62
110
  if (explicitArgs) {
@@ -64,7 +112,6 @@ export function _compileCallExpr(ctx, expr, typeHint) {
64
112
  }
65
113
  else {
66
114
  const env = new Map();
67
- const usable = Math.min(tirArgs.length, funcType.argTypes.length);
68
115
  for (let i = 0; i < usable; i++) {
69
116
  if (!inferTypeArgs(funcType.argTypes[i], tirArgs[i].type, env)) {
70
117
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.args[i].range, tirArgs[i].type.toString(), funcType.argTypes[i].toString());
@@ -1,10 +1,13 @@
1
1
  import { Identifier } from "../../../../ast/nodes/common/Identifier.js";
2
2
  import { ParentesizedExpr } from "../../../../ast/nodes/expr/ParentesizedExpr.js";
3
+ import { NamedDeconstructVarDecl as AstNamedDeconstructVarDecl } from "../../../../ast/nodes/statements/declarations/VarDecl/NamedDeconstructVarDecl.js";
4
+ import { SimpleVarDecl as AstSimpleVarDecl } from "../../../../ast/nodes/statements/declarations/VarDecl/SimpleVarDecl.js";
3
5
  import { DiagnosticCode } from "../../../../diagnostics/diagnosticMessages.generated.js";
4
6
  import { TirCaseExpr, TirCaseMatcher, TirWildcardCaseMatcher } from "../../../tir/expressions/TirCaseExpr.js";
5
7
  import { TirNamedDeconstructVarDecl } from "../../../tir/statements/TirVarDecl/TirNamedDeconstructVarDecl.js";
6
8
  import { TirSimpleVarDecl } from "../../../tir/statements/TirVarDecl/TirSimpleVarDecl.js";
7
9
  import { TirDataStructType, TirSoPStructType } from "../../../tir/types/TirStructType.js";
10
+ import { getEnumType } from "../../../tir/types/TirEnumType.js";
8
11
  import { canAssignTo, getStructType } from "../../../tir/types/utils/canAssignTo.js";
9
12
  import { _compileVarDecl } from "../statements/_compileVarStmt.js";
10
13
  import { _compileExpr } from "./_compileExpr.js";
@@ -29,6 +32,34 @@ export function _compileCaseExpr(ctx, expr, typeHint) {
29
32
  return new TirCaseExpr(matchExpr, cases, wildcardCase, returnType, expr.range);
30
33
  }
31
34
  export function _compileCaseExprMatcher(ctx, matcher, patternType, returnTypeHint, matchedVarName) {
35
+ const enumType = getEnumType(patternType);
36
+ if (enumType) {
37
+ const astPattern = matcher.pattern;
38
+ let memberName;
39
+ let patternRange = astPattern.range;
40
+ let ctorNameRange = astPattern.range;
41
+ if (astPattern instanceof AstSimpleVarDecl) {
42
+ memberName = astPattern.name.text;
43
+ patternRange = astPattern.name.range;
44
+ ctorNameRange = astPattern.name.range;
45
+ }
46
+ else if (astPattern instanceof AstNamedDeconstructVarDecl) {
47
+ if (astPattern.fields.size > 0 || astPattern.rest)
48
+ return ctx.error(DiagnosticCode.Enum_member_pattern_cannot_have_fields, astPattern.range);
49
+ memberName = astPattern.name.text;
50
+ ctorNameRange = astPattern.name.range;
51
+ }
52
+ else
53
+ return ctx.error(DiagnosticCode._case_expression_must_decontructed_the_inspected_value, astPattern.range);
54
+ if (enumType.indexOf(memberName) < 0)
55
+ return ctx.error(DiagnosticCode.Constructor_0_is_not_part_of_the_definition_of_1, ctorNameRange, memberName, enumType.toString());
56
+ const body = _compileExpr(ctx, matcher.body, returnTypeHint);
57
+ if (!body)
58
+ return undefined;
59
+ if (returnTypeHint && !canAssignTo(body.type, returnTypeHint))
60
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, matcher.body.range, body.type.toString(), returnTypeHint.toString());
61
+ return new TirCaseMatcher(new TirNamedDeconstructVarDecl(memberName, new Map(), undefined, enumType, undefined, true, patternRange, ctorNameRange), body, matcher.range);
62
+ }
32
63
  const pattern = _compileVarDecl(ctx, matcher.pattern, patternType);
33
64
  if (!pattern)
34
65
  return undefined;
@@ -1,5 +1,6 @@
1
1
  import { DiagnosticCode } from "../../../../diagnostics/diagnosticMessages.generated.js";
2
2
  import { TirIsExpr } from "../../../tir/expressions/TirIsExpr.js";
3
+ import { getEnumType } from "../../../tir/types/TirEnumType.js";
3
4
  import { getStructType } from "../../../tir/types/utils/canAssignTo.js";
4
5
  import { _compileExpr } from "./_compileExpr.js";
5
6
  export function _compileIsExpr(ctx, expr, _typeHint) {
@@ -7,6 +8,17 @@ export function _compileIsExpr(ctx, expr, _typeHint) {
7
8
  const target = _compileExpr(ctx, expr.instanceExpr, undefined);
8
9
  if (!target)
9
10
  return undefined;
11
+ const enumType = getEnumType(target.type);
12
+ if (enumType) {
13
+ const memberName = expr.ofConstr.text;
14
+ const memberIdx = enumType.indexOf(memberName);
15
+ if (memberIdx < 0)
16
+ return ctx.error(DiagnosticCode.Constructor_0_is_not_part_of_the_definition_of_1, expr.ofConstr.range, memberName, enumType.toString());
17
+ if (enumType.members.length === 1) {
18
+ ctx.warning(DiagnosticCode.This_check_is_redundant_Struct_0_has_only_one_possible_constructor, expr.range, enumType.toString());
19
+ }
20
+ return new TirIsExpr(target, memberName, memberIdx, expr.range, bool_t);
21
+ }
10
22
  const structType = getStructType(target.type);
11
23
  if (!structType)
12
24
  return ctx.error(DiagnosticCode.Cannot_use_is_operator_on_a_value_that_is_not_a_struct_type, expr.instanceExpr.range);
@@ -15,8 +15,10 @@ import { tryResolveNamespaceChain } from "../../utils/resolveNamespaceChain.js";
15
15
  import { _compileExpr } from "./_compileExpr.js";
16
16
  import { _compileNonNullExpr } from "./_compileNonNullExpr.js";
17
17
  import { TirLitNamedObjExpr } from "../../../tir/expressions/litteral/TirLitNamedObjExpr.js";
18
+ import { TirLitEnumMemberExpr } from "../../../tir/expressions/litteral/TirLitEnumMemberExpr.js";
18
19
  import { Identifier } from "../../../../ast/nodes/common/Identifier.js";
19
20
  import { TirSopOptT } from "../../../tir/types/TirNativeType/native/Optional/sop.js";
21
+ import { TirEnumType } from "../../../tir/types/TirEnumType.js";
20
22
  export function _compilePropAccessExpr(ctx, expr, typeHint) {
21
23
  if (expr instanceof OptionalPropAccessExpr)
22
24
  return _compileOptionalPropAccessExpr(ctx, expr, typeHint);
@@ -95,6 +97,12 @@ export function _compileNonNullPropAccessExpr(ctx, expr, _typeHint) {
95
97
  return _compileDotPropAccessExpr(ctx, new DotPropAccessExpr(nonNullObjExpr, expr.prop, expr.range), _typeHint);
96
98
  }
97
99
  export function _compileDotPropAccessExpr(ctx, expr, _typeHint) {
100
+ // Enum member access: `EnumName.Member`
101
+ if (expr.object instanceof Identifier) {
102
+ const enumRes = _tryResolveEnumMemberAccess(ctx, expr.object, expr.prop, expr);
103
+ if (enumRes)
104
+ return enumRes;
105
+ }
98
106
  // if the LHS is a (chain of) identifier(s) rooted at a namespace, resolve
99
107
  // the entire dotted chain through namespaces.
100
108
  const nsRes = tryResolveNamespaceChain(ctx, expr);
@@ -128,3 +136,31 @@ export function _compileDotPropAccessExpr(ctx, expr, _typeHint) {
128
136
  return ctx.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, expr.prop.range, expr.prop.text, objType.toString());
129
137
  return new TirPropAccessExpr(objExpr, expr.prop, returnType, expr.range);
130
138
  }
139
+ /**
140
+ * Returns a `TirLitEnumMemberExpr` if `objId` resolves to an enum type
141
+ * in scope and `propId` is one of its members.
142
+ * Emits a diagnostic and returns a placeholder failure (undefined) if the
143
+ * type is an enum but `propId` is not a member.
144
+ * Returns `undefined` (silently) if `objId` is not an enum-typed identifier
145
+ * — caller falls back to other resolution strategies.
146
+ */
147
+ function _tryResolveEnumMemberAccess(ctx, objId, propId, fullExpr) {
148
+ // skip if the identifier names a value in scope (variables shadow types)
149
+ if (ctx.scope.resolveValue(objId.text))
150
+ return undefined;
151
+ const possibleTirTypes = ctx.scope.resolveType(objId.text);
152
+ if (!possibleTirTypes)
153
+ return undefined;
154
+ const tirType = ctx.program.types.get(possibleTirTypes.sopTirName)
155
+ ?? (possibleTirTypes.dataTirName
156
+ ? ctx.program.types.get(possibleTirTypes.dataTirName)
157
+ : undefined);
158
+ if (!(tirType instanceof TirEnumType))
159
+ return undefined;
160
+ const memberIdx = tirType.indexOf(propId.text);
161
+ if (memberIdx < 0) {
162
+ ctx.error(DiagnosticCode.Property_0_is_not_a_member_of_enum_1, propId.range, propId.text, tirType.name);
163
+ return undefined;
164
+ }
165
+ return new TirLitEnumMemberExpr(tirType, memberIdx, fullExpr.range);
166
+ }
@@ -7,7 +7,9 @@ import { TirUnaryExclamation } from "../../../tir/expressions/unary/TirUnaryExcl
7
7
  import { TirUnaryMinus } from "../../../tir/expressions/unary/TirUnaryMinus.js";
8
8
  import { TirUnaryPlus } from "../../../tir/expressions/unary/TirUnaryPlus.js";
9
9
  import { TirUnaryTilde } from "../../../tir/expressions/unary/TirUnaryTilde.js";
10
+ import { TirValueT } from "../../../tir/types/TirNativeType/native/value.js";
10
11
  import { canAssignTo, canAssignToOptional } from "../../../tir/types/utils/canAssignTo.js";
12
+ import { getUnaliased } from "../../../tir/types/utils/getUnaliased.js";
11
13
  import { _compileExpr } from "./_compileExpr.js";
12
14
  export function _compileUnaryPrefixExpr(ctx, expr, _typeHint) {
13
15
  const bool_t = ctx.program.stdTypes.bool;
@@ -26,10 +28,20 @@ export function _compileUnaryPrefixExpr(ctx, expr, _typeHint) {
26
28
  }
27
29
  else if (expr instanceof UnaryPlus
28
30
  || expr instanceof UnaryMinus) {
29
- const operand = _compileExpr(ctx, expr.operand, int_t);
31
+ // Probe without hint so we can spot `-Value` (TirValueT) before
32
+ // failing the int check.
33
+ const operand = _compileExpr(ctx, expr.operand, undefined);
30
34
  if (!operand)
31
35
  return undefined;
32
36
  const operandType = operand.type;
37
+ const unaliasedTy = getUnaliased(operandType);
38
+ if (unaliasedTy instanceof TirValueT) {
39
+ // unary plus on Value is the identity; unary minus negates it.
40
+ if (expr instanceof UnaryPlus)
41
+ return new TirUnaryPlus(operand, operandType, expr.range);
42
+ if (expr instanceof UnaryMinus)
43
+ return new TirUnaryMinus(operand, operandType, expr.range);
44
+ }
33
45
  if (!canAssignTo(operandType, int_t)) {
34
46
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.operand.range, operand.type.toString(), "int");
35
47
  }