Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: separate project files by domain #1289

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ node_modules/
dist/
coverage/
**/output/
src/test/**/output/
src/func/funcfiftlib.js
test/**/output/
**/*.js
**/grammar.ohm*.ts
**/grammar.ohm*.js
src/grammar/next/grammar.ts
src/050-grammar/next/grammar.ts
jest.setup.js
jest.teardown.js
/docs
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ dist
output/
**/grammar.ohm-bundle.js
**/grammar.ohm-bundle.d.ts
src/func/funcfiftlib.wasm.js
src/test/contracts/pretty-printer-output
test/contracts/pretty-printer-output
9 changes: 4 additions & 5 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/dist
/src/func/funcfiftlib.js
/src/func/funcfiftlib.wasm.js
/src/grammar/prev/grammar.ohm-bundle.d.ts
/src/grammar/prev/grammar.ohm-bundle.js
src/grammar/next/grammar.ts
**/*.js
/src/050-grammar/prev/grammar.ohm-bundle.d.ts
/src/050-grammar/prev/grammar.ohm-bundle.js
src/050-grammar/next/grammar.ts
/src/imports/stdlib.ts
/grammar
/docs
56 changes: 28 additions & 28 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ The rest of the build and development dependencies are specified, as usual, in t

Tact's pipeline uses a patched version of the FunC compiler vendored as a WASM binary with some JS wrappers, see the following files:

- [src/func/funcfiftlib.js](./src/func/funcfiftlib.js)
- [src/func/funcfiftlib.wasm](./src/func/funcfiftlib.wasm)
- [src/func/funcfiftlib.wasm.js](./src/func/funcfiftlib.wasm.js)
- [src/func/funcfiftlib.js](src/090-func/funcfiftlib.js)
- [src/func/funcfiftlib.wasm](src/090-func/funcfiftlib.wasm)
- [src/func/funcfiftlib.wasm.js](src/090-func/funcfiftlib.wasm.js)

The message of the commit [`f777da3213e3b064a7f407b2569cfd546cca277e`](https://github.com/tact-lang/tact/commit/f777da3213e3b064a7f407b2569cfd546cca277e) explains how the patched version was obtained. We had to patch the FunC compiler because the corresponding [FunC compiler issue](https://github.com/ton-blockchain/ton/issues/971) is unresolved at the time of writing.

Expand Down Expand Up @@ -105,78 +105,78 @@ yarn knip
Tact's command-line interface (CLI) is located in [bin/tact.js](./bin/tact.js).
Tact uses the [meow](https://github.com/sindresorhus/meow) CLI arguments parser.

The main entry point for the Tact CLI is [src/node.ts](./src/node.ts) and [src/pipeline/build.ts](./src/pipeline/build.ts) is the platform-independent compiler driver which contains the high-level compiler pipeline logic described above.
The main entry point for the Tact CLI is [src/node.ts](./src/node.ts) and [src/pipeline/build.ts](src/010-pipeline/build.ts) is the platform-independent compiler driver which contains the high-level compiler pipeline logic described above.

The Tact CLI gets Tact settings from a `tact.config.json` file or creates a default config for a single-file compilation mode. The format of `tact.config.json` files is specified in [schemas/configSchema.json](./schemas/configSchema.json).
The Tact CLI gets Tact settings from a `tact.config.json` file or creates a default config for a single-file compilation mode. The format of `tact.config.json` files is specified in [schemas/configSchema.json](src/000-config/configSchema.json).

The so-called "pre-compilation" steps that include imports resolution, type-checking, building schemas for high-level Tact data structures to be serialized/deserialized as cells (this step is dubbed "allocation") are located in [src/pipeline/precompile.ts](src/pipeline/precompile.ts).
The so-called "pre-compilation" steps that include imports resolution, type-checking, building schemas for high-level Tact data structures to be serialized/deserialized as cells (this step is dubbed "allocation") are located in [src/pipeline/precompile.ts](src/010-pipeline/precompile.ts).

Besides the terminal, the Tact compiler is supposed to work in browser environments as well.

Some CLI tests can be found in [.github/workflows/tact.yml](./.github/workflows/tact.yml) GitHub Action file.

### Parser

The [src/grammar/grammar.ohm](./src/grammar/grammar.ohm) file contains the Tact grammar expressed in the PEG-like language of the [Ohm.js](https://ohmjs.org) parser generator.
The [src/grammar/grammar.ohm](src/050-grammar/grammar.ohm) file contains the Tact grammar expressed in the PEG-like language of the [Ohm.js](https://ohmjs.org) parser generator.

The helper file [src/grammar/grammar.ts](./src/grammar/grammar.ts) contains the logic that transforms concrete syntax trees produced with the help of the Ohm.js-generated parser into abstract syntax trees (ASTs) defined in [src/grammar/ast.ts](./src/grammar/ast.ts). The grammar.ts file also does a bit of grammar validation, like checking that function or constant attributes are not duplicated or that user identifiers do not start with certain reserved prefixes.
The helper file [src/grammar/grammar.ts](src/050-grammar/grammar.ts) contains the logic that transforms concrete syntax trees produced with the help of the Ohm.js-generated parser into abstract syntax trees (ASTs) defined in [src/grammar/ast.ts](src/050-grammar/ast.ts). The grammar.ts file also does a bit of grammar validation, like checking that function or constant attributes are not duplicated or that user identifiers do not start with certain reserved prefixes.

The [src/grammar/test](./src/grammar/test) folder contains Tact files that are supposed to be parsed without any issues, and the [src/grammar/test-failed](./src/grammar/test-failed) folder contains grammatically incorrect test files which should result in parser errors. The parser error messages and the locations they point to are fixed in the [src/grammar/**snapshots**/grammar.spec.ts.snap](./src/grammar/__snapshots__/grammar.spec.ts.snap) Jest snapshot file.
The [src/grammar/test](src/050-grammar/test) folder contains Tact files that are supposed to be parsed without any issues, and the [src/grammar/test-failed](src/050-grammar/test-failed) folder contains grammatically incorrect test files which should result in parser errors. The parser error messages and the locations they point to are fixed in the [src/grammar/**snapshots**/grammar.spec.ts.snap](src/050-grammar/__snapshots__/grammar.spec.ts.snap) Jest snapshot file.

### Typechecker

The Tact type-checker's implementation can be found mostly in the following files:

- [src/types/resolveDescriptors.ts](./src/types/resolveDescriptors.ts) takes care of checking at the level of module-items, data type definitions, function signatures, etc. and it does not deal with statements (so does not traverse function bodies);
- [src/types/resolveStatements.ts](./src/types/resolveStatements.ts) checks statements and statements blocks;
- [src/types/resolveExpression.ts](./src/types/resolveExpression.ts) type-checks the Tact expressions.
- [src/types/resolveDescriptors.ts](src/060-types/resolveDescriptors.ts) takes care of checking at the level of module-items, data type definitions, function signatures, etc. and it does not deal with statements (so does not traverse function bodies);
- [src/types/resolveStatements.ts](src/060-types/resolveStatements.ts) checks statements and statements blocks;
- [src/types/resolveExpression.ts](src/060-types/resolveExpression.ts) type-checks the Tact expressions.

The current implementation of the typechecker is going to be significantly refactored, as per [issue #458](https://github.com/tact-lang/tact/issues/458). The corresponding pull request will have formally specified the Tact typing rules.

Until we have the Tact type system specified, the only source of information about it would be the aforementioned Tact docs and the tests in the following locations:

- [src/types/test](./src/types/test): positive well-formedness tests at the level of data types, contracts, traits and function signatures;
- [src/types/test-failed](./src/types/test-failed): negative well-formedness tests at the level of data types, contracts, traits and function signatures;
- [src/types/stmts](./src/types/stmts): positive type-checking tests at the level of function bodies;
- [src/types/stmts-failed](./src/types/stmts-failed): negative type-checking tests at the level of function bodies;
- [src/test/compilation-failed](./src/test/compilation-failed): negative type-checking tests that require full environment, for instance, the standard library (the other tests in `src/types` don't have access to the full environment).
- [src/types/test](src/060-types/test): positive well-formedness tests at the level of data types, contracts, traits and function signatures;
- [src/types/test-failed](src/060-types/test-failed): negative well-formedness tests at the level of data types, contracts, traits and function signatures;
- [src/types/stmts](src/060-types/stmts): positive type-checking tests at the level of function bodies;
- [src/types/stmts-failed](src/060-types/stmts-failed): negative type-checking tests at the level of function bodies;
- [src/test/compilation-failed](test/compilation-failed): negative type-checking tests that require full environment, for instance, the standard library (the other tests in `src/types` don't have access to the full environment).

### Constant evaluator

The constant evaluator is used as an optimizer to prevent some statically known expressions from being evaluated at run-time and increase gas consumption of the contracts. It will be later extended to perform partial evaluation of contracts and use various simplification rules such as applying some algebraic laws to further reduce gas consumption of contracts at run-time.

The constant evaluator supports a large subset of Tact and handles, for instance, constants defined in terms of other constants, built-in and user-defined functions, logical and arithmetic operations.

The main logic of the constant evaluator can be found in the file [src/interpreter.ts](./src/interpreter.ts).
The main logic of the constant evaluator can be found in the file [src/interpreter.ts](src/070-optimizer/interpreter.ts).

You can find the relevant tests in [src/test/e2e-emulated/contracts/constants.tact](./src/test/e2e-emulated/contracts/constants.tact) and the corresponding spec-file: [](./src/test/e2e-emulated/constants.spec.ts).
You can find the relevant tests in [src/test/e2e-emulated/contracts/constants.tact](test/e2e-emulated/contracts/constants.tact) and the corresponding spec-file: [](test/e2e-emulated/constants.spec.ts).

The negative tests for constant evaluation are contained in the Tact files prefixed with `const-eval` in the [src/test/compilation-failed/contracts](./src/test/compilation-failed/contracts) folder.
The negative tests for constant evaluation are contained in the Tact files prefixed with `const-eval` in the [src/test/compilation-failed/contracts](test/compilation-failed/contracts) folder.

### Code generator

Some general information on how Tact code maps to FunC is described in the Tact docs: <https://docs.tact-lang.org/book/func>.

The code generator lives in the [src/generator](./src/generator) sub-folder with the entry point in [src/generator/writeProgram.ts](./src/generator/writeProgram.ts).
The code generator lives in the [src/generator](./src/080-generator) sub-folder with the entry point in [src/generator/writeProgram.ts](src/080-generator/writeProgram.ts).

The implementation that we have right now is being refactored to produce FunC ASTs and then pretty-print those ASTs as strings instead of producing source FunC code in one step. Here is the relevant pull request: <https://github.com/tact-lang/tact/pull/559>.

One can find the end-to-end codegen test spec files in the [src/test/e2e-emulated](./src/test/e2e-emulated/) folder. The test contracts are located in [src/test/e2e-emulated/contracts](./src/test/e2e-emulated/contracts) subfolder. Many of those spec files test various language features in relative isolation.
An important spec file that tests argument passing semantics for functions and assignment semantics for variables is here: [src/test/e2e-emulated/semantics.spec.ts](./src/test/e2e-emulated/semantics.spec.ts).
One can find the end-to-end codegen test spec files in the [src/test/e2e-emulated](test/e2e-emulated/) folder. The test contracts are located in [src/test/e2e-emulated/contracts](test/e2e-emulated/contracts) subfolder. Many of those spec files test various language features in relative isolation.
An important spec file that tests argument passing semantics for functions and assignment semantics for variables is here: [src/test/e2e-emulated/semantics.spec.ts](test/e2e-emulated/semantics.spec.ts).

Note: If you add an end-to-end test contract, you also need to include it into [tact.config.json](./tact.config.json) and run `yarn gen` to compile it and create TypeScript wrappers.

`yarn gen` also re-compiles test contracts, so it's important to run it when code generation is changed.

Some other codegen tests are as follows:

- [src/test/exit-codes](./src/test/exit-codes): test that certain actions produce the expected exit codes;
- [src/test/codegen](./src/test/codegen/): test that these contracts compile just fine without running any dynamic tests: bug fixes for FunC code generation often add tests into this folder.
- [src/test/exit-codes](test/exit-codes): test that certain actions produce the expected exit codes;
- [src/test/codegen](test/codegen/): test that these contracts compile just fine without running any dynamic tests: bug fixes for FunC code generation often add tests into this folder.

### Pretty-printer and AST comparators

The entry point to the Tact AST pretty-printer is [src/prettyPrinter.ts](./src/prettyPrinter.ts). It is going to be used for the Tact source code formatter once the parser keeps comments and other relevant information.
The entry point to the Tact AST pretty-printer is [src/prettyPrinter.ts](src/prettyPrinter/index.ts). It is going to be used for the Tact source code formatter once the parser keeps comments and other relevant information.

The AST comparator is defined in [src/grammar/compare.ts](./src/grammar/compare.ts). This is useful, for instance, for static analysis tools which can re-use the Tact TypeScript API.
The AST comparator is defined in [src/grammar/compare.ts](src/050-grammar/compare.ts). This is useful, for instance, for static analysis tools which can re-use the Tact TypeScript API.

The corresponding test spec files can be found in [src/test](./src/test/) folder with the test contracts in [src/test/contracts](./src/test/contracts/) folder.
The corresponding test spec files can be found in [src/test](./src/test/) folder with the test contracts in [src/test/contracts](test/contracts/) folder.
2 changes: 1 addition & 1 deletion STYLEGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export const includes = <const K extends string>(
- **Avoid unnecessary bigint**. We have to work with `bigint`, because TVM supports ints of 257 bit length, but in rest of the code `bigint` would only cause issues with debugging it.
- **Beware of `${}`** in template strings. Any inlining succeeds, and there won't be any compile-time errors even if it's a function `${(x: number) => x}`.
- **Avoid `null`**. `typeof null === 'object'`, and there is `undefined` anyway.
- **Avoid exceptions**. Exceptions are untyped. Pass error continuations explicitly `(onFooError: () => T) => T`. Example can be found in `src/grammar/parser-error.ts`.
- **Avoid exceptions**. Exceptions are untyped. Pass error continuations explicitly `(onFooError: () => T) => T`. Example can be found in `src/050-grammar/parser-error.ts`.
- **Avoid tuples**. TS gives them minimal distinction from arrays, and type system is broken around them. Occasionally for performance reasons tuples might be a better option than objects.
- **Avoid `enum`**. It's equivalent to unions since 5.0, except generates boilerplate JS code. A version that doesn't generate extraneous code, `const enum`, is not properly supported by `babel`.
- **Avoid iterators**. They're untypable unless fixed in JS standard. Prefer generators. Prefer iterating with `for (... of ...)`.
44 changes: 22 additions & 22 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,28 +150,28 @@
"node_modules",
"dist",
"func",
"grammar/sample.json",
"src/generator/writers/writeStdlib.ts",
"src/grammar/grammar.ohm-bundle.d.ts",
"src/grammar/test/items-native-fun-funcid.tact",
"src/grammar/test/items-asm-funs.tact",
"src/grammar/test-asm/*.tact",
"src/grammar/test-failed/funcid-*.tact",
"src/grammar/next/grammar.gg",
"src/grammar/next/grammar.ts",
"src/imports/stdlib.ts",
"/src/test/compilation-failed/const-eval-failed.spec.ts",
"src/test/e2e-emulated/address.spec.ts",
"src/test/e2e-emulated/intrinsics.spec.ts",
"src/test/e2e-emulated/optionals.spec.ts",
"src/test/e2e-emulated/strings.spec.ts",
"src/test/e2e-emulated/contracts/intrinsics.tact",
"src/test/e2e-emulated/contracts/strings.tact",
"src/test/e2e-emulated/contracts/dns.tact",
"src/test/compilation-fail/fail-const-eval.spec.ts",
"src/test/e2e-emulated/getter-names-conflict.spec.ts",
"src/test/exit-codes/contracts/compute-phase-errors.tact",
"stdlib/stdlib.fc",
"src/040-imports/stdlib.ts",
"src/040-imports/stdlib/stdlib.fc",
"src/050-grammar/grammar.ohm-bundle.d.ts",
"src/050-grammar/test/items-native-fun-funcid.tact",
"src/050-grammar/test/items-asm-funs.tact",
"src/050-grammar/test-asm/*.tact",
"src/050-grammar/test-failed/funcid-*.tact",
"src/050-grammar/next/grammar.gg",
"src/050-grammar/next/grammar.ts",
"src/080-generator/writers/writeStdlib.ts",
"src/090-func/funcfiftlib.js",
"src/090-func/funcCompile.ts",
"test/e2e-emulated/address.spec.ts",
"test/e2e-emulated/intrinsics.spec.ts",
"test/e2e-emulated/optionals.spec.ts",
"test/e2e-emulated/strings.spec.ts",
"test/e2e-emulated/contracts/intrinsics.tact",
"test/e2e-emulated/contracts/strings.tact",
"test/e2e-emulated/contracts/dns.tact",
"test/e2e-emulated/getter-names-conflict.spec.ts",
"test/compilation-failed/const-eval-failed.spec.ts",
"test/exit-codes/contracts/compute-phase-errors.tact",
"/docs"
]
}
41 changes: 41 additions & 0 deletions examples/examples.build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import fs from "fs";
import { run } from "../src/node";
import path from "path";
import { glob } from "glob";
import { verify } from "./verify";
import { Logger } from "../src/010-pipeline/logger";
import { __DANGER__disableVersionNumber } from "../src/010-pipeline/version";

const configPath = path.join(__dirname, "tact.config.json");
const packagePath = path.resolve(__dirname, "output", "*.pkg");

// Read cases
void (async () => {
// Disable version number in packages
__DANGER__disableVersionNumber();

const logger = new Logger();

try {
// Compile projects
const compileResult = await run({
configPath,
});
if (!compileResult.ok) {
throw new Error("Tact projects compilation failed");
}

// Verify projects
for (const pkgPath of glob.sync(path.normalize(packagePath))) {
const res = await verify({
pkg: fs.readFileSync(pkgPath, "utf-8"),
});
if (!res.ok) {
throw new Error(`Failed to verify ${pkgPath}: ${res.error}`);
}
}
} catch (error) {
logger.error(error as Error);
process.exit(1);
}
})();
Loading
Loading