@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
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
import { Env } from "./env";
|
|
2
|
+
import { folder } from "./folder";
|
|
3
|
+
import { assertErr } from "./parse";
|
|
4
|
+
const ASSERT = true;
|
|
5
|
+
const assert = function (val, str) {
|
|
6
|
+
if (!ASSERT) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (str === undefined) {
|
|
10
|
+
str = "failed!";
|
|
11
|
+
}
|
|
12
|
+
if (!val) {
|
|
13
|
+
throw new Error(str);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
// Helper function not part of the class
|
|
17
|
+
function nodeToJSON(n) {
|
|
18
|
+
let obj;
|
|
19
|
+
if (typeof n === "object") {
|
|
20
|
+
switch (n.tag) {
|
|
21
|
+
case "num":
|
|
22
|
+
obj = n.elts[0];
|
|
23
|
+
break;
|
|
24
|
+
case "str":
|
|
25
|
+
obj = n.elts[0];
|
|
26
|
+
break;
|
|
27
|
+
default:
|
|
28
|
+
obj = {};
|
|
29
|
+
obj.tag = n.tag;
|
|
30
|
+
obj.elts = [];
|
|
31
|
+
for (let i = 0; i < n.elts.length; i++) {
|
|
32
|
+
obj.elts[i] = nodeToJSON(n.elts[i]);
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (typeof n === "string") {
|
|
38
|
+
obj = n;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
obj = n;
|
|
42
|
+
}
|
|
43
|
+
return obj;
|
|
44
|
+
}
|
|
45
|
+
export class Ast {
|
|
46
|
+
static push(ctx, node) {
|
|
47
|
+
let nid;
|
|
48
|
+
if (typeof node === "number") { // if already interned
|
|
49
|
+
nid = node;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
nid = Ast.intern(ctx, node);
|
|
53
|
+
}
|
|
54
|
+
ctx.state.nodeStack.push(nid);
|
|
55
|
+
}
|
|
56
|
+
static topNode(ctx) {
|
|
57
|
+
const nodeStack = ctx.state.nodeStack;
|
|
58
|
+
return nodeStack[nodeStack.length - 1];
|
|
59
|
+
}
|
|
60
|
+
static pop(ctx) {
|
|
61
|
+
const nodeStack = ctx.state.nodeStack;
|
|
62
|
+
return nodeStack.pop();
|
|
63
|
+
}
|
|
64
|
+
static peek(ctx, n) {
|
|
65
|
+
if (n === undefined) {
|
|
66
|
+
n = 0;
|
|
67
|
+
}
|
|
68
|
+
const nodeStack = ctx.state.nodeStack;
|
|
69
|
+
return nodeStack[nodeStack.length - 1 - n];
|
|
70
|
+
}
|
|
71
|
+
static intern(ctx, n) {
|
|
72
|
+
if (!n) {
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
const nodeMap = ctx.state.nodeMap;
|
|
76
|
+
const nodePool = ctx.state.nodePool;
|
|
77
|
+
const tag = n.tag;
|
|
78
|
+
let elts = "";
|
|
79
|
+
const count = n.elts.length;
|
|
80
|
+
for (let i = 0; i < count; i++) {
|
|
81
|
+
if (typeof n.elts[i] === "object") {
|
|
82
|
+
n.elts[i] = Ast.intern(ctx, n.elts[i]);
|
|
83
|
+
}
|
|
84
|
+
elts += n.elts[i];
|
|
85
|
+
}
|
|
86
|
+
const key = tag + count + elts;
|
|
87
|
+
let nid = nodeMap[key];
|
|
88
|
+
if (nid === undefined) {
|
|
89
|
+
nodePool.push({ tag, elts: n.elts });
|
|
90
|
+
nid = nodePool.length - 1;
|
|
91
|
+
nodeMap[key] = nid;
|
|
92
|
+
if (n.coord) {
|
|
93
|
+
ctx.state.coords[nid] = n.coord;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return nid;
|
|
97
|
+
}
|
|
98
|
+
static node(ctx, nid) {
|
|
99
|
+
const n = ctx.state.nodePool[nid];
|
|
100
|
+
if (!nid) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
else if (!n) {
|
|
104
|
+
return {};
|
|
105
|
+
}
|
|
106
|
+
const elts = [];
|
|
107
|
+
switch (n.tag) {
|
|
108
|
+
case "NULL":
|
|
109
|
+
break;
|
|
110
|
+
case "NUM":
|
|
111
|
+
case "STR":
|
|
112
|
+
case "IDENT":
|
|
113
|
+
case "BOOL":
|
|
114
|
+
elts[0] = n.elts[0];
|
|
115
|
+
break;
|
|
116
|
+
default:
|
|
117
|
+
for (let i = 0; i < n.elts.length; i++) {
|
|
118
|
+
elts[i] = Ast.node(ctx, n.elts[i]);
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
tag: n.tag,
|
|
124
|
+
elts,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
static dumpAll(ctx) {
|
|
128
|
+
const nodePool = ctx.state.nodePool;
|
|
129
|
+
let s = "\n{";
|
|
130
|
+
for (let i = 1; i < nodePool.length; i++) {
|
|
131
|
+
const n = nodePool[i];
|
|
132
|
+
s = s + "\n " + i + ": " + Ast.dump(n) + ",";
|
|
133
|
+
}
|
|
134
|
+
s += "\n root: " + (nodePool.length - 1);
|
|
135
|
+
s += "\n}\n";
|
|
136
|
+
return s;
|
|
137
|
+
}
|
|
138
|
+
static poolToJSON(ctx) {
|
|
139
|
+
const nodePool = ctx.state.nodePool;
|
|
140
|
+
const obj = {};
|
|
141
|
+
for (let i = 1; i < nodePool.length; i++) {
|
|
142
|
+
const n = nodePool[i];
|
|
143
|
+
obj[i] = nodeToJSON(n);
|
|
144
|
+
}
|
|
145
|
+
obj.root = (nodePool.length - 1);
|
|
146
|
+
return obj;
|
|
147
|
+
}
|
|
148
|
+
static dump(n) {
|
|
149
|
+
let s;
|
|
150
|
+
if (typeof n === "object") {
|
|
151
|
+
switch (n.tag) {
|
|
152
|
+
case "num":
|
|
153
|
+
s = n.elts[0];
|
|
154
|
+
break;
|
|
155
|
+
case "str":
|
|
156
|
+
s = "\"" + n.elts[0] + "\"";
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
if (!n.elts) {
|
|
160
|
+
s = "<invalid>";
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
s = "{ tag: \"" + n.tag + "\", elts: [ ";
|
|
164
|
+
for (let i = 0; i < n.elts.length; i++) {
|
|
165
|
+
if (i > 0) {
|
|
166
|
+
s += " , ";
|
|
167
|
+
}
|
|
168
|
+
s += Ast.dump(n.elts[i]);
|
|
169
|
+
}
|
|
170
|
+
s += " ] }";
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else if (typeof n === "string") {
|
|
176
|
+
s = "\"" + n + "\"";
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
s = String(n);
|
|
180
|
+
}
|
|
181
|
+
return s;
|
|
182
|
+
}
|
|
183
|
+
static fold(ctx, fn, args) {
|
|
184
|
+
// Local defs:
|
|
185
|
+
// -- put bindings in env
|
|
186
|
+
// Three cases:
|
|
187
|
+
// -- full application, all args are available at parse time
|
|
188
|
+
// -- partial application, only some args are available at parse time
|
|
189
|
+
// -- late application, args are available at compile time (not parse time)
|
|
190
|
+
// apply <[x y]: add x y> data..
|
|
191
|
+
// x: val 0 data
|
|
192
|
+
// y: val 1 data
|
|
193
|
+
Env.enterEnv(ctx, fn.name);
|
|
194
|
+
if (fn.env) {
|
|
195
|
+
const lexicon = fn.env.lexicon;
|
|
196
|
+
const pattern = Ast.node(ctx, fn.env.pattern);
|
|
197
|
+
let outerEnv = null;
|
|
198
|
+
// let isListPattern;
|
|
199
|
+
// setup inner environment record (lexicon)
|
|
200
|
+
if (pattern && pattern.elts &&
|
|
201
|
+
pattern.elts.length === 1 &&
|
|
202
|
+
pattern.elts[0].tag === "LIST") {
|
|
203
|
+
// For now we only support one pattern per param list.
|
|
204
|
+
// isListPattern = true;
|
|
205
|
+
}
|
|
206
|
+
for (const id in lexicon) {
|
|
207
|
+
// For each parameter, get its definition assign the value of the argument
|
|
208
|
+
// used on the current function application.
|
|
209
|
+
if (!id)
|
|
210
|
+
continue;
|
|
211
|
+
const word = JSON.parse(JSON.stringify(lexicon[id])); // poor man's copy.
|
|
212
|
+
const index = args.length - word.offset - 1;
|
|
213
|
+
// TODO we currently ignore list patterns
|
|
214
|
+
// if (isListPattern) {
|
|
215
|
+
// // <[x y]: ...> foo..
|
|
216
|
+
// word.nid = Ast.intern(ctx, {
|
|
217
|
+
// tag: "VAL",
|
|
218
|
+
// elts: [{
|
|
219
|
+
// tag: "NUM",
|
|
220
|
+
// elts: [
|
|
221
|
+
// String(word.offset),
|
|
222
|
+
// ]}, {
|
|
223
|
+
// tag: "ARG",
|
|
224
|
+
// elts: [{
|
|
225
|
+
// tag: "NUM",
|
|
226
|
+
// elts: ["0"]
|
|
227
|
+
// }]
|
|
228
|
+
// }]
|
|
229
|
+
// });
|
|
230
|
+
// } else
|
|
231
|
+
if (index >= 0 && index < args.length) {
|
|
232
|
+
word.nid = args[index];
|
|
233
|
+
}
|
|
234
|
+
if (index < 0) {
|
|
235
|
+
// We've got an unbound variable or a variable with a default value,
|
|
236
|
+
// so add it to the new variable list.
|
|
237
|
+
// <x:x> => <x:x>
|
|
238
|
+
// (<x y: add x y> 10) => <y: add 10 y>
|
|
239
|
+
// (<y: let x = 10.. add x y>) => <y: add 10 y>
|
|
240
|
+
if (!outerEnv) {
|
|
241
|
+
outerEnv = {};
|
|
242
|
+
}
|
|
243
|
+
outerEnv[id] = word;
|
|
244
|
+
}
|
|
245
|
+
Env.addWord(ctx, id, word);
|
|
246
|
+
}
|
|
247
|
+
folder.fold(ctx, fn.nid);
|
|
248
|
+
if (outerEnv) {
|
|
249
|
+
Ast.lambda(ctx, {
|
|
250
|
+
lexicon: outerEnv,
|
|
251
|
+
pattern // FIXME need to trim pattern if some args where applied.
|
|
252
|
+
}, Ast.pop(ctx));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
Env.exitEnv(ctx);
|
|
256
|
+
}
|
|
257
|
+
static applyLate(ctx, count) {
|
|
258
|
+
// Ast.applyLate
|
|
259
|
+
const elts = [];
|
|
260
|
+
for (let i = count; i > 0; i--) {
|
|
261
|
+
elts.push(Ast.pop(ctx));
|
|
262
|
+
}
|
|
263
|
+
Ast.push(ctx, {
|
|
264
|
+
tag: "APPLY",
|
|
265
|
+
elts
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
static apply(ctx, fnId, argc) {
|
|
269
|
+
// Construct function and apply available arguments.
|
|
270
|
+
const fn = Ast.node(ctx, fnId);
|
|
271
|
+
// if (fn.tag !== "LAMBDA") {
|
|
272
|
+
// // Construct an APPLY node for compiling later.
|
|
273
|
+
// return {
|
|
274
|
+
// tag: "APPLY",
|
|
275
|
+
// elts: [
|
|
276
|
+
// fnId,
|
|
277
|
+
// ]
|
|
278
|
+
// };
|
|
279
|
+
// }
|
|
280
|
+
// Construct a lexicon
|
|
281
|
+
const lexicon = {};
|
|
282
|
+
let paramc = 0;
|
|
283
|
+
fn.elts[0].elts.forEach(function (n, i) {
|
|
284
|
+
const name = n.elts[0];
|
|
285
|
+
const nid = Ast.intern(ctx, fn.elts[3].elts[i]);
|
|
286
|
+
lexicon[name] = {
|
|
287
|
+
cls: "val",
|
|
288
|
+
name,
|
|
289
|
+
offset: i,
|
|
290
|
+
nid
|
|
291
|
+
};
|
|
292
|
+
if (!nid) {
|
|
293
|
+
// Parameters don't have nids.
|
|
294
|
+
// assert that there are parameters after a binding without a nid.
|
|
295
|
+
paramc++;
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
const def = {
|
|
299
|
+
name: "lambda",
|
|
300
|
+
nid: Ast.intern(ctx, fn.elts[1]),
|
|
301
|
+
env: {
|
|
302
|
+
lexicon,
|
|
303
|
+
pattern: Ast.intern(ctx, fn.elts[2])
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
const elts = [];
|
|
307
|
+
// While there are args on the stack, pop them.
|
|
308
|
+
while (argc-- > 0 && paramc-- > 0) {
|
|
309
|
+
const elt = Ast.pop(ctx);
|
|
310
|
+
elts.unshift(elt); // Get the order right.
|
|
311
|
+
}
|
|
312
|
+
Ast.fold(ctx, def, elts);
|
|
313
|
+
}
|
|
314
|
+
// Node constructors
|
|
315
|
+
static error(ctx, str, coord) {
|
|
316
|
+
console.log("error()", "str=" + str, "coord=" + JSON.stringify(coord));
|
|
317
|
+
const from = coord?.from !== undefined ? coord.from : -1;
|
|
318
|
+
const to = coord?.to !== undefined ? coord.to : -1;
|
|
319
|
+
Ast.number(ctx, to);
|
|
320
|
+
Ast.number(ctx, from);
|
|
321
|
+
Ast.string(ctx, str, coord);
|
|
322
|
+
Ast.push(ctx, {
|
|
323
|
+
tag: "ERROR",
|
|
324
|
+
elts: [
|
|
325
|
+
Ast.pop(ctx),
|
|
326
|
+
Ast.pop(ctx),
|
|
327
|
+
Ast.pop(ctx),
|
|
328
|
+
],
|
|
329
|
+
coord
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
static bool(ctx, val) {
|
|
333
|
+
let b;
|
|
334
|
+
if (val) {
|
|
335
|
+
b = true;
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
b = false;
|
|
339
|
+
}
|
|
340
|
+
Ast.push(ctx, {
|
|
341
|
+
tag: "BOOL",
|
|
342
|
+
elts: [b]
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
static nul(ctx) {
|
|
346
|
+
Ast.push(ctx, {
|
|
347
|
+
tag: "NULL",
|
|
348
|
+
elts: []
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
static number(ctx, num, coord) {
|
|
352
|
+
assert(typeof num === "string" || typeof num === "number");
|
|
353
|
+
Ast.push(ctx, {
|
|
354
|
+
tag: "NUM",
|
|
355
|
+
elts: [String(num)],
|
|
356
|
+
coord
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
static string(ctx, str, coord) {
|
|
360
|
+
Ast.push(ctx, {
|
|
361
|
+
tag: "STR",
|
|
362
|
+
elts: [str],
|
|
363
|
+
coord
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
static setName(ctx, name, coord) {
|
|
367
|
+
Ast.push(ctx, {
|
|
368
|
+
tag: "IDENT",
|
|
369
|
+
elts: [name],
|
|
370
|
+
coord
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
static expr(ctx, argc) {
|
|
374
|
+
// Ast.expr -- construct a expr node for the compiler.
|
|
375
|
+
const elts = [];
|
|
376
|
+
const pos = 1; // FIXME
|
|
377
|
+
console.trace("expr()", "argc=" + argc, "nodeStack=" + JSON.stringify(ctx.state.nodeStack, null, 2));
|
|
378
|
+
assertErr(ctx, argc <= ctx.state.nodeStack.length - 1, `Too few arguments. Expected ${argc} got ${ctx.state.nodeStack.length - 1}.`, {
|
|
379
|
+
from: pos - 1, to: pos
|
|
380
|
+
});
|
|
381
|
+
while (argc--) {
|
|
382
|
+
const elt = Ast.pop(ctx);
|
|
383
|
+
elts.push(elt);
|
|
384
|
+
}
|
|
385
|
+
const nameId = Ast.pop(ctx);
|
|
386
|
+
console.log("expr()", "nameId=" + nameId);
|
|
387
|
+
assertErr(ctx, Boolean(nameId), "Ill formed node.");
|
|
388
|
+
const e = Ast.node(ctx, nameId).elts;
|
|
389
|
+
assertErr(ctx, e && e.length > 0, "Ill formed node.");
|
|
390
|
+
const name = e[0];
|
|
391
|
+
Ast.push(ctx, {
|
|
392
|
+
tag: name,
|
|
393
|
+
elts,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
static parenExpr(ctx, coord) {
|
|
397
|
+
// Ast.parenExpr
|
|
398
|
+
const elts = [];
|
|
399
|
+
const elt = Ast.pop(ctx);
|
|
400
|
+
elts.push(elt);
|
|
401
|
+
Ast.push(ctx, {
|
|
402
|
+
tag: "PAREN",
|
|
403
|
+
elts,
|
|
404
|
+
coord
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
static list(ctx, count, coord, reverse) {
|
|
408
|
+
// Ast.list
|
|
409
|
+
const elts = [];
|
|
410
|
+
for (let i = count; i > 0; i--) {
|
|
411
|
+
const elt = Ast.pop(ctx);
|
|
412
|
+
if (elt !== undefined) {
|
|
413
|
+
elts.push(elt);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
Ast.push(ctx, {
|
|
417
|
+
tag: "LIST",
|
|
418
|
+
elts: reverse ? elts : elts.reverse(),
|
|
419
|
+
coord
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
static binaryExpr(ctx, name) {
|
|
423
|
+
const elts = [];
|
|
424
|
+
// args are in the order produced by the parser
|
|
425
|
+
elts.push(Ast.pop(ctx));
|
|
426
|
+
elts.push(Ast.pop(ctx));
|
|
427
|
+
Ast.push(ctx, {
|
|
428
|
+
tag: name,
|
|
429
|
+
elts: elts.reverse()
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
static unaryExpr(ctx, name) {
|
|
433
|
+
const elts = [];
|
|
434
|
+
elts.push(Ast.pop(ctx));
|
|
435
|
+
Ast.push(ctx, {
|
|
436
|
+
tag: name,
|
|
437
|
+
elts
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
static prefixExpr(ctx, name) {
|
|
441
|
+
const elts = [];
|
|
442
|
+
elts.push(Ast.pop(ctx));
|
|
443
|
+
Ast.push(ctx, {
|
|
444
|
+
tag: name,
|
|
445
|
+
elts
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
static neg(ctx) {
|
|
449
|
+
const v1 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
450
|
+
Ast.number(ctx, -1 * v1);
|
|
451
|
+
}
|
|
452
|
+
static add(ctx, coord) {
|
|
453
|
+
const n2 = Ast.node(ctx, Ast.pop(ctx));
|
|
454
|
+
const n1 = Ast.node(ctx, Ast.pop(ctx));
|
|
455
|
+
const v2 = n2.elts[0];
|
|
456
|
+
const v1 = n1.elts[0];
|
|
457
|
+
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
458
|
+
Ast.push(ctx, {
|
|
459
|
+
tag: "ADD",
|
|
460
|
+
elts: [n1, n2],
|
|
461
|
+
coord
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
Ast.number(ctx, +v1 + +v2);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
static sub(ctx) {
|
|
469
|
+
const n2 = Ast.node(ctx, Ast.pop(ctx));
|
|
470
|
+
const n1 = Ast.node(ctx, Ast.pop(ctx));
|
|
471
|
+
const v2 = n2.elts[0];
|
|
472
|
+
const v1 = n1.elts[0];
|
|
473
|
+
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
474
|
+
Ast.push(ctx, { tag: "SUB", elts: [n1, n2] });
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
Ast.number(ctx, +v1 - +v2);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// static mul(ctx: Context): void {
|
|
481
|
+
// let n2 = Ast.node(ctx, Ast.pop(ctx));
|
|
482
|
+
// let n1 = Ast.node(ctx, Ast.pop(ctx));
|
|
483
|
+
// const v2 = n2.elts[0];
|
|
484
|
+
// const v1 = n1.elts[0];
|
|
485
|
+
// if (n1.tag === undefined) {
|
|
486
|
+
// n1 = n1.elts[0];
|
|
487
|
+
// }
|
|
488
|
+
// if (n2.tag === undefined) {
|
|
489
|
+
// n2 = n2.elts[0];
|
|
490
|
+
// }
|
|
491
|
+
// if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
492
|
+
// Ast.push(ctx, { tag: "MUL", elts: [n2, n1] });
|
|
493
|
+
// } else {
|
|
494
|
+
// Ast.number(ctx, +v1 * +v2);
|
|
495
|
+
// }
|
|
496
|
+
// }
|
|
497
|
+
static div(ctx) {
|
|
498
|
+
const n2 = Ast.node(ctx, Ast.pop(ctx));
|
|
499
|
+
const n1 = Ast.node(ctx, Ast.pop(ctx));
|
|
500
|
+
const v2 = n2.elts[0];
|
|
501
|
+
const v1 = n1.elts[0];
|
|
502
|
+
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
503
|
+
Ast.push(ctx, { tag: "DIV", elts: [n1, n2] });
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
Ast.number(ctx, +v1 / +v2);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
static mod(ctx) {
|
|
510
|
+
const n2 = Ast.node(ctx, Ast.pop(ctx));
|
|
511
|
+
const n1 = Ast.node(ctx, Ast.pop(ctx));
|
|
512
|
+
const v1 = n1.elts[0];
|
|
513
|
+
const v2 = n2.elts[0];
|
|
514
|
+
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
515
|
+
Ast.push(ctx, { tag: "MOD", elts: [n1, n2] });
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
Ast.number(ctx, +v1 % +v2);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
static pow(ctx) {
|
|
522
|
+
const n2 = Ast.node(ctx, Ast.pop(ctx));
|
|
523
|
+
const n1 = Ast.node(ctx, Ast.pop(ctx));
|
|
524
|
+
const v2 = n2.elts[0];
|
|
525
|
+
const v1 = n1.elts[0];
|
|
526
|
+
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
527
|
+
Ast.push(ctx, { tag: "POW", elts: [n1, n2] });
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
Ast.number(ctx, Math.pow(+v1, +v2));
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
static concat(ctx) {
|
|
534
|
+
const n1 = Ast.node(ctx, Ast.pop(ctx));
|
|
535
|
+
Ast.push(ctx, {
|
|
536
|
+
tag: "CONCAT",
|
|
537
|
+
elts: [n1]
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
static eq(ctx) {
|
|
541
|
+
const v2 = Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
542
|
+
const v1 = Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
543
|
+
Ast.bool(ctx, v1 === v2);
|
|
544
|
+
}
|
|
545
|
+
static ne(ctx) {
|
|
546
|
+
const v2 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
547
|
+
const v1 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
548
|
+
Ast.bool(ctx, v1 !== v2);
|
|
549
|
+
}
|
|
550
|
+
static lt(ctx) {
|
|
551
|
+
const v2 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
552
|
+
const v1 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
553
|
+
Ast.bool(ctx, v1 < v2);
|
|
554
|
+
}
|
|
555
|
+
static gt(ctx) {
|
|
556
|
+
const v2 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
557
|
+
const v1 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
558
|
+
Ast.bool(ctx, v1 > v2);
|
|
559
|
+
}
|
|
560
|
+
static le(ctx) {
|
|
561
|
+
const v2 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
562
|
+
const v1 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
563
|
+
Ast.bool(ctx, v1 <= v2);
|
|
564
|
+
}
|
|
565
|
+
static ge(ctx) {
|
|
566
|
+
const v2 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
567
|
+
const v1 = +Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
568
|
+
Ast.bool(ctx, v1 >= v2);
|
|
569
|
+
}
|
|
570
|
+
static ifExpr(ctx) {
|
|
571
|
+
const elts = [];
|
|
572
|
+
elts.push(Ast.pop(ctx)); // if
|
|
573
|
+
elts.push(Ast.pop(ctx)); // then
|
|
574
|
+
elts.push(Ast.pop(ctx)); // else
|
|
575
|
+
Ast.push(ctx, { tag: "IF", elts: elts.reverse() });
|
|
576
|
+
}
|
|
577
|
+
static caseExpr(ctx, n) {
|
|
578
|
+
const elts = [];
|
|
579
|
+
elts.push(Ast.pop(ctx)); // val
|
|
580
|
+
for (let i = n; i > 0; i--) {
|
|
581
|
+
elts.push(Ast.pop(ctx)); // of
|
|
582
|
+
}
|
|
583
|
+
Ast.push(ctx, { tag: "CASE", elts: elts.reverse() });
|
|
584
|
+
}
|
|
585
|
+
static ofClause(ctx) {
|
|
586
|
+
const elts = [];
|
|
587
|
+
elts.push(Ast.pop(ctx));
|
|
588
|
+
elts.push(Ast.pop(ctx));
|
|
589
|
+
Ast.push(ctx, { tag: "OF", elts: elts.reverse() });
|
|
590
|
+
}
|
|
591
|
+
static record(ctx) {
|
|
592
|
+
// Ast.record
|
|
593
|
+
const count = ctx.state.exprc;
|
|
594
|
+
const elts = [];
|
|
595
|
+
for (let i = count; i > 0; i--) {
|
|
596
|
+
const elt = Ast.pop(ctx);
|
|
597
|
+
if (elt !== undefined) {
|
|
598
|
+
elts.push(elt);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
Ast.push(ctx, {
|
|
602
|
+
tag: "RECORD",
|
|
603
|
+
elts
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
static binding(ctx) {
|
|
607
|
+
// Ast.binding
|
|
608
|
+
const elts = [];
|
|
609
|
+
elts.push(Ast.pop(ctx));
|
|
610
|
+
elts.push(Ast.pop(ctx));
|
|
611
|
+
Ast.push(ctx, {
|
|
612
|
+
tag: "BINDING",
|
|
613
|
+
elts: elts.reverse()
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
static lambda(ctx, env, nid) {
|
|
617
|
+
// Ast.lambda
|
|
618
|
+
const names = [];
|
|
619
|
+
const nids = [];
|
|
620
|
+
for (const id in env.lexicon) {
|
|
621
|
+
const word = env.lexicon[id];
|
|
622
|
+
names.push({
|
|
623
|
+
tag: "IDENT",
|
|
624
|
+
elts: [word.name],
|
|
625
|
+
});
|
|
626
|
+
nids.push(word.nid || 0);
|
|
627
|
+
}
|
|
628
|
+
const pattern = env.pattern;
|
|
629
|
+
Ast.push(ctx, {
|
|
630
|
+
tag: "LAMBDA",
|
|
631
|
+
elts: [{
|
|
632
|
+
tag: "LIST",
|
|
633
|
+
elts: names
|
|
634
|
+
}, nid, {
|
|
635
|
+
tag: "LIST",
|
|
636
|
+
elts: pattern
|
|
637
|
+
}, {
|
|
638
|
+
tag: "LIST",
|
|
639
|
+
elts: nids
|
|
640
|
+
}]
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
static exprs(ctx, count, inReverse) {
|
|
644
|
+
// Ast.exprs
|
|
645
|
+
let elts = [];
|
|
646
|
+
assert(ctx.state.nodeStack.length >= count);
|
|
647
|
+
if (inReverse) {
|
|
648
|
+
for (let i = count; i > 0; i--) {
|
|
649
|
+
const elt = Ast.pop(ctx);
|
|
650
|
+
elts.push(elt); // Reverse order.
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
for (let i = count; i > 0; i--) {
|
|
655
|
+
const elt = Ast.pop(ctx);
|
|
656
|
+
elts.push(elt); // Reverse order.
|
|
657
|
+
}
|
|
658
|
+
elts = elts.reverse();
|
|
659
|
+
}
|
|
660
|
+
Ast.push(ctx, {
|
|
661
|
+
tag: "EXPRS",
|
|
662
|
+
elts
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
static letDef(ctx) {
|
|
666
|
+
// Clean up stack and produce initializer.
|
|
667
|
+
Ast.pop(ctx); // body
|
|
668
|
+
Ast.pop(ctx); // name
|
|
669
|
+
for (let i = 0; i < ctx.state.paramc; i++) {
|
|
670
|
+
Ast.pop(ctx); // params
|
|
671
|
+
}
|
|
672
|
+
ctx.state.exprc--; // don't count as expr.
|
|
673
|
+
}
|
|
674
|
+
static program(ctx) {
|
|
675
|
+
const elts = [];
|
|
676
|
+
elts.push(Ast.pop(ctx));
|
|
677
|
+
Ast.push(ctx, {
|
|
678
|
+
tag: "PROG",
|
|
679
|
+
elts
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
//# sourceMappingURL=ast.js.map
|