slige/compiler/desugar/struct_literal.ts
2025-01-17 11:50:14 +01:00

101 lines
2.9 KiB
TypeScript

import {
AstCreator,
ETypeKind,
Expr,
ExprKind,
Stmt,
StmtKind,
} from "../ast.ts";
import {
AstVisitor,
visitField,
VisitRes,
visitStmts,
} from "../ast_visitor.ts";
import { Pos } from "../token.ts";
export class StructLiteralDesugarer implements AstVisitor {
public constructor(
private astCreator: AstCreator,
) {}
public desugar(stmts: Stmt[]) {
visitStmts(stmts, this);
}
visitStructExpr(expr: Expr): VisitRes {
if (expr.kind.type !== "struct") {
throw new Error();
}
const npos: Pos = { index: 0, line: 1, col: 1 };
const Expr = (kind: ExprKind, pos = npos) =>
this.astCreator.expr(kind, pos);
const Stmt = (kind: StmtKind, pos = npos) =>
this.astCreator.stmt(kind, pos);
const EType = (kind: ETypeKind, pos = npos) =>
this.astCreator.etype(kind, pos);
const std = (ident: string): Expr =>
Expr({
type: "path",
subject: Expr({
type: "ident",
ident: "std",
}),
ident,
});
const fields = expr.kind.fields;
expr.kind = {
type: "block",
stmts: [
Stmt({
type: "let",
param: this.astCreator.param({
ident: "::value",
pos: npos,
}),
value: Expr({
type: "call",
subject: Expr({
type: "etype_args",
subject: std("struct_new"),
etypeArgs: [
EType({
type: "type_of",
expr: Expr({ ...expr.kind }),
}),
],
}),
args: [],
}),
}),
...expr.kind.fields
.map((field) =>
Stmt({
type: "assign",
assignType: "=",
subject: Expr({
type: "field",
subject: Expr({
type: "ident",
ident: "::value",
}),
ident: field.ident,
}),
value: field.expr,
})
),
],
expr: Expr({ type: "ident", ident: "::value" }),
};
for (const field of fields) {
visitField(field, this);
}
return "stop";
}
}