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", mut: true, 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"; } }