Skip to content

Commit 46b514c

Browse files
authored
Merge pull request #81 from thefrontside/env-module
✨Introduce the `--canon--` module
2 parents a199129 + 3ef3d1c commit 46b514c

File tree

7 files changed

+80
-83
lines changed

7 files changed

+80
-83
lines changed

load.ts

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { PSEnv, PSModule, PSValue } from "./types.ts";
1+
import type { PSEnv, PSMap, PSModule, PSValue } from "./types.ts";
22
import type { Operation } from "./deps.ts";
33

44
import { expect, useAbortSignal } from "./deps.ts";
@@ -11,30 +11,32 @@ export interface LoadOptions {
1111
location: string | URL;
1212
base?: string;
1313
env?: PSEnv;
14+
canon?: PSMap;
1415
}
1516

1617
export function* load(options: LoadOptions): Operation<PSModule> {
17-
let { location, base, env } = options;
18+
let { location, base, env, canon } = options;
1819
let url = typeof location === "string" ? new URL(location, base) : location;
1920

2021
let content = yield* read(url);
2122
let source = parse(content);
2223

23-
return yield* moduleEval({ source, location: url, env });
24+
return yield* moduleEval({ source, location: url, env, canon });
2425
}
2526

2627
export interface ModuleEvalOptions {
2728
location: string | URL;
2829
source: PSValue;
2930
env?: PSEnv;
31+
canon?: PSMap;
3032
}
3133

3234
export function* moduleEval(options: ModuleEvalOptions): Operation<PSModule> {
3335
let { location, source, env = createYSEnv() } = options;
3436
let url = typeof location === "string" ? new URL(location) : location;
3537

3638
let mod: PSModule = {
37-
url,
39+
location: location.toString(),
3840
source,
3941
value: source,
4042
imports: [],
@@ -45,6 +47,7 @@ export function* moduleEval(options: ModuleEvalOptions): Operation<PSModule> {
4547
}
4648

4749
let scope = data.map({});
50+
let canon = options.canon ?? data.map({});
4851

4952
let imports = lookup("$import", source);
5053
let rest = exclude(["$import"], source);
@@ -67,11 +70,19 @@ export function* moduleEval(options: ModuleEvalOptions): Operation<PSModule> {
6770
);
6871
}
6972
let bindings = matchBindings(names.value);
70-
let dep = yield* load({
71-
location: loc.value,
72-
base: url.toString(),
73-
env,
74-
});
73+
74+
let dep = loc.value === "--canon--"
75+
? ({
76+
location: loc.value,
77+
source: canon,
78+
value: canon,
79+
imports: [],
80+
})
81+
: yield* load({
82+
location: loc.value,
83+
base: url.toString(),
84+
env,
85+
});
7586

7687
mod.imports.push({
7788
module: dep,
@@ -85,13 +96,13 @@ export function* moduleEval(options: ModuleEvalOptions): Operation<PSModule> {
8596
value = dep.value;
8697
} else if (dep.value.type !== "map") {
8798
throw new Error(
88-
`tried to import a name from ${dep.url}, but it is not a 'map'. It is a ${dep.value.type}`,
99+
`tried to import a name from ${dep.location}, but it is not a 'map'. It is a ${dep.value.type}`,
89100
);
90101
} else {
91102
let result = lookup(binding.name, dep.value);
92103
if (result.type === "nothing") {
93104
throw new Error(
94-
`module ${dep.url} does not have a member named '${binding.name}'`,
105+
`module ${dep.location} does not have a member named '${binding.name}'`,
95106
);
96107
} else {
97108
value = result.value;

platformscript.ts

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { PSEnv, PSFn, PSMap, PSModule, PSValue } from "./types.ts";
22
import type { Operation, Task } from "./deps.ts";
33
import { createYSEnv, global } from "./evaluate.ts";
4-
import { concat } from "./psmap.ts";
54
import { load, moduleEval } from "./load.ts";
65
import { map } from "./data.ts";
76
import { run as $run } from "./deps.ts";
@@ -14,16 +13,11 @@ export interface PlatformScript {
1413
load(url: string | URL, base?: string): Task<PSModule>;
1514
}
1615

17-
export function createPlatformScript(
18-
globals?: (ps: PlatformScript) => PSMap,
19-
): PlatformScript {
20-
let env = lazy(() => {
21-
let ext = globals ? globals(platformscript) : map({});
22-
return createYSEnv(concat(global, ext));
23-
});
16+
export function createPlatformScript(canon = map({})): PlatformScript {
17+
let env = createYSEnv(global);
2418

2519
function run<T>(block: (env: PSEnv) => Operation<T>): Task<T> {
26-
return $run(() => block(env()));
20+
return $run(() => block(env));
2721
}
2822

2923
let platformscript: PlatformScript = {
@@ -35,20 +29,13 @@ export function createPlatformScript(
3529
return run((env) => env.eval(value, bindings));
3630
},
3731
moduleEval(value, url) {
38-
return run((env) => moduleEval({ source: value, location: url, env }));
32+
return run((env) =>
33+
moduleEval({ source: value, location: url, env, canon })
34+
);
3935
},
4036
load(location, base) {
41-
return run((env) => load({ location, base, env }));
37+
return run((env) => load({ location, base, env, canon }));
4238
},
4339
};
4440
return platformscript;
4541
}
46-
47-
function lazy<T>(create: () => T): () => T {
48-
let thunk = () => {
49-
let value = create();
50-
thunk = () => value;
51-
return value;
52-
};
53-
return () => thunk();
54-
}

test/external.test.ts

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,46 @@ import * as _ from "https://raw.githubusercontent.com/lodash/lodash/4.17.21-es/l
66
describe("external", () => {
77
it("can represent any arbitrary javascript value", async () => {
88
let obj = { unqiue: "object" };
9-
let ps = createPlatformScript(() =>
10-
map({
11-
"extern": external(obj),
12-
})
13-
);
14-
expect((await ps.eval(parse("$extern"))).value).toBe(obj);
9+
let binding = map({
10+
"extern": external(obj),
11+
});
12+
13+
let ps = createPlatformScript();
14+
expect((await ps.eval(parse("$extern"), binding)).value).toBe(obj);
1515
});
1616

1717
it("can define new PS values from the external value", async () => {
1818
let obj = { I: { contain: { the: { number: number(5) } } } };
19-
let ps = createPlatformScript(() =>
20-
map({
21-
"truly": external(obj, (path, o) => _.get(o, path)),
22-
})
23-
);
19+
let binding = map({
20+
"truly": external(obj, (path, o) => _.get(o, path)),
21+
});
22+
let ps = createPlatformScript();
2423

2524
let program = parse("$truly.I.contain.the.number");
26-
expect((await ps.eval(program)).value).toEqual(5);
25+
expect((await ps.eval(program, binding)).value).toEqual(5);
2726
});
2827
it("errors if a dereference is undefined", async () => {
29-
let ps = createPlatformScript(() =>
30-
map({
31-
"oops": external({}, () => void 0),
32-
})
33-
);
34-
try {
35-
await ps.eval(parse("$oops.i.did.it.again"));
36-
throw new Error("expected block to throw, but it did not");
37-
} catch (error) {
38-
expect(error.name).toEqual("ReferenceError");
39-
}
28+
let binding = map({
29+
"oops": external({}, () => void 0),
30+
});
31+
let ps = createPlatformScript();
32+
33+
await expect(ps.eval(parse("$oops.i.did.it.again"), binding)).rejects
34+
.toHaveProperty("name", "ReferenceError");
4035
});
4136
it("errors if a derefenence does not return a PSValue", async () => {
42-
let ps = createPlatformScript(() =>
43-
map({
44-
"oops": external(
45-
{ wrong: "type" },
46-
//@ts-expect-error situation could happen if you are using JavaScript...
47-
() => ({ type: "WAT!!", value: "hi" }),
48-
),
49-
})
37+
let binding = map({
38+
"oops": external(
39+
{ wrong: "type" },
40+
//@ts-expect-error situation could happen if you are using JavaScript...
41+
() => ({ type: "WAT!!", value: "hi" }),
42+
),
43+
});
44+
let ps = createPlatformScript();
45+
await expect(ps.eval(parse("$oops.wrong"), binding)).rejects.toHaveProperty(
46+
"name",
47+
"TypeError",
5048
);
51-
52-
try {
53-
await ps.eval(parse("$oops.wrong"));
54-
throw new Error("expected block to throw, but it did not");
55-
} catch (error) {
56-
expect(error.message).toMatch(
57-
/did not resolve to a platformscript value/,
58-
);
59-
expect(error.name).toEqual("TypeError");
60-
}
6149
});
6250
// it("can handle an exception that happens during dereference");
6351
});

test/fn.test.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,12 @@ $say: Hello
7373
});
7474

7575
it("can reference values from arguments to native functions", async () => {
76-
let interp = ps.createPlatformScript(() =>
77-
ps.map({
78-
id: ps.fn(function* $id({ arg, env }) {
79-
return yield* env.eval(arg);
80-
}, { name: "x" }),
81-
})
82-
);
76+
let binding = ps.map({
77+
id: ps.fn(function* $id({ arg, env }) {
78+
return yield* env.eval(arg);
79+
}, { name: "x" }),
80+
});
81+
let interp = ps.createPlatformScript();
8382

8483
let program = ps.parse(`
8584
$let:
@@ -89,7 +88,7 @@ $do:
8988
$myid: hello world
9089
`);
9190

92-
let result = await interp.eval(program);
91+
let result = await interp.eval(program, binding);
9392
expect(result.value).toEqual("hello world");
9493
});
9594

test/module.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { PSMap, PSModule } from "../types.ts";
22
import type { Task } from "../deps.ts";
33

44
import { describe, expect, it, useStaticFileServer } from "./suite.ts";
5-
import { load, moduleEval, number, parse, ps2js, string } from "../mod.ts";
5+
import { load, map, moduleEval, number, parse, ps2js, string } from "../mod.ts";
66
import { run } from "../deps.ts";
77
import { lookup, lookup$ } from "../psmap.ts";
88

@@ -101,6 +101,18 @@ main: $myfive
101101
expect(lookup$("main", mod.value)).toEqual(number(5));
102102
});
103103
});
104+
105+
it("supports importing from the canonical module", async () => {
106+
await run(function* () {
107+
let source = parse(`$import:\n five: --canon--\nhi: $five`);
108+
let mod = yield* moduleEval({
109+
source,
110+
location: new URL(`modules/virtual-module.yaml`, import.meta.url),
111+
canon: map({ "five": number(5) }),
112+
});
113+
expect(lookup$("hi", mod.value)).toEqual(number(5));
114+
});
115+
});
104116
});
105117

106118
function loadmod(url: string): Task<PSModule> {

test/suite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export * from "https://deno.land/std@0.145.0/testing/bdd.ts";
2-
export { expect } from "https://deno.land/x/expect@v0.2.9/mod.ts";
2+
export { expect } from "https://deno.land/x/expect@v0.3.0/mod.ts";
33
export * from "https://deno.land/std@0.165.0/testing/asserts.ts";
44

55
import { createPlatformScript, js2ps, parse, ps2js, PSMap } from "../mod.ts";

types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export interface PSEnv {
77
}
88

99
export interface PSModule {
10-
url: URL;
10+
location: string;
1111
source: PSValue;
1212
value: PSValue;
1313
imports: {

0 commit comments

Comments
 (0)