73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
import { Expr, FieldName, ProductPattern, Tag, VariableName } from "../expr";
|
|
import { ThrownRuntimeError } from "./error";
|
|
|
|
export type Value =
|
|
| { tag: "string", value: string }
|
|
| { tag: "number", value: number }
|
|
| { tag: "tag", tag_name: Tag }
|
|
| { tag: "tagged", tag_name: Tag, value: Value }
|
|
| { tag: "tuple", values: Value[] }
|
|
| { tag: "record", fields: Map<FieldName, Value> }
|
|
| { tag: "closure", closure: Closure }
|
|
|
|
export type ValueTag =
|
|
| "string"
|
|
| "number"
|
|
| "tag"
|
|
| "tagged"
|
|
| "tuple"
|
|
| "record"
|
|
| "closure"
|
|
|
|
// Used as a Stack of frames. Basically a linked list.
|
|
export type Env =
|
|
| { tag: "nil" }
|
|
| { tag: "frame", frame: EnvFrame, parent: Env }
|
|
|
|
export type EnvFrame = Map<VariableName, Value>;
|
|
|
|
export type Closure = {
|
|
env: Env,
|
|
parameters: ProductPattern[],
|
|
body: Expr,
|
|
}
|
|
|
|
export namespace Value {
|
|
export const string = (value: string): Value => ({ tag: "string", value });
|
|
export const number = (value: number): Value => ({ tag: "number", value });
|
|
export const tag = (tag_name: Tag): Value => ({ tag: "tag", tag_name });
|
|
export const tagged = (tag_name: Tag, value: Value): Value => ({ tag: "tagged", tag_name, value });
|
|
export const tuple = (values: Value[]): Value => ({ tag: "tuple", values });
|
|
export const record = (fields: Map<FieldName, Value>): Value => ({ tag: "record", fields });
|
|
export const closure = (closure: Closure): Value => ({ tag: "closure", closure });
|
|
}
|
|
|
|
export namespace Env {
|
|
export function nil(): Env {
|
|
return { tag: "nil" };
|
|
}
|
|
|
|
export function push_frame(env: Env, frame: EnvFrame): Env {
|
|
return { tag: "frame", frame, parent: env };
|
|
}
|
|
|
|
// may throw `ThrownRuntimeError`
|
|
export function lookup(env: Env, var_name: VariableName): Value {
|
|
let cur = env;
|
|
while (cur.tag !== "nil") {
|
|
if (cur.frame.has(var_name)) {
|
|
return cur.frame.get(var_name)!;
|
|
}
|
|
cur = cur.parent;
|
|
}
|
|
throw ThrownRuntimeError.error({
|
|
tag: "VariableLookupFailure",
|
|
name: var_name,
|
|
});
|
|
}
|
|
|
|
export function frame_insert_mut(frame: EnvFrame, var_name: VariableName, value: Value) {
|
|
frame.set(var_name, value);
|
|
}
|
|
}
|
|
|