mirror of
https://github.com/hi-language/transpiler.git
synced 2026-01-14 00:28:05 +00:00
Refactor: Implement AST parser and generator
This commit is contained in:
@@ -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.
|
* @param {string} sourceCode The Hi source code.
|
||||||
* @returns {string} The equivalent JavaScript code.
|
* @returns {string} The equivalent JavaScript code.
|
||||||
*/
|
*/
|
||||||
export function hi2js(sourceCode) {
|
export function hi2js(sourceCode) {
|
||||||
// This will be replaced by a proper AST-based generator.
|
// 1. Create a nearley parser instance from our compiled grammar
|
||||||
return sourceCode
|
const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
|
||||||
// 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);');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user