Skip to content

Commit

Permalink
[lang0] Env should not be a class
Browse files Browse the repository at this point in the history
xieyuheng committed Mar 31, 2024
1 parent b8cb93f commit e788d4b
Showing 6 changed files with 29 additions and 37 deletions.
2 changes: 0 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
[lang0] `Env` should not be a class

[lang1] 支持 `(import)`
[lang1] 支持 `(assert-equal)``(assert-not-equal)`
[lang1] 直接用 lang0 的测试
3 changes: 2 additions & 1 deletion src/lang0/actions/doAp.ts
Original file line number Diff line number Diff line change
@@ -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,
)
}
35 changes: 12 additions & 23 deletions src/lang0/env/Env.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
import { type Value } from "../value/index.js"

export class Env {
values: Map<string, Value>
export type Env = Map<string, Value>

constructor(options: { values: Map<string, Value> }) {
this.values = options.values
}

static init(): Env {
return new Env({
values: new Map(),
})
}
export function envEmpty(): Env {
return new Map()
}

get names(): Array<string> {
return Array.from(this.values.keys())
}
export function envNames(env: Env): Array<string> {
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]])
}
10 changes: 7 additions & 3 deletions src/lang0/evaluate/evaluate.ts
Original file line number Diff line number Diff line change
@@ -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)
4 changes: 2 additions & 2 deletions src/lang0/evaluate/evaluateDefinition.ts
Original file line number Diff line number Diff line change
@@ -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
}
12 changes: 6 additions & 6 deletions src/lang0/run/execute.ts
Original file line number Diff line number Diff line change
@@ -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)})`,

0 comments on commit e788d4b

Please sign in to comment.