@graffiticode/parser 0.1.0 → 0.1.2
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 +5 -9
- package/src/ast.js +730 -0
- package/src/env.js +50 -0
- package/src/folder.js +249 -0
- package/src/folder.spec.js +42 -0
- package/src/parse.js +35 -935
- package/src/parse.spec.js +118 -0
- package/src/parse.spec.js~ +119 -0
- package/src/parse.ts~ +1037 -0
- package/src/parser.spec.js +11 -35
- 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
package/src/parse.js
CHANGED
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
-- compiler checkers report these errors in the err callback arg
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import
|
|
15
|
-
import {
|
|
14
|
+
import { folder } from "./folder.js";
|
|
15
|
+
import { Ast } from "./ast.js";
|
|
16
|
+
import { Env } from "./env.js";
|
|
17
|
+
import { StringStream } from "./stringstream.js";
|
|
16
18
|
|
|
17
19
|
let CodeMirror;
|
|
18
20
|
if (typeof CodeMirror === "undefined") {
|
|
@@ -35,907 +37,6 @@ if (typeof window === "undefined") {
|
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
// ast module
|
|
39
|
-
|
|
40
|
-
export const Ast = (function () {
|
|
41
|
-
const ASSERT = true;
|
|
42
|
-
const assert = function (val, str) {
|
|
43
|
-
if (!ASSERT) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (str === undefined) {
|
|
47
|
-
str = "failed!";
|
|
48
|
-
}
|
|
49
|
-
if (!val) {
|
|
50
|
-
throw new Error(str);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const AstClass = function () { };
|
|
55
|
-
|
|
56
|
-
AstClass.prototype = {
|
|
57
|
-
intern,
|
|
58
|
-
node,
|
|
59
|
-
dump,
|
|
60
|
-
dumpAll,
|
|
61
|
-
poolToJSON,
|
|
62
|
-
number,
|
|
63
|
-
string,
|
|
64
|
-
name,
|
|
65
|
-
apply,
|
|
66
|
-
fold,
|
|
67
|
-
expr,
|
|
68
|
-
binaryExpr,
|
|
69
|
-
unaryExpr,
|
|
70
|
-
parenExpr,
|
|
71
|
-
prefixExpr,
|
|
72
|
-
lambda,
|
|
73
|
-
applyLate,
|
|
74
|
-
letDef,
|
|
75
|
-
ifExpr,
|
|
76
|
-
caseExpr,
|
|
77
|
-
ofClause,
|
|
78
|
-
record,
|
|
79
|
-
binding,
|
|
80
|
-
exprs,
|
|
81
|
-
program,
|
|
82
|
-
pop,
|
|
83
|
-
topNode,
|
|
84
|
-
peek,
|
|
85
|
-
push,
|
|
86
|
-
mod,
|
|
87
|
-
add,
|
|
88
|
-
sub,
|
|
89
|
-
// mul,
|
|
90
|
-
div,
|
|
91
|
-
pow,
|
|
92
|
-
concat,
|
|
93
|
-
eq,
|
|
94
|
-
ne,
|
|
95
|
-
lt,
|
|
96
|
-
gt,
|
|
97
|
-
le,
|
|
98
|
-
ge,
|
|
99
|
-
neg,
|
|
100
|
-
list,
|
|
101
|
-
bool,
|
|
102
|
-
nul,
|
|
103
|
-
error,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
return new AstClass();
|
|
107
|
-
|
|
108
|
-
// private implementation
|
|
109
|
-
|
|
110
|
-
function push(ctx, node) {
|
|
111
|
-
let nid;
|
|
112
|
-
if (typeof node === "number") { // if already interned
|
|
113
|
-
nid = node;
|
|
114
|
-
} else {
|
|
115
|
-
nid = intern(ctx, node);
|
|
116
|
-
}
|
|
117
|
-
ctx.state.nodeStack.push(nid);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function topNode(ctx) {
|
|
121
|
-
const nodeStack = ctx.state.nodeStack;
|
|
122
|
-
return nodeStack[nodeStack.length - 1];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function pop(ctx) {
|
|
126
|
-
const nodeStack = ctx.state.nodeStack;
|
|
127
|
-
return nodeStack.pop();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function peek(ctx, n) {
|
|
131
|
-
if (n === undefined) {
|
|
132
|
-
n = 0;
|
|
133
|
-
}
|
|
134
|
-
const nodeStack = ctx.state.nodeStack;
|
|
135
|
-
return nodeStack[nodeStack.length - 1 - n];
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function intern(ctx, n) {
|
|
139
|
-
if (!n) {
|
|
140
|
-
return 0;
|
|
141
|
-
}
|
|
142
|
-
const nodeMap = ctx.state.nodeMap;
|
|
143
|
-
const nodePool = ctx.state.nodePool;
|
|
144
|
-
const tag = n.tag;
|
|
145
|
-
let elts = "";
|
|
146
|
-
const count = n.elts.length;
|
|
147
|
-
for (let i = 0; i < count; i++) {
|
|
148
|
-
if (typeof n.elts[i] === "object") {
|
|
149
|
-
n.elts[i] = intern(ctx, n.elts[i]);
|
|
150
|
-
}
|
|
151
|
-
elts += n.elts[i];
|
|
152
|
-
}
|
|
153
|
-
const key = tag + count + elts;
|
|
154
|
-
let nid = nodeMap[key];
|
|
155
|
-
if (nid === undefined) {
|
|
156
|
-
nodePool.push({ tag, elts: n.elts });
|
|
157
|
-
nid = nodePool.length - 1;
|
|
158
|
-
nodeMap[key] = nid;
|
|
159
|
-
if (n.coord) {
|
|
160
|
-
ctx.state.coords[nid] = n.coord;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
return nid;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function node(ctx, nid) {
|
|
167
|
-
const n = ctx.state.nodePool[nid];
|
|
168
|
-
if (!nid) {
|
|
169
|
-
return null;
|
|
170
|
-
} else if (!n) {
|
|
171
|
-
return {};
|
|
172
|
-
}
|
|
173
|
-
const elts = [];
|
|
174
|
-
switch (n.tag) {
|
|
175
|
-
case "NULL":
|
|
176
|
-
break;
|
|
177
|
-
case "NUM":
|
|
178
|
-
case "STR":
|
|
179
|
-
case "IDENT":
|
|
180
|
-
case "BOOL":
|
|
181
|
-
elts[0] = n.elts[0];
|
|
182
|
-
break;
|
|
183
|
-
default:
|
|
184
|
-
for (let i = 0; i < n.elts.length; i++) {
|
|
185
|
-
elts[i] = node(ctx, n.elts[i]);
|
|
186
|
-
}
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
tag: n.tag,
|
|
191
|
-
elts,
|
|
192
|
-
coord: getCoord(ctx)
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function dumpAll(ctx) {
|
|
197
|
-
const nodePool = ctx.state.nodePool;
|
|
198
|
-
let s = "\n{";
|
|
199
|
-
for (let i = 1; i < nodePool.length; i++) {
|
|
200
|
-
const n = nodePool[i];
|
|
201
|
-
s = s + "\n " + i + ": " + dump(n) + ",";
|
|
202
|
-
}
|
|
203
|
-
s += "\n root: " + (nodePool.length - 1);
|
|
204
|
-
s += "\n}\n";
|
|
205
|
-
return s;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function poolToJSON(ctx) {
|
|
209
|
-
const nodePool = ctx.state.nodePool;
|
|
210
|
-
const obj = {};
|
|
211
|
-
for (let i = 1; i < nodePool.length; i++) {
|
|
212
|
-
const n = nodePool[i];
|
|
213
|
-
obj[i] = nodeToJSON(n);
|
|
214
|
-
}
|
|
215
|
-
obj.root = (nodePool.length - 1);
|
|
216
|
-
return obj;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function nodeToJSON(n) {
|
|
220
|
-
let obj;
|
|
221
|
-
if (typeof n === "object") {
|
|
222
|
-
switch (n.tag) {
|
|
223
|
-
case "num":
|
|
224
|
-
obj = n.elts[0];
|
|
225
|
-
break;
|
|
226
|
-
case "str":
|
|
227
|
-
obj = n.elts[0];
|
|
228
|
-
break;
|
|
229
|
-
default:
|
|
230
|
-
obj = {};
|
|
231
|
-
obj.tag = n.tag;
|
|
232
|
-
obj.elts = [];
|
|
233
|
-
for (let i = 0; i < n.elts.length; i++) {
|
|
234
|
-
obj.elts[i] = nodeToJSON(n.elts[i]);
|
|
235
|
-
}
|
|
236
|
-
break;
|
|
237
|
-
}
|
|
238
|
-
} else if (typeof n === "string") {
|
|
239
|
-
obj = n;
|
|
240
|
-
} else {
|
|
241
|
-
obj = n;
|
|
242
|
-
}
|
|
243
|
-
return obj;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function dump(n) {
|
|
247
|
-
let s;
|
|
248
|
-
if (typeof n === "object") {
|
|
249
|
-
switch (n.tag) {
|
|
250
|
-
case "num":
|
|
251
|
-
s = n.elts[0];
|
|
252
|
-
break;
|
|
253
|
-
case "str":
|
|
254
|
-
s = "\"" + n.elts[0] + "\"";
|
|
255
|
-
break;
|
|
256
|
-
default:
|
|
257
|
-
if (!n.elts) {
|
|
258
|
-
s += "<invalid>";
|
|
259
|
-
} else {
|
|
260
|
-
s = "{ tag: \"" + n.tag + "\", elts: [ ";
|
|
261
|
-
for (let i = 0; i < n.elts.length; i++) {
|
|
262
|
-
if (i > 0) {
|
|
263
|
-
s += " , ";
|
|
264
|
-
}
|
|
265
|
-
s += dump(n.elts[i]);
|
|
266
|
-
}
|
|
267
|
-
s += " ] }";
|
|
268
|
-
}
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
} else if (typeof n === "string") {
|
|
272
|
-
s = "\"" + n + "\"";
|
|
273
|
-
} else {
|
|
274
|
-
s = n;
|
|
275
|
-
}
|
|
276
|
-
return s;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
function fold(ctx, fn, args) {
|
|
280
|
-
// Local defs:
|
|
281
|
-
// -- put bindings in env
|
|
282
|
-
// Three cases:
|
|
283
|
-
// -- full application, all args are available at parse time
|
|
284
|
-
// -- partial application, only some args are available at parse time
|
|
285
|
-
// -- late application, args are available at compile time (not parse time)
|
|
286
|
-
// apply <[x y]: add x y> data..
|
|
287
|
-
// x: val 0 data
|
|
288
|
-
// y: val 1 data
|
|
289
|
-
env.enterEnv(ctx, fn.name);
|
|
290
|
-
if (fn.env) {
|
|
291
|
-
const lexicon = fn.env.lexicon;
|
|
292
|
-
const pattern = Ast.node(ctx, fn.env.pattern);
|
|
293
|
-
let outerEnv = null;
|
|
294
|
-
// let isListPattern;
|
|
295
|
-
// setup inner environment record (lexicon)
|
|
296
|
-
if (pattern && pattern.elts &&
|
|
297
|
-
pattern.elts.length === 1 &&
|
|
298
|
-
pattern.elts[0].tag === "LIST") {
|
|
299
|
-
// For now we only support one pattern per param list.
|
|
300
|
-
// isListPattern = true;
|
|
301
|
-
}
|
|
302
|
-
for (const id in lexicon) {
|
|
303
|
-
// For each parameter, get its definition assign the value of the argument
|
|
304
|
-
// used on the current function application.
|
|
305
|
-
if (!id) continue;
|
|
306
|
-
const word = JSON.parse(JSON.stringify(lexicon[id])); // poor man's copy.
|
|
307
|
-
const index = args.length - word.offset - 1;
|
|
308
|
-
// TODO we currently ignore list patterns
|
|
309
|
-
// if (isListPattern) {
|
|
310
|
-
// // <[x y]: ...> foo..
|
|
311
|
-
// word.nid = Ast.intern(ctx, {
|
|
312
|
-
// tag: "VAL",
|
|
313
|
-
// elts: [{
|
|
314
|
-
// tag: "NUM",
|
|
315
|
-
// elts: [
|
|
316
|
-
// String(word.offset),
|
|
317
|
-
// ]}, {
|
|
318
|
-
// tag: "ARG",
|
|
319
|
-
// elts: [{
|
|
320
|
-
// tag: "NUM",
|
|
321
|
-
// elts: ["0"]
|
|
322
|
-
// }]
|
|
323
|
-
// }]
|
|
324
|
-
// });
|
|
325
|
-
// } else
|
|
326
|
-
if (index >= 0 && index < args.length) {
|
|
327
|
-
word.nid = args[index];
|
|
328
|
-
}
|
|
329
|
-
if (index < 0) {
|
|
330
|
-
// We've got an unbound variable or a variable with a default value,
|
|
331
|
-
// so add it to the new variable list.
|
|
332
|
-
// <x:x> => <x:x>
|
|
333
|
-
// (<x y: add x y> 10) => <y: add 10 y>
|
|
334
|
-
// (<y: let x = 10.. add x y>) => <y: add 10 y>
|
|
335
|
-
if (!outerEnv) {
|
|
336
|
-
outerEnv = {};
|
|
337
|
-
}
|
|
338
|
-
outerEnv[id] = word;
|
|
339
|
-
}
|
|
340
|
-
env.addWord(ctx, id, word);
|
|
341
|
-
}
|
|
342
|
-
folder.fold(ctx, fn.nid);
|
|
343
|
-
if (outerEnv) {
|
|
344
|
-
lambda(ctx, {
|
|
345
|
-
lexicon: outerEnv,
|
|
346
|
-
pattern // FIXME need to trim pattern if some args where applied.
|
|
347
|
-
}, pop(ctx));
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
env.exitEnv(ctx);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function applyLate(ctx, count) {
|
|
354
|
-
// Ast.applyLate
|
|
355
|
-
const elts = [];
|
|
356
|
-
for (let i = count; i > 0; i--) {
|
|
357
|
-
elts.push(pop(ctx));
|
|
358
|
-
}
|
|
359
|
-
push(ctx, {
|
|
360
|
-
tag: "APPLY",
|
|
361
|
-
elts
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function apply(ctx, fnId, argc) {
|
|
366
|
-
// Construct function and apply available arguments.
|
|
367
|
-
const fn = node(ctx, fnId);
|
|
368
|
-
// if (fn.tag !== "LAMBDA") {
|
|
369
|
-
// // Construct an APPLY node for compiling later.
|
|
370
|
-
// return {
|
|
371
|
-
// tag: "APPLY",
|
|
372
|
-
// elts: [
|
|
373
|
-
// fnId,
|
|
374
|
-
// ]
|
|
375
|
-
// };
|
|
376
|
-
// }
|
|
377
|
-
// Construct a lexicon
|
|
378
|
-
const lexicon = {};
|
|
379
|
-
let paramc = 0;
|
|
380
|
-
fn.elts[0].elts.forEach(function (n, i) {
|
|
381
|
-
const name = n.elts[0];
|
|
382
|
-
const nid = Ast.intern(ctx, fn.elts[3].elts[i]);
|
|
383
|
-
lexicon[name] = {
|
|
384
|
-
cls: "val",
|
|
385
|
-
name,
|
|
386
|
-
offset: i,
|
|
387
|
-
nid
|
|
388
|
-
};
|
|
389
|
-
if (!nid) {
|
|
390
|
-
// Parameters don't have nids.
|
|
391
|
-
// assert that there are parameters after a binding without a nid.
|
|
392
|
-
paramc++;
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
const def = {
|
|
396
|
-
name: "lambda",
|
|
397
|
-
nid: Ast.intern(ctx, fn.elts[1]),
|
|
398
|
-
env: {
|
|
399
|
-
lexicon,
|
|
400
|
-
pattern: Ast.intern(ctx, fn.elts[2])
|
|
401
|
-
}
|
|
402
|
-
};
|
|
403
|
-
const elts = [];
|
|
404
|
-
// While there are args on the stack, pop them.
|
|
405
|
-
while (argc-- > 0 && paramc-- > 0) {
|
|
406
|
-
const elt = pop(ctx);
|
|
407
|
-
elts.unshift(elt); // Get the order right.
|
|
408
|
-
}
|
|
409
|
-
fold(ctx, def, elts);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Node constructors
|
|
413
|
-
|
|
414
|
-
function error(ctx, str, coord) {
|
|
415
|
-
console.log(
|
|
416
|
-
"error()",
|
|
417
|
-
"str=" + str,
|
|
418
|
-
"coord=" + JSON.stringify(coord),
|
|
419
|
-
);
|
|
420
|
-
const from = coord?.from !== undefined ? coord.from : -1;
|
|
421
|
-
const to = coord?.to !== undefined ? coord.to : -1;
|
|
422
|
-
number(ctx, to);
|
|
423
|
-
number(ctx, from);
|
|
424
|
-
string(ctx, str, coord);
|
|
425
|
-
push(ctx, {
|
|
426
|
-
tag: "ERROR",
|
|
427
|
-
elts: [
|
|
428
|
-
pop(ctx),
|
|
429
|
-
pop(ctx),
|
|
430
|
-
pop(ctx),
|
|
431
|
-
],
|
|
432
|
-
coord
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
function bool(ctx, val) {
|
|
437
|
-
let b;
|
|
438
|
-
if (val) {
|
|
439
|
-
b = true;
|
|
440
|
-
} else {
|
|
441
|
-
b = false;
|
|
442
|
-
}
|
|
443
|
-
push(ctx, {
|
|
444
|
-
tag: "BOOL",
|
|
445
|
-
elts: [b]
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
function nul(ctx) {
|
|
450
|
-
push(ctx, {
|
|
451
|
-
tag: "NULL",
|
|
452
|
-
elts: []
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
function number(ctx, num, coord) {
|
|
457
|
-
assert(typeof num === "string" || typeof num === "number");
|
|
458
|
-
push(ctx, {
|
|
459
|
-
tag: "NUM",
|
|
460
|
-
elts: [String(num)],
|
|
461
|
-
coord
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
function string(ctx, str, coord) {
|
|
466
|
-
push(ctx, {
|
|
467
|
-
tag: "STR",
|
|
468
|
-
elts: [str],
|
|
469
|
-
coord
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
function name(ctx, name, coord) {
|
|
474
|
-
push(ctx, {
|
|
475
|
-
tag: "IDENT",
|
|
476
|
-
elts: [name],
|
|
477
|
-
coord
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
function expr(ctx, argc) {
|
|
482
|
-
// Ast.expr -- construct a expr node for the compiler.
|
|
483
|
-
const elts = [];
|
|
484
|
-
const pos = getPos(ctx);
|
|
485
|
-
console.trace(
|
|
486
|
-
"expr()",
|
|
487
|
-
"argc=" + argc,
|
|
488
|
-
"nodeStack=" + JSON.stringify(ctx.state.nodeStack, null, 2),
|
|
489
|
-
);
|
|
490
|
-
assertErr(ctx, argc <= ctx.state.nodeStack.length - 1, `Too few arguments. Expected ${argc} got ${ctx.state.nodeStack.length - 1}.`, {
|
|
491
|
-
from: pos - 1, to: pos
|
|
492
|
-
});
|
|
493
|
-
while (argc--) {
|
|
494
|
-
const elt = pop(ctx);
|
|
495
|
-
elts.push(elt);
|
|
496
|
-
}
|
|
497
|
-
const nameId = pop(ctx);
|
|
498
|
-
console.log(
|
|
499
|
-
"expr()",
|
|
500
|
-
"nameId=" + nameId,
|
|
501
|
-
);
|
|
502
|
-
assertErr(ctx, nameId, "Ill formed node.");
|
|
503
|
-
const e = node(ctx, nameId).elts;
|
|
504
|
-
assertErr(ctx, e && e.length > 0, "Ill formed node.");
|
|
505
|
-
const name = e[0];
|
|
506
|
-
push(ctx, {
|
|
507
|
-
tag: name,
|
|
508
|
-
elts,
|
|
509
|
-
coord: getCoord(ctx)
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
function parenExpr(ctx, coord) {
|
|
514
|
-
// Ast.parenExpr
|
|
515
|
-
const elts = [];
|
|
516
|
-
const elt = pop(ctx);
|
|
517
|
-
elts.push(elt);
|
|
518
|
-
push(ctx, {
|
|
519
|
-
tag: "PAREN",
|
|
520
|
-
elts,
|
|
521
|
-
coord
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
function list(ctx, count, coord, reverse) {
|
|
526
|
-
// Ast.list
|
|
527
|
-
const elts = [];
|
|
528
|
-
for (let i = count; i > 0; i--) {
|
|
529
|
-
const elt = pop(ctx);
|
|
530
|
-
if (elt !== undefined) {
|
|
531
|
-
elts.push(elt);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
push(ctx, {
|
|
535
|
-
tag: "LIST",
|
|
536
|
-
elts: reverse ? elts : elts.reverse(),
|
|
537
|
-
coord
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
function binaryExpr(ctx, name) {
|
|
542
|
-
const elts = [];
|
|
543
|
-
// args are in the order produced by the parser
|
|
544
|
-
elts.push(pop(ctx));
|
|
545
|
-
elts.push(pop(ctx));
|
|
546
|
-
push(ctx, {
|
|
547
|
-
tag: name,
|
|
548
|
-
elts: elts.reverse()
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
function unaryExpr(ctx, name) {
|
|
552
|
-
const elts = [];
|
|
553
|
-
elts.push(pop(ctx));
|
|
554
|
-
push(ctx, {
|
|
555
|
-
tag: name,
|
|
556
|
-
elts
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
function prefixExpr(ctx, name) {
|
|
561
|
-
const elts = [];
|
|
562
|
-
elts.push(pop(ctx));
|
|
563
|
-
push(ctx, {
|
|
564
|
-
tag: name,
|
|
565
|
-
elts
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
function neg(ctx) {
|
|
570
|
-
const v1 = +node(ctx, pop(ctx)).elts[0];
|
|
571
|
-
number(ctx, -1 * v1);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
function add(ctx, coord) {
|
|
575
|
-
const n2 = node(ctx, pop(ctx));
|
|
576
|
-
const n1 = node(ctx, pop(ctx));
|
|
577
|
-
const v2 = n2.elts[0];
|
|
578
|
-
const v1 = n1.elts[0];
|
|
579
|
-
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
580
|
-
push(ctx, {
|
|
581
|
-
tag: "ADD",
|
|
582
|
-
elts: [n1, n2],
|
|
583
|
-
coord
|
|
584
|
-
});
|
|
585
|
-
} else {
|
|
586
|
-
number(ctx, +v1 + +v2);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
function sub(ctx) {
|
|
591
|
-
const n2 = node(ctx, pop(ctx));
|
|
592
|
-
const n1 = node(ctx, pop(ctx));
|
|
593
|
-
const v2 = n2.elts[0];
|
|
594
|
-
const v1 = n1.elts[0];
|
|
595
|
-
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
596
|
-
push(ctx, { tag: "SUB", elts: [n1, n2] });
|
|
597
|
-
} else {
|
|
598
|
-
number(ctx, +v1 - +v2);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
// function mul(ctx) {
|
|
603
|
-
// let n2 = node(ctx, pop(ctx));
|
|
604
|
-
// let n1 = node(ctx, pop(ctx));
|
|
605
|
-
// const v2 = n2.elts[0];
|
|
606
|
-
// const v1 = n1.elts[0];
|
|
607
|
-
// if (n1.tag === undefined) {
|
|
608
|
-
// n1 = n1.elts[0];
|
|
609
|
-
// }
|
|
610
|
-
// if (n2.tag === undefined) {
|
|
611
|
-
// n2 = n2.elts[0];
|
|
612
|
-
// }
|
|
613
|
-
// if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
614
|
-
// push(ctx, { tag: "MUL", elts: [n2, n1] });
|
|
615
|
-
// } else {
|
|
616
|
-
// number(ctx, +v1 * +v2);
|
|
617
|
-
// }
|
|
618
|
-
// }
|
|
619
|
-
|
|
620
|
-
function div(ctx) {
|
|
621
|
-
const n2 = node(ctx, pop(ctx));
|
|
622
|
-
const n1 = node(ctx, pop(ctx));
|
|
623
|
-
const v2 = n2.elts[0];
|
|
624
|
-
const v1 = n1.elts[0];
|
|
625
|
-
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
626
|
-
push(ctx, { tag: "DIV", elts: [n1, n2] });
|
|
627
|
-
} else {
|
|
628
|
-
number(ctx, +v1 / +v2);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
function mod(ctx) {
|
|
633
|
-
const n2 = node(ctx, pop(ctx));
|
|
634
|
-
const n1 = node(ctx, pop(ctx));
|
|
635
|
-
const v1 = n1.elts[0];
|
|
636
|
-
const v2 = n2.elts[0];
|
|
637
|
-
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
638
|
-
push(ctx, { tag: "MOD", elts: [n1, n2] });
|
|
639
|
-
} else {
|
|
640
|
-
number(ctx, +v1 % +v2);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
function pow(ctx) {
|
|
645
|
-
const n2 = node(ctx, pop(ctx));
|
|
646
|
-
const n1 = node(ctx, pop(ctx));
|
|
647
|
-
const v2 = n2.elts[0];
|
|
648
|
-
const v1 = n1.elts[0];
|
|
649
|
-
if (n1.tag !== "NUM" || n2.tag !== "NUM") {
|
|
650
|
-
push(ctx, { tag: "POW", elts: [n1, n2] });
|
|
651
|
-
} else {
|
|
652
|
-
number(ctx, Math.pow(+v1, +v2));
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
function concat(ctx) {
|
|
657
|
-
const n1 = node(ctx, pop(ctx));
|
|
658
|
-
push(ctx, {
|
|
659
|
-
tag: "CONCAT",
|
|
660
|
-
elts: [n1]
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
function eq(ctx) {
|
|
665
|
-
const v2 = node(ctx, pop(ctx)).elts[0];
|
|
666
|
-
const v1 = node(ctx, pop(ctx)).elts[0];
|
|
667
|
-
bool(ctx, v1 === v2);
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
function ne(ctx) {
|
|
671
|
-
const v2 = +node(ctx, pop(ctx)).elts[0];
|
|
672
|
-
const v1 = +node(ctx, pop(ctx)).elts[0];
|
|
673
|
-
bool(ctx, v1 !== v2);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
function lt(ctx) {
|
|
677
|
-
const v2 = +node(ctx, pop(ctx)).elts[0];
|
|
678
|
-
const v1 = +node(ctx, pop(ctx)).elts[0];
|
|
679
|
-
bool(ctx, v1 < v2);
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
function gt(ctx) {
|
|
683
|
-
const v2 = +node(ctx, pop(ctx)).elts[0];
|
|
684
|
-
const v1 = +node(ctx, pop(ctx)).elts[0];
|
|
685
|
-
bool(ctx, v1 > v2);
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
function le(ctx) {
|
|
689
|
-
const v2 = +node(ctx, pop(ctx)).elts[0];
|
|
690
|
-
const v1 = +node(ctx, pop(ctx)).elts[0];
|
|
691
|
-
bool(ctx, v1 <= v2);
|
|
692
|
-
}
|
|
693
|
-
function ge(ctx) {
|
|
694
|
-
const v2 = +node(ctx, pop(ctx)).elts[0];
|
|
695
|
-
const v1 = +node(ctx, pop(ctx)).elts[0];
|
|
696
|
-
bool(ctx, v1 >= v2);
|
|
697
|
-
}
|
|
698
|
-
function ifExpr(ctx) {
|
|
699
|
-
const elts = [];
|
|
700
|
-
elts.push(pop(ctx)); // if
|
|
701
|
-
elts.push(pop(ctx)); // then
|
|
702
|
-
elts.push(pop(ctx)); // else
|
|
703
|
-
push(ctx, { tag: "IF", elts: elts.reverse() });
|
|
704
|
-
}
|
|
705
|
-
function caseExpr(ctx, n) {
|
|
706
|
-
const elts = [];
|
|
707
|
-
elts.push(pop(ctx)); // val
|
|
708
|
-
for (let i = n; i > 0; i--) {
|
|
709
|
-
elts.push(pop(ctx)); // of
|
|
710
|
-
}
|
|
711
|
-
push(ctx, { tag: "CASE", elts: elts.reverse() });
|
|
712
|
-
}
|
|
713
|
-
function ofClause(ctx) {
|
|
714
|
-
const elts = [];
|
|
715
|
-
elts.push(pop(ctx));
|
|
716
|
-
elts.push(pop(ctx));
|
|
717
|
-
push(ctx, { tag: "OF", elts: elts.reverse() });
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
function record(ctx) {
|
|
721
|
-
// Ast.record
|
|
722
|
-
const count = ctx.state.exprc;
|
|
723
|
-
const elts = [];
|
|
724
|
-
for (let i = count; i > 0; i--) {
|
|
725
|
-
const elt = pop(ctx);
|
|
726
|
-
if (elt !== undefined) {
|
|
727
|
-
elts.push(elt);
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
push(ctx, {
|
|
731
|
-
tag: "RECORD",
|
|
732
|
-
elts
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
function binding(ctx) {
|
|
737
|
-
// Ast.binding
|
|
738
|
-
const elts = [];
|
|
739
|
-
elts.push(pop(ctx));
|
|
740
|
-
elts.push(pop(ctx));
|
|
741
|
-
push(ctx, {
|
|
742
|
-
tag: "BINDING",
|
|
743
|
-
elts: elts.reverse()
|
|
744
|
-
});
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
function lambda(ctx, env, nid) {
|
|
748
|
-
// Ast.lambda
|
|
749
|
-
const names = [];
|
|
750
|
-
const nids = [];
|
|
751
|
-
for (const id in env.lexicon) {
|
|
752
|
-
const word = env.lexicon[id];
|
|
753
|
-
names.push({
|
|
754
|
-
tag: "IDENT",
|
|
755
|
-
elts: [word.name],
|
|
756
|
-
coord: getCoord(ctx)
|
|
757
|
-
});
|
|
758
|
-
nids.push(word.nid || 0);
|
|
759
|
-
}
|
|
760
|
-
const pattern = env.pattern;
|
|
761
|
-
push(ctx, {
|
|
762
|
-
tag: "LAMBDA",
|
|
763
|
-
elts: [{
|
|
764
|
-
tag: "LIST",
|
|
765
|
-
elts: names
|
|
766
|
-
}, nid, {
|
|
767
|
-
tag: "LIST",
|
|
768
|
-
elts: pattern
|
|
769
|
-
}, {
|
|
770
|
-
tag: "LIST",
|
|
771
|
-
elts: nids
|
|
772
|
-
}]
|
|
773
|
-
});
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
function exprs(ctx, count, inReverse) {
|
|
777
|
-
// Ast.exprs
|
|
778
|
-
let elts = [];
|
|
779
|
-
assert(ctx.state.nodeStack.length >= count);
|
|
780
|
-
if (inReverse) {
|
|
781
|
-
for (let i = count; i > 0; i--) {
|
|
782
|
-
const elt = pop(ctx);
|
|
783
|
-
elts.push(elt); // Reverse order.
|
|
784
|
-
}
|
|
785
|
-
} else {
|
|
786
|
-
for (let i = count; i > 0; i--) {
|
|
787
|
-
const elt = pop(ctx);
|
|
788
|
-
elts.push(elt); // Reverse order.
|
|
789
|
-
}
|
|
790
|
-
elts = elts.reverse();
|
|
791
|
-
}
|
|
792
|
-
push(ctx, {
|
|
793
|
-
tag: "EXPRS",
|
|
794
|
-
elts
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
function letDef(ctx) {
|
|
799
|
-
// Clean up stack and produce initializer.
|
|
800
|
-
pop(ctx); // body
|
|
801
|
-
pop(ctx); // name
|
|
802
|
-
for (let i = 0; i < ctx.state.paramc; i++) {
|
|
803
|
-
pop(ctx); // params
|
|
804
|
-
}
|
|
805
|
-
ctx.state.exprc--; // don't count as expr.
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
function program(ctx) {
|
|
809
|
-
const elts = [];
|
|
810
|
-
elts.push(pop(ctx));
|
|
811
|
-
push(ctx, {
|
|
812
|
-
tag: "PROG",
|
|
813
|
-
elts
|
|
814
|
-
});
|
|
815
|
-
}
|
|
816
|
-
})();
|
|
817
|
-
|
|
818
|
-
// The following code for StreamString was copied from CodeMirror.
|
|
819
|
-
|
|
820
|
-
const StringStream = (function () {
|
|
821
|
-
// The character stream used by a mode's parser.
|
|
822
|
-
function StringStream(string, tabSize) {
|
|
823
|
-
this.pos = this.start = 0;
|
|
824
|
-
this.string = string;
|
|
825
|
-
this.tabSize = tabSize || 8;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
StringStream.prototype = {
|
|
829
|
-
eol: function () { return this.pos >= this.string.length; },
|
|
830
|
-
sol: function () { return this.pos === 0; },
|
|
831
|
-
peek: function () { return this.string.charAt(this.pos) || undefined; },
|
|
832
|
-
next: function () {
|
|
833
|
-
if (this.pos < this.string.length) { return this.string.charAt(this.pos++); }
|
|
834
|
-
},
|
|
835
|
-
eat: function (match) {
|
|
836
|
-
const ch = this.string.charAt(this.pos);
|
|
837
|
-
let ok;
|
|
838
|
-
if (typeof match === "string") {
|
|
839
|
-
ok = ch === match;
|
|
840
|
-
} else {
|
|
841
|
-
ok = ch && (match.test ? match.test(ch) : match(ch));
|
|
842
|
-
}
|
|
843
|
-
if (ok) { ++this.pos; return ch; }
|
|
844
|
-
},
|
|
845
|
-
eatWhile: function (match) {
|
|
846
|
-
const start = this.pos;
|
|
847
|
-
while (this.eat(match));
|
|
848
|
-
return this.pos > start;
|
|
849
|
-
},
|
|
850
|
-
eatSpace: function () {
|
|
851
|
-
const start = this.pos;
|
|
852
|
-
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
|
|
853
|
-
return this.pos > start;
|
|
854
|
-
},
|
|
855
|
-
skipToEnd: function () { this.pos = this.string.length; },
|
|
856
|
-
skipTo: function (ch) {
|
|
857
|
-
const found = this.string.indexOf(ch, this.pos);
|
|
858
|
-
if (found > -1) { this.pos = found; return true; }
|
|
859
|
-
},
|
|
860
|
-
backUp: function (n) { this.pos -= n; },
|
|
861
|
-
match: function (pattern, consume, caseInsensitive) {
|
|
862
|
-
assert(false, "Should not get here");
|
|
863
|
-
if (typeof pattern === "string") {
|
|
864
|
-
const cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
|
|
865
|
-
if (cased(this.string).indexOf(cased(pattern), this.pos) === this.pos) {
|
|
866
|
-
if (consume !== false) this.pos += pattern.length;
|
|
867
|
-
return true;
|
|
868
|
-
}
|
|
869
|
-
} else {
|
|
870
|
-
const match = this.string.slice(this.pos).match(pattern);
|
|
871
|
-
if (match && match.index > 0) return null;
|
|
872
|
-
if (match && consume !== false) this.pos += match[0].length;
|
|
873
|
-
return match;
|
|
874
|
-
}
|
|
875
|
-
},
|
|
876
|
-
current: function () { return this.string.slice(this.start, this.pos); }
|
|
877
|
-
};
|
|
878
|
-
|
|
879
|
-
return StringStream;
|
|
880
|
-
})();
|
|
881
|
-
|
|
882
|
-
// env
|
|
883
|
-
|
|
884
|
-
export const env = (function () {
|
|
885
|
-
return {
|
|
886
|
-
findWord,
|
|
887
|
-
addWord,
|
|
888
|
-
enterEnv,
|
|
889
|
-
exitEnv,
|
|
890
|
-
addPattern
|
|
891
|
-
};
|
|
892
|
-
|
|
893
|
-
// private functions
|
|
894
|
-
|
|
895
|
-
function findWord(ctx, lexeme) {
|
|
896
|
-
const env = ctx.state.env;
|
|
897
|
-
for (let i = env.length - 1; i >= 0; i--) {
|
|
898
|
-
const word = env[i].lexicon[lexeme];
|
|
899
|
-
if (word) {
|
|
900
|
-
return word;
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
return null;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
function addWord(ctx, lexeme, entry) {
|
|
907
|
-
window.gcexports.topEnv(ctx).lexicon[lexeme] = entry;
|
|
908
|
-
return null;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
function addPattern(ctx, pattern) {
|
|
912
|
-
window.gcexports.topEnv(ctx).pattern.push(pattern);
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
function enterEnv(ctx, name) {
|
|
916
|
-
// recursion guard
|
|
917
|
-
if (ctx.state.env.length > 380) {
|
|
918
|
-
console.trace(
|
|
919
|
-
"enterEnv()",
|
|
920
|
-
"name=" + name,
|
|
921
|
-
);
|
|
922
|
-
// return; // just stop recursing
|
|
923
|
-
throw new Error("runaway recursion");
|
|
924
|
-
}
|
|
925
|
-
window.gcexports.topEnv(ctx).paramc = ctx.state.paramc;
|
|
926
|
-
ctx.state.env.push({
|
|
927
|
-
name,
|
|
928
|
-
lexicon: {},
|
|
929
|
-
pattern: []
|
|
930
|
-
});
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
function exitEnv(ctx) {
|
|
934
|
-
ctx.state.env.pop();
|
|
935
|
-
ctx.state.paramc = window.gcexports.topEnv(ctx).paramc;
|
|
936
|
-
}
|
|
937
|
-
})();
|
|
938
|
-
|
|
939
40
|
let scanTime = 0;
|
|
940
41
|
let scanCount = 0;
|
|
941
42
|
window.gcexports.scanTime = function () {
|
|
@@ -957,24 +58,20 @@ window.gcexports.parseCount = function () {
|
|
|
957
58
|
};
|
|
958
59
|
|
|
959
60
|
function getCoord(ctx) {
|
|
960
|
-
return
|
|
961
|
-
from: ctx.scan.stream.start,
|
|
962
|
-
to: ctx.scan.stream.pos,
|
|
963
|
-
};
|
|
61
|
+
return ctx.state.nextTokenCoord;
|
|
964
62
|
}
|
|
965
63
|
|
|
966
64
|
function getPos(ctx) {
|
|
967
65
|
return ctx.scan.stream.pos;
|
|
968
66
|
}
|
|
969
67
|
|
|
970
|
-
function assertErr(ctx, b, str, coord) {
|
|
971
|
-
console.log(
|
|
972
|
-
"assertErr()",
|
|
973
|
-
"str=" + str,
|
|
974
|
-
);
|
|
68
|
+
export function assertErr(ctx, b, str, coord) {
|
|
975
69
|
if (!b) {
|
|
976
|
-
|
|
977
|
-
|
|
70
|
+
console.log(
|
|
71
|
+
"assertErr()",
|
|
72
|
+
"str=" + str,
|
|
73
|
+
);
|
|
74
|
+
Ast.error(ctx, str, coord);
|
|
978
75
|
throw new Error(str);
|
|
979
76
|
}
|
|
980
77
|
}
|
|
@@ -1108,7 +205,7 @@ export const parse = (function () {
|
|
|
1108
205
|
if (nextToken !== tk) {
|
|
1109
206
|
const to = getPos(ctx);
|
|
1110
207
|
const from = to - lexeme.length;
|
|
1111
|
-
|
|
208
|
+
assertErr(ctx, false, "Expecting " + tokenToLexeme(tk) +
|
|
1112
209
|
", found " + tokenToLexeme(nextToken) + ".", { from, to });
|
|
1113
210
|
next(ctx); // Advance past error.
|
|
1114
211
|
throw new Error("Expecting " + tokenToLexeme(tk) +
|
|
@@ -1135,11 +232,14 @@ export const parse = (function () {
|
|
|
1135
232
|
let tk;
|
|
1136
233
|
const nextToken = ctx.state.nextToken;
|
|
1137
234
|
if (nextToken < 0) {
|
|
235
|
+
const from = getPos(ctx);
|
|
1138
236
|
const t0 = new Date();
|
|
1139
237
|
tk = ctx.scan.start(ctx);
|
|
1140
238
|
const t1 = new Date();
|
|
1141
239
|
scanTime += (t1 - t0);
|
|
1142
240
|
ctx.state.nextToken = tk;
|
|
241
|
+
const to = getPos(ctx);
|
|
242
|
+
ctx.state.nextTokenCoord = { from, to };
|
|
1143
243
|
} else {
|
|
1144
244
|
tk = nextToken;
|
|
1145
245
|
}
|
|
@@ -1282,7 +382,7 @@ export const parse = (function () {
|
|
|
1282
382
|
return defList(ctx, cc);
|
|
1283
383
|
} else {
|
|
1284
384
|
eat(ctx, TK_IDENT);
|
|
1285
|
-
|
|
385
|
+
Env.addWord(ctx, lexeme, {
|
|
1286
386
|
tk: TK_IDENT,
|
|
1287
387
|
cls: "val",
|
|
1288
388
|
name: lexeme,
|
|
@@ -1299,7 +399,7 @@ export const parse = (function () {
|
|
|
1299
399
|
const to = getPos(ctx);
|
|
1300
400
|
const from = to - lexeme.length;
|
|
1301
401
|
const coord = { from, to };
|
|
1302
|
-
const word =
|
|
402
|
+
const word = Env.findWord(ctx, lexeme);
|
|
1303
403
|
if (word) {
|
|
1304
404
|
cc.cls = word.cls;
|
|
1305
405
|
if (word.cls === "number" && word.val) {
|
|
@@ -1315,11 +415,6 @@ export const parse = (function () {
|
|
|
1315
415
|
}
|
|
1316
416
|
} else {
|
|
1317
417
|
cc.cls = "error";
|
|
1318
|
-
console.log(
|
|
1319
|
-
"name()",
|
|
1320
|
-
"lexeme=" + lexeme,
|
|
1321
|
-
"coord=" + JSON.stringify(coord),
|
|
1322
|
-
);
|
|
1323
418
|
Ast.error(ctx, "Name '" + lexeme + "' not found.", coord);
|
|
1324
419
|
}
|
|
1325
420
|
// assert(cc, "name");
|
|
@@ -1376,7 +471,7 @@ export const parse = (function () {
|
|
|
1376
471
|
eat(ctx, TK_LEFTANGLE);
|
|
1377
472
|
const ret = function (ctx) {
|
|
1378
473
|
ctx.state.paramc = 0;
|
|
1379
|
-
|
|
474
|
+
Env.enterEnv(ctx, "lambda");
|
|
1380
475
|
return params(ctx, TK_COLON, function (ctx) {
|
|
1381
476
|
eat(ctx, TK_COLON);
|
|
1382
477
|
const ret = function (ctx) {
|
|
@@ -1384,7 +479,7 @@ export const parse = (function () {
|
|
|
1384
479
|
eat(ctx, TK_RIGHTANGLE);
|
|
1385
480
|
const nid = Ast.pop(ctx); // save body node id for aliased code
|
|
1386
481
|
Ast.lambda(ctx, topEnv(ctx), nid);
|
|
1387
|
-
|
|
482
|
+
Env.exitEnv(ctx);
|
|
1388
483
|
return cc;
|
|
1389
484
|
});
|
|
1390
485
|
};
|
|
@@ -1523,7 +618,7 @@ export const parse = (function () {
|
|
|
1523
618
|
if (match(ctx, TK_BINOP)) {
|
|
1524
619
|
eat(ctx, TK_BINOP);
|
|
1525
620
|
const ret = function (ctx) {
|
|
1526
|
-
let op =
|
|
621
|
+
let op = Env.findWord(ctx, lexeme).name;
|
|
1527
622
|
if (getPrecedence(prevOp) < getPrecedence(op)) {
|
|
1528
623
|
return binaryExpr(ctx, op, function (ctx, prevOp) {
|
|
1529
624
|
// This continuation's purpose is to construct a right recursive
|
|
@@ -1764,7 +859,7 @@ export const parse = (function () {
|
|
|
1764
859
|
let nid;
|
|
1765
860
|
while (Ast.peek(ctx) !== nid) {
|
|
1766
861
|
nid = Ast.pop(ctx);
|
|
1767
|
-
folder.fold(ctx, nid); //
|
|
862
|
+
folder.fold(ctx, nid); // Fold the exprs on top
|
|
1768
863
|
}
|
|
1769
864
|
Ast.exprs(ctx, ctx.state.nodeStack.length, true);
|
|
1770
865
|
Ast.program(ctx);
|
|
@@ -1788,7 +883,7 @@ export const parse = (function () {
|
|
|
1788
883
|
const ret = defName(ctx, function (ctx) {
|
|
1789
884
|
const name = Ast.node(ctx, Ast.pop(ctx)).elts[0];
|
|
1790
885
|
// nid=0 means def not finished yet
|
|
1791
|
-
|
|
886
|
+
Env.addWord(ctx, name, {
|
|
1792
887
|
tk: TK_IDENT,
|
|
1793
888
|
cls: "function",
|
|
1794
889
|
length: 0,
|
|
@@ -1796,17 +891,17 @@ export const parse = (function () {
|
|
|
1796
891
|
name
|
|
1797
892
|
});
|
|
1798
893
|
ctx.state.paramc = 0;
|
|
1799
|
-
|
|
894
|
+
Env.enterEnv(ctx, name); // FIXME need to link to outer env
|
|
1800
895
|
return params(ctx, TK_EQUAL, function (ctx) {
|
|
1801
|
-
const func =
|
|
896
|
+
const func = Env.findWord(ctx, topEnv(ctx).name);
|
|
1802
897
|
func.length = ctx.state.paramc;
|
|
1803
898
|
func.env = topEnv(ctx);
|
|
1804
899
|
eat(ctx, TK_EQUAL);
|
|
1805
900
|
const ret = function (ctx) {
|
|
1806
901
|
return exprsStart(ctx, TK_DOT, function (ctx) {
|
|
1807
|
-
const def =
|
|
902
|
+
const def = Env.findWord(ctx, topEnv(ctx).name);
|
|
1808
903
|
def.nid = Ast.peek(ctx); // save node id for aliased code
|
|
1809
|
-
|
|
904
|
+
Env.exitEnv(ctx);
|
|
1810
905
|
Ast.letDef(ctx); // Clean up stack
|
|
1811
906
|
return cc;
|
|
1812
907
|
});
|
|
@@ -1885,21 +980,24 @@ export const parse = (function () {
|
|
|
1885
980
|
}
|
|
1886
981
|
}
|
|
1887
982
|
while ((c = stream.peek()) &&
|
|
1888
|
-
(c === " " || c === "\t")) {
|
|
983
|
+
(c === " " || c === "\t" || c === "\n")) {
|
|
1889
984
|
stream.next();
|
|
1890
985
|
}
|
|
986
|
+
if (cc && !stream.peek()) {
|
|
987
|
+
assertErr(ctx, false, "End of progam reached.", getCoord(ctx));
|
|
988
|
+
}
|
|
1891
989
|
} catch (x) {
|
|
1892
|
-
console.log("catch() x=" + x);
|
|
990
|
+
// console.log("catch() x=" + x);
|
|
1893
991
|
if (x instanceof Error) {
|
|
1894
992
|
if (x.message === "comment") {
|
|
1895
993
|
cls = x;
|
|
1896
994
|
} else {
|
|
1897
995
|
console.log("catch() x=" + x.stack);
|
|
1898
996
|
// next(ctx);
|
|
997
|
+
state.cc = null; // done for now.
|
|
1899
998
|
return Ast.poolToJSON(ctx);
|
|
1900
|
-
// state.cc = null; // done for now.
|
|
1901
999
|
// cls = "error";
|
|
1902
|
-
//
|
|
1000
|
+
// throw new Error(JSON.stringify(window.gcexports.errors, null, 2));
|
|
1903
1001
|
}
|
|
1904
1002
|
} else {
|
|
1905
1003
|
// throw x
|
|
@@ -2068,6 +1166,8 @@ export const parse = (function () {
|
|
|
2068
1166
|
c = nextCC();
|
|
2069
1167
|
}
|
|
2070
1168
|
}
|
|
1169
|
+
const coord = { from: getPos(ctx) - lexeme.length, to: getPos(ctx) };
|
|
1170
|
+
assertErr(ctx, c !== 0, `Unterminated string: ${lexeme}`, coord);
|
|
2071
1171
|
if (quoteChar === CC_BACKTICK && c === CC_DOLLAR &&
|
|
2072
1172
|
peekCC() === CC_LEFTBRACE) {
|
|
2073
1173
|
nextCC(); // Eat CC_LEFTBRACE
|