add interpreter
This commit is contained in:
parent
ef269442f1
commit
3b3a189020
@ -6,9 +6,8 @@ fn add(a: int, b: int) -> int
|
||||
|
||||
fn main()
|
||||
{
|
||||
let sum = add(2, 3);
|
||||
let sum: void = add(2, 3);
|
||||
print_int(sum);
|
||||
}
|
||||
|
||||
// vim: syntax=rust
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import * as ast from "./ast.ts";
|
||||
import * as front from "./front.ts";
|
||||
import * as middle from "./middle.ts";
|
||||
import { MirInterpreter } from "./mir_interpreter.ts";
|
||||
|
||||
const filename = Deno.args[0];
|
||||
const text = await Deno.readTextFile(filename);
|
||||
@ -34,3 +35,6 @@ const m = new middle.MiddleLowerer(resols, checker);
|
||||
const mainMiddleFn = m.lowerFn(mainFn);
|
||||
|
||||
console.log(mainMiddleFn.pretty());
|
||||
|
||||
const interp = new MirInterpreter();
|
||||
interp.eval(mainMiddleFn);
|
||||
|
||||
@ -34,6 +34,7 @@ class FnLowerer {
|
||||
lower(): Fn {
|
||||
const ty = this.checker.check(this.stmt);
|
||||
this.lowerBlock(this.stmt.kind.body.as("Block"));
|
||||
this.pushInst(Ty.Void, "Return", { source: this.makeVoid() });
|
||||
return new Fn(this.stmt, ty, this.bbs);
|
||||
}
|
||||
|
||||
|
||||
113
src/mir_interpreter.ts
Normal file
113
src/mir_interpreter.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import * as mir from "./middle.ts";
|
||||
|
||||
export class MirInterpreter {
|
||||
constructor() {}
|
||||
|
||||
eval(fn: mir.Fn) {
|
||||
this.evalFn(fn, []);
|
||||
}
|
||||
|
||||
private evalFn(fn: mir.Fn, args: Val[]): Val {
|
||||
const regs = new Map<mir.Inst, Val>();
|
||||
const locals: (Val | null)[] = [];
|
||||
const localMap = new Map<mir.Inst, number>();
|
||||
|
||||
let bb = fn.bbs[0];
|
||||
for (const inst of bb.insts) {
|
||||
const k = inst.kind;
|
||||
switch (k.tag) {
|
||||
case "Error":
|
||||
throw new Error();
|
||||
case "Void":
|
||||
case "Int":
|
||||
case "Fn":
|
||||
regs.set(inst, new Val(k));
|
||||
continue;
|
||||
case "Param":
|
||||
regs.set(inst, args[k.idx]);
|
||||
continue;
|
||||
case "Call": {
|
||||
const fn = regs.get(k.callee);
|
||||
if (!fn || fn.kind.tag !== "Fn") {
|
||||
throw new Error();
|
||||
}
|
||||
const args = k.args.map((arg) => regs.get(arg)!);
|
||||
const val = this.evalFn(fn.kind.fn, args);
|
||||
regs.set(inst, val);
|
||||
continue;
|
||||
}
|
||||
case "AllocLocal":
|
||||
localMap.set(inst, locals.length);
|
||||
locals.push(null);
|
||||
continue;
|
||||
case "LocalLoad":
|
||||
if (!localMap.has(k.source)) {
|
||||
throw new Error();
|
||||
}
|
||||
if (locals[localMap.get(k.source)!] === null) {
|
||||
throw new Error();
|
||||
}
|
||||
regs.set(inst, locals[localMap.get(k.source)!]!);
|
||||
continue;
|
||||
case "LocalStore":
|
||||
if (!localMap.has(k.target)) {
|
||||
throw new Error();
|
||||
}
|
||||
locals[localMap.get(k.target)!] = regs.get(k.source)!;
|
||||
continue;
|
||||
case "Return":
|
||||
return regs.get(k.source)!;
|
||||
case "Add": {
|
||||
const left = regs.get(k.left)!;
|
||||
const right = regs.get(k.right)!;
|
||||
if (left.kind.tag === "Int" && right.kind.tag == "Int") {
|
||||
regs.set(
|
||||
inst,
|
||||
new Val({
|
||||
tag: "Int",
|
||||
value: left.kind.value + right.kind.value,
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
throw new Error();
|
||||
}
|
||||
case "DebugPrint":
|
||||
console.log(
|
||||
`debug: ${
|
||||
k.args.map((a) => regs.get(a)!.pretty()).join(", ")
|
||||
}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
const _: never = k;
|
||||
}
|
||||
return Val.Void;
|
||||
}
|
||||
}
|
||||
|
||||
class Val {
|
||||
constructor(
|
||||
public kind: ValKind,
|
||||
) {}
|
||||
|
||||
static Void = new Val({ tag: "Void" });
|
||||
|
||||
pretty() {
|
||||
const k = this.kind;
|
||||
switch (k.tag) {
|
||||
case "Void":
|
||||
return "void";
|
||||
case "Int":
|
||||
return `${k.value}`;
|
||||
case "Fn":
|
||||
return `<${k.fn.ty.pretty()}>`;
|
||||
}
|
||||
const _: never = k;
|
||||
}
|
||||
}
|
||||
|
||||
type ValKind =
|
||||
| { tag: "Void" }
|
||||
| { tag: "Int"; value: number }
|
||||
| { tag: "Fn"; fn: mir.Fn };
|
||||
Loading…
x
Reference in New Issue
Block a user