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

source-academy / js-slang / 15237418122

25 May 2025 11:31AM UTC coverage: 77.048% (-3.5%) from 80.538%
15237418122

push

github

web-flow
Rewrite: Stepper (#1742)

3433 of 4826 branches covered (71.14%)

Branch coverage included in aggregate %.

1032 of 1260 new or added lines in 27 files covered. (81.9%)

440 existing lines in 29 files now uncovered.

10099 of 12737 relevant lines covered (79.29%)

142411.96 hits per line

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

28.89
/src/stdlib/vm.prelude.ts
1
import OpCodes from '../vm/opcodes'
59✔
2
import { Program, SVMFunction } from '../vm/svml-compiler'
3
import { char_at, get_time, parse_int } from './misc'
59✔
4

5
// functions should be sorted in alphabetical order. Refer to SVML spec on wiki
6
// placeholders should be manually replaced with the correct machine code.
7
// customs require slight modification to the generated code, which is automated
8
// in the function calls below.
9
// added _ in front of every function name so that function calls
10
// use CALLP instead of CALL when compiled.
11
export const vmPrelude = `
59✔
12
// 0
13
function _accumulate(f, initial, xs) {
14
  return is_null(xs) ? initial : f(head(xs), accumulate(f, initial, tail(xs)));
15
}
16

17
// 1
18
function _append(xs, ys) {
19
  return is_null(xs) ? ys : pair(head(xs), append(tail(xs), ys));
20
}
21

22
// 2 placeholder
23
function _array_length(arr) {}
24

25
// 3
26
function _build_list(fun, n) {
27
  function build(i, fun, already_built) {
28
    return i < 0 ? already_built : build(i - 1, fun, pair(fun(i), already_built));
29
  }
30
  return build(n - 1, fun, null);
31
}
32

33
// 4
34
function _build_stream(n, fun) {
35
  function build(i) {
36
    return i >= n
37
      ? null
38
      : pair(fun(i),
39
        () => build(i + 1));
40
  }
41
  return build(0);
42
}
43

44
// 5 custom
45
// replace MODG opcode (25) with display opcode
46
// change number of arguments to varargs (-1)
47
function _display(args) {
48
  // display(args[0], args[1]);
49
  // compile this instead for easier replacing
50
  if (array_length(args) === 0) {
51
    error('Expected 1 or more arguments, but got ' + stringify(array_length(args)) + '.');
52
  } else {
53
    return args[0] % args[1];
54
  }
55
}
56

57
// 6 custom
58
// following math_hypot's implementation style
59
// using the ... operator on the machine
60
// change number of arguments to varargs (-1)
61
// replace NOTG opcode with DRAW_DATA opcode
62
function _draw_data(args) {
63
  if (array_length(args) === 0) {
64
    error('Expected 1 or more arguments, but got ' + stringify(array_length(args)) + '.');
65
  } else {
66
    !args;
67
    return args[0];
68
  }
69
}
70

71
// 7
72
function _enum_list(start, end) {
73
  return start > end ? null : pair(start, enum_list(start + 1, end));
74
}
75

76
// 8
77
function _enum_stream(start, end) {
78
  return start > end
79
    ? null
80
    : pair(start,
81
      () => enum_stream(start + 1, end));
82
}
83

84
// 9
85
function _equal(x, y) {
86
  return is_pair(x) && is_pair(y) ? equal(head(x), head(y)) && equal(tail(x), tail(y)) : x === y;
87
}
88

89
// 10 custom
90
// replace MODG opcode (25) with error opcode
91
// change number of arguments to varargs (-1)
92
function _error(args) {
93
  // error(args[0], args[1]);
94
  // compile this instead for easier replacing
95
  return args[0] % args[1];
96
}
97

98
// 11
99
function _eval_stream(s, n) {
100
  return n === 0
101
    ? null
102
    : pair(head(s),
103
      eval_stream(stream_tail(s),
104
        n - 1));
105
}
106

107
// 12
108
function _filter(pred, xs) {
109
  return is_null(xs)
110
    ? xs
111
    : pred(head(xs))
112
    ? pair(head(xs), filter(pred, tail(xs)))
113
    : filter(pred, tail(xs));
114
}
115

116
// 13
117
function _for_each(fun, xs) {
118
  if (is_null(xs)) {
119
    return true;
120
  } else {
121
    fun(head(xs));
122
    return for_each(fun, tail(xs));
123
  }
124
}
125

126
// 14
127
function _head(xs) {
128
  if (!is_pair(xs)) {
129
    error('head(xs) expects a pair as argument xs, but encountered ' + stringify(xs));
130
  } else {
131
    return xs[0];
132
  }
133
}
134

135
// 15
136
function _integers_from(n) {
137
  return pair(n,
138
    () => integers_from(n + 1));
139
}
140

141
// 16 placeholder
142
function _is_array(x) {}
143

144
// 17 placeholder
145
function _is_boolean(x) {}
146

147
// 18 placeholder
148
function _is_function(x) {}
149

150
// 19
151
function _is_list(xs) {
152
  return is_null(xs) || (is_pair(xs) && is_list(tail(xs)));
153
}
154

155
// 20 placeholder
156
function _is_null(x) {}
157

158
// 21 placeholder
159
function _is_number(x) {}
160

161
// 22
162
function _is_pair(x) {
163
  return is_array(x) && array_length(x) === 2;
164
}
165

166
// 23
167
function _is_stream(xs) {
168
  return is_null(xs) ||
169
    (is_pair(xs) &&
170
    is_function(tail(xs)) &&
171
    arity(tail(xs)) === 0 &&
172
    is_stream(stream_tail(xs)));
173
}
174

175
// 24 placeholder
176
function _is_string(x) {}
177

178
// 25 placeholder
179
function _is_undefined(x) {}
180

181
// 26
182
function _length(xs) {
183
  return is_null(xs) ? 0 : 1 + length(tail(xs));
184
}
185

186
// 27 custom
187
// change number of arguments to varargs (-1)
188
function _list(args) {
189
  let i = array_length(args) - 1;
190
  let p = null;
191
  while (i >= 0) {
192
    p = pair(args[i], p);
193
    i = i - 1;
194
  }
195
  return p;
196
}
197

198
// 28
199
function _list_ref(xs, n) {
200
  return n === 0 ? head(xs) : list_ref(tail(xs), n - 1);
201
}
202

203
// 29
204
function _list_to_stream(xs) {
205
  return is_null(xs)
206
    ? null
207
    : pair(head(xs),
208
      () => list_to_stream(tail(xs)));
209
}
210

211
// 30
212
function _list_to_string(xs) {
213
    return is_null(xs)
214
        ? "null"
215
        : is_pair(xs)
216
            ? "[" + list_to_string(head(xs)) + "," +
217
                list_to_string(tail(xs)) + "]"
218
            : stringify(xs);
219
}
220

221
// 31
222
function _map(f, xs) {
223
  return is_null(xs) ? null : pair(f(head(xs)), map(f, tail(xs)));
224
}
225

226
// 32 placeholder
227
function _math_abs(xs) {}
228

229
// 33 placeholder
230
function _math_acos(xs) {}
231

232
// 34 placeholder
233
function _math_acosh(xs) {}
234

235
// 35 placeholder
236
function _math_asin(xs) {}
237

238
// 36 placeholder
239
function _math_asinh(xs) {}
240

241
// 37 placeholder
242
function _math_atan(xs) {}
243

244
// 38 placeholder
245
function _math_atan2(xs) {}
246

247
// 39 placeholder
248
function _math_atanh(xs) {}
249

250
// 40 placeholder
251
function _math_cbrt(xs) {}
252

253
// 41 placeholder
254
function _math_ceil(xs) {}
255

256
// 42 placeholder
257
function _math_clz32(xs) {}
258

259
// 43 placeholder
260
function _math_cos(xs) {}
261

262
// 44 placeholder
263
function _math_cosh(xs) {}
264

265
// 45 placeholder
266
function _math_exp(xs) {}
267

268
// 46 placeholder
269
function _math_expm1(xs) {}
270

271
// 47 placeholder
272
function _math_floor(xs) {}
273

274
// 48 placeholder
275
function _math_fround(xs) {}
276

277
// 49 custom
278
// can't think of a way to deal with math_hypot
279
// without incurring a lot of redundant function calls
280
// so just using the ... operator instead on the machine
281
// change number of arguments to varargs (-1)
282
// replace NOTG opcode with MATH_HYPOT opcode
283
function _math_hypot(args) {
284
  // compile this instead for easier replacing
285
  return !args;
286
}
287

288
// 50 placeholder
289
function _math_imul(xs) {}
290

291
// 51 placeholder
292
function _math_log(xs) {}
293

294
// 52 placeholder
295
function _math_log1p(xs) {}
296

297
// 53 placeholder
298
function _math_log2(xs) {}
299

300
// 54 placeholder
301
function _math_log10(xs) {}
302

303
// 55 custom
304
// replace MODG opcode (25) with math_max opcode
305
// change number of arguments to varargs (-1)
306
function _math_max(args) {
307
  let i = array_length(args) - 1;
308
  let x = -Infinity;
309
  while (i >= 0) {
310
    // x = math_max(args[i],x)
311
    // compile this instead for easier replacing
312
    x = args[i] % x;
313
    i = i - 1;
314
  }
315
  return x;
316
}
317

318
// 56 custom
319
// replace MODG opcode (25) with math_max opcode
320
// change number of arguments to varargs (-1)
321
function _math_min(args) {
322
  let i = array_length(args) - 1;
323
  let x = Infinity;
324
  while (i >= 0) {
325
    // x = math_min(args[i],x)
326
    // compile this instead for easier replacing
327
    x = args[i] % x;
328
    i = i - 1;
329
  }
330
  return x;
331
}
332

333
// 57 placeholder
334
function _math_pow(xs) {}
335

336
// 58 placeholder
337
function _math_random(xs) {}
338

339
// 59 placeholder
340
function _math_round(xs) {}
341

342
// 60 placeholder
343
function _math_sign(xs) {}
344

345
// 61 placeholder
346
function _math_sin(xs) {}
347

348
// 62 placeholder
349
function _math_sinh(xs) {}
350

351
// 63 placeholder
352
function _math_sqrt(xs) {}
353

354
// 64 placeholder
355
function _math_tan(xs) {}
356

357
// 65 placeholder
358
function _math_tanh(xs) {}
359

360
// 66 placeholder
361
function _math_trunc(xs) {}
362

363
// 67
364
function _member(v, xs) {
365
  return is_null(xs) ? null : v === head(xs) ? xs : member(v, tail(xs));
366
}
367

368
// 68
369
function _pair(x, y) {
370
  return [x, y];
371
}
372

373
// 69 placeholder
374
function _parse_int(x,y) {}
375

376
// 70
377
function _remove(v, xs) {
378
  return is_null(xs) ? null : v === head(xs) ? tail(xs) : pair(head(xs), remove(v, tail(xs)));
379
}
380

381
// 71
382
function _remove_all(v, xs) {
383
  return is_null(xs)
384
    ? null
385
    : v === head(xs)
386
    ? remove_all(v, tail(xs))
387
    : pair(head(xs), remove_all(v, tail(xs)));
388
}
389

390
// 72
391
function _reverse(xs) {
392
  function rev(original, reversed) {
393
    return is_null(original) ? reversed : rev(tail(original), pair(head(original), reversed));
394
  }
395
  return rev(xs, null);
396
}
397

398
// 73 placeholder
399
function _get_time(x) {}
400

401
// 74
402
function _set_head(xs,x) {
403
  if (!is_pair(xs)) {
404
    error('set_head(xs) expects a pair as argument xs, but encountered ' + stringify(xs));
405
  } else {
406
    xs[0] = x;
407
  }
408
}
409

410
// 75
411
function _set_tail(xs, x) {
412
  if (!is_pair(xs)) {
413
    error('set_tail(xs) expects a pair as argument xs, but encountered ' + stringify(xs));
414
  } else {
415
    xs[1] = x;
416
  }
417
}
418

419
// 76 custom
420
// change number of arguments to varargs (-1)
421
function _stream(args) {
422
  let i = array_length(args) - 1;
423
  let p = null;
424
  while (i >= 0) {
425
    p = pair(args[i], p);
426
    i = i - 1;
427
  }
428
  return list_to_stream(p);
429
}
430

431
// 77
432
function _stream_append(xs, ys) {
433
  return is_null(xs)
434
    ? ys
435
    : pair(head(xs),
436
      () => stream_append(stream_tail(xs), ys));
437
}
438

439
// 78
440
function _stream_filter(p, s) {
441
  return is_null(s)
442
    ? null
443
    : p(head(s))
444
      ? pair(head(s),
445
        () => stream_filter(p, stream_tail(s)))
446
      : stream_filter(p, stream_tail(s));
447
}
448

449
// 79
450
function _stream_for_each(fun, xs) {
451
    if (is_null(xs)) {
452
      return true;
453
    } else {
454
      fun(head(xs));
455
      return stream_for_each(fun, stream_tail(xs));
456
    }
457
}
458

459
// 80
460
function _stream_length(xs) {
461
  return is_null(xs)
462
    ? 0
463
    : 1 + stream_length(stream_tail(xs));
464
}
465

466
// 81
467
function _stream_map(f, s) {
468
  return is_null(s)
469
    ? null
470
    : pair(f(head(s)),
471
      () => stream_map(f, stream_tail(s)));
472
}
473

474
// 82
475
function _stream_member(x, s) {
476
  return is_null(s)
477
    ? null
478
    : head(s) === x
479
      ? s
480
      : stream_member(x, stream_tail(s));
481
}
482

483
// 83
484
function _stream_ref(s, n) {
485
  return n === 0
486
    ? head(s)
487
    : stream_ref(stream_tail(s), n - 1);
488
}
489

490
// 84
491
function _stream_remove(v, xs) {
492
  return is_null(xs)
493
    ? null
494
    : v === head(xs)
495
      ? stream_tail(xs)
496
      : pair(head(xs),
497
        () => stream_remove(v, stream_tail(xs)));
498
}
499

500
// 85
501
function _stream_remove_all(v, xs) {
502
  return is_null(xs)
503
    ? null
504
    : v === head(xs)
505
      ? stream_remove_all(v, stream_tail(xs))
506
      : pair(head(xs), () => stream_remove_all(v, stream_tail(xs)));
507
}
508

509
// 86
510
function _stream_reverse(xs) {
511
  function rev(original, reversed) {
512
    return is_null(original)
513
      ? reversed
514
      : rev(stream_tail(original),
515
        pair(head(original), () => reversed));
516
  }
517
  return rev(xs, null);
518
}
519

520
// 87
521
function _stream_tail(xs) {
522
  if (!is_pair(xs)) {
523
    error('stream_tail(xs) expects a pair as argument xs, but encountered ' + stringify(xs));
524
  } else if (!is_function(xs[1])) {
525
    error('stream_tail(xs) expects a function as the tail of the argument pair xs, ' +
526
      'but encountered ' + stringify(xs[1]));
527
  } else {
528
    return xs[1]();
529
  }
530
}
531

532
// 88
533
function _stream_to_list(xs) {
534
  return is_null(xs)
535
    ? null
536
    : pair(head(xs), stream_to_list(stream_tail(xs)));
537
}
538

539
// 89
540
function _tail(xs) {
541
  if (!is_pair(xs)) {
542
    error('tail(xs) expects a pair as argument xs, but encountered ' + stringify(xs));
543
  } else {
544
    return xs[1];
545
  }
546
}
547

548
// 90 placeholder
549
function _stringify(x) {}
550

551
// 91 custom
552
// change number of args to varargs
553
// replace NOTG opcode with PROMPT opcode
554
function _prompt(args) {
555
  if (array_length(args) === 0) {
556
    const p = '';
557
    return !p;
558
  } else {
559
    return !args[0];
560
  }
561
}
562

563
// 92 custom
564
// replace MODG opcode (25) with display_list opcode
565
// change number of arguments to varargs (-1)
566
function _display_list(args) {
567
  // display_list(args[0], args[1]);
568
  // compile this instead for easier replacing
569
  return args[0] % args[1];
570
}
571

572
// 93 placeholder
573
function _char_at(str,index) {}
574

575
// 94 placeholder
576
function _arity(f) {}
577

578
// hack to make the call to Program easier, just replace the index 95 (number of primitive functions + 2)
579
(() => 0)();
580
`
581

582
// list of all primitive functions in alphabetical order. This determines the index
583
// of the function in the program array.
584
// If adding support for primitive functions, need to modify this array and the prelude
585
// above.
586
export const PRIMITIVE_FUNCTION_NAMES = [
59✔
587
  'accumulate',
588
  'append',
589
  'array_length',
590
  'build_list',
591
  'build_stream',
592
  'display',
593
  'draw_data',
594
  'enum_list',
595
  'enum_stream',
596
  'equal',
597
  'error',
598
  'eval_stream',
599
  'filter',
600
  'for_each',
601
  'head',
602
  'integers_from',
603
  'is_array',
604
  'is_boolean',
605
  'is_function',
606
  'is_list',
607
  'is_null',
608
  'is_number',
609
  'is_pair',
610
  'is_stream',
611
  'is_string',
612
  'is_undefined',
613
  'length',
614
  'list',
615
  'list_ref',
616
  'list_to_stream',
617
  'list_to_string',
618
  'map',
619
  'math_abs',
620
  'math_acos',
621
  'math_acosh',
622
  'math_asin',
623
  'math_asinh',
624
  'math_atan',
625
  'math_atan2',
626
  'math_atanh',
627
  'math_cbrt',
628
  'math_ceil',
629
  'math_clz32',
630
  'math_cos',
631
  'math_cosh',
632
  'math_exp',
633
  'math_expm1',
634
  'math_floor',
635
  'math_fround',
636
  'math_hypot',
637
  'math_imul',
638
  'math_log',
639
  'math_log1p',
640
  'math_log2',
641
  'math_log10',
642
  'math_max',
643
  'math_min',
644
  'math_pow',
645
  'math_random',
646
  'math_round',
647
  'math_sign',
648
  'math_sin',
649
  'math_sinh',
650
  'math_sqrt',
651
  'math_tan',
652
  'math_tanh',
653
  'math_trunc',
654
  'member',
655
  'pair',
656
  'parse_int',
657
  'remove',
658
  'remove_all',
659
  'reverse',
660
  'get_time',
661
  'set_head',
662
  'set_tail',
663
  'stream',
664
  'stream_append',
665
  'stream_filter',
666
  'stream_for_each',
667
  'stream_length',
668
  'stream_map',
669
  'stream_member',
670
  'stream_ref',
671
  'stream_remove',
672
  'stream_remove_all',
673
  'stream_reverse',
674
  'stream_tail',
675
  'stream_to_list',
676
  'tail',
677
  'stringify',
678
  'prompt',
679
  'display_list',
680
  'char_at',
681
  'arity'
682
]
683

684
export const VARARGS_NUM_ARGS = -1
59✔
685

686
// name, opcode, number of arguments, has return value
687
export const INTERNAL_FUNCTIONS: [string, OpCodes, number, boolean][] = [
59✔
688
  ['test_and_set', OpCodes.TEST_AND_SET, 1, true],
689
  ['clear', OpCodes.CLEAR, 1, false],
690
  ['concurrent_execute', OpCodes.EXECUTE, VARARGS_NUM_ARGS, false]
691
]
692

693
// for each function, replace a specified opcode with another opcode
694
const VARARG_PRIMITIVES: [string, number?, number?][] = [
59✔
695
  ['display', OpCodes.MODG, OpCodes.DISPLAY],
696
  ['error', OpCodes.MODG, OpCodes.ERROR],
697
  ['math_max', OpCodes.MODG, OpCodes.MATH_MAX],
698
  ['math_min', OpCodes.MODG, OpCodes.MATH_MIN],
699
  ['math_hypot', OpCodes.NOTG, OpCodes.MATH_HYPOT],
700
  ['list'],
701
  ['draw_data', OpCodes.NOTG, OpCodes.DRAW_DATA],
702
  ['stream'],
703
  ['prompt', OpCodes.NOTG, OpCodes.PROMPT],
704
  ['display_list', OpCodes.MODG, OpCodes.DISPLAY_LIST]
705
]
706

707
// primitives without a function should be manually implemented
708
export const NULLARY_PRIMITIVES: [string, number, any?][] = [
59✔
709
  ['math_random', OpCodes.MATH_RANDOM, Math.random],
710
  ['get_time', OpCodes.RUNTIME, get_time]
711
]
712

713
export const UNARY_PRIMITIVES: [string, number, any?][] = [
59✔
714
  ['array_length', OpCodes.ARRAY_LEN],
715
  ['is_array', OpCodes.IS_ARRAY],
716
  ['is_boolean', OpCodes.IS_BOOL],
717
  ['is_function', OpCodes.IS_FUNC],
718
  ['is_null', OpCodes.IS_NULL],
719
  ['is_number', OpCodes.IS_NUMBER],
720
  ['is_string', OpCodes.IS_STRING],
721
  ['is_undefined', OpCodes.IS_UNDEFINED],
722
  ['math_abs', OpCodes.MATH_ABS, Math.abs],
723
  ['math_acos', OpCodes.MATH_ACOS, Math.acos],
724
  ['math_acosh', OpCodes.MATH_ACOSH, Math.acosh],
725
  ['math_asin', OpCodes.MATH_ASIN, Math.asin],
726
  ['math_asinh', OpCodes.MATH_ASINH, Math.asinh],
727
  ['math_atan', OpCodes.MATH_ATAN, Math.atan],
728
  ['math_atanh', OpCodes.MATH_ATANH, Math.atanh],
729
  ['math_cbrt', OpCodes.MATH_CBRT, Math.cbrt],
730
  ['math_ceil', OpCodes.MATH_CEIL, Math.ceil],
731
  ['math_clz32', OpCodes.MATH_CLZ32, Math.clz32],
732
  ['math_cos', OpCodes.MATH_COS, Math.cos],
733
  ['math_cosh', OpCodes.MATH_COSH, Math.cosh],
734
  ['math_exp', OpCodes.MATH_EXP, Math.exp],
735
  ['math_expm1', OpCodes.MATH_EXPM1, Math.expm1],
736
  ['math_floor', OpCodes.MATH_FLOOR, Math.floor],
737
  ['math_fround', OpCodes.MATH_FROUND, Math.fround],
738
  ['math_log', OpCodes.MATH_LOG, Math.log],
739
  ['math_log1p', OpCodes.MATH_LOG1P, Math.log1p],
740
  ['math_log2', OpCodes.MATH_LOG2, Math.log2],
741
  ['math_log10', OpCodes.MATH_LOG10, Math.log10],
742
  ['math_round', OpCodes.MATH_ROUND, Math.round],
743
  ['math_sign', OpCodes.MATH_SIGN, Math.sign],
744
  ['math_sin', OpCodes.MATH_SIN, Math.sin],
745
  ['math_sinh', OpCodes.MATH_SINH, Math.sinh],
746
  ['math_sqrt', OpCodes.MATH_SQRT, Math.sqrt],
747
  ['math_tan', OpCodes.MATH_TAN, Math.tan],
748
  ['math_tanh', OpCodes.MATH_TANH, Math.tanh],
749
  ['math_trunc', OpCodes.MATH_TRUNC, Math.trunc],
750
  ['stringify', OpCodes.STRINGIFY],
751
  ['arity', OpCodes.ARITY]
752
]
753

754
export const BINARY_PRIMITIVES: [string, number, any?][] = [
59✔
755
  ['math_atan2', OpCodes.MATH_ATAN2, Math.atan2],
756
  ['math_imul', OpCodes.MATH_IMUL, Math.imul],
757
  ['math_pow', OpCodes.MATH_POW, Math.pow],
758
  ['parse_int', OpCodes.PARSE_INT, parse_int],
759
  ['char_at', OpCodes.CHAR_AT, char_at]
760
]
761

762
export const EXTERNAL_PRIMITIVES: [string, number][] = [
59✔
763
  ['display', OpCodes.DISPLAY],
764
  ['draw_data', OpCodes.DRAW_DATA],
765
  ['error', OpCodes.ERROR],
766
  ['prompt', OpCodes.PROMPT],
767
  ['display_list', OpCodes.DISPLAY_LIST]
768
]
769

770
export const CONSTANT_PRIMITIVES: [string, any][] = [
59✔
771
  ['undefined', undefined],
772
  ['Infinity', Infinity],
773
  ['NaN', NaN],
774
  ['math_E', Math.E],
775
  ['math_LN2', Math.LN2],
776
  ['math_LN10', Math.LN10],
777
  ['math_LOG2E', Math.LOG2E],
778
  ['math_LOG10E', Math.LOG10E],
779
  ['math_PI', Math.PI],
780
  ['math_SQRT1_2', Math.SQRT1_2],
781
  ['math_SQRT2', Math.SQRT2]
782
]
783

784
// helper functions to generate machine code
785
function generateNullaryPrimitive(index: number, opcode: number): [number, SVMFunction] {
UNCOV
786
  return [index, [1, 0, 0, [[opcode], [OpCodes.RETG]]]]
×
787
}
788

789
function generateUnaryPrimitive(index: number, opcode: number): [number, SVMFunction] {
UNCOV
790
  return [index, [1, 1, 1, [[OpCodes.LDLG, 0], [opcode], [OpCodes.RETG]]]]
×
791
}
792

793
function generateBinaryPrimitive(index: number, opcode: number): [number, SVMFunction] {
UNCOV
794
  return [index, [2, 2, 2, [[OpCodes.LDLG, 0], [OpCodes.LDLG, 1], [opcode], [OpCodes.RETG]]]]
×
795
}
796

797
// replaces prelude SVMFunction array with generated instructions
798
export function generatePrimitiveFunctionCode(prelude: Program) {
59✔
UNCOV
799
  const preludeFunctions = prelude[1]
×
UNCOV
800
  const functions: [number, SVMFunction][] = []
×
UNCOV
801
  const nameToIndexMap = new Map<string, number>()
×
802
  function convertPrimitiveVarArgs() {
UNCOV
803
    VARARG_PRIMITIVES.forEach(f => {
×
UNCOV
804
      const index = nameToIndexMap.get(f[0])!
×
UNCOV
805
      const opcodeToReplace = f[1]
×
UNCOV
806
      const opcodeToUse = f[2]
×
807
      // replace function's numargs to VARARGS_NUM_ARGS as indicator
UNCOV
808
      preludeFunctions[index + 1][2] = VARARGS_NUM_ARGS
×
809
      // replace opcode with corresponding opcode
UNCOV
810
      if (opcodeToReplace !== undefined && opcodeToUse !== undefined) {
×
UNCOV
811
        const instructions = preludeFunctions[index + 1][3]
×
UNCOV
812
        instructions.forEach(ins => {
×
UNCOV
813
          if (ins[0] === opcodeToReplace) ins[0] = opcodeToUse
×
814
        })
815
      }
816
    })
817
  }
818

UNCOV
819
  PRIMITIVE_FUNCTION_NAMES.forEach((name, index) => {
×
UNCOV
820
    nameToIndexMap.set(name, index)
×
821
  })
UNCOV
822
  NULLARY_PRIMITIVES.forEach(f =>
×
UNCOV
823
    functions.push(generateNullaryPrimitive(nameToIndexMap.get(f[0])!, f[1]))
×
824
  )
UNCOV
825
  UNARY_PRIMITIVES.forEach(f =>
×
UNCOV
826
    functions.push(generateUnaryPrimitive(nameToIndexMap.get(f[0])!, f[1]))
×
827
  )
UNCOV
828
  BINARY_PRIMITIVES.forEach(f =>
×
UNCOV
829
    functions.push(generateBinaryPrimitive(nameToIndexMap.get(f[0])!, f[1]))
×
830
  )
831

UNCOV
832
  functions.forEach(func => {
×
UNCOV
833
    const newFunc = func[1]
×
UNCOV
834
    const indexToReplace = func[0] + 1 // + 1 due to global env
×
UNCOV
835
    preludeFunctions[indexToReplace] = newFunc
×
836
  })
UNCOV
837
  convertPrimitiveVarArgs()
×
838
}
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