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

source-academy / py-slang / 24666773189

20 Apr 2026 12:35PM UTC coverage: 72.175% (+0.05%) from 72.13%
24666773189

Pull #147

github

web-flow
Merge 7010dd386 into 190d6ed20
Pull Request #147: Split `stdlib.ts` into a `MATH` and `MISC` group

1494 of 2370 branches covered (63.04%)

Branch coverage included in aggregate %.

312 of 427 new or added lines in 11 files covered. (73.07%)

4485 of 5914 relevant lines covered (75.84%)

7911.29 hits per line

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

72.28
/src/stdlib/misc.ts
1
import { ExprNS } from "../ast-types";
2
import { Context } from "../engines/cse/context";
3
import { ControlItem } from "../engines/cse/control";
4
import { handleRuntimeError } from "../engines/cse/error";
12✔
5
import { isFalsy } from "../engines/cse/operators";
12✔
6
import {
7
  BigIntValue,
8
  BoolValue,
9
  BuiltinValue,
10
  ComplexValue,
11
  NumberValue,
12
  StringValue,
13
  Value,
14
} from "../engines/cse/stash";
15
import { displayOutput, receiveInput } from "../engines/cse/streams";
12✔
16
import { isNumeric } from "../engines/cse/utils";
12✔
17
import { MissingRequiredPositionalError, TypeError, UserError, ValueError } from "../errors";
12✔
18
import { PyComplexNumber } from "../types";
12✔
19
import { GroupName, minArgMap, toPythonString, Validate } from "./utils";
12✔
20

21
const miscBuiltins = new Map<string, BuiltinValue>();
12✔
22

23
export class MiscBuiltins {
12✔
24
  @Validate(1, 1, "arity", true)
25
  static arity(args: Value[], source: string, command: ExprNS.Call, context: Context): BigIntValue {
12✔
26
    const func = args[0];
98✔
27
    if (func.type !== "builtin" && func.type !== "closure") {
98✔
28
      handleRuntimeError(context, new TypeError(source, command, context, func.type, "function"));
7✔
29
    }
30
    if (func.type === "closure") {
91✔
31
      const variadicInstance = func.closure.node.parameters.findIndex(param => param.isStarred);
11✔
32
      if (variadicInstance !== -1) {
11✔
33
        return { type: "bigint", value: BigInt(variadicInstance) };
4✔
34
      }
35
      return { type: "bigint", value: BigInt(func.closure.node.parameters.length) };
7✔
36
    }
37
    return { type: "bigint", value: BigInt(func.minArgs) };
80✔
38
  }
39

40
  @Validate(null, 2, "int", true)
41
  static int(args: Value[], source: string, command: ExprNS.Call, context: Context): BigIntValue {
12✔
42
    if (args.length === 0) {
27✔
43
      return { type: "bigint", value: BigInt(0) };
1✔
44
    }
45
    const arg = args[0];
26✔
46
    if (!isNumeric(arg) && arg.type !== "string" && arg.type !== "bool") {
26✔
47
      handleRuntimeError(
4✔
48
        context,
49
        new TypeError(source, command, context, arg.type, "str, int, float or bool"),
50
      );
51
    }
52

53
    if (args.length === 1) {
22✔
54
      if (arg.type === "number") {
10✔
55
        const truncated = Math.trunc(arg.value);
2✔
56
        return { type: "bigint", value: BigInt(truncated) };
2✔
57
      }
58
      if (arg.type === "bigint") {
8✔
59
        return { type: "bigint", value: arg.value };
1✔
60
      }
61
      if (arg.type === "string") {
7✔
62
        const str = arg.value.trim().replace(/_/g, "");
6✔
63
        if (!/^[+-]?\d+$/.test(str)) {
6✔
64
          handleRuntimeError(context, new ValueError(source, command, context, "int"));
3✔
65
        }
66
        return { type: "bigint", value: BigInt(str) };
3✔
67
      }
68
      return { type: "bigint", value: arg.value ? BigInt(1) : BigInt(0) };
1!
69
    }
70
    const baseArg = args[1];
12✔
71
    if (arg.type !== "string") {
12✔
72
      handleRuntimeError(context, new TypeError(source, command, context, arg.type, "string"));
1✔
73
    }
74
    if (baseArg.type !== "bigint") {
11!
NEW
75
      handleRuntimeError(context, new TypeError(source, command, context, baseArg.type, "int"));
×
76
    }
77

78
    let base = Number(baseArg.value);
11✔
79
    let str = arg.value.trim().replace(/_/g, "");
11✔
80

81
    const sign = str.startsWith("-") ? -1 : 1;
11✔
82
    if (str.startsWith("+") || str.startsWith("-")) {
11✔
83
      str = str.substring(1);
1✔
84
    }
85

86
    if (base === 0) {
11✔
87
      if (str.startsWith("0x") || str.startsWith("0X")) {
7✔
88
        base = 16;
1✔
89
        str = str.substring(2);
1✔
90
      } else if (str.startsWith("0o") || str.startsWith("0O")) {
6✔
91
        base = 8;
4✔
92
        str = str.substring(2);
4✔
93
      } else if (str.startsWith("0b") || str.startsWith("0B")) {
2✔
94
        base = 2;
1✔
95
        str = str.substring(2);
1✔
96
      } else {
97
        base = 10;
1✔
98
      }
99
    }
100

101
    if (base < 2 || base > 36) {
11✔
102
      handleRuntimeError(context, new ValueError(source, command, context, "int"));
2✔
103
    }
104

105
    const validChars = "0123456789abcdefghijklmnopqrstuvwxyz".substring(0, base);
9✔
106
    const regex = new RegExp(`^[${validChars}]+$`, "i");
9✔
107
    if (!regex.test(str)) {
9✔
108
      handleRuntimeError(context, new ValueError(source, command, context, "int"));
3✔
109
    }
110

111
    let res = BigInt(0);
6✔
112
    for (const char of str) {
6✔
113
      res = res * BigInt(base) + BigInt(validChars.indexOf(char.toLowerCase()));
16✔
114
    }
115
    return { type: "bigint", value: BigInt(sign) * res };
6✔
116
  }
117

118
  @Validate(null, 1, "float", true)
119
  static float(args: Value[], source: string, command: ExprNS.Call, context: Context): NumberValue {
12✔
120
    if (args.length === 0) {
25✔
121
      return { type: "number", value: 0 };
1✔
122
    }
123
    const val = args[0];
24✔
124
    if (val.type === "bigint") {
24✔
125
      return { type: "number", value: Number(val.value) };
1✔
126
    } else if (val.type === "number") {
23✔
127
      return { type: "number", value: val.value };
2✔
128
    } else if (val.type === "bool") {
21✔
129
      return { type: "number", value: val.value ? 1 : 0 };
1!
130
    } else if (val.type === "string") {
20✔
131
      const str = val.value.trim().replace(/_/g, "").toLowerCase();
16✔
132
      const mappings = {
16✔
133
        inf: Infinity,
134
        "+inf": Infinity,
135
        "-inf": -Infinity,
136
        infinity: Infinity,
137
        "+infinity": Infinity,
138
        "-infinity": -Infinity,
139
        nan: NaN,
140
        "+nan": NaN,
141
        "-nan": NaN,
142
      };
143
      if (str in mappings) {
16✔
144
        return { type: "number", value: mappings[str as keyof typeof mappings] };
8✔
145
      }
146
      const num = Number(str);
8✔
147
      if (isNaN(num)) {
8✔
148
        handleRuntimeError(context, new ValueError(source, command, context, "float"));
1✔
149
      }
150
      return { type: "number", value: num };
7✔
151
    }
152
    handleRuntimeError(
4✔
153
      context,
154
      new TypeError(source, command, context, val.type, "'float', 'int', 'bool' or 'str'"),
155
    );
156
  }
157

158
  @Validate(null, 2, "complex", true)
159
  static complex(
12✔
160
    args: Value[],
161
    source: string,
162
    command: ExprNS.Call,
163
    context: Context,
164
  ): ComplexValue {
165
    if (args.length === 0) {
36✔
166
      return { type: "complex", value: new PyComplexNumber(0, 0) };
1✔
167
    }
168
    if (args.length == 1) {
35✔
169
      const val = args[0];
27✔
170
      if (
27✔
171
        val.type !== "bigint" &&
103✔
172
        val.type !== "number" &&
173
        val.type !== "bool" &&
174
        val.type !== "string" &&
175
        val.type !== "complex"
176
      ) {
177
        handleRuntimeError(context, new TypeError(source, command, context, val.type, "complex"));
3✔
178
      }
179
      return {
24✔
180
        type: "complex",
181
        value: PyComplexNumber.fromValue(context, source, command, val.value),
182
      };
183
    }
184
    const invalidType = args.filter(
8✔
185
      val =>
186
        val.type !== "bigint" &&
16✔
187
        val.type !== "number" &&
188
        val.type !== "bool" &&
189
        val.type !== "complex",
190
    );
191
    if (invalidType.length > 0) {
8✔
192
      handleRuntimeError(
3✔
193
        context,
194
        new TypeError(
195
          source,
196
          command,
197
          context,
198
          invalidType[0].type,
199
          "'int', 'float', 'bool' or 'complex'",
200
        ),
201
      );
202
    }
203
    const [real, imag] = args as (BigIntValue | NumberValue | BoolValue | ComplexValue)[];
5✔
204
    const realPart = PyComplexNumber.fromValue(context, source, command, real.value);
5✔
205
    const imagPart = PyComplexNumber.fromValue(context, source, command, imag.value);
5✔
206
    return { type: "complex", value: realPart.add(imagPart.mul(new PyComplexNumber(0, 1))) };
5✔
207
  }
208

209
  @Validate(1, 1, "real", true)
210
  static real(args: Value[], source: string, command: ExprNS.Call, context: Context): NumberValue {
12✔
NEW
211
    const val = args[0];
×
NEW
212
    if (val.type !== "complex") {
×
NEW
213
      handleRuntimeError(context, new TypeError(source, command, context, val.type, "complex"));
×
214
    }
NEW
215
    return { type: "number", value: val.value.real };
×
216
  }
217

218
  @Validate(1, 1, "imag", true)
219
  static imag(args: Value[], source: string, command: ExprNS.Call, context: Context): NumberValue {
12✔
NEW
220
    const val = args[0];
×
NEW
221
    if (val.type !== "complex") {
×
NEW
222
      handleRuntimeError(context, new TypeError(source, command, context, val.type, "complex"));
×
223
    }
NEW
224
    return { type: "number", value: val.value.imag };
×
225
  }
226

227
  @Validate(null, 1, "bool", true)
228
  static bool(args: Value[], _source: string, _command: ControlItem, _context: Context): BoolValue {
12✔
229
    if (args.length === 0) {
13✔
230
      return { type: "bool", value: false };
1✔
231
    }
232
    const val = args[0];
12✔
233
    return { type: "bool", value: !isFalsy(val) };
12✔
234
  }
235

236
  @Validate(1, 1, "abs", false)
237
  static abs(
12✔
238
    args: Value[],
239
    source: string,
240
    command: ExprNS.Call,
241
    context: Context,
242
  ): BigIntValue | NumberValue {
243
    const x = args[0];
18✔
244
    switch (x.type) {
18!
245
      case "bigint": {
246
        const intVal = x.value;
14✔
247
        const result: bigint = intVal < 0 ? -intVal : intVal;
14✔
248
        return { type: "bigint", value: result };
14✔
249
      }
250
      case "number": {
251
        return { type: "number", value: Math.abs(x.value) };
2✔
252
      }
253
      case "complex": {
254
        // Calculate the modulus (absolute value) of a complex number.
NEW
255
        const real = x.value.real;
×
NEW
256
        const imag = x.value.imag;
×
NEW
257
        const modulus = Math.sqrt(real * real + imag * imag);
×
NEW
258
        return { type: "number", value: modulus };
×
259
      }
260
      default:
261
        handleRuntimeError(
2✔
262
          context,
263
          new TypeError(source, command, context, args[0].type, "float', 'int' or 'complex"),
264
        );
265
    }
266
  }
267

268
  @Validate(1, 1, "len", true)
269
  static len(args: Value[], source: string, command: ExprNS.Call, context: Context): BigIntValue {
12✔
270
    const val = args[0];
14✔
271
    if (val.type === "string" || val.type === "list") {
14✔
272
      // The spread operator is used to count the number of Unicode code points
273
      // in the string
274
      return { type: "bigint", value: BigInt([...val.value].length) };
7✔
275
    }
276
    handleRuntimeError(
7✔
277
      context,
278
      new TypeError(source, command, context, val.type, "object with length"),
279
    );
280
  }
281

282
  static error(args: Value[], _source: string, command: ExprNS.Call, context: Context): Value {
283
    const output = "Error: " + args.map(arg => toPythonString(arg)).join(" ") + "\n";
7✔
284
    handleRuntimeError(context, new UserError(output, command));
5✔
285
  }
286

287
  @Validate(2, null, "max", true)
288
  static max(args: Value[], source: string, command: ExprNS.Call, context: Context): Value {
12✔
289
    const numericTypes = ["bigint", "number"];
4✔
290
    const firstType = args[0].type;
4✔
291
    const isNumericValue = numericTypes.includes(firstType);
4✔
292
    const isString = firstType === "string";
4✔
293

294
    for (let i = 1; i < args.length; i++) {
4✔
295
      const t = args[i].type;
9✔
296
      if (isNumericValue && !numericTypes.includes(t)) {
9!
NEW
297
        handleRuntimeError(
×
298
          context,
299
          new TypeError(source, command, context, args[i].type, "float' or 'int"),
300
        );
301
      }
302
      if (isString && t !== "string") {
9!
NEW
303
        handleRuntimeError(
×
304
          context,
305
          new TypeError(source, command, context, args[i].type, "string"),
306
        );
307
      }
308
    }
309

310
    let useFloat = false;
4✔
311
    if (isNumericValue) {
4✔
312
      for (const arg of args) {
4✔
313
        if (arg.type === "number") {
13!
NEW
314
          useFloat = true;
×
NEW
315
          break;
×
316
        }
317
      }
318
    }
319

320
    let maxIndex = 0;
4✔
321
    if (isNumericValue) {
4!
322
      if (useFloat) {
4!
NEW
323
        if (args[0].type !== "number" && args[0].type !== "bigint") {
×
NEW
324
          handleRuntimeError(
×
325
            context,
326
            new TypeError(source, command, context, args[0].type, "float' or 'int"),
327
          );
328
        }
NEW
329
        let maxVal: number = Number(args[0].value);
×
NEW
330
        for (let i = 1; i < args.length; i++) {
×
NEW
331
          const arg = args[i];
×
NEW
332
          if (!isNumeric(arg)) {
×
NEW
333
            handleRuntimeError(
×
334
              context,
335
              new TypeError(source, command, context, arg.type, "float' or 'int"),
336
            );
337
          }
NEW
338
          const curr: number = Number(arg.value);
×
NEW
339
          if (curr > maxVal) {
×
NEW
340
            maxVal = curr;
×
NEW
341
            maxIndex = i;
×
342
          }
343
        }
344
      } else {
345
        if (args[0].type !== "bigint") {
4!
NEW
346
          handleRuntimeError(context, new TypeError(source, command, context, args[0].type, "int"));
×
347
        }
348
        let maxVal: bigint = args[0].value;
4✔
349
        for (let i = 1; i < args.length; i++) {
4✔
350
          const arg = args[i];
9✔
351
          if (arg.type !== "bigint") {
9!
NEW
352
            handleRuntimeError(context, new TypeError(source, command, context, arg.type, "int"));
×
353
          }
354
          const curr: bigint = arg.value;
9✔
355
          if (curr > maxVal) {
9✔
356
            maxVal = curr;
7✔
357
            maxIndex = i;
7✔
358
          }
359
        }
360
      }
NEW
361
    } else if (isString) {
×
NEW
362
      if (args[0].type !== "string") {
×
NEW
363
        handleRuntimeError(
×
364
          context,
365
          new TypeError(source, command, context, args[0].type, "string"),
366
        );
367
      }
NEW
368
      let maxVal = args[0].value;
×
NEW
369
      for (let i = 1; i < args.length; i++) {
×
NEW
370
        const arg = args[i];
×
NEW
371
        if (arg.type !== "string") {
×
NEW
372
          handleRuntimeError(context, new TypeError(source, command, context, arg.type, "string"));
×
373
        }
NEW
374
        const curr = arg.value;
×
NEW
375
        if (curr > maxVal) {
×
NEW
376
          maxVal = curr;
×
NEW
377
          maxIndex = i;
×
378
        }
379
      }
380
    } else {
381
      // Won't happen
NEW
382
      throw new Error(`max: unsupported type ${firstType}`);
×
383
    }
384

385
    return args[maxIndex];
4✔
386
  }
387

388
  @Validate(2, null, "min", true)
389
  static min(args: Value[], source: string, command: ExprNS.Call, context: Context): Value {
12✔
390
    if (args.length < 2) {
1!
NEW
391
      handleRuntimeError(
×
392
        context,
393
        new MissingRequiredPositionalError(source, command, "min", Number(2), args, true),
394
      );
395
    }
396

397
    const numericTypes = ["bigint", "number"];
1✔
398
    const firstType = args[0].type;
1✔
399
    const isNumericValue = numericTypes.includes(firstType);
1✔
400
    const isString = firstType === "string";
1✔
401

402
    for (let i = 1; i < args.length; i++) {
1✔
403
      const t = args[i].type;
2✔
404
      if (isNumericValue && !numericTypes.includes(t)) {
2!
NEW
405
        handleRuntimeError(
×
406
          context,
407
          new TypeError(source, command, context, args[i].type, "float' or 'int"),
408
        );
409
      }
410
      if (isString && t !== "string") {
2!
NEW
411
        handleRuntimeError(
×
412
          context,
413
          new TypeError(source, command, context, args[i].type, "string"),
414
        );
415
      }
416
    }
417

418
    let useFloat = false;
1✔
419
    if (isNumericValue) {
1✔
420
      for (const arg of args) {
1✔
421
        if (arg.type === "number") {
3!
NEW
422
          useFloat = true;
×
NEW
423
          break;
×
424
        }
425
      }
426
    }
427

428
    let maxIndex = 0;
1✔
429
    if (isNumericValue) {
1!
430
      if (useFloat) {
1!
NEW
431
        if (args[0].type !== "number" && args[0].type !== "bigint") {
×
NEW
432
          handleRuntimeError(
×
433
            context,
434
            new TypeError(source, command, context, args[0].type, "float' or 'int"),
435
          );
436
        }
NEW
437
        let maxVal: number = Number(args[0].value);
×
NEW
438
        for (let i = 1; i < args.length; i++) {
×
NEW
439
          const arg = args[i];
×
NEW
440
          if (!isNumeric(arg)) {
×
NEW
441
            handleRuntimeError(
×
442
              context,
443
              new TypeError(source, command, context, arg.type, "float' or 'int"),
444
            );
445
          }
NEW
446
          const curr: number = Number(arg.value);
×
NEW
447
          if (curr < maxVal) {
×
NEW
448
            maxVal = curr;
×
NEW
449
            maxIndex = i;
×
450
          }
451
        }
452
      } else {
453
        if (args[0].type !== "bigint") {
1!
NEW
454
          handleRuntimeError(context, new TypeError(source, command, context, args[0].type, "int"));
×
455
        }
456
        let maxVal: bigint = args[0].value;
1✔
457
        for (let i = 1; i < args.length; i++) {
1✔
458
          const arg = args[i];
2✔
459
          if (arg.type !== "bigint") {
2!
NEW
460
            handleRuntimeError(context, new TypeError(source, command, context, arg.type, "int"));
×
461
          }
462
          const curr: bigint = arg.value;
2✔
463
          if (curr < maxVal) {
2✔
464
            maxVal = curr;
1✔
465
            maxIndex = i;
1✔
466
          }
467
        }
468
      }
NEW
469
    } else if (isString) {
×
NEW
470
      if (args[0].type !== "string") {
×
NEW
471
        handleRuntimeError(
×
472
          context,
473
          new TypeError(source, command, context, args[0].type, "string"),
474
        );
475
      }
NEW
476
      let maxVal = args[0].value;
×
NEW
477
      for (let i = 1; i < args.length; i++) {
×
NEW
478
        const arg = args[i];
×
NEW
479
        if (arg.type !== "string") {
×
NEW
480
          handleRuntimeError(context, new TypeError(source, command, context, arg.type, "string"));
×
481
        }
NEW
482
        const curr = arg.value;
×
NEW
483
        if (curr < maxVal) {
×
NEW
484
          maxVal = curr;
×
NEW
485
          maxIndex = i;
×
486
        }
487
      }
488
    } else {
489
      // Won't happen
NEW
490
      throw new Error(`min: unsupported type ${firstType}`);
×
491
    }
492

493
    return args[maxIndex];
1✔
494
  }
495

496
  @Validate(null, 0, "random_random", true)
497
  static random_random(
12✔
498
    _args: Value[],
499
    _source: string,
500
    _command: ExprNS.Call,
501
    _context: Context,
502
  ): NumberValue {
NEW
503
    const result = Math.random();
×
NEW
504
    return { type: "number", value: result };
×
505
  }
506

507
  @Validate(1, 2, "round", true)
508
  static round(
12✔
509
    args: Value[],
510
    source: string,
511
    command: ExprNS.Call,
512
    context: Context,
513
  ): NumberValue | BigIntValue {
514
    const numArg = args[0];
15✔
515
    if (!isNumeric(numArg)) {
15✔
516
      handleRuntimeError(
2✔
517
        context,
518
        new TypeError(source, command, context, numArg.type, "float' or 'int"),
519
      );
520
    }
521

522
    let ndigitsArg: BigIntValue = { type: "bigint", value: BigInt(0) };
13✔
523
    if (args.length === 2 && args[1].type !== "none") {
13✔
524
      if (args[1].type !== "bigint") {
7✔
525
        handleRuntimeError(context, new TypeError(source, command, context, args[1].type, "int"));
1✔
526
      }
527
      ndigitsArg = args[1];
6✔
528
    } else {
529
      const shifted = Intl.NumberFormat("en-US", {
6✔
530
        roundingMode: "halfEven",
531
        useGrouping: false,
532
        maximumFractionDigits: 0,
533
      } as Intl.NumberFormatOptions).format(numArg.value);
534
      return { type: "bigint", value: BigInt(shifted) };
6✔
535
    }
536

537
    if (numArg.type === "number") {
6✔
538
      const numberValue: number = numArg.value;
4✔
539
      if (ndigitsArg.value >= 0) {
4✔
540
        const shifted = Intl.NumberFormat("en-US", {
3✔
541
          roundingMode: "halfEven",
542
          useGrouping: false,
543
          maximumFractionDigits: Number(ndigitsArg.value),
544
        } as Intl.NumberFormatOptions).format(numberValue);
545
        return { type: "number", value: Number(shifted) };
3✔
546
      } else {
547
        const shifted = Intl.NumberFormat("en-US", {
1✔
548
          roundingMode: "halfEven",
549
          useGrouping: false,
550
          maximumFractionDigits: 0,
551
        } as Intl.NumberFormatOptions).format(numArg.value / 10 ** -Number(ndigitsArg.value));
552
        return { type: "number", value: Number(shifted) * 10 ** -Number(ndigitsArg.value) };
1✔
553
      }
554
    } else {
555
      if (ndigitsArg.value >= 0) {
2!
556
        return numArg;
2✔
557
      } else {
NEW
558
        const shifted = Intl.NumberFormat("en-US", {
×
559
          roundingMode: "halfEven",
560
          useGrouping: false,
561
          maximumFractionDigits: 0,
562
        } as Intl.NumberFormatOptions).format(
563
          Number(numArg.value) / 10 ** -Number(ndigitsArg.value),
564
        );
NEW
565
        return { type: "bigint", value: BigInt(shifted) * 10n ** -ndigitsArg.value };
×
566
      }
567
    }
568
  }
569

570
  @Validate(null, 0, "time_time", true)
571
  static time_time(
12✔
572
    _args: Value[],
573
    _source: string,
574
    _command: ExprNS.Call,
575
    _context: Context,
576
  ): NumberValue {
NEW
577
    const currentTime = Date.now();
×
NEW
578
    return { type: "number", value: currentTime };
×
579
  }
580

581
  @Validate(1, 1, "is_none", true)
582
  static is_none(
12✔
583
    args: Value[],
584
    _source: string,
585
    _command: ExprNS.Call,
586
    _context: Context,
587
  ): BoolValue {
588
    const obj = args[0];
796✔
589
    return { type: "bool", value: obj.type === "none" };
796✔
590
  }
591

592
  @Validate(1, 1, "is_float", true)
593
  static is_float(
12✔
594
    args: Value[],
595
    _source: string,
596
    _command: ExprNS.Call,
597
    _context: Context,
598
  ): BoolValue {
599
    const obj = args[0];
16✔
600
    return { type: "bool", value: obj.type === "number" };
16✔
601
  }
602

603
  @Validate(1, 1, "is_string", true)
604
  static is_string(
12✔
605
    args: Value[],
606
    _source: string,
607
    _command: ExprNS.Call,
608
    _context: Context,
609
  ): BoolValue {
610
    const obj = args[0];
25✔
611
    return { type: "bool", value: obj.type === "string" };
25✔
612
  }
613

614
  @Validate(1, 1, "is_boolean", true)
615
  static is_boolean(
12✔
616
    args: Value[],
617
    _source: string,
618
    _command: ExprNS.Call,
619
    _context: Context,
620
  ): BoolValue {
621
    const obj = args[0];
17✔
622
    return { type: "bool", value: obj.type === "bool" };
17✔
623
  }
624

625
  @Validate(1, 1, "is_complex", true)
626
  static is_complex(
12✔
627
    args: Value[],
628
    _source: string,
629
    _command: ExprNS.Call,
630
    _context: Context,
631
  ): BoolValue {
NEW
632
    const obj = args[0];
×
NEW
633
    return { type: "bool", value: obj.type === "complex" };
×
634
  }
635

636
  @Validate(1, 1, "is_int", true)
637
  static is_int(
12✔
638
    args: Value[],
639
    _source: string,
640
    _command: ExprNS.Call,
641
    _context: Context,
642
  ): BoolValue {
643
    const obj = args[0];
386✔
644
    return { type: "bool", value: obj.type === "bigint" };
386✔
645
  }
646

647
  @Validate(1, 1, "is_function", true)
648
  static is_function(
12✔
649
    args: Value[],
650
    _source: string,
651
    _command: ExprNS.Call,
652
    _context: Context,
653
  ): BoolValue {
654
    const obj = args[0];
321✔
655
    return {
321✔
656
      type: "bool",
657
      value: obj.type === "function" || obj.type === "closure" || obj.type === "builtin",
740✔
658
    };
659
  }
660

661
  static async input(
662
    _args: Value[],
663
    _source: string,
664
    _command: ExprNS.Call,
665
    context: Context,
666
  ): Promise<Value> {
NEW
667
    const userInput = await receiveInput(context);
×
NEW
668
    return { type: "string", value: userInput };
×
669
  }
670

671
  static async print(
672
    args: Value[],
673
    _source: string,
674
    _command: ExprNS.Call,
675
    context: Context,
676
  ): Promise<Value> {
677
    const output = args.map(arg => toPythonString(arg)).join(" ");
159✔
678
    await displayOutput(context, output);
144✔
679
    return { type: "none" };
144✔
680
  }
681
  static str(
682
    args: Value[],
683
    _source: string,
684
    _command: ExprNS.Call,
685
    _context: Context,
686
  ): StringValue {
687
    if (args.length === 0) {
14!
NEW
688
      return { type: "string", value: "" };
×
689
    }
690
    const obj = args[0];
14✔
691
    const result = toPythonString(obj);
14✔
692
    return { type: "string", value: result };
14✔
693
  }
694
  @Validate(1, 1, "repr", true)
695
  static repr(
12✔
696
    args: Value[],
697
    _source: string,
698
    _command: ExprNS.Call,
699
    _context: Context,
700
  ): StringValue {
701
    const obj = args[0];
15✔
702
    const result = toPythonString(obj, true);
15✔
703
    return { type: "string", value: result };
15✔
704
  }
705
}
706
for (const builtin of Object.getOwnPropertyNames(MiscBuiltins)) {
12✔
707
  if (
348✔
708
    typeof MiscBuiltins[builtin as keyof typeof MiscBuiltins] === "function" &&
660✔
709
    !builtin.startsWith("_")
710
  ) {
711
    miscBuiltins.set(builtin, {
312✔
712
      type: "builtin",
713
      func: MiscBuiltins[builtin as keyof typeof MiscBuiltins] as BuiltinValue["func"],
714
      name: builtin,
715
      minArgs: minArgMap.get(builtin) || 0,
432✔
716
    });
717
  }
718
}
719

720
export default {
12✔
721
  name: GroupName.MISC,
722
  prelude: "",
723
  builtins: miscBuiltins,
724
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc