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