// Generates engine/chartable.zena (the byte-class constants) and engine/chartable.wat (the table itself, a // data segment scripts/build.sh merges in) for engine/lex.zena's byte classification. Run: // node scripts/gen/chartable.mjs import fs from "node:fs"; import path from "node:path"; import { CLASS_BASE, LEXC_BASE, dataModule } from "./layout.mjs"; // Bit flags, one 256-byte table instead of lex.zena's isIdStart/isIdChar/isDigit range-check chains and // its trivia if-chain (space/tab/VT/FF, CR/LF). ID_CHAR is precomputed as ID_START | DIGIT so the hot // identifier/number continuation loops stay a single mask test. const ID_START = 1; const DIGIT = 2; const ID_CHAR = 4; const WS = 8; const NL = 16; const table = Buffer.alloc(256); for (let c = 0; c < 256; c++) { let b = 0; const isStart = (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || c === 95 || c === 36; const isDigit = c >= 48 && c <= 57; if (isStart) b |= ID_START; if (isDigit) b |= DIGIT; if (isStart || isDigit) b |= ID_CHAR; if (c === 32 || c === 9 || c === 11 || c === 12) b |= WS; if (c === 10 || c === 13) b |= NL; table[c] = b; } const out = `// GENERATED by scripts/gen/chartable.mjs. Do not edit by hand. // Byte-class table for engine/lex.zena: one getU8(CLASS + c) load classifies a byte, replacing range-check // chains for isIdStart/isIdChar/isDigit and the trivia if-chain. export let CLASS: i32 = ${CLASS_BASE}; export let ID_START: i32 = ${ID_START}; export let DIGIT: i32 = ${DIGIT}; export let ID_CHAR: i32 = ${ID_CHAR}; // ID_START | DIGIT, so identifier/number continuation is one mask test export let WS: i32 = ${WS}; export let NL: i32 = ${NL}; `; const dest = path.resolve(import.meta.dirname, "../../engine/chartable.zena"); fs.writeFileSync(dest, out); const wat = path.resolve(import.meta.dirname, "../../engine/chartable.wat"); fs.writeFileSync(wat, dataModule("chartable.mjs", CLASS_BASE, table, LEXC_BASE)); console.log(`wrote ${dest} and ${wat}: 256 bytes of table`);