77 lines
2.7 KiB
JavaScript
77 lines
2.7 KiB
JavaScript
// Shared utilities for Magic WASM TCL-variant examples.
|
|
//
|
|
// Loads the TCL-enabled WASM variant. Scripts use magic:: prefixed commands;
|
|
// runScript() evaluates them through the Tcl interpreter via Tcl_EvalFile.
|
|
import createMagicModule from '../tcl/magic.js';
|
|
import { readFileSync } from 'node:fs';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { dirname, resolve, basename } from 'node:path';
|
|
|
|
export const EXAMPLES_DIR = dirname(fileURLToPath(import.meta.url));
|
|
export const wasmBinary = readFileSync(resolve(EXAMPLES_DIR, '../tcl/magic.wasm'));
|
|
export const DEFAULT_TECH = 'scmos';
|
|
export const DEFAULT_MAG = resolve(EXAMPLES_DIR, 'min.mag');
|
|
export const DEFAULT_OUT = resolve(EXAMPLES_DIR, 'output-tcl');
|
|
|
|
export { basename };
|
|
|
|
export function vfsWrite(FS, vfsPath, source) {
|
|
const dir = vfsPath.substring(0, vfsPath.lastIndexOf('/'));
|
|
if (dir) FS.mkdirTree(dir);
|
|
FS.writeFile(vfsPath, typeof source === 'string' ? readFileSync(source) : source);
|
|
}
|
|
|
|
export function vfsRead(FS, vfsPath) {
|
|
try { return Buffer.from(FS.readFile(vfsPath)); } catch { return null; }
|
|
}
|
|
|
|
export class MagicWasm {
|
|
constructor(mod) {
|
|
this._init = mod.cwrap('magic_wasm_init', 'number', []);
|
|
this._run = mod.cwrap('magic_wasm_run_command', 'number', ['string']);
|
|
this._sourceFile = mod.cwrap('magic_wasm_source_file', 'number', ['string']);
|
|
this.FS = mod.FS;
|
|
}
|
|
init() {
|
|
const rc = this._init();
|
|
if (rc !== 0) throw new Error(`magic_wasm_init failed with code ${rc}`);
|
|
}
|
|
// Evaluate a Tcl script (with magic:: prefixed commands) through the
|
|
// Tcl interpreter. Writes the script to VFS then calls magic_wasm_source_file,
|
|
// which in TCL mode uses Tcl_EvalFile.
|
|
runScript(text) {
|
|
const path = '/tmp/_magic_script.tcl';
|
|
this.FS.mkdirTree('/tmp');
|
|
this.FS.writeFile(path, text);
|
|
this._sourceFile(path);
|
|
}
|
|
// Evaluate a Tcl expression directly (needed for proc definitions in PCell).
|
|
runTcl(text) {
|
|
this._run(text);
|
|
}
|
|
}
|
|
|
|
export async function createMagic({ onPrint, onPrintErr } = {}) {
|
|
const lines = [];
|
|
const mod = await createMagicModule({
|
|
wasmBinary,
|
|
print: onPrint ?? (msg => { lines.push(msg); console.log('[magic-tcl]', msg); }),
|
|
printErr: onPrintErr ?? (msg => { lines.push(msg); console.error('[magic-tcl]', msg); }),
|
|
});
|
|
const magic = new MagicWasm(mod);
|
|
magic.init();
|
|
return { magic, lines };
|
|
}
|
|
|
|
export function loadCell(FS, tech, magFile) {
|
|
const cell = basename(magFile, '.mag');
|
|
vfsWrite(FS, `/work/${cell}.mag`, magFile);
|
|
return { tech, cell };
|
|
}
|
|
|
|
export function loadScript(name, tech, cell) {
|
|
return readFileSync(resolve(EXAMPLES_DIR, name), 'utf8')
|
|
.replaceAll('__TECH__', tech)
|
|
.replaceAll('__CELL__', cell);
|
|
}
|