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

source-academy / py-slang / 23727466431

30 Mar 2026 04:06AM UTC coverage: 59.421% (+18.2%) from 41.233%
23727466431

push

github

web-flow
Python chapter 2 (+ 3?) support (#81)

* feat: introduce chapter-based CSE evaluators + improve type safety of value type + add stubs for LINKED_LIST group

* add Python Chapter 1 back to the Rollup config

* Turned resolver type-checking back on + fix build_linked_list not working

* Fix bug where groups weren't loading + Make builtins more type-safe + Added native list functions (print_linked_list, head, tail)

* my changes

* Add Python chapter 3 functions + Fix syntax of stream prelude + Add list creation instruction + Make parser variant specific + Add basic tests for standard library

* Fix rounding + add tests for linked lists

* Fixed bug regarding representation of strings (printing ["a", "b"] returned [a, b])

* Mark files as unused (for now)

* Fix test cases

* Added variant to parser in WASM compiler

* Fix linked-list prelude using the old terminology of list + Fix build_linked_list(None) returning None instead of list()

* Add ability to check output from testing framework

* Add documentation for TestCases + add the repr function

* Improve alignment with Python specs + add ability to index lists + move variant checking to the resolver + improve test names + add a lot more tests

* Add more tests for operators + restrict the not operator to only booleans + disallow booleans in the unary minus operator

* FIx print_linked_list not actually printing the linked list

* Implement while loops + unpacking with for loops + implement tuples + break and continue

* Added a public is_linked_list function, added more comprehensive test cases for is_pair and is_linked_list

* extended test cases for linked lists

* Updated to have distinction between linkedlist Value and Python List for ease of future implementation of python list

* Revert "Updated to have distinction between linkedlist Value and Python List for ease of future implementation of python list"

This reverts commit d444793b1.

* fixed and/or operator bu... (continued)

779 of 1553 branches covered (50.16%)

Branch coverage included in aggregate %.

442 of 651 new or added lines in 32 files covered. (67.9%)

17 existing lines in 4 files now uncovered.

2400 of 3797 relevant lines covered (63.21%)

3195.38 hits per line

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

93.37
/src/ast-types.ts
1
// This file is autogenerated by generate-ast.ts. DO NOT EDIT THIS FILE DIRECTLY.
2
import { Token } from "./tokenizer";
3
import { PyComplexNumber } from "./types";
6✔
4

5
export type FunctionParam = Token & { isStarred: boolean };
6
export type AssignTarget = ExprNS.Variable | ExprNS.Subscript;
7
export namespace ExprNS {
6✔
8
  export interface Visitor<T> {
9
    visitBigIntLiteralExpr(expr: BigIntLiteral): T;
10
    visitBinaryExpr(expr: Binary): T;
11
    visitCompareExpr(expr: Compare): T;
12
    visitBoolOpExpr(expr: BoolOp): T;
13
    visitGroupingExpr(expr: Grouping): T;
14
    visitLiteralExpr(expr: Literal): T;
15
    visitUnaryExpr(expr: Unary): T;
16
    visitTernaryExpr(expr: Ternary): T;
17
    visitLambdaExpr(expr: Lambda): T;
18
    visitMultiLambdaExpr(expr: MultiLambda): T;
19
    visitVariableExpr(expr: Variable): T;
20
    visitCallExpr(expr: Call): T;
21
    visitListExpr(expr: List): T;
22
    visitSubscriptExpr(expr: Subscript): T;
23
    visitNoneExpr(expr: None): T;
24
    visitComplexExpr(expr: Complex): T;
25
  }
26
  export abstract class Expr {
6✔
27
    abstract readonly kind: string;
28
    startToken: Token;
29
    endToken: Token;
30
    protected constructor(startToken: Token, endToken: Token) {
31
      this.startToken = startToken;
118,370✔
32
      this.endToken = endToken;
118,370✔
33
    }
34
    abstract accept(visitor: Visitor<any>): any;
35
  }
36
  export class BigIntLiteral extends Expr {
6✔
37
    readonly kind = "BigIntLiteral";
3,238✔
38
    value: string;
39
    constructor(startToken: Token, endToken: Token, value: string) {
40
      super(startToken, endToken);
3,238✔
41
      this.value = value;
3,238✔
42
    }
43
    override accept(visitor: Visitor<any>): any {
44
      return visitor.visitBigIntLiteralExpr(this);
966✔
45
    }
46
  }
47
  export class Binary extends Expr {
6✔
48
    readonly kind = "Binary";
2,583✔
49
    left: Expr;
50
    operator: Token;
51
    right: Expr;
52
    constructor(startToken: Token, endToken: Token, left: Expr, operator: Token, right: Expr) {
53
      super(startToken, endToken);
2,583✔
54
      this.left = left;
2,583✔
55
      this.operator = operator;
2,583✔
56
      this.right = right;
2,583✔
57
    }
58
    override accept(visitor: Visitor<any>): any {
59
      return visitor.visitBinaryExpr(this);
549✔
60
    }
61
  }
62
  export class Compare extends Expr {
6✔
63
    readonly kind = "Compare";
3,065✔
64
    left: Expr;
65
    operator: Token;
66
    right: Expr;
67
    constructor(startToken: Token, endToken: Token, left: Expr, operator: Token, right: Expr) {
68
      super(startToken, endToken);
3,065✔
69
      this.left = left;
3,065✔
70
      this.operator = operator;
3,065✔
71
      this.right = right;
3,065✔
72
    }
73
    override accept(visitor: Visitor<any>): any {
74
      return visitor.visitCompareExpr(this);
317✔
75
    }
76
  }
77
  export class BoolOp extends Expr {
6✔
78
    readonly kind = "BoolOp";
4,751✔
79
    left: Expr;
80
    operator: Token;
81
    right: Expr;
82
    constructor(startToken: Token, endToken: Token, left: Expr, operator: Token, right: Expr) {
83
      super(startToken, endToken);
4,751✔
84
      this.left = left;
4,751✔
85
      this.operator = operator;
4,751✔
86
      this.right = right;
4,751✔
87
    }
88
    override accept(visitor: Visitor<any>): any {
89
      return visitor.visitBoolOpExpr(this);
34✔
90
    }
91
  }
92
  export class Grouping extends Expr {
6✔
93
    readonly kind = "Grouping";
2,658✔
94
    expression: Expr;
95
    constructor(startToken: Token, endToken: Token, expression: Expr) {
96
      super(startToken, endToken);
2,658✔
97
      this.expression = expression;
2,658✔
98
    }
99
    override accept(visitor: Visitor<any>): any {
100
      return visitor.visitGroupingExpr(this);
203✔
101
    }
102
  }
103
  export class Literal extends Expr {
6✔
104
    readonly kind = "Literal";
6,383✔
105
    value: true | false | number | string;
106
    constructor(startToken: Token, endToken: Token, value: true | false | number | string) {
107
      super(startToken, endToken);
6,383✔
108
      this.value = value;
6,383✔
109
    }
110
    override accept(visitor: Visitor<any>): any {
111
      return visitor.visitLiteralExpr(this);
695✔
112
    }
113
  }
114
  export class Unary extends Expr {
6✔
115
    readonly kind = "Unary";
679✔
116
    operator: Token;
117
    right: Expr;
118
    constructor(startToken: Token, endToken: Token, operator: Token, right: Expr) {
119
      super(startToken, endToken);
679✔
120
      this.operator = operator;
679✔
121
      this.right = right;
679✔
122
    }
123
    override accept(visitor: Visitor<any>): any {
124
      return visitor.visitUnaryExpr(this);
40✔
125
    }
126
  }
127
  export class Ternary extends Expr {
6✔
128
    readonly kind = "Ternary";
4,284✔
129
    predicate: Expr;
130
    consequent: Expr;
131
    alternative: Expr;
132
    constructor(
133
      startToken: Token,
134
      endToken: Token,
135
      predicate: Expr,
136
      consequent: Expr,
137
      alternative: Expr,
138
    ) {
139
      super(startToken, endToken);
4,284✔
140
      this.predicate = predicate;
4,284✔
141
      this.consequent = consequent;
4,284✔
142
      this.alternative = alternative;
4,284✔
143
    }
144
    override accept(visitor: Visitor<any>): any {
145
      return visitor.visitTernaryExpr(this);
×
146
    }
147
  }
148
  export class Lambda extends Expr {
6✔
149
    readonly kind = "Lambda";
2,821✔
150
    parameters: FunctionParam[];
151
    body: Expr;
152
    constructor(startToken: Token, endToken: Token, parameters: FunctionParam[], body: Expr) {
153
      super(startToken, endToken);
2,821✔
154
      this.parameters = parameters;
2,821✔
155
      this.body = body;
2,821✔
156
    }
157
    override accept(visitor: Visitor<any>): any {
158
      return visitor.visitLambdaExpr(this);
84✔
159
    }
160
  }
161
  export class MultiLambda extends Expr {
6✔
162
    readonly kind = "MultiLambda";
×
163
    parameters: FunctionParam[];
164
    body: StmtNS.Stmt[];
165
    varDecls: Token[];
166
    constructor(
167
      startToken: Token,
168
      endToken: Token,
169
      parameters: FunctionParam[],
170
      body: StmtNS.Stmt[],
171
      varDecls: Token[],
172
    ) {
173
      super(startToken, endToken);
×
174
      this.parameters = parameters;
×
175
      this.body = body;
×
176
      this.varDecls = varDecls;
×
177
    }
178
    override accept(visitor: Visitor<any>): any {
179
      return visitor.visitMultiLambdaExpr(this);
×
180
    }
181
  }
182
  export class Variable extends Expr {
6✔
183
    readonly kind = "Variable";
58,466✔
184
    name: Token;
185
    constructor(startToken: Token, endToken: Token, name: Token) {
186
      super(startToken, endToken);
58,466✔
187
      this.name = name;
58,466✔
188
    }
189
    override accept(visitor: Visitor<any>): any {
190
      return visitor.visitVariableExpr(this);
627✔
191
    }
192
  }
193
  export class Call extends Expr {
6✔
194
    readonly kind = "Call";
26,913✔
195
    callee: Expr;
196
    args: Expr[];
197
    constructor(startToken: Token, endToken: Token, callee: Expr, args: Expr[]) {
198
      super(startToken, endToken);
26,913✔
199
      this.callee = callee;
26,913✔
200
      this.args = args;
26,913✔
201
    }
202
    override accept(visitor: Visitor<any>): any {
203
      return visitor.visitCallExpr(this);
441✔
204
    }
205
  }
206
  export class List extends Expr {
6✔
207
    readonly kind = "List";
34✔
208
    elements: Expr[];
209
    constructor(startToken: Token, endToken: Token, elements: Expr[]) {
210
      super(startToken, endToken);
34✔
211
      this.elements = elements;
34✔
212
    }
213
    override accept(visitor: Visitor<any>): any {
214
      return visitor.visitListExpr(this);
16✔
215
    }
216
  }
217
  export class Subscript extends Expr {
6✔
218
    readonly kind = "Subscript";
278✔
219
    value: Expr;
220
    index: Expr;
221
    constructor(startToken: Token, endToken: Token, value: Expr, index: Expr) {
222
      super(startToken, endToken);
278✔
223
      this.value = value;
278✔
224
      this.index = index;
278✔
225
    }
226
    override accept(visitor: Visitor<any>): any {
227
      return visitor.visitSubscriptExpr(this);
3✔
228
    }
229
  }
230
  export class None extends Expr {
6✔
231
    readonly kind = "None";
1,959✔
232
    constructor(startToken: Token, endToken: Token) {
233
      super(startToken, endToken);
1,959✔
234
    }
235
    override accept(visitor: Visitor<any>): any {
236
      return visitor.visitNoneExpr(this);
119✔
237
    }
238
  }
239
  export class Complex extends Expr {
6✔
240
    readonly kind = "Complex";
258✔
241
    value: PyComplexNumber;
242
    constructor(startToken: Token, endToken: Token, value: string) {
243
      super(startToken, endToken);
258✔
244
      this.value = PyComplexNumber.fromString(value);
258✔
245
    }
246
    override accept(visitor: Visitor<any>): any {
247
      return visitor.visitComplexExpr(this);
257✔
248
    }
249
  }
250
}
251
export namespace StmtNS {
6✔
252
  export interface Visitor<T> {
253
    visitPassStmt(stmt: Pass): T;
254
    visitAssignStmt(stmt: Assign): T;
255
    visitAnnAssignStmt(stmt: AnnAssign): T;
256
    visitBreakStmt(stmt: Break): T;
257
    visitContinueStmt(stmt: Continue): T;
258
    visitReturnStmt(stmt: Return): T;
259
    visitFromImportStmt(stmt: FromImport): T;
260
    visitGlobalStmt(stmt: Global): T;
261
    visitNonLocalStmt(stmt: NonLocal): T;
262
    visitAssertStmt(stmt: Assert): T;
263
    visitIfStmt(stmt: If): T;
264
    visitWhileStmt(stmt: While): T;
265
    visitForStmt(stmt: For): T;
266
    visitFunctionDefStmt(stmt: FunctionDef): T;
267
    visitSimpleExprStmt(stmt: SimpleExpr): T;
268
    visitFileInputStmt(stmt: FileInput): T;
269
  }
270
  export abstract class Stmt {
6✔
271
    abstract readonly kind: string;
272
    startToken: Token;
273
    endToken: Token;
274
    protected constructor(startToken: Token, endToken: Token) {
275
      this.startToken = startToken;
60,332✔
276
      this.endToken = endToken;
60,332✔
277
    }
278
    abstract accept(visitor: Visitor<any>): any;
279
  }
280
  export class Pass extends Stmt {
6✔
281
    readonly kind = "Pass";
43✔
282
    constructor(startToken: Token, endToken: Token) {
283
      super(startToken, endToken);
43✔
284
    }
285
    override accept(visitor: Visitor<any>): any {
286
      return visitor.visitPassStmt(this);
8✔
287
    }
288
  }
289
  export class Assign extends Stmt {
6✔
290
    readonly kind = "Assign";
632✔
291
    target: AssignTarget;
292
    value: ExprNS.Expr;
293
    constructor(startToken: Token, endToken: Token, target: AssignTarget, value: ExprNS.Expr) {
294
      super(startToken, endToken);
632✔
295
      this.target = target;
632✔
296
      this.value = value;
632✔
297
    }
298
    override accept(visitor: Visitor<any>): any {
299
      return visitor.visitAssignStmt(this);
93✔
300
    }
301
  }
302
  export class AnnAssign extends Stmt {
6✔
303
    readonly kind = "AnnAssign";
17✔
304
    target: ExprNS.Variable;
305
    value: ExprNS.Expr;
306
    ann: ExprNS.Expr;
307
    constructor(
308
      startToken: Token,
309
      endToken: Token,
310
      target: ExprNS.Variable,
311
      value: ExprNS.Expr,
312
      ann: ExprNS.Expr,
313
    ) {
314
      super(startToken, endToken);
17✔
315
      this.target = target;
17✔
316
      this.value = value;
17✔
317
      this.ann = ann;
17✔
318
    }
319
    override accept(visitor: Visitor<any>): any {
UNCOV
320
      return visitor.visitAnnAssignStmt(this);
×
321
    }
322
  }
323
  export class Break extends Stmt {
6✔
324
    readonly kind = "Break";
7✔
325
    constructor(startToken: Token, endToken: Token) {
326
      super(startToken, endToken);
7✔
327
    }
328
    override accept(visitor: Visitor<any>): any {
329
      return visitor.visitBreakStmt(this);
×
330
    }
331
  }
332
  export class Continue extends Stmt {
6✔
333
    readonly kind = "Continue";
7✔
334
    constructor(startToken: Token, endToken: Token) {
335
      super(startToken, endToken);
7✔
336
    }
337
    override accept(visitor: Visitor<any>): any {
338
      return visitor.visitContinueStmt(this);
×
339
    }
340
  }
341
  export class Return extends Stmt {
6✔
342
    readonly kind = "Return";
26,037✔
343
    value: ExprNS.Expr | null;
344
    constructor(startToken: Token, endToken: Token, value: ExprNS.Expr | null) {
345
      super(startToken, endToken);
26,037✔
346
      this.value = value;
26,037✔
347
    }
348
    override accept(visitor: Visitor<any>): any {
349
      return visitor.visitReturnStmt(this);
26✔
350
    }
351
  }
352
  export class FromImport extends Stmt {
6✔
353
    readonly kind = "FromImport";
8✔
354
    module: Token;
355
    names: { name: Token; alias: Token | null }[];
356
    constructor(
357
      startToken: Token,
358
      endToken: Token,
359
      module: Token,
360
      names: { name: Token; alias: Token | null }[],
361
    ) {
362
      super(startToken, endToken);
8✔
363
      this.module = module;
8✔
364
      this.names = names;
8✔
365
    }
366
    override accept(visitor: Visitor<any>): any {
367
      return visitor.visitFromImportStmt(this);
1✔
368
    }
369
  }
370
  export class Global extends Stmt {
6✔
371
    readonly kind = "Global";
1✔
372
    name: Token;
373
    constructor(startToken: Token, endToken: Token, name: Token) {
374
      super(startToken, endToken);
1✔
375
      this.name = name;
1✔
376
    }
377
    override accept(visitor: Visitor<any>): any {
378
      return visitor.visitGlobalStmt(this);
×
379
    }
380
  }
381
  export class NonLocal extends Stmt {
6✔
382
    readonly kind = "NonLocal";
9✔
383
    name: Token;
384
    constructor(startToken: Token, endToken: Token, name: Token) {
385
      super(startToken, endToken);
9✔
386
      this.name = name;
9✔
387
    }
388
    override accept(visitor: Visitor<any>): any {
389
      return visitor.visitNonLocalStmt(this);
4✔
390
    }
391
  }
392
  export class Assert extends Stmt {
6✔
393
    readonly kind = "Assert";
5✔
394
    value: ExprNS.Expr;
395
    constructor(startToken: Token, endToken: Token, value: ExprNS.Expr) {
396
      super(startToken, endToken);
5✔
397
      this.value = value;
5✔
398
    }
399
    override accept(visitor: Visitor<any>): any {
400
      return visitor.visitAssertStmt(this);
×
401
    }
402
  }
403
  export class If extends Stmt {
6✔
404
    readonly kind = "If";
11,140✔
405
    condition: ExprNS.Expr;
406
    body: Stmt[];
407
    elseBlock: Stmt[] | null;
408
    constructor(
409
      startToken: Token,
410
      endToken: Token,
411
      condition: ExprNS.Expr,
412
      body: Stmt[],
413
      elseBlock: Stmt[] | null,
414
    ) {
415
      super(startToken, endToken);
11,140✔
416
      this.condition = condition;
11,140✔
417
      this.body = body;
11,140✔
418
      this.elseBlock = elseBlock;
11,140✔
419
    }
420
    override accept(visitor: Visitor<any>): any {
421
      return visitor.visitIfStmt(this);
×
422
    }
423
  }
424
  export class While extends Stmt {
6✔
425
    readonly kind = "While";
63✔
426
    condition: ExprNS.Expr;
427
    body: Stmt[];
428
    constructor(startToken: Token, endToken: Token, condition: ExprNS.Expr, body: Stmt[]) {
429
      super(startToken, endToken);
63✔
430
      this.condition = condition;
63✔
431
      this.body = body;
63✔
432
    }
433
    override accept(visitor: Visitor<any>): any {
434
      return visitor.visitWhileStmt(this);
3✔
435
    }
436
  }
437
  export class For extends Stmt {
6✔
438
    readonly kind = "For";
63✔
439
    target: Token;
440
    iter: ExprNS.Expr;
441
    body: Stmt[];
442
    constructor(
443
      startToken: Token,
444
      endToken: Token,
445
      target: Token,
446
      iter: ExprNS.Expr,
447
      body: Stmt[],
448
    ) {
449
      super(startToken, endToken);
63✔
450
      this.target = target;
63✔
451
      this.iter = iter;
63✔
452
      this.body = body;
63✔
453
    }
454
    override accept(visitor: Visitor<any>): any {
455
      return visitor.visitForStmt(this);
4✔
456
    }
457
  }
458
  export class FunctionDef extends Stmt {
6✔
459
    readonly kind = "FunctionDef";
5,512✔
460
    name: Token;
461
    parameters: FunctionParam[];
462
    body: Stmt[];
463
    varDecls: Token[];
464
    constructor(
465
      startToken: Token,
466
      endToken: Token,
467
      name: Token,
468
      parameters: FunctionParam[],
469
      body: Stmt[],
470
      varDecls: Token[],
471
    ) {
472
      super(startToken, endToken);
5,512✔
473
      this.name = name;
5,512✔
474
      this.parameters = parameters;
5,512✔
475
      this.body = body;
5,512✔
476
      this.varDecls = varDecls;
5,512✔
477
    }
478
    override accept(visitor: Visitor<any>): any {
479
      return visitor.visitFunctionDefStmt(this);
50✔
480
    }
481
  }
482
  export class SimpleExpr extends Stmt {
6✔
483
    readonly kind = "SimpleExpr";
7,426✔
484
    expression: ExprNS.Expr;
485
    constructor(startToken: Token, endToken: Token, expression: ExprNS.Expr) {
486
      super(startToken, endToken);
7,426✔
487
      this.expression = expression;
7,426✔
488
    }
489
    override accept(visitor: Visitor<any>): any {
490
      return visitor.visitSimpleExprStmt(this);
907✔
491
    }
492
  }
493
  export class FileInput extends Stmt {
6✔
494
    readonly kind = "FileInput";
9,362✔
495
    statements: Stmt[];
496
    varDecls: Token[];
497
    constructor(startToken: Token, endToken: Token, statements: Stmt[], varDecls: Token[]) {
498
      super(startToken, endToken);
9,362✔
499
      this.statements = statements;
9,362✔
500
      this.varDecls = varDecls;
9,362✔
501
    }
502
    override accept(visitor: Visitor<any>): any {
503
      return visitor.visitFileInputStmt(this);
959✔
504
    }
505
  }
506
}
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