@graffiticode/basis 1.5.7 → 1.5.8

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/src/parse.js DELETED
@@ -1,2426 +0,0 @@
1
- // Copyright 2021, ARTCOMPILER INC
2
-
3
- function assert(b, str) {
4
- if (!b) throw str;
5
- }
6
-
7
- const Ast = (function () {
8
- var ASSERT = true;
9
- var assert = function (val, str) {
10
- if ( !ASSERT ) {
11
- return;
12
- }
13
- if ( str === void 0 ) {
14
- str = "failed!";
15
- }
16
- if (!val) {
17
- throw new Error(str);
18
- }
19
- }
20
-
21
- var AstClass = function() { }
22
-
23
- AstClass.prototype = {
24
- intern: intern,
25
- node: node,
26
- dump: dump,
27
- dumpAll: dumpAll,
28
- poolToJSON: poolToJSON,
29
- number: number,
30
- string: string,
31
- name: name,
32
- apply: apply,
33
- fold: fold,
34
- expr: expr,
35
- binaryExpr: binaryExpr,
36
- unaryExpr: unaryExpr,
37
- parenExpr: parenExpr,
38
- prefixExpr: prefixExpr,
39
- lambda: lambda,
40
- applyLate: applyLate,
41
- letDef: letDef,
42
- caseExpr: caseExpr,
43
- ofClause: ofClause,
44
- record: record,
45
- binding: binding,
46
- exprs: exprs,
47
- program: program,
48
- pop: pop,
49
- topNode: topNode,
50
- peek: peek,
51
- push: push,
52
- mod: mod,
53
- add: add,
54
- sub: sub,
55
- // mul: mul,
56
- div: div,
57
- pow: pow,
58
- concat: concat,
59
- orelse: orelse,
60
- andalso: andalso,
61
- eq: eq,
62
- ne: ne,
63
- lt: lt,
64
- gt: gt,
65
- le: le,
66
- ge: ge,
67
- neg: neg,
68
- list: list,
69
- bool: bool,
70
- nul: nul,
71
- };
72
-
73
- return new AstClass;
74
-
75
- // private implementation
76
-
77
- function push(ctx, node) {
78
- var nid;
79
- if (typeof node === "number") { // if already interned
80
- nid = node;
81
- } else {
82
- nid = intern(ctx, node);
83
- }
84
- ctx.state.nodeStack.push(nid);
85
- }
86
-
87
- function topNode(ctx) {
88
- var nodeStack = ctx.state.nodeStack;
89
- return nodeStack[nodeStack.length-1];
90
- }
91
-
92
- function pop(ctx) {
93
- var nodeStack = ctx.state.nodeStack;
94
- return nodeStack.pop();
95
- }
96
-
97
- function peek(ctx, n) {
98
- if (n === undefined) {
99
- n = 0;
100
- }
101
- var nodeStack = ctx.state.nodeStack;
102
- return nodeStack[nodeStack.length - 1 - n];
103
- }
104
-
105
- function intern(ctx, n) {
106
- if (!n) {
107
- return 0;
108
- }
109
- var nodeMap = ctx.state.nodeMap;
110
- var nodePool = ctx.state.nodePool;
111
- var tag = n.tag;
112
- var elts = "";
113
- var elts_nids = [ ];
114
- var count = n.elts.length;
115
- for (var i = 0; i < count; i++) {
116
- if (typeof n.elts[i] === "object") {
117
- n.elts[i] = intern(ctx, n.elts[i]);
118
- }
119
- elts += n.elts[i];
120
- }
121
- var key = tag+count+elts;
122
- var nid = nodeMap[key];
123
- if (nid === void 0) {
124
- nodePool.push({tag: tag, elts: n.elts});
125
- nid = nodePool.length - 1;
126
- nodeMap[key] = nid;
127
- if (n.coord) {
128
- ctx.state.coords[nid] = n.coord;
129
- }
130
- }
131
- return nid;
132
- }
133
-
134
- function node(ctx, nid) {
135
- var n = ctx.state.nodePool[nid];
136
- if (!nid) {
137
- return null;
138
- } else if (!n) {
139
- return {};
140
- }
141
- var elts = [];
142
- switch (n.tag) {
143
- case "NULL":
144
- break;
145
- case "NUM":
146
- case "STR":
147
- case "IDENT":
148
- case "BOOL":
149
- elts[0] = n.elts[0];
150
- break;
151
- default:
152
- for (var i=0; i < n.elts.length; i++) {
153
- elts[i] = node(ctx, n.elts[i]);
154
- }
155
- break;
156
- }
157
- return {
158
- tag: n.tag,
159
- elts: elts,
160
- coord: getCoord(ctx),
161
- };
162
- }
163
-
164
- function dumpAll(ctx) {
165
- var nodePool = ctx.state.nodePool;
166
- var s = "\n{"
167
- for (var i=1; i < nodePool.length; i++) {
168
- var n = nodePool[i];
169
- s = s + "\n " + i+": "+dump(n) + ",";
170
- }
171
- s += "\n root: " + (nodePool.length-1);
172
- s += "\n}\n";
173
- return s;
174
- }
175
-
176
- function poolToJSON(ctx) {
177
- var nodePool = ctx.state.nodePool;
178
- var obj = { };
179
- for (var i=1; i < nodePool.length; i++) {
180
- var n = nodePool[i];
181
- obj[i] = nodeToJSON(n);
182
- }
183
- obj.root = (nodePool.length-1);
184
- obj.version = window.gcexports.version;
185
- return obj;
186
- }
187
-
188
- function nodeToJSON(n) {
189
- if (typeof n === "object") {
190
- switch (n.tag) {
191
- case "num":
192
- var obj = n.elts[0];
193
- break;
194
- case "str":
195
- var obj = n.elts[0];
196
- break;
197
- default:
198
- var obj = {};
199
- obj["tag"] = n.tag;
200
- obj["elts"] = [];
201
- for (var i=0; i < n.elts.length; i++) {
202
- obj["elts"][i] = nodeToJSON(n.elts[i]);
203
- }
204
- break;
205
- }
206
- } else if (typeof n === "string") {
207
- var obj = n;
208
- } else {
209
- var obj = n;
210
- }
211
- return obj;
212
- }
213
-
214
- function dump(n) {
215
- if (typeof n === "object") {
216
- switch (n.tag) {
217
- case "num":
218
- var s = n.elts[0];
219
- break;
220
- case "str":
221
- var s = "\""+n.elts[0]+"\"";
222
- break;
223
- default:
224
- if (!n.elts) {
225
- s += "<invalid>";
226
- } else {
227
- var s = "{ tag: \"" + n.tag + "\", elts: [ ";
228
- for (var i=0; i < n.elts.length; i++) {
229
- if (i > 0) {
230
- s += " , ";
231
- }
232
- s += dump(n.elts[i]);
233
- }
234
- s += " ] }";
235
- }
236
- break;
237
- }
238
- } else if (typeof n === "string") {
239
- var s = "\""+n+"\"";
240
- } else {
241
- var s = n;
242
- }
243
- return s;
244
- }
245
-
246
- function fold(ctx, fn, args) {
247
- // Local defs:
248
- // -- put bindings in env
249
- // Three cases:
250
- // -- full application, all args are available at parse time
251
- // -- partial application, only some args are available at parse time
252
- // -- late application, args are available at compile time (not parse time)
253
- // apply <[x y]: add x y> data..
254
- // x: val 0 data
255
- // y: val 1 data
256
- env.enterEnv(ctx, fn.name);
257
- if (fn.env) {
258
- var lexicon = fn.env.lexicon;
259
- var pattern = Ast.node(ctx, fn.env.pattern);
260
- var outerEnv = null;
261
- // setup inner environment record (lexicon)
262
- if (pattern && pattern.elts &&
263
- pattern.elts.length === 1 &&
264
- pattern.elts[0].tag === "LIST") {
265
- // For now we only support one pattern per param list.
266
- var isListPattern = true;
267
- }
268
- for (var id in lexicon) {
269
- // For each parameter, get its definition assign the value of the argument
270
- // used on the current function application.
271
- if (!id) continue;
272
- var word = JSON.parse(JSON.stringify(lexicon[id])); // poor man's copy.
273
- var index = args.length - word.offset - 1;
274
- // TODO we currently ignore list patterns
275
- // if (isListPattern) {
276
- // // <[x y]: ...> foo..
277
- // word.nid = Ast.intern(ctx, {
278
- // tag: "VAL",
279
- // elts: [{
280
- // tag: "NUM",
281
- // elts: [
282
- // String(word.offset),
283
- // ]}, {
284
- // tag: "ARG",
285
- // elts: [{
286
- // tag: "NUM",
287
- // elts: ["0"]
288
- // }]
289
- // }]
290
- // });
291
- // } else
292
- if (index >= 0 && index < args.length) {
293
- word.nid = args[index];
294
- }
295
- if (index < 0) {
296
- // We've got an unbound variable or a variable with a default value,
297
- // so add it to the new variable list.
298
- // <x:x> => <x:x>
299
- // (<x y: add x y> 10) => <y: add 10 y>
300
- // (<y: let x = 10.. add x y>) => <y: add 10 y>
301
- if (!outerEnv) {
302
- outerEnv = {};
303
- }
304
- outerEnv[id] = word;
305
- }
306
- env.addWord(ctx, id, word);
307
- }
308
- folder.fold(ctx, fn.nid);
309
- if (outerEnv) {
310
- lambda(ctx, {
311
- lexicon: outerEnv,
312
- pattern: pattern, // FIXME need to trim pattern if some args where applied.
313
- }, pop(ctx));
314
- }
315
- }
316
- env.exitEnv(ctx);
317
- }
318
-
319
- function applyLate(ctx, count) {
320
- // Ast.applyLate
321
- var elts = [];
322
- for (var i = count; i > 0; i--) {
323
- elts.push(pop(ctx));
324
- }
325
- push(ctx, {
326
- tag: "APPLY",
327
- elts: elts,
328
- });
329
- }
330
-
331
- function apply(ctx, fnId, argc) {
332
- // Construct function and apply available arguments.
333
- var fn = node(ctx, fnId);
334
- // if (fn.tag !== "LAMBDA") {
335
- // // Construct an APPLY node for compiling later.
336
- // return {
337
- // tag: "APPLY",
338
- // elts: [
339
- // fnId,
340
- // ]
341
- // };
342
- // }
343
- // Construct a lexicon
344
- var lexicon = {};
345
- var paramc = 0;
346
- fn.elts[0].elts.forEach(function (n, i) {
347
- var name = n.elts[0];
348
- var nid = Ast.intern(ctx, fn.elts[3].elts[i]);
349
- lexicon[name] = {
350
- cls: "val",
351
- name: name,
352
- offset: i,
353
- nid: nid,
354
- };
355
- if (!nid) {
356
- // Parameters don't have nids.
357
- // assert that there are parameters after a binding without a nid.
358
- paramc++;
359
- }
360
- });
361
- var def = {
362
- name: "lambda",
363
- nid: Ast.intern(ctx, fn.elts[1]),
364
- env: {
365
- lexicon: lexicon,
366
- pattern: Ast.intern(ctx, fn.elts[2]),
367
- },
368
- };
369
- var len = fn.elts[0].elts.length;
370
- var elts = [];
371
- // While there are args on the stack, pop them.
372
- while (argc-- > 0 && paramc-- > 0) {
373
- var elt = pop(ctx);
374
- elts.unshift(elt); // Get the order right.
375
- }
376
- fold(ctx, def, elts);
377
- }
378
-
379
- // Node constructors
380
-
381
- function bool(ctx, val) {
382
- if (val) {
383
- var b = true;
384
- } else {
385
- var b = false;
386
- }
387
- push(ctx, {
388
- tag: "BOOL",
389
- elts: [b]
390
- });
391
- }
392
-
393
- function nul(ctx) {
394
- push(ctx, {
395
- tag: "NULL",
396
- elts: []
397
- });
398
- }
399
-
400
- function number(ctx, str, coord) {
401
- assert(typeof str === "string" || typeof str === "number");
402
- push(ctx, {
403
- tag: "NUM",
404
- elts: [String(str)],
405
- coord: coord,
406
- });
407
- }
408
-
409
- function string(ctx, str, coord) {
410
- push(ctx, {
411
- tag: "STR",
412
- elts: [str],
413
- coord: coord,
414
- });
415
- }
416
-
417
- function name(ctx, name, coord) {
418
- push(ctx, {
419
- tag: "IDENT",
420
- elts: [name],
421
- coord: coord,
422
- });
423
- }
424
-
425
- function expr(ctx, argc) {
426
- // Ast.expr -- construct a expr node for the compiler.
427
- var elts = [];
428
- while (argc--) {
429
- var elt = pop(ctx);
430
- elts.push(elt);
431
- }
432
- var nameId = pop(ctx);
433
- assert(nameId, "Ill formed node.");
434
- var e = node(ctx, nameId).elts;
435
- assert(e && e.length > 0, "Ill formed node.");
436
- var name = e[0];
437
- push(ctx, {
438
- tag: name,
439
- elts: elts,
440
- coord: getCoord(ctx),
441
- });
442
- }
443
-
444
- function parenExpr(ctx, coord) {
445
- // Ast.parenExpr
446
- var elts = [];
447
- var elt = pop(ctx);
448
- elts.push(elt);
449
- push(ctx, {
450
- tag: "PAREN",
451
- elts: elts,
452
- coord: coord,
453
- });
454
- }
455
-
456
- function list(ctx, count, coord, reverse) {
457
- // Ast.list
458
- var elts = [];
459
- for (var i = count; i > 0; i--) {
460
- var elt = pop(ctx);
461
- if (elt !== void 0) {
462
- elts.push(elt);
463
- }
464
- }
465
- push(ctx, {
466
- tag: "LIST",
467
- elts: reverse ? elts : elts.reverse(),
468
- coord: coord,
469
- });
470
- }
471
-
472
- function binaryExpr(ctx, name) {
473
- var elts = [];
474
- // args are in the order produced by the parser
475
- elts.push(pop(ctx));
476
- elts.push(pop(ctx));
477
- push(ctx, {
478
- tag: name,
479
- elts: elts.reverse()
480
- });
481
- }
482
- function unaryExpr(ctx, name) {
483
- var elts = [];
484
- elts.push(pop(ctx));
485
- push(ctx, {
486
- tag: name,
487
- elts: elts
488
- });
489
- }
490
-
491
- function prefixExpr(ctx, name) {
492
- var elts = [];
493
- elts.push(pop(ctx));
494
- push(ctx, {
495
- tag: name,
496
- elts: elts
497
- });
498
- }
499
-
500
- function neg(ctx) {
501
- var v1 = +node(ctx, pop(ctx)).elts[0];
502
- number(ctx, -1*v1);
503
- }
504
-
505
- function add(ctx, coord) {
506
- var n2 = node(ctx, pop(ctx));
507
- var n1 = node(ctx, pop(ctx));
508
- var v2 = n2.elts[0];
509
- var v1 = n1.elts[0];
510
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
511
- push(ctx, {
512
- tag: "ADD",
513
- elts: [n1, n2],
514
- coord: coord
515
- });
516
- } else {
517
- number(ctx, +v1 + +v2);
518
- }
519
- }
520
-
521
- function sub(ctx) {
522
- var n2 = node(ctx, pop(ctx));
523
- var n1 = node(ctx, pop(ctx));
524
- var v2 = n2.elts[0];
525
- var v1 = n1.elts[0];
526
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
527
- push(ctx, {tag: "SUB", elts: [n1, n2]});
528
- } else {
529
- number(ctx, +v1 - +v2);
530
- }
531
- }
532
-
533
- function mul(ctx) {
534
- var n2 = node(ctx, pop(ctx));
535
- var n1 = node(ctx, pop(ctx));
536
- var v2 = n2.elts[0];
537
- var v1 = n1.elts[0];
538
- if (n1.tag === undefined) {
539
- n1 = n1.elts[0];
540
- }
541
- if (n2.tag === undefined) {
542
- n2 = n2.elts[0];
543
- }
544
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
545
- push(ctx, {tag: "MUL", elts: [n2, n1]});
546
- } else {
547
- number(ctx, +v1 * +v2);
548
- }
549
- }
550
-
551
- function div(ctx) {
552
- var n2 = node(ctx, pop(ctx));
553
- var n1 = node(ctx, pop(ctx));
554
- var v2 = n2.elts[0];
555
- var v1 = n1.elts[0];
556
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
557
- push(ctx, {tag: "DIV", elts: [n1, n2]});
558
- } else {
559
- number(ctx, +v1 / +v2);
560
- }
561
- }
562
-
563
- function mod(ctx) {
564
- var n2 = node(ctx, pop(ctx));
565
- var n1 = node(ctx, pop(ctx));
566
- var v1 = n1.elts[0];
567
- var v2 = n2.elts[0];
568
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
569
- push(ctx, {tag: "MOD", elts: [n1, n2]});
570
- } else {
571
- number(ctx, +v1 % +v2);
572
- }
573
- }
574
-
575
- function pow(ctx) {
576
- var n2 = node(ctx, pop(ctx));
577
- var n1 = node(ctx, pop(ctx));
578
- var v2 = n2.elts[0];
579
- var v1 = n1.elts[0];
580
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
581
- push(ctx, {tag: "POW", elts: [n1, n2]});
582
- } else {
583
- number(ctx, Math.pow(+v1, +v2));
584
- }
585
- }
586
-
587
- function concat(ctx) {
588
- var n1 = node(ctx, pop(ctx));
589
- push(ctx, {
590
- tag: "CONCAT",
591
- elts: [n1]
592
- });
593
- }
594
-
595
- function orelse(ctx) {
596
- var v2 = +node(ctx, pop(ctx)).elts[0];
597
- var v1 = +node(ctx, pop(ctx)).elts[0];
598
- throw "not implemented";
599
- }
600
-
601
- function andalso(ctx) {
602
- var v2 = +node(ctx, pop(ctx)).elts[0];
603
- var v1 = +node(ctx, pop(ctx)).elts[0];
604
- throw "not implemented";
605
- }
606
-
607
- function eq(ctx) {
608
- var v2 = node(ctx, pop(ctx)).elts[0];
609
- var v1 = node(ctx, pop(ctx)).elts[0];
610
- bool(ctx, v1==v2);
611
- }
612
-
613
- function ne(ctx) {
614
- var v2 = +node(ctx, pop(ctx)).elts[0];
615
- var v1 = +node(ctx, pop(ctx)).elts[0];
616
- bool(ctx, v1!=v2);
617
- }
618
-
619
- function lt(ctx) {
620
- var v2 = +node(ctx, pop(ctx)).elts[0];
621
- var v1 = +node(ctx, pop(ctx)).elts[0];
622
- bool(ctx, v1<v2);
623
- }
624
-
625
- function gt(ctx) {
626
- var v2 = +node(ctx, pop(ctx)).elts[0];
627
- var v1 = +node(ctx, pop(ctx)).elts[0];
628
- bool(ctx, v1>v2);
629
- }
630
-
631
- function le(ctx) {
632
- var v2 = +node(ctx, pop(ctx)).elts[0];
633
- var v1 = +node(ctx, pop(ctx)).elts[0];
634
- bool(ctx, v1<=v2);
635
- }
636
- function ge(ctx) {
637
- var v2 = +node(ctx, pop(ctx)).elts[0];
638
- var v1 = +node(ctx, pop(ctx)).elts[0];
639
- bool(ctx, v1>=v2);
640
- }
641
- function caseExpr(ctx, n) {
642
- var elts = [];
643
- for (var i = n; i > 0; i--) {
644
- elts.push(pop(ctx)) // of
645
- }
646
- elts.push(pop(ctx)) // exprs
647
- push(ctx, {tag: "CASE", elts: elts.reverse()});
648
- }
649
- function ofClause(ctx) {
650
- var elts = [];
651
- elts.push(pop(ctx));
652
- elts.push(pop(ctx));
653
- push(ctx, {tag: "OF", elts: elts.reverse()});
654
- }
655
-
656
- function record(ctx) {
657
- // Ast.record
658
- var count = ctx.state.exprc;
659
- var elts = [];
660
- for (var i = count; i > 0; i--) {
661
- var elt = pop(ctx);
662
- if (elt !== void 0) {
663
- elts.push(elt);
664
- }
665
- }
666
- push(ctx, {
667
- tag: "RECORD",
668
- elts: elts
669
- });
670
- }
671
-
672
- function binding(ctx) {
673
- // Ast.binding
674
- var elts = [];
675
- elts.push(pop(ctx));
676
- elts.push(pop(ctx));
677
- push(ctx, {
678
- tag: "BINDING",
679
- elts: elts.reverse()
680
- });
681
- }
682
-
683
- function lambda(ctx, env, nid) {
684
- // Ast.lambda
685
- var names = [];
686
- var nids = [];
687
- for (var id in env.lexicon) {
688
- var word = env.lexicon[id];
689
- names.push({
690
- tag: "IDENT",
691
- elts: [word.name],
692
- coord: getCoord(ctx),
693
- });
694
- nids.push(word.nid || 0);
695
- }
696
- var pattern = env.pattern;
697
- push(ctx, {
698
- tag: "LAMBDA",
699
- elts: [{
700
- tag: "LIST",
701
- elts: names
702
- }, nid, {
703
- tag: "LIST",
704
- elts: pattern
705
- }, {
706
- tag: "LIST",
707
- elts: nids
708
- }]
709
- });
710
- }
711
-
712
- function exprs(ctx, count, inReverse) {
713
- // Ast.exprs
714
- var elts = [];
715
- assert(ctx.state.nodeStack.length >= count);
716
- if (inReverse) {
717
- for (var i = count; i > 0; i--) {
718
- var elt = pop(ctx);
719
- var n;
720
- if (false && (n = node(ctx, elt)) && n.tag === "EXPRS") {
721
- elts = elts.concat(n.elts);
722
- } else {
723
- elts.push(elt); // Reverse order.
724
- }
725
- }
726
- } else {
727
- for (var i = count; i > 0; i--) {
728
- var elt = pop(ctx);
729
- var n;
730
- if (false && (n = node(ctx, elt)) && n.tag === "EXPRS") {
731
- elts = elts.concat(n.elts);
732
- } else {
733
- elts.push(elt); // Reverse order.
734
- }
735
- }
736
- elts = elts.reverse();
737
- }
738
- push(ctx, {
739
- tag: "EXPRS",
740
- elts: elts
741
- });
742
- }
743
-
744
- function letDef(ctx) {
745
- // Clean up stack and produce initializer.
746
- pop(ctx); // body
747
- pop(ctx); // name
748
- for (var i = 0; i < ctx.state.paramc; i++) {
749
- pop(ctx); // params
750
- }
751
- ctx.state.exprc--; // don't count as expr.
752
- }
753
-
754
- function program(ctx) {
755
- var elts = [];
756
- elts.push(pop(ctx));
757
- push(ctx, {
758
- tag: "PROG",
759
- elts: elts
760
- });
761
- }
762
- })();
763
-
764
- // The following code for StreamString was copied from CodeMirror.
765
-
766
- window.gcexports.StringStream = (function () {
767
-
768
- // The character stream used by a mode's parser.
769
- function StringStream(string, tabSize) {
770
- this.pos = this.start = 0;
771
- this.string = string;
772
- this.tabSize = tabSize || 8;
773
- }
774
-
775
- StringStream.prototype = {
776
- eol: function() {return this.pos >= this.string.length;},
777
- sol: function() {return this.pos == 0;},
778
- peek: function() {return this.string.charAt(this.pos) || undefined;},
779
- next: function() {
780
- if (this.pos < this.string.length)
781
- return this.string.charAt(this.pos++);
782
- },
783
- eat: function(match) {
784
- var ch = this.string.charAt(this.pos);
785
- if (typeof match == "string") {
786
- var ok = ch == match;
787
- } else {
788
- var ok = ch && (match.test ? match.test(ch) : match(ch));
789
- }
790
- if (ok) {++this.pos; return ch;}
791
- },
792
- eatWhile: function(match) {
793
- var start = this.pos;
794
- while (this.eat(match)){}
795
- return this.pos > start;
796
- },
797
- eatSpace: function() {
798
- var start = this.pos;
799
- while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
800
- return this.pos > start;
801
- },
802
- skipToEnd: function() {this.pos = this.string.length;},
803
- skipTo: function(ch) {
804
- var found = this.string.indexOf(ch, this.pos);
805
- if (found > -1) {this.pos = found; return true;}
806
- },
807
- backUp: function(n) {this.pos -= n;},
808
- column: function() {return countColumn(this.string, this.start, this.tabSize);},
809
- indentation: function() {return countColumn(this.string, null, this.tabSize);},
810
- match: function(pattern, consume, caseInsensitive) {
811
- if (typeof pattern == "string") {
812
- var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
813
- if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
814
- if (consume !== false) this.pos += pattern.length;
815
- return true;
816
- }
817
- } else {
818
- var match = this.string.slice(this.pos).match(pattern);
819
- if (match && match.index > 0) return null;
820
- if (match && consume !== false) this.pos += match[0].length;
821
- return match;
822
- }
823
- },
824
- current: function(){return this.string.slice(this.start, this.pos);}
825
- }
826
-
827
- return StringStream;
828
-
829
- })();
830
-
831
- // env
832
-
833
- var env = (function () {
834
- return {
835
- findWord: findWord,
836
- addWord: addWord,
837
- enterEnv: enterEnv,
838
- exitEnv: exitEnv,
839
- addPattern: addPattern,
840
- };
841
-
842
- // private functions
843
-
844
- function findWord(ctx, lexeme) {
845
- var env = ctx.state.env;
846
- for (var i = env.length-1; i >= 0; i--) {
847
- var word = env[i].lexicon[lexeme];
848
- if (word) {
849
- return word;
850
- }
851
- }
852
- return null;
853
- }
854
-
855
- function addWord(ctx, lexeme, entry) {
856
- window.gcexports.topEnv(ctx).lexicon[lexeme] = entry;
857
- return null;
858
- }
859
-
860
- function addPattern(ctx, pattern) {
861
- window.gcexports.topEnv(ctx).pattern.push(pattern);
862
- }
863
-
864
- function enterEnv(ctx, name) {
865
- // recursion guard
866
- if (ctx.state.env.length > 380) {
867
- //return; // just stop recursing
868
- throw new Error("runaway recursion");
869
- }
870
- window.gcexports.topEnv(ctx).paramc = ctx.state.paramc;
871
- ctx.state.env.push({
872
- name: name,
873
- lexicon: {},
874
- pattern: [],
875
- });
876
- }
877
-
878
- function exitEnv(ctx) {
879
- ctx.state.env.pop();
880
- ctx.state.paramc = window.gcexports.topEnv(ctx).paramc;
881
- }
882
-
883
- })();
884
-
885
- var scanTime = 0;
886
- var scanCount = 0;
887
- window.gcexports.scanTime = function () {
888
- return scanTime;
889
- };
890
- window.gcexports.scanCount = function () {
891
- return scanCount;
892
- };
893
-
894
-
895
- var parseTime = 0;
896
-
897
- window.gcexports.parseTime = function () {
898
- return parseTime;
899
- };
900
-
901
- var parseCount = 0;
902
- window.gcexports.parseCount = function () {
903
- return parseCount;
904
- };
905
-
906
- function getCoord(ctx) {
907
- let ln = ctx.scan.stream.lineOracle && ctx.scan.stream.lineOracle.line || 0;
908
- return {
909
- from: CodeMirror.Pos(ln, ctx.scan.stream.start),
910
- to: CodeMirror.Pos(ln, ctx.scan.stream.pos),
911
- };
912
- }
913
-
914
- // parser
915
- window.gcexports.parser = (function () {
916
- function assert(b, str) {
917
- if (!b) {
918
- throw new Error(str);
919
- }
920
- }
921
- var keywords = window.gcexports.keywords = {
922
- "let" : { "tk": 0x12, "cls": "keyword" },
923
- "if" : { "tk": 0x05, "cls": "keyword" },
924
- "then" : { "tk": 0x06, "cls": "keyword" },
925
- "else" : { "tk": 0x07, "cls": "keyword" },
926
- "case" : { "tk": 0x0F, "cls": "keyword" },
927
- "of" : { "tk": 0x10, "cls": "keyword" },
928
- "end" : { "tk": 0x11, "cls": "keyword", "length": 0 },
929
- "true" : { "tk": 0x14, "cls": "val", "length": 0 },
930
- "false" : { "tk": 0x14, "cls": "val", "length": 0 },
931
- "null" : { "tk": 0x15, "cls": "val", "length": 0 },
932
- };
933
- function addError(ctx, str) {
934
- let ln = ctx.scan.stream.lineOracle && ctx.scan.stream.lineOracle.line || 0;
935
- window.gcexports.errors.push({
936
- from: CodeMirror.Pos(ln, ctx.scan.stream.start),
937
- to: CodeMirror.Pos(ln, ctx.scan.stream.pos),
938
- message: str,
939
- severity : "error",
940
- });
941
- }
942
-
943
- var CC_DOUBLEQUOTE = 0x22;
944
- var CC_DOLLAR = 0x24;
945
- var CC_SINGLEQUOTE = 0x27;
946
- var CC_BACKTICK = 0x60;
947
- var CC_LEFTBRACE = 0x7B;
948
- var CC_RIGHTBRACE = 0x7D;
949
-
950
- var TK_IDENT = 0x01;
951
- var TK_NUM = 0x02;
952
- var TK_STR = 0x03;
953
- var TK_EQUAL = 0x04;
954
- var TK_IF = 0x05;
955
- var TK_THEN = 0x06;
956
- var TK_ELSE = 0x07;
957
- var TK_RETURN = 0x08;
958
- var TK_IS = 0x09;
959
- var TK_POSTOP = 0x0A;
960
- var TK_PREOP = 0x0B;
961
- var TK_FUN = 0x0C;
962
- var TK_VAL = 0x0D;
963
- var TK_BINOP = 0x0E;
964
- var TK_CASE = 0x0F;
965
- var TK_OF = 0x10;
966
- var TK_END = 0x11;
967
- var TK_LET = 0x12;
968
- var TK_OR = 0x13;
969
- var TK_BOOL = 0x14;
970
- var TK_NULL = 0x15;
971
- var TK_IN = 0x16;
972
-
973
- var TK_LEFTPAREN = 0xA1;
974
- var TK_RIGHTPAREN = 0xA2;
975
- var TK_LEFTBRACKET = 0xA3;
976
- var TK_RIGHTBRACKET = 0xA4;
977
- var TK_LEFTBRACE = 0xA5;
978
- var TK_RIGHTBRACE = 0xA6;
979
- var TK_PLUS = 0xA7;
980
- var TK_MINUS = 0xA8;
981
- var TK_DOT = 0xA9;
982
- var TK_COLON = 0xAA;
983
- var TK_COMMA = 0xAB;
984
- var TK_BACKQUOTE = 0xAC;
985
- var TK_COMMENT = 0xAD;
986
- var TK_LEFTANGLE = 0xAE;
987
- var TK_RIGHTANGLE = 0xAF;
988
- var TK_DOUBLELEFTBRACE = 0xB0;
989
- var TK_DOUBLERIGHTBRACE = 0xB1;
990
- var TK_STRPREFIX = 0xB2;
991
- var TK_STRMIDDLE = 0xB3;
992
- var TK_STRSUFFIX = 0xB4;
993
-
994
- function tokenToLexeme(tk) {
995
- switch (tk) {
996
- case TK_EQUAL: return "a '=' symbol";
997
- case TK_IF: return "the 'if' keyword";
998
- case TK_THEN: return "the 'then' keyword";
999
- case TK_ELSE: return "the 'else' keyword";
1000
- case TK_RETURN: return "the 'return' keyword";
1001
- case TK_IS: return "the 'is' keyword";
1002
- case TK_FUN: return "the 'fun' keyword";
1003
- case TK_VAL: return "the 'val' keyword";
1004
- case TK_CASE: return "the 'case' keyword";
1005
- case TK_OF: return "the 'of' keyword";
1006
- case TK_END: return "the 'end' keyword";
1007
- case TK_LET: return "the 'let' keyword";
1008
- case TK_OR: return "the 'or' keyword";
1009
- case TK_POSTOP:
1010
- case TK_PREOP:
1011
- case TK_BINOP:
1012
- return "an operator";
1013
- case TK_LEFTPAREN: return "a '('";
1014
- case TK_RIGHTPAREN: return "a ')'";
1015
- case TK_LEFTBRACKET: return "a '['";
1016
- case TK_RIGHTBRACKET: return "a ']'";
1017
- case TK_LEFTBRACE: return "a '{'";
1018
- case TK_RIGHTBRACE: return "a '}'";
1019
- case TK_LEFTANGLE: return "a '<'";
1020
- case TK_RIGHTANGLE: return "a '>'";
1021
- case TK_PLUS: return "a '+'";
1022
- case TK_MINUS: return "a '-'";
1023
- case TK_DOT: return "a '.'";
1024
- case TK_COLON: return "a ':'";
1025
- case TK_COMMA: return "a ','";
1026
- case TK_BACKQUOTE: return "a '`'";
1027
- case TK_COMMENT: return "a comment";
1028
- case 0: return "the end of the program";
1029
- }
1030
- return "an expression";
1031
- }
1032
-
1033
- function eat(ctx, tk) {
1034
- var nextToken = next(ctx);
1035
- if (nextToken !== tk) {
1036
- throw new Error("Expecting " + tokenToLexeme(tk) +
1037
- ", found " + tokenToLexeme(nextToken) + ".");
1038
- }
1039
- }
1040
-
1041
- function match(ctx, tk) {
1042
- if (peek(ctx) === tk) {
1043
- return true;
1044
- } else {
1045
- return false;
1046
- }
1047
- }
1048
-
1049
- function next(ctx) {
1050
- var tk = peek(ctx);
1051
- ctx.state.nextToken = -1;
1052
- scanCount++;
1053
- return tk;
1054
- }
1055
-
1056
- function peek(ctx) {
1057
- var tk;
1058
- var nextToken = ctx.state.nextToken;
1059
- if (nextToken < 0) {
1060
- var t0 = new Date();
1061
- tk = ctx.scan.start(ctx);
1062
- var t1 = new Date();
1063
- scanTime += (t1-t0);
1064
- ctx.state.nextToken = tk;
1065
- } else {
1066
- tk = nextToken;
1067
- }
1068
- return tk;
1069
- }
1070
-
1071
- // Parsing functions -- each parsing function consumes a single token and
1072
- // returns a continuation function for parsing the rest of the string.
1073
-
1074
- function nul(ctx, cc) {
1075
- eat(ctx, TK_NULL);
1076
- cc.cls = "number";
1077
- Ast.nul(ctx);
1078
- return cc;
1079
- }
1080
-
1081
- function bool(ctx, cc) {
1082
- eat(ctx, TK_BOOL);
1083
- cc.cls = "number";
1084
- Ast.bool(ctx, lexeme==="true");
1085
- return cc;
1086
- }
1087
-
1088
- function number(ctx, cc) {
1089
- eat(ctx, TK_NUM);
1090
- cc.cls = "number";
1091
- Ast.number(ctx, lexeme, getCoord(ctx));
1092
- return cc;
1093
- }
1094
-
1095
- function string(ctx, cc) {
1096
- eat(ctx, TK_STR);
1097
- var coord = getCoord(ctx);
1098
- cc.cls = "string";
1099
- Ast.string(ctx, lexeme.substring(1,lexeme.length-1), coord) // strip quotes;
1100
- return cc;
1101
- }
1102
-
1103
- /*
1104
- Str :
1105
- STR
1106
- STRPREFIX StrSuffix
1107
-
1108
- StrSuffix :
1109
- Expr STRMIDDLE StrSuffix
1110
- Expr STRSUFFIX
1111
- */
1112
-
1113
- function str(ctx, cc) {
1114
- if (match(ctx, TK_STR)) {
1115
- eat(ctx, TK_STR);
1116
- var coord = getCoord(ctx);
1117
- Ast.string(ctx, lexeme, coord); // strip quotes;
1118
- cc.cls = "string";
1119
- return cc;
1120
- } else if (match(ctx, TK_STRPREFIX)) {
1121
- ctx.state.inStr++;
1122
- eat(ctx, TK_STRPREFIX);
1123
- startCounter(ctx);
1124
- var coord = getCoord(ctx);
1125
- Ast.string(ctx, lexeme, coord) // strip quotes;
1126
- countCounter(ctx);
1127
- var ret = function(ctx) {
1128
- return strSuffix(ctx, function (ctx) {
1129
- ctx.state.inStr--;
1130
- eat(ctx, TK_STRSUFFIX);
1131
- var coord = getCoord(ctx);
1132
- Ast.string(ctx, lexeme, coord) // strip quotes;
1133
- countCounter(ctx);
1134
- Ast.list(ctx, ctx.state.exprc, getCoord(ctx));
1135
- stopCounter(ctx);
1136
- Ast.concat(ctx);
1137
- cc.cls = "string";
1138
- return cc;
1139
- });
1140
- }
1141
- ret.cls = "string";
1142
- return ret;
1143
- }
1144
- assert(false);
1145
- }
1146
- function strSuffix(ctx, resume) {
1147
- if (match(ctx, TK_STRSUFFIX)) {
1148
- // We have a STRSUFFIX so we are done.
1149
- return resume;
1150
- }
1151
- return strPart(ctx, function (ctx) {
1152
- if (match(ctx, TK_STRMIDDLE)) {
1153
- // Not done yet.
1154
- eat(ctx, TK_STRMIDDLE);
1155
- var coord = getCoord(ctx);
1156
- Ast.string(ctx, lexeme, coord) // strip quotes;
1157
- countCounter(ctx);
1158
- var ret = function (ctx) {
1159
- return strSuffix(ctx, resume);
1160
- };
1161
- ret.cls = "string";
1162
- return ret;
1163
- }
1164
- var ret = function (ctx) {
1165
- return strSuffix(ctx, resume);
1166
- };
1167
- ret.cls = "string";
1168
- return ret;
1169
- });
1170
- }
1171
- function strPart(ctx, resume) {
1172
- return expr(ctx, function(ctx) {
1173
- countCounter(ctx);
1174
- return resume(ctx);
1175
- });
1176
- }
1177
- function ident(ctx, cc) {
1178
- eat(ctx, TK_IDENT);
1179
- Ast.name(ctx, lexeme, getCoord(ctx));
1180
- cc.cls = "variable";
1181
- return cc;
1182
- }
1183
- function identOrString(ctx, cc) {
1184
- if (match(ctx, TK_IDENT)) {
1185
- return ident(ctx, cc);
1186
- }
1187
- if (match(ctx, TK_NUM)) {
1188
- return number(ctx, cc);
1189
- }
1190
- return str(ctx, cc);
1191
- }
1192
- function defList(ctx, resume) {
1193
- eat(ctx, TK_LEFTBRACKET);
1194
- var ret = (ctx) => {
1195
- return params(ctx, TK_RIGHTBRACKET, (ctx) => {
1196
- eat(ctx, TK_RIGHTBRACKET);
1197
- Ast.list(ctx, ctx.state.paramc, null, true);
1198
- ctx.state.paramc = 1;
1199
- return resume;
1200
- });
1201
- };
1202
- ret.cls = "punc";
1203
- return ret;
1204
- }
1205
- function defName(ctx, cc) {
1206
- if (match(ctx, TK_LEFTBRACKET)) {
1207
- return defList(ctx, cc);
1208
- } else {
1209
- eat(ctx, TK_IDENT);
1210
- env.addWord(ctx, lexeme, {
1211
- tk: TK_IDENT,
1212
- cls: "val",
1213
- name: lexeme,
1214
- offset: ctx.state.paramc,
1215
- nid: 0,
1216
- });
1217
- Ast.name(ctx, lexeme, getCoord(ctx));
1218
- cc.cls = "val";
1219
- return cc;
1220
- }
1221
- }
1222
- function name(ctx, cc) {
1223
- eat(ctx, TK_IDENT);
1224
- var coord = getCoord(ctx);
1225
- var word = env.findWord(ctx, lexeme);
1226
- if (word) {
1227
- cc.cls = word.cls;
1228
- if (word.cls==="number" && word.val) {
1229
- Ast.number(ctx, word.val, coord);
1230
- } else if (word.cls==="string" && word.val) {
1231
- Ast.string(ctx, word.val, coord);
1232
- } else {
1233
- if (word.nid) {
1234
- Ast.push(ctx, word.nid);
1235
- } else {
1236
- Ast.name(ctx, lexeme, coord);
1237
- }
1238
- }
1239
- } else {
1240
- cc.cls = "comment";
1241
- addError(ctx, "Name '" + lexeme + "' not found.");
1242
- }
1243
- assert(cc, "name");
1244
- return cc;
1245
- }
1246
- function record(ctx, cc) {
1247
- // Parse record
1248
- eat(ctx, TK_LEFTBRACE);
1249
- startCounter(ctx);
1250
- var ret = function(ctx) {
1251
- return bindings(ctx, function (ctx) {
1252
- eat(ctx, TK_RIGHTBRACE);
1253
- Ast.record(ctx);
1254
- stopCounter(ctx);
1255
- cc.cls = "punc";
1256
- return cc;
1257
- })
1258
- }
1259
- ret.cls = "punc";
1260
- return ret;
1261
- }
1262
- function bindings(ctx, cc) {
1263
- if (match(ctx, TK_RIGHTBRACE)) {
1264
- return cc;
1265
- }
1266
- return binding(ctx, function (ctx) {
1267
- if (match(ctx, TK_COMMA)) {
1268
- eat(ctx, TK_COMMA);
1269
- Ast.binding(ctx);
1270
- var ret = function (ctx) {
1271
- return bindings(ctx, cc);
1272
- };
1273
- ret.cls = "punc";
1274
- return ret;
1275
- }
1276
- return function (ctx) {
1277
- Ast.binding(ctx);
1278
- return bindings(ctx, cc);
1279
- };
1280
- })
1281
- }
1282
- function binding(ctx, cc) {
1283
- return identOrString(ctx, function(ctx) {
1284
- eat(ctx, TK_COLON);
1285
- var ret = function(ctx) {
1286
- countCounter(ctx);
1287
- return expr(ctx, cc);
1288
- }
1289
- ret.cls = "punc";
1290
- return ret;
1291
- })
1292
- }
1293
- function lambda(ctx, cc) {
1294
- eat(ctx, TK_LEFTANGLE);
1295
- var ret = function (ctx) {
1296
- ctx.state.paramc = 0;
1297
- env.enterEnv(ctx, "lambda");
1298
- return params(ctx, TK_COLON, function (ctx) {
1299
- eat(ctx, TK_COLON);
1300
- var ret = function(ctx) {
1301
- return exprsStart(ctx, TK_RIGHTANGLE, function (ctx) {
1302
- eat(ctx, TK_RIGHTANGLE);
1303
- var nid = Ast.pop(ctx); // save body node id for aliased code
1304
- Ast.lambda(ctx, topEnv(ctx), nid);
1305
- env.exitEnv(ctx);
1306
- return cc
1307
- });
1308
- };
1309
- ret.cls = "punc"
1310
- return ret
1311
- });
1312
- };
1313
- return ret;
1314
- }
1315
- function parenExpr(ctx, cc) {
1316
- let coord = getCoord(ctx);
1317
- eat(ctx, TK_LEFTPAREN);
1318
- var ret = function(ctx) {
1319
- return exprsStart(ctx, TK_RIGHTPAREN, function (ctx) {
1320
- eat(ctx, TK_RIGHTPAREN);
1321
- coord.to = getCoord(ctx).to;
1322
- Ast.parenExpr(ctx, coord);
1323
- cc.cls = "punc";
1324
- return cc;
1325
- })
1326
- }
1327
- ret.cls = "punc";
1328
- return ret;
1329
- }
1330
- function list(ctx, cc) {
1331
- let coord = getCoord(ctx);
1332
- eat(ctx, TK_LEFTBRACKET);
1333
- startCounter(ctx);
1334
- var ret = function(ctx) {
1335
- return elements(ctx, function (ctx) {
1336
- eat(ctx, TK_RIGHTBRACKET);
1337
- coord.to = getCoord(ctx).to;
1338
- Ast.list(ctx, ctx.state.exprc, coord);
1339
- stopCounter(ctx);
1340
- cc.cls = "punc";
1341
- return cc;
1342
- });
1343
- }
1344
- ret.cls = "punc";
1345
- return ret;
1346
- }
1347
- function elements(ctx, resume) {
1348
- if (match(ctx, TK_RIGHTBRACKET)) {
1349
- return resume;
1350
- }
1351
- return element(ctx, function (ctx) {
1352
- if (match(ctx, TK_COMMA)) {
1353
- eat(ctx, TK_COMMA);
1354
- var ret = function (ctx) {
1355
- return elements(ctx, resume);
1356
- };
1357
- ret.cls = "punc";
1358
- return ret;
1359
- }
1360
- return function (ctx) {
1361
- return elements(ctx, resume);
1362
- };
1363
- });
1364
- }
1365
- function element(ctx, resume) {
1366
- return expr(ctx, function(ctx) {
1367
- countCounter(ctx);
1368
- return resume(ctx);
1369
- });
1370
- }
1371
- function primaryExpr(ctx, cc) {
1372
- if (match(ctx, TK_NUM)) {
1373
- return number(ctx, cc);
1374
- } else if (match(ctx, TK_STR) || match(ctx, TK_STRPREFIX)) {
1375
- return str(ctx, cc);
1376
- } else if (match(ctx, TK_BOOL)) {
1377
- return bool(ctx, cc);
1378
- } else if (match(ctx, TK_NULL)) {
1379
- return nul(ctx, cc);
1380
- } else if (match(ctx, TK_LEFTBRACE)) {
1381
- return record(ctx, cc);
1382
- } else if (match(ctx, TK_LEFTPAREN)) {
1383
- return parenExpr(ctx, cc);
1384
- } else if (match(ctx, TK_LEFTBRACKET)) {
1385
- return list(ctx, cc);
1386
- } else if (match(ctx, TK_LEFTANGLE)) {
1387
- return lambda(ctx, cc);
1388
- }
1389
- return name(ctx, cc);
1390
- }
1391
- function postfixExpr(ctx, cc) {
1392
- return primaryExpr(ctx, function (ctx) {
1393
- if (match(ctx, TK_POSTOP)) {
1394
- eat(ctx, TK_POSTOP);
1395
- cc.cls = "operator";
1396
- Ast.postfixExpr(ctx, lexeme);
1397
- return cc;
1398
- }
1399
- return cc(ctx);
1400
- })
1401
- }
1402
-
1403
- function prefixExpr(ctx, cc) {
1404
- if (match(ctx, TK_MINUS)) {
1405
- eat(ctx, TK_MINUS);
1406
- var ret = function(ctx) {
1407
- return postfixExpr(ctx, function (ctx) {
1408
- Ast.prefixExpr(ctx, "NEG");
1409
- return cc;
1410
- })
1411
- }
1412
- ret.cls = "number" // use number because of convention
1413
- return ret;
1414
- }
1415
- return postfixExpr(ctx, cc);
1416
- }
1417
-
1418
- function getPrecedence(op) {
1419
- return {
1420
- "": 0
1421
- , "OR": 1
1422
- , "AND": 2
1423
- , "EQ": 3
1424
- , "NE": 3
1425
- , "LT": 4
1426
- , "GT": 4
1427
- , "LE": 4
1428
- , "GE": 4
1429
- , "CONCAT": 5
1430
- , "ADD": 5
1431
- , "SUB": 5
1432
- , "MUL": 6
1433
- , "DIV": 6
1434
- , "MOD": 6
1435
- , "POW": 7
1436
- }[op];
1437
- }
1438
-
1439
- function binaryExpr(ctx, prevOp, cc) {
1440
- return prefixExpr(ctx, function (ctx) {
1441
- if (match(ctx, TK_BINOP)) {
1442
- eat(ctx, TK_BINOP)
1443
- var ret = function (ctx) {
1444
- var op = env.findWord(ctx, lexeme).name
1445
- if (getPrecedence(prevOp) < getPrecedence(op)) {
1446
- return binaryExpr(ctx, op, function(ctx, prevOp) {
1447
- // This continuation's purpose is to construct a right recursive
1448
- // binary expression node. If the previous node is a binary node
1449
- // with equal or higher precedence, then we get here from the left
1450
- // recursive branch below and there is no way to know the current
1451
- // operator unless it gets passed as an argument, which is what
1452
- // prevOp is for.
1453
- if (prevOp !== void 0) {
1454
- op = prevOp
1455
- }
1456
- Ast.binaryExpr(ctx, op)
1457
- return cc(ctx)
1458
- })
1459
- } else {
1460
- Ast.binaryExpr(ctx, prevOp)
1461
- return binaryExpr(ctx, op, function(ctx, prevOp) {
1462
- if (prevOp !== void 0) {
1463
- op = prevOp
1464
- }
1465
- return cc(ctx, op)
1466
- })
1467
- }
1468
- }
1469
- ret.cls = "operator"
1470
- return ret
1471
- }
1472
- return cc(ctx)
1473
- })
1474
- }
1475
-
1476
- function relationalExpr(ctx, cc) {
1477
- return binaryExpr(ctx, "", function (ctx) {
1478
- return cc(ctx)
1479
- })
1480
- }
1481
-
1482
- function condExpr(ctx, cc) {
1483
- if (match(ctx, TK_CASE)) {
1484
- return caseExpr(ctx, cc)
1485
- }
1486
- return relationalExpr(ctx, cc)
1487
- }
1488
-
1489
- function caseExpr(ctx, cc) {
1490
- eat(ctx, TK_CASE);
1491
- var ret = function (ctx) {
1492
- return expr(ctx, function (ctx) {
1493
- startCounter(ctx);
1494
- return ofClauses(ctx, function (ctx) {
1495
- Ast.caseExpr(ctx, ctx.state.exprc);
1496
- stopCounter(ctx);
1497
- eat(ctx, TK_END);
1498
- cc.cls = "keyword";
1499
- return cc;
1500
- })
1501
- })
1502
- }
1503
- ret.cls = "keyword";
1504
- return ret;
1505
- }
1506
-
1507
- function ofClauses(ctx, cc) {
1508
- if (match(ctx, TK_OF)) {
1509
- return ofClause(ctx, function (ctx) {
1510
- countCounter(ctx);
1511
- if (match(ctx, TK_OF)) {
1512
- return ofClauses(ctx, cc);
1513
- }
1514
- return cc(ctx);
1515
- });
1516
- }
1517
- return cc(ctx);
1518
- }
1519
-
1520
- function ofClause (ctx, cc) {
1521
- eat(ctx, TK_OF);
1522
- var ret = function (ctx) {
1523
- return pattern(ctx, function (ctx) {
1524
- eat(ctx, TK_COLON);
1525
- var ret = function(ctx) {
1526
- return exprsStart(ctx, TK_OF, function(ctx) {
1527
- Ast.ofClause(ctx);
1528
- return cc(ctx);
1529
- });
1530
- }
1531
- ret.cls = "punc";
1532
- return ret;
1533
- });
1534
- }
1535
- ret.cls = "keyword";
1536
- return ret;
1537
- }
1538
-
1539
- function pattern(ctx, cc) {
1540
- // FIXME only matches idents and literals for now
1541
- return identOrString(ctx, cc);
1542
- }
1543
-
1544
- function thenClause(ctx, cc) {
1545
- eat(ctx, TK_THEN)
1546
- var ret = function (ctx) {
1547
- return exprsStart(ctx, TK_ELSE, function (ctx) {
1548
- if (match(ctx, TK_ELSE)) {
1549
- return elseClause(ctx, cc)
1550
- } else {
1551
- return cc(ctx)
1552
- }
1553
- })
1554
- }
1555
- ret.cls = "keyword"
1556
- return ret
1557
- }
1558
-
1559
- function elseClause(ctx, cc) {
1560
- eat(ctx, TK_ELSE)
1561
- var ret = function (ctx) {
1562
- return exprsStart(ctx, TK_END, cc)
1563
- }
1564
- ret.cls = "keyword"
1565
- return ret
1566
- }
1567
-
1568
- function expr(ctx, cc) {
1569
- var ret;
1570
- if (match(ctx, TK_LET)) {
1571
- ret = letDef(ctx, cc);
1572
- } else {
1573
- ret = condExpr(ctx, cc);
1574
- }
1575
- return ret;
1576
- }
1577
-
1578
- function emptyInput(ctx) {
1579
- return peek(ctx) === 0
1580
- }
1581
-
1582
- function emptyExpr(ctx) {
1583
- return emptyInput(ctx)
1584
- || match(ctx, TK_THEN)
1585
- || match(ctx, TK_ELSE)
1586
- || match(ctx, TK_OR)
1587
- || match(ctx, TK_END)
1588
- || match(ctx, TK_DOT);
1589
- }
1590
-
1591
- function countCounter(ctx) {
1592
- ctx.state.exprc++
1593
- }
1594
-
1595
- function startCounter(ctx) {
1596
- ctx.state.exprcStack.push(ctx.state.exprc)
1597
- ctx.state.exprc = 0
1598
- }
1599
-
1600
- function stopCounter(ctx) {
1601
- ctx.state.exprc = ctx.state.exprcStack.pop()
1602
- }
1603
-
1604
- function exprsStart(ctx, brk, cc) {
1605
- startCounter(ctx);
1606
- return exprs(ctx, brk, cc);
1607
- }
1608
-
1609
- function exprsFinish(ctx, cc) {
1610
- Ast.exprs(ctx, ctx.state.exprc)
1611
- stopCounter(ctx)
1612
- return cc(ctx)
1613
- }
1614
-
1615
- function exprs(ctx, brk, cc) {
1616
- if (match(ctx, TK_DOT)) { // second dot
1617
- eat(ctx, TK_DOT);
1618
- var ret = function(ctx) {
1619
- return exprsFinish(ctx, cc);
1620
- }
1621
- ret.cls = "punc";
1622
- return ret;
1623
- }
1624
- return expr(ctx, function (ctx) {
1625
- countCounter(ctx);
1626
- if (match(ctx, TK_DOT)) {
1627
- eat(ctx, TK_DOT);
1628
- var ret = function (ctx) {
1629
- if (emptyInput(ctx) || emptyExpr(ctx)) {
1630
- return exprsFinish(ctx, cc);
1631
- }
1632
- return exprs(ctx, brk, cc);
1633
- }
1634
- ret.cls = "punc";
1635
- return ret;
1636
- } else if (match(ctx, brk)) {
1637
- var ret = function (ctx) {
1638
- return exprsFinish(ctx, cc);
1639
- }
1640
- ret.cls = "punc";
1641
- return ret;
1642
- } else {
1643
- if (emptyInput(ctx) || emptyExpr(ctx)) {
1644
- return exprsFinish(ctx, cc);
1645
- }
1646
- return exprs(ctx, brk, cc);
1647
- }
1648
- return exprsFinish(ctx, cc);
1649
- });
1650
- }
1651
-
1652
- function program(ctx, cc) {
1653
- return exprsStart(ctx, TK_DOT, function (ctx) {
1654
- var nid;
1655
- while (Ast.peek(ctx) !== nid) {
1656
- var nid = Ast.pop(ctx);
1657
- folder.fold(ctx, nid) // fold the exprs on top
1658
- }
1659
- Ast.exprs(ctx, ctx.state.nodeStack.length, true);
1660
- Ast.program(ctx);
1661
- assert(cc===null, "internal error, expecting null continuation");
1662
- return cc;
1663
- });
1664
- }
1665
-
1666
- window.gcexports.program = program;
1667
-
1668
- /*
1669
-
1670
- fn = { head, body }
1671
-
1672
- */
1673
-
1674
- function letDef(ctx, cc) {
1675
- if (match(ctx, TK_LET)) {
1676
- eat(ctx, TK_LET);
1677
- var ret = function (ctx) {
1678
- var ret = defName(ctx, function (ctx) {
1679
- var name = Ast.node(ctx, Ast.pop(ctx)).elts[0];
1680
- // nid=0 means def not finished yet
1681
- env.addWord(ctx, name, {
1682
- tk: TK_IDENT,
1683
- cls: "function",
1684
- length: 0,
1685
- nid: 0,
1686
- name: name
1687
- });
1688
- ctx.state.paramc = 0;
1689
- env.enterEnv(ctx, name); // FIXME need to link to outer env
1690
- return params(ctx, TK_EQUAL, function (ctx) {
1691
- var func = env.findWord(ctx, topEnv(ctx).name);
1692
- func.length = ctx.state.paramc;
1693
- func.env = topEnv(ctx);
1694
- eat(ctx, TK_EQUAL);
1695
- var ret = function(ctx) {
1696
- return exprsStart(ctx, TK_DOT, function (ctx) {
1697
- var def = env.findWord(ctx, topEnv(ctx).name);
1698
- def.nid = Ast.peek(ctx); // save node id for aliased code
1699
- env.exitEnv(ctx);
1700
- Ast.letDef(ctx); // Clean up stack
1701
- return cc;
1702
- });
1703
- }
1704
- ret.cls = "punc";
1705
- return ret;
1706
- })
1707
- })
1708
- ret.cls = "def";
1709
- return ret;
1710
- }
1711
- ret.cls = "keyword";
1712
- return ret;
1713
- }
1714
- return name(ctx, cc);
1715
- }
1716
-
1717
- // TODO add argument for specifying the break token.
1718
- // e.g. TK_EQUAL | TK_VERTICALBAR
1719
- // params(ctx, brk, resume) {..}
1720
- function params(ctx, brk, cc) {
1721
- if (match(ctx, brk)) {
1722
- return cc
1723
- }
1724
- var ret = function (ctx) {
1725
- var ret = defName(ctx, (ctx) => {
1726
- Ast.pop(ctx); // Throw away name.
1727
- ctx.state.paramc++;
1728
- return params(ctx, brk, cc);
1729
- });
1730
- ret.cls = "param";
1731
- return ret;
1732
- };
1733
- ret.cls = "param";
1734
- return ret;
1735
- }
1736
-
1737
- function param(ctx, cc) {
1738
- return primaryExpr(ctx, function (ctx) {
1739
- return cc
1740
- });
1741
- }
1742
-
1743
- // Drive the parser
1744
-
1745
- function topEnv(ctx) {
1746
- return ctx.state.env[ctx.state.env.length-1];
1747
- }
1748
-
1749
- function parse(stream, state, resume) {
1750
- var ctx = {
1751
- scan: scanner(stream, state.env[0].lexicon),
1752
- state: state,
1753
- };
1754
- var cls
1755
- try {
1756
- var c;
1757
- while ((c = stream.peek()) && (c===' ' || c==='\t')) {
1758
- stream.next()
1759
- }
1760
- // if this is a blank line, treat it as a comment
1761
- if (stream.peek()===void 0) {
1762
- throw "comment"
1763
- }
1764
- // call the continuation and store the next continuation
1765
- if (state.cc === null) {
1766
- next(ctx)
1767
- return "comment"
1768
- }
1769
- var t0 = new Date;
1770
- var lastCC = state.cc
1771
- var cc = state.cc = state.cc(ctx, null)
1772
- if (cc) {
1773
- cls = cc.cls
1774
- }
1775
- if (cc === null) {
1776
- if (resume) {
1777
- // FIXME make all paths go through a resume function.
1778
- if (state.errors.length > 0) {
1779
- resume(state.errors);
1780
- } else {
1781
- resume(null, Ast.poolToJSON(ctx));
1782
- }
1783
- } else {
1784
- window.gcexports.errors = state.errors;
1785
- }
1786
- }
1787
- var c;
1788
- while ((c = stream.peek()) &&
1789
- (c===' ' || c==='\t')) {
1790
- stream.next()
1791
- }
1792
- } catch (x) {
1793
- if (x instanceof Error) {
1794
- next(ctx)
1795
- addError(ctx, x.message);
1796
- state.cc = null; // done for now.
1797
- cls = "error"
1798
- console.log(x.stack);
1799
- if (resume) {
1800
- resume(window.gcexports.errors);
1801
- }
1802
- } else if (x === "comment") {
1803
- cls = x
1804
- } else {
1805
- //throw x
1806
- next(ctx)
1807
- cls = "error"
1808
- console.log(x.stack);
1809
- }
1810
- }
1811
- var t1 = new Date;
1812
- parseCount++
1813
- parseTime += t1 - t0
1814
- window.gcexports.coords = state.coords;
1815
- return cls;
1816
- }
1817
-
1818
- var lexeme = ""
1819
-
1820
- function scanner(stream, globalLexicon) {
1821
-
1822
- return {
1823
- start: start ,
1824
- stream: stream,
1825
- lexeme: function () {
1826
- return lexeme
1827
- }
1828
- }
1829
-
1830
- // begin private functions
1831
-
1832
- function peekCC() {
1833
- return stream.peek() && stream.peek().charCodeAt(0) || 0;
1834
- }
1835
-
1836
- function nextCC() {
1837
- return stream.peek() && stream.next().charCodeAt(0) || 0;
1838
- }
1839
-
1840
- function start(ctx) {
1841
- var c;
1842
- lexeme = "";
1843
- while (stream.peek() !== void 0) {
1844
- switch ((c = stream.next().charCodeAt(0))) {
1845
- case 32: // space
1846
- case 9: // tab
1847
- case 10: // new line
1848
- case 13: // carriage return
1849
- c = ' ';
1850
- continue
1851
- case 46: // dot
1852
- if (isNumeric(stream.peek())) {
1853
- return number(c);
1854
- }
1855
- lexeme += String.fromCharCode(c);
1856
- return TK_DOT
1857
- case 44: // comma
1858
- lexeme += String.fromCharCode(c);
1859
- return TK_COMMA
1860
- case 58: // colon
1861
- lexeme += String.fromCharCode(c);
1862
- return TK_COLON
1863
- case 61: // equal
1864
- lexeme += String.fromCharCode(c);
1865
- return TK_EQUAL
1866
- case 40: // left paren
1867
- lexeme += String.fromCharCode(c);
1868
- return TK_LEFTPAREN
1869
- case 41: // right paren
1870
- lexeme += String.fromCharCode(c);
1871
- return TK_RIGHTPAREN
1872
- case 45: // dash
1873
- lexeme += String.fromCharCode(c);
1874
- return TK_MINUS
1875
- case 60: // left angle
1876
- lexeme += String.fromCharCode(c);
1877
- return TK_LEFTANGLE
1878
- case 62: // right angle
1879
- lexeme += String.fromCharCode(c);
1880
- return TK_RIGHTANGLE
1881
- case 91: // left bracket
1882
- lexeme += String.fromCharCode(c);
1883
- return TK_LEFTBRACKET
1884
- case 93: // right bracket
1885
- lexeme += String.fromCharCode(c);
1886
- return TK_RIGHTBRACKET
1887
- case 123: // left brace
1888
- lexeme += String.fromCharCode(c);
1889
- return TK_LEFTBRACE
1890
- case 125: // right brace
1891
- lexeme += String.fromCharCode(c);
1892
- if (ctx.state.inStr) {
1893
- return stringSuffix(ctx);
1894
- }
1895
- return TK_RIGHTBRACE
1896
- case CC_DOUBLEQUOTE:
1897
- case CC_SINGLEQUOTE:
1898
- case CC_BACKTICK:
1899
- return string(ctx, c)
1900
-
1901
- case 96: // backquote
1902
- case 47: // slash
1903
- case 92: // backslash
1904
- case 33: // !
1905
- case 124: // |
1906
- comment(c)
1907
- throw "comment"
1908
- case 94: // caret
1909
- case 44: // comma
1910
- case 42: // asterisk
1911
- lexeme += String.fromCharCode(c);
1912
- return c; // char code is the token id
1913
- default:
1914
- if ((c >= 'A'.charCodeAt(0) && c <= 'Z'.charCodeAt(0)) ||
1915
- (c >= 'a'.charCodeAt(0) && c <= 'z'.charCodeAt(0)) ||
1916
- (c === '_'.charCodeAt(0))) {
1917
- return ident(c);
1918
- } else if (isNumeric(c) || c === '.'.charCodeAt(0) && isNumeric(stream.peek())) {
1919
- //lex += String.fromCharCode(c);
1920
- //c = src.charCodeAt(curIndex++);
1921
- //return TK_NUM;
1922
- return number(c);
1923
- } else {
1924
- return 0;
1925
- }
1926
- }
1927
- }
1928
-
1929
- return 0;
1930
- }
1931
-
1932
- function isNumeric(c) {
1933
- if (typeof c === "string") {
1934
- c = c.charCodeAt(0);
1935
- }
1936
- return c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0);
1937
- }
1938
-
1939
- function number(c) {
1940
- // 123, 1.23, .123
1941
- while (isNumeric(c) || c === '.'.charCodeAt(0) && isNumeric(stream.peek())) {
1942
- lexeme += String.fromCharCode(c);
1943
- var s;
1944
- c = (s = stream.next()) ? s.charCodeAt(0) : 0
1945
- }
1946
- if (c) {
1947
- stream.backUp(1);
1948
- } // otherwise, we are at the end of stream
1949
- return TK_NUM;
1950
- }
1951
-
1952
- // "abc" --> "abc"
1953
- // "a${x}c" --> concat ["a", x, "b"]
1954
- function string(ctx, c) {
1955
- var quoteChar = c;
1956
- ctx.state.quoteCharStack.push(c);
1957
- lexeme += String.fromCharCode(c)
1958
- c = nextCC();
1959
- while (c !== quoteChar && c !== 0 &&
1960
- (quoteChar === CC_BACKTICK || !(c === CC_DOLLAR && peekCC() === CC_LEFTBRACE))) {
1961
- lexeme += String.fromCharCode(c);
1962
- var s;
1963
- c = nextCC();
1964
- }
1965
- if (c === CC_DOLLAR &&
1966
- peekCC() === CC_LEFTBRACE) {
1967
- nextCC(); // Eat CC_LEFTBRACE
1968
- lexeme = lexeme.substring(1); // Strip off punct.
1969
- return TK_STRPREFIX;
1970
- } else if (c) {
1971
- lexeme = lexeme.substring(1); // Strip off leading quote.
1972
- return TK_STR;
1973
- } else {
1974
- return 0
1975
- }
1976
- }
1977
-
1978
- function stringSuffix(ctx) {
1979
- var c, s;
1980
- var quoteCharStack = ctx.state.quoteCharStack;
1981
- var quoteChar = quoteCharStack[quoteCharStack.length - 1];
1982
- c = nextCC();
1983
- while (c !== quoteChar && c !== 0 &&
1984
- !(c === CC_DOLLAR &&
1985
- peekCC() === CC_LEFTBRACE)) {
1986
- lexeme += String.fromCharCode(c);
1987
- c = nextCC();
1988
- }
1989
- if (c === CC_DOLLAR &&
1990
- peekCC() === CC_LEFTBRACE) {
1991
- nextCC() ; // Eat brace.
1992
- lexeme = lexeme.substring(1); // Strip off leading brace and trailing brace.
1993
- return TK_STRMIDDLE;
1994
- } else if (c) {
1995
- quoteCharStack.pop();
1996
- lexeme = lexeme.substring(1); // Strip off leading braces.
1997
- return TK_STRSUFFIX;
1998
- } else {
1999
- return 0
2000
- }
2001
- }
2002
-
2003
- function comment(c) {
2004
- var quoteChar = c
2005
- c = (s = stream.next()) ? s.charCodeAt(0) : 0
2006
-
2007
- while (c !== quoteChar && c != 10 && c!= 13 && c !== 0) {
2008
- var s;
2009
- c = (s = stream.next()) ? s.charCodeAt(0) : 0
2010
- }
2011
-
2012
- return TK_COMMENT
2013
- }
2014
-
2015
- function ident(c) {
2016
- while ((c >= 'A'.charCodeAt(0) && c <= 'Z'.charCodeAt(0)) ||
2017
- (c >= 'a'.charCodeAt(0) && c <= 'z'.charCodeAt(0)) ||
2018
- (c === '-'.charCodeAt(0)) ||
2019
- (c === '@'.charCodeAt(0)) ||
2020
- (c === '+'.charCodeAt(0)) ||
2021
- (c === '#'.charCodeAt(0)) ||
2022
- (c === '_'.charCodeAt(0)) ||
2023
- (c === '~'.charCodeAt(0)) ||
2024
- (c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0)))
2025
- {
2026
- lexeme += String.fromCharCode(c);
2027
- c = stream.peek() ? stream.next().charCodeAt(0) : 0
2028
- }
2029
-
2030
- if (c) {
2031
- stream.backUp(1);
2032
- } // otherwise, we are at the end of stream
2033
-
2034
- var tk = TK_IDENT
2035
- if (keywords[lexeme]) {
2036
- tk = keywords[lexeme].tk;
2037
- } else if (globalLexicon[lexeme]) {
2038
- tk = globalLexicon[lexeme].tk
2039
- }
2040
- return tk;
2041
- }
2042
- }
2043
-
2044
- var parser = {
2045
- token: function(stream, state) {
2046
- return parse(stream, state)
2047
- },
2048
- parse: parse,
2049
- program: program,
2050
- }
2051
-
2052
- window.gcexports.parse = parser.parse
2053
- return parser
2054
- })(); // end parser
2055
-
2056
- var foldTime = 0
2057
-
2058
- window.gcexports.foldTime = function () {
2059
- return foldTime
2060
- }
2061
-
2062
- var folder = function() {
2063
- var _ = window.gcexports._;
2064
-
2065
- var table = {
2066
- "PROG" : program,
2067
- "EXPRS" : exprs,
2068
- "PAREN" : parenExpr,
2069
- "IDENT" : ident,
2070
- "BOOL" : bool,
2071
- "NUM" : num,
2072
- "STR" : str,
2073
- "PARENS" : unaryExpr,
2074
- "APPLY" : apply,
2075
- "LAMBDA" : lambda,
2076
- // "MUL": mul,
2077
- // "DIV": div,
2078
- // "SUB": sub,
2079
- "ADD": add,
2080
- "POW": pow,
2081
- "MOD": mod,
2082
- "CONCAT": concat,
2083
- // "OR": orelse,
2084
- // "AND": andalso,
2085
- // "NE": ne,
2086
- // "EQ": eq,
2087
- // "LT": lt,
2088
- // "GT": gt,
2089
- // "LE": le,
2090
- // "GE": ge,
2091
- "NEG": neg,
2092
- "LIST": list,
2093
- // "CASE": caseExpr,
2094
- // "OF": ofClause,
2095
- };
2096
-
2097
- var canvasWidth = 0;
2098
- var canvasHeight = 0;
2099
-
2100
- return {
2101
- fold: fold,
2102
- };
2103
-
2104
- // CONTROL FLOW ENDS HERE
2105
-
2106
- var nodePool;
2107
- var ctx;
2108
-
2109
- function fold(cx, nid) {
2110
- ctx = cx;
2111
- nodePool = ctx.state.nodePool;
2112
- var t0 = new Date;
2113
- visit(nid);
2114
- var t1 = new Date;
2115
- foldTime += (t1-t0);
2116
- }
2117
-
2118
- function visit(nid) {
2119
- var node = nodePool[nid];
2120
- if (node == null) {
2121
- return null;
2122
- }
2123
- if (node.tag === void 0) {
2124
- return [ ] // clean up stubs;
2125
- } else if (isFunction(table[node.tag])) {
2126
- // Have a primitive operation so apply it to construct a new node.
2127
- var ret = table[node.tag](node);
2128
- return ret;
2129
- }
2130
- expr(node);
2131
- }
2132
-
2133
- function isArray(v) {
2134
- return v instanceof Array;
2135
- }
2136
-
2137
- function isString(v) {
2138
- return typeof v === "string";
2139
- }
2140
-
2141
- function isPrimitive(v) {
2142
- return (
2143
- v === null ||
2144
- typeof v === "string" ||
2145
- typeof v === "number" ||
2146
- typeof v === "boolean"
2147
- );
2148
- }
2149
-
2150
- function isFunction(v) {
2151
- return v instanceof Function;
2152
- }
2153
-
2154
- // BEGIN VISITOR METHODS
2155
-
2156
- var edgesNode;
2157
-
2158
- function program(node) {
2159
- visit(node.elts[0]);
2160
- Ast.program(ctx);
2161
- }
2162
-
2163
- function caseExpr(node) {
2164
- visit(node.elts[node.elts.length-1]);
2165
- var expr = Ast.pop(ctx);
2166
- for (var i = node.elts.length-2; i >= 0; i--) {
2167
- var ofNode = ctx.state.nodePool[node.elts[i]];
2168
- var patternNode = ofNode.elts[1];
2169
- visit(patternNode);
2170
- var pattern = Ast.pop(ctx);
2171
- // if (Ast.intern(expr) === Ast.intern(pattern)) {
2172
- if (expr === pattern) {
2173
- visit(ofNode.elts[0]);
2174
- return;
2175
- }
2176
- }
2177
- }
2178
-
2179
- function ofClause(node) {
2180
- for (var i = 0; i < node.elts.length; i++) {
2181
- visit(node.elts[i]);
2182
- }
2183
- Ast.ofClause(ctx);
2184
- }
2185
- function pushNodeStack(ctx) {
2186
- ctx.state.nodeStackStack.push(ctx.state.nodeStack);
2187
- ctx.state.nodeStack = [];
2188
- }
2189
- function popNodeStack(ctx) {
2190
- var stack = ctx.state.nodeStack;
2191
- ctx.state.nodeStack = ctx.state.nodeStackStack.pop().concat(stack);
2192
- }
2193
-
2194
- function list(node) {
2195
- // Fold list
2196
- // for (var i = 0; i < node.elts.length; i++) {
2197
- // visit(node.elts[i]);
2198
- // }
2199
- pushNodeStack(ctx);
2200
- for (var i = node.elts.length - 1; i >= 0; i--) {
2201
- visit(node.elts[i]); // Keep original order.
2202
- }
2203
- Ast.list(ctx, ctx.state.nodeStack.length, null, true);
2204
- popNodeStack(ctx);
2205
- }
2206
-
2207
- function exprs(node) {
2208
- // Fold exprs in reverse order to get precedence right.
2209
- for (var i = node.elts.length - 1; i >= 0; i--) {
2210
- visit(node.elts[i]); // Keep original order.
2211
- }
2212
- ctx.state.exprc = node.elts.length;
2213
- }
2214
-
2215
- function lambda(node) {
2216
- // Fold initializers and apply args.
2217
- var inits = Ast.node(ctx, node.elts[3]).elts;
2218
- inits.forEach((init, i) => {
2219
- if (init) {
2220
- // If we have an init then fold it and replace in inits list.
2221
- folder.fold(ctx, Ast.intern(ctx, init));
2222
- inits[i] = Ast.pop(ctx);
2223
- }
2224
- });
2225
- // FIXME don't patch old node. construct a new one.
2226
- node.elts[3] = Ast.intern(ctx, {tag: "LIST", elts: inits});
2227
- var fnId = Ast.intern(ctx, node);
2228
- var argc = ctx.state.nodeStack.length;
2229
- Ast.apply(ctx, fnId, argc);
2230
- }
2231
-
2232
- function apply(node) {
2233
- for (var i = node.elts.length-1; i >= 0; i--) {
2234
- visit(node.elts[i]);
2235
- }
2236
- Ast.applyLate(ctx, node.elts.length);
2237
- }
2238
-
2239
- function expr(node) {
2240
- // Construct an expression node for the compiler.
2241
- Ast.name(ctx, node.tag, getCoord(ctx));
2242
- for (var i = node.elts.length-1; i >= 0; i--) {
2243
- visit(node.elts[i]);
2244
- }
2245
- Ast.expr(ctx, node.elts.length);
2246
- }
2247
-
2248
- function neg(node) {
2249
- visit(node.elts[0]);
2250
- Ast.neg(ctx);
2251
- }
2252
-
2253
- function parenExpr(node) {
2254
- pushNodeStack(ctx);
2255
- visit(node.elts[0]);
2256
- Ast.parenExpr(ctx);
2257
- popNodeStack(ctx);
2258
- }
2259
-
2260
- function unaryExpr(node) {
2261
- visit(node.elts[0]);
2262
- Ast.unaryExpr(ctx, node.tag);
2263
- }
2264
-
2265
- function add(node) {
2266
- visit(node.elts[0]);
2267
- visit(node.elts[1]);
2268
- Ast.add(ctx);
2269
- }
2270
-
2271
- function sub(node) {
2272
- visit(node.elts[0]);
2273
- visit(node.elts[1]);
2274
- Ast.sub(ctx);
2275
- }
2276
-
2277
- function mul(node) {
2278
- visit(node.elts[0]);
2279
- visit(node.elts[1]);
2280
- Ast.mul(ctx);
2281
- }
2282
-
2283
- function div(node) {
2284
- visit(node.elts[0]);
2285
- visit(node.elts[1]);
2286
- Ast.div(ctx);
2287
- }
2288
-
2289
- function pow(node) {
2290
- visit(node.elts[0]);
2291
- visit(node.elts[1]);
2292
- Ast.pow(ctx);
2293
- }
2294
-
2295
- function concat(node) {
2296
- visit(node.elts[0]);
2297
- Ast.concat(ctx);
2298
- }
2299
-
2300
- function mod(node) {
2301
- visit(node.elts[0]);
2302
- visit(node.elts[1]);
2303
- Ast.mod(ctx);
2304
- }
2305
-
2306
- function orelse(node) {
2307
- visit(node.elts[0]);
2308
- visit(node.elts[1]);
2309
- Ast.orelse(ctx);
2310
- }
2311
-
2312
- function andalso(node) {
2313
- visit(node.elts[0]);
2314
- visit(node.elts[1]);
2315
- Ast.andalso(ctx);
2316
- }
2317
-
2318
- function eq(node) {
2319
- visit(node.elts[0]);
2320
- visit(node.elts[1]);
2321
- Ast.eq(ctx);
2322
- }
2323
-
2324
- function ne(node) {
2325
- visit(node.elts[0]);
2326
- visit(node.elts[1]);
2327
- Ast.ne(ctx);
2328
- }
2329
-
2330
- function lt(node) {
2331
- visit(node.elts[0]);
2332
- visit(node.elts[1]);
2333
- Ast.lt(ctx);
2334
- }
2335
-
2336
- function gt(node) {
2337
- visit(node.elts[0]);
2338
- visit(node.elts[1]);
2339
- Ast.gt(ctx);
2340
- }
2341
-
2342
- function le(node) {
2343
- visit(node.elts[0]);
2344
- visit(node.elts[1]);
2345
- Ast.le(ctx);
2346
- }
2347
-
2348
- function ge(node) {
2349
- visit(node.elts[0]);
2350
- visit(node.elts[1]);
2351
- Ast.ge(ctx);
2352
- }
2353
-
2354
- function ident(node) {
2355
- var name = node.elts[0];
2356
- var word = env.findWord(ctx, name);
2357
- if (word) {
2358
- if (word.cls==="val") {
2359
- if (word.val) {
2360
- Ast.push(ctx, word.val);
2361
- visit(Ast.pop(ctx)); // reduce the val expr
2362
- } else if (word.nid) {
2363
- var wrd;
2364
- if ((wrd = Ast.node(ctx, word.nid)).tag === "LAMBDA") {
2365
- var argc = wrd.elts[0].elts.length;
2366
- Ast.apply(ctx, word.nid, argc);
2367
- } else {
2368
- Ast.push(ctx, word.nid);
2369
- }
2370
- } else if (word.name) {
2371
- Ast.push(ctx, node);
2372
- } else {
2373
- // push the original node to be resolved later.
2374
- Ast.push(ctx, node);
2375
- }
2376
- } else if (word.cls==="function") {
2377
- let coord = getCoord(ctx);
2378
- var elts = [];
2379
- for (var i = 0; i < word.length; i++) {
2380
- var elt = Ast.pop(ctx);
2381
- elts.push(elt);
2382
- }
2383
- if (word.nid) {
2384
- Ast.fold(ctx, word, elts);
2385
- } else {
2386
- Ast.push(ctx, {
2387
- tag: word.name,
2388
- elts: elts,
2389
- coord: coord,
2390
- });
2391
- folder.fold(ctx, Ast.pop(ctx));
2392
- }
2393
- } else {
2394
- assert(false);
2395
- }
2396
- } else {
2397
- //assert(false, "unresolved ident "+name);
2398
- Ast.push(ctx, node);
2399
- }
2400
- }
2401
-
2402
- function num(node) {
2403
- Ast.number(ctx, node.elts[0]);
2404
- }
2405
-
2406
- function str(node) {
2407
- Ast.string(ctx, node.elts[0]);
2408
- }
2409
-
2410
- function bool(node) {
2411
- Ast.bool(ctx, node.elts[0]);
2412
- }
2413
-
2414
- function nul(node) {
2415
- Ast.nul(ctx);
2416
- }
2417
-
2418
- function stub(node) {
2419
- return "";
2420
- }
2421
- }();
2422
-
2423
-
2424
- if (typeof exports !== "undefined") {
2425
- exports.parser = window.gcexports.parser;
2426
- }