Files
transpiler/transpiler.js

57 lines
2.0 KiB
JavaScript

import nearley from 'nearley';
import grammar from './grammar.js';
/**
* 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) {
// 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}`);
}
}