mirror of
https://github.com/hi-language/transpiler.git
synced 2026-01-14 08:38:37 +00:00
Feat: Generate JS for new AST nodes and implicit returns
This commit is contained in:
@@ -9,35 +9,71 @@ export function generate(ast) {
|
|||||||
const generators = {
|
const generators = {
|
||||||
Program: (node) => node.body.map(generate).join('\n'),
|
Program: (node) => node.body.map(generate).join('\n'),
|
||||||
ExpressionStatement: (node) => `${generate(node.expression)};`,
|
ExpressionStatement: (node) => `${generate(node.expression)};`,
|
||||||
VariableDeclaration: (node) => `let ${node.identifier} = ${generate(node.value)};`,
|
|
||||||
Assignment: (node) => `${node.identifier} = ${generate(node.value)};`,
|
VariableDeclaration: (node) => {
|
||||||
|
const keyword = node.value.type.includes('Function') ? 'const' : 'let';
|
||||||
|
return `${keyword} ${node.identifier} = ${generate(node.value)};`;
|
||||||
|
},
|
||||||
|
AssignmentExpression: (node) => `${generate(node.left)} = ${generate(node.right)}`,
|
||||||
|
|
||||||
|
ReturnStatement: (node) => `return ${node.argument ? generate(node.argument) : ''};`,
|
||||||
|
|
||||||
|
ConditionalExpression: (node) => {
|
||||||
|
const wrap = (n) => {
|
||||||
|
if (n.type !== 'Block') return generate(n);
|
||||||
|
// Wrap blocks in IIFEs to handle statements and return values
|
||||||
|
return `(() => ${generate(n)})()`;
|
||||||
|
};
|
||||||
|
return `(${generate(node.test)} ? ${wrap(node.consequent)} : ${wrap(node.alternate)})`;
|
||||||
|
},
|
||||||
|
|
||||||
CallExpression: (node) => {
|
CallExpression: (node) => {
|
||||||
const callee = generate(node.callee);
|
const callee = generate(node.callee);
|
||||||
const args = node.arguments.map(generate).join(', ');
|
const args = node.arguments.map(generate).join(', ');
|
||||||
if (callee === '_') {
|
if (callee === '_') return `console.log(${args})`;
|
||||||
return `console.log(${args})`;
|
|
||||||
}
|
|
||||||
return `${callee}(${args})`;
|
return `${callee}(${args})`;
|
||||||
},
|
},
|
||||||
|
|
||||||
MemberExpression: (node) => `${generate(node.object)}.${generate(node.property)}`,
|
MemberExpression: (node) => node.computed
|
||||||
|
? `${generate(node.object)}[${generate(node.property)}]`
|
||||||
|
: `${generate(node.object)}.${generate(node.property)}`,
|
||||||
|
|
||||||
BinaryExpression: (node) => `(${generate(node.left)} ${node.operator} ${generate(node.right)})`,
|
BinaryExpression: (node) => `(${generate(node.left)} ${node.operator} ${generate(node.right)})`,
|
||||||
|
|
||||||
Block: (node) => {
|
Block: (node) => {
|
||||||
if (node.properties.length === 0) return '{}';
|
let bodyCode = node.body.map(generate).join('\n');
|
||||||
const properties = node.properties.map(p => ` ${generate(p)}`).join(',\n');
|
// Check for implicit return
|
||||||
return `{\n${properties}\n}`;
|
const lastNode = node.body[node.body.length - 1];
|
||||||
|
if (lastNode && lastNode.type === 'ExpressionStatement') {
|
||||||
|
const bodyWithoutLast = node.body.slice(0, -1).map(generate).join('\n');
|
||||||
|
const lastExpr = `return ${generate(lastNode.expression)};`;
|
||||||
|
bodyCode = (bodyWithoutLast ? bodyWithoutLast + '\n' : '') + lastExpr;
|
||||||
|
}
|
||||||
|
return `{\n${bodyCode.split('\n').map(l => ' ' + l).join('\n')}\n}`;
|
||||||
},
|
},
|
||||||
Property: (node) => `${node.key}: ${generate(node.value)}`,
|
BlockStatement: (node) => generators.Block(node),
|
||||||
|
|
||||||
|
FunctionExpression: (node) => `function(${node.params.map(generate).join(', ')}) ${generate(node.body)}`,
|
||||||
|
ArrowFunctionExpression: (node) => {
|
||||||
|
const params = node.params.map(generate).join(', ');
|
||||||
|
const body = generate(node.body);
|
||||||
|
// If body is not a block, it's an implicit return
|
||||||
|
const bodyStr = node.body.type === 'Block' || node.body.type === 'BlockStatement' ? body : `(${body})`;
|
||||||
|
return `(${params}) => ${bodyStr}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
ArrayLiteral: (node) => `[${node.elements.map(generate).join(', ')}]`,
|
||||||
|
|
||||||
Identifier: (node) => node.name,
|
Identifier: (node) => node.name,
|
||||||
|
ThisExpression: () => 'this',
|
||||||
NumericLiteral: (node) => node.value,
|
NumericLiteral: (node) => node.value,
|
||||||
StringLiteral: (node) => node.value,
|
StringLiteral: (node) => `"${node.value}"`,
|
||||||
|
BooleanLiteral: (node) => node.value,
|
||||||
|
NullLiteral: () => 'null',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!generators[ast.type]) {
|
if (!generators[ast.type]) {
|
||||||
throw new Error(`Unknown AST node type: ${ast.type}`);
|
throw new Error(`Master, I cannot generate code for AST node type: ${ast.type}`);
|
||||||
}
|
}
|
||||||
return generators[ast.type](ast);
|
return generators[ast.type](ast);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user