Skip to content

Commit

Permalink
Merge branch 'main' into trailing-comma
Browse files Browse the repository at this point in the history
  • Loading branch information
anton-trunov committed Apr 2, 2024
2 parents 4f4de39 + 20eb6e0 commit e362df6
Show file tree
Hide file tree
Showing 30 changed files with 506 additions and 168 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `log2` and `log` math functions in `@stdlib/math`: PR [#166](https://github.com/tact-lang/tact/pull/166)
- Reserve mode constants in `@stdlib/reserve`, namely `ReserveExact`, `ReserveAllExcept`, `ReserveAtMost`, `ReserveAddOriginalBalance`, `ReserveInvertSign`, `ReserveBounceIfActionFail`: PR [#173](https://github.com/tact-lang/tact/pull/173)
- JSON Schema for `tact.config.json`: PR [#194](https://github.com/tact-lang/tact/pull/194)
- Display an error for integer overflow at compile-time: PR [#200](https://github.com/tact-lang/tact/pull/200)
- Non-modifying `StringBuilder`'s `concat` method for chained string concatenations: PR [#217](https://github.com/tact-lang/tact/pull/217)
- `toString` extension function for `Address` type: PR [#224](https://github.com/tact-lang/tact/pull/224)

### Changed
- Update the `dump` function to handle addresses: PR [#175](https://github.com/tact-lang/tact/pull/175)
- Support trailing commas for struct fields and function arguments: PR [#179](https://github.com/tact-lang/tact/pull/179)
- The implicit empty `init` function is now present by default in the contract if not declared: PR [#167](https://github.com/tact-lang/tact/pull/167)
- `@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)
- Support escape sequences for strings (`\\`, `\"`, `\n`, `\r`, `\t`, `\v`, `\b`, `\f`, `\u{0}` through `\u{FFFFFF}`, `\u0000` through `\uFFFF`, `\x00` through `\xFF`): PR [#192](https://github.com/tact-lang/tact/pull/192)

### Fixed
- Incorrect "already exists" errors when using names such as `toString` or `valueOf`: PR [#208](https://github.com/tact-lang/tact/pull/208)
- Escape backticks in error messages for generated TypeScript code: PR [#192](https://github.com/tact-lang/tact/pull/192)

## [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(', ')})`;
}
}
}
}]
]);
6 changes: 5 additions & 1 deletion src/bindings/writeTypescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ export function writeTypescript(abi: ContractABI, init?: {
w.inIndent(() => {
if (abi.errors) {
for (const k in abi.errors) {
w.append(`${k}: { message: \`${abi.errors[parseInt(k, 10)].message}\` },`);
w.append(
`${k}: { message: \`${abi.errors[
parseInt(k, 10)
].message.replaceAll('`', '\\`')}\` },`
);
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2996,6 +2996,21 @@ return ((builders), ());",
"name": "__tact_string_builder_append",
"signature": "((tuple), ()) __tact_string_builder_append(tuple builders, slice sc)",
},
{
"code": {
"code": "builders~__tact_string_builder_append(sc);
return builders;",
"kind": "generic",
},
"comment": null,
"context": "stdlib",
"depends": Set {
"__tact_string_builder_append",
},
"flags": Set {},
"name": "__tact_string_builder_append_not_mut",
"signature": "(tuple) __tact_string_builder_append_not_mut(tuple builders, slice sc)",
},
{
"code": {
"code": "var b = begin_cell();
Expand Down Expand Up @@ -6978,6 +6993,21 @@ return ((builders), ());",
"name": "__tact_string_builder_append",
"signature": "((tuple), ()) __tact_string_builder_append(tuple builders, slice sc)",
},
{
"code": {
"code": "builders~__tact_string_builder_append(sc);
return builders;",
"kind": "generic",
},
"comment": null,
"context": "stdlib",
"depends": Set {
"__tact_string_builder_append",
},
"flags": Set {},
"name": "__tact_string_builder_append_not_mut",
"signature": "(tuple) __tact_string_builder_append_not_mut(tuple builders, slice sc)",
},
{
"code": {
"code": "var b = begin_cell();
Expand Down Expand Up @@ -10960,6 +10990,21 @@ return ((builders), ());",
"name": "__tact_string_builder_append",
"signature": "((tuple), ()) __tact_string_builder_append(tuple builders, slice sc)",
},
{
"code": {
"code": "builders~__tact_string_builder_append(sc);
return builders;",
"kind": "generic",
},
"comment": null,
"context": "stdlib",
"depends": Set {
"__tact_string_builder_append",
},
"flags": Set {},
"name": "__tact_string_builder_append_not_mut",
"signature": "(tuple) __tact_string_builder_append_not_mut(tuple builders, slice sc)",
},
{
"code": {
"code": "var b = begin_cell();
Expand Down
58 changes: 50 additions & 8 deletions src/generator/writers/writeExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,44 @@ export function writeExpression(f: ASTExpression, ctx: WriterContext): string {
//

if (f.kind === 'string') {
const id = writeString(f.value, ctx);
const s = f.value.replace(/\\\\|\\"|\\n|\\r|\\t|\\v|\\b|\\f|\\u{([0-9A-Fa-f]+)}|\\u([0-9A-Fa-f]{4})|\\x([0-9A-Fa-f]{2})/g, (match, unicodeCodePoint, unicodeEscape, hexEscape) => {
switch (match) {
case '\\\\':
return '\\';
case '\\"':
return '"';
case '\\n':
return '\n';
case '\\r':
return '\r';
case '\\t':
return '\t';
case '\\v':
return '\v';
case '\\b':
return '\b';
case '\\f':
return '\f';
default:
// Handle Unicode code point escape
if (unicodeCodePoint) {
const codePoint = parseInt(unicodeCodePoint, 16);
return String.fromCodePoint(codePoint);
}
// Handle Unicode escape
if (unicodeEscape) {
const codeUnit = parseInt(unicodeEscape, 16);
return String.fromCharCode(codeUnit);
}
// Handle hex escape
if (hexEscape) {
const hexValue = parseInt(hexEscape, 16);
return String.fromCharCode(hexValue);
}
return match;
}
});
const id = writeString(s, ctx);
ctx.used(id);
return `${id}()`;
}
Expand Down Expand Up @@ -471,8 +508,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 +568,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 +619,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
11 changes: 11 additions & 0 deletions src/generator/writers/writeStdlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,17 @@ export function writeStdlib(ctx: WriterContext) {
});
});

ctx.fun(`__tact_string_builder_append_not_mut`, () => {
ctx.signature(`(tuple) __tact_string_builder_append_not_mut(tuple builders, slice sc)`);
ctx.context('stdlib');
ctx.body(() => {
ctx.write(`
builders~${ctx.used('__tact_string_builder_append')}(sc);
return builders;
`);
});
});

ctx.fun(`__tact_int_to_string`, () => {
ctx.signature(`slice __tact_int_to_string(int src)`);
ctx.context('stdlib');
Expand Down
15 changes: 13 additions & 2 deletions src/grammar/grammar.ohm
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,19 @@ Tact {
boolLiteral = ("true" | "false") ~idPart

// String literal
stringLiteralCharacter = ~("\"" | "\\" | lineTerminator) any
stringLiteral = "\"" stringLiteralCharacter* "\""
stringLiteral = "\"" (nonQuoteOrBackslashChar | escapeSequence)* "\""
nonQuoteOrBackslashChar = ~("\"" | "\\") any
escapeSequence = "\\\\" -- backslash
| "\\\"" -- doubleQuote
| "\\n" -- newline
| "\\r" -- carriageReturn
| "\\t" -- tab
| "\\v" -- verticalTab
| "\\b" -- backspace
| "\\f" -- formFeed
| "\\u{" hexDigit hexDigit? hexDigit? hexDigit? hexDigit? hexDigit? "}" -- unicodeCodePoint
| "\\u" hexDigit hexDigit hexDigit hexDigit -- unicodeEscape
| "\\x" hexDigit hexDigit -- hexEscape

// Keywords
// NOTE Order is important
Expand Down
Loading

0 comments on commit e362df6

Please sign in to comment.