diff --git a/TODO.md b/TODO.md index 00e7bbf..c137fc3 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,3 @@ -[lang0] `Env` should not be a class - [lang1] 支持 `(import)` [lang1] 支持 `(assert-equal)` 与 `(assert-not-equal)` [lang1] 直接用 lang0 的测试 diff --git a/src/lang0/actions/doAp.ts b/src/lang0/actions/doAp.ts index 84c5e94..62b88b1 100644 --- a/src/lang0/actions/doAp.ts +++ b/src/lang0/actions/doAp.ts @@ -1,3 +1,4 @@ +import { envExtend } from "../env/Env.js" import { evaluate } from "../evaluate/index.js" import * as Neutrals from "../neutral/index.js" import * as Values from "../value/index.js" @@ -8,7 +9,7 @@ export function doAp(target: Value, arg: Value): Value { case "Fn": { return evaluate( target.mod, - target.env.extend(target.name, arg), + envExtend(target.env, target.name, arg), target.ret, ) } diff --git a/src/lang0/env/Env.ts b/src/lang0/env/Env.ts index 55dd907..34dfb35 100644 --- a/src/lang0/env/Env.ts +++ b/src/lang0/env/Env.ts @@ -1,30 +1,19 @@ import { type Value } from "../value/index.js" -export class Env { - values: Map +export type Env = Map - constructor(options: { values: Map }) { - this.values = options.values - } - - static init(): Env { - return new Env({ - values: new Map(), - }) - } +export function envEmpty(): Env { + return new Map() +} - get names(): Array { - return Array.from(this.values.keys()) - } +export function envNames(env: Env): Array { + return Array.from(env.keys()) +} - findValue(name: string): undefined | Value { - return this.values.get(name) - } +export function envFindValue(env: Env, name: string): undefined | Value { + return env.get(name) +} - extend(name: string, value: Value): Env { - return new Env({ - ...this, - values: new Map([...this.values, [name, value]]), - }) - } +export function envExtend(env: Env, name: string, value: Value): Env { + return new Map([...env, [name, value]]) } diff --git a/src/lang0/evaluate/evaluate.ts b/src/lang0/evaluate/evaluate.ts index 401aa5d..fbe13df 100644 --- a/src/lang0/evaluate/evaluate.ts +++ b/src/lang0/evaluate/evaluate.ts @@ -1,5 +1,5 @@ import * as Actions from "../actions/index.js" -import { type Env } from "../env/index.js" +import { envExtend, envFindValue, type Env } from "../env/index.js" import { type Exp } from "../exp/index.js" import { modFindValue, type Mod } from "../mod/index.js" import { substitutionBindings } from "../substitution/index.js" @@ -11,7 +11,7 @@ export function evaluate(mod: Mod, env: Env, exp: Exp): Value { case "Var": { let value = undefined - value = env.findValue(exp.name) + value = envFindValue(env, exp.name) if (value !== undefined) return value value = modFindValue(mod, exp.name) @@ -33,7 +33,11 @@ export function evaluate(mod: Mod, env: Env, exp: Exp): Value { case "Let": { let newEnv = env for (const binding of substitutionBindings(exp.substitution)) { - newEnv = newEnv.extend(binding.name, evaluate(mod, env, binding.exp)) + newEnv = envExtend( + newEnv, + binding.name, + evaluate(mod, env, binding.exp), + ) } return evaluate(mod, newEnv, exp.body) diff --git a/src/lang0/evaluate/evaluateDefinition.ts b/src/lang0/evaluate/evaluateDefinition.ts index 61b4095..fbcd02d 100644 --- a/src/lang0/evaluate/evaluateDefinition.ts +++ b/src/lang0/evaluate/evaluateDefinition.ts @@ -1,5 +1,5 @@ import { type Definition } from "../definition/index.js" -import { Env } from "../env/index.js" +import { envEmpty } from "../env/index.js" import { evaluate } from "../evaluate/index.js" import { type Value } from "../value/index.js" @@ -8,6 +8,6 @@ export function evaluateDefinition(definition: Definition): Value { return definition.cache } - definition.cache = evaluate(definition.mod, Env.init(), definition.exp) + definition.cache = evaluate(definition.mod, envEmpty(), definition.exp) return definition.cache } diff --git a/src/lang0/run/execute.ts b/src/lang0/run/execute.ts index 728b77a..8a83935 100644 --- a/src/lang0/run/execute.ts +++ b/src/lang0/run/execute.ts @@ -1,4 +1,4 @@ -import { Env } from "../env/index.js" +import { envEmpty } from "../env/index.js" import { equivalent, EquivalentCtx } from "../equivalent/index.js" import { evaluate } from "../evaluate/index.js" import * as Exps from "../exp/index.js" @@ -29,7 +29,7 @@ export function execute(mod: Mod, stmt: Stmt): void | string { } case "Compute": { - const value = evaluate(mod, Env.init(), stmt.exp) + const value = evaluate(mod, envEmpty(), stmt.exp) const exp = readback(ReadbackCtx.init(), value) return formatExp(exp) } @@ -74,8 +74,8 @@ export function execute(mod: Mod, stmt: Stmt): void | string { } function assertEqual(mod: Mod, left: Exp, right: Exp): void { - const leftValue = evaluate(mod, Env.init(), left) - const rightValue = evaluate(mod, Env.init(), right) + const leftValue = evaluate(mod, envEmpty(), left) + const rightValue = evaluate(mod, envEmpty(), right) if (!equivalent(EquivalentCtx.init(), leftValue, rightValue)) { throw new Error( `((fail assert-equal) ${formatExp(left)} ${formatExp(right)})`, @@ -84,8 +84,8 @@ function assertEqual(mod: Mod, left: Exp, right: Exp): void { } function assertNotEqual(mod: Mod, left: Exp, right: Exp): void { - const leftValue = evaluate(mod, Env.init(), left) - const rightValue = evaluate(mod, Env.init(), right) + const leftValue = evaluate(mod, envEmpty(), left) + const rightValue = evaluate(mod, envEmpty(), right) if (equivalent(EquivalentCtx.init(), leftValue, rightValue)) { throw new Error( `((fail assert-not-equal) ${formatExp(left)} ${formatExp(right)})`,