Skip to content

Commit

Permalink
fix: use maps instead of objects for tables of globals (#208)
Browse files Browse the repository at this point in the history
to avoid issues with `toString`, `valueOf`, etc. that exist for JS objects
and clash with Tact's builtins when querying e.g. the global functions map
  • Loading branch information
Gusarich authored Apr 2, 2024
1 parent a7f3ad0 commit c1f013f
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 132 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `@stdlib/stoppable` now imports `@stdlib/ownable` so the programmer does not have to do it separately: PR [#193](https://github.com/tact-lang/tact/pull/193)

### Fixed
- Incorrect "already exists" errors when using names such as `toString` or `valueOf`: PR [#208](https://github.com/tact-lang/tact/pull/208)

## [1.2.0] - 2024-02-29

Expand Down
36 changes: 18 additions & 18 deletions src/abi/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { getErrorId } from "../types/resolveErrors";
import { AbiFunction } from "./AbiFunction";
import { sha256_sync } from "@ton/crypto";

export const GlobalFunctions: { [key: string]: AbiFunction } = {
ton: {
export const GlobalFunctions: Map<string, AbiFunction> = new Map([
['ton', {
name: 'ton',
resolve: (ctx, args, ref) => {
if (args.length !== 1) {
Expand All @@ -30,8 +30,8 @@ export const GlobalFunctions: { [key: string]: AbiFunction } = {
const str = resolveConstantValue({ kind: 'ref', name: 'String', optional: false }, resolved[0], ctx.ctx) as string;
return toNano(str).toString(10);
}
},
pow: {
}],
['pow', {
name: 'pow',
resolve: (ctx, args, ref) => {
if (args.length !== 2) {
Expand Down Expand Up @@ -59,8 +59,8 @@ export const GlobalFunctions: { [key: string]: AbiFunction } = {
const b = resolveConstantValue({ kind: 'ref', name: 'Int', optional: false }, resolved[1], ctx.ctx) as bigint;
return (a ** b).toString(10);
}
},
require: {
}],
['require', {
name: 'require',
resolve: (ctx, args, ref) => {
if (args.length !== 2) {
Expand All @@ -87,8 +87,8 @@ export const GlobalFunctions: { [key: string]: AbiFunction } = {
const str = resolveConstantValue({ kind: 'ref', name: 'String', optional: false }, resolved[1], ctx.ctx) as string;
return `throw_unless(${getErrorId(str, ctx.ctx)}, ${writeExpression(resolved[0], ctx)})`;
}
},
address: {
}],
['address', {
name: 'address',
resolve: (ctx, args, ref) => {
if (args.length !== 1) {
Expand Down Expand Up @@ -122,8 +122,8 @@ export const GlobalFunctions: { [key: string]: AbiFunction } = {
ctx.used(res);
return res + '()';
}
},
cell: {
}],
['cell', {
name: 'cell',
resolve: (ctx, args, ref) => {
if (args.length !== 1) {
Expand Down Expand Up @@ -156,8 +156,8 @@ export const GlobalFunctions: { [key: string]: AbiFunction } = {
ctx.used(res);
return `${res}()`;
}
},
dump: {
}],
['dump', {
name: 'dump',
resolve: (ctx, args, ref) => {
if (args.length !== 1) {
Expand Down Expand Up @@ -196,8 +196,8 @@ export const GlobalFunctions: { [key: string]: AbiFunction } = {
throwError('dump() not supported for argument', ref);
}
}
},
emptyMap: {
}],
['emptyMap', {
name: 'emptyMap',
resolve: (ctx, args, ref) => {
if (args.length !== 0) {
Expand All @@ -208,8 +208,8 @@ export const GlobalFunctions: { [key: string]: AbiFunction } = {
generate: (_ctx, _args, _resolved, _ref) => {
return 'null()';
}
},
sha256: {
}],
['sha256', {
name: 'sha256',
resolve: (ctx, args, ref) => {
if (args.length !== 1) {
Expand Down Expand Up @@ -254,5 +254,5 @@ export const GlobalFunctions: { [key: string]: AbiFunction } = {

throwError('sha256 expects string or slice argument', ref);
}
}
}
}]
])
16 changes: 8 additions & 8 deletions src/abi/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { throwError } from "../grammar/ast";
import { getType } from "../types/resolveDescriptors";
import { AbiFunction } from "./AbiFunction";

export const MapFunctions: { [key: string]: AbiFunction } = {
set: {
export const MapFunctions: Map<string, AbiFunction> = new Map([
['set', {
name: 'set',
resolve(ctx, args, ref) {

Expand Down Expand Up @@ -152,8 +152,8 @@ export const MapFunctions: { [key: string]: AbiFunction } = {

throwError(`set expects a map with Int keys`, ref);
}
},
get: {
}],
['get', {
name: 'get',
resolve(ctx, args, ref) {

Expand Down Expand Up @@ -277,8 +277,8 @@ export const MapFunctions: { [key: string]: AbiFunction } = {

throwError(`set expects a map with Int keys`, ref);
}
},
asCell: {
}],
['asCell', {
name: 'asCell',
resolve(ctx, args, ref) {

Expand All @@ -304,5 +304,5 @@ export const MapFunctions: { [key: string]: AbiFunction } = {

return writeExpression(exprs[0], ctx);
}
}
}
}]
]);
8 changes: 4 additions & 4 deletions src/abi/struct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { throwError } from "../grammar/ast";
import { getType } from "../types/resolveDescriptors";
import { AbiFunction } from "./AbiFunction";

export const StructFunctions: { [key: string]: AbiFunction } = {
toCell: {
export const StructFunctions: Map<string, AbiFunction> = new Map([
['toCell', {
name: 'toCell',
resolve: (ctx, args, ref) => {
if (args.length !== 1) {
Expand All @@ -29,5 +29,5 @@ export const StructFunctions: { [key: string]: AbiFunction } = {
}
return `${ops.writerCell(args[0].name, ctx)}(${resolved.map((v) => writeExpression(v, ctx)).join(', ')})`;
}
}
}
}]
]);
19 changes: 12 additions & 7 deletions src/generator/writers/writeExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,8 @@ export function writeExpression(f: ASTExpression, ctx: WriterContext): string {
if (f.kind === 'op_static_call') {

// Check global functions
if (GlobalFunctions[f.name]) {
return GlobalFunctions[f.name].generate(ctx,
if (GlobalFunctions.has(f.name)) {
return GlobalFunctions.get(f.name)!.generate(ctx,
f.args.map((v) => getExpType(ctx.ctx, v)),
f.args,
f.ref);
Expand Down Expand Up @@ -531,9 +531,14 @@ export function writeExpression(f: ASTExpression, ctx: WriterContext): string {

// Check struct ABI
if (t.kind === 'struct') {
const abi = StructFunctions[f.name];
if (abi) {
return abi.generate(ctx, [src, ...f.args.map((v) => getExpType(ctx.ctx, v))], [f.src, ...f.args], f.ref);
if (StructFunctions.has(f.name)) {
const abi = StructFunctions.get(f.name)!;
return abi.generate(
ctx,
[src, ...f.args.map((v) => getExpType(ctx.ctx, v))],
[f.src, ...f.args],
f.ref
);
}
}

Expand Down Expand Up @@ -577,10 +582,10 @@ export function writeExpression(f: ASTExpression, ctx: WriterContext): string {

// Map types
if (src.kind === 'map') {
const abf = MapFunctions[f.name];
if (!abf) {
if (!MapFunctions.has(f.name)) {
throwError(`Map function "${f.name}" not found`, f.ref);
}
const abf = MapFunctions.get(f.name)!;
return abf.generate(ctx, [src, ...f.args.map((v) => getExpType(ctx.ctx, v))], [f.src, ...f.args], f.ref);
}

Expand Down
77 changes: 77 additions & 0 deletions src/types/__snapshots__/resolveStatements.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,16 @@ Line 5, col 39:
"
`;
exports[`resolveStatements should fail statements for case-30 1`] = `
"<unknown>:7:9: Static function "toString" does not exist
Line 7, col 9:
6 | init() {
> 7 | toString(); // non-existent function
^~~~~~~~~~
8 | }
"
`;
exports[`resolveStatements should resolve statements for case-0 1`] = `
[
[
Expand Down Expand Up @@ -812,3 +822,70 @@ exports[`resolveStatements should resolve statements for case-9 1`] = `
],
]
`;
exports[`resolveStatements should resolve statements for case-10 1`] = `
[
[
"123",
"Int",
],
[
"toString()",
"Int",
],
]
`;
exports[`resolveStatements should resolve statements for case-11 1`] = `
[
[
"1",
"Int",
],
[
"toString",
"Int",
],
[
"dump(toString)",
"<void>",
],
]
`;
exports[`resolveStatements should resolve statements for case-12 1`] = `
[
[
"a",
"Int",
],
[
"b",
"Int",
],
[
"a + b",
"Int",
],
[
"2",
"Int",
],
[
"(a + b) / 2",
"Int",
],
[
"1",
"Int",
],
[
"10",
"Int",
],
[
"valueOf(1, 10)",
"Int",
],
]
`;
Loading

0 comments on commit c1f013f

Please sign in to comment.