From d76c6a012dbdeed8a8dc9f23477eaa72d07f3912 Mon Sep 17 00:00:00 2001 From: i582 <51853996+i582@users.noreply.github.com> Date: Fri, 19 Sep 2025 18:20:07 +0400 Subject: [PATCH 1/6] Source maps --- package.json | 3 +- src/cli.ts | 7 + src/high-level-source-map.ts | 72 +++++ src/index.ts | 106 ++++++- tests/__snapshots__/source-maps.spec.ts.snap | 295 +++++++++++++++++++ tests/source-maps.spec.ts | 142 +++++++++ tsconfig.json | 5 +- yarn.lock | 25 ++ 8 files changed, 650 insertions(+), 5 deletions(-) create mode 100644 src/high-level-source-map.ts create mode 100644 tests/__snapshots__/source-maps.spec.ts.snap create mode 100644 tests/source-maps.spec.ts diff --git a/package.json b/package.json index 1d3e251..39e3880 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ton/tolk-js", - "version": "1.0.0", + "version": "1.0.68", "description": "Tolk Language compiler (next-generation FunC)", "main": "dist/index.js", "bin": "./dist/cli.js", @@ -26,6 +26,7 @@ "@ton/crypto": "^3.3.0", "@types/jest": "^29.5.12", "jest": "^29.7.0", + "ton-assembly": "/Users/petrmakhnev/tasm-new/ton-assembly-0.3.0.tgz", "ts-jest": "^29.2.4", "typescript": "^5.5.4" }, diff --git a/src/cli.ts b/src/cli.ts index 6e89a97..e435cdb 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -13,6 +13,7 @@ async function tolkJsCli() { '--output-fift': String, '--experimental-options': String, '--cwd': String, + '--source-map': Boolean, '-v': '--version', '-h': '--help', @@ -31,6 +32,7 @@ Options: --output-fif - output .fif file with Fift code output --experimental-options - set experimental compiler options, comma-separated --cwd , -C — sets cwd to locate .tolk files (doesn't affect output paths) +--source-map — collect a source map for debugging `) process.exit(0) } @@ -57,6 +59,7 @@ Options: entrypointFileName: args._[0], experimentalOptions: args['--experimental-options'], fsReadCallback: p => fs.readFileSync(cwd ? path.join(cwd, p) : p, 'utf-8'), + collectSourceMap: args['--source-map'] === true, }) if (result.status === 'error') { @@ -71,6 +74,10 @@ Options: codeBoc64: result.codeBoc64, codeHashHex: result.codeHashHex, sourcesSnapshot: result.sourcesSnapshot, + fiftSourceMapCode: result.fiftSourceMapCode, + sourceMapCodeRecompiledBoc64: result.sourceMapCodeRecompiledBoc64, + sourceMapCodeBoc64: result.sourceMapCodeBoc64, + sourceMap: result.sourceMap, }, null, 2)) } diff --git a/src/high-level-source-map.ts b/src/high-level-source-map.ts new file mode 100644 index 0000000..a779cdc --- /dev/null +++ b/src/high-level-source-map.ts @@ -0,0 +1,72 @@ +enum FunctionInlineMode { + NotCalculated = 0, + InlineViaFif = 1, + InlineRef = 2, + InlineInPlace = 3, + NoInline = 4, +} + +export type HighLevelSourceMapLocation = { + readonly file: string + readonly line: number + readonly col: number + readonly line_offset: number + readonly length: number +} + +export type HighLevelSourceMapEntryContext = { + readonly descr?: string + readonly is_entry?: boolean + readonly ast_kind: string + readonly func_name: string + readonly inlined_to_func?: string + readonly func_inline_mode: FunctionInlineMode + readonly before_inlined_function_call?: boolean + readonly after_inlined_function_call?: boolean +} + +export type HighLevelSourceMapDebugInfo = { + readonly opcode?: string + readonly line_str?: string + readonly line_off?: string +} + +export type HighLevelSourceMapEntry = { + readonly idx: number + readonly loc: HighLevelSourceMapLocation + readonly vars: readonly HighLevelSourceMapVariable[] + readonly context: HighLevelSourceMapEntryContext + readonly debug?: HighLevelSourceMapDebugInfo +} + +export type HighLevelSourceMapVariable = { + readonly name: string + readonly type: string + readonly constant_value?: string + readonly possible_qualifier_types: readonly string[] +} + +export type HighLevelSourceMapGlobalVariable = { + readonly name: string + readonly type: string +} + +export type HighLevelSourceMapFile = { + readonly path: string + readonly is_stdlib: boolean + readonly content: string +} + +/** + * Represents a high-level source map. + * "High-level" in this case means that this source map only contains a mapping from DEBUGMARK ID to + * high-level language code, but it does not contain any further mapping from DEBUGMARK ID to + * specific instructions in bitcode. + */ +export type HighLevelSourceMap = { + readonly version: string + readonly files: readonly HighLevelSourceMapFile[] + readonly globals: readonly HighLevelSourceMapGlobalVariable[] + readonly locations: readonly HighLevelSourceMapEntry[] + readonly debugCode64?: string +} diff --git a/src/index.ts b/src/index.ts index 2f05180..5fd194e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,8 @@ import wasmBase64 from "./tolkfiftlib.wasm.js" // @ts-ignore import stdlibContents from "./stdlib.tolk.js" import {realpath} from "./path-utils" +import {Cell, runtime, text, trace} from "ton-assembly"; +import {HighLevelSourceMap} from "./high-level-source-map"; let wasmBinary: Uint8Array | undefined = undefined @@ -19,6 +21,22 @@ export type TolkCompilerConfig = { withStackComments?: boolean withSrcLineComments?: boolean experimentalOptions?: string + collectSourceMap?: boolean +} + +/** + * Represents a source map for Tolk code. + */ +export type SourceMap = { + /** + * Maps high-level source code to debug sections in assembly code. + */ + readonly highlevelMapping: HighLevelSourceMap + /** + * Maps code Cells to assembly instructions. + * Each instruction can be mapped to specific debug sections. + */ + readonly assemblyMapping: trace.MappingInfo } export type TolkResultSuccess = { @@ -27,9 +45,24 @@ export type TolkResultSuccess = { codeBoc64: string codeHashHex: string stderr: string + fiftSourceMapCode?: string + sourceMapCodeRecompiledBoc64?: string + sourceMapCodeBoc64?: string + sourceMap?: SourceMap sourcesSnapshot: { filename: string, contents: string }[] } +type TolkCompilerResultSuccess = { + status: "ok" + fiftCode: string + codeBoc64: string + codeHashHex: string + stderr: string + fiftSourceMapCode?: string + sourceMapCodeBoc64?: string + sourceMap?: HighLevelSourceMap +} + export type TolkResultError = { status: "error" message: string @@ -122,6 +155,7 @@ export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promi withStackComments: compilerConfig.withStackComments, withSrcLineComments: compilerConfig.withSrcLineComments, experimentalOptions: compilerConfig.experimentalOptions, + collectSourceMap: compilerConfig.collectSourceMap, }) const configStrPtr = copyToCStringAllocating(mod, configStr) @@ -129,10 +163,78 @@ export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promi const resultPtr = mod._tolk_compile(configStrPtr, callbackPtr) allocatedPointers.push(resultPtr) - const result: TolkResultSuccess | TolkResultError = JSON.parse(copyFromCString(mod, resultPtr)) + const result: TolkCompilerResultSuccess | TolkResultError = JSON.parse(copyFromCString(mod, resultPtr)) allocatedPointers.forEach(ptr => mod._free(ptr)) mod.removeFunction(callbackPtr) - return result.status === 'error' ? result : {...result, sourcesSnapshot} + if (result.status === 'error') { + return result + } + + if (compilerConfig.collectSourceMap) { + // When we compile with a source map enabled, the compiler generates special DEBUGMARK %id + // instructions that describe the start of a code section with a specific ID. + // These instructions, along with the rest of the Fifth code, are compiled into "poisoned" + // bitcode. + // The result of this compilation is stored in the `sourceMapCodeBoc64` field. + // + // The code generated in this way is not runnable, since the DEBUGMARK instruction is + // unknown to TVM, running such code directly will cause TVM to crash. + // + // And this is where the further code comes into play. + // + // Its task is to disassemble bitcode back into instructions, including DEBUGMARK, and + // compile it back into bitcode. + // Thanks to DEBUGMARK instructions, upon recompilation, TASM can map of each instruction + // and the debug section, thus getting a complete source code map that is accurately down + // to the specific TVM instruction. + + const sourceMapCodeCell = Cell.fromBoc(Buffer.from(result.sourceMapCodeBoc64 ?? result.codeBoc64, "base64"))[0] + const [cleanCell, mapping] = recompileCell(sourceMapCodeCell); + const assemblyMapping = trace.createMappingInfo(mapping) + + if (result.sourceMap === undefined) { + console.warn('Source map was not generated. This is probably a bug in Tolk compiler.') + } + + const highlevelMapping: HighLevelSourceMap | undefined = result.sourceMap ? { + ...result.sourceMap, + debugCode64: result.sourceMapCodeBoc64, + } : emptyHighlevelSourceMap + + return { + ...result, + codeBoc64: result.codeBoc64, + sourceMapCodeRecompiledBoc64: cleanCell.toBoc().toString('base64'), + sourceMapCodeBoc64: result.sourceMapCodeBoc64, + sourceMap: { + highlevelMapping, + assemblyMapping, + }, + sourcesSnapshot + } + } + + return {...result, sourcesSnapshot, sourceMap: undefined} } + +function recompileCell(cell: Cell): [Cell, runtime.Mapping] { + const instructions = runtime.decompileCell(cell); + const assembly = text.print(instructions); + + const parseResult = text.parse("out.tasm", assembly); + if (parseResult.$ === "ParseFailure") { + throw new Error("Cannot parse resulting text Assembly"); + } + + return runtime.compileCellWithMapping(parseResult.instructions, {skipRefs: true}); +} + +const emptyHighlevelSourceMap = { + version: "0", + files: [], + globals: [], + locations: [], + debugCode64: "", +}; diff --git a/tests/__snapshots__/source-maps.spec.ts.snap b/tests/__snapshots__/source-maps.spec.ts.snap new file mode 100644 index 0000000..b9ed7b6 --- /dev/null +++ b/tests/__snapshots__/source-maps.spec.ts.snap @@ -0,0 +1,295 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`source-maps should generate correct source map for lazy match 1`] = ` +" + 1 | struct (0x1) Single { + 2 | x: int32 + 3 | } + 4 | + 5 | struct (0x2) Pair { + 6 | x: int32 + 7 | y: int32 + 8 | } + 9 | + 10 | type Data = Single | Pair + 11 | + 12 | fun <#0>main(data: slice) { + 13 | <#1>val thing = <#6>lazy Data<#2>.fromSlice(data); + 14 | + 15 | match (thing) { + 16 | <#7>Single => { + 17 | <#8>throw thing.x; + 18 | } + 19 | <#9>Pair => { + 20 | <#11>throw thing.x <#10>+ thing.y; + 21 | } + 22 | else => { + 23 | <#13>return <#12>10; + 24 | } + 25 | } + 26 | } + +Cell 1821d664...: + 0: SETCP + 16: DICTPUSHCONST + 40: DICTIGETJMPZ + 56: THROWARG + 56: RET + +Cell 259edd3f...: + 0: SDBEGINSQ [#0,#1,#2,#3,#4,#5,#6,#7] + 32: PUSHCONT_SHORT + 40: PLDI + 64: THROWANY [#8] + 64: RET + 80: IFJMP + 88: SDBEGINSQ [#9] + 120: PUSHCONT + 136: LDI + 152: PLDI + 176: ADD [#10] + 184: THROWANY [#11] + 184: RET + 200: IFJMP + 208: DROP [#12] + 216: PUSHINT_4 + 216: RET [#13] + +" +`; + +exports[`source-maps should generate correct source map for simple function 1`] = ` +" + 1 | fun <#0>main(a: int) { + 2 | <#1>var x = a <#3>+ <#2>1; + 3 | <#6>return <#5>max(x, <#4>10); + 4 | } + +Cell 808c59db...: + 0: SETCP + 16: DICTPUSHCONST + 40: DICTIGETJMPZ + 56: THROWARG + 56: RET + +Cell 71e0ec90...: + 0: INC [#0,#1,#2,#3] + 8: PUSHINT_4 [#4] + 16: MAX [#5] + 16: RET [#6] + +" +`; + +exports[`source-maps should generate source map 1`] = ` +{ + "assemblyMapping": { + "cells": { + "8bea7604d0b072b209c4e479a40999439f4f67f574f4a47691381dda9451d308": { + "instructions": [ + { + "debugSections": [ + 0, + 1, + ], + "loc": { + "file": "out.tasm", + "line": 5, + "otherLines": [], + }, + "name": "PUSHINT_4", + "offset": 0, + }, + { + "debugSections": [ + 2, + ], + "loc": { + "file": "out.tasm", + "line": 7, + "otherLines": [], + }, + "name": "MAX", + "offset": 8, + }, + { + "debugSections": [ + 3, + ], + "loc": { + "file": "out.tasm", + "line": 7, + "otherLines": [], + }, + "name": "RET", + "offset": 8, + }, + ], + }, + "fd8692835670899ef97044b0a2d78da8c72156229c1f48102feed7753ceadef0": { + "instructions": [ + { + "debugSections": [], + "loc": { + "file": "out.tasm", + "line": 0, + "otherLines": [], + }, + "name": "SETCP", + "offset": 0, + }, + { + "debugSections": [], + "loc": { + "file": "out.tasm", + "line": 1, + "otherLines": [], + }, + "name": "DICTPUSHCONST", + "offset": 16, + }, + { + "debugSections": [], + "loc": { + "file": "out.tasm", + "line": 11, + "otherLines": [], + }, + "name": "DICTIGETJMPZ", + "offset": 40, + }, + { + "debugSections": [], + "loc": { + "file": "out.tasm", + "line": 12, + "otherLines": [], + }, + "name": "THROWARG", + "offset": 56, + }, + { + "debugSections": [], + "loc": { + "file": "out.tasm", + "line": 12, + "otherLines": [], + }, + "name": "RET", + "offset": 56, + }, + ], + }, + }, + "dictionaryCells": [ + { + "cell": "a9e0df6bc8c41cca2abd6f8bbc8de4da6a520b743348e40b468cce4d251a674a", + "dataCell": "8bea7604d0b072b209c4e479a40999439f4f67f574f4a47691381dda9451d308", + "offset": 8, + }, + ], + }, + "highlevelMapping": { + "debugCode64": "te6ccgEBAgEAIwABFP8A9KQT9LzyyAsBACjT+VUAAPlVAAF6+VUAArYJ+VUAAw==", + "files": [], + "globals": [], + "locations": [ + { + "context": { + "ast_kind": "ast_function_declaration", + "func_inline_mode": 0, + "func_name": "main", + "is_entry": true, + }, + "debug": undefined, + "idx": 0, + "loc": { + "col": 4, + "file": "wallet-code.tolk", + "length": 1, + "line": 1, + "line_offset": 0, + }, + "vars": [ + { + "name": "a", + "type": "int", + }, + ], + }, + { + "context": { + "ast_kind": "ast_int_const", + "func_inline_mode": 0, + "func_name": "main", + }, + "debug": undefined, + "idx": 1, + "loc": { + "col": 18, + "file": "wallet-code.tolk", + "length": 1, + "line": 2, + "line_offset": 0, + }, + "vars": [ + { + "name": "a", + "type": "int", + }, + ], + }, + { + "context": { + "ast_kind": "ast_function_call", + "func_inline_mode": 0, + "func_name": "main", + }, + "debug": undefined, + "idx": 2, + "loc": { + "col": 11, + "file": "wallet-code.tolk", + "length": 1, + "line": 2, + "line_offset": 0, + }, + "vars": [ + { + "name": "a", + "type": "int", + }, + { + "constant_value": "10", + "name": "'1", + "type": "int", + }, + ], + }, + { + "context": { + "ast_kind": "ast_return_statement", + "func_inline_mode": 0, + "func_name": "main", + }, + "debug": undefined, + "idx": 3, + "loc": { + "col": 4, + "file": "wallet-code.tolk", + "length": 1, + "line": 2, + "line_offset": 1, + }, + "vars": [ + { + "name": "'2", + "type": "int", + }, + ], + }, + ], + "version": "1", + }, +} +`; diff --git a/tests/source-maps.spec.ts b/tests/source-maps.spec.ts new file mode 100644 index 0000000..96d87c5 --- /dev/null +++ b/tests/source-maps.spec.ts @@ -0,0 +1,142 @@ +import {runTolkCompiler, SourceMap} from "../src"; +import {HighLevelSourceMapEntry} from "../src/high-level-source-map"; + +describe('source-maps', () => { + it('should generate source map', async () => { + const file = `fun main(a: int) { + return max(a, 10); +}` + + const result = await runTolkCompiler({ + entrypointFileName: "wallet-code.tolk", + fsReadCallback: () => file, + collectSourceMap: true, + }) + if (result.status !== 'ok') { + throw result.message + } + + if (result.sourceMap?.highlevelMapping) { + const sourceMap = { + ...result.sourceMap, + highlevelMapping: { + ...result.sourceMap.highlevelMapping, + files: [], + locations: result.sourceMap.highlevelMapping.locations.map(it => ({ + ...it, + debug: undefined + })) + } + } + expect(sourceMap).toMatchSnapshot() + } + }); + + it('should generate correct source map for simple function', async () => { + const file = `fun main(a: int) { + var x = a + 1; + return max(x, 10); +}` + await doTest(file); + }); + + it('should generate correct source map for lazy match', async () => { + const file = `struct (0x1) Single { + x: int32 +} + +struct (0x2) Pair { + x: int32 + y: int32 +} + +type Data = Single | Pair + +fun main(data: slice) { + val thing = lazy Data.fromSlice(data); + + match (thing) { + Single => { + throw thing.x; + } + Pair => { + throw thing.x + thing.y; + } + else => { + return 10; + } + } +}` + await doTest(file); + }); + + + async function doTest(file: string) { + const result = await runTolkCompiler({ + entrypointFileName: "test.tolk", + fsReadCallback: () => file, + collectSourceMap: true, + withStackComments: true, + }) + if (result.status !== 'ok') { + throw result.message + } + + expect(result.sourceMap).toBeDefined() + const visualization = visualizeMappings(result.sourceMap!, file) + expect(visualization).toMatchSnapshot() + } +}) + +function visualizeMappings(sourceMap: SourceMap, sourceCode: string): string { + const {highlevelMapping, assemblyMapping} = sourceMap + let result = '' + + result += "\n" + + const lines = sourceCode.split('\n') + const locationsByLine = new Map() + + for (const location of highlevelMapping.locations) { + if (!locationsByLine.has(location.loc.line)) { + locationsByLine.set(location.loc.line, []) + } + locationsByLine.get(location.loc.line)!.push(location) + } + + for (let i = 0; i < lines.length; i++) { + const lineNum = i + 1 + const line = lines[i] + const lineLocations = locationsByLine.get(lineNum) || [] + + lineLocations.sort((a, b) => a.loc.col - b.loc.col) + + let modifiedLine = line + let offset = 0 + + for (const location of lineLocations) { + const marker = `<#${location.idx}>` + const insertPos = location.loc.col + offset + modifiedLine = modifiedLine.slice(0, insertPos) + marker + modifiedLine.slice(insertPos) + offset += marker.length + } + + result += `${lineNum.toString().padStart(3)} | ${modifiedLine}\n` + } + + result += "\n" + + for (const [cellHash, cell] of Object.entries(assemblyMapping.cells)) { + if (!cell) continue + result += `Cell ${cellHash.slice(0, 8)}...:\n` + for (const instruction of cell.instructions) { + const debugStr = instruction.debugSections.length > 0 + ? ` [${instruction.debugSections.map(it => `#${it}`).join(',')}]` + : '' + result += ` ${instruction.offset.toString().padStart(3)}: ${instruction.name}${debugStr}\n` + } + result += '\n' + } + + return result +} diff --git a/tsconfig.json b/tsconfig.json index 26feb07..1749651 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,7 @@ "skipLibCheck": true, }, "include": [ - "src/**/*" + "src/**/*", + "tests/**/*", ] -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index d8316e3..030665b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -536,6 +536,13 @@ dependencies: symbol.inspect "1.0.1" +"@ton/core@^0.60.1": + version "0.60.1" + resolved "https://registry.yarnpkg.com/@ton/core/-/core-0.60.1.tgz#cc9a62fb308d7597b1217dc8e44c7e2dcc0aceaa" + integrity sha512-8FwybYbfkk57C3l9gvnlRhRBHbLYmeu0LbB1z9N+dhDz0Z+FJW8w0TJlks8CgHrAFxsT3FlR2LsqFnsauMp38w== + dependencies: + symbol.inspect "1.0.1" + "@ton/crypto-primitives@2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@ton/crypto-primitives/-/crypto-primitives-2.1.0.tgz#8c9277c250b59aae3c819e0d6bd61e44d998e9ca" @@ -552,6 +559,11 @@ jssha "3.2.0" tweetnacl "1.0.3" +"@tonstudio/parser-runtime@^0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@tonstudio/parser-runtime/-/parser-runtime-0.0.1.tgz#469955fb7ea354d4fadaa5964359b11fd17f926b" + integrity sha512-5s4fLkXWxa4SAd7QGGvJXe13GakEo0J3VF5dUI/i3A//bGZxMwCp1FcnbErpNs3y0LcAZoXE5FCUnDowDQptqw== + "@types/babel__core@^7.1.14": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" @@ -815,6 +827,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2109,6 +2126,14 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +"ton-assembly@file:../tasm-new/ton-assembly-0.3.0.tgz": + version "0.3.0" + resolved "file:../tasm-new/ton-assembly-0.3.0.tgz#18db59d61da2053e3b9ec38d97f9fc52d3d332f3" + dependencies: + "@ton/core" "^0.60.1" + "@tonstudio/parser-runtime" "^0.0.1" + cac "^6.7.14" + ts-jest@^29.2.4: version "29.2.4" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.4.tgz#38ccf487407d7a63054a72689f6f99b075e296e5" From ec9c5d2d28d81f5eb880360f8fd3f6ba6bc18a9c Mon Sep 17 00:00:00 2001 From: i582 <51853996+i582@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:10:00 +0400 Subject: [PATCH 2/6] fix tests --- tests/__snapshots__/source-maps.spec.ts.snap | 112 ++++++++++++++----- 1 file changed, 82 insertions(+), 30 deletions(-) diff --git a/tests/__snapshots__/source-maps.spec.ts.snap b/tests/__snapshots__/source-maps.spec.ts.snap index b9ed7b6..e088499 100644 --- a/tests/__snapshots__/source-maps.spec.ts.snap +++ b/tests/__snapshots__/source-maps.spec.ts.snap @@ -13,18 +13,18 @@ exports[`source-maps should generate correct source map for lazy match 1`] = ` 9 | 10 | type Data = Single | Pair 11 | - 12 | fun <#0>main(data: slice) { - 13 | <#1>val thing = <#6>lazy Data<#2>.fromSlice(data); + 12 | fun <#3>main(data: slice) { + 13 | <#4>val thing = <#9>lazy Data<#5>.fromSlice(data); 14 | 15 | match (thing) { - 16 | <#7>Single => { - 17 | <#8>throw thing.x; + 16 | <#10>Single => { + 17 | <#11>throw thing.x; 18 | } - 19 | <#9>Pair => { - 20 | <#11>throw thing.x <#10>+ thing.y; + 19 | <#12>Pair => { + 20 | <#14>throw thing.x <#13>+ thing.y; 21 | } 22 | else => { - 23 | <#13>return <#12>10; + 23 | <#16>return <#15>10; 24 | } 25 | } 26 | } @@ -37,32 +37,32 @@ Cell 1821d664...: 56: RET Cell 259edd3f...: - 0: SDBEGINSQ [#0,#1,#2,#3,#4,#5,#6,#7] + 0: SDBEGINSQ [#3,#4,#5,#6,#7,#8,#9,#10] 32: PUSHCONT_SHORT 40: PLDI - 64: THROWANY [#8] + 64: THROWANY [#11] 64: RET 80: IFJMP - 88: SDBEGINSQ [#9] + 88: SDBEGINSQ [#12] 120: PUSHCONT 136: LDI 152: PLDI - 176: ADD [#10] - 184: THROWANY [#11] + 176: ADD [#13] + 184: THROWANY [#14] 184: RET 200: IFJMP - 208: DROP [#12] + 208: DROP [#15] 216: PUSHINT_4 - 216: RET [#13] + 216: RET [#16] " `; exports[`source-maps should generate correct source map for simple function 1`] = ` " - 1 | fun <#0>main(a: int) { - 2 | <#1>var x = a <#3>+ <#2>1; - 3 | <#6>return <#5>max(x, <#4>10); + 1 | fun <#3>main(a: int) { + 2 | <#4>var x = a <#6>+ <#5>1; + 3 | <#9>return <#8>max(x, <#7>10); 4 | } Cell 808c59db...: @@ -73,10 +73,10 @@ Cell 808c59db...: 56: RET Cell 71e0ec90...: - 0: INC [#0,#1,#2,#3] - 8: PUSHINT_4 [#4] - 16: MAX [#5] - 16: RET [#6] + 0: INC [#3,#4,#5,#6] + 8: PUSHINT_4 [#7] + 16: MAX [#8] + 16: RET [#9] " `; @@ -89,8 +89,8 @@ exports[`source-maps should generate source map 1`] = ` "instructions": [ { "debugSections": [ - 0, - 1, + 3, + 4, ], "loc": { "file": "out.tasm", @@ -102,7 +102,7 @@ exports[`source-maps should generate source map 1`] = ` }, { "debugSections": [ - 2, + 5, ], "loc": { "file": "out.tasm", @@ -114,7 +114,7 @@ exports[`source-maps should generate source map 1`] = ` }, { "debugSections": [ - 3, + 6, ], "loc": { "file": "out.tasm", @@ -190,7 +190,7 @@ exports[`source-maps should generate source map 1`] = ` ], }, "highlevelMapping": { - "debugCode64": "te6ccgEBAgEAIwABFP8A9KQT9LzyyAsBACjT+VUAAPlVAAF6+VUAArYJ+VUAAw==", + "debugCode64": "te6ccgEBAgEAIwABFP8A9KQT9LzyyAsBACjT+VUAA/lVAAR6+VUABbYJ+VUABg==", "files": [], "globals": [], "locations": [ @@ -198,11 +198,63 @@ exports[`source-maps should generate source map 1`] = ` "context": { "ast_kind": "ast_function_declaration", "func_inline_mode": 0, - "func_name": "main", + "func_name": "MapLookupResult.loadValue", "is_entry": true, }, "debug": undefined, "idx": 0, + "loc": { + "col": 27, + "file": "@stdlib/common.tolk", + "length": 1, + "line": 927, + "line_offset": 0, + }, + "vars": [], + }, + { + "context": { + "ast_kind": "ast_not_null_operator", + "func_inline_mode": 0, + "func_name": "MapLookupResult.loadValue", + }, + "debug": undefined, + "idx": 1, + "loc": { + "col": 15, + "file": "@stdlib/common.tolk", + "length": 1, + "line": 928, + "line_offset": 0, + }, + "vars": [], + }, + { + "context": { + "ast_kind": "ast_return_statement", + "func_inline_mode": 0, + "func_name": "MapLookupResult.loadValue", + }, + "debug": undefined, + "idx": 2, + "loc": { + "col": 4, + "file": "@stdlib/common.tolk", + "length": 1, + "line": 928, + "line_offset": 1, + }, + "vars": [], + }, + { + "context": { + "ast_kind": "ast_function_declaration", + "func_inline_mode": 0, + "func_name": "main", + "is_entry": true, + }, + "debug": undefined, + "idx": 3, "loc": { "col": 4, "file": "wallet-code.tolk", @@ -224,7 +276,7 @@ exports[`source-maps should generate source map 1`] = ` "func_name": "main", }, "debug": undefined, - "idx": 1, + "idx": 4, "loc": { "col": 18, "file": "wallet-code.tolk", @@ -246,7 +298,7 @@ exports[`source-maps should generate source map 1`] = ` "func_name": "main", }, "debug": undefined, - "idx": 2, + "idx": 5, "loc": { "col": 11, "file": "wallet-code.tolk", @@ -273,7 +325,7 @@ exports[`source-maps should generate source map 1`] = ` "func_name": "main", }, "debug": undefined, - "idx": 3, + "idx": 6, "loc": { "col": 4, "file": "wallet-code.tolk", From 37f9a172fda7218aa88296fe0aca9f14020138a5 Mon Sep 17 00:00:00 2001 From: i582 <51853996+i582@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:21:21 +0400 Subject: [PATCH 3/6] use ton-assembly package --- package.json | 2 +- yarn.lock | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9c3df9c..ac2fba3 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@ton/crypto": "^3.3.0", "@types/jest": "^29.5.12", "jest": "^29.7.0", - "ton-assembly": "/Users/petrmakhnev/tasm-new/ton-assembly-0.3.0.tgz", + "ton-assembly": "0.3.0", "ts-jest": "^29.2.4", "typescript": "^5.5.4" }, diff --git a/yarn.lock b/yarn.lock index 030665b..32270a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2126,9 +2126,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -"ton-assembly@file:../tasm-new/ton-assembly-0.3.0.tgz": +ton-assembly@0.3.0: version "0.3.0" - resolved "file:../tasm-new/ton-assembly-0.3.0.tgz#18db59d61da2053e3b9ec38d97f9fc52d3d332f3" + resolved "https://registry.yarnpkg.com/ton-assembly/-/ton-assembly-0.3.0.tgz#18db59d61da2053e3b9ec38d97f9fc52d3d332f3" + integrity sha512-BgHJlmmB0fztmma2KgkSNyWbCY6CvNx7mpxnWvzxglmJYq1rlC7+yC7DzGrT+jiOAHvxOTG2OyOkAUCX6A85mQ== dependencies: "@ton/core" "^0.60.1" "@tonstudio/parser-runtime" "^0.0.1" From db104da788610bec24cbecf6d625c10c71a900d7 Mon Sep 17 00:00:00 2001 From: i582 <51853996+i582@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:14:09 +0400 Subject: [PATCH 4/6] use ton-source-map package, add prettier --- package.json | 37 +++++++++++++++--- src/high-level-source-map.ts | 72 ------------------------------------ src/index.ts | 35 ++++-------------- tsconfig.json | 3 +- yarn.lock | 34 +++++++++-------- 5 files changed, 58 insertions(+), 123 deletions(-) delete mode 100644 src/high-level-source-map.ts diff --git a/package.json b/package.json index ac2fba3..f4dfc79 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ton/tolk-js", - "version": "1.1.0", + "version": "1.1.6", "description": "Tolk Language compiler (next-generation FunC)", "main": "dist/index.js", "bin": "./dist/cli.js", @@ -13,7 +13,9 @@ "stdlib:pack": "node scripts/pack-stdlib-to-object.js", "wasm:dist": "cp src/tolkfiftlib.js dist && cp src/tolkfiftlib.wasm.js dist", "stdlib:dist": "cp -r src/tolk-stdlib dist && cp src/stdlib.tolk.js dist", - "test": "yarn wasm:pack && yarn stdlib:pack && yarn jest" + "test": "yarn wasm:pack && yarn stdlib:pack && yarn jest", + "fmt": "prettier --write -l --cache .", + "fmt:check": "prettier --check --cache ." }, "author": "TON Blockchain", "license": "MIT", @@ -22,15 +24,38 @@ "url": "git+https://github.com/ton-blockchain/tolk-js.git" }, "devDependencies": { - "@ton/core": "^0.56.3", + "@ton/core": "^0.61.0", "@ton/crypto": "^3.3.0", "@types/jest": "^29.5.12", "jest": "^29.7.0", - "ton-assembly": "0.3.0", "ts-jest": "^29.2.4", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "prettier": "^3.6.2" }, "dependencies": { - "arg": "^5.0.2" + "arg": "^5.0.2", + "ton-source-map": "0.1.0", + "ton-assembly": "0.3.1" + }, + "prettier": { + "arrowParens": "avoid", + "bracketSpacing": false, + "printWidth": 100, + "semi": false, + "tabWidth": 2, + "trailingComma": "all", + "useTabs": false, + "quoteProps": "preserve", + "overrides": [ + { + "files": [ + "*.yaml", + "*.yml" + ], + "options": { + "tabWidth": 2 + } + } + ] } } diff --git a/src/high-level-source-map.ts b/src/high-level-source-map.ts deleted file mode 100644 index a779cdc..0000000 --- a/src/high-level-source-map.ts +++ /dev/null @@ -1,72 +0,0 @@ -enum FunctionInlineMode { - NotCalculated = 0, - InlineViaFif = 1, - InlineRef = 2, - InlineInPlace = 3, - NoInline = 4, -} - -export type HighLevelSourceMapLocation = { - readonly file: string - readonly line: number - readonly col: number - readonly line_offset: number - readonly length: number -} - -export type HighLevelSourceMapEntryContext = { - readonly descr?: string - readonly is_entry?: boolean - readonly ast_kind: string - readonly func_name: string - readonly inlined_to_func?: string - readonly func_inline_mode: FunctionInlineMode - readonly before_inlined_function_call?: boolean - readonly after_inlined_function_call?: boolean -} - -export type HighLevelSourceMapDebugInfo = { - readonly opcode?: string - readonly line_str?: string - readonly line_off?: string -} - -export type HighLevelSourceMapEntry = { - readonly idx: number - readonly loc: HighLevelSourceMapLocation - readonly vars: readonly HighLevelSourceMapVariable[] - readonly context: HighLevelSourceMapEntryContext - readonly debug?: HighLevelSourceMapDebugInfo -} - -export type HighLevelSourceMapVariable = { - readonly name: string - readonly type: string - readonly constant_value?: string - readonly possible_qualifier_types: readonly string[] -} - -export type HighLevelSourceMapGlobalVariable = { - readonly name: string - readonly type: string -} - -export type HighLevelSourceMapFile = { - readonly path: string - readonly is_stdlib: boolean - readonly content: string -} - -/** - * Represents a high-level source map. - * "High-level" in this case means that this source map only contains a mapping from DEBUGMARK ID to - * high-level language code, but it does not contain any further mapping from DEBUGMARK ID to - * specific instructions in bitcode. - */ -export type HighLevelSourceMap = { - readonly version: string - readonly files: readonly HighLevelSourceMapFile[] - readonly globals: readonly HighLevelSourceMapGlobalVariable[] - readonly locations: readonly HighLevelSourceMapEntry[] - readonly debugCode64?: string -} diff --git a/src/index.ts b/src/index.ts index 5fd194e..6762ca3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ import wasmBase64 from "./tolkfiftlib.wasm.js" import stdlibContents from "./stdlib.tolk.js" import {realpath} from "./path-utils" import {Cell, runtime, text, trace} from "ton-assembly"; -import {HighLevelSourceMap} from "./high-level-source-map"; +import {AssemblyMapping, HighLevelMapping, SourceMap} from "ton-source-map" let wasmBinary: Uint8Array | undefined = undefined @@ -24,21 +24,6 @@ export type TolkCompilerConfig = { collectSourceMap?: boolean } -/** - * Represents a source map for Tolk code. - */ -export type SourceMap = { - /** - * Maps high-level source code to debug sections in assembly code. - */ - readonly highlevelMapping: HighLevelSourceMap - /** - * Maps code Cells to assembly instructions. - * Each instruction can be mapped to specific debug sections. - */ - readonly assemblyMapping: trace.MappingInfo -} - export type TolkResultSuccess = { status: "ok" fiftCode: string @@ -60,7 +45,7 @@ type TolkCompilerResultSuccess = { stderr: string fiftSourceMapCode?: string sourceMapCodeBoc64?: string - sourceMap?: HighLevelSourceMap + sourceMap?: HighLevelMapping } export type TolkResultError = { @@ -192,27 +177,22 @@ export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promi const sourceMapCodeCell = Cell.fromBoc(Buffer.from(result.sourceMapCodeBoc64 ?? result.codeBoc64, "base64"))[0] const [cleanCell, mapping] = recompileCell(sourceMapCodeCell); - const assemblyMapping = trace.createMappingInfo(mapping) + const assemblyMapping: AssemblyMapping = trace.createMappingInfo(mapping) if (result.sourceMap === undefined) { console.warn('Source map was not generated. This is probably a bug in Tolk compiler.') } - const highlevelMapping: HighLevelSourceMap | undefined = result.sourceMap ? { - ...result.sourceMap, - debugCode64: result.sourceMapCodeBoc64, - } : emptyHighlevelSourceMap - return { ...result, codeBoc64: result.codeBoc64, sourceMapCodeRecompiledBoc64: cleanCell.toBoc().toString('base64'), sourceMapCodeBoc64: result.sourceMapCodeBoc64, sourceMap: { - highlevelMapping, + highlevelMapping: result.sourceMap ?? emptyHighlevelMapping, assemblyMapping, }, - sourcesSnapshot + sourcesSnapshot, } } @@ -231,10 +211,11 @@ function recompileCell(cell: Cell): [Cell, runtime.Mapping] { return runtime.compileCellWithMapping(parseResult.instructions, {skipRefs: true}); } -const emptyHighlevelSourceMap = { +const emptyHighlevelMapping: HighLevelMapping = { version: "0", + language: "tolk", + compiler_version: "", files: [], globals: [], locations: [], - debugCode64: "", }; diff --git a/tsconfig.json b/tsconfig.json index 1749651..6d83659 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,6 @@ "skipLibCheck": true, }, "include": [ - "src/**/*", - "tests/**/*", + "src/**/*" ] } diff --git a/yarn.lock b/yarn.lock index 32270a5..9f5f6cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -529,17 +529,10 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@ton/core@^0.56.3": - version "0.56.3" - resolved "https://registry.yarnpkg.com/@ton/core/-/core-0.56.3.tgz#1162764573abb76032eba70f8497e5cb2ea532ee" - integrity sha512-HVkalfqw8zqLLPehtq0CNhu5KjVzc7IrbDwDHPjGoOSXmnqSobiWj8a5F+YuWnZnEbQKtrnMGNOOjVw4LG37rg== - dependencies: - symbol.inspect "1.0.1" - -"@ton/core@^0.60.1": - version "0.60.1" - resolved "https://registry.yarnpkg.com/@ton/core/-/core-0.60.1.tgz#cc9a62fb308d7597b1217dc8e44c7e2dcc0aceaa" - integrity sha512-8FwybYbfkk57C3l9gvnlRhRBHbLYmeu0LbB1z9N+dhDz0Z+FJW8w0TJlks8CgHrAFxsT3FlR2LsqFnsauMp38w== +"@ton/core@^0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@ton/core/-/core-0.61.0.tgz#09b37801cb2f5a942020fcc992be1e99f4b16689" + integrity sha512-0qyVfP2dDue2bq80ydXggo2MlufcmzuFk6G94qRrZxvyQ3NSe4UeBTeRf1gQmN7tywgTsX2gS61e4yvJrlUu4Q== dependencies: symbol.inspect "1.0.1" @@ -1910,6 +1903,11 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +prettier@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" + integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== + pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" @@ -2126,15 +2124,19 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -ton-assembly@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/ton-assembly/-/ton-assembly-0.3.0.tgz#18db59d61da2053e3b9ec38d97f9fc52d3d332f3" - integrity sha512-BgHJlmmB0fztmma2KgkSNyWbCY6CvNx7mpxnWvzxglmJYq1rlC7+yC7DzGrT+jiOAHvxOTG2OyOkAUCX6A85mQ== +ton-assembly@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/ton-assembly/-/ton-assembly-0.3.1.tgz#be5d9c75ed36e4297b5956e72da5f9c15fff8468" + integrity sha512-AEbjnN4Osy+gqoNuNaY8YfUTTsyhbtr8Q8UexHL5M1FT45SzsXTer9UDakFo8tyoq3Uddfgy6d46AHUEGd8mvw== dependencies: - "@ton/core" "^0.60.1" "@tonstudio/parser-runtime" "^0.0.1" cac "^6.7.14" +ton-source-map@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ton-source-map/-/ton-source-map-0.1.0.tgz#ad53847c9776f1f417f28158dc814f58ac7ff0e1" + integrity sha512-88y+DUhjnERBpFif3Aza0J5RkjQLer2jvXChb5cBxNKfS65YkgBkj+xrv41YCRwoze9ZJXJPR6SDo4ROA9854w== + ts-jest@^29.2.4: version "29.2.4" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.4.tgz#38ccf487407d7a63054a72689f6f99b075e296e5" From 9d0cca555095f333efddf07d97b33137ecbacb93 Mon Sep 17 00:00:00 2001 From: i582 <51853996+i582@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:18:00 +0400 Subject: [PATCH 5/6] fix tests --- package.json | 2 +- tests/__snapshots__/source-maps.spec.ts.snap | 3 ++- tests/source-maps.spec.ts | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index f4dfc79..2b625f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ton/tolk-js", - "version": "1.1.6", + "version": "1.1.0", "description": "Tolk Language compiler (next-generation FunC)", "main": "dist/index.js", "bin": "./dist/cli.js", diff --git a/tests/__snapshots__/source-maps.spec.ts.snap b/tests/__snapshots__/source-maps.spec.ts.snap index e088499..febc660 100644 --- a/tests/__snapshots__/source-maps.spec.ts.snap +++ b/tests/__snapshots__/source-maps.spec.ts.snap @@ -190,9 +190,10 @@ exports[`source-maps should generate source map 1`] = ` ], }, "highlevelMapping": { - "debugCode64": "te6ccgEBAgEAIwABFP8A9KQT9LzyyAsBACjT+VUAA/lVAAR6+VUABbYJ+VUABg==", + "compiler_version": "1.1.0", "files": [], "globals": [], + "language": "tolk", "locations": [ { "context": { diff --git a/tests/source-maps.spec.ts b/tests/source-maps.spec.ts index 96d87c5..2613470 100644 --- a/tests/source-maps.spec.ts +++ b/tests/source-maps.spec.ts @@ -1,5 +1,5 @@ -import {runTolkCompiler, SourceMap} from "../src"; -import {HighLevelSourceMapEntry} from "../src/high-level-source-map"; +import {runTolkCompiler} from "../src"; +import {HighLevelSourceMapEntry, SourceMap} from "ton-source-map" describe('source-maps', () => { it('should generate source map', async () => { From f122609e45b0acc0e48fa288015663e897ed4604 Mon Sep 17 00:00:00 2001 From: i582 <51853996+i582@users.noreply.github.com> Date: Tue, 23 Sep 2025 21:06:08 +0400 Subject: [PATCH 6/6] set recompiledCode field in SourceMap + update tests --- package.json | 2 +- src/index.ts | 3 +- tests/__snapshots__/source-maps.spec.ts.snap | 142 ++++++++++++------- tests/source-maps.spec.ts | 8 +- yarn.lock | 8 +- 5 files changed, 101 insertions(+), 62 deletions(-) diff --git a/package.json b/package.json index 2b625f6..2d43ac4 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "arg": "^5.0.2", - "ton-source-map": "0.1.0", + "ton-source-map": "0.2.1", "ton-assembly": "0.3.1" }, "prettier": { diff --git a/src/index.ts b/src/index.ts index 6762ca3..db97fc1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -175,7 +175,7 @@ export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promi // and the debug section, thus getting a complete source code map that is accurately down // to the specific TVM instruction. - const sourceMapCodeCell = Cell.fromBoc(Buffer.from(result.sourceMapCodeBoc64 ?? result.codeBoc64, "base64"))[0] + const sourceMapCodeCell = Cell.fromBase64(result.sourceMapCodeBoc64 ?? result.codeBoc64) const [cleanCell, mapping] = recompileCell(sourceMapCodeCell); const assemblyMapping: AssemblyMapping = trace.createMappingInfo(mapping) @@ -191,6 +191,7 @@ export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promi sourceMap: { highlevelMapping: result.sourceMap ?? emptyHighlevelMapping, assemblyMapping, + recompiledCode: cleanCell.toBoc().toString('base64'), }, sourcesSnapshot, } diff --git a/tests/__snapshots__/source-maps.spec.ts.snap b/tests/__snapshots__/source-maps.spec.ts.snap index febc660..df227f5 100644 --- a/tests/__snapshots__/source-maps.spec.ts.snap +++ b/tests/__snapshots__/source-maps.spec.ts.snap @@ -197,73 +197,94 @@ exports[`source-maps should generate source map 1`] = ` "locations": [ { "context": { - "ast_kind": "ast_function_declaration", - "func_inline_mode": 0, - "func_name": "MapLookupResult.loadValue", - "is_entry": true, + "containing_function": "MapLookupResult.loadValue", + "description": { + "ast_kind": "ast_function_declaration", + }, + "event": "EnterFunction", + "inlining": { + "containing_func_inline_mode": 0, + }, }, "debug": undefined, "idx": 0, "loc": { - "col": 27, + "column": 26, + "end_column": 0, + "end_line": 0, "file": "@stdlib/common.tolk", "length": 1, - "line": 927, - "line_offset": 0, + "line": 926, }, - "vars": [], + "variables": [], }, { "context": { - "ast_kind": "ast_not_null_operator", - "func_inline_mode": 0, - "func_name": "MapLookupResult.loadValue", + "containing_function": "MapLookupResult.loadValue", + "description": { + "ast_kind": "ast_not_null_operator", + }, + "inlining": { + "containing_func_inline_mode": 0, + }, }, "debug": undefined, "idx": 1, "loc": { - "col": 15, + "column": 14, + "end_column": 0, + "end_line": 0, "file": "@stdlib/common.tolk", "length": 1, - "line": 928, - "line_offset": 0, + "line": 927, }, - "vars": [], + "variables": [], }, { "context": { - "ast_kind": "ast_return_statement", - "func_inline_mode": 0, - "func_name": "MapLookupResult.loadValue", + "containing_function": "MapLookupResult.loadValue", + "description": { + "ast_kind": "ast_return_statement", + }, + "event": "LeaveFunction", + "inlining": { + "containing_func_inline_mode": 0, + }, }, "debug": undefined, "idx": 2, "loc": { - "col": 4, + "column": 3, + "end_column": 0, + "end_line": 0, "file": "@stdlib/common.tolk", "length": 1, - "line": 928, - "line_offset": 1, + "line": 927, }, - "vars": [], + "variables": [], }, { "context": { - "ast_kind": "ast_function_declaration", - "func_inline_mode": 0, - "func_name": "main", - "is_entry": true, + "containing_function": "main", + "description": { + "ast_kind": "ast_function_declaration", + }, + "event": "EnterFunction", + "inlining": { + "containing_func_inline_mode": 0, + }, }, "debug": undefined, "idx": 3, "loc": { - "col": 4, + "column": 3, + "end_column": 0, + "end_line": 0, "file": "wallet-code.tolk", "length": 1, - "line": 1, - "line_offset": 0, + "line": 0, }, - "vars": [ + "variables": [ { "name": "a", "type": "int", @@ -272,20 +293,25 @@ exports[`source-maps should generate source map 1`] = ` }, { "context": { - "ast_kind": "ast_int_const", - "func_inline_mode": 0, - "func_name": "main", + "containing_function": "main", + "description": { + "ast_kind": "ast_int_const", + }, + "inlining": { + "containing_func_inline_mode": 0, + }, }, "debug": undefined, "idx": 4, "loc": { - "col": 18, + "column": 17, + "end_column": 0, + "end_line": 0, "file": "wallet-code.tolk", "length": 1, - "line": 2, - "line_offset": 0, + "line": 1, }, - "vars": [ + "variables": [ { "name": "a", "type": "int", @@ -294,20 +320,25 @@ exports[`source-maps should generate source map 1`] = ` }, { "context": { - "ast_kind": "ast_function_call", - "func_inline_mode": 0, - "func_name": "main", + "containing_function": "main", + "description": { + "ast_kind": "ast_function_call", + }, + "inlining": { + "containing_func_inline_mode": 0, + }, }, "debug": undefined, "idx": 5, "loc": { - "col": 11, + "column": 10, + "end_column": 0, + "end_line": 0, "file": "wallet-code.tolk", "length": 1, - "line": 2, - "line_offset": 0, + "line": 1, }, - "vars": [ + "variables": [ { "name": "a", "type": "int", @@ -321,20 +352,26 @@ exports[`source-maps should generate source map 1`] = ` }, { "context": { - "ast_kind": "ast_return_statement", - "func_inline_mode": 0, - "func_name": "main", + "containing_function": "main", + "description": { + "ast_kind": "ast_return_statement", + }, + "event": "LeaveFunction", + "inlining": { + "containing_func_inline_mode": 0, + }, }, "debug": undefined, "idx": 6, "loc": { - "col": 4, + "column": 3, + "end_column": 0, + "end_line": 0, "file": "wallet-code.tolk", "length": 1, - "line": 2, - "line_offset": 1, + "line": 1, }, - "vars": [ + "variables": [ { "name": "'2", "type": "int", @@ -342,7 +379,8 @@ exports[`source-maps should generate source map 1`] = ` ], }, ], - "version": "1", + "version": "1.0.0", }, + "recompiledCode": "te6cckEBAgEAEwABFP8A9KQT9LzyyAsBAAjTerYJGThbJA==", } `; diff --git a/tests/source-maps.spec.ts b/tests/source-maps.spec.ts index 2613470..4cb9c52 100644 --- a/tests/source-maps.spec.ts +++ b/tests/source-maps.spec.ts @@ -105,23 +105,23 @@ function visualizeMappings(sourceMap: SourceMap, sourceCode: string): string { } for (let i = 0; i < lines.length; i++) { - const lineNum = i + 1 + const lineNum = i const line = lines[i] const lineLocations = locationsByLine.get(lineNum) || [] - lineLocations.sort((a, b) => a.loc.col - b.loc.col) + lineLocations.sort((a, b) => a.loc.column - b.loc.column) let modifiedLine = line let offset = 0 for (const location of lineLocations) { const marker = `<#${location.idx}>` - const insertPos = location.loc.col + offset + const insertPos = location.loc.column + 1 + offset modifiedLine = modifiedLine.slice(0, insertPos) + marker + modifiedLine.slice(insertPos) offset += marker.length } - result += `${lineNum.toString().padStart(3)} | ${modifiedLine}\n` + result += `${(lineNum + 1).toString().padStart(3)} | ${modifiedLine}\n` } result += "\n" diff --git a/yarn.lock b/yarn.lock index 9f5f6cd..50e3c2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2132,10 +2132,10 @@ ton-assembly@0.3.1: "@tonstudio/parser-runtime" "^0.0.1" cac "^6.7.14" -ton-source-map@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/ton-source-map/-/ton-source-map-0.1.0.tgz#ad53847c9776f1f417f28158dc814f58ac7ff0e1" - integrity sha512-88y+DUhjnERBpFif3Aza0J5RkjQLer2jvXChb5cBxNKfS65YkgBkj+xrv41YCRwoze9ZJXJPR6SDo4ROA9854w== +ton-source-map@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ton-source-map/-/ton-source-map-0.2.1.tgz#76996e09df3f50f8a7d39398e9aab66694d1d84f" + integrity sha512-EeMfdGcHFeBOVa2pxit9RJFUzFM1KwelfxzqqUDURt2h2tcJT0TheOenbcWgpF6FZVLUkSFgysCl1dif2BJ3HA== ts-jest@^29.2.4: version "29.2.4"