mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-14 08:25:02 +01:00
96 lines
2.5 KiB
TypeScript
96 lines
2.5 KiB
TypeScript
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);
|
|
}
|