tact-lang / tact

Tact compiler main repository
https://tact-lang.org
MIT License
393 stars 110 forks source link

Tact frontend API: Improvements for tooling #314

Open byakuren-hijiri opened 6 months ago

byakuren-hijiri commented 6 months ago

There are a few possible ways to improve the Tact frontend API that would be helpful for tooling:

These are my points after working with the Tact API for a while. Feel free to discuss and extend them and create separate issues from each checkbox when working on these.

novusnota commented 6 months ago

Save types to AST or improve an access API to type information.

This would be insanely useful in tools like language server and such!

In general, I agree with all those points, but implementation of some may just require us to make our own lexer→parser→semantic analysis pipeline, suitable for compiler AND external tooling depending on various steps in it. I'd say this depends on #286, but I may be wrong and we could pull off such feat without compromising the Ohm's toolkit.

byakuren-hijiri commented 6 months ago

I would also suggest creating named union types for AST entries used in fields. For example:

export type ASTContract = {
    kind: 'def_contract';
    origin: TypeOrigin;
    id: number;
    name: string;
    traits: ASTString[];
    attributes: ASTContractAttribute[];
    declarations: (ASTField | ASTFunction | ASTInitFunction | ASTReceive | ASTConstant)[];
    ref: ASTRef;
};

Could be rewritten as:

export type ASTContractDeclaration = (ASTField | ASTFunction | ASTInitFunction | ASTReceive | ASTConstant);
export type ASTContract = {
    kind: 'def_contract';
    origin: TypeOrigin;
    id: number;
    name: string;
    traits: ASTString[];
    attributes: ASTContractAttribute[];
    declarations: ASTContractDeclaration[];
    ref: ASTRef;
};

This will simplify the life of tooling developers by enabling them to reuse these type definitions from the compiler. Otherwise, I find myself copy-pasting these entries in my projects. Here is an example of a function with such a signature implemented in the static analyzer internals:

function getMethodInfo(
    decl: ASTField | ASTFunction | ASTInitFunction | ASTReceive | ASTConstant,
  ): [string | undefined, FunctionKind | undefined] {
byakuren-hijiri commented 5 months ago

Added three more points:

Add more context to every internal Error to be thrown in compiler internals. This is crucial for debugging third-party tools. Add AST iterators that perform functional map and fold over nested nodes of the AST. This will enable API users to inspect the AST in a more convenient way, for example, sorting nodes of a certain type. Add an API that provides equivalence checks between AST nodes of the same type. This is needed, for example, in https://github.com/tact-lang/tact/pull/335 to implement unit tests.

byakuren-hijiri commented 4 months ago

Added while working on tests for https://github.com/tact-lang/tact/pull/559:

  • [ ] Refactoring: Extract methods from the build function (src/pipeline/build.ts) to make it more modular. We need to separate the build functionality from CLI parsing and use different methods to create context, compile, and precompile. This is important to implement in order to enable third-party tools to hook into the compilation pipeline in the most flexible way. Perhaps, the best way to achieve this functionality is to create the Builder class with public methods defining the pipeline.