Skip to content

Commit 0146be1

Browse files
committed
support circular imports
> if we can support mutually defined recursive function, > we should also support circular imports. - call `handleImport` after `handleDefine` - `handleDefine` -- should not evaluate `exp` -- evaluate on first `modFindValue`
1 parent 7dc7252 commit 0146be1

File tree

6 files changed

+22
-38
lines changed

6 files changed

+22
-38
lines changed

TODO.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
call `handleImport` after `handleDefine` -- to support circular imports
2-
3-
- if we can support mutually defined recursive function,
4-
we should also support circular imports.
1+
test circular imports
52

63
# lazy evaluation
74

src/lang/load/handleDefine.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
1-
import { emptyEnv } from "../env/Env.ts"
2-
import { evaluate } from "../evaluate/evaluate.ts"
31
import { modDefine } from "../mod/index.ts"
42
import type { Mod } from "../mod/Mod.ts"
53
import type { Stmt } from "../stmt/Stmt.ts"
64

75
export async function handleDefine(mod: Mod, stmt: Stmt): Promise<void> {
86
if (stmt.kind === "Define") {
9-
const value = evaluate(mod, emptyEnv(), stmt.exp)
10-
if (value.kind === "Lambda") {
11-
value.definedName = stmt.name
12-
}
13-
147
modDefine(mod, stmt.name, {
158
mod,
169
name: stmt.name,
1710
exp: stmt.exp,
18-
value,
1911
})
2012

2113
return

src/lang/load/handleImport.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { modDefine, modFind, modResolve } from "../mod/index.ts"
22
import type { Mod } from "../mod/Mod.ts"
33
import type { ImportEntry, Stmt } from "../stmt/Stmt.ts"
4-
import { globalLoadedMods } from "./globalLoadedMods.ts"
4+
import { load } from "./load.ts"
55

66
export async function handleImport(mod: Mod, stmt: Stmt): Promise<void> {
77
if (stmt.kind === "Import") {
@@ -20,20 +20,16 @@ async function importOne(
2020
): Promise<void> {
2121
const url = modResolve(mod, path)
2222
if (url.href === mod.url.href) {
23-
throw new Error(`I can not circular import: ${path}`)
23+
throw new Error(`[import] A module can not import itself: ${path}`)
2424
}
2525

26-
const found = globalLoadedMods.get(url.href)
27-
if (found === undefined) {
28-
throw new Error(`Mod is not loaded: ${path}`)
29-
}
26+
const importedMod = await load(url)
3027

3128
const { name, rename } = entry
32-
33-
const def = modFind(found.mod, name)
29+
const def = modFind(importedMod, name)
3430
if (def === undefined) {
3531
throw new Error(
36-
`I can not import undefined name: ${name}, from path: ${path}`,
32+
`[import] I can not import undefined name: ${name}, from path: ${path}`,
3733
)
3834
}
3935

src/lang/load/load.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,20 @@
11
import { ParsingError } from "@xieyuheng/x-data.js"
22
import fs from "node:fs"
3-
import { createMod, modResolve, type Mod } from "../mod/index.ts"
3+
import { createMod, type Mod } from "../mod/index.ts"
44
import { parseStmts } from "../parse/index.ts"
55
import { globalLoadedMods } from "./globalLoadedMods.ts"
66
import { run } from "./run.ts"
77

88
export async function load(url: URL): Promise<Mod> {
99
const found = globalLoadedMods.get(url.href)
10-
if (found !== undefined) {
11-
return found.mod
12-
}
10+
if (found !== undefined) return found.mod
1311

1412
const text = await fs.promises.readFile(url.pathname, "utf8")
1513

1614
try {
1715
const mod = createMod(url)
1816
mod.stmts = parseStmts(text)
1917
globalLoadedMods.set(url.href, { mod, text })
20-
21-
for (const stmt of mod.stmts) {
22-
if (stmt.kind === "Import") {
23-
const importedUrl = modResolve(mod, stmt.path)
24-
await load(importedUrl)
25-
}
26-
}
27-
2818
await run(mod)
2919
return mod
3020
} catch (error) {

src/lang/load/run.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@ import { handleImport } from "./handleImport.ts"
88
export async function run(mod: Mod): Promise<void> {
99
if (mod.isFinished) return
1010

11-
for (const stmt of mod.stmts) await handleImport(mod, stmt)
1211
for (const stmt of mod.stmts) await handleDefine(mod, stmt)
13-
12+
for (const stmt of mod.stmts) await handleImport(mod, stmt)
1413
for (const def of modOwnDefs(mod).values()) assertAllNamesDefined(mod, def)
15-
1614
for (const stmt of mod.stmts) await handleEffect(mod, stmt)
1715

1816
mod.isFinished = true

src/lang/mod/Mod.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { emptyEnv } from "../env/Env.ts"
2+
import { evaluate } from "../evaluate/evaluate.ts"
13
import { type Exp } from "../exp/index.ts"
24
import { type Stmt } from "../stmt/index.ts"
35
import { type Value } from "../value/index.ts"
@@ -6,7 +8,7 @@ export type Def = {
68
mod: Mod
79
name: string
810
exp: Exp
9-
value: Value
11+
value?: Value
1012
}
1113

1214
export type Mod = {
@@ -42,7 +44,16 @@ export function modFind(mod: Mod, name: string): Def | undefined {
4244
export function modFindValue(mod: Mod, name: string): Value | undefined {
4345
const def = modFind(mod, name)
4446
if (def === undefined) return undefined
45-
return def.value
47+
48+
if (def.value) return def.value
49+
50+
const value = evaluate(def.mod, emptyEnv(), def.exp)
51+
if (value.kind === "Lambda") {
52+
value.definedName = def.name
53+
}
54+
55+
def.value = value
56+
return value
4657
}
4758

4859
export function modResolve(mod: Mod, href: string): URL {

0 commit comments

Comments
 (0)