• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

source-academy / py-slang / 23708009447

29 Mar 2026 11:27AM UTC coverage: 40.74% (-0.5%) from 41.233%
23708009447

Pull #124

github

web-flow
Merge e14b903ae into 7b1e59a17
Pull Request #124: Fix types of Python grammar

198 of 884 branches covered (22.4%)

Branch coverage included in aggregate %.

55 of 56 new or added lines in 2 files covered. (98.21%)

3 existing lines in 2 files now uncovered.

1223 of 2604 relevant lines covered (46.97%)

51.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.37
/src/parser/python-grammar.ts
1
// Generated automatically by nearley, version 2.20.1
2
// http://github.com/Hardmath123/nearley
3
function id(x: unknown[]) {
4
  return x[0];
8,824✔
5
}
6

7
import { ExprNS, FunctionParam, StmtNS } from "../ast-types";
3✔
8
import { Token } from "../tokenizer";
9
import pythonLexer from "./lexer";
3✔
10
import { toAstToken, toFunctionParam } from "./token-bridge";
3✔
11

12
const list = <T>([x]: [T]) => [x];
3✔
13
const drop = () => [];
45✔
14

15
/** Strip surrounding quotes and process escape sequences. */
16
function stripQuotes(s: string) {
17
  let inner;
18
  if (s.startsWith('"""') || s.startsWith("'''")) inner = s.slice(3, -3);
32✔
19
  else if (s.startsWith('"') || s.startsWith("'")) inner = s.slice(1, -1);
26!
20
  else return s;
×
21
  return inner.replace(/\\(["'\\\/bfnrtav0]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|.)/g, (_, ch) => {
32✔
22
    switch (ch[0]) {
7!
23
      case "n":
24
        return "\n";
2✔
25
      case "t":
26
        return "\t";
1✔
27
      case "r":
28
        return "\r";
×
29
      case "\\":
30
        return "\\";
1✔
31
      case "'":
32
        return "'";
×
33
      case '"':
34
        return '"';
×
35
      case "/":
36
        return "/";
×
37
      case "b":
38
        return "\b";
×
39
      case "f":
40
        return "\f";
×
41
      case "a":
42
        return "\x07";
×
43
      case "v":
44
        return "\x0B";
×
45
      case "0":
46
        return "\0";
1✔
47
      case "x":
48
        return String.fromCharCode(parseInt(ch.slice(1), 16));
1✔
49
      case "u":
50
        return String.fromCharCode(parseInt(ch.slice(1), 16));
×
51
      default:
52
        return "\\" + ch; // unrecognized escapes kept literally
1✔
53
    }
54
  });
55
}
56

57
// ── Leaf AST constructors (token → node) ────────────────────────────────
58
const astVariable = ([t]: [moo.Token]) => {
3✔
59
  const k = toAstToken(t);
322✔
60
  return new ExprNS.Variable(k, k, k);
322✔
61
};
62
const astBigInt = ([t]: [moo.Token]) => {
3✔
63
  const k = toAstToken(t);
318✔
64
  return new ExprNS.BigIntLiteral(k, k, t.value);
318✔
65
};
66
const astComplex = ([t]: [moo.Token]) => {
3✔
67
  const k = toAstToken(t);
12✔
68
  return new ExprNS.Complex(k, k, t.value);
12✔
69
};
70
const astNone = ([t]: [moo.Token]) => {
3✔
71
  const k = toAstToken(t);
7✔
72
  return new ExprNS.None(k, k);
7✔
73
};
74
const astString = ([t]: [moo.Token]) => {
3✔
75
  const k = toAstToken(t);
32✔
76
  return new ExprNS.Literal(k, k, stripQuotes(t.value));
32✔
77
};
78
const astTrue = ([t]: [moo.Token]) => {
3✔
79
  const k = toAstToken(t);
31✔
80
  return new ExprNS.Literal(k, k, true);
31✔
81
};
82
const astFalse = ([t]: [moo.Token]) => {
3✔
83
  const k = toAstToken(t);
1✔
84
  return new ExprNS.Literal(k, k, false);
1✔
85
};
86

87
// ── Operator AST constructors (children → node) ────────────────────────
88
const astBinary = ([l, op, r]: [ExprNS.Expr, Token, ExprNS.Expr]) =>
3✔
89
  new ExprNS.Binary(l.startToken, r.endToken, l, op, r);
72✔
90
const astBinaryTok = ([l, op, r]: [ExprNS.Expr, moo.Token, ExprNS.Expr]) =>
3✔
91
  new ExprNS.Binary(l.startToken, r.endToken, l, toAstToken(op), r);
6✔
92
const astBoolOp = ([l, op, r]: [ExprNS.Expr, moo.Token, ExprNS.Expr]) =>
3✔
93
  new ExprNS.BoolOp(l.startToken, r.endToken, l, toAstToken(op), r);
29✔
94
const astUnary = ([op, arg]: [moo.Token, ExprNS.Expr]) =>
3✔
95
  new ExprNS.Unary(toAstToken(op), arg.endToken, toAstToken(op), arg);
13✔
96
const astCompare = ([l, op, r]: [ExprNS.Expr, Token, ExprNS.Expr]) =>
3✔
97
  new ExprNS.Compare(l.startToken, r.endToken, l, op, r);
38✔
98

99
// ── Token / list helpers ────────────────────────────────────────────────
100
const tok = ([t]: [moo.Token]) => toAstToken(t);
103✔
101
const flatList = <T>([first, rest]: [T, [unknown, T][]]): T[] => [first, ...rest.map(d => d[1])];
162✔
102
const tokList = ([first, rest]: [moo.Token, [unknown, moo.Token][]]) => [
11✔
103
  toAstToken(first),
NEW
104
  ...rest.map(d => toAstToken(d[1])),
×
105
];
106
const Lexer = pythonLexer;
3✔
107
const ParserRules = [
3✔
108
  { name: "program$ebnf$1", symbols: [] },
109
  { name: "program$ebnf$1$subexpression$1", symbols: ["import_stmt", { type: "newline" }] },
110
  {
111
    name: "program$ebnf$1",
112
    symbols: ["program$ebnf$1", "program$ebnf$1$subexpression$1"],
113
    postprocess: function arrpush<T>(d: [T[], T]) {
114
      return d[0].concat([d[1]]);
7✔
115
    },
116
  },
117
  { name: "program$ebnf$2", symbols: [] },
118
  { name: "program$ebnf$2$subexpression$1", symbols: ["statement"] },
119
  { name: "program$ebnf$2$subexpression$1", symbols: [{ type: "newline" }] },
120
  {
121
    name: "program$ebnf$2",
122
    symbols: ["program$ebnf$2", "program$ebnf$2$subexpression$1"],
123
    postprocess: function arrpush<T>(d: [T[], T]) {
124
      return d[0].concat([d[1]]);
350✔
125
    },
126
  },
127
  {
128
    name: "program",
129
    symbols: ["program$ebnf$1", "program$ebnf$2"],
130
    postprocess: ([imports, stmts]: [
131
      [StmtNS.FromImport, moo.Token][],
132
      ([StmtNS.Stmt] | [moo.Token])[],
133
    ]) => {
134
      const importNodes = imports.map(d => d[0]);
628✔
135
      const stmtNodes = stmts.map(d => d[0]).filter(s => "startToken" in s);
628✔
136
      const filtered = [...importNodes, ...stmtNodes];
628✔
137
      const start = filtered[0]
628✔
138
        ? filtered[0].startToken
139
        : toAstToken({ type: "newline", value: "", line: 1, col: 1, offset: 0 });
140
      const end = filtered.length > 0 ? filtered[filtered.length - 1].endToken : start;
628✔
141
      return new StmtNS.FileInput(start, end, filtered, []);
628✔
142
    },
143
  },
144
  {
145
    name: "import_stmt",
146
    symbols: [{ literal: "from" }, "dotted_name", { literal: "import" }, "import_clause"],
147
    postprocess: ([kw, mod, , names]: [
148
      moo.Token,
149
      Token,
150
      moo.Token,
151
      StmtNS.FromImport["names"],
152
    ]) => {
153
      const last = names[names.length - 1];
8✔
154
      const endTok = last.alias || last.name;
8✔
155
      return new StmtNS.FromImport(toAstToken(kw), endTok, mod, names);
8✔
156
    },
157
  },
158
  { name: "dotted_name$ebnf$1", symbols: [] },
159
  { name: "dotted_name$ebnf$1$subexpression$1", symbols: [{ literal: "." }, { type: "name" }] },
160
  {
161
    name: "dotted_name$ebnf$1",
162
    symbols: ["dotted_name$ebnf$1", "dotted_name$ebnf$1$subexpression$1"],
163
    postprocess: function arrpush<T>(d: [T[], T]) {
164
      return d[0].concat([d[1]]);
2✔
165
    },
166
  },
167
  {
168
    name: "dotted_name",
169
    symbols: [{ type: "name" }, "dotted_name$ebnf$1"],
170
    postprocess: ([first, rest]: [moo.Token, [moo.Token, moo.Token][]]) => {
171
      const tok = toAstToken(first);
9✔
172
      for (const [, n] of rest) {
9✔
173
        const right = toAstToken(n);
2✔
174
        tok.lexeme = tok.lexeme + "." + right.lexeme;
2✔
175
      }
176
      return tok;
9✔
177
    },
178
  },
179
  { name: "import_clause", symbols: ["import_as_names"], postprocess: id },
180
  {
181
    name: "import_clause",
182
    symbols: [{ literal: "(" }, "import_as_names", { literal: ")" }],
183
    postprocess: ([, ns]: [moo.Token, StmtNS.FromImport["names"][number], moo.Token]) => ns,
3✔
184
  },
185
  { name: "import_as_names$ebnf$1", symbols: [] },
186
  { name: "import_as_names$ebnf$1$subexpression$1", symbols: [{ literal: "," }, "import_as_name"] },
187
  {
188
    name: "import_as_names$ebnf$1",
189
    symbols: ["import_as_names$ebnf$1", "import_as_names$ebnf$1$subexpression$1"],
190
    postprocess: function arrpush<T>(d: [T[], T]) {
191
      return d[0].concat([d[1]]);
3✔
192
    },
193
  },
194
  {
195
    name: "import_as_names",
196
    symbols: ["import_as_name", "import_as_names$ebnf$1"],
197
    postprocess: flatList,
198
  },
199
  {
200
    name: "import_as_name",
201
    symbols: [{ type: "name" }],
202
    postprocess: ([t]: [moo.Token]) => ({ name: toAstToken(t), alias: null }),
10✔
203
  },
204
  {
205
    name: "import_as_name",
206
    symbols: [{ type: "name" }, { literal: "as" }, { type: "name" }],
207
    postprocess: ([t, , a]: [moo.Token, moo.Token, moo.Token]) => ({
1✔
208
      name: toAstToken(t),
209
      alias: toAstToken(a),
210
    }),
211
  },
212
  { name: "statement", symbols: ["statementAssign", { type: "newline" }], postprocess: id },
213
  { name: "statement", symbols: ["statementAnnAssign", { type: "newline" }], postprocess: id },
214
  {
215
    name: "statement",
216
    symbols: ["statementSubscriptAssign", { type: "newline" }],
217
    postprocess: id,
218
  },
219
  { name: "statement", symbols: ["statementReturn", { type: "newline" }], postprocess: id },
220
  { name: "statement", symbols: ["statementPass", { type: "newline" }], postprocess: id },
221
  { name: "statement", symbols: ["statementBreak", { type: "newline" }], postprocess: id },
222
  { name: "statement", symbols: ["statementContinue", { type: "newline" }], postprocess: id },
223
  { name: "statement", symbols: ["statementGlobal", { type: "newline" }], postprocess: id },
224
  { name: "statement", symbols: ["statementNonlocal", { type: "newline" }], postprocess: id },
225
  { name: "statement", symbols: ["statementAssert", { type: "newline" }], postprocess: id },
226
  { name: "statement", symbols: ["statementExpr", { type: "newline" }], postprocess: id },
227
  { name: "statement", symbols: ["if_statement"], postprocess: id },
228
  { name: "statement", symbols: ["statementWhile"], postprocess: id },
229
  { name: "statement", symbols: ["statementFor"], postprocess: id },
230
  { name: "statement", symbols: ["statementDef"], postprocess: id },
231
  {
232
    name: "statementAssign",
233
    symbols: [{ type: "name" }, { literal: "=" }, "expression"],
234
    postprocess: ([n, , v]: [moo.Token, moo.Token, ExprNS.Expr]) => {
235
      const tok = toAstToken(n);
117✔
236
      return new StmtNS.Assign(tok, v.endToken, new ExprNS.Variable(tok, tok, tok), v);
117✔
237
    },
238
  },
239
  {
240
    name: "statementAnnAssign",
241
    symbols: [{ type: "name" }, { literal: ":" }, "expression", { literal: "=" }, "expression"],
242
    postprocess: ([n, , ann, , v]: [moo.Token, moo.Token, ExprNS.Expr, moo.Token, ExprNS.Expr]) => {
243
      const tok = toAstToken(n);
7✔
244
      return new StmtNS.AnnAssign(tok, v.endToken, new ExprNS.Variable(tok, tok, tok), v, ann);
7✔
245
    },
246
  },
247
  {
248
    name: "statementAnnAssign",
249
    symbols: [{ type: "name" }, { literal: ":" }, "expression"],
250
    postprocess: ([n, , ann]: [moo.Token, moo.Token, ExprNS.Expr]) => {
251
      const nameTok = toAstToken(n);
8✔
252
      const dummyVal = new ExprNS.None(ann.endToken, ann.endToken);
8✔
253
      return new StmtNS.AnnAssign(
8✔
254
        nameTok,
255
        ann.endToken,
256
        new ExprNS.Variable(nameTok, nameTok, nameTok),
257
        dummyVal,
258
        ann,
259
      );
260
    },
261
  },
262
  {
263
    name: "statementSubscriptAssign",
264
    symbols: [
265
      "expressionPost",
266
      { type: "lsqb" },
267
      "expression",
268
      { type: "rsqb" },
269
      { literal: "=" },
270
      "expression",
271
    ],
272
    postprocess: function (
273
      d: [ExprNS.Expr, moo.Token, ExprNS.Expr, moo.Token, moo.Token, ExprNS.Expr],
274
    ) {
275
      const obj = d[0],
3✔
276
        idx = d[2],
3✔
277
        rsqb = d[3],
3✔
278
        val = d[5];
3✔
279
      const sub = new ExprNS.Subscript(obj.startToken, toAstToken(rsqb), obj, idx);
3✔
280
      return new StmtNS.Assign(obj.startToken, val.endToken, sub, val);
3✔
281
    },
282
  },
283
  {
284
    name: "statementReturn",
285
    symbols: [{ literal: "return" }, "expression"],
286
    postprocess: ([kw, expr]: [moo.Token, ExprNS.Expr]) =>
287
      new StmtNS.Return(toAstToken(kw), expr.endToken, expr),
48✔
288
  },
289
  {
290
    name: "statementReturn",
291
    symbols: [{ literal: "return" }],
292
    postprocess: ([t]: [moo.Token]) => {
293
      const tok = toAstToken(t);
37✔
294
      return new StmtNS.Return(tok, tok, null);
37✔
295
    },
296
  },
297
  {
298
    name: "statementPass",
299
    symbols: [{ literal: "pass" }],
300
    postprocess: ([t]: [moo.Token]) => {
301
      const tok = toAstToken(t);
43✔
302
      return new StmtNS.Pass(tok, tok);
43✔
303
    },
304
  },
305
  {
306
    name: "statementBreak",
307
    symbols: [{ literal: "break" }],
308
    postprocess: ([t]: [moo.Token]) => {
309
      const tok = toAstToken(t);
3✔
310
      return new StmtNS.Break(tok, tok);
3✔
311
    },
312
  },
313
  {
314
    name: "statementContinue",
315
    symbols: [{ literal: "continue" }],
316
    postprocess: ([t]: [moo.Token]) => {
317
      const tok = toAstToken(t);
3✔
318
      return new StmtNS.Continue(tok, tok);
3✔
319
    },
320
  },
321
  {
322
    name: "statementGlobal",
323
    symbols: [{ literal: "global" }, { type: "name" }],
324
    postprocess: ([kw, n]: [moo.Token, moo.Token]) =>
325
      new StmtNS.Global(toAstToken(kw), toAstToken(n), toAstToken(n)),
1✔
326
  },
327
  {
328
    name: "statementNonlocal",
329
    symbols: [{ literal: "nonlocal" }, { type: "name" }],
330
    postprocess: ([kw, n]: [moo.Token, moo.Token]) =>
331
      new StmtNS.NonLocal(toAstToken(kw), toAstToken(n), toAstToken(n)),
9✔
332
  },
333
  {
334
    name: "statementAssert",
335
    symbols: [{ literal: "assert" }, "expression"],
336
    postprocess: ([kw, e]: [moo.Token, ExprNS.Expr]) =>
337
      new StmtNS.Assert(toAstToken(kw), e.endToken, e),
5✔
338
  },
339
  {
340
    name: "statementExpr",
341
    symbols: ["expression"],
342
    postprocess: ([e]: [ExprNS.Expr]) => new StmtNS.SimpleExpr(e.startToken, e.endToken, e),
438✔
343
  },
344
  {
345
    name: "statementWhile",
346
    symbols: [{ literal: "while" }, "expression", { literal: ":" }, "block"],
347
    postprocess: ([kw, test, , body]: [moo.Token, ExprNS.Expr, moo.Token, StmtNS.Stmt[]]) =>
348
      new StmtNS.While(toAstToken(kw), body[body.length - 1].endToken, test, body),
8✔
349
  },
350
  {
351
    name: "statementFor",
352
    symbols: [
353
      { literal: "for" },
354
      { type: "name" },
355
      { literal: "in" },
356
      "expression",
357
      { literal: ":" },
358
      "block",
359
    ],
360
    postprocess: ([kw, target, , iter, , body]: [
361
      moo.Token,
362
      moo.Token,
363
      moo.Token,
364
      ExprNS.Expr,
365
      moo.Token,
366
      StmtNS.Stmt[],
367
    ]) =>
368
      new StmtNS.For(
11✔
369
        toAstToken(kw),
370
        body[body.length - 1].endToken,
371
        toAstToken(target),
372
        iter,
373
        body,
374
      ),
375
  },
376
  {
377
    name: "statementDef",
378
    symbols: [{ literal: "def" }, { type: "name" }, "params", { literal: ":" }, "block"],
379
    postprocess: ([kw, name, params, , body]: [
380
      moo.Token,
381
      moo.Token,
382
      FunctionParam[],
383
      moo.Token,
384
      StmtNS.Stmt[],
385
    ]) =>
386
      new StmtNS.FunctionDef(
60✔
387
        toAstToken(kw),
388
        body[body.length - 1].endToken,
389
        toAstToken(name),
390
        params,
391
        body,
392
        [],
393
      ),
394
  },
395
  { name: "if_statement$ebnf$1", symbols: [] },
396
  {
397
    name: "if_statement$ebnf$1$subexpression$1",
398
    symbols: [{ literal: "elif" }, "expression", { literal: ":" }, "block"],
399
  },
400
  {
401
    name: "if_statement$ebnf$1",
402
    symbols: ["if_statement$ebnf$1", "if_statement$ebnf$1$subexpression$1"],
403
    postprocess: function arrpush<T>(d: [T[], T]) {
404
      return d[0].concat([d[1]]);
5✔
405
    },
406
  },
407
  {
408
    name: "if_statement$ebnf$2$subexpression$1",
409
    symbols: [{ literal: "else" }, { literal: ":" }, "block"],
410
  },
411
  {
412
    name: "if_statement$ebnf$2",
413
    symbols: ["if_statement$ebnf$2$subexpression$1"],
414
    postprocess: id,
415
  },
416
  { name: "if_statement$ebnf$2", symbols: [], postprocess: () => null },
34✔
417
  {
418
    name: "if_statement",
419
    symbols: [
420
      { literal: "if" },
421
      "expression",
422
      { literal: ":" },
423
      "block",
424
      "if_statement$ebnf$1",
425
      "if_statement$ebnf$2",
426
    ],
427
    postprocess: ([kw, test, , body, elifs, elseBlock]: [
428
      moo.Token,
429
      ExprNS.Expr,
430
      moo.Token,
431
      StmtNS.Stmt[],
432
      [moo.Token, ExprNS.Expr, moo.Token, StmtNS.Stmt[]][],
433
      [moo.Token, moo.Token, StmtNS.Stmt[]],
434
    ]) => {
435
      let else_ = elseBlock ? elseBlock[2] : null;
49✔
436
      for (let i = elifs.length - 1; i >= 0; i--) {
49✔
437
        const [ekw, etest, , ebody] = elifs[i];
11✔
438
        const endTok =
439
          else_ && else_.length > 0
11✔
440
            ? else_[else_.length - 1].endToken
441
            : ebody[ebody.length - 1].endToken;
442
        else_ = [new StmtNS.If(toAstToken(ekw), endTok, etest, ebody, else_)];
11✔
443
      }
444
      const endTok =
445
        else_ && else_.length > 0
49✔
446
          ? else_[else_.length - 1].endToken
447
          : body[body.length - 1].endToken;
448
      return new StmtNS.If(toAstToken(kw), endTok, test, body, else_);
49✔
449
    },
450
  },
451
  { name: "names$ebnf$1", symbols: [] },
452
  { name: "names$ebnf$1$subexpression$1", symbols: [{ literal: "," }, { type: "name" }] },
453
  {
454
    name: "names$ebnf$1",
455
    symbols: ["names$ebnf$1", "names$ebnf$1$subexpression$1"],
456
    postprocess: function arrpush<T>(d: [T[], T]) {
457
      return d[0].concat([d[1]]);
×
458
    },
459
  },
460
  { name: "names", symbols: [{ type: "name" }, "names$ebnf$1"], postprocess: tokList },
461
  { name: "block", symbols: ["blockInline", { type: "newline" }], postprocess: list },
462
  { name: "block$ebnf$1$subexpression$1", symbols: ["statement"] },
463
  { name: "block$ebnf$1$subexpression$1", symbols: [{ type: "newline" }] },
464
  { name: "block$ebnf$1", symbols: ["block$ebnf$1$subexpression$1"] },
465
  { name: "block$ebnf$1$subexpression$2", symbols: ["statement"] },
466
  { name: "block$ebnf$1$subexpression$2", symbols: [{ type: "newline" }] },
467
  {
468
    name: "block$ebnf$1",
469
    symbols: ["block$ebnf$1", "block$ebnf$1$subexpression$2"],
470
    postprocess: function arrpush<T>(d: [T[], T]) {
471
      return d[0].concat([d[1]]);
46✔
472
    },
473
  },
474
  {
475
    name: "block",
476
    symbols: [{ type: "newline" }, { type: "indent" }, "block$ebnf$1", { type: "dedent" }],
477
    postprocess: ([, , stmts]: [moo.Token, moo.Token, ([StmtNS.Stmt] | [moo.Token])[]]) =>
478
      stmts.map(d => d[0]).filter(s => s && "startToken" in s),
174✔
479
  },
480
  { name: "blockInline", symbols: ["statementAssign"], postprocess: id },
481
  { name: "blockInline", symbols: ["statementAnnAssign"], postprocess: id },
482
  { name: "blockInline", symbols: ["statementSubscriptAssign"], postprocess: id },
483
  { name: "blockInline", symbols: ["statementReturn"], postprocess: id },
484
  { name: "blockInline", symbols: ["statementPass"], postprocess: id },
485
  { name: "blockInline", symbols: ["statementBreak"], postprocess: id },
486
  { name: "blockInline", symbols: ["statementContinue"], postprocess: id },
487
  { name: "blockInline", symbols: ["statementGlobal"], postprocess: id },
488
  { name: "blockInline", symbols: ["statementNonlocal"], postprocess: id },
489
  { name: "blockInline", symbols: ["statementAssert"], postprocess: id },
490
  { name: "blockInline", symbols: ["statementExpr"], postprocess: id },
491
  {
492
    name: "rest_names",
493
    symbols: [{ type: "name" }],
494
    postprocess: ([t]: [moo.Token]) => {
495
      const tok = toFunctionParam(t, false);
13✔
496
      return [tok];
13✔
497
    },
498
  },
499
  {
500
    name: "rest_names",
501
    symbols: [{ literal: "*" }, { type: "name" }],
502
    postprocess: ([, t]: [moo.Token, moo.Token]) => {
503
      const tok = toFunctionParam(t, true);
4✔
504
      return [tok];
4✔
505
    },
506
  },
507
  {
508
    name: "rest_names",
509
    symbols: ["rest_names", { literal: "," }, { type: "name" }],
510
    postprocess: ([params, , t]: [FunctionParam[], moo.Token, moo.Token]) => {
511
      const tok = toFunctionParam(t, false);
14✔
512
      return [...params, tok];
14✔
513
    },
514
  },
515
  {
516
    name: "rest_names",
517
    symbols: ["rest_names", { literal: "," }, { literal: "*" }, { type: "name" }],
518
    postprocess: ([params, , , t]: [FunctionParam[], moo.Token, moo.Token, moo.Token]) => {
519
      const tok = toFunctionParam(t, true);
1✔
520
      return [...params, tok];
1✔
521
    },
522
  },
523
  { name: "params", symbols: [{ literal: "(" }, { literal: ")" }], postprocess: drop },
524
  {
525
    name: "params",
526
    symbols: [{ literal: "(" }, "rest_names", { literal: ")" }],
527
    postprocess: ([, ps]: [moo.Token, FunctionParam[], moo.Token]) => ps,
17✔
528
  },
529
  {
530
    name: "expression",
531
    symbols: ["expressionOr", { literal: "if" }, "expressionOr", { literal: "else" }, "expression"],
532
    postprocess: ([cons, , test, , alt]: [
533
      ExprNS.Expr,
534
      moo.Token,
535
      ExprNS.Expr,
536
      moo.Token,
537
      ExprNS.Expr,
538
    ]) => new ExprNS.Ternary(cons.startToken, alt.endToken, test, cons, alt),
8✔
539
  },
540
  { name: "expression", symbols: ["expressionOr"], postprocess: id },
541
  { name: "expression", symbols: ["lambda_expr"], postprocess: id },
542
  {
543
    name: "expressionOr",
544
    symbols: ["expressionOr", { literal: "or" }, "expressionAnd"],
545
    postprocess: astBoolOp,
546
  },
547
  { name: "expressionOr", symbols: ["expressionAnd"], postprocess: id },
548
  {
549
    name: "expressionAnd",
550
    symbols: ["expressionAnd", { literal: "and" }, "expressionNot"],
551
    postprocess: astBoolOp,
552
  },
553
  { name: "expressionAnd", symbols: ["expressionNot"], postprocess: id },
554
  { name: "expressionNot", symbols: [{ literal: "not" }, "expressionNot"], postprocess: astUnary },
555
  { name: "expressionNot", symbols: ["expressionCmp"], postprocess: id },
556
  {
557
    name: "expressionCmp",
558
    symbols: ["expressionCmp", "expressionCmpOp", "expressionAdd"],
559
    postprocess: astCompare,
560
  },
561
  { name: "expressionCmp", symbols: ["expressionAdd"], postprocess: id },
562
  { name: "expressionCmpOp", symbols: [{ type: "less" }], postprocess: tok },
563
  { name: "expressionCmpOp", symbols: [{ type: "greater" }], postprocess: tok },
564
  { name: "expressionCmpOp", symbols: [{ type: "doubleequal" }], postprocess: tok },
565
  { name: "expressionCmpOp", symbols: [{ type: "greaterequal" }], postprocess: tok },
566
  { name: "expressionCmpOp", symbols: [{ type: "lessequal" }], postprocess: tok },
567
  { name: "expressionCmpOp", symbols: [{ type: "notequal" }], postprocess: tok },
568
  { name: "expressionCmpOp", symbols: [{ literal: "in" }], postprocess: tok },
569
  {
570
    name: "expressionCmpOp",
571
    symbols: [{ literal: "not" }, { literal: "in" }],
572
    postprocess: ([t]: [moo.Token]) => {
573
      const tok = toAstToken(t);
3✔
574
      tok.lexeme = "not in";
3✔
575
      return tok;
3✔
576
    },
577
  },
578
  { name: "expressionCmpOp", symbols: [{ literal: "is" }], postprocess: tok },
579
  {
580
    name: "expressionCmpOp",
581
    symbols: [{ literal: "is" }, { literal: "not" }],
582
    postprocess: ([t]: [moo.Token]) => {
583
      const tok = toAstToken(t);
3✔
584
      tok.lexeme = "is not";
3✔
585
      return tok;
3✔
586
    },
587
  },
588
  {
589
    name: "expressionAdd",
590
    symbols: ["expressionAdd", "expressionAddOp", "expressionMul"],
591
    postprocess: astBinary,
592
  },
593
  { name: "expressionAdd", symbols: ["expressionMul"], postprocess: id },
594
  { name: "expressionAddOp", symbols: [{ type: "plus" }], postprocess: tok },
595
  { name: "expressionAddOp", symbols: [{ type: "minus" }], postprocess: tok },
596
  {
597
    name: "expressionMul",
598
    symbols: ["expressionMul", "expressionMulOp", "expressionUnary"],
599
    postprocess: astBinary,
600
  },
601
  { name: "expressionMul", symbols: ["expressionUnary"], postprocess: id },
602
  { name: "expressionMulOp", symbols: [{ type: "star" }], postprocess: tok },
603
  { name: "expressionMulOp", symbols: [{ type: "slash" }], postprocess: tok },
604
  { name: "expressionMulOp", symbols: [{ type: "percent" }], postprocess: tok },
605
  { name: "expressionMulOp", symbols: [{ type: "doubleslash" }], postprocess: tok },
606
  {
607
    name: "expressionUnary",
608
    symbols: [{ type: "plus" }, "expressionUnary"],
609
    postprocess: astUnary,
610
  },
611
  {
612
    name: "expressionUnary",
613
    symbols: [{ type: "minus" }, "expressionUnary"],
614
    postprocess: astUnary,
615
  },
616
  { name: "expressionUnary", symbols: ["expressionPow"], postprocess: id },
617
  {
618
    name: "expressionPow",
619
    symbols: ["expressionPost", { type: "doublestar" }, "expressionUnary"],
620
    postprocess: astBinaryTok,
621
  },
622
  { name: "expressionPow", symbols: ["expressionPost"], postprocess: id },
623
  {
624
    name: "expressionPost",
625
    symbols: ["expressionPost", { type: "lsqb" }, "expression", { type: "rsqb" }],
626
    postprocess: ([obj, , idx, rsqb]: [ExprNS.Expr, moo.Token, ExprNS.Expr, moo.Token]) =>
627
      new ExprNS.Subscript(obj.startToken, toAstToken(rsqb), obj, idx),
6✔
628
  },
629
  {
630
    name: "expressionPost",
631
    symbols: ["expressionPost", { literal: "(" }, "expressions", { literal: ")" }],
632
    postprocess: ([callee, , args, rparen]: [ExprNS.Expr, moo.Token, ExprNS.Expr[], moo.Token]) =>
633
      new ExprNS.Call(callee.startToken, toAstToken(rparen), callee, args),
56✔
634
  },
635
  {
636
    name: "expressionPost",
637
    symbols: ["expressionPost", { literal: "(" }, { literal: ")" }],
638
    postprocess: ([callee, , rparen]: [ExprNS.Expr, moo.Token, moo.Token]) =>
639
      new ExprNS.Call(callee.startToken, toAstToken(rparen), callee, []),
25✔
640
  },
641
  { name: "expressionPost", symbols: ["atom"], postprocess: id },
642
  {
643
    name: "atom",
644
    symbols: [{ literal: "(" }, "expression", { literal: ")" }],
645
    postprocess: ([, e]: [moo.Token, ExprNS.Expr, moo.Token]) =>
646
      new ExprNS.Grouping(e.startToken, e.endToken, e),
10✔
647
  },
648
  {
649
    name: "atom",
650
    symbols: [{ type: "lsqb" }, { type: "rsqb" }],
651
    postprocess: ([l, r]: [moo.Token, moo.Token]) =>
652
      new ExprNS.List(toAstToken(l), toAstToken(r), []),
4✔
653
  },
654
  {
655
    name: "atom",
656
    symbols: [{ type: "lsqb" }, "expressions", { type: "rsqb" }],
657
    postprocess: ([l, elems, r]: [moo.Token, ExprNS.Expr[], moo.Token]) =>
658
      new ExprNS.List(toAstToken(l), toAstToken(r), elems),
9✔
659
  },
660
  { name: "atom", symbols: [{ type: "name" }], postprocess: astVariable },
661
  {
662
    name: "atom",
663
    symbols: [{ type: "number_float" }],
664
    postprocess: ([t]: [moo.Token]) => {
665
      const tok = toAstToken(t);
11✔
666
      return new ExprNS.Literal(tok, tok, parseFloat(t.value));
11✔
667
    },
668
  },
669
  { name: "atom", symbols: [{ type: "number_int" }], postprocess: astBigInt },
670
  { name: "atom", symbols: [{ type: "number_hex" }], postprocess: astBigInt },
671
  { name: "atom", symbols: [{ type: "number_oct" }], postprocess: astBigInt },
672
  { name: "atom", symbols: [{ type: "number_bin" }], postprocess: astBigInt },
673
  { name: "atom", symbols: [{ type: "number_complex" }], postprocess: astComplex },
674
  { name: "atom", symbols: ["stringLit"], postprocess: id },
675
  { name: "atom", symbols: [{ literal: "None" }], postprocess: astNone },
676
  { name: "atom", symbols: [{ literal: "True" }], postprocess: astTrue },
677
  { name: "atom", symbols: [{ literal: "False" }], postprocess: astFalse },
678
  {
679
    name: "lambda_expr",
680
    symbols: [{ literal: "lambda" }, "names", { literal: ":" }, "expression"],
681
    postprocess: ([kw, params, , body]: [moo.Token, FunctionParam[], moo.Token, ExprNS.Expr]) =>
682
      new ExprNS.Lambda(toAstToken(kw), body.endToken, params, body),
16✔
683
  },
684
  {
685
    name: "lambda_expr",
686
    symbols: [{ literal: "lambda" }, "names", { type: "doublecolon" }, "block"],
687
    postprocess: ([kw, params, , body]: [moo.Token, FunctionParam[], moo.Token, StmtNS.Stmt[]]) =>
UNCOV
688
      new ExprNS.MultiLambda(toAstToken(kw), body[body.length - 1].endToken, params, body, []),
×
689
  },
690
  {
691
    name: "lambda_expr",
692
    symbols: [{ literal: "lambda" }, { literal: ":" }, "expression"],
693
    postprocess: ([kw, , body]: [moo.Token, moo.Token, ExprNS.Expr]) =>
694
      new ExprNS.Lambda(toAstToken(kw), body.endToken, [], body),
1✔
695
  },
696
  {
697
    name: "lambda_expr",
698
    symbols: [{ literal: "lambda" }, { type: "doublecolon" }, "block"],
699
    postprocess: ([kw, , body]: [moo.Token, moo.Token, StmtNS.Stmt[]]) =>
UNCOV
700
      new ExprNS.MultiLambda(toAstToken(kw), body[body.length - 1].endToken, [], body, []),
×
701
  },
702
  { name: "expressions$ebnf$1", symbols: [] },
703
  { name: "expressions$ebnf$1$subexpression$1", symbols: [{ literal: "," }, "expression"] },
704
  {
705
    name: "expressions$ebnf$1",
706
    symbols: ["expressions$ebnf$1", "expressions$ebnf$1$subexpression$1"],
707
    postprocess: function arrpush<T>(d: [T[], T]) {
708
      return d[0].concat([d[1]]);
39✔
709
    },
710
  },
711
  { name: "expressions$ebnf$2$subexpression$1", symbols: [{ type: "comma" }] },
712
  { name: "expressions$ebnf$2", symbols: ["expressions$ebnf$2$subexpression$1"], postprocess: id },
713
  { name: "expressions$ebnf$2", symbols: [], postprocess: () => null },
117✔
714
  {
715
    name: "expressions",
716
    symbols: ["expression", "expressions$ebnf$1", "expressions$ebnf$2"],
717
    postprocess: flatList,
718
  },
719
  { name: "stringLit", symbols: [{ type: "string_triple_double" }], postprocess: astString },
720
  { name: "stringLit", symbols: [{ type: "string_triple_single" }], postprocess: astString },
721
  { name: "stringLit", symbols: [{ type: "string_double" }], postprocess: astString },
722
  { name: "stringLit", symbols: [{ type: "string_single" }], postprocess: astString },
723
];
724
const ParserStart = "program";
3✔
725
export default { Lexer, ParserRules, ParserStart };
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc