This commit is contained in:
nora 2023-07-23 14:02:53 +02:00
parent 91b183c002
commit 4e95bc05a3
9 changed files with 640 additions and 132 deletions

96
src/printer.ts Normal file
View file

@ -0,0 +1,96 @@
import { Expr, FunctionDef, Item } from "./ast";
export function printAst(ast: Item[]): string {
return ast.map(printItem).join("\n");
}
function printItem(item: Item): string {
switch (item.kind) {
case "function": {
return printFunction(item.node);
}
}
}
function printFunction(func: FunctionDef): string {
const args = func.args.map(({ name }) => name).join(", ");
return `function ${func.name}(${args}) = ${printExpr(func.body, 0)}`;
}
function printExpr(expr: Expr, indent: number): string {
switch (expr.kind) {
case "empty": {
return "";
}
case "let": {
return `let ${expr.name} = ${printExpr(expr.rhs, 1)} in${linebreak(
indent
)}`;
}
case "block": {
const exprs = expr.exprs.map((expr) => printExpr(expr, indent + 1));
if (exprs.length === 1) {
return `(${exprs[0]})`;
}
const shortExprs =
exprs.map((s) => s.length).reduce((a, b) => a + b, 0) < 40;
if (shortExprs) {
const alreadyHasTrailingSpace = expr.exprs[exprs.length - 1]?.kind === "empty";
const trailingSpace = alreadyHasTrailingSpace ? "" : " ";
return `( ${exprs.join("; ")}${trailingSpace})`;
} else {
const joiner = `;${linebreak(indent + 1)}`;
return (
`(${linebreak(indent + 1)}` +
`${exprs.join(joiner)}` +
`${linebreak(indent)})`
);
}
}
case "literal": {
switch (expr.value.kind) {
case "str": {
return `"${expr.value.value}"`;
}
case "int": {
return `${expr.value.value}`;
}
}
}
case "ident": {
return expr.value;
}
case "binary": {
return `${printExpr(expr.lhs, indent)} ${expr.binaryKind} ${printExpr(
expr.rhs,
indent
)}`;
}
case "unary": {
return `${expr.unaryKind}${printExpr(expr.rhs, indent)}`;
}
case "call": {
const args = expr.args.map((arg) => printExpr(arg, indent + 1));
const shortArgs =
args.map((s) => s.length).reduce((a, b) => a + b, 0) < 40;
if (shortArgs) {
return `${printExpr(expr.lhs, indent)}(${args.join(", ")})`;
} else {
return (
`${printExpr(expr.lhs, indent)}(${linebreak(indent + 1)}` +
`${args.join(linebreak(indent + 1))}` +
`${linebreak(indent)})`
);
}
}
}
}
function linebreak(indent: number): string {
return `\n${ind(indent)}`;
}
function ind(indent: number): string {
return " ".repeat(indent * 2);
}