From 072eeb7e996131f8f264f9f279c032e7a8f21b0d Mon Sep 17 00:00:00 2001 From: multipleof4 Date: Fri, 26 Sep 2025 01:41:42 -0700 Subject: [PATCH] Refactor: Implement AST parser and generator --- transpiler.js | 62 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/transpiler.js b/transpiler.js index 64f7405..25a35de 100644 --- a/transpiler.js +++ b/transpiler.js @@ -1,18 +1,56 @@ +import nearley from 'nearley'; +import grammar from './grammar.js'; + /** - * Transpiles a string of Hi source code into JavaScript. + * Generates JavaScript code from a Hi AST. + * @param {object} ast The Abstract Syntax Tree. + * @returns {string} The equivalent JavaScript code. + */ +function generate(ast) { + const generator = { + Program: (node) => node.body.map(generate).join('\n'), + Comment: (node) => node.value, + VariableDeclaration: (node) => `let ${node.identifier} = ${generate(node.value)};`, + Assignment: (node) => `${node.identifier} = ${generate(node.value)};`, + OutputCall: (node) => `console.log(${node.arguments.map(generate).join(', ')});`, + NumericLiteral: (node) => node.value, + StringLiteral: (node) => node.value, + }; + + if (!generator[ast.type]) { + throw new Error(`Unknown AST node type: ${ast.type}`); + } + return generator[ast.type](ast); +} + +/** + * Transpiles a string of Hi source code into JavaScript using an AST. * @param {string} sourceCode The Hi source code. * @returns {string} The equivalent JavaScript code. */ export function hi2js(sourceCode) { - // This will be replaced by a proper AST-based generator. - return sourceCode - // Comments: // ... - .replace(/^\s*\/\/.*/gm, (match) => match) - // Declaration: name: value -> let name = value; - .replace(/^(?!.*\/\/.*)([\w$]+)\s*:\s*(.*)/gm, 'let $1 = $2;') - // Assignment: name = value -> name = value; - .replace(/^(?!.*\/\/.*)([\w$]+)\s*=\s*([^:;].*)/gm, '$1 = $2;') - // Global output: _(...) -> console.log(...); - .replace(/^(?!.*\/\/.*)\s*_\((.*)\)/gm, 'console.log($1);'); -} + // 1. Create a nearley parser instance from our compiled grammar + const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar)); + try { + // 2. Feed the source code to the parser + parser.feed(sourceCode); + + // 3. Check for ambiguity and get the AST + if (parser.results.length > 1) { + console.warn("Master, the grammar is ambiguous. Using the first parse tree."); + } + if (parser.results.length === 0) { + throw new Error("Unexpected end of input. The code is incomplete."); + } + const ast = parser.results[0]; + + // 4. Generate JavaScript from the AST + return generate(ast); + + } catch (err) { + // Provide a more helpful error message + const message = err.message.replace(/ Instead, I found a "[^"]+" token here:/, "."); + throw new Error(`Parsing error: ${message}`); + } +}