add interpreter
This commit is contained in:
parent
ef269442f1
commit
3b3a189020
@ -6,9 +6,8 @@ fn add(a: int, b: int) -> int
|
|||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
{
|
{
|
||||||
let sum = add(2, 3);
|
let sum: void = add(2, 3);
|
||||||
print_int(sum);
|
print_int(sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: syntax=rust
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import * as ast from "./ast.ts";
|
import * as ast from "./ast.ts";
|
||||||
import * as front from "./front.ts";
|
import * as front from "./front.ts";
|
||||||
import * as middle from "./middle.ts";
|
import * as middle from "./middle.ts";
|
||||||
|
import { MirInterpreter } from "./mir_interpreter.ts";
|
||||||
|
|
||||||
const filename = Deno.args[0];
|
const filename = Deno.args[0];
|
||||||
const text = await Deno.readTextFile(filename);
|
const text = await Deno.readTextFile(filename);
|
||||||
@ -34,3 +35,6 @@ const m = new middle.MiddleLowerer(resols, checker);
|
|||||||
const mainMiddleFn = m.lowerFn(mainFn);
|
const mainMiddleFn = m.lowerFn(mainFn);
|
||||||
|
|
||||||
console.log(mainMiddleFn.pretty());
|
console.log(mainMiddleFn.pretty());
|
||||||
|
|
||||||
|
const interp = new MirInterpreter();
|
||||||
|
interp.eval(mainMiddleFn);
|
||||||
|
|||||||
@ -34,6 +34,7 @@ class FnLowerer {
|
|||||||
lower(): Fn {
|
lower(): Fn {
|
||||||
const ty = this.checker.check(this.stmt);
|
const ty = this.checker.check(this.stmt);
|
||||||
this.lowerBlock(this.stmt.kind.body.as("Block"));
|
this.lowerBlock(this.stmt.kind.body.as("Block"));
|
||||||
|
this.pushInst(Ty.Void, "Return", { source: this.makeVoid() });
|
||||||
return new Fn(this.stmt, ty, this.bbs);
|
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