2020-02-25 17:55:17 +01:00
|
|
|
|
2020-05-10 15:56:34 +02:00
|
|
|
import { Syntax, SyntaxKind, kindToString } from "./ast"
|
2020-02-25 17:55:17 +01:00
|
|
|
|
|
|
|
export class Emitter {
|
|
|
|
|
2020-05-24 21:03:15 +02:00
|
|
|
public emit(node: Syntax) {
|
2020-02-25 17:55:17 +01:00
|
|
|
|
2020-05-10 23:50:42 +02:00
|
|
|
let out = '';
|
2020-05-10 18:21:44 +02:00
|
|
|
|
2020-02-25 17:55:17 +01:00
|
|
|
switch (node.kind) {
|
|
|
|
|
2020-05-25 17:46:01 +02:00
|
|
|
case SyntaxKind.BoltModulePath:
|
|
|
|
out += node.elements.map(el => el.text).join('::');
|
|
|
|
break;
|
|
|
|
|
2020-05-24 22:23:18 +02:00
|
|
|
case SyntaxKind.BoltQualName:
|
|
|
|
if (node.modulePath !== null) {
|
|
|
|
for (const element of node.modulePath) {
|
|
|
|
out += '.' + element.text;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out += this.emit(node.name);
|
|
|
|
break;
|
|
|
|
|
2020-05-24 21:03:15 +02:00
|
|
|
case SyntaxKind.BoltIdentifier:
|
|
|
|
case SyntaxKind.BoltOperator:
|
|
|
|
out += node.text;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.BoltGtSign:
|
|
|
|
out += '>';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.BoltLtSign:
|
|
|
|
out += '<';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.BoltEqSign:
|
|
|
|
out += '=';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.BoltVBar:
|
|
|
|
out += '|';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.BoltExMark:
|
|
|
|
out += '!';
|
|
|
|
break;
|
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
case SyntaxKind.JSExpressionStatement:
|
|
|
|
out += this.emit(node.expression) + ';\n';
|
|
|
|
break;
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
case SyntaxKind.JSReferenceExpression:
|
2020-05-10 23:50:42 +02:00
|
|
|
out += node.name;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.JSConstantExpression:
|
|
|
|
if (typeof node.value === 'string') {
|
|
|
|
out += '"' + node.value + '"';
|
|
|
|
} else if (typeof node.value === 'bigint') {
|
|
|
|
out += node.value.toString();
|
|
|
|
} else {
|
|
|
|
throw new Error(`Could not emit the value of a specific JSConstantExpression.`);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.JSFunctionDeclaration:
|
|
|
|
out += 'function ' + node.name.text + '(';
|
|
|
|
//out += node.params.map(p => this.emit(p)).join(', ');
|
|
|
|
out += ') {\n';
|
|
|
|
out += '}\n\n'
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.JSCallExpression:
|
|
|
|
out += this.emit(node.operator) + '(';
|
|
|
|
out += node.operands.map(op => this.emit(op)).join(', ');
|
|
|
|
out += ')'
|
|
|
|
break;
|
2020-05-10 18:21:44 +02:00
|
|
|
|
2020-05-10 15:56:34 +02:00
|
|
|
case SyntaxKind.JSSourceFile:
|
2020-02-25 17:55:17 +01:00
|
|
|
for (const element of node.elements) {
|
|
|
|
out += this.emit(element);
|
|
|
|
}
|
2020-05-10 23:50:42 +02:00
|
|
|
break;
|
2020-02-25 17:55:17 +01:00
|
|
|
|
|
|
|
default:
|
2020-05-10 15:56:34 +02:00
|
|
|
throw new Error(`Could not emit source code for ${kindToString(node.kind)}`)
|
2020-02-25 17:55:17 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-05-10 23:50:42 +02:00
|
|
|
return out;
|
|
|
|
|
2020-02-25 17:55:17 +01:00
|
|
|
}
|
2020-05-24 21:03:15 +02:00
|
|
|
|
2020-02-25 17:55:17 +01:00
|
|
|
}
|
|
|
|
|
2020-05-10 11:58:07 +02:00
|
|
|
/**
|
|
|
|
* A wrapper around `Emitter` for quick emission of AST nodes with sane defaults.
|
|
|
|
*/
|
|
|
|
export function emit(node: Syntax) {
|
|
|
|
const emitter = new Emitter();
|
|
|
|
return emitter.emit(node);
|
|
|
|
}
|
|
|
|
|