gen-typescript-from-tolk-dev 0.2.3 → 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.
package/README.md CHANGED
@@ -18,7 +18,7 @@ const abi: ContractABI = getAbiFromSomewhereElse();
18
18
  const wrapperSource = generateTypeScriptFileForContract(abi);
19
19
  ```
20
20
 
21
- The generator expects ABI that already contains the contract metadata needed for wrapper emission, including `codeBoc64`.
21
+ The generator expects ABI that already contains the contract metadata needed for wrapper emission, including `code_boc64`.
22
22
 
23
23
  Generated wrappers import `@ton/core`, so the project that uses the generated wrapper file should have `@ton/core` installed.
24
24
 
@@ -27,17 +27,37 @@ Generated wrappers import `@ton/core`, so the project that uses the generated wr
27
27
  Print wrapper code to `stdout`:
28
28
 
29
29
  ```bash
30
- npx gen-typescript-from-tolk '{"contractName":"MyContract","declarations":[],"storage":{},"incomingMessages":[],"incomingExternal":[],"outgoingMessages":[],"emittedEvents":[],"getMethods":[],"thrownErrors":[],"compilerName":"tolk","compilerVersion":"dev","codeBoc64":"te6ccgEBAQEAAgAAAA=="}'
30
+ npx gen-typescript-from-tolk '{"contract_name":"MyContract","unique_types":[...], ..., "compiler_version":"1.4.0","code_boc64":"te6ccgEBAQEAAgAAAA=="}'
31
31
  ```
32
32
 
33
33
  Write to a file:
34
34
 
35
35
  ```bash
36
- npx gen-typescript-from-tolk '{"contractName":"MyContract","declarations":[],"storage":{},"incomingMessages":[],"incomingExternal":[],"outgoingMessages":[],"emittedEvents":[],"getMethods":[],"thrownErrors":[],"compilerName":"tolk","compilerVersion":"dev","codeBoc64":"te6ccgEBAQEAAgAAAA=="}' --out ./MyContract.ts
36
+ npx gen-typescript-from-tolk '<abi-json-with-code_boc64>' --out ./MyContract.gen.ts
37
37
  ```
38
38
 
39
39
  You can also pass `-` instead of JSON to read ABI JSON from `stdin`.
40
40
 
41
+ ## Known limitations
42
+
43
+ ### Generic structs whose unions reshape after monomorphization
44
+
45
+ When generic `T` is inside a union, substituting concrete type arguments may collapse or expand the union's variants.
46
+ The instantiated type then no longer matches what you'd get by naive substitution.
47
+
48
+ ```tolk
49
+ struct WithFallback<T> {
50
+ field: T | int32
51
+ }
52
+ ```
53
+
54
+ The following corner cases would not work, because wrappers for TS `interface WithFallback<T>` assume `field` to be a union of two:
55
+
56
+ - `WithFallback<int32>` — field collapses to `int32`.
57
+ - `WithFallback<bool | int8>` — field becomes `bool | int8 | int32`.
58
+
59
+ In practice, such cases never occur.
60
+
41
61
  ## Development
42
62
 
43
63
  ```bash
@@ -48,54 +48,54 @@ export type Ty = {
48
48
  kind: 'unknown';
49
49
  } | {
50
50
  kind: 'nullable';
51
- inner: Ty;
51
+ inner_ty_idx: number;
52
52
  stack_type_id?: number;
53
53
  stack_width?: number;
54
54
  } | {
55
55
  kind: 'cellOf';
56
- inner: Ty;
56
+ inner_ty_idx: number;
57
57
  } | {
58
58
  kind: 'arrayOf';
59
- inner: Ty;
59
+ inner_ty_idx: number;
60
60
  } | {
61
61
  kind: 'lispListOf';
62
- inner: Ty;
62
+ inner_ty_idx: number;
63
63
  } | {
64
64
  kind: 'tensor';
65
- items: Ty[];
65
+ items_ty_idx: number[];
66
66
  } | {
67
67
  kind: 'shapedTuple';
68
- items: Ty[];
68
+ items_ty_idx: number[];
69
69
  } | {
70
70
  kind: 'mapKV';
71
- k: Ty;
72
- v: Ty;
71
+ key_ty_idx: number;
72
+ value_ty_idx: number;
73
73
  } | {
74
74
  kind: 'EnumRef';
75
75
  enum_name: string;
76
76
  } | {
77
77
  kind: 'StructRef';
78
78
  struct_name: string;
79
- type_args?: Ty[];
79
+ type_args_ty_idx?: number[];
80
80
  } | {
81
81
  kind: 'AliasRef';
82
82
  alias_name: string;
83
- type_args?: Ty[];
83
+ type_args_ty_idx?: number[];
84
84
  } | {
85
85
  kind: 'genericT';
86
86
  name_t: string;
87
87
  } | {
88
88
  kind: 'union';
89
89
  variants: UnionVariant[];
90
- stack_width: number;
90
+ stack_width?: number;
91
91
  };
92
92
  export interface UnionVariant {
93
- variant_ty: Ty;
94
- prefix_str: string;
93
+ variant_ty_idx: number;
94
+ prefix_num: number;
95
95
  prefix_len: number;
96
96
  is_prefix_implicit?: boolean;
97
- stack_type_id: number;
98
- stack_width: number;
97
+ stack_type_id?: number;
98
+ stack_width?: number;
99
99
  }
100
100
  export type ABIConstExpression = {
101
101
  kind: 'int';
@@ -125,7 +125,7 @@ export type ABIConstExpression = {
125
125
  } | {
126
126
  kind: 'castTo';
127
127
  inner: ABIConstExpression;
128
- cast_to: Ty;
128
+ cast_to_ty_idx: number;
129
129
  } | {
130
130
  kind: 'null';
131
131
  };
@@ -136,14 +136,15 @@ export interface ABICustomSerializers {
136
136
  export interface ABIStruct {
137
137
  kind: 'struct';
138
138
  name: string;
139
+ ty_idx: number;
139
140
  type_params?: string[];
140
141
  prefix?: {
141
- prefix_str: string;
142
+ prefix_num: number;
142
143
  prefix_len: number;
143
144
  };
144
145
  fields: {
145
146
  name: string;
146
- ty: Ty;
147
+ ty_idx: number;
147
148
  default_value?: ABIConstExpression;
148
149
  description?: string;
149
150
  }[];
@@ -152,18 +153,30 @@ export interface ABIStruct {
152
153
  export interface ABIAlias {
153
154
  kind: 'alias';
154
155
  name: string;
155
- target_ty: Ty;
156
+ ty_idx: number;
157
+ target_ty_idx: number;
156
158
  type_params?: string[];
157
159
  custom_pack_unpack?: ABICustomSerializers;
158
160
  }
159
161
  export interface ABIEnum {
160
162
  kind: 'enum';
161
163
  name: string;
162
- encoded_as: Ty;
164
+ ty_idx: number;
165
+ encoded_as_ty_idx: number;
163
166
  members: {
164
167
  name: string;
165
168
  value: bigint_as_string;
166
169
  }[];
167
170
  custom_pack_unpack?: ABICustomSerializers;
168
171
  }
172
+ export interface ABIStructInstantiation {
173
+ ty_idx: number;
174
+ struct_name: string;
175
+ monomorphic_fields_ty_idx: number[];
176
+ }
177
+ export interface ABIAliasInstantiation {
178
+ ty_idx: number;
179
+ alias_name: string;
180
+ monomorphic_target_ty_idx: number;
181
+ }
169
182
  export {};
package/dist/abi.d.ts CHANGED
@@ -1,33 +1,32 @@
1
- import { Ty, ABIStruct, ABIAlias, ABIEnum, ABIConstExpression } from './abi-types';
1
+ import { Ty, ABIStruct, ABIAlias, ABIEnum, ABIConstExpression, ABIStructInstantiation, ABIAliasInstantiation } from './abi-types';
2
2
  export interface ABIGetMethod {
3
3
  tvm_method_id: number;
4
4
  name: string;
5
5
  parameters: {
6
6
  name: string;
7
- ty: Ty;
7
+ ty_idx: number;
8
8
  description?: string;
9
9
  default_value?: ABIConstExpression;
10
10
  }[];
11
- return_ty: Ty;
11
+ return_ty_idx: number;
12
12
  description?: string;
13
13
  }
14
14
  export interface ABIInternalMessage {
15
- body_ty: Ty;
15
+ body_ty_idx: number;
16
16
  description?: string;
17
- minimal_msg_value?: number;
18
- preferred_send_mode?: number;
19
17
  }
20
18
  export interface ABIExternalMessage {
21
- body_ty: Ty;
19
+ body_ty_idx: number;
22
20
  description?: string;
23
21
  }
24
22
  export interface ABIOutgoingMessage {
25
- body_ty: Ty;
23
+ body_ty_idx: number;
26
24
  description?: string;
27
25
  }
28
26
  export interface ABIStorage {
29
- storage_ty?: Ty;
30
- storage_at_deployment_ty?: Ty;
27
+ storage_ty_idx?: number;
28
+ storage_at_deployment_ty_idx?: number;
29
+ description?: string;
31
30
  }
32
31
  export interface ABIThrownError {
33
32
  kind: 'plain_int' | 'constant' | 'enum_member';
@@ -40,6 +39,9 @@ export interface ContractABI {
40
39
  author?: string;
41
40
  version?: string;
42
41
  description?: string;
42
+ unique_types: Ty[];
43
+ struct_instantiations: ABIStructInstantiation[];
44
+ alias_instantiations: ABIAliasInstantiation[];
43
45
  declarations: (ABIStruct | ABIAlias | ABIEnum)[];
44
46
  storage: ABIStorage;
45
47
  incoming_messages: ABIInternalMessage[];
@@ -50,5 +52,4 @@ export interface ContractABI {
50
52
  thrown_errors: ABIThrownError[];
51
53
  compiler_name: string;
52
54
  compiler_version: string;
53
- codeBoc64: string;
54
55
  }
@@ -1,4 +1,5 @@
1
- import type { Ty, ABIStruct, ABIAlias, ABIEnum } from './abi-types';
1
+ import type { ContractABI } from './abi';
2
+ import { SymTable } from './types-kernel';
2
3
  export declare const RUNTIME: {
3
4
  beginCell: string;
4
5
  lookupPrefix: string;
@@ -25,16 +26,6 @@ export declare const RUNTIME: {
25
26
  ExtraSendOptions: string;
26
27
  StackReader: string;
27
28
  };
28
- export declare class SymTable {
29
- private structs;
30
- private aliases;
31
- private enums;
32
- constructor(declarations: (ABIStruct | ABIAlias | ABIEnum)[]);
33
- getStruct(structName: string): ABIStruct;
34
- getAlias(aliasName: string): ABIAlias;
35
- getEnum(enumName: string): ABIEnum;
36
- getAliasTarget(aliasName: string): Ty;
37
- }
38
29
  export declare class CodegenCtx {
39
30
  readonly symbols: SymTable;
40
31
  intNOccurred: Set<string>;
@@ -61,6 +52,6 @@ export declare class CodegenCtx {
61
52
  stackReadsUnionType: boolean;
62
53
  stackReadsCellRef: boolean;
63
54
  stackReadsNullLiteral: boolean;
64
- constructor(declarations: (ABIStruct | ABIAlias | ABIEnum)[]);
55
+ constructor(abi: ContractABI);
65
56
  sortOccurred(occurred: Set<string>): string[];
66
57
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CodegenCtx = exports.SymTable = exports.RUNTIME = void 0;
4
- const unsupported_errors_1 = require("./unsupported-errors");
3
+ exports.CodegenCtx = exports.RUNTIME = void 0;
4
+ const types_kernel_1 = require("./types-kernel");
5
5
  // Functions implemented in an output template, used to detect name shadowing.
6
6
  exports.RUNTIME = {
7
7
  beginCell: 'beginCell',
@@ -29,44 +29,6 @@ exports.RUNTIME = {
29
29
  ExtraSendOptions: 'ExtraSendOptions',
30
30
  StackReader: 'StackReader',
31
31
  };
32
- // SymTable is an index of top-level declarations.
33
- class SymTable {
34
- constructor(declarations) {
35
- this.structs = new Map();
36
- this.aliases = new Map();
37
- this.enums = new Map();
38
- for (const n of declarations) {
39
- if (n.kind === 'struct')
40
- this.structs.set(n.name, n);
41
- else if (n.kind === 'alias')
42
- this.aliases.set(n.name, n);
43
- else if (n.kind === 'enum')
44
- this.enums.set(n.name, n);
45
- }
46
- }
47
- getStruct(structName) {
48
- const s = this.structs.get(structName);
49
- if (s === undefined)
50
- throw new unsupported_errors_1.SymbolNotFound('struct', structName);
51
- return s;
52
- }
53
- getAlias(aliasName) {
54
- const a = this.aliases.get(aliasName);
55
- if (a === undefined)
56
- throw new unsupported_errors_1.SymbolNotFound('alias', aliasName);
57
- return a;
58
- }
59
- getEnum(enumName) {
60
- const e = this.enums.get(enumName);
61
- if (e === undefined)
62
- throw new unsupported_errors_1.SymbolNotFound('enum', enumName);
63
- return e;
64
- }
65
- getAliasTarget(aliasName) {
66
- return this.getAlias(aliasName).target_ty;
67
- }
68
- }
69
- exports.SymTable = SymTable;
70
32
  // CodegenCtx represents current state of TypeScript code generation.
71
33
  // It contains properties that affect final output and help resolve symbols.
72
34
  // For example, we want Tolk `int64` not be just TS `bigint`, but
@@ -74,7 +36,7 @@ exports.SymTable = SymTable;
74
36
  // that's why we track all occurred intN.
75
37
  // Same for other public properties, they are modified while iterating through declarations.
76
38
  class CodegenCtx {
77
- constructor(declarations) {
39
+ constructor(abi) {
78
40
  this.intNOccurred = new Set(['int8', 'int16', 'int32', 'int256']);
79
41
  this.uintNOccurred = new Set(['uint8', 'uint16', 'uint32', 'uint256']);
80
42
  this.varIntNOccurred = new Set();
@@ -99,7 +61,7 @@ class CodegenCtx {
99
61
  this.stackReadsUnionType = false;
100
62
  this.stackReadsCellRef = false;
101
63
  this.stackReadsNullLiteral = false;
102
- this.symbols = new SymTable(declarations);
64
+ this.symbols = new types_kernel_1.SymTable(abi.declarations, abi.unique_types, abi.struct_instantiations, abi.alias_instantiations);
103
65
  }
104
66
  sortOccurred(occurred) {
105
67
  return [...occurred].sort((a, b) => a.length - b.length || a.localeCompare(b));
@@ -1,6 +1,6 @@
1
1
  import * as c from '@ton/core';
2
- import { SymTable } from './codegen-ctx';
3
2
  import { ABIGetMethod, ContractABI } from './abi';
3
+ import { SymTable } from './types-kernel';
4
4
  type CustomPackToBuilderFn<T> = (self: T, b: c.Builder) => void;
5
5
  type CustomUnpackFromSliceFn<T> = (s: c.Slice) => T;
6
6
  export declare class DynamicCtx {
@@ -8,7 +8,7 @@ export declare class DynamicCtx {
8
8
  readonly getMethods: ABIGetMethod[];
9
9
  readonly symbols: SymTable;
10
10
  private customSerializersRegistry;
11
- constructor(contract: ContractABI);
11
+ constructor(abi: ContractABI);
12
12
  registerCustomPackUnpack<T>(typeName: string, packToBuilderFn: CustomPackToBuilderFn<T> | null, unpackFromSliceFn: CustomUnpackFromSliceFn<T> | null): void;
13
13
  getCustomPackFnOrThrow(typeName: string, fieldPath: string): CustomPackToBuilderFn<any>;
14
14
  getCustomUnpackFnOrThrow(typeName: string, fieldPath: string): CustomUnpackFromSliceFn<any>;
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DynamicCtx = void 0;
4
- const codegen_ctx_1 = require("./codegen-ctx");
5
4
  const unsupported_errors_1 = require("./unsupported-errors");
5
+ const types_kernel_1 = require("./types-kernel");
6
6
  class DynamicCtx {
7
- constructor(contract) {
7
+ constructor(abi) {
8
8
  this.customSerializersRegistry = new Map;
9
- this.contractName = contract.contract_name;
10
- this.getMethods = contract.get_methods;
11
- this.symbols = new codegen_ctx_1.SymTable(contract.declarations);
9
+ this.contractName = abi.contract_name;
10
+ this.getMethods = abi.get_methods;
11
+ this.symbols = new types_kernel_1.SymTable(abi.declarations, abi.unique_types, abi.struct_instantiations, abi.alias_instantiations);
12
12
  }
13
13
  registerCustomPackUnpack(typeName, packToBuilderFn, unpackFromSliceFn) {
14
14
  if (this.customSerializersRegistry.has(typeName)) {
@@ -1,9 +1,8 @@
1
1
  import { DynamicCtx } from './dynamic-ctx';
2
- import { Ty } from './abi-types';
3
2
  import { StackReader } from './dynamic-get-methods';
4
3
  /**
5
4
  * Read a value of type `ty` from the TVM stack `tuple` and return a human-readable string.
6
5
  * Consumes `calcWidthOnStack(ty)` elements from the beginning of the array.
7
6
  * Example: given `Point { x: int, y: int }` and stack `[10n, 20n]`, returns "Point { x: 10, y: 20 }".
8
7
  */
9
- export declare function debugPrintFromStack(ctx: DynamicCtx, r: StackReader, ty: Ty): string;
8
+ export declare function debugPrintFromStack(ctx: DynamicCtx, r: StackReader, tyIdx: number): string;
@@ -16,13 +16,14 @@ function printRawCellContents(c) {
16
16
  }
17
17
  // Read `ty` from a stack and return formatted human-readable representation.
18
18
  // Throws if a stack is too small or failed to deserialize a value (inside `Cell<T>` or a map, for example).
19
- function debugFormat(ctx, r, fieldPath, ty, unTupleIfW = false) {
19
+ function debugFormat(ctx, r, fieldPath, tyIdx, unTupleIfW = false) {
20
20
  if (unTupleIfW) {
21
- let wOnStack = (0, types_kernel_1.calcWidthOnStack)(ctx.symbols, ty);
21
+ let wOnStack = (0, types_kernel_1.calcWidthOnStack)(ctx.symbols, tyIdx);
22
22
  if (wOnStack !== 1) {
23
- return r.readTuple(wOnStack, (r) => debugFormat(ctx, r, fieldPath, ty, false));
23
+ return r.readTuple(wOnStack, (r) => debugFormat(ctx, r, fieldPath, tyIdx, false));
24
24
  }
25
25
  }
26
+ const ty = ctx.symbols.tyByIdx(tyIdx);
26
27
  switch (ty.kind) {
27
28
  case 'int':
28
29
  case 'intN':
@@ -38,10 +39,10 @@ function debugFormat(ctx, r, fieldPath, ty, unTupleIfW = false) {
38
39
  case 'remaining': return `slice{${printRawCellContents(r.readSlice().asCell())}}`;
39
40
  case 'string': return `"${r.readSnakeString()}"`;
40
41
  case 'address': return r.readSlice().loadAddress().toString();
41
- case 'addressOpt': return debugFormat(ctx, r, fieldPath, { kind: 'nullable', inner: { kind: 'address' } });
42
+ case 'addressOpt': return r.readNullable((r) => r.readSlice().loadAddress().toString()) ?? 'null';
42
43
  case 'addressExt': return r.readSlice().loadExternalAddress().toString();
43
44
  case 'addressAny': {
44
- let addr = (0, dynamic_serialization_1.dynamicUnpack)(ctx, fieldPath, ty, r.readSlice());
45
+ let addr = (0, dynamic_serialization_1.dynamicUnpack)(ctx, fieldPath, tyIdx, r.readSlice());
45
46
  return addr === 'none' ? 'addr_none' : addr.toString();
46
47
  }
47
48
  case 'nullLiteral': return r.readNullLiteral() ?? 'null';
@@ -49,48 +50,48 @@ function debugFormat(ctx, r, fieldPath, ty, unTupleIfW = false) {
49
50
  case 'unknown': return debugPrintUnknown(r.readUnknown());
50
51
  case 'nullable': {
51
52
  if (ty.stack_type_id) {
52
- return r.readWideNullable(ty.stack_width, (r) => debugFormat(ctx, r, fieldPath, ty.inner)) ?? 'null';
53
+ return r.readWideNullable(ty.stack_width, (r) => debugFormat(ctx, r, fieldPath, ty.inner_ty_idx)) ?? 'null';
53
54
  }
54
- return r.readNullable((r) => debugFormat(ctx, r, fieldPath, ty.inner)) ?? 'null';
55
+ return r.readNullable((r) => debugFormat(ctx, r, fieldPath, ty.inner_ty_idx)) ?? 'null';
55
56
  }
56
57
  case 'cellOf': {
57
58
  let innerStr = r.readCellRef((s) => {
58
- const deserialized = (0, dynamic_serialization_1.dynamicUnpack)(ctx, fieldPath, ty.inner, s);
59
- return debugFormatValue(ctx, fieldPath, ty.inner, deserialized);
59
+ const deserialized = (0, dynamic_serialization_1.dynamicUnpack)(ctx, fieldPath, ty.inner_ty_idx, s);
60
+ return debugFormatValue(ctx, fieldPath, ty.inner_ty_idx, deserialized);
60
61
  });
61
62
  return `ref{${innerStr.ref}}`;
62
63
  }
63
64
  case 'arrayOf': {
64
- let items = r.readArrayOf((r) => debugFormat(ctx, r, fieldPath, ty.inner, true));
65
+ let items = r.readArrayOf((r) => debugFormat(ctx, r, fieldPath, ty.inner_ty_idx, true));
65
66
  return `[${items.join(', ')}]`;
66
67
  }
67
68
  case 'lispListOf': {
68
- let items = r.readLispListOf((r) => debugFormat(ctx, r, fieldPath, ty.inner, true));
69
+ let items = r.readLispListOf((r) => debugFormat(ctx, r, fieldPath, ty.inner_ty_idx, true));
69
70
  return `[${items.join(', ')}]`;
70
71
  }
71
72
  case 'tensor': {
72
73
  let parts = [];
73
- for (let i = 0; i < ty.items.length; ++i) {
74
- parts.push(debugFormat(ctx, r, `${fieldPath}[${i}]`, ty.items[i]));
74
+ for (let i = 0; i < ty.items_ty_idx.length; ++i) {
75
+ parts.push(debugFormat(ctx, r, `${fieldPath}[${i}]`, ty.items_ty_idx[i]));
75
76
  }
76
77
  return `(${parts.join(', ')})`;
77
78
  }
78
79
  case 'shapedTuple': {
79
- return r.readTuple(ty.items.length, (r) => {
80
+ return r.readTuple(ty.items_ty_idx.length, (r) => {
80
81
  let parts = [];
81
- for (let i = 0; i < ty.items.length; ++i) {
82
- parts.push(debugFormat(ctx, r, `${fieldPath}[${i}]`, ty.items[i], true));
82
+ for (let i = 0; i < ty.items_ty_idx.length; ++i) {
83
+ parts.push(debugFormat(ctx, r, `${fieldPath}[${i}]`, ty.items_ty_idx[i], true));
83
84
  }
84
85
  return `[${parts.join(', ')}]`;
85
86
  });
86
87
  }
87
88
  case 'mapKV': {
88
- let dictKey = (0, dynamic_serialization_1.createTonCoreDictionaryKey)(fieldPath, ty.k);
89
- let dictValue = (0, dynamic_serialization_1.createTonCoreDictionaryValue)(ctx, fieldPath, ty.v);
89
+ let dictKey = (0, dynamic_serialization_1.createTonCoreDictionaryKey)(ctx, fieldPath, ty.key_ty_idx);
90
+ let dictValue = (0, dynamic_serialization_1.createTonCoreDictionaryValue)(ctx, fieldPath, ty.value_ty_idx);
90
91
  let entries = [];
91
92
  for (let [k, v] of r.readDictionary(dictKey, dictValue)) {
92
- let kStr = debugFormatValue(ctx, fieldPath, ty.k, k);
93
- let vStr = debugFormatValue(ctx, `${fieldPath}[${kStr}]`, ty.v, v);
93
+ let kStr = debugFormatValue(ctx, fieldPath, ty.key_ty_idx, k);
94
+ let vStr = debugFormatValue(ctx, `${fieldPath}[${kStr}]`, ty.value_ty_idx, v);
94
95
  entries.push(`${kStr}: ${vStr}`);
95
96
  }
96
97
  if (entries.length === 0) {
@@ -108,28 +109,29 @@ function debugFormat(ctx, r, fieldPath, ty, unTupleIfW = false) {
108
109
  return `${ty.enum_name}(${value})`;
109
110
  }
110
111
  case 'StructRef': {
111
- const structRef = ctx.symbols.getStruct(ty.struct_name);
112
- if (structRef.fields.length === 0) {
112
+ let fields = ctx.symbols.structFieldsOf(tyIdx);
113
+ if (fields.length === 0) {
113
114
  return `${ty.struct_name} {}`;
114
115
  }
115
116
  const fieldStrs = [];
116
- for (const f of structRef.fields) {
117
- const fTy = ty.type_args ? (0, types_kernel_1.instantiateGenerics)(f.ty, structRef.type_params, ty.type_args) : f.ty;
118
- fieldStrs.push(`${f.name}: ${debugFormat(ctx, r, `${fieldPath}.${f.name}`, fTy)}`);
117
+ for (const f of fields) {
118
+ fieldStrs.push(`${f.name}: ${debugFormat(ctx, r, `${fieldPath}.${f.name}`, f.ty_idx)}`);
119
119
  }
120
120
  return `${ty.struct_name} { ${fieldStrs.join(', ')} }`;
121
121
  }
122
122
  case 'AliasRef': {
123
- const aliasRef = ctx.symbols.getAlias(ty.alias_name);
124
- const targetTy = ty.type_args ? (0, types_kernel_1.instantiateGenerics)(aliasRef.target_ty, aliasRef.type_params, ty.type_args) : aliasRef.target_ty;
125
- return debugFormat(ctx, r, fieldPath, targetTy);
123
+ const target = ctx.symbols.aliasTargetOf(tyIdx);
124
+ return debugFormat(ctx, r, fieldPath, target.ty_idx);
126
125
  }
127
126
  case 'union': {
127
+ if (ty.stack_width === undefined) {
128
+ throw new Error(`unexpected stack_width=undefined at ${fieldPath}`);
129
+ }
128
130
  const variants = (0, types_kernel_1.createLabelsForUnion)(ctx.symbols, ty.variants);
129
131
  const infoForTypeId = {};
130
132
  for (let v of variants) {
131
133
  infoForTypeId[v.stack_type_id] = [v.stack_width, v.hasValueField ? v.labelStr : null,
132
- (r) => debugFormat(ctx, r, `${fieldPath}#${v.labelStr}`, v.variant_ty)
134
+ (r) => debugFormat(ctx, r, `${fieldPath}#${v.labelStr}`, v.variant_ty_idx)
133
135
  ];
134
136
  }
135
137
  // readUnionType returns `valueT` (if no label) or `{ $: "label", value: valueT }`
@@ -152,12 +154,12 @@ function debugFormat(ctx, r, fieldPath, ty, unTupleIfW = false) {
152
154
  // Format a value that was already parsed by dynamicUnpack into a JS representation.
153
155
  // This is used for inner values of `Cell<T>` and map entries, where we parse via `dynamicUnpack`
154
156
  // and then need to show the result as a string.
155
- function debugFormatValue(ctx, fieldPath, ty, value) {
157
+ function debugFormatValue(ctx, fieldPath, tyIdx, value) {
156
158
  // unlike `debugFormat()`, here we don't read `ty` from a stack: we already have `value` of type `ty`;
157
159
  // to visualize it, instead of making a giant switch-case for all types, do the following trick:
158
160
  // pack value back to a tuple, and render this tuple as if it's a stack value
159
- const backToTuple = (0, dynamic_get_methods_1.makeTvmTupleDynamic)(ctx, ty, value);
160
- return debugFormat(ctx, new dynamic_get_methods_1.StackReader(backToTuple), fieldPath, ty);
161
+ const backToTuple = (0, dynamic_get_methods_1.makeTvmTupleDynamic)(ctx, tyIdx, value);
162
+ return debugFormat(ctx, new dynamic_get_methods_1.StackReader(backToTuple), fieldPath, tyIdx);
161
163
  }
162
164
  // `unknown` is a raw TVM tuple item; `tuple`, by definition, is `array<unknown>`,
163
165
  // it has no compile-time type information, so visualize it anyhow
@@ -178,6 +180,6 @@ function debugPrintUnknown(item) {
178
180
  * Consumes `calcWidthOnStack(ty)` elements from the beginning of the array.
179
181
  * Example: given `Point { x: int, y: int }` and stack `[10n, 20n]`, returns "Point { x: 10, y: 20 }".
180
182
  */
181
- function debugPrintFromStack(ctx, r, ty) {
182
- return debugFormat(ctx, r, 'self', ty);
183
+ function debugPrintFromStack(ctx, r, tyIdx) {
184
+ return debugFormat(ctx, r, 'self', tyIdx);
183
185
  }
@@ -1,6 +1,5 @@
1
1
  import * as c from '@ton/core';
2
2
  import { DynamicCtx } from './dynamic-ctx';
3
- import { Ty } from './abi-types';
4
3
  type LoadCallback<T> = (s: c.Slice) => T;
5
4
  export declare class StackReader {
6
5
  private tuple;
@@ -32,7 +31,7 @@ export declare class StackReader {
32
31
  * Pack any `value` of type `ty` to a TVM tuple.
33
32
  * This tuple can be used as a get method argument or debug-printed as human-readable.
34
33
  */
35
- export declare function makeTvmTupleDynamic(ctx: DynamicCtx, ty: Ty, value: any): c.TupleItem[];
34
+ export declare function makeTvmTupleDynamic(ctx: DynamicCtx, tyIdx: number, value: any): c.TupleItem[];
36
35
  /**
37
36
  * Invoke any get method taking plain JS variables as arguments and interpreting the resulting TVM tuple according to ABI.
38
37
  * Example: `get fun intAndPoint(i: int, p: Point): Point`.