Skip to content

Commit

Permalink
implement
Browse files Browse the repository at this point in the history
  • Loading branch information
Gusarich committed May 15, 2024
1 parent 79e87d5 commit 7ca95f5
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 44 deletions.
56 changes: 33 additions & 23 deletions src/generator/writers/writeFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ export function writeStatement(
writeStatement(s, self, returns, ctx);
}
});
ctx.append(`} catch (_, ${id(f.catchName)}) {`);
if (f.catchName == "_") {
ctx.append(`} catch (_) {`);
} else {
ctx.append(`} catch (_, ${id(f.catchName)}) {`);
}
ctx.inIndent(() => {
for (const s of f.catchStatements) {
writeStatement(s, self, returns, ctx);
Expand All @@ -201,6 +205,12 @@ export function writeStatement(
}

const flag = freshIdentifier("flag");
const key =
f.keyName == "_" ? freshIdentifier("underscore") : id(f.keyName);
const value =
f.valueName == "_"
? freshIdentifier("underscore")
: id(f.valueName);

// Handle Int key
if (t.key === "Int") {
Expand All @@ -223,75 +233,75 @@ export function writeStatement(
}

ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_${vkind}`)}(${id(f.map.value)}, ${bits}, ${vbits});`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_${vkind}`)}(${id(f.map.value)}, ${bits}, ${vbits});`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_${vkind}`)}(${id(f.map.value)}, ${bits}, ${id(f.keyName)}, ${vbits});`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_${vkind}`)}(${id(f.map.value)}, ${bits}, ${key}, ${vbits});`,
);
});
ctx.append(`}`);
} else if (t.value === "Bool") {
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_int`)}(${id(f.map.value)}, ${bits}, 1);`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_int`)}(${id(f.map.value)}, ${bits}, 1);`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_int`)}(${id(f.map.value)}, ${bits}, ${id(f.keyName)}, 1);`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_int`)}(${id(f.map.value)}, ${bits}, ${key}, 1);`,
);
});
ctx.append(`}`);
} else if (t.value === "Cell") {
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_cell`)}(${id(f.map.value)}, ${bits});`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_cell`)}(${id(f.map.value)}, ${bits});`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_cell`)}(${id(f.map.value)}, ${bits}, ${id(f.keyName)});`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_cell`)}(${id(f.map.value)}, ${bits}, ${key});`,
);
});
ctx.append(`}`);
} else if (t.value === "Address") {
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_slice`)}(${id(f.map.value)}, ${bits});`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_slice`)}(${id(f.map.value)}, ${bits});`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_slice`)}(${id(f.map.value)}, ${bits}, ${id(f.keyName)});`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_slice`)}(${id(f.map.value)}, ${bits}, ${key});`,
);
});
ctx.append(`}`);
} else {
// value is struct
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_cell`)}(${id(f.map.value)}, ${bits});`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_${kind}_cell`)}(${id(f.map.value)}, ${bits});`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
ctx.append(
`var ${resolveFuncTypeUnpack(t.value, id(f.valueName), ctx)} = ${ops.typeNotNull(t.value, ctx)}(${ops.readerOpt(t.value, ctx)}(${id(f.valueName)}));`,
`var ${resolveFuncTypeUnpack(t.value, id(f.valueName), ctx)} = ${ops.typeNotNull(t.value, ctx)}(${ops.readerOpt(t.value, ctx)}(${value}));`,
);
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_cell`)}(${id(f.map.value)}, ${bits}, ${id(f.keyName)});`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_${kind}_cell`)}(${id(f.map.value)}, ${bits}, ${key});`,
);
});
ctx.append(`}`);
Expand All @@ -310,75 +320,75 @@ export function writeStatement(
vkind = "uint";
}
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_${vkind}`)}(${id(f.map.value)}, 267, ${vbits});`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_${vkind}`)}(${id(f.map.value)}, 267, ${vbits});`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_${vkind}`)}(${id(f.map.value)}, 267, ${id(f.keyName)}, ${vbits});`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_${vkind}`)}(${id(f.map.value)}, 267, ${key}, ${vbits});`,
);
});
ctx.append(`}`);
} else if (t.value === "Bool") {
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_int`)}(${id(f.map.value)}, 267, 1);`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_int`)}(${id(f.map.value)}, 267, 1);`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_int`)}(${id(f.map.value)}, 267, ${id(f.keyName)}, 1);`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_int`)}(${id(f.map.value)}, 267, ${key}, 1);`,
);
});
ctx.append(`}`);
} else if (t.value === "Cell") {
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_cell`)}(${id(f.map.value)}, 267);`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_cell`)}(${id(f.map.value)}, 267);`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_cell`)}(${id(f.map.value)}, 267, ${id(f.keyName)});`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_cell`)}(${id(f.map.value)}, 267, ${key});`,
);
});
ctx.append(`}`);
} else if (t.value === "Address") {
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_slice`)}(${id(f.map.value)}, 267);`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_slice`)}(${id(f.map.value)}, 267);`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_slice`)}(${id(f.map.value)}, 267, ${id(f.keyName)});`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_slice`)}(${id(f.map.value)}, 267, ${key});`,
);
});
ctx.append(`}`);
} else {
// value is struct
ctx.append(
`var (${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_cell`)}(${id(f.map.value)}, 267);`,
`var (${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_min_slice_cell`)}(${id(f.map.value)}, 267);`,
);
ctx.append(`while (${flag}) {`);
ctx.inIndent(() => {
ctx.append(
`var ${resolveFuncTypeUnpack(t.value, id(f.valueName), ctx)} = ${ops.typeNotNull(t.value, ctx)}(${ops.readerOpt(t.value, ctx)}(${id(f.valueName)}));`,
`var ${resolveFuncTypeUnpack(t.value, id(f.valueName), ctx)} = ${ops.typeNotNull(t.value, ctx)}(${ops.readerOpt(t.value, ctx)}(${value}));`,
);
for (const s of f.statements) {
writeStatement(s, self, returns, ctx);
}
ctx.append(
`(${id(f.keyName)}, ${id(f.valueName)}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_cell`)}(${id(f.map.value)}, 267, ${id(f.keyName)});`,
`(${key}, ${value}, ${flag}) = ${ctx.used(`__tact_dict_next_slice_cell`)}(${id(f.map.value)}, 267, ${key});`,
);
});
ctx.append(`}`);
Expand Down
25 changes: 25 additions & 0 deletions src/test/feature-underscore-variable.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { toNano } from "@ton/core";
import { ContractSystem } from "@tact-lang/emulator";
import { __DANGER_resetNodeId } from "../grammar/ast";
import { UnderscoreVariableTestContract } from "./features/output/underscore-variable_UnderscoreVariableTestContract";

describe("feature-underscore-variable", () => {
beforeEach(() => {
__DANGER_resetNodeId();
});
it("should implement underscore variables correctly", async () => {
// Init
const system = await ContractSystem.create();
const treasure = system.treasure("treasure");
const contract = system.open(
await UnderscoreVariableTestContract.fromInit(),
);
await contract.send(treasure, { value: toNano("10") }, null);
await system.run();

// Check methods
expect(await contract.getTest1()).toEqual(0n);
expect(await contract.getTest2()).toEqual(12n);
expect(await contract.getTest3()).toEqual(6n);
});
});
42 changes: 42 additions & 0 deletions src/test/features/underscore-variable.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
contract UnderscoreVariableTestContract {
init() {
// Nothing to do
}

receive() {
// Nothing to do
}

get fun test1(): Int {
try {
nativeThrow(1);
} catch (_) {
return 0;
}
return 1;
}

get fun test2(): Int {
let m: map<Int, Int> = emptyMap();
m.set(1, 2);
m.set(2, 4);
m.set(3, 6);
let x: Int = 0;
foreach (_, v in m) {
x += v;
}
return x;
}

get fun test3(): Int {
let m: map<Int, Int> = emptyMap();
m.set(1, 2);
m.set(2, 4);
m.set(3, 6);
let x: Int = 0;
foreach (k, _ in m) {
x += k;
}
return x;
}
}
62 changes: 62 additions & 0 deletions src/types/__snapshots__/resolveStatements.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,26 @@ Line 8, col 12:
"
`;
exports[`resolveStatements should fail statements for case-51 1`] = `
"<unknown>:6:16: Unable to resolve id _
Line 6, col 16:
5 | foreach (_, _ in m) {
> 6 | return _;
^
7 | }
"
`;
exports[`resolveStatements should fail statements for case-52 1`] = `
"<unknown>:7:14: Unable to resolve id _
Line 7, col 14:
6 | foreach (_, v in m) {
> 7 | x += _;
^
8 | }
"
`;
exports[`resolveStatements should resolve statements for case-0 1`] = `
[
[
Expand Down Expand Up @@ -1366,3 +1386,45 @@ exports[`resolveStatements should resolve statements for case-20 1`] = `
],
]
`;
exports[`resolveStatements should resolve statements for case-21 1`] = `
[
[
"emptyMap()",
"<null>",
],
[
"m",
"map<Int, Int>",
],
]
`;
exports[`resolveStatements should resolve statements for case-22 1`] = `
[
[
"emptyMap()",
"<null>",
],
[
"0",
"Int",
],
[
"m",
"map<Int, Int>",
],
[
"x",
"Int",
],
[
"v",
"Int",
],
[
"x",
"Int",
],
]
`;
Loading

0 comments on commit 7ca95f5

Please sign in to comment.