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

source-academy / py-slang / 23708317062

29 Mar 2026 11:46AM UTC coverage: 39.893% (-1.3%) from 41.233%
23708317062

Pull #117

github

web-flow
Merge 40ad9bde1 into 7b1e59a17
Pull Request #117: Add Pyodide implementation

287 of 1043 branches covered (27.52%)

Branch coverage included in aggregate %.

43 of 43 new or added lines in 2 files covered. (100.0%)

13 existing lines in 1 file now uncovered.

1130 of 2509 relevant lines covered (45.04%)

53.8 hits per line

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

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

8
import { ExprNS, StmtNS } from "../ast-types";
9
import pythonLexer from "./lexer";
10
import { toAstToken } from "./token-bridge";
11

12
const nil = () => null;
3✔
13
const list = ([x]) => [x];
3✔
14
const drop = () => [];
45✔
15

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

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

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

96
// ── Token / list helpers ────────────────────────────────────────────────
97
const tok = ([t]) => toAstToken(t);
103✔
98
const flatList = ([first, rest]) => [first, ...rest.map(d => d[1])];
162✔
99
const tokList = ([first, rest]) => [toAstToken(first), ...rest.map(d => toAstToken(d[1]))];
11✔
100
let Lexer = pythonLexer;
3✔
101
let ParserRules = [
3✔
102
  { name: "program$ebnf$1", symbols: [] },
103
  {
104
    name: "program$ebnf$1$subexpression$1",
105
    symbols: ["import_stmt", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
106
  },
107
  {
108
    name: "program$ebnf$1",
109
    symbols: ["program$ebnf$1", "program$ebnf$1$subexpression$1"],
110
    postprocess: function arrpush(d) {
111
      return d[0].concat([d[1]]);
7✔
112
    },
113
  },
114
  { name: "program$ebnf$2", symbols: [] },
115
  { name: "program$ebnf$2$subexpression$1", symbols: ["statement"] },
116
  {
117
    name: "program$ebnf$2$subexpression$1",
118
    symbols: [pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
119
  },
120
  {
121
    name: "program$ebnf$2",
122
    symbols: ["program$ebnf$2", "program$ebnf$2$subexpression$1"],
123
    postprocess: function arrpush(d) {
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
      const importNodes = imports.map(d => d[0]);
628✔
132
      const stmtNodes = stmts.map(d => d[0]).filter(s => s && s.startToken !== undefined);
628✔
133
      const filtered = [...importNodes, ...stmtNodes];
628✔
134
      const start = filtered[0]
628✔
135
        ? filtered[0].startToken
136
        : toAstToken({ type: "newline", value: "", line: 1, col: 1, offset: 0 });
137
      const end = filtered.length > 0 ? filtered[filtered.length - 1].endToken : start;
628✔
138
      return new StmtNS.FileInput(start, end, filtered, []);
628✔
139
    },
140
  },
141
  {
142
    name: "import_stmt",
143
    symbols: [{ literal: "from" }, "dotted_name", { literal: "import" }, "import_clause"],
144
    postprocess: ([kw, mod, , names]) => {
145
      const last = names[names.length - 1];
8✔
146
      const endTok = last.alias || last.name;
8✔
147
      return new StmtNS.FromImport(toAstToken(kw), endTok, mod, names);
8✔
148
    },
149
  },
150
  { name: "dotted_name$ebnf$1", symbols: [] },
151
  {
152
    name: "dotted_name$ebnf$1$subexpression$1",
153
    symbols: [{ literal: "." }, pythonLexer.has("name") ? { type: "name" } : name],
3!
154
  },
155
  {
156
    name: "dotted_name$ebnf$1",
157
    symbols: ["dotted_name$ebnf$1", "dotted_name$ebnf$1$subexpression$1"],
158
    postprocess: function arrpush(d) {
159
      return d[0].concat([d[1]]);
2✔
160
    },
161
  },
162
  {
163
    name: "dotted_name",
164
    symbols: [pythonLexer.has("name") ? { type: "name" } : name, "dotted_name$ebnf$1"],
3!
165
    postprocess: ([first, rest]) => {
166
      let tok = toAstToken(first);
9✔
167
      for (const [, n] of rest) {
9✔
168
        const right = toAstToken(n);
2✔
169
        tok.lexeme = tok.lexeme + "." + right.lexeme;
2✔
170
      }
171
      return tok;
9✔
172
    },
173
  },
174
  { name: "import_clause", symbols: ["import_as_names"], postprocess: id },
175
  {
176
    name: "import_clause",
177
    symbols: [{ literal: "(" }, "import_as_names", { literal: ")" }],
178
    postprocess: ([, ns]) => ns,
3✔
179
  },
180
  { name: "import_as_names$ebnf$1", symbols: [] },
181
  { name: "import_as_names$ebnf$1$subexpression$1", symbols: [{ literal: "," }, "import_as_name"] },
182
  {
183
    name: "import_as_names$ebnf$1",
184
    symbols: ["import_as_names$ebnf$1", "import_as_names$ebnf$1$subexpression$1"],
185
    postprocess: function arrpush(d) {
186
      return d[0].concat([d[1]]);
3✔
187
    },
188
  },
189
  {
190
    name: "import_as_names",
191
    symbols: ["import_as_name", "import_as_names$ebnf$1"],
192
    postprocess: flatList,
193
  },
194
  {
195
    name: "import_as_name",
196
    symbols: [pythonLexer.has("name") ? { type: "name" } : name],
3!
197
    postprocess: ([t]) => ({ name: toAstToken(t), alias: null }),
10✔
198
  },
199
  {
200
    name: "import_as_name",
201
    symbols: [
202
      pythonLexer.has("name") ? { type: "name" } : name,
3!
203
      { literal: "as" },
204
      pythonLexer.has("name") ? { type: "name" } : name,
3!
205
    ],
206
    postprocess: ([t, , a]) => ({ name: toAstToken(t), alias: toAstToken(a) }),
1✔
207
  },
208
  {
209
    name: "statement",
210
    symbols: ["statementAssign", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
211
    postprocess: id,
212
  },
213
  {
214
    name: "statement",
215
    symbols: ["statementAnnAssign", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
216
    postprocess: id,
217
  },
218
  {
219
    name: "statement",
220
    symbols: [
221
      "statementSubscriptAssign",
222
      pythonLexer.has("newline") ? { type: "newline" } : newline,
3!
223
    ],
224
    postprocess: id,
225
  },
226
  {
227
    name: "statement",
228
    symbols: ["statementReturn", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
229
    postprocess: id,
230
  },
231
  {
232
    name: "statement",
233
    symbols: ["statementPass", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
234
    postprocess: id,
235
  },
236
  {
237
    name: "statement",
238
    symbols: ["statementBreak", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
239
    postprocess: id,
240
  },
241
  {
242
    name: "statement",
243
    symbols: ["statementContinue", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
244
    postprocess: id,
245
  },
246
  {
247
    name: "statement",
248
    symbols: ["statementGlobal", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
249
    postprocess: id,
250
  },
251
  {
252
    name: "statement",
253
    symbols: ["statementNonlocal", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
254
    postprocess: id,
255
  },
256
  {
257
    name: "statement",
258
    symbols: ["statementAssert", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
259
    postprocess: id,
260
  },
261
  {
262
    name: "statement",
263
    symbols: ["statementExpr", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
264
    postprocess: id,
265
  },
266
  { name: "statement", symbols: ["if_statement"], postprocess: id },
267
  { name: "statement", symbols: ["statementWhile"], postprocess: id },
268
  { name: "statement", symbols: ["statementFor"], postprocess: id },
269
  { name: "statement", symbols: ["statementDef"], postprocess: id },
270
  {
271
    name: "statementAssign",
272
    symbols: [pythonLexer.has("name") ? { type: "name" } : name, { literal: "=" }, "expression"],
3!
273
    postprocess: ([n, , v]) => {
274
      const tok = toAstToken(n);
117✔
275
      return new StmtNS.Assign(tok, v.endToken, new ExprNS.Variable(tok, tok, tok), v);
117✔
276
    },
277
  },
278
  {
279
    name: "statementAnnAssign",
280
    symbols: [
281
      pythonLexer.has("name") ? { type: "name" } : name,
3!
282
      { literal: ":" },
283
      "expression",
284
      { literal: "=" },
285
      "expression",
286
    ],
287
    postprocess: ([n, , ann, , v]) => {
288
      const tok = toAstToken(n);
7✔
289
      return new StmtNS.AnnAssign(tok, v.endToken, new ExprNS.Variable(tok, tok, tok), v, ann);
7✔
290
    },
291
  },
292
  {
293
    name: "statementAnnAssign",
294
    symbols: [pythonLexer.has("name") ? { type: "name" } : name, { literal: ":" }, "expression"],
3!
295
    postprocess: ([n, , ann]) => {
296
      const nameTok = toAstToken(n);
8✔
297
      const dummyVal = new ExprNS.None(ann.endToken, ann.endToken);
8✔
298
      return new StmtNS.AnnAssign(
8✔
299
        nameTok,
300
        ann.endToken,
301
        new ExprNS.Variable(nameTok, nameTok, nameTok),
302
        dummyVal,
303
        ann,
304
      );
305
    },
306
  },
307
  {
308
    name: "statementSubscriptAssign",
309
    symbols: [
310
      "expressionPost",
311
      pythonLexer.has("lsqb") ? { type: "lsqb" } : lsqb,
3!
312
      "expression",
313
      pythonLexer.has("rsqb") ? { type: "rsqb" } : rsqb,
3!
314
      { literal: "=" },
315
      "expression",
316
    ],
317
    postprocess: function (d) {
318
      var obj = d[0],
3✔
319
        idx = d[2],
3✔
320
        rsqb = d[3],
3✔
321
        val = d[5];
3✔
322
      var sub = new ExprNS.Subscript(obj.startToken, toAstToken(rsqb), obj, idx);
3✔
323
      return new StmtNS.Assign(obj.startToken, val.endToken, sub, val);
3✔
324
    },
325
  },
326
  {
327
    name: "statementReturn",
328
    symbols: [{ literal: "return" }, "expression"],
329
    postprocess: ([kw, expr]) => new StmtNS.Return(toAstToken(kw), expr.endToken, expr),
48✔
330
  },
331
  {
332
    name: "statementReturn",
333
    symbols: [{ literal: "return" }],
334
    postprocess: ([t]) => {
335
      const tok = toAstToken(t);
37✔
336
      return new StmtNS.Return(tok, tok, null);
37✔
337
    },
338
  },
339
  {
340
    name: "statementPass",
341
    symbols: [{ literal: "pass" }],
342
    postprocess: ([t]) => {
343
      const tok = toAstToken(t);
43✔
344
      return new StmtNS.Pass(tok, tok);
43✔
345
    },
346
  },
347
  {
348
    name: "statementBreak",
349
    symbols: [{ literal: "break" }],
350
    postprocess: ([t]) => {
351
      const tok = toAstToken(t);
3✔
352
      return new StmtNS.Break(tok, tok);
3✔
353
    },
354
  },
355
  {
356
    name: "statementContinue",
357
    symbols: [{ literal: "continue" }],
358
    postprocess: ([t]) => {
359
      const tok = toAstToken(t);
3✔
360
      return new StmtNS.Continue(tok, tok);
3✔
361
    },
362
  },
363
  {
364
    name: "statementGlobal",
365
    symbols: [{ literal: "global" }, pythonLexer.has("name") ? { type: "name" } : name],
3!
366
    postprocess: ([kw, n]) => new StmtNS.Global(toAstToken(kw), toAstToken(n), toAstToken(n)),
1✔
367
  },
368
  {
369
    name: "statementNonlocal",
370
    symbols: [{ literal: "nonlocal" }, pythonLexer.has("name") ? { type: "name" } : name],
3!
371
    postprocess: ([kw, n]) => new StmtNS.NonLocal(toAstToken(kw), toAstToken(n), toAstToken(n)),
9✔
372
  },
373
  {
374
    name: "statementAssert",
375
    symbols: [{ literal: "assert" }, "expression"],
376
    postprocess: ([kw, e]) => new StmtNS.Assert(toAstToken(kw), e.endToken, e),
5✔
377
  },
378
  {
379
    name: "statementExpr",
380
    symbols: ["expression"],
381
    postprocess: ([e]) => new StmtNS.SimpleExpr(e.startToken, e.endToken, e),
438✔
382
  },
383
  {
384
    name: "statementWhile",
385
    symbols: [{ literal: "while" }, "expression", { literal: ":" }, "block"],
386
    postprocess: ([kw, test, , body]) =>
387
      new StmtNS.While(toAstToken(kw), body[body.length - 1].endToken, test, body),
8✔
388
  },
389
  {
390
    name: "statementFor",
391
    symbols: [
392
      { literal: "for" },
393
      pythonLexer.has("name") ? { type: "name" } : name,
3!
394
      { literal: "in" },
395
      "expression",
396
      { literal: ":" },
397
      "block",
398
    ],
399
    postprocess: ([kw, target, , iter, , body]) =>
400
      new StmtNS.For(
11✔
401
        toAstToken(kw),
402
        body[body.length - 1].endToken,
403
        toAstToken(target),
404
        iter,
405
        body,
406
      ),
407
  },
408
  {
409
    name: "statementDef",
410
    symbols: [
411
      { literal: "def" },
412
      pythonLexer.has("name") ? { type: "name" } : name,
3!
413
      "params",
414
      { literal: ":" },
415
      "block",
416
    ],
417
    postprocess: ([kw, name, params, , body]) =>
418
      new StmtNS.FunctionDef(
60✔
419
        toAstToken(kw),
420
        body[body.length - 1].endToken,
421
        toAstToken(name),
422
        params,
423
        body,
424
        [],
425
      ),
426
  },
427
  { name: "if_statement$ebnf$1", symbols: [] },
428
  {
429
    name: "if_statement$ebnf$1$subexpression$1",
430
    symbols: [{ literal: "elif" }, "expression", { literal: ":" }, "block"],
431
  },
432
  {
433
    name: "if_statement$ebnf$1",
434
    symbols: ["if_statement$ebnf$1", "if_statement$ebnf$1$subexpression$1"],
435
    postprocess: function arrpush(d) {
436
      return d[0].concat([d[1]]);
5✔
437
    },
438
  },
439
  {
440
    name: "if_statement$ebnf$2$subexpression$1",
441
    symbols: [{ literal: "else" }, { literal: ":" }, "block"],
442
  },
443
  {
444
    name: "if_statement$ebnf$2",
445
    symbols: ["if_statement$ebnf$2$subexpression$1"],
446
    postprocess: id,
447
  },
448
  {
449
    name: "if_statement$ebnf$2",
450
    symbols: [],
451
    postprocess: function (d) {
452
      return null;
34✔
453
    },
454
  },
455
  {
456
    name: "if_statement",
457
    symbols: [
458
      { literal: "if" },
459
      "expression",
460
      { literal: ":" },
461
      "block",
462
      "if_statement$ebnf$1",
463
      "if_statement$ebnf$2",
464
    ],
465
    postprocess: ([kw, test, , body, elifs, elseBlock]) => {
466
      let else_ = elseBlock ? elseBlock[0][2] : null;
49✔
467
      for (let i = elifs.length - 1; i >= 0; i--) {
49✔
468
        const [ekw, etest, ecolon, ebody] = elifs[i];
11✔
469
        const endTok =
470
          else_ && else_.length > 0
11✔
471
            ? else_[else_.length - 1].endToken
472
            : ebody[ebody.length - 1].endToken;
473
        else_ = [new StmtNS.If(toAstToken(ekw), endTok, etest, ebody, else_)];
11✔
474
      }
475
      const endTok =
476
        else_ && else_.length > 0
49✔
477
          ? else_[else_.length - 1].endToken
478
          : body[body.length - 1].endToken;
479
      return new StmtNS.If(toAstToken(kw), endTok, test, body, else_);
49✔
480
    },
481
  },
482
  { name: "names$ebnf$1", symbols: [] },
483
  {
484
    name: "names$ebnf$1$subexpression$1",
485
    symbols: [{ literal: "," }, pythonLexer.has("name") ? { type: "name" } : name],
3!
486
  },
487
  {
488
    name: "names$ebnf$1",
489
    symbols: ["names$ebnf$1", "names$ebnf$1$subexpression$1"],
490
    postprocess: function arrpush(d) {
UNCOV
491
      return d[0].concat([d[1]]);
×
492
    },
493
  },
494
  {
495
    name: "names",
496
    symbols: [pythonLexer.has("name") ? { type: "name" } : name, "names$ebnf$1"],
3!
497
    postprocess: tokList,
498
  },
499
  {
500
    name: "block",
501
    symbols: ["blockInline", pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
502
    postprocess: list,
503
  },
504
  { name: "block$ebnf$1$subexpression$1", symbols: ["statement"] },
505
  {
506
    name: "block$ebnf$1$subexpression$1",
507
    symbols: [pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
508
  },
509
  { name: "block$ebnf$1", symbols: ["block$ebnf$1$subexpression$1"] },
510
  { name: "block$ebnf$1$subexpression$2", symbols: ["statement"] },
511
  {
512
    name: "block$ebnf$1$subexpression$2",
513
    symbols: [pythonLexer.has("newline") ? { type: "newline" } : newline],
3!
514
  },
515
  {
516
    name: "block$ebnf$1",
517
    symbols: ["block$ebnf$1", "block$ebnf$1$subexpression$2"],
518
    postprocess: function arrpush(d) {
519
      return d[0].concat([d[1]]);
46✔
520
    },
521
  },
522
  {
523
    name: "block",
524
    symbols: [
525
      pythonLexer.has("newline") ? { type: "newline" } : newline,
3!
526
      pythonLexer.has("indent") ? { type: "indent" } : indent,
3!
527
      "block$ebnf$1",
528
      pythonLexer.has("dedent") ? { type: "dedent" } : dedent,
3!
529
    ],
530
    postprocess: ([, , stmts]) => stmts.map(d => d[0]).filter(s => s && s.startToken !== undefined),
174✔
531
  },
532
  { name: "blockInline", symbols: ["statementAssign"], postprocess: id },
533
  { name: "blockInline", symbols: ["statementAnnAssign"], postprocess: id },
534
  { name: "blockInline", symbols: ["statementSubscriptAssign"], postprocess: id },
535
  { name: "blockInline", symbols: ["statementReturn"], postprocess: id },
536
  { name: "blockInline", symbols: ["statementPass"], postprocess: id },
537
  { name: "blockInline", symbols: ["statementBreak"], postprocess: id },
538
  { name: "blockInline", symbols: ["statementContinue"], postprocess: id },
539
  { name: "blockInline", symbols: ["statementGlobal"], postprocess: id },
540
  { name: "blockInline", symbols: ["statementNonlocal"], postprocess: id },
541
  { name: "blockInline", symbols: ["statementAssert"], postprocess: id },
542
  { name: "blockInline", symbols: ["statementExpr"], postprocess: id },
543
  {
544
    name: "rest_names",
545
    symbols: [pythonLexer.has("name") ? { type: "name" } : name],
3!
546
    postprocess: ([t]) => {
547
      const tok = toAstToken(t);
13✔
548
      tok.isStarred = false;
13✔
549
      return [tok];
13✔
550
    },
551
  },
552
  {
553
    name: "rest_names",
554
    symbols: [{ literal: "*" }, pythonLexer.has("name") ? { type: "name" } : name],
3!
555
    postprocess: ([, t]) => {
556
      const tok = toAstToken(t);
4✔
557
      tok.isStarred = true;
4✔
558
      return [tok];
4✔
559
    },
560
  },
561
  {
562
    name: "rest_names",
563
    symbols: ["rest_names", { literal: "," }, pythonLexer.has("name") ? { type: "name" } : name],
3!
564
    postprocess: ([params, , t]) => {
565
      const tok = toAstToken(t);
14✔
566
      tok.isStarred = false;
14✔
567
      return [...params, tok];
14✔
568
    },
569
  },
570
  {
571
    name: "rest_names",
572
    symbols: [
573
      "rest_names",
574
      { literal: "," },
575
      { literal: "*" },
576
      pythonLexer.has("name") ? { type: "name" } : name,
3!
577
    ],
578
    postprocess: ([params, , , t]) => {
579
      const tok = toAstToken(t);
1✔
580
      tok.isStarred = true;
1✔
581
      return [...params, tok];
1✔
582
    },
583
  },
584
  { name: "params", symbols: [{ literal: "(" }, { literal: ")" }], postprocess: drop },
585
  {
586
    name: "params",
587
    symbols: [{ literal: "(" }, "rest_names", { literal: ")" }],
588
    postprocess: ([, ps]) => ps,
17✔
589
  },
590
  {
591
    name: "expression",
592
    symbols: ["expressionOr", { literal: "if" }, "expressionOr", { literal: "else" }, "expression"],
593
    postprocess: ([cons, , test, , alt]) =>
594
      new ExprNS.Ternary(cons.startToken, alt.endToken, test, cons, alt),
8✔
595
  },
596
  { name: "expression", symbols: ["expressionOr"], postprocess: id },
597
  { name: "expression", symbols: ["lambda_expr"], postprocess: id },
598
  {
599
    name: "expressionOr",
600
    symbols: ["expressionOr", { literal: "or" }, "expressionAnd"],
601
    postprocess: astBoolOp,
602
  },
603
  { name: "expressionOr", symbols: ["expressionAnd"], postprocess: id },
604
  {
605
    name: "expressionAnd",
606
    symbols: ["expressionAnd", { literal: "and" }, "expressionNot"],
607
    postprocess: astBoolOp,
608
  },
609
  { name: "expressionAnd", symbols: ["expressionNot"], postprocess: id },
610
  { name: "expressionNot", symbols: [{ literal: "not" }, "expressionNot"], postprocess: astUnary },
611
  { name: "expressionNot", symbols: ["expressionCmp"], postprocess: id },
612
  {
613
    name: "expressionCmp",
614
    symbols: ["expressionCmp", "expressionCmpOp", "expressionAdd"],
615
    postprocess: astCompare,
616
  },
617
  { name: "expressionCmp", symbols: ["expressionAdd"], postprocess: id },
618
  {
619
    name: "expressionCmpOp",
620
    symbols: [pythonLexer.has("less") ? { type: "less" } : less],
3!
621
    postprocess: tok,
622
  },
623
  {
624
    name: "expressionCmpOp",
625
    symbols: [pythonLexer.has("greater") ? { type: "greater" } : greater],
3!
626
    postprocess: tok,
627
  },
628
  {
629
    name: "expressionCmpOp",
630
    symbols: [pythonLexer.has("doubleequal") ? { type: "doubleequal" } : doubleequal],
3!
631
    postprocess: tok,
632
  },
633
  {
634
    name: "expressionCmpOp",
635
    symbols: [pythonLexer.has("greaterequal") ? { type: "greaterequal" } : greaterequal],
3!
636
    postprocess: tok,
637
  },
638
  {
639
    name: "expressionCmpOp",
640
    symbols: [pythonLexer.has("lessequal") ? { type: "lessequal" } : lessequal],
3!
641
    postprocess: tok,
642
  },
643
  {
644
    name: "expressionCmpOp",
645
    symbols: [pythonLexer.has("notequal") ? { type: "notequal" } : notequal],
3!
646
    postprocess: tok,
647
  },
648
  { name: "expressionCmpOp", symbols: [{ literal: "in" }], postprocess: tok },
649
  {
650
    name: "expressionCmpOp",
651
    symbols: [{ literal: "not" }, { literal: "in" }],
652
    postprocess: ([t]) => {
653
      const tok = toAstToken(t);
3✔
654
      tok.lexeme = "not in";
3✔
655
      return tok;
3✔
656
    },
657
  },
658
  { name: "expressionCmpOp", symbols: [{ literal: "is" }], postprocess: tok },
659
  {
660
    name: "expressionCmpOp",
661
    symbols: [{ literal: "is" }, { literal: "not" }],
662
    postprocess: ([t]) => {
663
      const tok = toAstToken(t);
3✔
664
      tok.lexeme = "is not";
3✔
665
      return tok;
3✔
666
    },
667
  },
668
  {
669
    name: "expressionAdd",
670
    symbols: ["expressionAdd", "expressionAddOp", "expressionMul"],
671
    postprocess: astBinary,
672
  },
673
  { name: "expressionAdd", symbols: ["expressionMul"], postprocess: id },
674
  {
675
    name: "expressionAddOp",
676
    symbols: [pythonLexer.has("plus") ? { type: "plus" } : plus],
3!
677
    postprocess: tok,
678
  },
679
  {
680
    name: "expressionAddOp",
681
    symbols: [pythonLexer.has("minus") ? { type: "minus" } : minus],
3!
682
    postprocess: tok,
683
  },
684
  {
685
    name: "expressionMul",
686
    symbols: ["expressionMul", "expressionMulOp", "expressionUnary"],
687
    postprocess: astBinary,
688
  },
689
  { name: "expressionMul", symbols: ["expressionUnary"], postprocess: id },
690
  {
691
    name: "expressionMulOp",
692
    symbols: [pythonLexer.has("star") ? { type: "star" } : star],
3!
693
    postprocess: tok,
694
  },
695
  {
696
    name: "expressionMulOp",
697
    symbols: [pythonLexer.has("slash") ? { type: "slash" } : slash],
3!
698
    postprocess: tok,
699
  },
700
  {
701
    name: "expressionMulOp",
702
    symbols: [pythonLexer.has("percent") ? { type: "percent" } : percent],
3!
703
    postprocess: tok,
704
  },
705
  {
706
    name: "expressionMulOp",
707
    symbols: [pythonLexer.has("doubleslash") ? { type: "doubleslash" } : doubleslash],
3!
708
    postprocess: tok,
709
  },
710
  {
711
    name: "expressionUnary",
712
    symbols: [pythonLexer.has("plus") ? { type: "plus" } : plus, "expressionUnary"],
3!
713
    postprocess: astUnary,
714
  },
715
  {
716
    name: "expressionUnary",
717
    symbols: [pythonLexer.has("minus") ? { type: "minus" } : minus, "expressionUnary"],
3!
718
    postprocess: astUnary,
719
  },
720
  { name: "expressionUnary", symbols: ["expressionPow"], postprocess: id },
721
  {
722
    name: "expressionPow",
723
    symbols: [
724
      "expressionPost",
725
      pythonLexer.has("doublestar") ? { type: "doublestar" } : doublestar,
3!
726
      "expressionUnary",
727
    ],
728
    postprocess: astBinaryTok,
729
  },
730
  { name: "expressionPow", symbols: ["expressionPost"], postprocess: id },
731
  {
732
    name: "expressionPost",
733
    symbols: [
734
      "expressionPost",
735
      pythonLexer.has("lsqb") ? { type: "lsqb" } : lsqb,
3!
736
      "expression",
737
      pythonLexer.has("rsqb") ? { type: "rsqb" } : rsqb,
3!
738
    ],
739
    postprocess: ([obj, , idx, rsqb]) =>
740
      new ExprNS.Subscript(obj.startToken, toAstToken(rsqb), obj, idx),
6✔
741
  },
742
  {
743
    name: "expressionPost",
744
    symbols: ["expressionPost", { literal: "(" }, "expressions", { literal: ")" }],
745
    postprocess: ([callee, , args, rparen]) =>
746
      new ExprNS.Call(callee.startToken, toAstToken(rparen), callee, args),
56✔
747
  },
748
  {
749
    name: "expressionPost",
750
    symbols: ["expressionPost", { literal: "(" }, { literal: ")" }],
751
    postprocess: ([callee, , rparen]) =>
752
      new ExprNS.Call(callee.startToken, toAstToken(rparen), callee, []),
25✔
753
  },
754
  { name: "expressionPost", symbols: ["atom"], postprocess: id },
755
  {
756
    name: "atom",
757
    symbols: [{ literal: "(" }, "expression", { literal: ")" }],
758
    postprocess: ([, e]) => new ExprNS.Grouping(e.startToken, e.endToken, e),
10✔
759
  },
760
  {
761
    name: "atom",
762
    symbols: [
763
      pythonLexer.has("lsqb") ? { type: "lsqb" } : lsqb,
3!
764
      pythonLexer.has("rsqb") ? { type: "rsqb" } : rsqb,
3!
765
    ],
766
    postprocess: ([l, r]) => new ExprNS.List(toAstToken(l), toAstToken(r), []),
4✔
767
  },
768
  {
769
    name: "atom",
770
    symbols: [
771
      pythonLexer.has("lsqb") ? { type: "lsqb" } : lsqb,
3!
772
      "expressions",
773
      pythonLexer.has("rsqb") ? { type: "rsqb" } : rsqb,
3!
774
    ],
775
    postprocess: ([l, elems, r]) => new ExprNS.List(toAstToken(l), toAstToken(r), elems),
9✔
776
  },
777
  {
778
    name: "atom",
779
    symbols: [pythonLexer.has("name") ? { type: "name" } : name],
3!
780
    postprocess: astVariable,
781
  },
782
  {
783
    name: "atom",
784
    symbols: [pythonLexer.has("number_float") ? { type: "number_float" } : number_float],
3!
785
    postprocess: ([t]) => {
786
      const tok = toAstToken(t);
11✔
787
      return new ExprNS.Literal(tok, tok, parseFloat(t.value));
11✔
788
    },
789
  },
790
  {
791
    name: "atom",
792
    symbols: [pythonLexer.has("number_int") ? { type: "number_int" } : number_int],
3!
793
    postprocess: astBigInt,
794
  },
795
  {
796
    name: "atom",
797
    symbols: [pythonLexer.has("number_hex") ? { type: "number_hex" } : number_hex],
3!
798
    postprocess: astBigInt,
799
  },
800
  {
801
    name: "atom",
802
    symbols: [pythonLexer.has("number_oct") ? { type: "number_oct" } : number_oct],
3!
803
    postprocess: astBigInt,
804
  },
805
  {
806
    name: "atom",
807
    symbols: [pythonLexer.has("number_bin") ? { type: "number_bin" } : number_bin],
3!
808
    postprocess: astBigInt,
809
  },
810
  {
811
    name: "atom",
812
    symbols: [pythonLexer.has("number_complex") ? { type: "number_complex" } : number_complex],
3!
813
    postprocess: astComplex,
814
  },
815
  { name: "atom", symbols: ["stringLit"], postprocess: id },
816
  { name: "atom", symbols: [{ literal: "None" }], postprocess: astNone },
817
  { name: "atom", symbols: [{ literal: "True" }], postprocess: astTrue },
818
  { name: "atom", symbols: [{ literal: "False" }], postprocess: astFalse },
819
  {
820
    name: "lambda_expr",
821
    symbols: [{ literal: "lambda" }, "names", { literal: ":" }, "expression"],
822
    postprocess: ([kw, params, , body]) =>
823
      new ExprNS.Lambda(toAstToken(kw), body.endToken, params, body),
16✔
824
  },
825
  {
826
    name: "lambda_expr",
827
    symbols: [
828
      { literal: "lambda" },
829
      "names",
830
      pythonLexer.has("doublecolon") ? { type: "doublecolon" } : doublecolon,
3!
831
      "block",
832
    ],
833
    postprocess: ([kw, params, , body]) =>
UNCOV
834
      new ExprNS.MultiLambda(toAstToken(kw), body[body.length - 1].endToken, params, body, []),
×
835
  },
836
  {
837
    name: "lambda_expr",
838
    symbols: [{ literal: "lambda" }, { literal: ":" }, "expression"],
839
    postprocess: ([kw, , body]) => new ExprNS.Lambda(toAstToken(kw), body.endToken, [], body),
1✔
840
  },
841
  {
842
    name: "lambda_expr",
843
    symbols: [
844
      { literal: "lambda" },
845
      pythonLexer.has("doublecolon") ? { type: "doublecolon" } : doublecolon,
3!
846
      "block",
847
    ],
848
    postprocess: ([kw, , body]) =>
UNCOV
849
      new ExprNS.MultiLambda(toAstToken(kw), body[body.length - 1].endToken, [], body, []),
×
850
  },
851
  { name: "expressions$ebnf$1", symbols: [] },
852
  { name: "expressions$ebnf$1$subexpression$1", symbols: [{ literal: "," }, "expression"] },
853
  {
854
    name: "expressions$ebnf$1",
855
    symbols: ["expressions$ebnf$1", "expressions$ebnf$1$subexpression$1"],
856
    postprocess: function arrpush(d) {
857
      return d[0].concat([d[1]]);
39✔
858
    },
859
  },
860
  { name: "expressions$ebnf$2$subexpression$1", symbols: [{ literal: "," }] },
861
  { name: "expressions$ebnf$2", symbols: ["expressions$ebnf$2$subexpression$1"], postprocess: id },
862
  {
863
    name: "expressions$ebnf$2",
864
    symbols: [],
865
    postprocess: function (d) {
866
      return null;
117✔
867
    },
868
  },
869
  {
870
    name: "expressions",
871
    symbols: ["expression", "expressions$ebnf$1", "expressions$ebnf$2"],
872
    postprocess: flatList,
873
  },
874
  {
875
    name: "stringLit",
876
    symbols: [
877
      pythonLexer.has("string_triple_double")
3!
878
        ? { type: "string_triple_double" }
879
        : string_triple_double,
880
    ],
881
    postprocess: astString,
882
  },
883
  {
884
    name: "stringLit",
885
    symbols: [
886
      pythonLexer.has("string_triple_single")
3!
887
        ? { type: "string_triple_single" }
888
        : string_triple_single,
889
    ],
890
    postprocess: astString,
891
  },
892
  {
893
    name: "stringLit",
894
    symbols: [pythonLexer.has("string_double") ? { type: "string_double" } : string_double],
3!
895
    postprocess: astString,
896
  },
897
  {
898
    name: "stringLit",
899
    symbols: [pythonLexer.has("string_single") ? { type: "string_single" } : string_single],
3!
900
    postprocess: astString,
901
  },
902
];
903
let ParserStart = "program";
3✔
904
export default { Lexer, ParserRules, ParserStart };
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