-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnode.mjs
162 lines (129 loc) · 4.94 KB
/
node.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// quick & dirty test for local nodejs usage
// should work the same in browsers too
import { load, Prolog, atom, Compound, toJSON } from '../trealla.js';
await load();
// create new Prolog interpreter
const pl = new Prolog({
library: "/lib", // optionally specify library directory ("/library" by default)
env: {
// environment variables (grab them with getenv/2)
GREET: 'greetings'
}
});
// create a file in the virtual filesystem
pl.fs.open("/greeting.pl", { write: true, create: true }).writeString(`
:- module(greeting, [hello/1]).
:- dynamic(hello/1).
hello(world).
hello(世界).
`);
// custom library we can load from the use_module(library(...)) directive
pl.fs.createDir("/lib");
pl.fs.open("/lib/test.pl", { write: true, create: true }).writeString(`library(ok).`);
// mortal(Who), format("All humans are mortal. ~s is human. Hence, %s is mortal.").
// consult the file we just created. "greeting" or "/greeting.pl" both work
await pl.consult("greeting");
// assert some dynamic facts
console.log(await pl.queryOnce("assertz(lang(prolog)), greeting:assertz(hello('Welt'))."));
// { status: 'success', answer: {}, output: '' } // as in the regular toplevel's "true."
// run a query on the file we loaded and facts we asserted
await dumpQuery(
pl.query(`use_module(greeting), hello(Planet), lang(Lang), format("hello ~w from ~w!~n", [Planet, Lang]).`, {encode: {atoms: "string"}}));
/*
{
status: 'success',
answer: { Planet: 'world', Lang: 'prolog' },
output: 'hello world from prolog!\n'
}
{
status: 'success',
answer: { Planet: '世界', Lang: 'prolog' },
output: 'hello 世界 from prolog!\n'
}
{
status: 'success',
answer: { Planet: 'Welt', Lang: 'prolog' },
output: 'hello Welt from prolog!\n'
}
*/
await dumpQuery(pl.query("use_module(library(test)), library(Status)."));
/*
{ status: 'success', answer: { Status: 'ok' }, output: '' }
*/
// testing the optional "program" parameter which is consulted before the query is run
await dumpQuery(pl.query("🤠 howdy.", {
program: `
:- op(201, fy, 🤠).
🤠(X) :- format("yee haw ~w~n", [X]).`
}));
/*
{ status: 'success', answer: {}, output: 'yee haw howdy\n' }
*/
// multiple async queries:
const q1 = pl.query("between(0,9,X).");
const q2 = pl.query("between(10,19,N).");
await q1.next();
await q2.next();
console.log(await q1.next()); // X=1
console.log(await q2.next()); // N=11
// kill queries
await q1.return();
await q2.return();
// Prolog-format toplevel
await dumpQuery(
pl.query(`use_module(greeting), hello(Planet), lang(Lang), format("hello ~w from ~w!~n", [Planet, Lang]).`, {
format: "prolog"
})
);
// residual goals
for await (const answer of pl.query(`dif(A, B) ; dif(C, D).`, {format: "prolog"})) {
console.log(answer);
};
// console.log(await pl.queryOnce("throw(test).", {format: "prolog"}));
console.log(await pl.queryOnce("true.", {format: "prolog"}));
console.log(await pl.queryOnce("fail.", {format: "prolog"}));
// getenv/2
console.log(await pl.queryOnce("getenv('GREET', X).", {format: "prolog"}));
// trace
console.log(await pl.queryOnce("trace, findall(X, between(1,10,X), Xs).", {format: "prolog"}));
// boolean
console.log(await pl.queryOnce("T = {true}, F = {false}, N = {null}.", {format: "json", encode: {booleans: "{}", nulls: "{}"}}));
console.log(await pl.queryOnce("T = @true, F = @false, N = @null.", {program: ":- op(201, fx, @).", format: "json", encode: {booleans: "@", nulls: "@"}}));
// singleton warning
console.dir(await pl.queryOnce("x(X).", {program: "x(A) :- atom(B).", format: "json"}), {depth: null});
// TODO: this reports the last module loaded as the error location which is kinda confusing
console.dir(await pl.queryOnce("syntax error :-", {format: "prolog"}), {depth: null});
console.dir(await pl.queryOnce("write(X), nl, write(Y), nl, write(Z).", {
bind: {"X": 123, "Y": atom`hello`, "Z": new Compound("mortal", ["socrates"])}
}));
const got = (await pl.queryOnce("write(X), X=Y, Z=abc(def(xx, 123), Q), dif(W,T).", {})).answer;
for (const [k, v] of Object.entries(got)) {
console.dir({key: k, val: v, pl: v.toProlog()}, {depth: null});
}
const greeting = await pl.queryOnce('format("hello ~a", [X])', {bind: {X: atom`world`}});
console.log(greeting.stdout); // "hello world"
// bigint
const thicc = await pl.queryOnce("X=9999999999999999, Y = -9999999999999999, Z = 123", {format: "json"});
console.dir(thicc, {depth: null});
console.log(toJSON(thicc));
console.dir(await pl.queryOnce("throw(test).", {format: "json"}), {depth: null});
console.dir(await pl.queryOnce("X = foo(a, '').", {format: "json"}), {depth: null});
// json parsing/generating
await dumpQuery(
pl.query(`json_chars(X, "{\\"abc\\":-1, \\"foo\\":-555}").`, {
format: "prolog"
})
);
await dumpQuery(
pl.query(`write_term_to_chars("\\x3\\", [json(true)], Cs).`, {
format: "prolog"
})
);
async function dumpQuery(query) {
for await (const answer of query) {
console.log(answer);
if (answer.error) {
console.log(JSON.stringify(answer));
}
}
}