bolt/src/emitter.ts

201 lines
4.9 KiB
TypeScript

import { Syntax, SyntaxKind } from "./cst";
import { IndentWriter, assertNever } from "./util";
export class Emitter {
public constructor(
public writer: IndentWriter,
) {
}
public emit(node: Syntax): void {
switch (node.kind) {
case SyntaxKind.ModuleDeclaration:
this.writer.write(`mod ${node.name.text}`);
if (node.elements === null) {
this.writer.write('\n');
break;
}
this.writer.write('.\n');
this.writer.indent();
for (const element of node.elements) {
this.emit(element);
}
this.writer.dedent();
break;
case SyntaxKind.ReferenceExpression:
for (const [name, _dot] of node.modulePath) {
this.writer.write(name.text);
this.writer.write('.');
}
this.writer.write(node.name.text);
break;
case SyntaxKind.CallExpression:
this.emit(node.func);
for (const arg of node.args) {
this.writer.write(' ');
this.emit(arg);
}
break;
case SyntaxKind.ReferenceTypeExpression:
for (const [name, _dot] of node.modulePath) {
this.writer.write(name.text);
this.writer.write('.');
}
this.writer.write(node.name.text);
break;
case SyntaxKind.StructExpressionField:
this.writer.write(node.name.text);
this.writer.write(' = ');
this.emit(node.expression);
break;
case SyntaxKind.StructExpression:
this.writer.write('{ ');
for (const member of node.members) {
this.emit(member);
this.writer.write(', ');
}
this.writer.write(' }');
break;
case SyntaxKind.ConstantExpression:
this.writer.write(node.token.text);
break;
case SyntaxKind.FunctionExpression:
this.writer.write('\\');
for (const param of node.params) {
this.emit(param);
this.writer.write(' ');
}
this.emit(node.body);
break;
case SyntaxKind.ArrowTypeExpression:
for (const typeExpr of node.paramTypeExprs) {
this.emit(typeExpr);
this.writer.write(' -> ');
}
this.emit(node.returnTypeExpr);
break;
case SyntaxKind.VarTypeExpression:
this.writer.write(node.name.text);
break;
case SyntaxKind.Param:
this.emit(node.pattern);
break;
case SyntaxKind.NamedPattern:
this.writer.write(node.name.text);
break;
case SyntaxKind.ExpressionStatement:
this.emit(node.expression);
this.writer.write('\n');
break;
case SyntaxKind.SourceFile:
for (const element of node.elements) {
this.emit(element);
}
break;
case SyntaxKind.TypeAssert:
this.writer.write(': ');
this.emit(node.typeExpression);
break;
case SyntaxKind.ExprBody:
this.writer.write(node.equals.text);
this.writer.write(' ');
this.emit(node.expression);
break
case SyntaxKind.BlockBody:
this.writer.write('.\n');
this.writer.indent();
for (const element of node.elements) {
this.emit(element);
}
this.writer.dedent();
break;
case SyntaxKind.LetDeclaration:
if (node.pubKeyword) {
this.writer.write('pub ');
}
this.writer.write('let ');
if (node.mutKeyword) {
this.writer.write(' mut ');
}
this.emit(node.pattern);
this.writer.write(' ');
for (const param of node.params) {
this.emit(param);
this.writer.write(' ');
}
if (node.typeAssert) {
this.emit(node.typeAssert);
this.writer.write(' ');
}
if (node.body) {
this.emit(node.body);
}
this.writer.write('\n\n');
break;
case SyntaxKind.ClassConstraint:
this.writer.write(node.name.text);
for (const type of node.types) {
this.writer.write(' ');
this.emit(type);
}
break;
case SyntaxKind.ClassDeclaration:
if (node.pubKeyword) {
this.writer.write('pub ');
}
this.writer.write(`class `);
if (node.constraintClause) {
for (const constraint of node.constraintClause.constraints) {
this.emit(constraint);
this.writer.write(`, `);
}
this.writer.write(' => ');
}
this.emit(node.name);
for (const type of node.types) {
this.writer.write(' ');
this.emit(type);
}
if (node.elements !== null) {
this.writer.write('.\n');
this.writer.indent();
for (const element of node.elements) {
this.emit(element);
}
this.writer.dedent();
}
break;
default:
assertNever(node);
}
}
}