Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/tolkfiftlib.js
**/*.md
6 changes: 3 additions & 3 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @type {import('ts-jest').JestConfigWithTsJest} **/
module.exports = {
testEnvironment: "node",
testEnvironment: 'node',
transform: {
"^.+.tsx?$": ["ts-jest",{}],
'^.+.tsx?$': ['ts-jest', {}],
},
};
}
28 changes: 26 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -27,9 +29,31 @@
"@types/jest": "^29.5.12",
"jest": "^29.7.0",
"ts-jest": "^29.2.4",
"typescript": "^5.5.4"
"typescript": "^5.5.4",
"prettier": "^3.6.2"
},
"dependencies": {
"arg": "^5.0.2"
},
"prettier": {
"arrowParens": "avoid",
"bracketSpacing": false,
"printWidth": 100,
"semi": false,
"tabWidth": 2,
"trailingComma": "all",
"useTabs": false,
"singleQuote": true,
"overrides": [
{
"files": [
"*.yaml",
"*.yml"
],
"options": {
"tabWidth": 2
}
}
]
}
}
7 changes: 5 additions & 2 deletions scripts/pack-stdlib-to-object.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ let out = `// stdlib files are stored as strings in order to make it work on web
module.exports = {\n\n`

let fileNames = [
...fs.readdirSync('./src/tolk-stdlib').filter(s => s.endsWith('.tolk')).sort(),
...fs
.readdirSync('./src/tolk-stdlib')
.filter(s => s.endsWith('.tolk'))
.sort(),
]

for (let fileName of fileNames) {
const contents = fs.readFileSync('./src/tolk-stdlib/' + fileName, 'utf-8')
out += `'@stdlib/${fileName}':\`${contents.replace(/`/g, '\\`')}\`,\n\n`
}

out += "};\n"
out += '};\n'
fs.writeFileSync('./src/stdlib.tolk.js', out)

// note, that Asm.fif and similar are embedded into wasm binary,
Expand Down
25 changes: 16 additions & 9 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Options:
}

if (args._.length !== 1) {
throw 'entrypointFileName wasn\'t specified. Run with -h to see help.'
throw "entrypointFileName wasn't specified. Run with -h to see help."
}

console.log(`Compiling using Tolk v${version}`)
Expand All @@ -64,14 +64,21 @@ Options:
}

if (args['--output-json']) {
fs.writeFileSync(args['--output-json'], JSON.stringify({
artifactVersion: 1,
tolkVersion: version,
fiftCode: result.fiftCode,
codeBoc64: result.codeBoc64,
codeHashHex: result.codeHashHex,
sourcesSnapshot: result.sourcesSnapshot,
}, null, 2))
fs.writeFileSync(
args['--output-json'],
JSON.stringify(
{
artifactVersion: 1,
tolkVersion: version,
fiftCode: result.fiftCode,
codeBoc64: result.codeBoc64,
codeHashHex: result.codeHashHex,
sourcesSnapshot: result.sourcesSnapshot,
},
null,
2,
),
)
}

if (args['--output-fift']) {
Expand Down
49 changes: 30 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// @ts-ignore
import wasmModule from "./tolkfiftlib.js"
import wasmModule from './tolkfiftlib.js'
// @ts-ignore
import wasmBase64 from "./tolkfiftlib.wasm.js"
import wasmBase64 from './tolkfiftlib.wasm.js'
// @ts-ignore
import stdlibContents from "./stdlib.tolk.js"
import {realpath} from "./path-utils"
import stdlibContents from './stdlib.tolk.js'
import {realpath} from './path-utils'

let wasmBinary: Uint8Array | undefined = undefined

Expand All @@ -22,16 +22,16 @@ export type TolkCompilerConfig = {
}

export type TolkResultSuccess = {
status: "ok"
status: 'ok'
fiftCode: string
codeBoc64: string
codeHashHex: string
stderr: string
sourcesSnapshot: { filename: string, contents: string }[]
sourcesSnapshot: {filename: string; contents: string}[]
}

export type TolkResultError = {
status: "error"
status: 'error'
message: string
}

Expand All @@ -54,10 +54,12 @@ function copyFromCString(mod: WasmModule, inPtr: any): string {

async function instantiateWasmModule() {
if (wasmBinary === undefined) {
if (typeof Buffer !== 'undefined') { // node.js
if (typeof Buffer !== 'undefined') {
// node.js
wasmBinary = new Uint8Array(Buffer.from(wasmBase64, 'base64'))
} else if (typeof window !== 'undefined') { // browser
const binaryString = atob(wasmBase64) // window.atob() is fast and safe for valid base64 strings
} else if (typeof window !== 'undefined') {
// browser
const binaryString = atob(wasmBase64) // window.atob() is fast and safe for valid base64 strings
wasmBinary = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) {
wasmBinary[i] = binaryString.charCodeAt(i)
Expand All @@ -77,33 +79,41 @@ export async function getTolkCompilerVersion(): Promise<string> {
return result.tolkVersion
}

export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promise<TolkResultSuccess | TolkResultError> {
export async function runTolkCompiler(
compilerConfig: TolkCompilerConfig,
): Promise<TolkResultSuccess | TolkResultError> {
const mod = await instantiateWasmModule()
const allocatedPointers = []
const sourcesSnapshot: TolkResultSuccess['sourcesSnapshot'] = []

// see tolk-wasm.cpp: typedef void (*WasmFsReadCallback)(int, char const*, char**, char**)
const callbackPtr = mod.addFunction(function (kind: number, dataPtr: any, destContents: any, destError: any) {
switch (kind) { // enum ReadCallback::Kind in C++
case 0: // realpath
let relativeFilename = copyFromCString(mod, dataPtr) // from `import` statement, relative to cur file
const callbackPtr = mod.addFunction(function (
kind: number,
dataPtr: any,
destContents: any,
destError: any,
) {
// enum ReadCallback::Kind in C++
switch (kind) {
case 0: // realpath
let relativeFilename = copyFromCString(mod, dataPtr) // from `import` statement, relative to cur file
if (!relativeFilename.endsWith('.tolk')) {
relativeFilename += '.tolk'
}
allocatedPointers.push(copyToCStringPtr(mod, realpath(relativeFilename), destContents))
break
case 1: // read file
case 1: // read file
try {
const filename = copyFromCString(mod, dataPtr) // already normalized (as returned above)
if (filename.startsWith('@stdlib/')) {
if (filename in stdlibContents) {
allocatedPointers.push(copyToCStringPtr(mod, stdlibContents[filename], destContents))
} else {
allocatedPointers.push(copyToCStringPtr(mod, filename + " not found", destError))
allocatedPointers.push(copyToCStringPtr(mod, filename + ' not found', destError))
}
} else {
const contents = compilerConfig.fsReadCallback(filename)
sourcesSnapshot.push({ filename, contents })
sourcesSnapshot.push({filename, contents})
allocatedPointers.push(copyToCStringPtr(mod, contents, destContents))
}
} catch (err: any) {
Expand All @@ -116,7 +126,8 @@ export async function runTolkCompiler(compilerConfig: TolkCompilerConfig): Promi
}
}, 'viiii')

const configStr = JSON.stringify({ // undefined fields won't be present, defaults will be used, see tolk-wasm.cpp
// undefined fields won't be present, defaults will be used, see tolk-wasm.cpp
const configStr = JSON.stringify({
entrypointFileName: compilerConfig.entrypointFileName,
optimizationLevel: compilerConfig.optimizationLevel,
withStackComments: compilerConfig.withStackComments,
Expand Down
3 changes: 2 additions & 1 deletion src/path-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ export function realpath(p: string): string {
let isAbsolute = p.charCodeAt(0) === SLASH
let path = posixNormalize(p, !isAbsolute)

if (isAbsolute) { // posixNormalize() drops leading slash
if (isAbsolute) {
// posixNormalize() drops leading slash
return '/' + path
}
return path.length === 0 ? '.' : path
Expand Down
48 changes: 23 additions & 25 deletions tests/codegen-checks.spec.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,38 @@
import {runTolkCompiler, getTolkCompilerVersion, TolkResultSuccess, TolkResultError} from "../src";
import fs from "fs";
import {runTolkCompiler, getTolkCompilerVersion, TolkResultSuccess, TolkResultError} from '../src'
import fs from 'fs'

const EXPECT_TO_CONTAIN = [
`
`
check1() PROC:<{
NEWC
ENDC
CTOS
HASHSU
}>
`
`,
]

const EXPECT_NOT_TO_CONTAIN = [
'HASHBU',
]
const EXPECT_NOT_TO_CONTAIN = ['HASHBU']

describe('codegen-checks', () => {
let outFiftCode = ''
let outFiftCode = ''

beforeAll(async () => {
let result = (await runTolkCompiler({
entrypointFileName: 'codegen-checks.tolk',
fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8'),
})) as TolkResultSuccess

beforeAll(async () => {
let result = await runTolkCompiler({
entrypointFileName: "codegen-checks.tolk",
fsReadCallback: path => fs.readFileSync(`./tests/contracts/${path}`, 'utf-8')
}) as TolkResultSuccess
expect(result.status).toEqual('ok')
outFiftCode = result.fiftCode
})

expect(result.status).toEqual('ok')
outFiftCode = result.fiftCode
})

it('check contains', () => {
for (let subFift of EXPECT_TO_CONTAIN) {
expect(outFiftCode).toContain(subFift.trim())
}
for (let subFift of EXPECT_NOT_TO_CONTAIN) {
expect(outFiftCode).not.toContain(subFift)
}
})
it('check contains', () => {
for (let subFift of EXPECT_TO_CONTAIN) {
expect(outFiftCode).toContain(subFift.trim())
}
for (let subFift of EXPECT_NOT_TO_CONTAIN) {
expect(outFiftCode).not.toContain(subFift)
}
})
})
2 changes: 1 addition & 1 deletion tests/realpath.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {realpath} from "../src/path-utils";
import {realpath} from '../src/path-utils'

describe('realpath', () => {
it('should not change already normalized', () => {
Expand Down
Loading