@graffiticode/parser 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/src/config/config.d.ts +3 -0
- package/dist/api/src/config/config.js +4 -0
- package/dist/api/src/config/config.js.map +1 -0
- package/dist/api/src/config/index.d.ts +1 -0
- package/dist/api/src/config/index.js +3 -0
- package/dist/api/src/config/index.js.map +1 -0
- package/dist/api/src/lang/base-url.d.ts +7 -0
- package/dist/api/src/lang/base-url.js +24 -0
- package/dist/api/src/lang/base-url.js.map +1 -0
- package/dist/api/src/lang/compile.d.ts +4 -0
- package/dist/api/src/lang/compile.js +6 -0
- package/dist/api/src/lang/compile.js.map +1 -0
- package/dist/api/src/lang/get-asset.d.ts +4 -0
- package/dist/api/src/lang/get-asset.js +9 -0
- package/dist/api/src/lang/get-asset.js.map +1 -0
- package/dist/api/src/lang/index.d.ts +4 -0
- package/dist/api/src/lang/index.js +22 -0
- package/dist/api/src/lang/index.js.map +1 -0
- package/dist/api/src/lang/ping-lang.d.ts +5 -0
- package/dist/api/src/lang/ping-lang.js +31 -0
- package/dist/api/src/lang/ping-lang.js.map +1 -0
- package/dist/api/src/util.d.ts +23 -0
- package/dist/api/src/util.js +187 -0
- package/dist/api/src/util.js.map +1 -0
- package/dist/parser/src/ast.d.ts +58 -0
- package/dist/parser/src/ast.js +683 -0
- package/dist/parser/src/ast.js.map +1 -0
- package/dist/parser/src/env.d.ts +8 -0
- package/dist/parser/src/env.js +38 -0
- package/dist/parser/src/env.js.map +1 -0
- package/dist/parser/src/fold.d.ts +4 -0
- package/dist/parser/src/fold.js +217 -0
- package/dist/parser/src/fold.js.map +1 -0
- package/dist/parser/src/folder.d.ts +30 -0
- package/dist/parser/src/folder.js +231 -0
- package/dist/parser/src/folder.js.map +1 -0
- package/dist/parser/src/index.d.ts +5 -0
- package/dist/parser/src/index.js +6 -0
- package/dist/parser/src/index.js.map +1 -0
- package/dist/parser/src/parse.d.ts +56 -0
- package/dist/parser/src/parse.js +902 -0
- package/dist/parser/src/parse.js.map +1 -0
- package/dist/parser/src/parser.d.ts +17 -0
- package/dist/parser/src/parser.js +89 -0
- package/dist/parser/src/parser.js.map +1 -0
- package/dist/parser/src/parserForTests.d.ts +3 -0
- package/dist/parser/src/parserForTests.js +4 -0
- package/dist/parser/src/parserForTests.js.map +1 -0
- package/dist/parser/src/stringstream.d.ts +10 -0
- package/dist/parser/src/stringstream.js +21 -0
- package/dist/parser/src/stringstream.js.map +1 -0
- package/dist/parser/src/testing/index.d.ts +2 -0
- package/dist/parser/src/testing/index.js +17 -0
- package/dist/parser/src/testing/index.js.map +1 -0
- package/dist/parser/src/types.d.ts +44 -0
- package/dist/parser/src/types.js +2 -0
- package/dist/parser/src/types.js.map +1 -0
- package/package.json +2 -4
- package/src/ast.js +724 -0
- package/src/env.js +46 -0
- package/src/folder.js +244 -0
- package/src/parse.js +35 -935
- package/src/parse.ts~ +1037 -0
- package/src/{parser.js~ → parser.ts~} +25 -7
- package/src/stringstream.js +22 -0
- package/src/fold.js +0 -235
- package/src/parser.spec.js~ +0 -175
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import vm from "vm";
|
|
2
|
-
import { getLangAsset } from "
|
|
3
|
-
|
|
2
|
+
import { getLangAsset } from "../../api/src/lang/index.js";
|
|
3
|
+
// Import parse module
|
|
4
|
+
import parse from "./parse";
|
|
5
|
+
|
|
6
|
+
// Define interfaces
|
|
7
|
+
interface ParserOptions {
|
|
8
|
+
log: (message: string, ...args: any[]) => void;
|
|
9
|
+
cache: Map<string, any>;
|
|
10
|
+
getLangAsset: (lang: string, path: string) => Promise<any>;
|
|
11
|
+
main: MainParser;
|
|
12
|
+
vm: typeof vm;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface MainParser {
|
|
16
|
+
parse: (src: string, lexicon: any) => any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Parser {
|
|
20
|
+
parse: (lang: string, src: string) => Promise<any>;
|
|
21
|
+
}
|
|
4
22
|
|
|
5
23
|
// commonjs export
|
|
6
|
-
const main = {
|
|
7
|
-
parse(src, lexicon) {
|
|
24
|
+
const main: MainParser = {
|
|
25
|
+
parse(src: string, lexicon: any) {
|
|
8
26
|
const stream = new parse.StringStream(src);
|
|
9
27
|
const state = {
|
|
10
28
|
cc: parse.program, // top level parsing function
|
|
@@ -49,9 +67,9 @@ export const buildParser = ({
|
|
|
49
67
|
getLangAsset,
|
|
50
68
|
main,
|
|
51
69
|
vm
|
|
52
|
-
}) => {
|
|
70
|
+
}: ParserOptions): Parser => {
|
|
53
71
|
return {
|
|
54
|
-
async parse(lang, src) {
|
|
72
|
+
async parse(lang: string, src: string) {
|
|
55
73
|
if (!cache.has(lang)) {
|
|
56
74
|
let data = await getLangAsset(lang, "/lexicon.js");
|
|
57
75
|
// TODO Make lexicon JSON.
|
|
@@ -69,7 +87,7 @@ export const buildParser = ({
|
|
|
69
87
|
} catch (err) {
|
|
70
88
|
if (err instanceof SyntaxError) {
|
|
71
89
|
log(`failed to parse ${lang} lexicon: ${err.message}`);
|
|
72
|
-
const context = { window: { gcexports: {} } };
|
|
90
|
+
const context = { window: { gcexports: { globalLexicon: null } } };
|
|
73
91
|
vm.createContext(context);
|
|
74
92
|
vm.runInContext(data, context);
|
|
75
93
|
if (typeof (context.window.gcexports.globalLexicon) === "object") {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export class StringStream {
|
|
2
|
+
constructor(string, tabSize = 2) {
|
|
3
|
+
this.pos = 0;
|
|
4
|
+
this.start = 0;
|
|
5
|
+
this.string = string;
|
|
6
|
+
this.tabSize = tabSize;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
peek() {
|
|
10
|
+
return this.string.charAt(this.pos) || undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
next() {
|
|
14
|
+
if (this.pos < this.string.length) {
|
|
15
|
+
return this.string.charAt(this.pos++);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
backUp(n) {
|
|
20
|
+
this.pos -= n;
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/fold.js
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import assert from "assert";
|
|
2
|
-
import { Ast, env } from "./parse.js";
|
|
3
|
-
|
|
4
|
-
export const folder = (function () {
|
|
5
|
-
const table = {
|
|
6
|
-
PROG: program,
|
|
7
|
-
EXPRS: exprs,
|
|
8
|
-
PAREN: parenExpr,
|
|
9
|
-
IDENT: ident,
|
|
10
|
-
BOOL: bool,
|
|
11
|
-
NUM: num,
|
|
12
|
-
STR: str,
|
|
13
|
-
PARENS: unaryExpr,
|
|
14
|
-
APPLY: apply,
|
|
15
|
-
LAMBDA: lambda,
|
|
16
|
-
// "MUL": mul,
|
|
17
|
-
// "DIV": div,
|
|
18
|
-
// "SUB": sub,
|
|
19
|
-
ADD: add,
|
|
20
|
-
POW: pow,
|
|
21
|
-
MOD: mod,
|
|
22
|
-
CONCAT: concat,
|
|
23
|
-
// "OR": orelse,
|
|
24
|
-
// "AND": andalso,
|
|
25
|
-
// "NE": ne,
|
|
26
|
-
// "EQ": eq,
|
|
27
|
-
// "LT": lt,
|
|
28
|
-
// "GT": gt,
|
|
29
|
-
// "LE": le,
|
|
30
|
-
// "GE": ge,
|
|
31
|
-
NEG: neg,
|
|
32
|
-
LIST: list
|
|
33
|
-
// "CASE": caseExpr,
|
|
34
|
-
// "OF": ofClause,
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
let nodePool;
|
|
38
|
-
let ctx;
|
|
39
|
-
|
|
40
|
-
function fold(cx, nid) {
|
|
41
|
-
ctx = cx;
|
|
42
|
-
nodePool = ctx.state.nodePool;
|
|
43
|
-
visit(nid);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function visit(nid) {
|
|
47
|
-
const node = nodePool[nid];
|
|
48
|
-
if (!node) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
if (node.tag === undefined) {
|
|
52
|
-
return []; // clean up stubs;
|
|
53
|
-
} else if (isFunction(table[node.tag])) {
|
|
54
|
-
// Have a primitive operation so apply it to construct a new node.
|
|
55
|
-
const ret = table[node.tag](node);
|
|
56
|
-
return ret;
|
|
57
|
-
}
|
|
58
|
-
expr(node);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function isFunction(v) {
|
|
62
|
-
return v instanceof Function;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// BEGIN VISITOR METHODS
|
|
66
|
-
|
|
67
|
-
function program(node) {
|
|
68
|
-
visit(node.elts[0]);
|
|
69
|
-
Ast.program(ctx);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function pushNodeStack(ctx) {
|
|
73
|
-
ctx.state.nodeStackStack.push(ctx.state.nodeStack);
|
|
74
|
-
ctx.state.nodeStack = [];
|
|
75
|
-
}
|
|
76
|
-
function popNodeStack(ctx) {
|
|
77
|
-
const stack = ctx.state.nodeStack;
|
|
78
|
-
ctx.state.nodeStack = ctx.state.nodeStackStack.pop().concat(stack);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function list(node) {
|
|
82
|
-
// Fold list
|
|
83
|
-
// for (var i = 0; i < node.elts.length; i++) {
|
|
84
|
-
// visit(node.elts[i]);
|
|
85
|
-
// }
|
|
86
|
-
pushNodeStack(ctx);
|
|
87
|
-
for (let i = node.elts.length - 1; i >= 0; i--) {
|
|
88
|
-
visit(node.elts[i]); // Keep original order.
|
|
89
|
-
}
|
|
90
|
-
Ast.list(ctx, ctx.state.nodeStack.length, null, true);
|
|
91
|
-
popNodeStack(ctx);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function exprs(node) {
|
|
95
|
-
// Fold exprs in reverse order to get precedence right.
|
|
96
|
-
for (let i = node.elts.length - 1; i >= 0; i--) {
|
|
97
|
-
visit(node.elts[i]); // Keep original order.
|
|
98
|
-
}
|
|
99
|
-
ctx.state.exprc = node.elts.length;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function lambda(node) {
|
|
103
|
-
// Fold initializers and apply args.
|
|
104
|
-
const inits = Ast.node(ctx, node.elts[3]).elts;
|
|
105
|
-
inits.forEach((init, i) => {
|
|
106
|
-
if (init) {
|
|
107
|
-
// If we have an init then fold it and replace in inits list.
|
|
108
|
-
folder.fold(ctx, Ast.intern(ctx, init));
|
|
109
|
-
inits[i] = Ast.pop(ctx);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
// FIXME don't patch old node. construct a new one.
|
|
113
|
-
node.elts[3] = Ast.intern(ctx, { tag: "LIST", elts: inits });
|
|
114
|
-
const fnId = Ast.intern(ctx, node);
|
|
115
|
-
const argc = ctx.state.nodeStack.length;
|
|
116
|
-
Ast.apply(ctx, fnId, argc);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function apply(node) {
|
|
120
|
-
for (let i = node.elts.length - 1; i >= 0; i--) {
|
|
121
|
-
visit(node.elts[i]);
|
|
122
|
-
}
|
|
123
|
-
Ast.applyLate(ctx, node.elts.length);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function expr(node) {
|
|
127
|
-
// Construct an expression node for the compiler.
|
|
128
|
-
Ast.name(ctx, node.tag);
|
|
129
|
-
for (let i = node.elts.length - 1; i >= 0; i--) {
|
|
130
|
-
visit(node.elts[i]);
|
|
131
|
-
}
|
|
132
|
-
Ast.expr(ctx, node.elts.length);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function neg(node) {
|
|
136
|
-
visit(node.elts[0]);
|
|
137
|
-
Ast.neg(ctx);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function parenExpr(node) {
|
|
141
|
-
pushNodeStack(ctx);
|
|
142
|
-
visit(node.elts[0]);
|
|
143
|
-
Ast.parenExpr(ctx);
|
|
144
|
-
popNodeStack(ctx);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function unaryExpr(node) {
|
|
148
|
-
visit(node.elts[0]);
|
|
149
|
-
Ast.unaryExpr(ctx, node.tag);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function add(node) {
|
|
153
|
-
visit(node.elts[0]);
|
|
154
|
-
visit(node.elts[1]);
|
|
155
|
-
Ast.add(ctx);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function pow(node) {
|
|
159
|
-
visit(node.elts[0]);
|
|
160
|
-
visit(node.elts[1]);
|
|
161
|
-
Ast.pow(ctx);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function concat(node) {
|
|
165
|
-
visit(node.elts[0]);
|
|
166
|
-
Ast.concat(ctx);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function mod(node) {
|
|
170
|
-
visit(node.elts[0]);
|
|
171
|
-
visit(node.elts[1]);
|
|
172
|
-
Ast.mod(ctx);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function ident(node) {
|
|
176
|
-
const name = node.elts[0];
|
|
177
|
-
const word = env.findWord(ctx, name);
|
|
178
|
-
if (word) {
|
|
179
|
-
if (word.cls === "val") {
|
|
180
|
-
if (word.val) {
|
|
181
|
-
Ast.string(ctx, word.val); // strip quotes;
|
|
182
|
-
} else if (word.nid) {
|
|
183
|
-
let wrd;
|
|
184
|
-
if ((wrd = Ast.node(ctx, word.nid)).tag === "LAMBDA") {
|
|
185
|
-
const argc = wrd.elts[0].elts.length;
|
|
186
|
-
Ast.apply(ctx, word.nid, argc);
|
|
187
|
-
} else {
|
|
188
|
-
Ast.push(ctx, word.nid);
|
|
189
|
-
}
|
|
190
|
-
} else if (word.name) {
|
|
191
|
-
Ast.push(ctx, node);
|
|
192
|
-
} else {
|
|
193
|
-
// push the original node to be resolved later.
|
|
194
|
-
Ast.push(ctx, node);
|
|
195
|
-
}
|
|
196
|
-
} else if (word.cls === "function") {
|
|
197
|
-
const elts = [];
|
|
198
|
-
for (let i = 0; i < word.length; i++) {
|
|
199
|
-
const elt = Ast.pop(ctx);
|
|
200
|
-
elts.push(elt);
|
|
201
|
-
}
|
|
202
|
-
if (word.nid) {
|
|
203
|
-
Ast.fold(ctx, word, elts);
|
|
204
|
-
} else {
|
|
205
|
-
Ast.push(ctx, {
|
|
206
|
-
tag: word.name,
|
|
207
|
-
elts
|
|
208
|
-
});
|
|
209
|
-
folder.fold(ctx, Ast.pop(ctx));
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
assert(false);
|
|
213
|
-
}
|
|
214
|
-
} else {
|
|
215
|
-
// assert(false, "unresolved ident "+name);
|
|
216
|
-
Ast.push(ctx, node);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function num(node) {
|
|
221
|
-
Ast.number(ctx, node.elts[0]);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function str(node) {
|
|
225
|
-
Ast.string(ctx, node.elts[0]);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function bool(node) {
|
|
229
|
-
Ast.bool(ctx, node.elts[0]);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
fold
|
|
234
|
-
};
|
|
235
|
-
}());
|
package/src/parser.spec.js~
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { jest } from "@jest/globals";
|
|
2
|
-
import { parser, buildParser } from "./parser.js";
|
|
3
|
-
import { mockPromiseValue, mockPromiseError } from "../testing/index.js";
|
|
4
|
-
|
|
5
|
-
describe("lang/parser", () => {
|
|
6
|
-
const log = jest.fn();
|
|
7
|
-
it("should call main parser language lexicon", async () => {
|
|
8
|
-
// Arrange
|
|
9
|
-
const cache = new Map();
|
|
10
|
-
const getLangAsset = mockPromiseValue("{}");
|
|
11
|
-
const main = {
|
|
12
|
-
parse: mockPromiseValue({ root: "0" })
|
|
13
|
-
};
|
|
14
|
-
const parser = buildParser({ log, cache, getLangAsset, main });
|
|
15
|
-
const lang = "0";
|
|
16
|
-
const src = "'foo'..";
|
|
17
|
-
|
|
18
|
-
// Act
|
|
19
|
-
await expect(parser.parse(lang, src)).resolves.toStrictEqual({ root: "0" });
|
|
20
|
-
|
|
21
|
-
// Assert
|
|
22
|
-
expect(getLangAsset).toHaveBeenCalledWith(lang, "/lexicon.js");
|
|
23
|
-
expect(main.parse).toHaveBeenCalledWith(src, {});
|
|
24
|
-
expect(cache.has(lang)).toBe(true);
|
|
25
|
-
expect(cache.get(lang)).toStrictEqual({});
|
|
26
|
-
});
|
|
27
|
-
it("should call main parser cached lexicon", async () => {
|
|
28
|
-
// Arrange
|
|
29
|
-
const cache = new Map();
|
|
30
|
-
const main = {
|
|
31
|
-
parse: mockPromiseValue({ root: "0" })
|
|
32
|
-
};
|
|
33
|
-
const parser = buildParser({
|
|
34
|
-
cache,
|
|
35
|
-
main
|
|
36
|
-
});
|
|
37
|
-
const lang = "0";
|
|
38
|
-
const src = "'foo'..";
|
|
39
|
-
cache.set(lang, {});
|
|
40
|
-
|
|
41
|
-
// Act
|
|
42
|
-
await expect(parser.parse(lang, src)).resolves.toStrictEqual({ root: "0" });
|
|
43
|
-
|
|
44
|
-
// Assert
|
|
45
|
-
expect(main.parse).toHaveBeenCalledWith(src, {});
|
|
46
|
-
});
|
|
47
|
-
it("should return error if get language asset fails", async () => {
|
|
48
|
-
// Arrange
|
|
49
|
-
const cache = new Map();
|
|
50
|
-
const err = new Error("failed to get lexicon");
|
|
51
|
-
const getLangAsset = mockPromiseError(err);
|
|
52
|
-
const parser = buildParser({
|
|
53
|
-
cache,
|
|
54
|
-
getLangAsset
|
|
55
|
-
});
|
|
56
|
-
const lang = "00";
|
|
57
|
-
const src = "'foo'..";
|
|
58
|
-
|
|
59
|
-
// Act
|
|
60
|
-
await expect(parser.parse(lang, src)).rejects.toBe(err);
|
|
61
|
-
|
|
62
|
-
// Assert
|
|
63
|
-
expect(getLangAsset).toHaveBeenCalledWith(lang, "/lexicon.js");
|
|
64
|
-
});
|
|
65
|
-
it("should return error if main parser fails", async () => {
|
|
66
|
-
// Arrange
|
|
67
|
-
const log = jest.fn();
|
|
68
|
-
const cache = new Map();
|
|
69
|
-
const getLangAsset = mockPromiseValue("{}");
|
|
70
|
-
const err = new Error("main parser failed");
|
|
71
|
-
const main = { parse: mockPromiseError(err) };
|
|
72
|
-
const parser = buildParser({ log, cache, getLangAsset, main });
|
|
73
|
-
const lang = "0";
|
|
74
|
-
const src = "'foo'..";
|
|
75
|
-
|
|
76
|
-
// Act
|
|
77
|
-
await expect(parser.parse(lang, src)).rejects.toBe(err);
|
|
78
|
-
|
|
79
|
-
// Assert
|
|
80
|
-
expect(getLangAsset).toHaveBeenCalledWith(lang, "/lexicon.js");
|
|
81
|
-
expect(main.parse).toHaveBeenCalledWith(src, {});
|
|
82
|
-
expect(cache.has(lang)).toBe(true);
|
|
83
|
-
expect(cache.get(lang)).toStrictEqual({});
|
|
84
|
-
});
|
|
85
|
-
it("should return succeed if lexicon is a buffer", async () => {
|
|
86
|
-
// Arrange
|
|
87
|
-
const log = jest.fn();
|
|
88
|
-
const cache = new Map();
|
|
89
|
-
const getLangAsset = mockPromiseValue(Buffer.from("{}"));
|
|
90
|
-
const ast = { root: "0" };
|
|
91
|
-
const main = { parse: mockPromiseValue(ast) };
|
|
92
|
-
const parser = buildParser({ log, cache, getLangAsset, main });
|
|
93
|
-
const lang = "0";
|
|
94
|
-
const src = "'foo'..";
|
|
95
|
-
|
|
96
|
-
// Act
|
|
97
|
-
await expect(parser.parse(lang, src)).resolves.toStrictEqual(ast);
|
|
98
|
-
|
|
99
|
-
// Assert
|
|
100
|
-
expect(getLangAsset).toHaveBeenCalledWith(lang, "/lexicon.js");
|
|
101
|
-
expect(main.parse).toHaveBeenCalledWith(src, {});
|
|
102
|
-
expect(cache.has(lang)).toBe(true);
|
|
103
|
-
expect(cache.get(lang)).toStrictEqual({});
|
|
104
|
-
});
|
|
105
|
-
it("should try vm if lexicon cannot parse JSON", async () => {
|
|
106
|
-
// Arrange
|
|
107
|
-
const log = jest.fn();
|
|
108
|
-
const cache = new Map();
|
|
109
|
-
const rawLexicon = `
|
|
110
|
-
(() => {
|
|
111
|
-
window.gcexports.globalLexicon = {};
|
|
112
|
-
})();
|
|
113
|
-
`;
|
|
114
|
-
const getLangAsset = mockPromiseValue(rawLexicon);
|
|
115
|
-
const ast = { root: "0" };
|
|
116
|
-
const main = { parse: mockPromiseValue(ast) };
|
|
117
|
-
const vm = {
|
|
118
|
-
createContext: jest.fn(),
|
|
119
|
-
runInContext: jest.fn().mockImplementation((data, context) => {
|
|
120
|
-
context.window.gcexports.globalLexicon = {};
|
|
121
|
-
})
|
|
122
|
-
};
|
|
123
|
-
const parser = buildParser({ log, cache, getLangAsset, main, vm });
|
|
124
|
-
const lang = "0";
|
|
125
|
-
const src = "'foo'..";
|
|
126
|
-
|
|
127
|
-
// Act
|
|
128
|
-
await expect(parser.parse(lang, src)).resolves.toStrictEqual(ast);
|
|
129
|
-
|
|
130
|
-
// Assert
|
|
131
|
-
expect(getLangAsset).toHaveBeenCalledWith(lang, "/lexicon.js");
|
|
132
|
-
expect(main.parse).toHaveBeenCalledWith(src, {});
|
|
133
|
-
expect(cache.has(lang)).toBe(true);
|
|
134
|
-
expect(cache.get(lang)).toStrictEqual({});
|
|
135
|
-
expect(vm.createContext).toHaveBeenCalled();
|
|
136
|
-
expect(vm.runInContext).toHaveBeenCalledWith(rawLexicon, expect.anything());
|
|
137
|
-
});
|
|
138
|
-
it.skip("should parse 'hello, world!'", async () => {
|
|
139
|
-
const lang = "0";
|
|
140
|
-
const src = "'hello, world'..";
|
|
141
|
-
const ast = {
|
|
142
|
-
1: {
|
|
143
|
-
elts: [
|
|
144
|
-
"hello, world"
|
|
145
|
-
],
|
|
146
|
-
tag: "STR"
|
|
147
|
-
},
|
|
148
|
-
2: {
|
|
149
|
-
elts: [
|
|
150
|
-
1
|
|
151
|
-
],
|
|
152
|
-
tag: "EXPRS"
|
|
153
|
-
},
|
|
154
|
-
3: {
|
|
155
|
-
elts: [
|
|
156
|
-
2
|
|
157
|
-
],
|
|
158
|
-
tag: "PROG"
|
|
159
|
-
},
|
|
160
|
-
root: 3
|
|
161
|
-
};
|
|
162
|
-
await expect(parser.parse(lang, src)).resolves.toStrictEqual(ast);
|
|
163
|
-
});
|
|
164
|
-
it.skip("should parse error", async () => {
|
|
165
|
-
const lang = "0";
|
|
166
|
-
const src = "'hello, world'";
|
|
167
|
-
await expect(parser.parse(lang, src)).rejects.toThrow("End of program reached");
|
|
168
|
-
});
|
|
169
|
-
// it("should parse error", async () => {
|
|
170
|
-
// const lang = "0";
|
|
171
|
-
// const src = "'hello, world..";
|
|
172
|
-
// const ast = {};
|
|
173
|
-
// await expect(parser.parse(lang, src)).rejects.toThrow("End of program reached");
|
|
174
|
-
// });
|
|
175
|
-
});
|