From 85f71ddd5ffd252b9c551ea4d6bf83039f070caa Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Thu, 6 Mar 2025 12:38:32 +0100 Subject: [PATCH 01/10] fix: union with parsedModules. --- src/context/store.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/context/store.ts b/src/context/store.ts index 43b9d89df..8e1ec82c8 100644 --- a/src/context/store.ts +++ b/src/context/store.ts @@ -53,7 +53,9 @@ export function parseModules(sources: Source[], parser: Parser): A.AstModule[] { * Extends the compiler context by adding AST entries and source information from * given sources and parsed programs. * @public - * @param parsedModules An optional array of previously parsed programs. If not defined, they will be parsed from `sources`. + * @param parsedModules An optional array of previously parsed programs. + * If not defined, they will be parsed from `sources`. + * If defined, the function will take the union of `parsedModules` with the parsed modules in `sources`. * @returns The updated compiler context. */ export function openContext( @@ -63,7 +65,11 @@ export function openContext( parser: Parser, parsedModules?: A.AstModule[], ): CompilerContext { - const modules = parsedModules ?? parseModules(sources, parser); + const parsedSources = parseModules(sources, parser); + const modules = + typeof parsedModules === "undefined" + ? parsedSources + : [...parsedSources, ...parsedModules]; const types: A.AstTypeDecl[] = []; const functions: ( | A.AstNativeFunctionDecl From bcef0e3764d77e4d33b19a568f63b2a42c6b94cf Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Thu, 6 Mar 2025 13:57:55 +0100 Subject: [PATCH 02/10] test: Added test that shows AST with stdlib references now passes pre-compile. --- src/test/pipeline/empty.tact | 0 src/test/pipeline/precompile-ast.spec.ts | 152 +++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 src/test/pipeline/empty.tact create mode 100644 src/test/pipeline/precompile-ast.spec.ts diff --git a/src/test/pipeline/empty.tact b/src/test/pipeline/empty.tact new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/pipeline/precompile-ast.spec.ts b/src/test/pipeline/precompile-ast.spec.ts new file mode 100644 index 000000000..15ef77abc --- /dev/null +++ b/src/test/pipeline/precompile-ast.spec.ts @@ -0,0 +1,152 @@ +import path from "path"; +import type * as A from "../../ast/ast"; +import { getAstFactory } from "../../ast/ast-helpers"; +import { CompilerContext } from "../../context/context"; +import { defaultParser, getParser } from "../../grammar/grammar"; +import { precompile } from "../../pipeline/precompile"; +import files from "../../stdlib/stdlib"; +import { createVirtualFileSystem } from "../../vfs/createVirtualFileSystem"; +import fs from "fs"; +import { getSrcInfo } from "../../grammar/src-info"; + +describe("pre-compilation of ASTs", () => { + const astF = getAstFactory(); + // Using dummySrcInfo causes internal compiler error. So, just use this with a blank empty source, since there is no source file. + const emptySrcInfo = getSrcInfo(" ", 0, 0, null, "user"); + + // This function manually creates a module containing a contract with a reference to StateInit in its single field. + // StateInit is declared in stdlib. + // + // contract Test { + // f: StateInit + // + // init() { + // self.f = initOf Test(); + // } + // } + + function makeModule(): A.AstModule { + return astF.createNode({ + kind: "module", + imports: [], + items: [makeContract()], + }) as A.AstModule; + } + + function makeId(name: string): A.AstId { + return astF.createNode({ + kind: "id", + text: name, + loc: emptySrcInfo, + }) as A.AstId; + } + + function makeTypeId(name: string): A.AstTypeId { + return astF.createNode({ + kind: "type_id", + text: name, + loc: emptySrcInfo, + }) as A.AstTypeId; + } + + function makeInitOf( + contract: A.AstId, + args: A.AstExpression[], + ): A.AstInitOf { + return astF.createNode({ + kind: "init_of", + args, + contract, + loc: emptySrcInfo, + }) as A.AstInitOf; + } + + function makeAssignStatement( + path: A.AstExpression, + expr: A.AstExpression, + ): A.AstStatementAssign { + return astF.createNode({ + kind: "statement_assign", + path: path, + expression: expr, + loc: emptySrcInfo, + }) as A.AstStatementAssign; + } + + function makeFieldAccess( + aggregate: A.AstExpression, + field: A.AstId, + ): A.AstFieldAccess { + return astF.createNode({ + kind: "field_access", + aggregate, + field, + loc: emptySrcInfo, + }) as A.AstFieldAccess; + } + + function makeContractField( + name: A.AstId, + type: A.AstTypeId, + expr: A.AstExpression | undefined, + ): A.AstFieldDecl { + return astF.createNode({ + kind: "field_decl", + name, + type, + as: undefined, + initializer: expr, + loc: emptySrcInfo, + }) as A.AstFieldDecl; + } + + function makeContractInit(): A.AstContractInit { + const initOfExpr = makeInitOf(makeId("Test"), []); + const path = makeFieldAccess(makeId("self"), makeId("f")); + const assignStmt = makeAssignStatement(path, initOfExpr); + return astF.createNode({ + kind: "contract_init", + params: [], + statements: [assignStmt], + loc: emptySrcInfo, + }) as A.AstContractInit; + } + + function makeContract(): A.AstContract { + const field = makeContractField( + makeId("f"), + makeTypeId("StateInit"), + undefined, + ); + const init = makeContractInit(); + return astF.createNode({ + kind: "contract", + name: makeId("Test"), + params: undefined, + traits: [], + attributes: [], + declarations: [field, init], + loc: emptySrcInfo, + }) as A.AstContract; + } + + it("should pass pre-compilation of AST with references to stdlib", () => { + const ctx = new CompilerContext(); + + // An empty tact file is required so that pre-compile does not complain about + // non-existence of an entry point. + const fileSystem = { + ["empty.tact"]: fs + .readFileSync(path.join(__dirname, "empty.tact")) + .toString("base64"), + }; + + const project = createVirtualFileSystem("/", fileSystem, false); + const stdlib = createVirtualFileSystem("@stdlib", files); + const parser = getParser(astF, defaultParser); + + precompile(ctx, project, stdlib, "empty.tact", parser, astF, [ + makeModule(), + ]); + }); +}); From 750191a5d02d239fb7c5beea01b13028bc1147da Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Thu, 6 Mar 2025 14:43:08 +0100 Subject: [PATCH 03/10] tests: more tests, including a negative one. --- .../__snapshots__/precompile-ast.spec.ts.snap | 8 ++++ src/test/pipeline/dummy.tact | 7 +++ src/test/pipeline/precompile-ast.spec.ts | 43 ++++++++++++++++++- 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/test/pipeline/__snapshots__/precompile-ast.spec.ts.snap create mode 100644 src/test/pipeline/dummy.tact diff --git a/src/test/pipeline/__snapshots__/precompile-ast.spec.ts.snap b/src/test/pipeline/__snapshots__/precompile-ast.spec.ts.snap new file mode 100644 index 000000000..045489dd1 --- /dev/null +++ b/src/test/pipeline/__snapshots__/precompile-ast.spec.ts.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`pre-compilation of ASTs should fail pre-compilation when source files and a manual AST have declaration clashes 1`] = ` +"Type "Test" already exists +> 1 | + ^ +" +`; diff --git a/src/test/pipeline/dummy.tact b/src/test/pipeline/dummy.tact new file mode 100644 index 000000000..427f3123d --- /dev/null +++ b/src/test/pipeline/dummy.tact @@ -0,0 +1,7 @@ +contract Test { + f: StateInit; + + init() { + self.f = initOf Test(); + } +} \ No newline at end of file diff --git a/src/test/pipeline/precompile-ast.spec.ts b/src/test/pipeline/precompile-ast.spec.ts index 15ef77abc..a3cc4e770 100644 --- a/src/test/pipeline/precompile-ast.spec.ts +++ b/src/test/pipeline/precompile-ast.spec.ts @@ -18,7 +18,7 @@ describe("pre-compilation of ASTs", () => { // StateInit is declared in stdlib. // // contract Test { - // f: StateInit + // f: StateInit; // // init() { // self.f = initOf Test(); @@ -149,4 +149,45 @@ describe("pre-compilation of ASTs", () => { makeModule(), ]); }); + + it("should pass pre-compilation with no manual AST", () => { + const ctx = new CompilerContext(); + + // The dummy.tact file contains exactly the same declarations + // carried out by the function makeModule() + const fileSystem = { + ["dummy.tact"]: fs + .readFileSync(path.join(__dirname, "dummy.tact")) + .toString("base64"), + }; + + const project = createVirtualFileSystem("/", fileSystem, false); + const stdlib = createVirtualFileSystem("@stdlib", files); + const parser = getParser(astF, defaultParser); + + precompile(ctx, project, stdlib, "dummy.tact", parser, astF); + }); + + it("should fail pre-compilation when source files and a manual AST have declaration clashes", () => { + const ctx = new CompilerContext(); + + // The dummy.tact file contains exactly the same declarations + // carried out by the function makeModule() + const fileSystem = { + ["dummy.tact"]: fs + .readFileSync(path.join(__dirname, "dummy.tact")) + .toString("base64"), + }; + + const project = createVirtualFileSystem("/", fileSystem, false); + const stdlib = createVirtualFileSystem("@stdlib", files); + const parser = getParser(astF, defaultParser); + + // So, a clash should occur here, since dummy.tact and makeModule() both declare the contract Test. + expect(() => + precompile(ctx, project, stdlib, "dummy.tact", parser, astF, [ + makeModule(), + ]), + ).toThrowErrorMatchingSnapshot(); + }); }); From 65c917132ebd40af9b42f9a269903c7e2b31b8df Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Thu, 20 Mar 2025 11:51:41 +0100 Subject: [PATCH 04/10] refactor: make parsedModules a required argument in `opencontext` function. --- src/context/store.ts | 12 ++--------- src/generator/writers/resolveFuncType.spec.ts | 17 +++++++++++----- src/generator/writers/writeExpression.spec.ts | 10 +++++++--- .../writers/writeSerialization.spec.ts | 10 +++++++--- .../test/interpreter-eval-failed.spec.ts | 10 +++++++--- .../test/interpreter-eval-success.spec.ts | 10 +++++++--- src/pipeline/precompile.ts | 10 ++++++++-- src/storage/resolveAllocation.spec.ts | 14 +++++++------ src/test/pipeline/precompile-ast.spec.ts | 14 ++++++------- src/types/effects.spec.ts | 20 ++++++++++--------- src/types/resolveDescriptors.spec.ts | 17 +++++++++++----- src/types/resolveStatements.spec.ts | 17 +++++++++++----- 12 files changed, 99 insertions(+), 62 deletions(-) diff --git a/src/context/store.ts b/src/context/store.ts index e148d99bf..0e5ee8382 100644 --- a/src/context/store.ts +++ b/src/context/store.ts @@ -53,23 +53,15 @@ export function parseModules(sources: Source[], parser: Parser): A.AstModule[] { * Extends the compiler context by adding AST entries and source information from * given sources and parsed programs. * @public - * @param parsedModules An optional array of previously parsed programs. - * If not defined, they will be parsed from `sources`. - * If defined, the function will take the union of `parsedModules` with the parsed modules in `sources`. + * @param modules Previously parsed sources. * @returns The updated compiler context. */ export function openContext( ctx: CompilerContext, sources: Source[], funcSources: { code: string; path: string }[], - parser: Parser, - parsedModules?: A.AstModule[], + modules: A.AstModule[], ): CompilerContext { - const parsedSources = parseModules(sources, parser); - const modules = - typeof parsedModules === "undefined" - ? parsedSources - : [...parsedSources, ...parsedModules]; const types: A.AstTypeDecl[] = []; const functions: ( | A.AstNativeFunctionDecl diff --git a/src/generator/writers/resolveFuncType.spec.ts b/src/generator/writers/resolveFuncType.spec.ts index 1d120edd0..a70bf5db5 100644 --- a/src/generator/writers/resolveFuncType.spec.ts +++ b/src/generator/writers/resolveFuncType.spec.ts @@ -2,9 +2,10 @@ import { getAstFactory } from "../../ast/ast-helpers"; import { resolveDescriptors } from "../../types/resolveDescriptors"; import { WriterContext } from "../Writer"; import { resolveFuncType } from "./resolveFuncType"; -import { openContext } from "../../context/store"; +import { openContext, parseModules } from "../../context/store"; import { CompilerContext } from "../../context/context"; import { getParser } from "../../grammar"; +import type { Source } from "../../imports/source"; const primitiveCode = ` primitive Int; @@ -48,11 +49,14 @@ contract Contract2 { describe("resolveFuncType", () => { it("should process primitive types", () => { const ast = getAstFactory(); + const sources: Source[] = [ + { code: primitiveCode, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: primitiveCode, path: "", origin: "user" }], + sources, [], - getParser(ast), + parseModules(sources, getParser(ast)), ); ctx = resolveDescriptors(ctx, ast); const wCtx = new WriterContext(ctx, "Contract1"); @@ -117,11 +121,14 @@ describe("resolveFuncType", () => { it("should process contract and struct types", () => { const ast = getAstFactory(); + const sources: Source[] = [ + { code: primitiveCode, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: primitiveCode, path: "", origin: "user" }], + sources, [], - getParser(ast), + parseModules(sources, getParser(ast)), ); ctx = resolveDescriptors(ctx, ast); const wCtx = new WriterContext(ctx, "Contract1"); diff --git a/src/generator/writers/writeExpression.spec.ts b/src/generator/writers/writeExpression.spec.ts index 267bf2380..38c453601 100644 --- a/src/generator/writers/writeExpression.spec.ts +++ b/src/generator/writers/writeExpression.spec.ts @@ -4,11 +4,12 @@ import { } from "../../types/resolveDescriptors"; import { WriterContext } from "../Writer"; import { writeExpression } from "./writeExpression"; -import { openContext } from "../../context/store"; +import { openContext, parseModules } from "../../context/store"; import { resolveStatements } from "../../types/resolveStatements"; import { CompilerContext } from "../../context/context"; import { getParser } from "../../grammar"; import { getAstFactory } from "../../ast/ast-helpers"; +import type { Source } from "../../imports/source"; const code = ` @@ -71,11 +72,14 @@ const golden: string[] = [ describe("writeExpression", () => { it("should write expression", () => { const ast = getAstFactory(); + const sources: Source[] = [ + { code: code, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: code, path: "", origin: "user" }], + sources, [], - getParser(ast), + parseModules(sources, getParser(ast)), ); ctx = resolveDescriptors(ctx, ast); ctx = resolveStatements(ctx); diff --git a/src/generator/writers/writeSerialization.spec.ts b/src/generator/writers/writeSerialization.spec.ts index ded6b4420..d8b598c01 100644 --- a/src/generator/writers/writeSerialization.spec.ts +++ b/src/generator/writers/writeSerialization.spec.ts @@ -11,10 +11,11 @@ import { import { WriterContext } from "../Writer"; import { writeParser, writeSerializer } from "./writeSerialization"; import { writeStdlib } from "./writeStdlib"; -import { openContext } from "../../context/store"; +import { openContext, parseModules } from "../../context/store"; import { writeAccessors } from "./writeAccessors"; import { getParser } from "../../grammar"; import { getAstFactory } from "../../ast/ast-helpers"; +import type { Source } from "../../imports/source"; const code = ` primitive Int; @@ -60,11 +61,14 @@ describe("writeSerialization", () => { for (const s of ["A", "B", "C"]) { it("should write serializer for " + s, () => { const ast = getAstFactory(); + const sources: Source[] = [ + { code, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code, path: "", origin: "user" }], + sources, [], - getParser(ast), + parseModules(sources, getParser(ast)), ); ctx = resolveDescriptors(ctx, ast); ctx = resolveAllocations(ctx); diff --git a/src/optimizer/test/interpreter-eval-failed.spec.ts b/src/optimizer/test/interpreter-eval-failed.spec.ts index 1500110dd..908db4cd7 100644 --- a/src/optimizer/test/interpreter-eval-failed.spec.ts +++ b/src/optimizer/test/interpreter-eval-failed.spec.ts @@ -1,7 +1,8 @@ import { getAstFactory } from "../../ast/ast-helpers"; import { CompilerContext } from "../../context/context"; -import { openContext } from "../../context/store"; +import { openContext, parseModules } from "../../context/store"; import { getParser } from "../../grammar"; +import type { Source } from "../../imports/source"; import { evalComptimeExpressions } from "../../types/evalComptimeExpressions"; import { resolveDescriptors } from "../../types/resolveDescriptors"; import { resolveSignatures } from "../../types/resolveSignatures"; @@ -12,11 +13,14 @@ describe("interpreter-evaluation", () => { for (const r of loadCases(__dirname + "/failed/")) { it(`${r.name} should fail compilation`, () => { const Ast = getAstFactory(); + const sources: Source[] = [ + { code: r.code, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: r.code, path: "", origin: "user" }], + sources, [], - getParser(Ast), + parseModules(sources, getParser(Ast)), ); expect(() => { ctx = resolveDescriptors(ctx, Ast); diff --git a/src/optimizer/test/interpreter-eval-success.spec.ts b/src/optimizer/test/interpreter-eval-success.spec.ts index 504fad194..9a1eaf052 100644 --- a/src/optimizer/test/interpreter-eval-success.spec.ts +++ b/src/optimizer/test/interpreter-eval-success.spec.ts @@ -1,7 +1,8 @@ import { getAstFactory } from "../../ast/ast-helpers"; import { CompilerContext } from "../../context/context"; -import { openContext } from "../../context/store"; +import { openContext, parseModules } from "../../context/store"; import { getParser } from "../../grammar"; +import type { Source } from "../../imports/source"; import { evalComptimeExpressions } from "../../types/evalComptimeExpressions"; import { resolveDescriptors } from "../../types/resolveDescriptors"; import { getAllExpressionTypes } from "../../types/resolveExpression"; @@ -13,11 +14,14 @@ describe("interpreter-evaluation", () => { for (const r of loadCases(__dirname + "/success/")) { it(`${r.name} should pass compilation`, () => { const Ast = getAstFactory(); + const sources: Source[] = [ + { code: r.code, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: r.code, path: "", origin: "user" }], + sources, [], - getParser(Ast), + parseModules(sources, getParser(Ast)), ); ctx = resolveDescriptors(ctx, Ast); ctx = resolveStatements(ctx); diff --git a/src/pipeline/precompile.ts b/src/pipeline/precompile.ts index d1ad69308..0ec7c2e79 100644 --- a/src/pipeline/precompile.ts +++ b/src/pipeline/precompile.ts @@ -1,7 +1,7 @@ import type { CompilerContext } from "../context/context"; import { resolveDescriptors } from "../types/resolveDescriptors"; import { resolveAllocations } from "../storage/resolveAllocation"; -import { openContext } from "../context/store"; +import { openContext, parseModules } from "../context/store"; import { resolveStatements } from "../types/resolveStatements"; import { resolveErrors } from "../types/resolveErrors"; import { resolveSignatures } from "../types/resolveSignatures"; @@ -25,8 +25,14 @@ export function precompile( // Load all sources const imported = resolveImports({ entrypoint, project, stdlib, parser }); + // Parse the sources and attach the given parsed modules + const finalModules = [ + ...parseModules(imported.tact, parser), + ...(parsedModules ?? []), + ]; + // Add information about all the source code entries to the context - ctx = openContext(ctx, imported.tact, imported.func, parser, parsedModules); + ctx = openContext(ctx, imported.tact, imported.func, finalModules); // First load type descriptors and check that // they all have valid signatures diff --git a/src/storage/resolveAllocation.spec.ts b/src/storage/resolveAllocation.spec.ts index bbe353410..c3f82228f 100644 --- a/src/storage/resolveAllocation.spec.ts +++ b/src/storage/resolveAllocation.spec.ts @@ -1,7 +1,7 @@ import fs from "fs"; import { resolveDescriptors } from "../types/resolveDescriptors"; import { getAllocations, resolveAllocations } from "./resolveAllocation"; -import { openContext } from "../context/store"; +import { openContext, parseModules } from "../context/store"; import { resolveStatements } from "../types/resolveStatements"; import { CompilerContext } from "../context/context"; import { resolveSignatures } from "../types/resolveSignatures"; @@ -9,6 +9,7 @@ import path from "path"; import { getParser } from "../grammar"; import { getAstFactory } from "../ast/ast-helpers"; import { stdlibPath } from "../stdlib/path"; +import type { Source } from "../imports/source"; const primitivesPath = path.join(stdlibPath, "/std/internal/primitives.tact"); const stdlib = fs.readFileSync(primitivesPath, "utf-8"); @@ -65,14 +66,15 @@ contract Sample { describe("resolveAllocation", () => { it("should write program", () => { const ast = getAstFactory(); + const sources: Source[] = [ + { code: stdlib, path: primitivesPath, origin: "stdlib" }, + { code: src, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [ - { code: stdlib, path: primitivesPath, origin: "stdlib" }, - { code: src, path: "", origin: "user" }, - ], + sources, [], - getParser(ast), + parseModules(sources, getParser(ast)), ); ctx = resolveDescriptors(ctx, ast); ctx = resolveSignatures(ctx, ast); diff --git a/src/test/pipeline/precompile-ast.spec.ts b/src/test/pipeline/precompile-ast.spec.ts index a3cc4e770..8cd6477a0 100644 --- a/src/test/pipeline/precompile-ast.spec.ts +++ b/src/test/pipeline/precompile-ast.spec.ts @@ -2,12 +2,12 @@ import path from "path"; import type * as A from "../../ast/ast"; import { getAstFactory } from "../../ast/ast-helpers"; import { CompilerContext } from "../../context/context"; -import { defaultParser, getParser } from "../../grammar/grammar"; import { precompile } from "../../pipeline/precompile"; import files from "../../stdlib/stdlib"; import { createVirtualFileSystem } from "../../vfs/createVirtualFileSystem"; import fs from "fs"; import { getSrcInfo } from "../../grammar/src-info"; +import { getParser } from "../../grammar"; describe("pre-compilation of ASTs", () => { const astF = getAstFactory(); @@ -136,14 +136,12 @@ describe("pre-compilation of ASTs", () => { // An empty tact file is required so that pre-compile does not complain about // non-existence of an entry point. const fileSystem = { - ["empty.tact"]: fs - .readFileSync(path.join(__dirname, "empty.tact")) - .toString("base64"), + ["empty.tact"]: "", }; const project = createVirtualFileSystem("/", fileSystem, false); const stdlib = createVirtualFileSystem("@stdlib", files); - const parser = getParser(astF, defaultParser); + const parser = getParser(astF); precompile(ctx, project, stdlib, "empty.tact", parser, astF, [ makeModule(), @@ -163,9 +161,9 @@ describe("pre-compilation of ASTs", () => { const project = createVirtualFileSystem("/", fileSystem, false); const stdlib = createVirtualFileSystem("@stdlib", files); - const parser = getParser(astF, defaultParser); + const parser = getParser(astF); - precompile(ctx, project, stdlib, "dummy.tact", parser, astF); + precompile(ctx, project, stdlib, "dummy.tact", parser, astF, []); }); it("should fail pre-compilation when source files and a manual AST have declaration clashes", () => { @@ -181,7 +179,7 @@ describe("pre-compilation of ASTs", () => { const project = createVirtualFileSystem("/", fileSystem, false); const stdlib = createVirtualFileSystem("@stdlib", files); - const parser = getParser(astF, defaultParser); + const parser = getParser(astF); // So, a clash should occur here, since dummy.tact and makeModule() both declare the contract Test. expect(() => diff --git a/src/types/effects.spec.ts b/src/types/effects.spec.ts index fb759748e..ffd6614b1 100644 --- a/src/types/effects.spec.ts +++ b/src/types/effects.spec.ts @@ -1,28 +1,30 @@ import { getAllTypes, resolveDescriptors } from "./resolveDescriptors"; import { loadCases } from "../utils/loadCases"; -import { openContext } from "../context/store"; +import { openContext, parseModules } from "../context/store"; import { resolveStatements } from "./resolveStatements"; import { CompilerContext } from "../context/context"; import { featureEnable } from "../config/features"; import { getParser } from "../grammar"; import { getAstFactory } from "../ast/ast-helpers"; import { computeReceiversEffects } from "./effects"; +import type { Source } from "../imports/source"; describe("effects", () => { for (const testContract of loadCases(__dirname + "/effects/")) { it(`should correctly compute effects: ${testContract.name}`, () => { const Ast = getAstFactory(); + const sources: Source[] = [ + { + code: testContract.code, + path: "", + origin: "user", + }, + ]; let ctx = openContext( new CompilerContext(), - [ - { - code: testContract.code, - path: "", - origin: "user", - }, - ], + sources, [], - getParser(Ast), + parseModules(sources, getParser(Ast)), ); ctx = featureEnable(ctx, "external"); ctx = resolveDescriptors(ctx, Ast); diff --git a/src/types/resolveDescriptors.spec.ts b/src/types/resolveDescriptors.spec.ts index f928592d1..a2bc37302 100644 --- a/src/types/resolveDescriptors.spec.ts +++ b/src/types/resolveDescriptors.spec.ts @@ -6,7 +6,7 @@ import { } from "./resolveDescriptors"; import { resolveSignatures } from "./resolveSignatures"; import { loadCases } from "../utils/loadCases"; -import { openContext } from "../context/store"; +import { openContext, parseModules } from "../context/store"; import { featureEnable } from "../config/features"; import type { SrcInfo } from "../grammar"; import { getParser } from "../grammar"; @@ -14,6 +14,7 @@ import { getAstFactory } from "../ast/ast-helpers"; import { isSrcInfo } from "../grammar/src-info"; import { resolveStatements } from "./resolveStatements"; import { evalComptimeExpressions } from "./evalComptimeExpressions"; +import type { Source } from "../imports/source"; expect.addSnapshotSerializer({ test: (src) => isSrcInfo(src), @@ -24,11 +25,14 @@ describe("resolveDescriptors", () => { for (const r of loadCases(__dirname + "/test/")) { it("should resolve descriptors for " + r.name, () => { const Ast = getAstFactory(); + const sources: Source[] = [ + { code: r.code, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: r.code, path: "", origin: "user" }], + sources, [], - getParser(Ast), + parseModules(sources, getParser(Ast)), ); ctx = featureEnable(ctx, "external"); ctx = resolveDescriptors(ctx, Ast); @@ -40,11 +44,14 @@ describe("resolveDescriptors", () => { for (const r of loadCases(__dirname + "/test-failed/")) { it("should fail descriptors for " + r.name, () => { const Ast = getAstFactory(); + const sources: Source[] = [ + { code: r.code, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: r.code, path: "", origin: "user" }], + sources, [], - getParser(Ast), + parseModules(sources, getParser(Ast)), ); ctx = featureEnable(ctx, "external"); expect(() => { diff --git a/src/types/resolveStatements.spec.ts b/src/types/resolveStatements.spec.ts index b63ec4276..6cdbb443a 100644 --- a/src/types/resolveStatements.spec.ts +++ b/src/types/resolveStatements.spec.ts @@ -1,23 +1,27 @@ import { getAllExpressionTypes } from "./resolveExpression"; import { resolveDescriptors } from "./resolveDescriptors"; import { loadCases } from "../utils/loadCases"; -import { openContext } from "../context/store"; +import { openContext, parseModules } from "../context/store"; import { resolveStatements } from "./resolveStatements"; import { CompilerContext } from "../context/context"; import { featureEnable } from "../config/features"; import { getParser } from "../grammar"; import { getAstFactory } from "../ast/ast-helpers"; import { evalComptimeExpressions } from "./evalComptimeExpressions"; +import type { Source } from "../imports/source"; describe("resolveStatements", () => { for (const r of loadCases(__dirname + "/stmts/")) { it("should resolve statements for " + r.name, () => { const Ast = getAstFactory(); + const sources: Source[] = [ + { code: r.code, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: r.code, path: "", origin: "user" }], + sources, [], - getParser(Ast), + parseModules(sources, getParser(Ast)), ); ctx = featureEnable(ctx, "external"); ctx = resolveDescriptors(ctx, Ast); @@ -29,11 +33,14 @@ describe("resolveStatements", () => { for (const r of loadCases(__dirname + "/stmts-failed/")) { it("should fail statements for " + r.name, () => { const Ast = getAstFactory(); + const sources: Source[] = [ + { code: r.code, path: "", origin: "user" }, + ]; let ctx = openContext( new CompilerContext(), - [{ code: r.code, path: "", origin: "user" }], + sources, [], - getParser(Ast), + parseModules(sources, getParser(Ast)), ); ctx = featureEnable(ctx, "external"); ctx = resolveDescriptors(ctx, Ast); From 2feeb97a1c29a68c54dc82f70d6b7362c34a77eb Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Sun, 23 Mar 2025 12:43:44 +0100 Subject: [PATCH 05/10] tests: Added generation of makeX and makeDummyX functions. --- package.json | 4 + .../generated/gen-make-functions-script.ts | 303 +++ src/ast/generated/make-factory.template | 20 + src/ast/generated/make-factory.ts | 1724 +++++++++++++++++ yarn.lock | 26 + 5 files changed, 2077 insertions(+) create mode 100644 src/ast/generated/gen-make-functions-script.ts create mode 100644 src/ast/generated/make-factory.template create mode 100644 src/ast/generated/make-factory.ts diff --git a/package.json b/package.json index 913b1ef63..cd8395c78 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "all": "yarn clean && yarn gen && yarn build && yarn coverage && yarn lint:all", "next-version": "ts-node version.build.ts", "random-ast": "ts-node ./src/ast/random-ast.ts", + "gen-make-functions": "ts-node ./src/ast/generated/gen-make-functions-script.ts && yarn prettier -w ./src/ast/generated/make-factory.ts", "top10": "find . -type f -exec du -h {} + | sort -rh | head -n 10" }, "files": [ @@ -106,6 +107,9 @@ "@types/node": "^22.5.0", "@typescript-eslint/eslint-plugin": "^8.21.0", "@typescript-eslint/parser": "^8.21.0", + "@babel/generator": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/types": "^7.26.10", "chalk": "4.1.2", "cli-table3": "^0.6.5", "cross-env": "^7.0.3", diff --git a/src/ast/generated/gen-make-functions-script.ts b/src/ast/generated/gen-make-functions-script.ts new file mode 100644 index 000000000..ccde52ad5 --- /dev/null +++ b/src/ast/generated/gen-make-functions-script.ts @@ -0,0 +1,303 @@ +import generate from "@babel/generator"; +import type { ParserOptions } from "@babel/parser"; +import { parse } from "@babel/parser"; +import * as t from "@babel/types"; +import * as fs from "fs"; +import * as path from "path"; + +function main() { + const options: ParserOptions = { + sourceType: "module", + plugins: ["typescript"], + }; + + const astModule = fs + .readFileSync(path.join(__dirname, "..", "ast.ts")) + .toString(); + const astTypeDecls = parse(astModule, options); + const decls = astTypeDecls.program.body + .filter((stmt) => stmt.type === "ExportNamedDeclaration") + .map((stmt) => stmt.declaration) + .filter((stmt) => stmt?.type === "TSTypeAliasDeclaration"); + + const declNames = new Set(decls.map((decl) => decl.id.name)); + + const finalFunctions: { name: string; code: string }[] = []; + + // Extract from the declarations all the union types + const unionTypes = decls + .map((decl) => decl.typeAnnotation) + .filter((decl) => decl.type === "TSUnionType"); + + for (const unionType of unionTypes) { + const subtypes = unionType.types + .filter((typeDecl) => typeDecl.type === "TSTypeReference") + .map((typeDecl) => typeDecl.typeName) + .filter((typeDecl) => typeDecl.type === "Identifier"); + + for (const subtype of subtypes) { + const subtypeDecl = decls.find( + (decl) => decl.id.name === subtype.name, + ); + if (typeof subtypeDecl === "undefined") { + throw new Error(`${subtype.name} is not declared.`); + } + + const subtypeDeclType = subtypeDecl.typeAnnotation.type; + if (subtypeDeclType === "TSTypeLiteral") { + const genFunctions = createMakeAndDummyFunctions( + subtypeDecl.typeAnnotation, + subtypeDecl.id, + declNames, + ); + const genFunctionsFiltered = genFunctions.filter((genF) => + finalFunctions.every((f) => f.name !== genF.name), + ); + + if (genFunctionsFiltered.length > 0) { + console.log( + `Generated [${genFunctionsFiltered.map((entry) => entry.name).join(", ")}] for ${subtype.name}`, + ); + } + + finalFunctions.push(...genFunctionsFiltered); + } else if (subtypeDeclType === "TSUnionType") { + // Do nothing, since it will be processed later. + } else { + // Unexpected type + throw new Error( + `${subtype.name} is not a reference to a type literal or a union type.`, + ); + } + } + } + + // Create the make factory file + const makeFactoryTemplate = fs + .readFileSync(path.join(__dirname, "make-factory.template")) + .toString(); + + const functionCodes = finalFunctions + .map((genFun) => genFun.code) + .join("\n\n"); + const functionNames = finalFunctions + .map((genFun) => genFun.name) + .join(",\n"); + + const makeFactoryCode = makeFactoryTemplate + .replace("", functionCodes) + .replace("", functionNames); + + fs.writeFileSync(path.join(__dirname, "make-factory.ts"), makeFactoryCode); + + console.log("Finished."); +} + +function createMakeAndDummyFunctions( + decl: t.TSTypeLiteral, + id: t.Identifier, + decls: Set, +): { name: string; code: string }[] { + const astNamespace = "Ast"; + const astFactoryObject = "astF"; + const createNodeFunName = "createNode"; + const emptySrcInfo = "emptySrcInfo"; + + const rawFieldsArray = decl.members.filter( + (decl) => decl.type === "TSPropertySignature", + ); + const generalParams: { id: t.Identifier; type: t.TSType }[] = []; + const paramsWithLiteralTypes: { + id: t.Identifier; + type: t.TSLiteralType; + }[] = []; + + // If there is no loc field, + // the makeDummy function cannot be created + const makeDummy = rawFieldsArray.some( + (f) => f.key.type === "Identifier" && f.key.name === "loc", + ); + + for (const field of rawFieldsArray) { + if (field.key.type !== "Identifier") { + throw new Error( + `Expected identifier in fields, but found ${field.key.type}`, + ); + } + const fieldName = field.key.name; + if (fieldName === "id") { + // The id field should not occur as an argument to the function, + // nor as a parameter to createNode + continue; + } + if (field.typeAnnotation) { + const typeAnnotation = field.typeAnnotation.typeAnnotation; + if (typeAnnotation.type === "TSLiteralType") { + paramsWithLiteralTypes.push({ + id: field.key, + type: typeAnnotation, + }); + } else { + generalParams.push({ id: field.key, type: typeAnnotation }); + } + } else { + throw new Error( + `Expected field ${fieldName} to have a type annotation`, + ); + } + } + + const makeFunName = `make${id.name}`; + const makeDummyFunName = `makeDummy${id.name}`; + // The params to the make functions do not have fields with literal types + // Also, the dummy function needs to filter the loc parameter + const createParam = (entry: { id: t.Identifier; type: t.TSType }) => { + const newId = t.identifier(`p_${entry.id.name}`); + newId.typeAnnotation = t.tsTypeAnnotation( + qualifyType(astNamespace, entry.type, decls), + ); + return newId; + }; + const makeFunParamsArray = generalParams.map((entry) => createParam(entry)); + const makeDummyFunParamsArray = generalParams + .filter(({ id, type: _ }) => id.name !== "loc") + .map((entry) => createParam(entry)); + + // The arguments with literal values to the createNode call inside the make functions body + const createNodeLiteralArgs = paramsWithLiteralTypes.map(({ id, type }) => + t.objectProperty(id, type.literal), + ); + // The non-literal arguments to the createNode call inside the make functions body + const createNodeArgsForMake = generalParams.map(({ id, type: _ }) => + t.objectProperty(id, t.identifier(`p_${id.name}`)), + ); + const createNodeArgsForMakeDummy = generalParams.map(({ id, type: _ }) => + id.name === "loc" + ? t.objectProperty(id, t.identifier(emptySrcInfo)) + : t.objectProperty(id, t.identifier(`p_${id.name}`)), + ); + const funReturnType = t.tsTypeReference( + t.tSQualifiedName(t.identifier(astNamespace), id), + ); + // Function to create the function codes + const createFun = ( + name: string, + params: t.Identifier[], + createNodeArgs: t.ObjectProperty[], + ) => { + const body = t.returnStatement( + t.tsAsExpression( + t.callExpression( + t.memberExpression( + t.identifier(astFactoryObject), + t.identifier(createNodeFunName), + ), + [t.objectExpression(createNodeArgs)], + ), + funReturnType, + ), + ); + const funDecl = t.functionDeclaration( + t.identifier(name), + params, + t.blockStatement([body]), + ); + funDecl.returnType = t.tsTypeAnnotation(funReturnType); + return funDecl; + }; + + const makeFun = createFun(makeFunName, makeFunParamsArray, [ + ...createNodeLiteralArgs, + ...createNodeArgsForMake, + ]); + const makeDummyFun = createFun(makeDummyFunName, makeDummyFunParamsArray, [ + ...createNodeLiteralArgs, + ...createNodeArgsForMakeDummy, + ]); + + if (makeDummy) { + return [ + { name: makeFunName, code: generate(makeFun).code }, + { name: makeDummyFunName, code: generate(makeDummyFun).code }, + ]; + } else { + console.log( + `[WARNING] Skipped makeDummy for ${id.name}, because there is no loc field in ${id.name}.`, + ); + return [{ name: makeFunName, code: generate(makeFun).code }]; + } +} + +function qualifyType( + namespace: string, + typ: t.TSType, + decls: Set, +): t.TSType { + switch (typ.type) { + case "TSTypeReference": { + if (typ.typeName.type === "Identifier") { + if (decls.has(typ.typeName.name)) { + return t.tsTypeReference( + t.tSQualifiedName( + t.identifier(namespace), + typ.typeName, + ), + ); + } else { + // Leave the identifier unchanged, but check if it has type parameters + const typRef = t.tsTypeReference(typ.typeName); + if (typ.typeParameters) { + typRef.typeParameters = t.tsTypeParameterInstantiation( + typ.typeParameters.params.map((t) => + qualifyType(namespace, t, decls), + ), + ); + } + return typRef; + } + } + // Currently unsupported + throw new Error( + `Unsupported type ${typ.typeName.type} of TSTypeReference`, + ); + } + case "TSUnionType": { + return t.tsUnionType( + typ.types.map((t) => qualifyType(namespace, t, decls)), + ); + } + case "TSArrayType": { + return t.tsArrayType( + qualifyType(namespace, typ.elementType, decls), + ); + } + case "TSTypeOperator": { + const op = t.tsTypeOperator( + qualifyType(namespace, typ.typeAnnotation, decls), + ); + op.operator = typ.operator; + return op; + } + case "TSTupleType": { + if ( + typ.elementTypes.every((t) => t.type !== "TSNamedTupleMember") + ) { + return t.tsTupleType( + typ.elementTypes.map((t) => + qualifyType(namespace, t, decls), + ), + ); + } else { + // Currently unsupported + throw new Error( + "TSNamedTupleMember is currently not supported in TSTupleType", + ); + } + } + + default: + return typ; + } +} + +main(); diff --git a/src/ast/generated/make-factory.template b/src/ast/generated/make-factory.template new file mode 100644 index 000000000..4afc523f9 --- /dev/null +++ b/src/ast/generated/make-factory.template @@ -0,0 +1,20 @@ +// THIS IS AN AUTOGENERATED FILE. TO GENERATE IT AGAIN, EXECUTE yarn gen-make-functions + +import type { FactoryAst } from "../ast-helpers"; +import type * as Ast from "../ast"; +import type { SrcInfo } from "../../grammar"; +import type { Address, Cell, Slice } from "@ton/core"; +import { getSrcInfo } from "../../grammar/src-info"; + +export const getMakeAst = (astF: FactoryAst) => { + + const emptySrcInfo = getSrcInfo(" ", 0, 0, null, "user"); + + + + return { + + }; +}; + +export type MakeAstFactory = ReturnType; \ No newline at end of file diff --git a/src/ast/generated/make-factory.ts b/src/ast/generated/make-factory.ts new file mode 100644 index 000000000..1eb9150fc --- /dev/null +++ b/src/ast/generated/make-factory.ts @@ -0,0 +1,1724 @@ +// THIS IS AN AUTOGENERATED FILE. TO GENERATE IT AGAIN, EXECUTE yarn gen-make-functions + +import type { FactoryAst } from "../ast-helpers"; +import type * as Ast from "../ast"; +import type { SrcInfo } from "../../grammar"; +import type { Address, Cell, Slice } from "@ton/core"; +import { getSrcInfo } from "../../grammar/src-info"; + +export const getMakeAst = (astF: FactoryAst) => { + const emptySrcInfo = getSrcInfo(" ", 0, 0, null, "user"); + + function makeAstPrimitiveTypeDecl( + p_name: Ast.AstId, + p_loc: SrcInfo, + ): Ast.AstPrimitiveTypeDecl { + return astF.createNode({ + kind: "primitive_type_decl", + name: p_name, + loc: p_loc, + }) as Ast.AstPrimitiveTypeDecl; + } + + function makeDummyAstPrimitiveTypeDecl( + p_name: Ast.AstId, + ): Ast.AstPrimitiveTypeDecl { + return astF.createNode({ + kind: "primitive_type_decl", + name: p_name, + loc: emptySrcInfo, + }) as Ast.AstPrimitiveTypeDecl; + } + + function makeAstFunctionDef( + p_attributes: readonly Ast.AstFunctionAttribute[], + p_name: Ast.AstId, + p_return: Ast.AstType | undefined, + p_params: readonly Ast.AstTypedParameter[], + p_statements: readonly Ast.AstStatement[], + p_loc: SrcInfo, + ): Ast.AstFunctionDef { + return astF.createNode({ + kind: "function_def", + attributes: p_attributes, + name: p_name, + return: p_return, + params: p_params, + statements: p_statements, + loc: p_loc, + }) as Ast.AstFunctionDef; + } + + function makeDummyAstFunctionDef( + p_attributes: readonly Ast.AstFunctionAttribute[], + p_name: Ast.AstId, + p_return: Ast.AstType | undefined, + p_params: readonly Ast.AstTypedParameter[], + p_statements: readonly Ast.AstStatement[], + ): Ast.AstFunctionDef { + return astF.createNode({ + kind: "function_def", + attributes: p_attributes, + name: p_name, + return: p_return, + params: p_params, + statements: p_statements, + loc: emptySrcInfo, + }) as Ast.AstFunctionDef; + } + + function makeAstAsmFunctionDef( + p_shuffle: Ast.AstAsmShuffle, + p_attributes: readonly Ast.AstFunctionAttribute[], + p_name: Ast.AstId, + p_return: Ast.AstType | undefined, + p_params: readonly Ast.AstTypedParameter[], + p_instructions: readonly Ast.AstAsmInstruction[], + p_loc: SrcInfo, + ): Ast.AstAsmFunctionDef { + return astF.createNode({ + kind: "asm_function_def", + shuffle: p_shuffle, + attributes: p_attributes, + name: p_name, + return: p_return, + params: p_params, + instructions: p_instructions, + loc: p_loc, + }) as Ast.AstAsmFunctionDef; + } + + function makeDummyAstAsmFunctionDef( + p_shuffle: Ast.AstAsmShuffle, + p_attributes: readonly Ast.AstFunctionAttribute[], + p_name: Ast.AstId, + p_return: Ast.AstType | undefined, + p_params: readonly Ast.AstTypedParameter[], + p_instructions: readonly Ast.AstAsmInstruction[], + ): Ast.AstAsmFunctionDef { + return astF.createNode({ + kind: "asm_function_def", + shuffle: p_shuffle, + attributes: p_attributes, + name: p_name, + return: p_return, + params: p_params, + instructions: p_instructions, + loc: emptySrcInfo, + }) as Ast.AstAsmFunctionDef; + } + + function makeAstNativeFunctionDecl( + p_attributes: readonly Ast.AstFunctionAttribute[], + p_name: Ast.AstId, + p_nativeName: Ast.AstFuncId, + p_params: readonly Ast.AstTypedParameter[], + p_return: Ast.AstType | undefined, + p_loc: SrcInfo, + ): Ast.AstNativeFunctionDecl { + return astF.createNode({ + kind: "native_function_decl", + attributes: p_attributes, + name: p_name, + nativeName: p_nativeName, + params: p_params, + return: p_return, + loc: p_loc, + }) as Ast.AstNativeFunctionDecl; + } + + function makeDummyAstNativeFunctionDecl( + p_attributes: readonly Ast.AstFunctionAttribute[], + p_name: Ast.AstId, + p_nativeName: Ast.AstFuncId, + p_params: readonly Ast.AstTypedParameter[], + p_return: Ast.AstType | undefined, + ): Ast.AstNativeFunctionDecl { + return astF.createNode({ + kind: "native_function_decl", + attributes: p_attributes, + name: p_name, + nativeName: p_nativeName, + params: p_params, + return: p_return, + loc: emptySrcInfo, + }) as Ast.AstNativeFunctionDecl; + } + + function makeAstConstantDef( + p_attributes: readonly Ast.AstConstantAttribute[], + p_name: Ast.AstId, + p_type: Ast.AstType, + p_initializer: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstConstantDef { + return astF.createNode({ + kind: "constant_def", + attributes: p_attributes, + name: p_name, + type: p_type, + initializer: p_initializer, + loc: p_loc, + }) as Ast.AstConstantDef; + } + + function makeDummyAstConstantDef( + p_attributes: readonly Ast.AstConstantAttribute[], + p_name: Ast.AstId, + p_type: Ast.AstType, + p_initializer: Ast.AstExpression, + ): Ast.AstConstantDef { + return astF.createNode({ + kind: "constant_def", + attributes: p_attributes, + name: p_name, + type: p_type, + initializer: p_initializer, + loc: emptySrcInfo, + }) as Ast.AstConstantDef; + } + + function makeAstStructDecl( + p_name: Ast.AstId, + p_fields: readonly Ast.AstFieldDecl[], + p_loc: SrcInfo, + ): Ast.AstStructDecl { + return astF.createNode({ + kind: "struct_decl", + name: p_name, + fields: p_fields, + loc: p_loc, + }) as Ast.AstStructDecl; + } + + function makeDummyAstStructDecl( + p_name: Ast.AstId, + p_fields: readonly Ast.AstFieldDecl[], + ): Ast.AstStructDecl { + return astF.createNode({ + kind: "struct_decl", + name: p_name, + fields: p_fields, + loc: emptySrcInfo, + }) as Ast.AstStructDecl; + } + + function makeAstMessageDecl( + p_name: Ast.AstId, + p_opcode: Ast.AstExpression | undefined, + p_fields: readonly Ast.AstFieldDecl[], + p_loc: SrcInfo, + ): Ast.AstMessageDecl { + return astF.createNode({ + kind: "message_decl", + name: p_name, + opcode: p_opcode, + fields: p_fields, + loc: p_loc, + }) as Ast.AstMessageDecl; + } + + function makeDummyAstMessageDecl( + p_name: Ast.AstId, + p_opcode: Ast.AstExpression | undefined, + p_fields: readonly Ast.AstFieldDecl[], + ): Ast.AstMessageDecl { + return astF.createNode({ + kind: "message_decl", + name: p_name, + opcode: p_opcode, + fields: p_fields, + loc: emptySrcInfo, + }) as Ast.AstMessageDecl; + } + + function makeAstContract( + p_name: Ast.AstId, + p_traits: readonly Ast.AstId[], + p_attributes: readonly Ast.AstContractAttribute[], + p_params: undefined | readonly Ast.AstFieldDecl[], + p_declarations: readonly Ast.AstContractDeclaration[], + p_loc: SrcInfo, + ): Ast.AstContract { + return astF.createNode({ + kind: "contract", + name: p_name, + traits: p_traits, + attributes: p_attributes, + params: p_params, + declarations: p_declarations, + loc: p_loc, + }) as Ast.AstContract; + } + + function makeDummyAstContract( + p_name: Ast.AstId, + p_traits: readonly Ast.AstId[], + p_attributes: readonly Ast.AstContractAttribute[], + p_params: undefined | readonly Ast.AstFieldDecl[], + p_declarations: readonly Ast.AstContractDeclaration[], + ): Ast.AstContract { + return astF.createNode({ + kind: "contract", + name: p_name, + traits: p_traits, + attributes: p_attributes, + params: p_params, + declarations: p_declarations, + loc: emptySrcInfo, + }) as Ast.AstContract; + } + + function makeAstTrait( + p_name: Ast.AstId, + p_traits: readonly Ast.AstId[], + p_attributes: readonly Ast.AstContractAttribute[], + p_declarations: readonly Ast.AstTraitDeclaration[], + p_loc: SrcInfo, + ): Ast.AstTrait { + return astF.createNode({ + kind: "trait", + name: p_name, + traits: p_traits, + attributes: p_attributes, + declarations: p_declarations, + loc: p_loc, + }) as Ast.AstTrait; + } + + function makeDummyAstTrait( + p_name: Ast.AstId, + p_traits: readonly Ast.AstId[], + p_attributes: readonly Ast.AstContractAttribute[], + p_declarations: readonly Ast.AstTraitDeclaration[], + ): Ast.AstTrait { + return astF.createNode({ + kind: "trait", + name: p_name, + traits: p_traits, + attributes: p_attributes, + declarations: p_declarations, + loc: emptySrcInfo, + }) as Ast.AstTrait; + } + + function makeAstFieldDecl( + p_name: Ast.AstId, + p_type: Ast.AstType, + p_initializer: Ast.AstExpression | undefined, + p_as: Ast.AstId | undefined, + p_loc: SrcInfo, + ): Ast.AstFieldDecl { + return astF.createNode({ + kind: "field_decl", + name: p_name, + type: p_type, + initializer: p_initializer, + as: p_as, + loc: p_loc, + }) as Ast.AstFieldDecl; + } + + function makeDummyAstFieldDecl( + p_name: Ast.AstId, + p_type: Ast.AstType, + p_initializer: Ast.AstExpression | undefined, + p_as: Ast.AstId | undefined, + ): Ast.AstFieldDecl { + return astF.createNode({ + kind: "field_decl", + name: p_name, + type: p_type, + initializer: p_initializer, + as: p_as, + loc: emptySrcInfo, + }) as Ast.AstFieldDecl; + } + + function makeAstContractInit( + p_params: readonly Ast.AstTypedParameter[], + p_statements: readonly Ast.AstStatement[], + p_loc: SrcInfo, + ): Ast.AstContractInit { + return astF.createNode({ + kind: "contract_init", + params: p_params, + statements: p_statements, + loc: p_loc, + }) as Ast.AstContractInit; + } + + function makeDummyAstContractInit( + p_params: readonly Ast.AstTypedParameter[], + p_statements: readonly Ast.AstStatement[], + ): Ast.AstContractInit { + return astF.createNode({ + kind: "contract_init", + params: p_params, + statements: p_statements, + loc: emptySrcInfo, + }) as Ast.AstContractInit; + } + + function makeAstReceiver( + p_selector: Ast.AstReceiverKind, + p_statements: readonly Ast.AstStatement[], + p_loc: SrcInfo, + ): Ast.AstReceiver { + return astF.createNode({ + kind: "receiver", + selector: p_selector, + statements: p_statements, + loc: p_loc, + }) as Ast.AstReceiver; + } + + function makeDummyAstReceiver( + p_selector: Ast.AstReceiverKind, + p_statements: readonly Ast.AstStatement[], + ): Ast.AstReceiver { + return astF.createNode({ + kind: "receiver", + selector: p_selector, + statements: p_statements, + loc: emptySrcInfo, + }) as Ast.AstReceiver; + } + + function makeAstFunctionDecl( + p_attributes: readonly Ast.AstFunctionAttribute[], + p_name: Ast.AstId, + p_return: Ast.AstType | undefined, + p_params: readonly Ast.AstTypedParameter[], + p_loc: SrcInfo, + ): Ast.AstFunctionDecl { + return astF.createNode({ + kind: "function_decl", + attributes: p_attributes, + name: p_name, + return: p_return, + params: p_params, + loc: p_loc, + }) as Ast.AstFunctionDecl; + } + + function makeDummyAstFunctionDecl( + p_attributes: readonly Ast.AstFunctionAttribute[], + p_name: Ast.AstId, + p_return: Ast.AstType | undefined, + p_params: readonly Ast.AstTypedParameter[], + ): Ast.AstFunctionDecl { + return astF.createNode({ + kind: "function_decl", + attributes: p_attributes, + name: p_name, + return: p_return, + params: p_params, + loc: emptySrcInfo, + }) as Ast.AstFunctionDecl; + } + + function makeAstConstantDecl( + p_attributes: readonly Ast.AstConstantAttribute[], + p_name: Ast.AstId, + p_type: Ast.AstType, + p_loc: SrcInfo, + ): Ast.AstConstantDecl { + return astF.createNode({ + kind: "constant_decl", + attributes: p_attributes, + name: p_name, + type: p_type, + loc: p_loc, + }) as Ast.AstConstantDecl; + } + + function makeDummyAstConstantDecl( + p_attributes: readonly Ast.AstConstantAttribute[], + p_name: Ast.AstId, + p_type: Ast.AstType, + ): Ast.AstConstantDecl { + return astF.createNode({ + kind: "constant_decl", + attributes: p_attributes, + name: p_name, + type: p_type, + loc: emptySrcInfo, + }) as Ast.AstConstantDecl; + } + + function makeAstStatementLet( + p_name: Ast.AstId, + p_type: Ast.AstType | undefined, + p_expression: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstStatementLet { + return astF.createNode({ + kind: "statement_let", + name: p_name, + type: p_type, + expression: p_expression, + loc: p_loc, + }) as Ast.AstStatementLet; + } + + function makeDummyAstStatementLet( + p_name: Ast.AstId, + p_type: Ast.AstType | undefined, + p_expression: Ast.AstExpression, + ): Ast.AstStatementLet { + return astF.createNode({ + kind: "statement_let", + name: p_name, + type: p_type, + expression: p_expression, + loc: emptySrcInfo, + }) as Ast.AstStatementLet; + } + + function makeAstStatementReturn( + p_expression: Ast.AstExpression | undefined, + p_loc: SrcInfo, + ): Ast.AstStatementReturn { + return astF.createNode({ + kind: "statement_return", + expression: p_expression, + loc: p_loc, + }) as Ast.AstStatementReturn; + } + + function makeDummyAstStatementReturn( + p_expression: Ast.AstExpression | undefined, + ): Ast.AstStatementReturn { + return astF.createNode({ + kind: "statement_return", + expression: p_expression, + loc: emptySrcInfo, + }) as Ast.AstStatementReturn; + } + + function makeAstStatementExpression( + p_expression: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstStatementExpression { + return astF.createNode({ + kind: "statement_expression", + expression: p_expression, + loc: p_loc, + }) as Ast.AstStatementExpression; + } + + function makeDummyAstStatementExpression( + p_expression: Ast.AstExpression, + ): Ast.AstStatementExpression { + return astF.createNode({ + kind: "statement_expression", + expression: p_expression, + loc: emptySrcInfo, + }) as Ast.AstStatementExpression; + } + + function makeAstStatementAssign( + p_path: Ast.AstExpression, + p_expression: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstStatementAssign { + return astF.createNode({ + kind: "statement_assign", + path: p_path, + expression: p_expression, + loc: p_loc, + }) as Ast.AstStatementAssign; + } + + function makeDummyAstStatementAssign( + p_path: Ast.AstExpression, + p_expression: Ast.AstExpression, + ): Ast.AstStatementAssign { + return astF.createNode({ + kind: "statement_assign", + path: p_path, + expression: p_expression, + loc: emptySrcInfo, + }) as Ast.AstStatementAssign; + } + + function makeAstStatementAugmentedAssign( + p_op: Ast.AstAugmentedAssignOperation, + p_path: Ast.AstExpression, + p_expression: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstStatementAugmentedAssign { + return astF.createNode({ + kind: "statement_augmentedassign", + op: p_op, + path: p_path, + expression: p_expression, + loc: p_loc, + }) as Ast.AstStatementAugmentedAssign; + } + + function makeDummyAstStatementAugmentedAssign( + p_op: Ast.AstAugmentedAssignOperation, + p_path: Ast.AstExpression, + p_expression: Ast.AstExpression, + ): Ast.AstStatementAugmentedAssign { + return astF.createNode({ + kind: "statement_augmentedassign", + op: p_op, + path: p_path, + expression: p_expression, + loc: emptySrcInfo, + }) as Ast.AstStatementAugmentedAssign; + } + + function makeAstStatementCondition( + p_condition: Ast.AstExpression, + p_trueStatements: readonly Ast.AstStatement[], + p_falseStatements: readonly Ast.AstStatement[] | undefined, + p_loc: SrcInfo, + ): Ast.AstStatementCondition { + return astF.createNode({ + kind: "statement_condition", + condition: p_condition, + trueStatements: p_trueStatements, + falseStatements: p_falseStatements, + loc: p_loc, + }) as Ast.AstStatementCondition; + } + + function makeDummyAstStatementCondition( + p_condition: Ast.AstExpression, + p_trueStatements: readonly Ast.AstStatement[], + p_falseStatements: readonly Ast.AstStatement[] | undefined, + ): Ast.AstStatementCondition { + return astF.createNode({ + kind: "statement_condition", + condition: p_condition, + trueStatements: p_trueStatements, + falseStatements: p_falseStatements, + loc: emptySrcInfo, + }) as Ast.AstStatementCondition; + } + + function makeAstStatementWhile( + p_condition: Ast.AstExpression, + p_statements: readonly Ast.AstStatement[], + p_loc: SrcInfo, + ): Ast.AstStatementWhile { + return astF.createNode({ + kind: "statement_while", + condition: p_condition, + statements: p_statements, + loc: p_loc, + }) as Ast.AstStatementWhile; + } + + function makeDummyAstStatementWhile( + p_condition: Ast.AstExpression, + p_statements: readonly Ast.AstStatement[], + ): Ast.AstStatementWhile { + return astF.createNode({ + kind: "statement_while", + condition: p_condition, + statements: p_statements, + loc: emptySrcInfo, + }) as Ast.AstStatementWhile; + } + + function makeAstStatementUntil( + p_condition: Ast.AstExpression, + p_statements: readonly Ast.AstStatement[], + p_loc: SrcInfo, + ): Ast.AstStatementUntil { + return astF.createNode({ + kind: "statement_until", + condition: p_condition, + statements: p_statements, + loc: p_loc, + }) as Ast.AstStatementUntil; + } + + function makeDummyAstStatementUntil( + p_condition: Ast.AstExpression, + p_statements: readonly Ast.AstStatement[], + ): Ast.AstStatementUntil { + return astF.createNode({ + kind: "statement_until", + condition: p_condition, + statements: p_statements, + loc: emptySrcInfo, + }) as Ast.AstStatementUntil; + } + + function makeAstStatementRepeat( + p_iterations: Ast.AstExpression, + p_statements: readonly Ast.AstStatement[], + p_loc: SrcInfo, + ): Ast.AstStatementRepeat { + return astF.createNode({ + kind: "statement_repeat", + iterations: p_iterations, + statements: p_statements, + loc: p_loc, + }) as Ast.AstStatementRepeat; + } + + function makeDummyAstStatementRepeat( + p_iterations: Ast.AstExpression, + p_statements: readonly Ast.AstStatement[], + ): Ast.AstStatementRepeat { + return astF.createNode({ + kind: "statement_repeat", + iterations: p_iterations, + statements: p_statements, + loc: emptySrcInfo, + }) as Ast.AstStatementRepeat; + } + + function makeAstStatementTry( + p_statements: readonly Ast.AstStatement[], + p_catchBlock: Ast.AstCatchBlock | undefined, + p_loc: SrcInfo, + ): Ast.AstStatementTry { + return astF.createNode({ + kind: "statement_try", + statements: p_statements, + catchBlock: p_catchBlock, + loc: p_loc, + }) as Ast.AstStatementTry; + } + + function makeDummyAstStatementTry( + p_statements: readonly Ast.AstStatement[], + p_catchBlock: Ast.AstCatchBlock | undefined, + ): Ast.AstStatementTry { + return astF.createNode({ + kind: "statement_try", + statements: p_statements, + catchBlock: p_catchBlock, + loc: emptySrcInfo, + }) as Ast.AstStatementTry; + } + + function makeAstStatementForEach( + p_keyName: Ast.AstId, + p_valueName: Ast.AstId, + p_map: Ast.AstExpression, + p_statements: readonly Ast.AstStatement[], + p_loc: SrcInfo, + ): Ast.AstStatementForEach { + return astF.createNode({ + kind: "statement_foreach", + keyName: p_keyName, + valueName: p_valueName, + map: p_map, + statements: p_statements, + loc: p_loc, + }) as Ast.AstStatementForEach; + } + + function makeDummyAstStatementForEach( + p_keyName: Ast.AstId, + p_valueName: Ast.AstId, + p_map: Ast.AstExpression, + p_statements: readonly Ast.AstStatement[], + ): Ast.AstStatementForEach { + return astF.createNode({ + kind: "statement_foreach", + keyName: p_keyName, + valueName: p_valueName, + map: p_map, + statements: p_statements, + loc: emptySrcInfo, + }) as Ast.AstStatementForEach; + } + + function makeAstStatementDestruct( + p_type: Ast.AstTypeId, + p_identifiers: ReadonlyMap, + p_ignoreUnspecifiedFields: boolean, + p_expression: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstStatementDestruct { + return astF.createNode({ + kind: "statement_destruct", + type: p_type, + identifiers: p_identifiers, + ignoreUnspecifiedFields: p_ignoreUnspecifiedFields, + expression: p_expression, + loc: p_loc, + }) as Ast.AstStatementDestruct; + } + + function makeDummyAstStatementDestruct( + p_type: Ast.AstTypeId, + p_identifiers: ReadonlyMap, + p_ignoreUnspecifiedFields: boolean, + p_expression: Ast.AstExpression, + ): Ast.AstStatementDestruct { + return astF.createNode({ + kind: "statement_destruct", + type: p_type, + identifiers: p_identifiers, + ignoreUnspecifiedFields: p_ignoreUnspecifiedFields, + expression: p_expression, + loc: emptySrcInfo, + }) as Ast.AstStatementDestruct; + } + + function makeAstStatementBlock( + p_statements: readonly Ast.AstStatement[], + p_loc: SrcInfo, + ): Ast.AstStatementBlock { + return astF.createNode({ + kind: "statement_block", + statements: p_statements, + loc: p_loc, + }) as Ast.AstStatementBlock; + } + + function makeDummyAstStatementBlock( + p_statements: readonly Ast.AstStatement[], + ): Ast.AstStatementBlock { + return astF.createNode({ + kind: "statement_block", + statements: p_statements, + loc: emptySrcInfo, + }) as Ast.AstStatementBlock; + } + + function makeAstTypeId(p_text: string, p_loc: SrcInfo): Ast.AstTypeId { + return astF.createNode({ + kind: "type_id", + text: p_text, + loc: p_loc, + }) as Ast.AstTypeId; + } + + function makeDummyAstTypeId(p_text: string): Ast.AstTypeId { + return astF.createNode({ + kind: "type_id", + text: p_text, + loc: emptySrcInfo, + }) as Ast.AstTypeId; + } + + function makeAstOptionalType( + p_typeArg: Ast.AstType, + p_loc: SrcInfo, + ): Ast.AstOptionalType { + return astF.createNode({ + kind: "optional_type", + typeArg: p_typeArg, + loc: p_loc, + }) as Ast.AstOptionalType; + } + + function makeDummyAstOptionalType( + p_typeArg: Ast.AstType, + ): Ast.AstOptionalType { + return astF.createNode({ + kind: "optional_type", + typeArg: p_typeArg, + loc: emptySrcInfo, + }) as Ast.AstOptionalType; + } + + function makeAstMapType( + p_keyType: Ast.AstTypeId, + p_keyStorageType: Ast.AstId | undefined, + p_valueType: Ast.AstTypeId, + p_valueStorageType: Ast.AstId | undefined, + p_loc: SrcInfo, + ): Ast.AstMapType { + return astF.createNode({ + kind: "map_type", + keyType: p_keyType, + keyStorageType: p_keyStorageType, + valueType: p_valueType, + valueStorageType: p_valueStorageType, + loc: p_loc, + }) as Ast.AstMapType; + } + + function makeDummyAstMapType( + p_keyType: Ast.AstTypeId, + p_keyStorageType: Ast.AstId | undefined, + p_valueType: Ast.AstTypeId, + p_valueStorageType: Ast.AstId | undefined, + ): Ast.AstMapType { + return astF.createNode({ + kind: "map_type", + keyType: p_keyType, + keyStorageType: p_keyStorageType, + valueType: p_valueType, + valueStorageType: p_valueStorageType, + loc: emptySrcInfo, + }) as Ast.AstMapType; + } + + function makeAstBouncedMessageType( + p_messageType: Ast.AstTypeId, + p_loc: SrcInfo, + ): Ast.AstBouncedMessageType { + return astF.createNode({ + kind: "bounced_message_type", + messageType: p_messageType, + loc: p_loc, + }) as Ast.AstBouncedMessageType; + } + + function makeDummyAstBouncedMessageType( + p_messageType: Ast.AstTypeId, + ): Ast.AstBouncedMessageType { + return astF.createNode({ + kind: "bounced_message_type", + messageType: p_messageType, + loc: emptySrcInfo, + }) as Ast.AstBouncedMessageType; + } + + function makeAstOpBinary( + p_op: Ast.AstBinaryOperation, + p_left: Ast.AstExpression, + p_right: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstOpBinary { + return astF.createNode({ + kind: "op_binary", + op: p_op, + left: p_left, + right: p_right, + loc: p_loc, + }) as Ast.AstOpBinary; + } + + function makeDummyAstOpBinary( + p_op: Ast.AstBinaryOperation, + p_left: Ast.AstExpression, + p_right: Ast.AstExpression, + ): Ast.AstOpBinary { + return astF.createNode({ + kind: "op_binary", + op: p_op, + left: p_left, + right: p_right, + loc: emptySrcInfo, + }) as Ast.AstOpBinary; + } + + function makeAstOpUnary( + p_op: Ast.AstUnaryOperation, + p_operand: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstOpUnary { + return astF.createNode({ + kind: "op_unary", + op: p_op, + operand: p_operand, + loc: p_loc, + }) as Ast.AstOpUnary; + } + + function makeDummyAstOpUnary( + p_op: Ast.AstUnaryOperation, + p_operand: Ast.AstExpression, + ): Ast.AstOpUnary { + return astF.createNode({ + kind: "op_unary", + op: p_op, + operand: p_operand, + loc: emptySrcInfo, + }) as Ast.AstOpUnary; + } + + function makeAstConditional( + p_condition: Ast.AstExpression, + p_thenBranch: Ast.AstExpression, + p_elseBranch: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstConditional { + return astF.createNode({ + kind: "conditional", + condition: p_condition, + thenBranch: p_thenBranch, + elseBranch: p_elseBranch, + loc: p_loc, + }) as Ast.AstConditional; + } + + function makeDummyAstConditional( + p_condition: Ast.AstExpression, + p_thenBranch: Ast.AstExpression, + p_elseBranch: Ast.AstExpression, + ): Ast.AstConditional { + return astF.createNode({ + kind: "conditional", + condition: p_condition, + thenBranch: p_thenBranch, + elseBranch: p_elseBranch, + loc: emptySrcInfo, + }) as Ast.AstConditional; + } + + function makeAstMethodCall( + p_self: Ast.AstExpression, + p_method: Ast.AstId, + p_args: readonly Ast.AstExpression[], + p_loc: SrcInfo, + ): Ast.AstMethodCall { + return astF.createNode({ + kind: "method_call", + self: p_self, + method: p_method, + args: p_args, + loc: p_loc, + }) as Ast.AstMethodCall; + } + + function makeDummyAstMethodCall( + p_self: Ast.AstExpression, + p_method: Ast.AstId, + p_args: readonly Ast.AstExpression[], + ): Ast.AstMethodCall { + return astF.createNode({ + kind: "method_call", + self: p_self, + method: p_method, + args: p_args, + loc: emptySrcInfo, + }) as Ast.AstMethodCall; + } + + function makeAstFieldAccess( + p_aggregate: Ast.AstExpression, + p_field: Ast.AstId, + p_loc: SrcInfo, + ): Ast.AstFieldAccess { + return astF.createNode({ + kind: "field_access", + aggregate: p_aggregate, + field: p_field, + loc: p_loc, + }) as Ast.AstFieldAccess; + } + + function makeDummyAstFieldAccess( + p_aggregate: Ast.AstExpression, + p_field: Ast.AstId, + ): Ast.AstFieldAccess { + return astF.createNode({ + kind: "field_access", + aggregate: p_aggregate, + field: p_field, + loc: emptySrcInfo, + }) as Ast.AstFieldAccess; + } + + function makeAstStaticCall( + p_function: Ast.AstId, + p_args: readonly Ast.AstExpression[], + p_loc: SrcInfo, + ): Ast.AstStaticCall { + return astF.createNode({ + kind: "static_call", + function: p_function, + args: p_args, + loc: p_loc, + }) as Ast.AstStaticCall; + } + + function makeDummyAstStaticCall( + p_function: Ast.AstId, + p_args: readonly Ast.AstExpression[], + ): Ast.AstStaticCall { + return astF.createNode({ + kind: "static_call", + function: p_function, + args: p_args, + loc: emptySrcInfo, + }) as Ast.AstStaticCall; + } + + function makeAstStructInstance( + p_type: Ast.AstId, + p_args: readonly Ast.AstStructFieldInitializer[], + p_loc: SrcInfo, + ): Ast.AstStructInstance { + return astF.createNode({ + kind: "struct_instance", + type: p_type, + args: p_args, + loc: p_loc, + }) as Ast.AstStructInstance; + } + + function makeDummyAstStructInstance( + p_type: Ast.AstId, + p_args: readonly Ast.AstStructFieldInitializer[], + ): Ast.AstStructInstance { + return astF.createNode({ + kind: "struct_instance", + type: p_type, + args: p_args, + loc: emptySrcInfo, + }) as Ast.AstStructInstance; + } + + function makeAstId(p_text: string, p_loc: SrcInfo): Ast.AstId { + return astF.createNode({ + kind: "id", + text: p_text, + loc: p_loc, + }) as Ast.AstId; + } + + function makeDummyAstId(p_text: string): Ast.AstId { + return astF.createNode({ + kind: "id", + text: p_text, + loc: emptySrcInfo, + }) as Ast.AstId; + } + + function makeAstInitOf( + p_contract: Ast.AstId, + p_args: readonly Ast.AstExpression[], + p_loc: SrcInfo, + ): Ast.AstInitOf { + return astF.createNode({ + kind: "init_of", + contract: p_contract, + args: p_args, + loc: p_loc, + }) as Ast.AstInitOf; + } + + function makeDummyAstInitOf( + p_contract: Ast.AstId, + p_args: readonly Ast.AstExpression[], + ): Ast.AstInitOf { + return astF.createNode({ + kind: "init_of", + contract: p_contract, + args: p_args, + loc: emptySrcInfo, + }) as Ast.AstInitOf; + } + + function makeAstCodeOf( + p_contract: Ast.AstId, + p_loc: SrcInfo, + ): Ast.AstCodeOf { + return astF.createNode({ + kind: "code_of", + contract: p_contract, + loc: p_loc, + }) as Ast.AstCodeOf; + } + + function makeDummyAstCodeOf(p_contract: Ast.AstId): Ast.AstCodeOf { + return astF.createNode({ + kind: "code_of", + contract: p_contract, + loc: emptySrcInfo, + }) as Ast.AstCodeOf; + } + + function makeAstString(p_value: string, p_loc: SrcInfo): Ast.AstString { + return astF.createNode({ + kind: "string", + value: p_value, + loc: p_loc, + }) as Ast.AstString; + } + + function makeDummyAstString(p_value: string): Ast.AstString { + return astF.createNode({ + kind: "string", + value: p_value, + loc: emptySrcInfo, + }) as Ast.AstString; + } + + function makeAstNumber( + p_base: Ast.AstNumberBase, + p_value: bigint, + p_loc: SrcInfo, + ): Ast.AstNumber { + return astF.createNode({ + kind: "number", + base: p_base, + value: p_value, + loc: p_loc, + }) as Ast.AstNumber; + } + + function makeDummyAstNumber( + p_base: Ast.AstNumberBase, + p_value: bigint, + ): Ast.AstNumber { + return astF.createNode({ + kind: "number", + base: p_base, + value: p_value, + loc: emptySrcInfo, + }) as Ast.AstNumber; + } + + function makeAstBoolean(p_value: boolean, p_loc: SrcInfo): Ast.AstBoolean { + return astF.createNode({ + kind: "boolean", + value: p_value, + loc: p_loc, + }) as Ast.AstBoolean; + } + + function makeDummyAstBoolean(p_value: boolean): Ast.AstBoolean { + return astF.createNode({ + kind: "boolean", + value: p_value, + loc: emptySrcInfo, + }) as Ast.AstBoolean; + } + + function makeAstNull(p_loc: SrcInfo): Ast.AstNull { + return astF.createNode({ + kind: "null", + loc: p_loc, + }) as Ast.AstNull; + } + + function makeDummyAstNull(): Ast.AstNull { + return astF.createNode({ + kind: "null", + loc: emptySrcInfo, + }) as Ast.AstNull; + } + + function makeAstSimplifiedString( + p_value: string, + p_loc: SrcInfo, + ): Ast.AstSimplifiedString { + return astF.createNode({ + kind: "simplified_string", + value: p_value, + loc: p_loc, + }) as Ast.AstSimplifiedString; + } + + function makeDummyAstSimplifiedString( + p_value: string, + ): Ast.AstSimplifiedString { + return astF.createNode({ + kind: "simplified_string", + value: p_value, + loc: emptySrcInfo, + }) as Ast.AstSimplifiedString; + } + + function makeAstAddress(p_value: Address, p_loc: SrcInfo): Ast.AstAddress { + return astF.createNode({ + kind: "address", + value: p_value, + loc: p_loc, + }) as Ast.AstAddress; + } + + function makeDummyAstAddress(p_value: Address): Ast.AstAddress { + return astF.createNode({ + kind: "address", + value: p_value, + loc: emptySrcInfo, + }) as Ast.AstAddress; + } + + function makeAstCell(p_value: Cell, p_loc: SrcInfo): Ast.AstCell { + return astF.createNode({ + kind: "cell", + value: p_value, + loc: p_loc, + }) as Ast.AstCell; + } + + function makeDummyAstCell(p_value: Cell): Ast.AstCell { + return astF.createNode({ + kind: "cell", + value: p_value, + loc: emptySrcInfo, + }) as Ast.AstCell; + } + + function makeAstSlice(p_value: Slice, p_loc: SrcInfo): Ast.AstSlice { + return astF.createNode({ + kind: "slice", + value: p_value, + loc: p_loc, + }) as Ast.AstSlice; + } + + function makeDummyAstSlice(p_value: Slice): Ast.AstSlice { + return astF.createNode({ + kind: "slice", + value: p_value, + loc: emptySrcInfo, + }) as Ast.AstSlice; + } + + function makeAstStructValue( + p_type: Ast.AstId, + p_args: readonly Ast.AstStructFieldValue[], + p_loc: SrcInfo, + ): Ast.AstStructValue { + return astF.createNode({ + kind: "struct_value", + type: p_type, + args: p_args, + loc: p_loc, + }) as Ast.AstStructValue; + } + + function makeDummyAstStructValue( + p_type: Ast.AstId, + p_args: readonly Ast.AstStructFieldValue[], + ): Ast.AstStructValue { + return astF.createNode({ + kind: "struct_value", + type: p_type, + args: p_args, + loc: emptySrcInfo, + }) as Ast.AstStructValue; + } + + function makeAstFunctionAttributeGet( + p_methodId: Ast.AstExpression | undefined, + p_loc: SrcInfo, + ): Ast.AstFunctionAttributeGet { + return astF.createNode({ + kind: "function_attribute", + type: "get", + methodId: p_methodId, + loc: p_loc, + }) as Ast.AstFunctionAttributeGet; + } + + function makeDummyAstFunctionAttributeGet( + p_methodId: Ast.AstExpression | undefined, + ): Ast.AstFunctionAttributeGet { + return astF.createNode({ + kind: "function_attribute", + type: "get", + methodId: p_methodId, + loc: emptySrcInfo, + }) as Ast.AstFunctionAttributeGet; + } + + function makeAstFunctionAttributeRest( + p_type: Ast.AstFunctionAttributeName, + p_loc: SrcInfo, + ): Ast.AstFunctionAttributeRest { + return astF.createNode({ + kind: "function_attribute", + type: p_type, + loc: p_loc, + }) as Ast.AstFunctionAttributeRest; + } + + function makeDummyAstFunctionAttributeRest( + p_type: Ast.AstFunctionAttributeName, + ): Ast.AstFunctionAttributeRest { + return astF.createNode({ + kind: "function_attribute", + type: p_type, + loc: emptySrcInfo, + }) as Ast.AstFunctionAttributeRest; + } + + function makeAstReceiverSimple( + p_param: Ast.AstTypedParameter, + ): Ast.AstReceiverSimple { + return astF.createNode({ + kind: "simple", + param: p_param, + }) as Ast.AstReceiverSimple; + } + + function makeAstReceiverFallback(): Ast.AstReceiverFallback { + return astF.createNode({ + kind: "fallback", + }) as Ast.AstReceiverFallback; + } + + function makeAstReceiverComment( + p_comment: Ast.AstString, + ): Ast.AstReceiverComment { + return astF.createNode({ + kind: "comment", + comment: p_comment, + }) as Ast.AstReceiverComment; + } + + function makeAstReceiverInternal( + p_subKind: Ast.AstReceiverSubKind, + p_loc: SrcInfo, + ): Ast.AstReceiverInternal { + return astF.createNode({ + kind: "internal", + subKind: p_subKind, + loc: p_loc, + }) as Ast.AstReceiverInternal; + } + + function makeDummyAstReceiverInternal( + p_subKind: Ast.AstReceiverSubKind, + ): Ast.AstReceiverInternal { + return astF.createNode({ + kind: "internal", + subKind: p_subKind, + loc: emptySrcInfo, + }) as Ast.AstReceiverInternal; + } + + function makeAstReceiverExternal( + p_subKind: Ast.AstReceiverSubKind, + p_loc: SrcInfo, + ): Ast.AstReceiverExternal { + return astF.createNode({ + kind: "external", + subKind: p_subKind, + loc: p_loc, + }) as Ast.AstReceiverExternal; + } + + function makeDummyAstReceiverExternal( + p_subKind: Ast.AstReceiverSubKind, + ): Ast.AstReceiverExternal { + return astF.createNode({ + kind: "external", + subKind: p_subKind, + loc: emptySrcInfo, + }) as Ast.AstReceiverExternal; + } + + function makeAstReceiverBounce( + p_param: Ast.AstTypedParameter, + p_loc: SrcInfo, + ): Ast.AstReceiverBounce { + return astF.createNode({ + kind: "bounce", + param: p_param, + loc: p_loc, + }) as Ast.AstReceiverBounce; + } + + function makeDummyAstReceiverBounce( + p_param: Ast.AstTypedParameter, + ): Ast.AstReceiverBounce { + return astF.createNode({ + kind: "bounce", + param: p_param, + loc: emptySrcInfo, + }) as Ast.AstReceiverBounce; + } + + function makeAstFuncId(p_text: string, p_loc: SrcInfo): Ast.AstFuncId { + return astF.createNode({ + kind: "func_id", + text: p_text, + loc: p_loc, + }) as Ast.AstFuncId; + } + + function makeDummyAstFuncId(p_text: string): Ast.AstFuncId { + return astF.createNode({ + kind: "func_id", + text: p_text, + loc: emptySrcInfo, + }) as Ast.AstFuncId; + } + + function makeAstDestructMapping( + p_field: Ast.AstId, + p_name: Ast.AstId, + p_loc: SrcInfo, + ): Ast.AstDestructMapping { + return astF.createNode({ + kind: "destruct_mapping", + field: p_field, + name: p_name, + loc: p_loc, + }) as Ast.AstDestructMapping; + } + + function makeDummyAstDestructMapping( + p_field: Ast.AstId, + p_name: Ast.AstId, + ): Ast.AstDestructMapping { + return astF.createNode({ + kind: "destruct_mapping", + field: p_field, + name: p_name, + loc: emptySrcInfo, + }) as Ast.AstDestructMapping; + } + + function makeAstDestructEnd( + p_ignoreUnspecifiedFields: boolean, + p_loc: SrcInfo, + ): Ast.AstDestructEnd { + return astF.createNode({ + kind: "destruct_end", + ignoreUnspecifiedFields: p_ignoreUnspecifiedFields, + loc: p_loc, + }) as Ast.AstDestructEnd; + } + + function makeDummyAstDestructEnd( + p_ignoreUnspecifiedFields: boolean, + ): Ast.AstDestructEnd { + return astF.createNode({ + kind: "destruct_end", + ignoreUnspecifiedFields: p_ignoreUnspecifiedFields, + loc: emptySrcInfo, + }) as Ast.AstDestructEnd; + } + + function makeAstTypedParameter( + p_name: Ast.AstId, + p_type: Ast.AstType, + p_loc: SrcInfo, + ): Ast.AstTypedParameter { + return astF.createNode({ + kind: "typed_parameter", + name: p_name, + type: p_type, + loc: p_loc, + }) as Ast.AstTypedParameter; + } + + function makeDummyAstTypedParameter( + p_name: Ast.AstId, + p_type: Ast.AstType, + ): Ast.AstTypedParameter { + return astF.createNode({ + kind: "typed_parameter", + name: p_name, + type: p_type, + loc: emptySrcInfo, + }) as Ast.AstTypedParameter; + } + + function makeAstModule( + p_imports: readonly Ast.AstImport[], + p_items: readonly Ast.AstModuleItem[], + ): Ast.AstModule { + return astF.createNode({ + kind: "module", + imports: p_imports, + items: p_items, + }) as Ast.AstModule; + } + + function makeAstStructFieldInitializer( + p_field: Ast.AstId, + p_initializer: Ast.AstExpression, + p_loc: SrcInfo, + ): Ast.AstStructFieldInitializer { + return astF.createNode({ + kind: "struct_field_initializer", + field: p_field, + initializer: p_initializer, + loc: p_loc, + }) as Ast.AstStructFieldInitializer; + } + + function makeDummyAstStructFieldInitializer( + p_field: Ast.AstId, + p_initializer: Ast.AstExpression, + ): Ast.AstStructFieldInitializer { + return astF.createNode({ + kind: "struct_field_initializer", + field: p_field, + initializer: p_initializer, + loc: emptySrcInfo, + }) as Ast.AstStructFieldInitializer; + } + + function makeAstStructFieldValue( + p_field: Ast.AstId, + p_initializer: Ast.AstLiteral, + p_loc: SrcInfo, + ): Ast.AstStructFieldValue { + return astF.createNode({ + kind: "struct_field_value", + field: p_field, + initializer: p_initializer, + loc: p_loc, + }) as Ast.AstStructFieldValue; + } + + function makeDummyAstStructFieldValue( + p_field: Ast.AstId, + p_initializer: Ast.AstLiteral, + ): Ast.AstStructFieldValue { + return astF.createNode({ + kind: "struct_field_value", + field: p_field, + initializer: p_initializer, + loc: emptySrcInfo, + }) as Ast.AstStructFieldValue; + } + + function makeAstImport( + p_importPath: Ast.ImportPath, + p_loc: SrcInfo, + ): Ast.AstImport { + return astF.createNode({ + kind: "import", + importPath: p_importPath, + loc: p_loc, + }) as Ast.AstImport; + } + + function makeDummyAstImport(p_importPath: Ast.ImportPath): Ast.AstImport { + return astF.createNode({ + kind: "import", + importPath: p_importPath, + loc: emptySrcInfo, + }) as Ast.AstImport; + } + + return { + makeAstPrimitiveTypeDecl, + makeDummyAstPrimitiveTypeDecl, + makeAstFunctionDef, + makeDummyAstFunctionDef, + makeAstAsmFunctionDef, + makeDummyAstAsmFunctionDef, + makeAstNativeFunctionDecl, + makeDummyAstNativeFunctionDecl, + makeAstConstantDef, + makeDummyAstConstantDef, + makeAstStructDecl, + makeDummyAstStructDecl, + makeAstMessageDecl, + makeDummyAstMessageDecl, + makeAstContract, + makeDummyAstContract, + makeAstTrait, + makeDummyAstTrait, + makeAstFieldDecl, + makeDummyAstFieldDecl, + makeAstContractInit, + makeDummyAstContractInit, + makeAstReceiver, + makeDummyAstReceiver, + makeAstFunctionDecl, + makeDummyAstFunctionDecl, + makeAstConstantDecl, + makeDummyAstConstantDecl, + makeAstStatementLet, + makeDummyAstStatementLet, + makeAstStatementReturn, + makeDummyAstStatementReturn, + makeAstStatementExpression, + makeDummyAstStatementExpression, + makeAstStatementAssign, + makeDummyAstStatementAssign, + makeAstStatementAugmentedAssign, + makeDummyAstStatementAugmentedAssign, + makeAstStatementCondition, + makeDummyAstStatementCondition, + makeAstStatementWhile, + makeDummyAstStatementWhile, + makeAstStatementUntil, + makeDummyAstStatementUntil, + makeAstStatementRepeat, + makeDummyAstStatementRepeat, + makeAstStatementTry, + makeDummyAstStatementTry, + makeAstStatementForEach, + makeDummyAstStatementForEach, + makeAstStatementDestruct, + makeDummyAstStatementDestruct, + makeAstStatementBlock, + makeDummyAstStatementBlock, + makeAstTypeId, + makeDummyAstTypeId, + makeAstOptionalType, + makeDummyAstOptionalType, + makeAstMapType, + makeDummyAstMapType, + makeAstBouncedMessageType, + makeDummyAstBouncedMessageType, + makeAstOpBinary, + makeDummyAstOpBinary, + makeAstOpUnary, + makeDummyAstOpUnary, + makeAstConditional, + makeDummyAstConditional, + makeAstMethodCall, + makeDummyAstMethodCall, + makeAstFieldAccess, + makeDummyAstFieldAccess, + makeAstStaticCall, + makeDummyAstStaticCall, + makeAstStructInstance, + makeDummyAstStructInstance, + makeAstId, + makeDummyAstId, + makeAstInitOf, + makeDummyAstInitOf, + makeAstCodeOf, + makeDummyAstCodeOf, + makeAstString, + makeDummyAstString, + makeAstNumber, + makeDummyAstNumber, + makeAstBoolean, + makeDummyAstBoolean, + makeAstNull, + makeDummyAstNull, + makeAstSimplifiedString, + makeDummyAstSimplifiedString, + makeAstAddress, + makeDummyAstAddress, + makeAstCell, + makeDummyAstCell, + makeAstSlice, + makeDummyAstSlice, + makeAstStructValue, + makeDummyAstStructValue, + makeAstFunctionAttributeGet, + makeDummyAstFunctionAttributeGet, + makeAstFunctionAttributeRest, + makeDummyAstFunctionAttributeRest, + makeAstReceiverSimple, + makeAstReceiverFallback, + makeAstReceiverComment, + makeAstReceiverInternal, + makeDummyAstReceiverInternal, + makeAstReceiverExternal, + makeDummyAstReceiverExternal, + makeAstReceiverBounce, + makeDummyAstReceiverBounce, + makeAstFuncId, + makeDummyAstFuncId, + makeAstDestructMapping, + makeDummyAstDestructMapping, + makeAstDestructEnd, + makeDummyAstDestructEnd, + makeAstTypedParameter, + makeDummyAstTypedParameter, + makeAstModule, + makeAstStructFieldInitializer, + makeDummyAstStructFieldInitializer, + makeAstStructFieldValue, + makeDummyAstStructFieldValue, + makeAstImport, + makeDummyAstImport, + }; +}; + +export type MakeAstFactory = ReturnType; diff --git a/yarn.lock b/yarn.lock index 7db168dfc..170923b20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -66,6 +66,17 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^3.0.2" +"@babel/generator@^7.26.10": + version "7.26.10" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz#a60d9de49caca16744e6340c3658dfef6138c3f7" + integrity sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang== + dependencies: + "@babel/parser" "^7.26.10" + "@babel/types" "^7.26.10" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + "@babel/generator@^7.26.2": version "7.26.3" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019" @@ -140,6 +151,13 @@ dependencies: "@babel/types" "^7.26.5" +"@babel/parser@^7.26.10": + version "7.26.10" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz#e9bdb82f14b97df6569b0b038edd436839c57749" + integrity sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA== + dependencies: + "@babel/types" "^7.26.10" + "@babel/parser@^7.26.3": version "7.26.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234" @@ -304,6 +322,14 @@ "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" +"@babel/types@^7.26.10": + version "7.26.10" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259" + integrity sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" From 60d0dcb07b052a119bc5f380b77061eaf23d4940 Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Sun, 23 Mar 2025 13:14:16 +0100 Subject: [PATCH 06/10] refactor: change test files to use autogenerated make factory. --- src/test/pipeline/precompile-ast.spec.ts | 166 ++++++----------------- 1 file changed, 45 insertions(+), 121 deletions(-) diff --git a/src/test/pipeline/precompile-ast.spec.ts b/src/test/pipeline/precompile-ast.spec.ts index 8cd6477a0..53a0a5374 100644 --- a/src/test/pipeline/precompile-ast.spec.ts +++ b/src/test/pipeline/precompile-ast.spec.ts @@ -6,129 +6,53 @@ import { precompile } from "../../pipeline/precompile"; import files from "../../stdlib/stdlib"; import { createVirtualFileSystem } from "../../vfs/createVirtualFileSystem"; import fs from "fs"; -import { getSrcInfo } from "../../grammar/src-info"; import { getParser } from "../../grammar"; +import { getMakeAst } from "../../ast/generated/make-factory"; +import type { MakeAstFactory } from "../../ast/generated/make-factory"; + +// This function manually creates a module containing a contract with a reference to StateInit in its single field. +// StateInit is declared in stdlib. +// +// contract Test { +// f: StateInit; +// +// init() { +// self.f = initOf Test(); +// } +// } + +function makeModule(mF: MakeAstFactory): A.AstModule { + // The contract field + const field = mF.makeDummyAstFieldDecl( + mF.makeDummyAstId("f"), + mF.makeDummyAstTypeId("StateInit"), + undefined, + undefined, + ); + // The contract init function + const initOfExpr = mF.makeDummyAstInitOf(mF.makeDummyAstId("Test"), []); + const path = mF.makeDummyAstFieldAccess( + mF.makeDummyAstId("self"), + mF.makeDummyAstId("f"), + ); + const assignStmt = mF.makeDummyAstStatementAssign(path, initOfExpr); + const init = mF.makeDummyAstContractInit([], [assignStmt]); + + // The contract + const contract = mF.makeDummyAstContract( + mF.makeDummyAstId("Test"), + [], + [], + undefined, + [field, init], + ); + + return mF.makeAstModule([], [contract]); +} describe("pre-compilation of ASTs", () => { const astF = getAstFactory(); - // Using dummySrcInfo causes internal compiler error. So, just use this with a blank empty source, since there is no source file. - const emptySrcInfo = getSrcInfo(" ", 0, 0, null, "user"); - - // This function manually creates a module containing a contract with a reference to StateInit in its single field. - // StateInit is declared in stdlib. - // - // contract Test { - // f: StateInit; - // - // init() { - // self.f = initOf Test(); - // } - // } - - function makeModule(): A.AstModule { - return astF.createNode({ - kind: "module", - imports: [], - items: [makeContract()], - }) as A.AstModule; - } - - function makeId(name: string): A.AstId { - return astF.createNode({ - kind: "id", - text: name, - loc: emptySrcInfo, - }) as A.AstId; - } - - function makeTypeId(name: string): A.AstTypeId { - return astF.createNode({ - kind: "type_id", - text: name, - loc: emptySrcInfo, - }) as A.AstTypeId; - } - - function makeInitOf( - contract: A.AstId, - args: A.AstExpression[], - ): A.AstInitOf { - return astF.createNode({ - kind: "init_of", - args, - contract, - loc: emptySrcInfo, - }) as A.AstInitOf; - } - - function makeAssignStatement( - path: A.AstExpression, - expr: A.AstExpression, - ): A.AstStatementAssign { - return astF.createNode({ - kind: "statement_assign", - path: path, - expression: expr, - loc: emptySrcInfo, - }) as A.AstStatementAssign; - } - - function makeFieldAccess( - aggregate: A.AstExpression, - field: A.AstId, - ): A.AstFieldAccess { - return astF.createNode({ - kind: "field_access", - aggregate, - field, - loc: emptySrcInfo, - }) as A.AstFieldAccess; - } - - function makeContractField( - name: A.AstId, - type: A.AstTypeId, - expr: A.AstExpression | undefined, - ): A.AstFieldDecl { - return astF.createNode({ - kind: "field_decl", - name, - type, - as: undefined, - initializer: expr, - loc: emptySrcInfo, - }) as A.AstFieldDecl; - } - - function makeContractInit(): A.AstContractInit { - const initOfExpr = makeInitOf(makeId("Test"), []); - const path = makeFieldAccess(makeId("self"), makeId("f")); - const assignStmt = makeAssignStatement(path, initOfExpr); - return astF.createNode({ - kind: "contract_init", - params: [], - statements: [assignStmt], - loc: emptySrcInfo, - }) as A.AstContractInit; - } - - function makeContract(): A.AstContract { - const field = makeContractField( - makeId("f"), - makeTypeId("StateInit"), - undefined, - ); - const init = makeContractInit(); - return astF.createNode({ - kind: "contract", - name: makeId("Test"), - params: undefined, - traits: [], - attributes: [], - declarations: [field, init], - loc: emptySrcInfo, - }) as A.AstContract; - } + const mF = getMakeAst(astF); it("should pass pre-compilation of AST with references to stdlib", () => { const ctx = new CompilerContext(); @@ -144,7 +68,7 @@ describe("pre-compilation of ASTs", () => { const parser = getParser(astF); precompile(ctx, project, stdlib, "empty.tact", parser, astF, [ - makeModule(), + makeModule(mF), ]); }); @@ -184,7 +108,7 @@ describe("pre-compilation of ASTs", () => { // So, a clash should occur here, since dummy.tact and makeModule() both declare the contract Test. expect(() => precompile(ctx, project, stdlib, "dummy.tact", parser, astF, [ - makeModule(), + makeModule(mF), ]), ).toThrowErrorMatchingSnapshot(); }); From afa988f5964d5e00495ae8fb59ecacc3f605f508 Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Sun, 23 Mar 2025 17:44:44 +0100 Subject: [PATCH 07/10] fix: conflict in imports version. --- package.json | 6 +++--- src/test/pipeline/empty.tact | 0 yarn.lock | 26 -------------------------- 3 files changed, 3 insertions(+), 29 deletions(-) delete mode 100644 src/test/pipeline/empty.tact diff --git a/package.json b/package.json index cd8395c78..523c7e70a 100644 --- a/package.json +++ b/package.json @@ -107,9 +107,9 @@ "@types/node": "^22.5.0", "@typescript-eslint/eslint-plugin": "^8.21.0", "@typescript-eslint/parser": "^8.21.0", - "@babel/generator": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/types": "^7.26.10", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.5", + "@babel/types": "^7.26.5", "chalk": "4.1.2", "cli-table3": "^0.6.5", "cross-env": "^7.0.3", diff --git a/src/test/pipeline/empty.tact b/src/test/pipeline/empty.tact deleted file mode 100644 index e69de29bb..000000000 diff --git a/yarn.lock b/yarn.lock index 170923b20..7db168dfc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -66,17 +66,6 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^3.0.2" -"@babel/generator@^7.26.10": - version "7.26.10" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz#a60d9de49caca16744e6340c3658dfef6138c3f7" - integrity sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang== - dependencies: - "@babel/parser" "^7.26.10" - "@babel/types" "^7.26.10" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - "@babel/generator@^7.26.2": version "7.26.3" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019" @@ -151,13 +140,6 @@ dependencies: "@babel/types" "^7.26.5" -"@babel/parser@^7.26.10": - version "7.26.10" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz#e9bdb82f14b97df6569b0b038edd436839c57749" - integrity sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA== - dependencies: - "@babel/types" "^7.26.10" - "@babel/parser@^7.26.3": version "7.26.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234" @@ -322,14 +304,6 @@ "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" -"@babel/types@^7.26.10": - version "7.26.10" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259" - integrity sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ== - dependencies: - "@babel/helper-string-parser" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" From e0bbee8e21c5d3ee6c6882cb7c8a958a84b0c6cd Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Wed, 26 Mar 2025 02:19:21 +0100 Subject: [PATCH 08/10] refactor: tSQualifiedName --> tsQualifiedName --- src/ast/generated/gen-make-functions-script.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/generated/gen-make-functions-script.ts b/src/ast/generated/gen-make-functions-script.ts index 20c9f567d..e1bebaaf6 100644 --- a/src/ast/generated/gen-make-functions-script.ts +++ b/src/ast/generated/gen-make-functions-script.ts @@ -177,7 +177,7 @@ function createMakeAndDummyFunctions( : t.objectProperty(id, t.identifier(`p_${id.name}`)), ); const funReturnType = t.tsTypeReference( - t.tSQualifiedName(t.identifier(astNamespace), id), + t.tsQualifiedName(t.identifier(astNamespace), id), ); // Function to create the function codes const createFun = ( @@ -238,7 +238,7 @@ function qualifyType( if (typ.typeName.type === "Identifier") { if (decls.has(typ.typeName.name)) { return t.tsTypeReference( - t.tSQualifiedName( + t.tsQualifiedName( t.identifier(namespace), typ.typeName, ), From e2d2b0f4777cc415b106a0430e05c1a2275a019f Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Wed, 26 Mar 2025 03:00:11 +0100 Subject: [PATCH 09/10] refactor: changed comparisons to types for isX guard functions. Set default case in switch to throw an exception. --- .../generated/gen-make-functions-script.ts | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/ast/generated/gen-make-functions-script.ts b/src/ast/generated/gen-make-functions-script.ts index e1bebaaf6..6cb420179 100644 --- a/src/ast/generated/gen-make-functions-script.ts +++ b/src/ast/generated/gen-make-functions-script.ts @@ -14,11 +14,12 @@ function main() { const astModule = fs .readFileSync(path.join(__dirname, "..", "ast.ts")) .toString(); + const astTypeDecls = parse(astModule, options); const decls = astTypeDecls.program.body - .filter((stmt) => stmt.type === "ExportNamedDeclaration") + .filter((stmt) => t.isExportNamedDeclaration(stmt)) .map((stmt) => stmt.declaration) - .filter((stmt) => stmt?.type === "TSTypeAliasDeclaration"); + .filter((stmt) => t.isTSTypeAliasDeclaration(stmt)); const declNames = new Set(decls.map((decl) => decl.id.name)); @@ -27,13 +28,13 @@ function main() { // Extract from the declarations all the union types const unionTypes = decls .map((decl) => decl.typeAnnotation) - .filter((decl) => decl.type === "TSUnionType"); + .filter((decl) => t.isTSUnionType(decl)); for (const unionType of unionTypes) { const subtypes = unionType.types - .filter((typeDecl) => typeDecl.type === "TSTypeReference") + .filter((typeDecl) => t.isTSTypeReference(typeDecl)) .map((typeDecl) => typeDecl.typeName) - .filter((typeDecl) => typeDecl.type === "Identifier"); + .filter((typeDecl) => t.isIdentifier(typeDecl)); for (const subtype of subtypes) { const subtypeDecl = decls.find( @@ -43,10 +44,10 @@ function main() { throw new Error(`${subtype.name} is not declared.`); } - const subtypeDeclType = subtypeDecl.typeAnnotation.type; - if (subtypeDeclType === "TSTypeLiteral") { + const subtypeDeclAnnotation = subtypeDecl.typeAnnotation; + if (t.isTSTypeLiteral(subtypeDeclAnnotation)) { const genFunctions = createMakeAndDummyFunctions( - subtypeDecl.typeAnnotation, + subtypeDeclAnnotation, subtypeDecl.id, declNames, ); @@ -61,7 +62,7 @@ function main() { } finalFunctions.push(...genFunctionsFiltered); - } else if (subtypeDeclType === "TSUnionType") { + } else if (t.isTSUnionType(subtypeDeclAnnotation)) { // Do nothing, since it will be processed later. } else { // Unexpected type @@ -103,8 +104,8 @@ function createMakeAndDummyFunctions( const createNodeFunName = "createNode"; const emptySrcInfo = "emptySrcInfo"; - const rawFieldsArray = decl.members.filter( - (decl) => decl.type === "TSPropertySignature", + const rawFieldsArray = decl.members.filter((decl) => + t.isTSPropertySignature(decl), ); const generalParams: { id: t.Identifier; type: t.TSType }[] = []; const paramsWithLiteralTypes: { @@ -115,11 +116,11 @@ function createMakeAndDummyFunctions( // If there is no loc field, // the makeDummy function cannot be created const makeDummy = rawFieldsArray.some( - (f) => f.key.type === "Identifier" && f.key.name === "loc", + (f) => t.isIdentifier(f.key) && f.key.name === "loc", ); for (const field of rawFieldsArray) { - if (field.key.type !== "Identifier") { + if (!t.isIdentifier(field.key)) { throw new Error( `Expected identifier in fields, but found ${field.key.type}`, ); @@ -132,7 +133,7 @@ function createMakeAndDummyFunctions( } if (field.typeAnnotation) { const typeAnnotation = field.typeAnnotation.typeAnnotation; - if (typeAnnotation.type === "TSLiteralType") { + if (t.isTSLiteralType(typeAnnotation)) { paramsWithLiteralTypes.push({ id: field.key, type: typeAnnotation, @@ -235,7 +236,7 @@ function qualifyType( ): t.TSType { switch (typ.type) { case "TSTypeReference": { - if (typ.typeName.type === "Identifier") { + if (t.isIdentifier(typ.typeName)) { if (decls.has(typ.typeName.name)) { return t.tsTypeReference( t.tsQualifiedName( @@ -278,7 +279,9 @@ function qualifyType( } case "TSTupleType": { if ( - typ.elementTypes.every((t) => t.type !== "TSNamedTupleMember") + // Cannot use guard function isTSNamedTupleMember, because compiler cannot deduce the type inside + // the condition if the guard function is used. + typ.elementTypes.every((ty) => ty.type !== "TSNamedTupleMember") ) { return t.tsTupleType( typ.elementTypes.map((t) => @@ -292,9 +295,13 @@ function qualifyType( ); } } - - default: + case "TSUndefinedKeyword": + case "TSStringKeyword": + case "TSBooleanKeyword": + case "TSBigIntKeyword": return typ; + default: + throw new Error(`${typ.type} is not supported`); } } From 128f19d5c43cfef6dbaf6d6379236b772b2d0c4e Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Wed, 26 Mar 2025 03:06:03 +0100 Subject: [PATCH 10/10] refactor: changed named of yarn command to gen:make-funs --- package.json | 2 +- src/ast/generated/make-factory.template | 2 +- src/ast/generated/make-factory.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 523c7e70a..dbd4f83d8 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "all": "yarn clean && yarn gen && yarn build && yarn coverage && yarn lint:all", "next-version": "ts-node version.build.ts", "random-ast": "ts-node ./src/ast/random-ast.ts", - "gen-make-functions": "ts-node ./src/ast/generated/gen-make-functions-script.ts && yarn prettier -w ./src/ast/generated/make-factory.ts", + "gen:make-funs": "ts-node ./src/ast/generated/gen-make-functions-script.ts && yarn prettier -w ./src/ast/generated/make-factory.ts", "top10": "find . -type f -exec du -h {} + | sort -rh | head -n 10" }, "files": [ diff --git a/src/ast/generated/make-factory.template b/src/ast/generated/make-factory.template index 624b8450f..38e1423a6 100644 --- a/src/ast/generated/make-factory.template +++ b/src/ast/generated/make-factory.template @@ -1,4 +1,4 @@ -// THIS IS AN AUTOGENERATED FILE. TO GENERATE IT AGAIN, EXECUTE yarn gen-make-functions +// THIS IS AN AUTOGENERATED FILE. TO GENERATE IT AGAIN, EXECUTE yarn gen:make-funs import type { FactoryAst } from "../ast-helpers"; import type * as Ast from "../ast"; diff --git a/src/ast/generated/make-factory.ts b/src/ast/generated/make-factory.ts index 179bdf3c2..87bfc4c83 100644 --- a/src/ast/generated/make-factory.ts +++ b/src/ast/generated/make-factory.ts @@ -1,4 +1,4 @@ -// THIS IS AN AUTOGENERATED FILE. TO GENERATE IT AGAIN, EXECUTE yarn gen-make-functions +// THIS IS AN AUTOGENERATED FILE. TO GENERATE IT AGAIN, EXECUTE yarn gen:make-funs import type { FactoryAst } from "../ast-helpers"; import type * as Ast from "../ast";