slige/compiler/desugar/special_loop.ts

247 lines
9.6 KiB
TypeScript
Raw Normal View History

import { AstCreator, Expr, ExprKind, Stmt, StmtKind } from "../ast.ts";
import { AstVisitor, visitExpr, VisitRes, visitStmts } from "../ast_visitor.ts";
import { Pos } from "../token.ts";
export class SpecialLoopDesugarer implements AstVisitor {
public constructor(
private astCreator: AstCreator,
) {}
public desugar(stmts: Stmt[]) {
visitStmts(stmts, this);
}
visitWhileExpr(expr: Expr): VisitRes {
if (expr.kind.type !== "while") {
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);
expr.kind = {
type: "loop",
body: Expr({
type: "block",
stmts: [
Stmt({
type: "expr",
expr: Expr({
type: "if",
cond: Expr({
type: "unary",
unaryType: "not",
subject: expr.kind.cond,
}),
truthy: Expr({
type: "block",
stmts: [
Stmt({ type: "break" }),
],
}),
}),
}),
Stmt({
type: "expr",
expr: expr.kind.body,
}),
],
}),
};
visitExpr(expr, this);
return "stop";
}
visitForInExpr(expr: Expr): VisitRes {
if (expr.kind.type !== "for_in") {
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);
expr.kind = {
type: "block",
stmts: [
Stmt({
type: "let",
param: { ident: "::values", pos: npos },
value: expr.kind.value,
}),
Stmt({
type: "let",
param: { ident: "::length", pos: npos },
value: Expr({
type: "call",
subject: Expr({
2024-12-30 23:54:58 +00:00
type: "path",
subject: Expr({
type: "ident",
ident: "std",
}),
ident: "array_length",
}),
args: [
Expr({
type: "ident",
ident: "::values",
}),
],
}),
}),
Stmt({
type: "let",
param: { ident: "::index", pos: npos },
value: Expr({ type: "int", value: 0 }),
}, expr.pos),
Stmt({
type: "expr",
expr: Expr({
type: "loop",
body: Expr({
type: "block",
stmts: [
Stmt({
type: "expr",
expr: Expr({
type: "if",
cond: Expr({
type: "unary",
unaryType: "not",
subject: Expr({
type: "binary",
binaryType: "<",
left: Expr({
type: "ident",
ident: "::index",
}),
right: Expr({
type: "ident",
ident: "::length",
}),
}),
}),
truthy: Expr({
type: "block",
stmts: [
Stmt({
type: "break",
}),
],
}),
}),
}),
Stmt({
type: "let",
param: expr.kind.param,
value: Expr({
type: "index",
subject: Expr({
type: "ident",
ident: "::values",
}),
value: Expr({
type: "ident",
ident: "::index",
}),
}),
}, expr.pos),
Stmt({
type: "expr",
expr: expr.kind.body,
}),
Stmt({
type: "assign",
assignType: "+=",
subject: Expr({
type: "ident",
ident: "::index",
}),
value: Expr({
type: "int",
value: 1,
}),
}),
],
}),
}),
}),
],
};
visitExpr(expr, this);
return "stop";
}
visitForExpr(expr: Expr): VisitRes {
if (expr.kind.type !== "for") {
throw new Error();
}
const Expr = (
kind: ExprKind,
pos: Pos = { index: 0, line: 1, col: 1 },
) => this.astCreator.expr(kind, pos);
const Stmt = (
kind: StmtKind,
pos: Pos = { index: 0, line: 1, col: 1 },
) => this.astCreator.stmt(kind, pos);
expr.kind = {
type: "block",
stmts: [
...[expr.kind.decl]
.filter((v) => v !== undefined),
Stmt({
type: "expr",
expr: Expr({
type: "loop",
body: Expr({
type: "block",
stmts: [
...[expr.kind.cond]
.filter((v) => v !== undefined)
.map(
(cond) =>
Stmt({
type: "expr",
expr: Expr({
type: "if",
cond: Expr({
type: "unary",
unaryType: "not",
subject: cond,
}),
truthy: Expr({
type: "block",
stmts: [
Stmt({
type: "break",
}),
],
}),
}),
2024-12-15 03:24:07 +00:00
}, cond.pos),
),
Stmt({
type: "expr",
expr: expr.kind.body,
}),
...[expr.kind.incr]
.filter((v) => v !== undefined),
],
}),
}),
}),
],
};
visitExpr(expr, this);
return "stop";
}
}