153 lines
4.9 KiB
TypeScript
153 lines
4.9 KiB
TypeScript
|
import { BinaryType, Stmt } from "../ast.ts";
|
||
|
import { VType, vtypeToString } from "../vtype.ts";
|
||
|
|
||
|
export type Mir = {
|
||
|
fns: Fn[];
|
||
|
};
|
||
|
|
||
|
export type Fn = {
|
||
|
stmt: Stmt;
|
||
|
locals: Local[];
|
||
|
blocks: Block[];
|
||
|
};
|
||
|
|
||
|
export type LocalId = number;
|
||
|
|
||
|
export type Local = {
|
||
|
id: LocalId;
|
||
|
vtype: VType;
|
||
|
};
|
||
|
|
||
|
export type BlockId = number;
|
||
|
|
||
|
export type Block = {
|
||
|
id: BlockId;
|
||
|
ops: Op[];
|
||
|
ter: Ter;
|
||
|
label?: string;
|
||
|
};
|
||
|
|
||
|
export type Op = {
|
||
|
kind: OpKind;
|
||
|
};
|
||
|
|
||
|
type L = LocalId;
|
||
|
|
||
|
export type OpKind =
|
||
|
| { type: "error" }
|
||
|
| { type: "return" }
|
||
|
| { type: "drop"; val: L }
|
||
|
| { type: "assign"; dst: L; src: L }
|
||
|
| { type: "assign_error"; dst: L }
|
||
|
| { type: "assign_null"; dst: L }
|
||
|
| { type: "assign_bool"; dst: L; val: boolean }
|
||
|
| { type: "assign_int"; dst: L; val: number }
|
||
|
| { type: "assign_string"; dst: L; val: string }
|
||
|
| { type: "assign_fn"; dst: L; stmt: Stmt }
|
||
|
| { type: "field"; dst: L; subject: L; ident: string }
|
||
|
| { type: "assign_field"; subject: L; ident: string; src: L }
|
||
|
| { type: "index"; dst: L; subject: L; index: number }
|
||
|
| { type: "assign_field"; subject: L; index: L; src: L }
|
||
|
| { type: "call_val"; dst: L; subject: L; args: L[] }
|
||
|
| { type: "binary"; binaryType: BinaryType; dst: L; left: L; right: L };
|
||
|
|
||
|
export type Ter = {
|
||
|
kind: TerKind;
|
||
|
};
|
||
|
|
||
|
export type TerKind =
|
||
|
| { type: "error" }
|
||
|
| { type: "jump"; target: BlockId }
|
||
|
| { type: "if"; cond: L; truthy: BlockId; falsy: BlockId };
|
||
|
|
||
|
export function printMir(mir: Mir) {
|
||
|
for (const fn of mir.fns) {
|
||
|
const stmt = fn.stmt;
|
||
|
if (stmt.kind.type !== "fn") {
|
||
|
throw new Error();
|
||
|
}
|
||
|
const name = stmt.kind.ident;
|
||
|
|
||
|
const vtype = stmt.kind.vtype;
|
||
|
if (vtype?.type !== "fn") {
|
||
|
throw new Error();
|
||
|
}
|
||
|
const generics = vtype.genericParams
|
||
|
?.map(({ ident }) => `${ident}`).join(", ") ?? "";
|
||
|
const params = vtype.params
|
||
|
.map(({ vtype }, i) =>
|
||
|
`_${fn.locals[i + 1].id}: ${vtypeToString(vtype)}`
|
||
|
)
|
||
|
.join(", ");
|
||
|
const returnType = vtypeToString(vtype.returnType);
|
||
|
console.log(`${name}${generics}(${params}) -> ${returnType}:`);
|
||
|
for (const { id, vtype } of fn.locals) {
|
||
|
console.log(` let _${id}: ${vtypeToString(vtype)};`);
|
||
|
}
|
||
|
for (const block of fn.blocks) {
|
||
|
console.log(`.${block.label ?? block.id}:`);
|
||
|
for (const op of block.ops) {
|
||
|
const k = op.kind;
|
||
|
switch (k.type) {
|
||
|
case "error":
|
||
|
console.log(` <error>;`);
|
||
|
break;
|
||
|
case "return":
|
||
|
console.log(` return;`);
|
||
|
break;
|
||
|
case "drop":
|
||
|
console.log(` drop _${k.val};`);
|
||
|
break;
|
||
|
case "assign":
|
||
|
console.log(` _${k.dst} = _${k.src};`);
|
||
|
break;
|
||
|
case "assign_error":
|
||
|
console.log(` _${k.dst} = <error>;`);
|
||
|
break;
|
||
|
case "assign_null":
|
||
|
console.log(` _${k.dst} = null;`);
|
||
|
break;
|
||
|
case "assign_bool":
|
||
|
console.log(` _${k.dst} = ${k.val};`);
|
||
|
break;
|
||
|
case "assign_int":
|
||
|
console.log(` _${k.dst} = ${k.val};`);
|
||
|
break;
|
||
|
case "assign_string":
|
||
|
console.log(` _${k.dst} = "${k.val}";`);
|
||
|
break;
|
||
|
case "assign_fn": {
|
||
|
const stmt = k.stmt;
|
||
|
if (stmt.kind.type !== "fn") {
|
||
|
throw new Error();
|
||
|
}
|
||
|
console.log(` _${k.dst} = ${stmt.kind.ident};`);
|
||
|
break;
|
||
|
}
|
||
|
case "field":
|
||
|
console.log(
|
||
|
` _${k.dst} = _${k.subject}.${k.ident};`,
|
||
|
);
|
||
|
break;
|
||
|
case "index":
|
||
|
console.log(
|
||
|
` _${k.dst} = _${k.subject}[_${k.index}];`,
|
||
|
);
|
||
|
break;
|
||
|
case "call_val": {
|
||
|
const args = k.args.map((arg) => `_${arg}`).join(", ");
|
||
|
console.log(` _${k.dst} = _${k.subject}(${args});`);
|
||
|
break;
|
||
|
}
|
||
|
case "binary": {
|
||
|
console.log(
|
||
|
` _${k.dst} = _${k.left} ${k.binaryType} _${k.right};`,
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|