gen-typescript-from-tolk-dev 0.1.0 → 0.2.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 (50) hide show
  1. package/README.md +33 -29
  2. package/dist/abi-types.d.ts +169 -0
  3. package/dist/abi-types.js +8 -0
  4. package/dist/abi.d.ts +54 -0
  5. package/dist/abi.js +13 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +83 -0
  8. package/dist/codegen-ctx.d.ts +66 -0
  9. package/dist/codegen-ctx.js +108 -0
  10. package/dist/emit-field-defs.d.ts +5 -0
  11. package/dist/emit-field-defs.js +61 -0
  12. package/dist/emit-pack-unpack.d.ts +9 -0
  13. package/dist/emit-pack-unpack.js +296 -0
  14. package/dist/emit-stack-rw.d.ts +4 -0
  15. package/dist/emit-stack-rw.js +232 -0
  16. package/dist/emit-ts-types.d.ts +6 -0
  17. package/dist/emit-ts-types.js +74 -0
  18. package/dist/formatting.d.ts +15 -0
  19. package/{src/formatting.ts → dist/formatting.js} +26 -28
  20. package/dist/generate-ts-wrappers.d.ts +7 -0
  21. package/dist/generate-ts-wrappers.js +444 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.js +11 -0
  24. package/dist/out-template.generated.d.ts +1 -0
  25. package/dist/out-template.generated.js +6 -0
  26. package/dist/types-kernel.d.ts +10 -0
  27. package/dist/types-kernel.js +212 -0
  28. package/dist/unsupported-errors.d.ts +28 -0
  29. package/{src/unsupported-errors.ts → dist/unsupported-errors.js} +33 -39
  30. package/package.json +56 -30
  31. package/bin/generator.js +0 -15
  32. package/src/abi-types.ts +0 -157
  33. package/src/abi.ts +0 -132
  34. package/src/cli-generate-from-abi-json.ts +0 -21
  35. package/src/codegen-ctx.ts +0 -115
  36. package/src/dynamic-ctx.ts +0 -55
  37. package/src/dynamic-debug-print.ts +0 -191
  38. package/src/dynamic-get-methods.ts +0 -454
  39. package/src/dynamic-serialization.ts +0 -430
  40. package/src/dynamic-validation.ts +0 -55
  41. package/src/emit-field-defs.ts +0 -60
  42. package/src/emit-pack-unpack.ts +0 -280
  43. package/src/emit-stack-rw.ts +0 -239
  44. package/src/emit-ts-types.ts +0 -66
  45. package/src/generate-from-abi-json.ts +0 -22
  46. package/src/generate-ts-wrappers.ts +0 -477
  47. package/src/out-template.ts +0 -514
  48. package/src/tolk-to-abi.ts +0 -5
  49. package/src/types-kernel.ts +0 -215
  50. package/tsconfig.json +0 -13
package/README.md CHANGED
@@ -1,47 +1,51 @@
1
- # Tolk-to-TypeScript wrappers generator (alpha)
1
+ # gen-typescript-from-tolk
2
2
 
3
- Currently, it uses a patched LSP to parse and Tolk source code (for MVP). Later, the compiler will be able
4
- to emit ABI of a contract, and LSP won't be used in this process.
3
+ Generate production-ready TypeScript wrappers from a prebuilt Tolk ABI.
5
4
 
6
- ### Main CLI
7
-
8
- The main entrypoint accepts contract ABI as a JSON string and prints the generated TypeScript wrapper to stdout:
5
+ ## Install
9
6
 
10
7
  ```bash
11
- npx gen-typescript-from-tolk '{"contractName":"MyContract", ... }'
8
+ npm install gen-typescript-from-tolk
12
9
  ```
13
10
 
14
- This package no longer bundles a Tolk compiler. It only supports `ABI JSON -> TypeScript wrapper`.
11
+ ## Library usage
15
12
 
13
+ ```ts
14
+ import { generateTypeScriptFileForContract } from 'gen-typescript-from-tolk';
15
+ import type { ContractABI } from 'gen-typescript-from-tolk';
16
16
 
17
- ### Configuring TypeScript output
17
+ const abi: ContractABI = getAbiFromSomewhereElse();
18
+ const wrapperSource = generateTypeScriptFileForContract(abi);
19
+ ```
18
20
 
19
- 1. All structs/aliases/enums are generated to the output it's unconfigurable currently.
20
- If a struct can't be serialized (contains `int` for example, not int32/uint64),
21
- its `fromSlice` and `store` just contain `throw new Error` with a description.
21
+ The generator expects ABI that already contains the contract metadata needed for wrapper emission, including `codeBoc64`.
22
22
 
23
- 2. Default values of all structs are preserved:
24
- ```
25
- struct WalletStorage {
26
- jettonBalance: coins = 0 // <----
27
- ownerAddress: address
28
- minterAddress: address
29
- }
30
- ```
23
+ Generated wrappers import `@ton/core`, so the project that uses the generated wrapper file should have `@ton/core` installed.
24
+
25
+ ## CLI usage
31
26
 
32
- Then, `jettonBalance` key in `WalletStorage.create()` will be optional. If it's a storage or a message, it will also be optional in `fromStorage` and `sendXXX`.
27
+ Print wrapper code to `stdout`:
33
28
 
34
- 3. If your storage change shape after initialization (the case of NFT), you can specify an "uninited storage" shape:
29
+ ```bash
30
+ npx gen-typescript-from-tolk '{"contractName":"MyContract","declarations":[],"storage":{},"incomingMessages":[],"incomingExternal":[],"outgoingMessages":[],"emittedEvents":[],"getMethods":[],"thrownErrors":[],"compilerName":"tolk","compilerVersion":"dev","codeBoc64":"te6ccgEBAQEAAgAAAA=="}'
35
31
  ```
36
- type NOT_INITIALIZED_STORAGE = StorageStructNotInitialized
32
+
33
+ Write to a file:
34
+
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
37
37
  ```
38
38
 
39
- Then, `fromStorage` will accept fields from this struct, not from `STORAGE`.
39
+ You can also pass `-` instead of JSON to read ABI JSON from `stdin`.
40
40
 
41
+ ## Development
42
+
43
+ ```bash
44
+ npm run build
45
+ npm test
46
+ npm pack --dry-run
47
+ ```
41
48
 
42
- ### Known issues
49
+ Local tests and dev scripts compile `.tolk` files through `@ton/tolk-js`, but that compiler is intentionally not part of the published runtime package.
43
50
 
44
- 1. Generics behave incorrectly when `T` is used inside unions (because generics are not monomorphic, they are true TypeScript generics). For example, you have `struct A<T> { v: T | int8 }` and instantiate `A<int2 | int4>`, then an actual prefix tree will be '00/01/10', but a TS wrapper serializes '0+T/1'; or, for `A<int8>` actually will be no union (`int8 | int8` = `int8`), but a TS wrapper will still serialize as '0+int8/1'. Similar corner cases appear in get methods that work via the stack. For example, `struct MyNullable<T> { v: T? }`, instantiated as `MyNullable<Point>` has no information about stack layout and type-id.
45
- 2. Non-standard keys for maps are unsupported, like `map<Point, ...>`. Only intN/uintN/address are supported (99% use cases). Others can not be represented via `@ton/core` library at all.
46
- 3. Custom serializers for generic structs `fun Some<T>.packToBuilder` not supported (works perfectly for non-generic structs and aliases, but not for generic).
47
- 4. Default values for struct fields, if a field contains a union, not supported.
51
+ Only `dist/` and `README.md` are included in the published npm package.
@@ -0,0 +1,169 @@
1
+ type bigint_as_string = string;
2
+ export type Ty = {
3
+ kind: 'int';
4
+ } | {
5
+ kind: 'intN';
6
+ n: number;
7
+ } | {
8
+ kind: 'uintN';
9
+ n: number;
10
+ } | {
11
+ kind: 'varintN';
12
+ n: number;
13
+ } | {
14
+ kind: 'varuintN';
15
+ n: number;
16
+ } | {
17
+ kind: 'coins';
18
+ } | {
19
+ kind: 'bool';
20
+ } | {
21
+ kind: 'cell';
22
+ } | {
23
+ kind: 'builder';
24
+ } | {
25
+ kind: 'slice';
26
+ } | {
27
+ kind: 'string';
28
+ } | {
29
+ kind: 'remaining';
30
+ } | {
31
+ kind: 'address';
32
+ } | {
33
+ kind: 'addressOpt';
34
+ } | {
35
+ kind: 'addressExt';
36
+ } | {
37
+ kind: 'addressAny';
38
+ } | {
39
+ kind: 'bitsN';
40
+ n: number;
41
+ } | {
42
+ kind: 'nullLiteral';
43
+ } | {
44
+ kind: 'callable';
45
+ } | {
46
+ kind: 'void';
47
+ } | {
48
+ kind: 'unknown';
49
+ } | {
50
+ kind: 'nullable';
51
+ inner: Ty;
52
+ stack_type_id?: number;
53
+ stack_width?: number;
54
+ } | {
55
+ kind: 'cellOf';
56
+ inner: Ty;
57
+ } | {
58
+ kind: 'arrayOf';
59
+ inner: Ty;
60
+ } | {
61
+ kind: 'lispListOf';
62
+ inner: Ty;
63
+ } | {
64
+ kind: 'tensor';
65
+ items: Ty[];
66
+ } | {
67
+ kind: 'shapedTuple';
68
+ items: Ty[];
69
+ } | {
70
+ kind: 'mapKV';
71
+ k: Ty;
72
+ v: Ty;
73
+ } | {
74
+ kind: 'EnumRef';
75
+ enum_name: string;
76
+ } | {
77
+ kind: 'StructRef';
78
+ struct_name: string;
79
+ type_args?: Ty[];
80
+ } | {
81
+ kind: 'AliasRef';
82
+ alias_name: string;
83
+ type_args?: Ty[];
84
+ } | {
85
+ kind: 'genericT';
86
+ name_t: string;
87
+ } | {
88
+ kind: 'union';
89
+ variants: UnionVariant[];
90
+ stack_width: number;
91
+ };
92
+ export interface UnionVariant {
93
+ variant_ty: Ty;
94
+ prefix_str: string;
95
+ prefix_len: number;
96
+ is_prefix_implicit?: boolean;
97
+ stack_type_id: number;
98
+ stack_width: number;
99
+ }
100
+ export type ABIConstExpression = {
101
+ kind: 'int';
102
+ v: bigint_as_string;
103
+ } | {
104
+ kind: 'bool';
105
+ v: boolean;
106
+ } | {
107
+ kind: 'slice';
108
+ hex: string;
109
+ } | {
110
+ kind: 'string';
111
+ str: string;
112
+ } | {
113
+ kind: 'address';
114
+ addr: string;
115
+ } | {
116
+ kind: 'tensor';
117
+ items: ABIConstExpression[];
118
+ } | {
119
+ kind: 'shapedTuple';
120
+ items: ABIConstExpression[];
121
+ } | {
122
+ kind: 'object';
123
+ struct_name: string;
124
+ fields: ABIConstExpression[];
125
+ } | {
126
+ kind: 'castTo';
127
+ inner: ABIConstExpression;
128
+ cast_to: Ty;
129
+ } | {
130
+ kind: 'null';
131
+ };
132
+ export interface ABICustomSerializers {
133
+ pack_to_builder: boolean;
134
+ unpack_from_slice: boolean;
135
+ }
136
+ export interface ABIStruct {
137
+ kind: 'struct';
138
+ name: string;
139
+ type_params?: string[];
140
+ prefix?: {
141
+ prefix_str: string;
142
+ prefix_len: number;
143
+ };
144
+ fields: {
145
+ name: string;
146
+ ty: Ty;
147
+ default_value?: ABIConstExpression;
148
+ description?: string;
149
+ }[];
150
+ custom_pack_unpack?: ABICustomSerializers;
151
+ }
152
+ export interface ABIAlias {
153
+ kind: 'alias';
154
+ name: string;
155
+ target_ty: Ty;
156
+ type_params?: string[];
157
+ custom_pack_unpack?: ABICustomSerializers;
158
+ }
159
+ export interface ABIEnum {
160
+ kind: 'enum';
161
+ name: string;
162
+ encoded_as: Ty;
163
+ members: {
164
+ name: string;
165
+ value: bigint_as_string;
166
+ }[];
167
+ custom_pack_unpack?: ABICustomSerializers;
168
+ }
169
+ export {};
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /*
3
+ ABI Types — describes the type system and symbols definitions in the Tolk language.
4
+ The goal is to have a full bidirectional mapping from any Tolk struct to ABI:
5
+ all tricky types like generics, aliases, inline unions, etc. should be supported.
6
+ Then, any input could be packed to a cell and unpacked back — exactly as it's done by the compiler.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/abi.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ import { Ty, ABIStruct, ABIAlias, ABIEnum, ABIConstExpression } from './abi-types';
2
+ export interface ABIGetMethod {
3
+ tvm_method_id: number;
4
+ name: string;
5
+ parameters: {
6
+ name: string;
7
+ ty: Ty;
8
+ description?: string;
9
+ default_value?: ABIConstExpression;
10
+ }[];
11
+ return_ty: Ty;
12
+ description?: string;
13
+ }
14
+ export interface ABIInternalMessage {
15
+ body_ty: Ty;
16
+ description?: string;
17
+ minimal_msg_value?: number;
18
+ preferred_send_mode?: number;
19
+ }
20
+ export interface ABIExternalMessage {
21
+ body_ty: Ty;
22
+ description?: string;
23
+ }
24
+ export interface ABIOutgoingMessage {
25
+ body_ty: Ty;
26
+ description?: string;
27
+ }
28
+ export interface ABIStorage {
29
+ storage_ty?: Ty;
30
+ storage_at_deployment_ty?: Ty;
31
+ }
32
+ export interface ABIThrownError {
33
+ kind: 'plain_int' | 'constant' | 'enum_member';
34
+ name?: string;
35
+ description?: string;
36
+ err_code: number;
37
+ }
38
+ export interface ContractABI {
39
+ contract_name: string;
40
+ author?: string;
41
+ version?: string;
42
+ description?: string;
43
+ declarations: (ABIStruct | ABIAlias | ABIEnum)[];
44
+ storage: ABIStorage;
45
+ incoming_messages: ABIInternalMessage[];
46
+ incoming_external: ABIExternalMessage[];
47
+ outgoing_messages: ABIOutgoingMessage[];
48
+ emitted_events: ABIOutgoingMessage[];
49
+ get_methods: ABIGetMethod[];
50
+ thrown_errors: ABIThrownError[];
51
+ compiler_name: string;
52
+ compiler_version: string;
53
+ codeBoc64: string;
54
+ }
package/dist/abi.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /*
3
+ ABI of a contract describes how the contract is "seen" by external observers:
4
+ its get methods, incoming messages, etc.
5
+ Given an ABI, it becomes possible to
6
+ - post messages from a client, since ABI provides sufficient info for serialization
7
+ - generate wrappers for TypeScript and other languages
8
+ - render its storage in the explorer
9
+ - create a UI to interact with a contract from Web/IDE
10
+ - etc.
11
+ The ABI is emitted by the Tolk compiler, along with bytecode.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function runCli(argv: string[]): void;
package/dist/cli.js ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.runCli = runCli;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const generate_ts_wrappers_1 = require("./generate-ts-wrappers");
10
+ function printHelp() {
11
+ const help = [
12
+ `Usage:`,
13
+ ` gen-typescript-from-tolk '{"contract_name":"MyContract",...}' --out ./MyContract.ts`,
14
+ `Options:`,
15
+ ` --out — output file name; if missing, stdout is used`
16
+ ].join('\n');
17
+ process.stdout.write(`${help}\n`);
18
+ }
19
+ function parseArgs(argv) {
20
+ const args = [...argv];
21
+ const options = { showHelp: false };
22
+ while (args.length > 0) {
23
+ const arg = args.shift();
24
+ if (arg === '--help' || arg === '-h') {
25
+ options.showHelp = true;
26
+ continue;
27
+ }
28
+ if (arg === '--out') {
29
+ const outFile = args.shift();
30
+ if (!outFile) {
31
+ throw new Error("Missing value for '--out'");
32
+ }
33
+ options.outFile = outFile;
34
+ continue;
35
+ }
36
+ if (arg.startsWith('--')) {
37
+ throw new Error(`Unknown option '${arg}'`);
38
+ }
39
+ if (options.abiJsonArg !== undefined) {
40
+ throw new Error('Only one ABI JSON argument is expected');
41
+ }
42
+ options.abiJsonArg = arg;
43
+ }
44
+ return options;
45
+ }
46
+ function parseAbiJson(rawJson) {
47
+ try {
48
+ return JSON.parse(rawJson);
49
+ }
50
+ catch (error) {
51
+ throw new Error(`Failed to parse ABI JSON: ${error.message || error}`);
52
+ }
53
+ }
54
+ function writeOutput(output, outFile) {
55
+ if (outFile) {
56
+ fs_1.default.writeFileSync(outFile, output, 'utf-8');
57
+ process.stdout.write(`written ${outFile}\n`);
58
+ return;
59
+ }
60
+ process.stdout.write(output);
61
+ }
62
+ function runCli(argv) {
63
+ const options = parseArgs(argv);
64
+ if (options.showHelp) {
65
+ printHelp();
66
+ return;
67
+ }
68
+ if (!options.abiJsonArg) {
69
+ throw new Error("ABI JSON argument is required");
70
+ }
71
+ const abi = parseAbiJson(options.abiJsonArg);
72
+ const generated = (0, generate_ts_wrappers_1.generateTypeScriptFileForContract)(abi);
73
+ writeOutput(generated, options.outFile);
74
+ }
75
+ if (require.main === module) {
76
+ try {
77
+ runCli(process.argv.slice(2));
78
+ }
79
+ catch (ex) {
80
+ process.stderr.write(`${ex.message || ex}\n`);
81
+ process.exitCode = 1;
82
+ }
83
+ }
@@ -0,0 +1,66 @@
1
+ import type { Ty, ABIStruct, ABIAlias, ABIEnum } from './abi-types';
2
+ export declare const RUNTIME: {
3
+ beginCell: string;
4
+ lookupPrefix: string;
5
+ lookupPrefixAndEat: string;
6
+ throwNonePrefixMatch: string;
7
+ loadAndCheckPrefix32: string;
8
+ loadAndCheckPrefix: string;
9
+ loadTolkBitsN: string;
10
+ storeTolkBitsN: string;
11
+ loadTolkAddressAny: string;
12
+ storeTolkAddressAny: string;
13
+ loadTolkRemaining: string;
14
+ storeTolkRemaining: string;
15
+ loadCellRef: string;
16
+ storeCellRef: string;
17
+ loadArrayOf: string;
18
+ storeArrayOf: string;
19
+ loadLispListOf: string;
20
+ storeLispListOf: string;
21
+ storeTolkNullable: string;
22
+ makeCellFrom: string;
23
+ createDictionaryValue: string;
24
+ registerCustomPackUnpack: string;
25
+ ExtraSendOptions: string;
26
+ StackReader: string;
27
+ };
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
+ export declare class CodegenCtx {
39
+ readonly symbols: SymTable;
40
+ intNOccurred: Set<string>;
41
+ uintNOccurred: Set<string>;
42
+ varIntNOccurred: Set<string>;
43
+ bitsNOccurred: Set<string>;
44
+ has_RemainingBitsAndRefs: boolean;
45
+ has_customPackUnpack: boolean;
46
+ has_customDictV: boolean;
47
+ has_implicitUnionPrefix: boolean;
48
+ has_non32Prefixes: boolean;
49
+ has_addressAny: boolean;
50
+ has_arrayOf: boolean;
51
+ has_lispListOf: boolean;
52
+ stackReadsUnknown: boolean;
53
+ stackReadsArrayOf: boolean;
54
+ stackReadsLispListOf: boolean;
55
+ stackReadsSnakeString: boolean;
56
+ stackReadsTuple: boolean;
57
+ stackReadsMapKV: boolean;
58
+ stackReadsBuilder: boolean;
59
+ stackReadsNullable: boolean;
60
+ stackReadsWideNullable: boolean;
61
+ stackReadsUnionType: boolean;
62
+ stackReadsCellRef: boolean;
63
+ stackReadsNullLiteral: boolean;
64
+ constructor(declarations: (ABIStruct | ABIAlias | ABIEnum)[]);
65
+ sortOccurred(occurred: Set<string>): string[];
66
+ }
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CodegenCtx = exports.SymTable = exports.RUNTIME = void 0;
4
+ const unsupported_errors_1 = require("./unsupported-errors");
5
+ // Functions implemented in an output template, used to detect name shadowing.
6
+ exports.RUNTIME = {
7
+ beginCell: 'beginCell',
8
+ lookupPrefix: 'lookupPrefix',
9
+ lookupPrefixAndEat: 'lookupPrefixAndEat',
10
+ throwNonePrefixMatch: 'throwNonePrefixMatch',
11
+ loadAndCheckPrefix32: 'loadAndCheckPrefix32',
12
+ loadAndCheckPrefix: 'loadAndCheckPrefix',
13
+ loadTolkBitsN: 'loadTolkBitsN',
14
+ storeTolkBitsN: 'storeTolkBitsN',
15
+ loadTolkAddressAny: 'loadTolkAddressAny',
16
+ storeTolkAddressAny: 'storeTolkAddressAny',
17
+ loadTolkRemaining: 'loadTolkRemaining',
18
+ storeTolkRemaining: 'storeTolkRemaining',
19
+ loadCellRef: 'loadCellRef',
20
+ storeCellRef: 'storeCellRef',
21
+ loadArrayOf: 'loadArrayOf',
22
+ storeArrayOf: 'storeArrayOf',
23
+ loadLispListOf: 'loadLispListOf',
24
+ storeLispListOf: 'storeLispListOf',
25
+ storeTolkNullable: 'storeTolkNullable',
26
+ makeCellFrom: 'makeCellFrom',
27
+ createDictionaryValue: 'createDictionaryValue',
28
+ registerCustomPackUnpack: 'registerCustomPackUnpack',
29
+ ExtraSendOptions: 'ExtraSendOptions',
30
+ StackReader: 'StackReader',
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
+ // CodegenCtx represents current state of TypeScript code generation.
71
+ // It contains properties that affect final output and help resolve symbols.
72
+ // For example, we want Tolk `int64` not be just TS `bigint`, but
73
+ // to export `type int64 = bigint` and use `int64` directly,
74
+ // that's why we track all occurred intN.
75
+ // Same for other public properties, they are modified while iterating through declarations.
76
+ class CodegenCtx {
77
+ constructor(declarations) {
78
+ this.intNOccurred = new Set(['int8', 'int16', 'int32', 'int256']);
79
+ this.uintNOccurred = new Set(['uint8', 'uint16', 'uint32', 'uint256']);
80
+ this.varIntNOccurred = new Set();
81
+ this.bitsNOccurred = new Set();
82
+ this.has_RemainingBitsAndRefs = false;
83
+ this.has_customPackUnpack = false;
84
+ this.has_customDictV = false;
85
+ this.has_implicitUnionPrefix = false;
86
+ this.has_non32Prefixes = false;
87
+ this.has_addressAny = false;
88
+ this.has_arrayOf = false;
89
+ this.has_lispListOf = false;
90
+ this.stackReadsUnknown = false;
91
+ this.stackReadsArrayOf = false;
92
+ this.stackReadsLispListOf = false;
93
+ this.stackReadsSnakeString = false;
94
+ this.stackReadsTuple = false;
95
+ this.stackReadsMapKV = false;
96
+ this.stackReadsBuilder = false;
97
+ this.stackReadsNullable = false;
98
+ this.stackReadsWideNullable = false;
99
+ this.stackReadsUnionType = false;
100
+ this.stackReadsCellRef = false;
101
+ this.stackReadsNullLiteral = false;
102
+ this.symbols = new SymTable(declarations);
103
+ }
104
+ sortOccurred(occurred) {
105
+ return [...occurred].sort((a, b) => a.length - b.length || a.localeCompare(b));
106
+ }
107
+ }
108
+ exports.CodegenCtx = CodegenCtx;
@@ -0,0 +1,5 @@
1
+ import { ABIConstExpression, Ty } from './abi-types';
2
+ import { CodegenCtx } from './codegen-ctx';
3
+ export declare function isDefaultValueSupported(fieldTy: Ty): boolean;
4
+ export declare function emitFieldDefault(ctx: CodegenCtx, expr: ABIConstExpression): string;
5
+ export declare function emitFieldDefaultInComment(expr: ABIConstExpression): string;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDefaultValueSupported = isDefaultValueSupported;
4
+ exports.emitFieldDefault = emitFieldDefault;
5
+ exports.emitFieldDefaultInComment = emitFieldDefaultInComment;
6
+ const formatting_1 = require("./formatting");
7
+ const types_kernel_1 = require("./types-kernel");
8
+ // Default values of struct fields are also exported to TypeScript unless they are hard to be represented.
9
+ // In practice, all simple values are okay: `f: int = 5`, `f: coins = ton("1")`, etc.
10
+ // But in theory, a field can be a union, for example. It will require a large amount of work to support
11
+ // cases like `f: int8 | slice = 5` or `f: int32 | int64 = 5 as int64` (to generate correct `$` labels).
12
+ // So, if such a field exists, then we just assume it has no default.
13
+ function isDefaultValueSupported(fieldTy) {
14
+ if (fieldTy.kind === 'arrayOf')
15
+ return isDefaultValueSupported(fieldTy.inner);
16
+ if (fieldTy.kind === 'lispListOf')
17
+ return isDefaultValueSupported(fieldTy.inner);
18
+ if (fieldTy.kind === 'tensor')
19
+ return fieldTy.items.every(isDefaultValueSupported);
20
+ if (fieldTy.kind === 'shapedTuple')
21
+ return fieldTy.items.every(isDefaultValueSupported);
22
+ return fieldTy.kind !== 'union' && fieldTy.kind !== 'mapKV';
23
+ }
24
+ // Default values of fields (particularly, in storage) are precalculated by the compiler
25
+ // and stored as "const expression" intermediate representation in ABI.
26
+ // Here we output them to a valid TypeScript expression.
27
+ // Default parameters for get methods follow the same logic, they are also "const expressions".
28
+ function emitFieldDefault(ctx, expr) {
29
+ switch (expr.kind) {
30
+ case 'int': return expr.v + 'n';
31
+ case 'bool': return expr.v ? 'true' : 'false';
32
+ case 'slice': return `new c.Slice(new c.BitReader(new c.BitString(Buffer.from('${expr.hex}', 'hex'), 0, ${expr.hex.length * 4})), [])`;
33
+ case 'string': return JSON.stringify(expr.str);
34
+ case 'address': return `c.Address.parse('${expr.addr}')`;
35
+ case 'tensor': return `[${expr.items.map(i => emitFieldDefault(ctx, i)).join(', ')}]`;
36
+ case 'shapedTuple': return `[${expr.items.map(i => emitFieldDefault(ctx, i)).join(', ')}]`;
37
+ case 'object': {
38
+ const structRef = ctx.symbols.getStruct(expr.struct_name);
39
+ return `{ $: '${structRef.name}', ${[...structRef.fields.map((f, i) => `${(0, formatting_1.safeFieldDecl)(f.name)}: ${emitFieldDefault(ctx, expr.fields[i])}`)].join(', ')} }`;
40
+ }
41
+ case 'castTo': return emitFieldDefault(ctx, expr.inner);
42
+ case 'null': return `null`;
43
+ }
44
+ }
45
+ // Output a default value not as a TypeScript expression, but as a human-readable one.
46
+ // For instance, "123" instead of bigint "123n".
47
+ // It's inserted inside comments next to fields having defaults.
48
+ function emitFieldDefaultInComment(expr) {
49
+ switch (expr.kind) {
50
+ case 'int': return expr.v;
51
+ case 'bool': return expr.v ? 'true' : 'false';
52
+ case 'slice': return `hex('${expr.hex}')`;
53
+ case 'string': return JSON.stringify(expr.str);
54
+ case 'address': return `address('${expr.addr}')`;
55
+ case 'tensor': return `[${expr.items.map(emitFieldDefaultInComment).join(', ')}]`;
56
+ case 'shapedTuple': return `[${expr.items.map(emitFieldDefaultInComment).join(', ')}]`;
57
+ case 'object': return `${expr.struct_name} { ${expr.fields.map(emitFieldDefaultInComment).join(', ')} }`;
58
+ case 'castTo': return `${emitFieldDefaultInComment(expr.inner)} as ${(0, types_kernel_1.renderTy)(expr.cast_to)}`;
59
+ case 'null': return `null`;
60
+ }
61
+ }
@@ -0,0 +1,9 @@
1
+ import type { Ty } from './abi-types';
2
+ import { CodegenCtx } from './codegen-ctx';
3
+ export declare function emitLoadExpr(ctx: CodegenCtx, fieldPath: string, ty: Ty): string;
4
+ export declare function emitLoadCallback(ctx: CodegenCtx, fieldPath: string, ty: Ty): string;
5
+ export declare function emitStoreStatement(ctx: CodegenCtx, tsExpr: string, ty: Ty): string;
6
+ export declare function emitStoreCallback(ctx: CodegenCtx, ty: Ty): string;
7
+ export declare function emitMakeCellFromExpr(ctx: CodegenCtx, tsExpr: string, ty: Ty, disableShortHand?: boolean): string;
8
+ export declare function emitCallToCreateMethodExpr(ctx: CodegenCtx, bodyArg: string, ty: Ty): string;
9
+ export declare function emitDictKVSerializers(ctx: CodegenCtx, fieldPath: string, tyK: Ty, tyV: Ty): string;