@harmoniclabs/pebble 0.1.9 → 0.2.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 (97) hide show
  1. package/dist/IR/IRNodes/IRConst.js +14 -3
  2. package/dist/IR/IRNodes/IRNative/index.js +5 -1
  3. package/dist/IR/toUPLC/CompilerOptions.d.ts +22 -7
  4. package/dist/IR/toUPLC/CompilerOptions.js +5 -1
  5. package/dist/IR/tree_utils/bytesToHex.d.ts +8 -0
  6. package/dist/IR/tree_utils/bytesToHex.js +69 -0
  7. package/dist/ast/nodes/expr/functions/FuncExpr.d.ts +16 -2
  8. package/dist/ast/nodes/expr/functions/FuncExpr.js +17 -0
  9. package/dist/ast/nodes/expr/litteral/LitteralExpr.d.ts +2 -1
  10. package/dist/ast/nodes/expr/litteral/LitteralExpr.js +2 -0
  11. package/dist/ast/nodes/expr/litteral/TemplateStrExpr.d.ts +30 -0
  12. package/dist/ast/nodes/expr/litteral/TemplateStrExpr.js +35 -0
  13. package/dist/ast/nodes/statements/ExportStmt.d.ts +3 -3
  14. package/dist/ast/nodes/statements/PebbleStmt.d.ts +4 -3
  15. package/dist/ast/nodes/statements/PebbleStmt.js +6 -2
  16. package/dist/ast/nodes/statements/TestParam.d.ts +18 -0
  17. package/dist/ast/nodes/statements/TestParam.js +18 -0
  18. package/dist/ast/nodes/statements/TestStmt.d.ts +5 -3
  19. package/dist/ast/nodes/statements/TestStmt.js +3 -1
  20. package/dist/ast/nodes/statements/UsingStmt.d.ts +32 -2
  21. package/dist/ast/nodes/statements/UsingStmt.js +39 -3
  22. package/dist/ast/nodes/statements/declarations/NamespaceDecl.d.ts +21 -0
  23. package/dist/ast/nodes/statements/declarations/NamespaceDecl.js +31 -0
  24. package/dist/compiler/AstCompiler/AstCompiler.d.ts +26 -0
  25. package/dist/compiler/AstCompiler/AstCompiler.js +203 -3
  26. package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +14 -4
  27. package/dist/compiler/AstCompiler/internal/exprs/_compileCallExpr.js +97 -6
  28. package/dist/compiler/AstCompiler/internal/exprs/_compileFuncExpr.js +12 -5
  29. package/dist/compiler/AstCompiler/internal/exprs/_compileLitteralExpr.js +59 -0
  30. package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.d.ts +2 -3
  31. package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +28 -0
  32. package/dist/compiler/AstCompiler/internal/exprs/_compileVarAccessExpr.js +2 -0
  33. package/dist/compiler/AstCompiler/internal/statements/_compileStatement.js +4 -1
  34. package/dist/compiler/AstCompiler/internal/statements/_compileTestStmt.d.ts +15 -1
  35. package/dist/compiler/AstCompiler/internal/statements/_compileTestStmt.js +70 -30
  36. package/dist/compiler/AstCompiler/internal/statements/_compileUsingAliasStmt.d.ts +11 -0
  37. package/dist/compiler/AstCompiler/internal/statements/_compileUsingAliasStmt.js +26 -0
  38. package/dist/compiler/AstCompiler/internal/statements/_compileUsingStmt.d.ts +9 -4
  39. package/dist/compiler/AstCompiler/internal/statements/_compileUsingStmt.js +51 -10
  40. package/dist/compiler/AstCompiler/internal/types/_compileDataEncodedConcreteType.js +21 -2
  41. package/dist/compiler/AstCompiler/internal/types/_compileSopEncodedConcreteType.js +17 -2
  42. package/dist/compiler/AstCompiler/scope/AstScope.d.ts +70 -1
  43. package/dist/compiler/AstCompiler/scope/AstScope.js +91 -0
  44. package/dist/compiler/AstCompiler/utils/getPropAccessReturnType.js +25 -1
  45. package/dist/compiler/AstCompiler/utils/monomorphizeGeneric.d.ts +36 -0
  46. package/dist/compiler/AstCompiler/utils/monomorphizeGeneric.js +123 -0
  47. package/dist/compiler/AstCompiler/utils/resolveNamespaceChain.d.ts +28 -0
  48. package/dist/compiler/AstCompiler/utils/resolveNamespaceChain.js +95 -0
  49. package/dist/compiler/AstCompiler/utils/resolveNamespacePath.d.ts +37 -0
  50. package/dist/compiler/AstCompiler/utils/resolveNamespacePath.js +93 -0
  51. package/dist/compiler/Compiler.d.ts +9 -1
  52. package/dist/compiler/Compiler.js +204 -9
  53. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +26 -7
  54. package/dist/compiler/test/TestResult.d.ts +38 -0
  55. package/dist/compiler/test/TestResult.js +6 -0
  56. package/dist/compiler/test/fuzz/PRNG.d.ts +26 -0
  57. package/dist/compiler/test/fuzz/PRNG.js +59 -0
  58. package/dist/compiler/tir/expressions/TirExpr.d.ts +2 -1
  59. package/dist/compiler/tir/expressions/TirExpr.js +2 -0
  60. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +17 -0
  61. package/dist/compiler/tir/expressions/TirNativeFunc.js +53 -106
  62. package/dist/compiler/tir/expressions/TirShowExpr.d.ts +52 -0
  63. package/dist/compiler/tir/expressions/TirShowExpr.js +199 -0
  64. package/dist/compiler/tir/expressions/TirTraceExpr.js +11 -7
  65. package/dist/compiler/tir/program/TypedProgram.d.ts +101 -0
  66. package/dist/compiler/tir/program/TypedProgram.js +43 -0
  67. package/dist/compiler/tir/program/stdScope/populateBuiltinInterfaces.d.ts +17 -0
  68. package/dist/compiler/tir/program/stdScope/populateBuiltinInterfaces.js +70 -0
  69. package/dist/compiler/tir/program/stdScope/populateStdNamespace.d.ts +22 -0
  70. package/dist/compiler/tir/program/stdScope/populateStdNamespace.js +574 -0
  71. package/dist/compiler/tir/program/stdScope/stdScope.d.ts +1 -0
  72. package/dist/compiler/tir/program/stdScope/stdScope.js +1 -1
  73. package/dist/compiler/tir/statements/TirStmt.js +0 -1
  74. package/dist/compiler/tir/statements/TirTestStmt.d.ts +46 -0
  75. package/dist/compiler/tir/statements/TirTestStmt.js +35 -0
  76. package/dist/compiler/tir/types/TirNativeType/TirNativeType.d.ts +50 -1
  77. package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +53 -1
  78. package/dist/compiler/tir/types/TirType.js +3 -1
  79. package/dist/compiler/tir/types/utils/canAssignTo.js +8 -1
  80. package/dist/compiler/tir/types/utils/inferTypeArgs.d.ts +19 -0
  81. package/dist/compiler/tir/types/utils/inferTypeArgs.js +79 -0
  82. package/dist/compiler/tir/types/utils/substituteTypeParams.d.ts +9 -0
  83. package/dist/compiler/tir/types/utils/substituteTypeParams.js +62 -0
  84. package/dist/diagnostics/diagnosticMessages.generated.d.ts +5 -0
  85. package/dist/diagnostics/diagnosticMessages.generated.js +10 -0
  86. package/dist/index.d.ts +2 -0
  87. package/dist/index.js +2 -0
  88. package/dist/parser/Parser.d.ts +73 -3
  89. package/dist/parser/Parser.js +333 -33
  90. package/dist/tokenizer/Token.d.ts +105 -102
  91. package/dist/tokenizer/Token.js +110 -109
  92. package/dist/tokenizer/utils/tokenFromKeyword.js +9 -6
  93. package/dist/utils/semverSatisfies.d.ts +1 -0
  94. package/dist/utils/semverSatisfies.js +161 -0
  95. package/dist/version.generated.d.ts +1 -0
  96. package/dist/version.generated.js +2 -0
  97. package/package.json +4 -2
@@ -1,13 +1,17 @@
1
1
  import { OptionalPropAccessExpr, NonNullPropAccessExpr, DotPropAccessExpr } from "../../../../ast/nodes/expr/PropAccessExpr.js";
2
2
  import { NonNullExpr } from "../../../../ast/nodes/expr/unary/NonNullExpr.js";
3
3
  import { DiagnosticCode } from "../../../../diagnostics/diagnosticMessages.generated.js";
4
+ import { TirCallExpr } from "../../../tir/expressions/TirCallExpr.js";
4
5
  import { TirCaseExpr, TirCaseMatcher } from "../../../tir/expressions/TirCaseExpr.js";
6
+ import { TirNativeFunc } from "../../../tir/expressions/TirNativeFunc.js";
5
7
  import { TirPropAccessExpr } from "../../../tir/expressions/TirPropAccessExpr.js";
6
8
  import { TirVariableAccessExpr } from "../../../tir/expressions/TirVariableAccessExpr.js";
7
9
  import { TirNamedDeconstructVarDecl } from "../../../tir/statements/TirVarDecl/TirNamedDeconstructVarDecl.js";
8
10
  import { TirSimpleVarDecl } from "../../../tir/statements/TirVarDecl/TirSimpleVarDecl.js";
11
+ import { TirUnConstrDataResultT } from "../../../tir/types/TirNativeType/index.js";
9
12
  import { getOptTypeArg } from "../../../tir/types/utils/getOptTypeArg.js";
10
13
  import { getPropAccessReturnType } from "../../utils/getPropAccessReturnType.js";
14
+ import { tryResolveNamespaceChain } from "../../utils/resolveNamespaceChain.js";
11
15
  import { _compileExpr } from "./_compileExpr.js";
12
16
  import { _compileNonNullExpr } from "./_compileNonNullExpr.js";
13
17
  import { TirLitNamedObjExpr } from "../../../tir/expressions/litteral/TirLitNamedObjExpr.js";
@@ -91,10 +95,34 @@ export function _compileNonNullPropAccessExpr(ctx, expr, _typeHint) {
91
95
  return _compileDotPropAccessExpr(ctx, new DotPropAccessExpr(nonNullObjExpr, expr.prop, expr.range), _typeHint);
92
96
  }
93
97
  export function _compileDotPropAccessExpr(ctx, expr, _typeHint) {
98
+ // if the LHS is a (chain of) identifier(s) rooted at a namespace, resolve
99
+ // the entire dotted chain through namespaces.
100
+ const nsRes = tryResolveNamespaceChain(ctx, expr);
101
+ if (nsRes) {
102
+ if (nsRes.kind === "value")
103
+ return nsRes.expr;
104
+ if (nsRes.kind === "namespace")
105
+ return ctx.error(DiagnosticCode.Namespace_path_is_incomplete_expected_a_value_type_function_or_interface, expr.range);
106
+ // "incomplete" — diagnostic already emitted
107
+ return undefined;
108
+ }
94
109
  const objExpr = _compileExpr(ctx, expr.object, undefined);
95
110
  if (!objExpr)
96
111
  return undefined;
97
112
  const objType = objExpr.type;
113
+ // RawConstr (TirUnConstrDataResultT) field access lowers directly to
114
+ // fstPair / sndPair on the underlying pair(int, list(data)).
115
+ if (objType instanceof TirUnConstrDataResultT) {
116
+ if (expr.prop.text === "index") {
117
+ const fn = TirNativeFunc.unConstrDataResultIndex;
118
+ return new TirCallExpr(fn, [objExpr], fn.type.returnType, expr.range);
119
+ }
120
+ if (expr.prop.text === "fields") {
121
+ const fn = TirNativeFunc.unConstrDataResultFields;
122
+ return new TirCallExpr(fn, [objExpr], fn.type.returnType, expr.range);
123
+ }
124
+ return ctx.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, expr.prop.range, expr.prop.text, "RawConstr");
125
+ }
98
126
  const returnType = getPropAccessReturnType(ctx, objType, expr.prop);
99
127
  if (!returnType)
100
128
  return ctx.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, expr.prop.range, expr.prop.text, objType.toString());
@@ -3,6 +3,8 @@ import { TirVariableAccessExpr } from "../../../tir/expressions/TirVariableAcces
3
3
  export function _compileVarAccessExpr(ctx, expr, typeHint) {
4
4
  const resolvedValue = ctx.scope.resolveValue(expr.text);
5
5
  if (!resolvedValue) {
6
+ if (ctx.scope.resolveNamespace(expr.text))
7
+ return ctx.error(DiagnosticCode.Namespace_path_is_incomplete_expected_a_value_type_function_or_interface, expr.range);
6
8
  console.trace(ctx.scope.allVariables(), expr.text);
7
9
  return ctx.error(DiagnosticCode._0_is_not_defined, expr.range, expr.text);
8
10
  }
@@ -12,7 +12,7 @@ import { ForStmt } from "../../../../ast/nodes/statements/ForStmt.js";
12
12
  import { IfStmt } from "../../../../ast/nodes/statements/IfStmt.js";
13
13
  import { MatchStmt } from "../../../../ast/nodes/statements/MatchStmt.js";
14
14
  import { ReturnStmt } from "../../../../ast/nodes/statements/ReturnStmt.js";
15
- import { UsingStmt } from "../../../../ast/nodes/statements/UsingStmt.js";
15
+ import { UsingAliasStmt, UsingStmt } from "../../../../ast/nodes/statements/UsingStmt.js";
16
16
  import { VarStmt } from "../../../../ast/nodes/statements/VarStmt.js";
17
17
  import { WhileStmt } from "../../../../ast/nodes/statements/WhileStmt.js";
18
18
  import { _compileAssertStmt } from "./_compileAssertStmt.js";
@@ -28,6 +28,7 @@ import { _compileIfStmt } from "./_compileIfStmt.js";
28
28
  import { _compileMatchStmt } from "./_compileMatchStmt.js";
29
29
  import { _compileReturnStmt } from "./_compileReturnStmt.js";
30
30
  import { _compileUsingStmt } from "./_compileUsingStmt.js";
31
+ import { _compileUsingAliasStmt } from "./_compileUsingAliasStmt.js";
31
32
  import { _compileVarStmt } from "./_compileVarStmt.js";
32
33
  import { _compileWhileStmt } from "./_compileWhileStmt.js";
33
34
  /**
@@ -74,6 +75,8 @@ export function _compileStatement(ctx, stmt) {
74
75
  // if( stmt instanceof ExprStmt ) return _compileExprStmt( ctx, stmt );
75
76
  if (stmt instanceof UsingStmt)
76
77
  return _compileUsingStmt(ctx, stmt);
78
+ if (stmt instanceof UsingAliasStmt)
79
+ return _compileUsingAliasStmt(ctx, stmt);
77
80
  const tsEnsureExhautstiveCheck = stmt;
78
81
  console.error(stmt);
79
82
  throw new Error("unreachable::AstCompiler::_compileStatement");
@@ -1 +1,15 @@
1
- export {};
1
+ import { TestStmt } from "../../../../ast/nodes/statements/TestStmt.js";
2
+ import { AstCompilationCtx } from "../../AstCompilationCtx.js";
3
+ /**
4
+ * Compiles a `test name( params? ) { body }` declaration.
5
+ *
6
+ * Synthesises a `function <tirFuncName>( params ): void { body }` and
7
+ * runs it through `_compileFuncExpr` so type-checking, scoping and
8
+ * later TIR-to-UPLC compilation work exactly like a user-defined function.
9
+ *
10
+ * Registers the resulting `TirFuncExpr` in `program.functions` and pushes
11
+ * a `TirTestStmt` referencing it onto `program.tests`.
12
+ *
13
+ * @returns `true` on success (test registered), `false` on failure (diagnostic emitted).
14
+ */
15
+ export declare function _compileTestStmt(ctx: AstCompilationCtx, stmt: TestStmt, srcUid: string, sourceFile: string): boolean;
@@ -1,32 +1,72 @@
1
- export {};
2
- /*
3
- export function _compileTestStmt(
4
- ctx: AstCompilationCtx,
5
- stmt: TestStmt
6
- ): [ TirTestStmt ] | undefined
7
- {
8
- if( ctx.functionCtx ) return ctx.error(
9
- DiagnosticCode.A_test_statement_can_only_be_used_outside_a_function,
10
- stmt.range
1
+ import { Identifier } from "../../../../ast/nodes/common/Identifier.js";
2
+ import { FuncExpr } from "../../../../ast/nodes/expr/functions/FuncExpr.js";
3
+ import { ArrowKind } from "../../../../ast/nodes/expr/functions/ArrowKind.js";
4
+ import { AstFuncType, AstVoidType } from "../../../../ast/nodes/types/AstNativeTypeExpr.js";
5
+ import { CommonFlags } from "../../../../common.js";
6
+ import { SimpleVarDecl } from "../../../../ast/nodes/statements/declarations/VarDecl/SimpleVarDecl.js";
7
+ import { PEBBLE_INTERNAL_IDENTIFIER_PREFIX } from "../../../internalVar.js";
8
+ import { TirTestStmt } from "../../../tir/statements/TirTestStmt.js";
9
+ import { _compileFuncExpr } from "../exprs/_compileFuncExpr.js";
10
+ import { TirIntT } from "../../../tir/types/TirNativeType/native/int.js";
11
+ import { TirBoolT } from "../../../tir/types/TirNativeType/native/bool.js";
12
+ import { getUnaliased } from "../../../tir/types/utils/getUnaliased.js";
13
+ /**
14
+ * Compiles a `test name( params? ) { body }` declaration.
15
+ *
16
+ * Synthesises a `function <tirFuncName>( params ): void { body }` and
17
+ * runs it through `_compileFuncExpr` so type-checking, scoping and
18
+ * later TIR-to-UPLC compilation work exactly like a user-defined function.
19
+ *
20
+ * Registers the resulting `TirFuncExpr` in `program.functions` and pushes
21
+ * a `TirTestStmt` referencing it onto `program.tests`.
22
+ *
23
+ * @returns `true` on success (test registered), `false` on failure (diagnostic emitted).
24
+ */
25
+ export function _compileTestStmt(ctx, stmt, srcUid, sourceFile) {
26
+ const program = ctx.program;
27
+ const astName = stmt.testName.text;
28
+ const tirFuncName = PEBBLE_INTERNAL_IDENTIFIER_PREFIX + "test_" + astName + "_" + srcUid;
29
+ // Lower each TestParam to a SimpleVarDecl for the synthesized FuncExpr.
30
+ // `viaExpr` is consumed later (fuzzer resolution); the wrapper function
31
+ // itself takes the same params a regular `function name( ... )` would.
32
+ const lowerParams = stmt.params.map(p => new SimpleVarDecl(p.name, p.type, undefined, // initExpr
33
+ CommonFlags.Const, p.range));
34
+ const sig = new AstFuncType(lowerParams, new AstVoidType(stmt.testName.range), stmt.range);
35
+ const astFuncExpr = new FuncExpr(new Identifier(tirFuncName, stmt.testName.range), CommonFlags.None, [], // typeParams
36
+ sig, stmt.body, ArrowKind.None, stmt.range);
37
+ const tirFuncExpr = _compileFuncExpr(ctx, astFuncExpr, undefined, // expectedFuncType
38
+ false // isMethod
11
39
  );
12
-
13
- let tirBody = wrapManyStatements(
14
- _compileStatement(
15
- ctx.newBranchChildScope(),
16
- stmt.body
17
- ),
18
- stmt.body.range
19
- );
20
- if( !tirBody ) return undefined;
21
- if(!( tirBody instanceof TirBlockStmt))
22
- {
23
- tirBody = new TirBlockStmt( [ tirBody ], stmt.body.range );
24
- }
25
-
26
- return [ new TirTestStmt(
27
- stmt.testName?.string,
28
- tirBody as TirBlockStmt,
29
- stmt.range
30
- ) ];
40
+ if (!tirFuncExpr)
41
+ return false;
42
+ program.functions.set(tirFuncName, tirFuncExpr);
43
+ // Resolve per-parameter fuzzer info. This walks both the source-level
44
+ // `TestParam` array (which carries any `via` expressions) and the
45
+ // resolved TIR param types (taken from the compiled function).
46
+ const fuzzerInfos = stmt.params.map((astParam, idx) => {
47
+ // Phase 1: `via` is parsed but execution of user-defined fuzzers
48
+ // is not wired up. Type-checking the expression is also deferred
49
+ // until the stdlib `std.test.fuzz` namespace ships.
50
+ if (astParam.viaExpr) {
51
+ return { kind: "via_not_implemented" };
52
+ }
53
+ const tirParamType = tirFuncExpr.params[idx]?.type;
54
+ if (!tirParamType) {
55
+ return {
56
+ kind: "unsupported",
57
+ reason: `parameter '${astParam.name.text}' has no resolved type`
58
+ };
59
+ }
60
+ const unaliased = getUnaliased(tirParamType);
61
+ if (unaliased instanceof TirIntT)
62
+ return { kind: "primitive", primitive: "int" };
63
+ if (unaliased instanceof TirBoolT)
64
+ return { kind: "primitive", primitive: "bool" };
65
+ return {
66
+ kind: "unsupported",
67
+ reason: `parameter '${astParam.name.text}' of type '${tirParamType.toString()}' has no default fuzzer; specify one with 'via <expr>' (note: user-defined fuzzers via 'via' are not yet executable)`
68
+ };
69
+ });
70
+ program.tests.push(new TirTestStmt(astName, tirFuncName, sourceFile, stmt.range, fuzzerInfos));
71
+ return true;
31
72
  }
32
- //*/
@@ -0,0 +1,11 @@
1
+ import { UsingAliasStmt } from "../../../../ast/nodes/statements/UsingStmt.js";
2
+ import { AstCompilationCtx } from "../../AstCompilationCtx.js";
3
+ /**
4
+ * `using <alias> = <NamespacePath>;`
5
+ *
6
+ * binds `<alias>` in the current scope as a namespace alias for the
7
+ * namespace at `<NamespacePath>`.
8
+ *
9
+ * compile-time only — no IR is emitted.
10
+ */
11
+ export declare function _compileUsingAliasStmt(ctx: AstCompilationCtx, stmt: UsingAliasStmt): [] | undefined;
@@ -0,0 +1,26 @@
1
+ import { DiagnosticCode } from "../../../../diagnostics/diagnosticMessages.generated.js";
2
+ import { resolveNamespacePath } from "../../utils/resolveNamespacePath.js";
3
+ /**
4
+ * `using <alias> = <NamespacePath>;`
5
+ *
6
+ * binds `<alias>` in the current scope as a namespace alias for the
7
+ * namespace at `<NamespacePath>`.
8
+ *
9
+ * compile-time only — no IR is emitted.
10
+ */
11
+ export function _compileUsingAliasStmt(ctx, stmt) {
12
+ const resolved = resolveNamespacePath(ctx, stmt.rhs);
13
+ if (!resolved) {
14
+ ctx.error(DiagnosticCode._0_is_not_a_namespace, stmt.rhs.range, stmt.rhs.segments[0].text);
15
+ return undefined;
16
+ }
17
+ const ok = ctx.scope.defineNamespace({
18
+ name: stmt.aliasName.text,
19
+ publicScope: resolved.namespace.publicScope
20
+ });
21
+ if (!ok) {
22
+ ctx.error(DiagnosticCode.Constructor_name_0_is_already_declared_in_this_scope, stmt.aliasName.range, stmt.aliasName.text);
23
+ return undefined;
24
+ }
25
+ return [];
26
+ }
@@ -1,11 +1,16 @@
1
1
  import { UsingStmt } from "../../../../ast/nodes/statements/UsingStmt.js";
2
2
  import { AstCompilationCtx } from "../../AstCompilationCtx.js";
3
3
  /**
4
- * `using` only introduces symbols in scope
4
+ * `using` only introduces symbols in scope.
5
5
  *
6
- * we don't represent `using` statements in the TIR
6
+ * we don't represent `using` statements in the TIR.
7
7
  *
8
- * @returns {[]} an empty array if successful compilation
8
+ * the RHS can be either:
9
+ * - a struct type expression (legacy behavior, brings constructors into scope)
10
+ * - a namespace path (new behavior, destructures the namespace's exported
11
+ * members into the current scope)
12
+ *
13
+ * @returns {[]} an empty array if compilation succeeded
9
14
  * @returns {undefined} `undefined` if compilation failed
10
- **/
15
+ */
11
16
  export declare function _compileUsingStmt(ctx: AstCompilationCtx, stmt: UsingStmt): [] | undefined;
@@ -1,27 +1,55 @@
1
+ import { UsingPath } from "../../../../ast/nodes/statements/UsingStmt.js";
1
2
  import { DiagnosticCode } from "../../../../diagnostics/diagnosticMessages.generated.js";
2
3
  import { getStructType } from "../../../tir/types/utils/canAssignTo.js";
4
+ import { bindNamespaceMember, resolveNamespacePath } from "../../utils/resolveNamespacePath.js";
3
5
  import { _compileDataEncodedConcreteType } from "../types/_compileDataEncodedConcreteType.js";
4
6
  import { _compileSopEncodedConcreteType } from "../types/_compileSopEncodedConcreteType.js";
7
+ import { AstNamedTypeExpr } from "../../../../ast/nodes/types/AstNamedTypeExpr.js";
5
8
  /**
6
- * `using` only introduces symbols in scope
9
+ * `using` only introduces symbols in scope.
7
10
  *
8
- * we don't represent `using` statements in the TIR
11
+ * we don't represent `using` statements in the TIR.
9
12
  *
10
- * @returns {[]} an empty array if successful compilation
13
+ * the RHS can be either:
14
+ * - a struct type expression (legacy behavior, brings constructors into scope)
15
+ * - a namespace path (new behavior, destructures the namespace's exported
16
+ * members into the current scope)
17
+ *
18
+ * @returns {[]} an empty array if compilation succeeded
11
19
  * @returns {undefined} `undefined` if compilation failed
12
- **/
20
+ */
13
21
  export function _compileUsingStmt(ctx, stmt) {
14
- stmt.constructorNames;
15
- stmt.structTypeExpr;
16
- stmt.range;
17
- const structOrAliasType = (_compileSopEncodedConcreteType(ctx, stmt.structTypeExpr)
18
- ?? _compileDataEncodedConcreteType(ctx, stmt.structTypeExpr));
22
+ const rhs = stmt.rhs;
23
+ if (rhs instanceof UsingPath) {
24
+ // namespace path. if the head is a namespace, destructure
25
+ // its public members; otherwise fall through to the struct path
26
+ // (this supports the single-identifier case where a name could
27
+ // be either a struct or a namespace).
28
+ const ns = resolveNamespacePath(ctx, rhs);
29
+ if (ns) {
30
+ return _compileUsingNamespaceDestructure(ctx, stmt, ns.namespace);
31
+ }
32
+ // single-segment fallback: treat as a struct type ref
33
+ if (rhs.segments.length === 1) {
34
+ const ident = rhs.segments[0];
35
+ const fakeTypeExpr = new AstNamedTypeExpr(ident, [], ident.range);
36
+ return _compileUsingStructDestructure(ctx, stmt, fakeTypeExpr);
37
+ }
38
+ ctx.error(DiagnosticCode._0_is_not_a_namespace, rhs.range, rhs.segments[0].text);
39
+ return undefined;
40
+ }
41
+ // RHS is an AstTypeExpr (existing struct-destructure code path)
42
+ return _compileUsingStructDestructure(ctx, stmt, rhs);
43
+ }
44
+ function _compileUsingStructDestructure(ctx, stmt, rhs) {
45
+ const structOrAliasType = (_compileSopEncodedConcreteType(ctx, rhs)
46
+ ?? _compileDataEncodedConcreteType(ctx, rhs));
19
47
  if (!structOrAliasType)
20
48
  return undefined;
21
49
  // un-alias
22
50
  const structType = getStructType(structOrAliasType);
23
51
  if (!structType || !structType.isConcrete())
24
- return ctx.error(DiagnosticCode.Type_0_does_not_have_constructors, stmt.structTypeExpr.range, structOrAliasType.toString());
52
+ return ctx.error(DiagnosticCode.Type_0_does_not_have_constructors, rhs.range, structOrAliasType.toString());
25
53
  const defCtorNames = structType.constructors.map(c => c.name);
26
54
  const sameStmtCtorNames = [];
27
55
  for (const stmtCtor of stmt.constructorNames) {
@@ -39,3 +67,16 @@ export function _compileUsingStmt(ctx, stmt) {
39
67
  }
40
68
  return [];
41
69
  }
70
+ function _compileUsingNamespaceDestructure(ctx, stmt, ns) {
71
+ const seen = new Set();
72
+ for (const decl of stmt.constructorNames) {
73
+ const name = decl.constructorName;
74
+ if (seen.has(name.text))
75
+ return ctx.error(DiagnosticCode.Constructor_0_was_already_specified, name.range, name.text);
76
+ seen.add(name.text);
77
+ const ok = bindNamespaceMember(ctx, ns, name, decl.renamedConstructorName, ctx.scope);
78
+ if (!ok)
79
+ return undefined;
80
+ }
81
+ return [];
82
+ }
@@ -46,11 +46,30 @@ export function _compileDataEncodedConcreteType(ctx, typeExpr, optionalsAsSop =
46
46
  return undefined; // no data encoding for function types
47
47
  if (typeExpr instanceof AstNamedTypeExpr) // struct, aliases and respective params
48
48
  {
49
+ // generic type parameters take precedence: `T` in a generic function
50
+ // body resolves directly to its TirTypeParam, leaving substitution
51
+ // to `monomorphizeGeneric` at call time.
52
+ const typeParam = ctx.scope.resolveTypeParam(typeExpr.name.text);
53
+ if (typeParam)
54
+ return typeParam;
49
55
  const possibleTirNames = ctx.scope.resolveType(typeExpr.name.text);
50
56
  if (!possibleTirNames)
51
57
  return ctx.error(DiagnosticCode._0_is_not_defined, typeExpr.name.range, typeExpr.name.text);
52
- if (possibleTirNames.isGeneric)
53
- throw new Error("not implemented: _compileDataEncodedConcreteType for generic types");
58
+ if (possibleTirNames.isGeneric) {
59
+ // Generic named type with explicit type-args, e.g. `List<int>` —
60
+ // compile each arg and apply the generic.
61
+ if (typeExpr.tyArgs.length === 0)
62
+ return ctx.error(DiagnosticCode._0_is_not_defined, typeExpr.name.range, typeExpr.name.text);
63
+ const compiledArgs = [];
64
+ for (const aExpr of typeExpr.tyArgs) {
65
+ const a = _compileDataEncodedConcreteType(ctx, aExpr, optionalsAsSop);
66
+ if (!a)
67
+ return undefined;
68
+ compiledArgs.push(a);
69
+ }
70
+ const applied = ctx.program.getAppliedGeneric(possibleTirNames.dataTirName ?? possibleTirNames.sopTirName, compiledArgs);
71
+ return applied;
72
+ }
54
73
  if (typeof possibleTirNames.dataTirName !== "string")
55
74
  return undefined;
56
75
  return ctx.program.types.get(possibleTirNames.dataTirName);
@@ -44,11 +44,26 @@ export function _compileSopEncodedConcreteType(ctx, typeExpr) {
44
44
  return undefined; // no data encoding for function types
45
45
  if (typeExpr instanceof AstNamedTypeExpr) // struct, aliases and respective params
46
46
  {
47
+ // generic type parameters take precedence over named-type lookup
48
+ const typeParam = ctx.scope.resolveTypeParam(typeExpr.name.text);
49
+ if (typeParam)
50
+ return typeParam;
47
51
  const possibleTirNames = ctx.scope.resolveType(typeExpr.name.text);
48
52
  if (!possibleTirNames)
49
53
  return ctx.error(DiagnosticCode._0_is_not_defined, typeExpr.name.range, typeExpr.name.text);
50
- if (possibleTirNames.isGeneric)
51
- throw new Error("not implemented: _compileSopEncodedConcreteType for generic types");
54
+ if (possibleTirNames.isGeneric) {
55
+ if (typeExpr.tyArgs.length === 0)
56
+ return ctx.error(DiagnosticCode._0_is_not_defined, typeExpr.name.range, typeExpr.name.text);
57
+ const compiledArgs = [];
58
+ for (const aExpr of typeExpr.tyArgs) {
59
+ const a = _compileSopEncodedConcreteType(ctx, aExpr);
60
+ if (!a)
61
+ return undefined;
62
+ compiledArgs.push(a);
63
+ }
64
+ const applied = ctx.program.getAppliedGeneric(possibleTirNames.sopTirName, compiledArgs);
65
+ return applied;
66
+ }
52
67
  if (typeof possibleTirNames.dataTirName !== "string")
53
68
  return undefined;
54
69
  return ctx.program.types.get(possibleTirNames.dataTirName);
@@ -1,6 +1,7 @@
1
1
  import { AstFuncType } from "../../../ast/nodes/types/AstNativeTypeExpr.js";
2
- import { TypedProgram } from "../../tir/program/TypedProgram.js";
2
+ import { TypedProgram, TypeParamConstraint } from "../../tir/program/TypedProgram.js";
3
3
  import { TirType } from "../../tir/types/TirType.js";
4
+ import { TirTypeParam } from "../../tir/types/TirTypeParam.js";
4
5
  export interface ScopeInfos {
5
6
  isFunctionDeclScope: boolean;
6
7
  isMethodScope: boolean;
@@ -32,6 +33,29 @@ export interface IVariableInfos {
32
33
  name: string;
33
34
  type: TirType;
34
35
  isConstant: boolean;
36
+ /**
37
+ * If set, this binding is a placeholder for a generic function template.
38
+ * The actual TIR function does not exist yet; it must be instantiated
39
+ * at the call site by `monomorphizeGeneric` using the template stored in
40
+ * `TypedProgram.genericTemplates` under this name.
41
+ *
42
+ * `type` for a generic placeholder is the *un-substituted* TirFuncT —
43
+ * i.e. it may contain `TirTypeParam` nodes for each declared type param.
44
+ */
45
+ genericTemplateName?: string;
46
+ }
47
+ /**
48
+ * A namespace is a compile-time only construct that groups
49
+ * symbols (values, types, functions, interfaces, and nested
50
+ * namespaces) under a single name.
51
+ *
52
+ * Members of the namespace marked with `private` are NOT included
53
+ * in `publicScope`; they only live in the namespace's body-compilation
54
+ * scope and are unreachable from outside.
55
+ */
56
+ export interface NamespaceSymbol {
57
+ name: string;
58
+ publicScope: AstScope;
35
59
  }
36
60
  export interface PossibleTirTypes {
37
61
  sopTirName: string;
@@ -81,6 +105,24 @@ export declare class AstScope {
81
105
  */
82
106
  readonly narrowings: Map<string, TirType>;
83
107
  readonly aviableConstructors: Map<string, IAvaiableConstructor>;
108
+ /**
109
+ * ast name -> namespace symbol
110
+ *
111
+ * namespaces are compile-time only; they do not emit IR
112
+ */
113
+ readonly namespaces: Map<string, NamespaceSymbol>;
114
+ /**
115
+ * Generic type parameters in scope, e.g. while compiling the signature
116
+ * (and later the body) of a generic function `function f<T>(...)`. These
117
+ * are NOT real types — they only mark positions that must be substituted
118
+ * by `monomorphizeGeneric` at each call site.
119
+ *
120
+ * When `_compileDataEncodedConcreteType` / `_compileSopEncodedConcreteType`
121
+ * encounter an `AstNamedTypeExpr` whose name is here, it returns the
122
+ * corresponding `TirTypeParam` directly instead of going through the
123
+ * regular `resolveType` path.
124
+ */
125
+ readonly typeParams: Map<string, TirTypeParam>;
84
126
  private _isReadonly;
85
127
  readonly infos: ScopeInfos;
86
128
  constructor(parent: AstScope | undefined, program: TypedProgram, infos: Partial<ScopeInfos>);
@@ -111,5 +153,32 @@ export declare class AstScope {
111
153
  */
112
154
  defineAviableConstructorIfValid(declaredName: string, originalName: string, structOrAliasType: TirType): boolean;
113
155
  inferStructTypeFromConstructorName(name: string): IAvaiableConstructor | undefined;
156
+ /** define a namespace in this scope; returns `false` if shadowed in current scope */
157
+ defineNamespace(ns: NamespaceSymbol): boolean;
158
+ /** resolve a namespace by walking the scope chain */
159
+ resolveNamespace(name: string): NamespaceSymbol | undefined;
160
+ /** define a generic type parameter in this scope; returns `false` if shadowed */
161
+ defineTypeParam(name: string, param: TirTypeParam): boolean;
162
+ /** resolve a generic type parameter by walking the scope chain */
163
+ resolveTypeParam(name: string): TirTypeParam | undefined;
164
+ /**
165
+ * Type-parameter constraints declared via `<T implements I>` syntax.
166
+ * Populated by `AstCompiler._registerGenericTemplate` for the function
167
+ * template's compilation scope. `resolveTypeParamConstraint` walks the
168
+ * parent chain like the other resolvers.
169
+ */
170
+ readonly typeParamConstraints: Map<string, TypeParamConstraint>;
171
+ defineTypeParamConstraint(name: string, constraint: TypeParamConstraint): boolean;
172
+ resolveTypeParamConstraint(name: string): TypeParamConstraint | undefined;
173
+ /**
174
+ * Walk the scope chain to resolve an interface by name. Returns the
175
+ * method-name -> AstFuncType signature map.
176
+ */
177
+ resolveInterface(name: string): Map<string, AstFuncType> | undefined;
178
+ /**
179
+ * `true` if `name` is bound in this scope (or any parent) under any kind.
180
+ * Used to detect shadowing across symbol categories when defining a new symbol.
181
+ */
182
+ hasAnySymbol(name: string): boolean;
114
183
  clone(): AstScope;
115
184
  }
@@ -59,6 +59,24 @@ export class AstScope {
59
59
  */
60
60
  narrowings = new Map();
61
61
  aviableConstructors = new Map();
62
+ /**
63
+ * ast name -> namespace symbol
64
+ *
65
+ * namespaces are compile-time only; they do not emit IR
66
+ */
67
+ namespaces = new Map();
68
+ /**
69
+ * Generic type parameters in scope, e.g. while compiling the signature
70
+ * (and later the body) of a generic function `function f<T>(...)`. These
71
+ * are NOT real types — they only mark positions that must be substituted
72
+ * by `monomorphizeGeneric` at each call site.
73
+ *
74
+ * When `_compileDataEncodedConcreteType` / `_compileSopEncodedConcreteType`
75
+ * encounter an `AstNamedTypeExpr` whose name is here, it returns the
76
+ * corresponding `TirTypeParam` directly instead of going through the
77
+ * regular `resolveType` path.
78
+ */
79
+ typeParams = new Map();
62
80
  _isReadonly = false;
63
81
  infos;
64
82
  constructor(parent, program, infos) {
@@ -202,6 +220,77 @@ export class AstScope {
202
220
  return (this.aviableConstructors.get(name)
203
221
  ?? this.parent?.inferStructTypeFromConstructorName(name));
204
222
  }
223
+ /** define a namespace in this scope; returns `false` if shadowed in current scope */
224
+ defineNamespace(ns) {
225
+ if (this._isReadonly)
226
+ return false;
227
+ if (invalidSymbolNames.has(ns.name))
228
+ return false;
229
+ if (this.namespaces.has(ns.name))
230
+ return false;
231
+ this.namespaces.set(ns.name, ns);
232
+ return true;
233
+ }
234
+ /** resolve a namespace by walking the scope chain */
235
+ resolveNamespace(name) {
236
+ return (this.namespaces.get(name)
237
+ ?? this.parent?.resolveNamespace(name));
238
+ }
239
+ /** define a generic type parameter in this scope; returns `false` if shadowed */
240
+ defineTypeParam(name, param) {
241
+ if (this._isReadonly)
242
+ return false;
243
+ if (this.typeParams.has(name))
244
+ return false;
245
+ this.typeParams.set(name, param);
246
+ return true;
247
+ }
248
+ /** resolve a generic type parameter by walking the scope chain */
249
+ resolveTypeParam(name) {
250
+ return (this.typeParams.get(name)
251
+ ?? this.parent?.resolveTypeParam(name));
252
+ }
253
+ /**
254
+ * Type-parameter constraints declared via `<T implements I>` syntax.
255
+ * Populated by `AstCompiler._registerGenericTemplate` for the function
256
+ * template's compilation scope. `resolveTypeParamConstraint` walks the
257
+ * parent chain like the other resolvers.
258
+ */
259
+ typeParamConstraints = new Map();
260
+ defineTypeParamConstraint(name, constraint) {
261
+ if (this._isReadonly)
262
+ return false;
263
+ if (this.typeParamConstraints.has(name))
264
+ return false;
265
+ this.typeParamConstraints.set(name, constraint);
266
+ return true;
267
+ }
268
+ resolveTypeParamConstraint(name) {
269
+ return (this.typeParamConstraints.get(name)
270
+ ?? this.parent?.resolveTypeParamConstraint(name));
271
+ }
272
+ /**
273
+ * Walk the scope chain to resolve an interface by name. Returns the
274
+ * method-name -> AstFuncType signature map.
275
+ */
276
+ resolveInterface(name) {
277
+ return (this.interfaces.get(name)
278
+ ?? this.parent?.resolveInterface(name));
279
+ }
280
+ /**
281
+ * `true` if `name` is bound in this scope (or any parent) under any kind.
282
+ * Used to detect shadowing across symbol categories when defining a new symbol.
283
+ */
284
+ hasAnySymbol(name) {
285
+ if (this.variables.has(name)
286
+ || this.types.has(name)
287
+ || this.functions.has(name)
288
+ || this.interfaces.has(name)
289
+ || this.namespaces.has(name)
290
+ || this.aviableConstructors.has(name))
291
+ return true;
292
+ return this.parent?.hasAnySymbol(name) ?? false;
293
+ }
205
294
  clone() {
206
295
  const cloned = new AstScope(this.parent, this.program, this.infos);
207
296
  for (const [key, value] of this.variables)
@@ -219,6 +308,8 @@ export class AstScope {
219
308
  });
220
309
  for (const [name, methods] of this.interfaces)
221
310
  cloned.interfaces.set(name, new Map(methods));
311
+ for (const [name, ns] of this.namespaces)
312
+ cloned.namespaces.set(name, ns);
222
313
  return cloned;
223
314
  }
224
315
  }