Skip to content

Commit

Permalink
struct dependencies handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Gusarich committed Jul 11, 2024
1 parent 18a124a commit 073ab23
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/generator/createABI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { CompilerContext } from "../context";
import { idText } from "../grammar/ast";
import { getSupportedInterfaces } from "../types/getSupportedInterfaces";
import { createABITypeRefFromTypeRef } from "../types/resolveABITypeRef";
import { getAllTypes } from "../types/resolveDescriptors";
import {
getAllTypes,
getStructDependencies,
} from "../types/resolveDescriptors";
import { getAllErrors } from "../types/resolveErrors";

export function createABI(ctx: CompilerContext, name: string): ContractABI {
Expand All @@ -21,7 +24,8 @@ export function createABI(ctx: CompilerContext, name: string): ContractABI {

// Structs
const types: ABIType[] = [];
for (const t of allTypes) {
const structDependencies = getStructDependencies(ctx, contract.name);
for (const t of structDependencies) {
if (t.kind === "struct") {
types.push({
name: t.name,
Expand Down
60 changes: 60 additions & 0 deletions src/test/e2e-emulated/contracts/abi.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import "@stdlib/deploy";

struct S {
x: Int;
}

struct S2 {
y: Int;
}

struct S3 {
z: Int;
}

fun testS3(): Int {
let s3 = S3 { z: 123 };
return s3.z;
}

contract A with Deployable {
receive() {}

get fun test(): S2 {
return S2 { y: 123 };
}
}

contract B with Deployable {
receive() {
require(1 == 1, "1 is not equal to 1");
}

get fun test1(): Address {
return contractAddress(initOf A());
}

get fun test2(): S {
return S { x: 123 };
}
}

contract C with Deployable {
s: S;

init () {
self.s = S { x: 123 };
}

get fun test(): S {
return self.s;
}
}

contract D with Deployable {
receive() {}

get fun test(): Int {
return testS3();
}
}
107 changes: 107 additions & 0 deletions src/types/resolveDescriptors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import { ItemOrigin } from "../grammar/grammar";
const store = createContextStore<TypeDescription>();
const staticFunctionsStore = createContextStore<FunctionDescription>();
const staticConstantsStore = createContextStore<ConstantDescription>();
const structDependenciesStore = createContextStore<Set<TypeDescription>>();

function verifyMapType(
key: string,
Expand Down Expand Up @@ -264,6 +265,7 @@ export function resolveDescriptors(ctx: CompilerContext) {
const types: Map<string, TypeDescription> = new Map();
const staticFunctions: Map<string, FunctionDescription> = new Map();
const staticConstants: Map<string, ConstantDescription> = new Map();
const structDependencies: Map<string, Set<TypeDescription>> = new Map();
const ast = getRawAST(ctx);

//
Expand Down Expand Up @@ -1783,6 +1785,97 @@ export function resolveDescriptors(ctx: CompilerContext) {
staticConstants.set(idText(a.name), buildConstantDescription(a));
}

//
// Register structs dependencies
//

function structDependenciesHandler(name: string) {
return (src: AstNode) => {
if (src.kind === "id" || src.kind === "type_id") {
if (
types.get(idText(src))?.kind === "struct" &&
types.get(idText(src))?.origin === "user"
) {
if (!structDependencies.has(name)) {
structDependencies.set(name, new Set());
}
structDependencies.get(name)!.add(types.get(idText(src))!);
}
} else if (src.kind === "init_of") {
if (
types.get(idText(src.contract))?.kind === "contract" &&
types.get(idText(src.contract))?.origin === "user"
) {
if (!structDependencies.has(name)) {
structDependencies.set(name, new Set());
}
structDependencies.set(
name,
new Set([
...structDependencies.get(name)!,
...(structDependencies.get(idText(src.contract)) ??
new Set()),
]),
);
}
} else if (src.kind === "static_call") {
if (staticFunctions.has(src.function.text)) {
if (!structDependencies.has(name)) {
structDependencies.set(name, new Set());
}
structDependencies.set(
name,
new Set([
...structDependencies.get(name)!,
...(structDependencies.get(idText(src.function)) ??
new Set()),
]),
);
}
}
};
}

for (const [k, t] of staticFunctions) {
const handler = structDependenciesHandler(k);
traverse(t.ast, handler);
}

for (const [k, t] of types) {
const handler = structDependenciesHandler(k);

// Traverse fields
for (const f of t.fields) {
traverse(f.ast, handler);
}

// Traverse constants
for (const f of t.constants) {
traverse(f.ast, handler);
}

// Traverse functions
for (const f of t.functions.values()) {
traverse(f.ast, handler);
}

// Traverse init
if (t.init) {
traverse(t.init.ast, handler);
}

// Traverse receivers
for (const f of t.receivers) {
traverse(f.ast, handler);
}
}

for (const [k, v] of structDependencies) {
// print k and .name of each v
const vNames = Array.from(v).map((v) => v.name);
console.log(k, vNames);
}

//
// Register types and functions in context
//
Expand All @@ -1796,6 +1889,9 @@ export function resolveDescriptors(ctx: CompilerContext) {
for (const [k, t] of staticConstants) {
ctx = staticConstantsStore.set(ctx, k, t);
}
for (const [k, t] of structDependencies) {
ctx = structDependenciesStore.set(ctx, k, t);
}

return ctx;
}
Expand Down Expand Up @@ -1860,6 +1956,17 @@ export function getAllStaticConstants(ctx: CompilerContext) {
return staticConstantsStore.all(ctx);
}

export function getStructDependencies(
ctx: CompilerContext,
name: string,
): Set<TypeDescription> {
const r = structDependenciesStore.get(ctx, name);
if (!r) {
throw Error("Entity '" + name + "' not found");
}
return r;
}

function resolvePartialFields(ctx: CompilerContext, type: TypeDescription) {
if (type.kind !== "struct") return 0;

Expand Down
5 changes: 5 additions & 0 deletions tact.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,11 @@
"options": {
"debug": true
}
},
{
"name": "abi",
"path": "./src/test/e2e-emulated/contracts/abi.tact",
"output": "./src/test/e2e-emulated/contracts/output"
}
]
}

0 comments on commit 073ab23

Please sign in to comment.