1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
|
#!/bin/bash
# full check: bootstraps the compiler from zc0, verifies the fixpoint, then runs
# the examples and tests on the portable interpreter (host), the microcore, the
# arm64 jit under qemu-user, and the llvm backend. needs a c compiler with c23
# #embed (src/tools/findcc.sh picks one; CC overrides it). the jit half needs
# aarch64-linux-gnu-gcc and qemu-aarch64 (linux-user, not qemu-system).
#
# the suite reads nothing from build/: it lays out the default map, bootstraps
# the compiler and builds every core into its own scratch directory, so it runs
# the same from a clean checkout as after `make`.
# the llvm half needs llvm-config (LLVM_CONFIG names another) and libLLVM. src/baremetal/run.sh boots the
# microcore on qemu-system-riscv64 and qemu-system-aarch64 when those cross
# compilers and system emulators are installed. each of these is skipped
# when its tools are missing.
#
# -j N runs N sections at a time, where N is how many cores to use. the
# sections are independent and each gets its own scratch directory, so they
# can overlap; the output still reads in the same order either way. -j 1 is
# the default, and is what make test does unless JOBS says otherwise.
#
# -q (make check) is the minimal suite for iterating: the bootstrap and the
# fixpoint, the interpreter section and the language server's own checks.
# it skips the other backends, the node protocol and corpus tests, and the
# js and make sections. run the whole thing (no -q) when the work is done.
cd "$(dirname "$0")/.."; T=$(mktemp -d); trap 'rm -rf $T' EXIT
ok=0; bad=0
chk(){ if [ "$1" = "$2" ]; then echo "ok $3"; ok=$((ok+1)); else echo "FAIL $3: got [$1]"; bad=$((bad+1)); fi; }
# the compiler is the files listed in src/compiler/parts, in that order
ccparts(){ tr -d '\r' < src/compiler/parts | sed 's|^|src/compiler/|'; }
src(){ cat src/runtime/rt.zc src/core/core.zc $(ccparts); }
# -j N runs N sections at a time: j is how many cores to use. each section
# writes its own log, so the output still reads in the order it always did.
JOBS=1; QUICK=0; SELECT=""
while [ $# -gt 0 ]; do
case "$1" in
-j) JOBS=$2; shift 2;;
-j*) JOBS=${1#-j}; shift;;
-q) QUICK=1; shift;;
--section) SELECT=$2; shift 2;;
*) echo "usage: $0 [-q] [-j N] [--section NAME]"; exit 2;;
esac
done
case "$JOBS" in ''|*[!0-9]*|0) JOBS=1;; esac
# each section gets its own scratch directory, so none of them can tread on
# another's files when they overlap
SECS="interp micro small runonly bare jit llvm lsp js make learn"
[ $QUICK = 1 ] && SECS="interp lsp learn"
if [ -n "$SELECT" ]; then
case " $SECS " in *" $SELECT "*) SECS=$SELECT;; *) echo "unknown test section: $SELECT" >&2; exit 2;; esac
fi
ROOT=$T
CC=${CC:-$(sh src/tools/findcc.sh)} || exit 1
export CC
# the language server runs on the interpreter unless the host has a jit (arm64, or x86-64
# linux), and a check of a large document then takes many seconds: stretch the drivers'
# deadlines. the x86-64 jit gets a little room
if [ -z "${ZC_TEST_TIMEOUT_SCALE:-}" ]; then case "$(uname -s)-$(uname -m)" in *-arm64|*-aarch64) ZC_TEST_TIMEOUT_SCALE=1;; Linux-x86_64) ZC_TEST_TIMEOUT_SCALE=2;; *) ZC_TEST_TIMEOUT_SCALE=8;; esac; fi
export ZC_TEST_TIMEOUT_SCALE
# the default map, generated as make does it, and the tools built against it
$CC -O2 -w -fwrapv src/tools/genmap.c -o $T/genmap || exit 1
$T/genmap --preset default --check -o $T/map >$T/genmap.log 2>&1 || { cat $T/genmap.log; echo "FAIL the default map does not match the checked-in sources"; exit 1; }
MAP=$T/map
$CC -O1 -w -fwrapv src/tools/zc0.c -Isrc/core -I$MAP -o $T/zc0 && $CC -O1 -w -fwrapv src/tools/mkgenome.c -I$MAP -o $T/mkg || exit 1
# the c helper for tests/programs/structval.zc: structs by value, loaded with cload
mkdir -p build && $CC -shared -fPIC -w tests/data/sbv.c -o build/sbv.so || exit 1
selfc(){ (cat src/tools/build.zc; printf '`'; src) | $1 > $2; }
# bootstrap: zc0 (c) -> g0, g0 compiles the compiler -> g1, g1 compiles it -> g2.
# each stage's core embeds the image in its own directory
mkdir $T/s0 $T/s1
src | $T/zc0 > $T/s0/g0.bin && $T/mkg < $T/s0/g0.bin > $T/s0/genome.bin || exit 1
$CC -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c -Isrc/core -I$MAP --embed-dir=$T/s0 -o $T/zy0 || exit 1
selfc $T/zy0 $T/g1.bin; $T/mkg < $T/g1.bin > $T/s1/genome.bin || exit 1
$CC -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c -Isrc/core -I$MAP --embed-dir=$T/s1 -o $T/zy1 || exit 1
selfc $T/zy1 $T/g2.bin
cmp -s $T/g1.bin $T/g2.bin && chk 1 1 "fixpoint: the compiler compiles itself to the same $(($(wc -c < $T/g1.bin) / 8)) words" || chk 0 1 "fixpoint"
# every core below carries the fixpoint genome: GI is the include and embed path for it
GI="-Isrc/core -I$MAP --embed-dir=$T/s1"
# built here rather than inside a section: interp runs the program list on
# it, and the run-only and bare-metal sections read it as the reference.
$CC -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c $GI -o $T/zy || exit 1
chk "$($T/zc0 < tests/programs/zc0typed.zc | md5sum)" "$($T/zc0 < tests/programs/zc0plain.zc | md5sum)" "zc0 reads types and throws them away: typed and plain sources give one image"
case "$($T/zc0 < tests/programs/zc0embed_write.zc 2>&1 >/dev/null)" in *"line 6: a local embed array is part of the code"*) chk 1 1 "zc0 refuses a store into a local embed array";; *) chk 0 1 "zc0 refuses a store into a local embed array";; esac
for n in $SECS; do
mkdir -p $ROOT/$n
cp $ROOT/g1.bin $ROOT/$n/ # the bootstrap's image, read by micro, jit and llvm
cp $ROOT/zy $ROOT/$n/zy # the interpreter, built once above
cp $ROOT/genmap $ROOT/$n/genmap
done
run(){ # $1 = vm command, $2 = label
local vm="$1" l="$2"
chk "$($vm < examples/hello.zc)" "hello, world!" "$l hello"
chk "$($vm < examples/fact.zc | tr '\n' '/')" "1101110101111100000000/3628800/" "$l factorial"
chk "$( (cat examples/echo.zc; printf '`abc\n') | $vm)" "abc" "$l echo after the backtick"
chk "$( (cat tests/programs/backtick.zc; printf '`xyz') | $vm)" "3 3 96 39 xyz" "$l a backtick in a comment, string or char literal does not end the source"
chk "$($vm < examples/selfpatch.zc)" "ABC" "$l self-patching code"
chk "$($vm < examples/lists.zc | tr '\n' '/')" "[0 1 4 9 16 25]/live: 7/after the block: 0/" "$l ownership frees everything"
chk "$( (cat examples/repl.zc; printf '`fn sq(x) { return x * x; }`rt.put_n(sq(7)); rt.put_c(10);`rt.put_s("hi\\n");') | $vm | tr '\n' '/')" "49/hi/" "$l repl on the resident compiler"
chk "$($vm < examples/typed.zc | tr '\n' '/')" "last: 4/point is 2 words: x int, y int/vec<point*> is 3 words: len int, cap int, items point**/push is bool(vec<T>*, T.d)/the heap says v is a vec<point*>, and v.items[0] is a point/" "$l typed example"
chk "$($vm < examples/wiring.zc)" "16 1234 25 4/9" "$l enhancement example"
chk "$($vm < tests/programs/allocfast.zc)" "0 0 499500 0" "$l constant-size allocation fast path"
chk "$($vm < tests/programs/o3_freelist.zc)" "0 0 1 12502500 500 1" "$l o3 new and free: class-list reuse, zeroing, an empty list, untyped neighbours"
chk "$(sed 's/^include rt;$/include rt;\nmemdebug on;/' tests/programs/o3_freelist.zc | $vm)" "0 0 1 12502500 500 1" "$l o3 new and free under memdebug take the general path"
chk "$($vm < tests/programs/basics.zc | tr '\n' '/')" "285 610 42 512/hey 65 -3 -2 1024 -8/12456/757/9 100-101/5/ok/" "$l language basics"
chk "$($vm < tests/programs/umd.zc)" "100 6 0 15 99 5 5" "$l u m d lifetimes"
chk "$($vm < tests/programs/names.zc)" "12 1 8" "$l u, m and d are ordinary names"
chk "$($vm < tests/programs/zc0umd.zc | tr '\n' '/')" "6 6 28 24 37 10/42 41 336 59/21 6 72 120 105 21/" "$l u, m and d as names, products, recasts and tags (the zc0 subset)"
chk "$($vm < tests/programs/gc.zc)" "1000 1 900 1 199900" "$l mark-sweep collector"
chk "$($vm < tests/programs/meta.zc | tr '\n' '/')" "1024 19/unless ok/rrr/15 42/7/42/7/144/" "$l parse words, quote, eval, load, operator tables"
chk "$($vm < tests/programs/misc.zc | tr '\n' '/')" "45/54321/ok/" "$l compile-time eval, patched mnemonics, unchecked"
chk "$($vm < tests/programs/defer.zc | tr '\n' '/')" "1 2 10 11 20 30 /7 /2 2 /9 18 /-1 /500 1 /501 500 2 /2 1 5 9 /4 3 5 9 /1 101 102 3 103 104 777 0 200 300 201 2 202 401 402 403 900 /60 50 0 51 1 62 52 2 2000 1000 /51 1 50 /50 51 2 3 /4 3 5 2 6 1 7 /10 11 99 0 /21 99 0 /31 0 /2 1 42 /9 12 /0 2 /0 /10 11 20 0 /2 3 4 5 /9 0 2 3 /" "$l defer: block end, return, break, continue, ownership"
chk "$($vm < tests/programs/types.zc | tr '\n' '/')" "12 5 2 15 56 42 7 14 3/rect rect* list<int>* list<T>*.u(int) T(list<T>*) fn(word.d)/a:point@0 b:point@2 tag:int@4 /point 1 1/" "$l types, generics, reflection"
chk "$($vm < tests/programs/typedef.zc | tr '\n' '/')" "7 1 42 5 30/13 4 19 4/4 3 3 12/5 11/hihihihellook/8/" "$l typedef, global and local, in every place a type goes, and string"
chk "$($vm < tests/programs/typeok.zc)" "14" "$l a program the typechecker accepts"
chk "$($vm < tests/programs/typeoff.zc)" "6" "$l the typechecker is off by default"
chk "$($vm < tests/programs/enhance.zc)" "100 0 343 3,2 5 -2 0" "$l virtual enhancements"
chk "$($vm < tests/programs/precedence.zc)" "1 1 1 1 1 1" "$l && binds tighter than ||, as in c"
chk "$($vm < tests/programs/const_local.zc)" "6 42 zc" "$l an untyped local const takes its initializer's type"
chk "$($vm < tests/programs/joins.zc)" "0 0 5 80 8 3 9 0" "$l joins free what one path gave away; switch, ?:, no prototypes"
chk "$($vm < tests/programs/buddy.zc)" "131072 262144 1 0" "$l buddy allocator merges freed blocks"
chk "$($vm < tests/programs/growheap.zc)" "144 1 7 1" "$l the heap grows past its initial size and a bigger block fits after the frees"
chk "$($vm < tests/programs/sized.zc | md5sum)" "$(md5sum < tests/programs/sized.expected)" "$l sized integers wrap, and arrays and pointers of them are packed"
chk "$($vm < tests/programs/bitops.zc | md5sum)" "$(md5sum < tests/programs/bitops.expected)" "$l ctz, popcnt, bswap, rotates, mulh and float32 conversion micro-ops"
chk "$($vm < tests/programs/f32.zc | md5sum)" "$(md5sum < tests/programs/f32.expected)" "$l f32: single precision scalars and packed arrays"
chk "$($vm < tests/programs/f32o3.zc)" "10718.750000 1.600000 0" "$l f32 inside an o3 region"
chk "$($vm < tests/programs/sizedvec.zc | md5sum)" "$(md5sum < tests/programs/sizedvec.expected)" "$l growable arrays of the sized types and f32"
chk "$($vm < tests/programs/packedfields.zc | md5sum)" "$(md5sum < tests/programs/packedfields.expected)" "$l struct fields of the sized types pack into words"
chk "$($vm < tests/programs/generics.zc | md5sum)" "$(md5sum < tests/programs/generics.expected)" "$l generic functions are compiled per type arguments"
chk "$($vm < tests/programs/genmeth.zc | md5sum)" "$(md5sum < tests/programs/genmeth.expected)" "$l methods of generic structs are compiled per type arguments"
chk "$($vm < tests/programs/static.zc)" "14 5 9" "$l static functions of a struct are called as Struct.name(args)"
chk "$($vm < tests/programs/struct_const.zc)" "24 49 24 23 19 55 12 99" "$l constants declared in a struct are reached as Struct.NAME, and by bare name in its methods"
chk "$($vm < tests/programs/struct_static_call.zc)" "3 100 11 8 1010 7" "$l a static function of a struct is called by its bare name in its methods, and wins over a global of the same name"
chk "$($vm < tests/programs/methodown.zc)" "7 9" "$l struct methods and functions return owned objects (.u)"
chk "$($vm < tests/programs/typedmethods.zc)" "14 5 13" "$l struct methods declare a return type and typed parameters"
chk "$($vm < tests/programs/enumscope.zc)" "0 5 6 blue" "$l enum members are reached as Enum.MEMBER, also in a case"
chk "$($vm < tests/programs/enumtype.zc)" "6 5 1" "$l typed enums: members take their enum, an enum becomes an int"
chk "$($vm < tests/programs/tagenum.zc)" "27 20 0 0 1 2" "$l tagged enums: members carry fields, constructors build them, a case binds the fields"
chk "$($vm < tests/programs/tagenum_warn.zc)" "$(printf 'zc: line 8: warning: this switch doesn'"'"'t cover rect\n0')" "$l a switch on a tagged enum that misses a member warns, on the switch's line"
chk "$($vm < tests/programs/tagenum_two.zc)" "3 8 12" "$l two tagged enums with the same member name, and a case in an o3 loop"
chk "$($vm < tests/programs/o3push.zc | md5sum)" "$(md5sum < tests/programs/o3push.expected)" "$l push and pop of a growable array are inline in o3"
chk "$($vm < tests/programs/o3copy.zc)" "520507 1005" "$l o3 copies of a loop variable read the source instead"
chk "$($vm < tests/programs/borrowmove.zc)" "6" "$l storing into a borrowed object moves it"
chk "$($vm < tests/programs/embed.zc | tr '\n' '/')" "hello/world 11 42 5 255 8 -1 0 119 15 5 255 3 98 321 63/" "$l embed declarations: strings, numbers and arrays from files, global and local"
chk "$($vm < tests/programs/ownmove.zc)" "7 50 0 1" "$l an owned local moves into a released owner, and a global borrows a local until it is restored"
chk "$($vm < tests/programs/alias.zc)" "11 22 4 8" "$l aliases of a live owner: arithmetic, field, index"
chk "$($vm < tests/programs/quarantine.zc)" "0 1234" "$l quarantine: stale alias reads intact data, second free is a no-op"
chk "$($vm < tests/programs/recycle.zc)" "1 0 1" "$l recycle returns a dropped block to its size class"
chk "$($vm < tests/programs/roots.zc)" "1 0" "$l the collector marks the live stack, and scrub clears the rest"
chk "$($vm < tests/programs/arena.zc)" "4 7 0 1 1" "$l bump arena allocates, rewinds, and refuses a bump past the end"
chk "$($vm < tests/programs/csyn.zc)" "13 0 5 6 0" "$l do/while, enum, and a C cast"
chk "$($vm < tests/programs/use_std.zc)" "42 -7 1" "$l include and the string helpers"
chk "$($vm < tests/programs/stdbuf.zc)" "4 1 266 8" "$l stdlib arena and packed byte buffer"
chk "$($vm < tests/programs/stdmore.zc)" "$(printf '5 1 0 0 7 copy me 12 -1 0 1 0 1\n9 mixed 123 9 MIXED 123\n11 [padded line]\n42 3 9 10 12 81 9 10 -1 0\n6 1 2 -1 1 0')" "$l stdlib text, byte-string and num helpers"
chk "$( (cat tests/programs/stdio.zc; printf '`abc\nlonger\nxyz') | $vm)" "$(cat tests/programs/stdio.expected)" "$l std.Io writers, capture, getline and read"
chk "$(ZC_FILE=tests/data/hi.txt $vm < examples/cli.zc)" "6 h" "$l reading a file named by the environment"
chk "$(ZC_ARG_TEST=ok $vm < tests/programs/args.zc)" "1 <eval> <eval> 1 1" "$l argv and envp from the host, argv[0] is <eval> on stdin"
chk "$(ZC_ARG_TEST=ok $vm < tests/programs/capture.zc)" "0
1
15
hello world!42
1
1
0" "$l capture.start() collects output and end() hands back the string"
chk "$($vm < tests/programs/capture_long.zc)" "7
256
v" "$l a full capture is still terminated inside its buffer"
chk "$($vm < tests/programs/sys.zc)" "2 zy time" "$l syscalls: write, read, time"
chk "$($vm < tests/programs/file_drop.zc)" "5 1 1 hello! 1" "$l std.File: its drop closes the descriptor at block end"
chk "$($vm < tests/programs/memleak.zc)" $'leak: line 8 1 words\n1' "$l memdebug names a live allocation"
chk "$($vm < tests/programs/uaf.zc)" $'zc: line 10: warning: use after free: this storage\'s lifetime ended on line 9\nzy: use after free from line 7\n at <stdin>:10 in main' "$l memdebug: use after free"
chk "$($vm < tests/programs/uaf_in.zc)" $'zy: use after free from line 7\n at <stdin>:11 in main' "$l memdebug: use after free through an interior pointer"
chk "$($vm < tests/programs/doublefree.zc)" $'zy: double free from line 7\n at <stdin>:9 in main\nok' "$l memdebug: double free is reported and does nothing"
chk "$($vm < tests/programs/trace.zc 2>&1 | md5sum)" "$(md5sum < tests/programs/trace.expected)" "$l rt.trace() and a fault print the call stack with file, line and function"
chk "$($vm < tests/programs/trace_more.zc 2>&1 | sed 's/0x[0-9a-f]*/ADDR/' | md5sum)" "$(md5sum < tests/programs/trace_more.expected)" "$l backtraces: methods, closures, lines off, a deep stack is cut to its ends"
chk "$($vm < tests/programs/trace_jit.zc 2>&1 | md5sum)" "$(md5sum < tests/programs/trace_jit.expected)" "$l rt.trace() from code the jit has translated: op 56 reads the return stack pointer there too"
chk "$($vm < tests/programs/scrub.zc)" $'zc: line 9: warning: use after free: this storage\'s lifetime ended on line 8\n57005' "$l memdebug scrub poisons a freed payload"
chk "$($vm < tests/programs/interior.zc)" "0" "$l an interior pointer keeps a quarantined block"
chk "$($vm < tests/programs/wide.zc)" "1099511627776 1 1 1 -1" "$l 64-bit shifts and equality"
chk "$($vm < tests/programs/float.zc)" "4.000000 4.500000 3.000000 2.500000 2.500000 0.001500 0.100000 -0.125000 inf -inf nan 1 1 1 0 0 3 -3 3.000000 -2.000000 2" "$l floating point"
chk "$($vm < tests/programs/ftruth.zc)" "00111000110107" "$l negative zero is false"
chk "$($vm < tests/programs/ftype.zc)" "3.500000 10.500000 3.500000 4.250000 5.250000 4.250000 6.500000 2 4 4.250000 8.500000 1 4" "$l float type through calls, globals, fields"
chk "$($vm < tests/programs/fo3.zc)" "5997 5997 4.000000 nan 0 3.250000 1 0 0" "$l o3 lifts float ops"
chk "$($vm < tests/programs/ftext.zc)" "1e+308 1e-10 -0 inf -inf nan 0.1 1.50 1.250e+0 100000000000000000000.000000 1e+40 1111111111" "$l float text: shortest, fixed, scientific, 17 digits"
chk "$($vm < tests/programs/bytes.zc)" "17 34 43981 16909060 1 205 171 -3674937295934316015 1108152156331 0 0 30768
ABC" "$l byte addressing"
chk "$($vm < tests/programs/o3bytes.zc)" "190 4660 7 2055 16909060 0 0
ABC" "$l o3 lifts byte loads and stores"
chk "$($vm < tests/programs/o3zero.zc)" "1" "$l untyped new inside o3 zeroes its words"
chk "$($vm < tests/programs/strings.zc)" "hi! 3 3 104 i! 1 1 1 -42 42 -42 11 1 -9223372036854775808 0 1 3 10 1 1 1 W ab" "$l byte strings"
chk "$($vm < tests/programs/share.zc)" "1 2 1 4 1 1 1 1 42 1 1 1 6 0" "$l shared cons cells"
chk "$($vm < tests/programs/share_dbg.zc)" "7 1" "$l memdebug accepts a shared cell"
chk "$($vm < tests/programs/memdebug_interior.zc | md5sum)" "$(md5sum < tests/programs/memdebug_interior.expected)" "$l memdebug finds the block of a deep interior pointer"
chk "$($vm < tests/programs/global_transfer.zc)" "5 9" "$l an m or u owner stored in a global is transferred"
chk "$($vm < tests/programs/closure_result.zc)" "8 1.500000" "$l a closure with a declared result type"
chk "$($vm < examples/strings.zc)" "hello, zc
9 42" "$l byte string example"
chk "$(ZC_BSTR=zybyte $vm < tests/programs/bstr_io.zc)" "byte-io 7 7 1 6 122 101" "$l byte-string file and getenv"
chk "$($vm < tests/programs/manyerrors.zc | tr '\n' '/')" "zc: line 6: expected an expression, found ';'/zc: line 7: x: owned object is never used/zc: line 8: type error: initializer: expected char*, got int/zc: line 9: expected ';', found '}'/zc: 4 errors/" "$l several errors in one run"
chk "$($vm < tests/programs/overflow_return.zc 2>&1)" "zy: return stack overflow" "$l return stack overflow is caught"
chk "$($vm < tests/programs/overflow_data.zc 2>&1)" "zy: data stack overflow" "$l data stack overflow is caught"
chk "$($vm < tests/programs/overflow_frame.zc 2>&1 | head -1)" "zc: out of heap memory" "$l frame growth stops at a configured memory limit"
chk "$($vm < examples/mandel.zc 2>&1 | md5sum | cut -c1-32)" "f41aecbf2c844168050413cfa832db0e" "$l example: mandelbrot with a fixed-point enhancement"
chk "$($vm < examples/bf.zc 2>&1 | md5sum | cut -c1-32)" "223570983752b17f7ece32e93d5e19e4" "$l example: brainfuck compiled at runtime"
chk "$($vm < examples/dump.zc 2>&1 | md5sum | cut -c1-32)" "757774b00f6b3cd0bfbcba66448a8619" "$l example: struct printer through reflection"
chk "$($vm < examples/tree.zc 2>&1 | md5sum | cut -c1-32)" "b86a2e4e9e31acc294a4ddf86be863f2" "$l example: owning tree frees itself"
chk "$($vm < examples/lang.zc 2>&1 | md5sum | cut -c1-32)" "$(printf '22\none isn'"'"'t bigger than two\n***\nassertion failed on line 50\n' | md5sum | cut -c1-32)" "$l example: pipe operator, unless, assert, times"
chk "$($vm < examples/staged.zc 2>&1 | md5sum | cut -c1-32)" "6f790a125c48b0cc7a897cee73ee5627" "$l example: staged code compiled while running"
chk "$($vm < examples/quine.zc 2>&1 | md5sum | cut -c1-32)" "$(md5sum < examples/quine.zc | cut -c1-32)" "$l example: quine"
chk "$($vm < examples/primes.zc 2>&1 | md5sum | cut -c1-32)" "814faffc70dad0ae520c0671c33e73d4" "$l example: o3 prime sieve"
chk "$($vm < examples/life.zc 2>&1 | md5sum | cut -c1-32)" "aefb036b6f9ad1dadfc3e6bb47a6885d" "$l example: game of life"
chk "$($vm < tests/programs/arrays.zc | tr '\n' '/')" "100 128 9801 9801 99 3 4 12 19 8 19 28/0/" "$l growable and fixed arrays"
chk "$($vm < tests/programs/o3.zc)" "3142 42 43 9 57 98781 520625 10192 -18782 1152" "$l o3 regions: loops, calls, recursion, switch, arrays, more vars than registers"
chk "$($vm < tests/programs/o3scopes.zc)" "116" "$l o3 registers shared by scopes, cached fixed arrays"
chk "$($vm < tests/programs/borrow_rules.zc)" "$(cat tests/programs/borrow_rules.expected)" "$l inferred transfers, projections and shared closure cells"
chk "$($vm < tests/programs/forward_borrow.zc)" "2b00" "$l forward calls: results that do not borrow, or are not used after the owner ends, are accepted"
chk "$($vm < tests/programs/borrows_clause.zc)" "x" "$l a borrows clause ties the result to the named argument only"
chk "$($vm < tests/programs/replace_owner.zc)" "$(cat tests/programs/replace_owner.expected)" "$l replacing a released owner moves ownership and cleans up once"
chk "$($vm < tests/programs/temporary_borrows.zc)" "$(cat tests/programs/temporary_borrows.expected)" "$l temporary borrows preserve aliases and release allocations"
chk "$($vm < tests/programs/array_values.zc)" "$(cat tests/programs/array_values.expected)" "$l array initializers, designators, zero filling, nested and compound literals"
chk "$($vm < tests/programs/o3fat.zc)" "node node 3 box node int[0]" "$l o3 data gets fattened on the way out"
chk "$($vm < tests/programs/o3call.zc)" "0 0 4 23 55 node" "$l o3 calls o3 directly, and new stamps the header"
chk "$($vm < tests/programs/o3direct.zc | md5sum)" "$(md5sum < tests/programs/o3direct.expected)" "$l o3 calls: arguments, results, recursion, floats, pointers, the ways out of a fast call"
chk "$($vm < tests/programs/o3licm.zc)" "3184200 7950 315 50 260 -56" "$l o3 hoists loop invariants and shares values between blocks"
chk "$($vm < tests/programs/o3deep.zc)" "30000" "$l o3 recursion thirty thousand deep"
chk "$($vm < tests/programs/o3deep_over.zc 2>&1)" "100000" "$l o3 recursion grows past the original stack"
chk "$($vm < tests/programs/o3_bounds.zc 2>&1; echo "rc=$?")" "rc=0" "$l o3 implies unbounded: no check on a T[?] index"
chk "$($vm < tests/programs/bounds.zc)" "55 55 8" "$l a proved +1 loop skips the bounds check"
chk "$($vm < tests/programs/bounds_lo.zc 2>&1 | head -1)" "zy: index -1 out of range (length 4)" "$l a negative loop index is still checked"
chk "$($vm < tests/programs/bounds_hi.zc 2>&1; echo "rc=$?")" "rc=0" "$l o3 implies unbounded: an index that is not the induction variable is not checked"
chk "$($vm < tests/programs/boundsrules.zc 2>&1 | head -3)" $'5\n7\nzy: index 5 out of range (length 4)' "$l unbounded as prefix, block and statement, o3 implies it; checked code reports"
chk "$($vm < tests/programs/bounds_fixed.zc 2>&1 | head -3)" $'55\n29\nzy: index 6 out of range (length 6)' "$l a fixed array with a variable index is checked against its length"
chk "$($vm < tests/programs/bounds_heap.zc 2>&1 | head -4)" $'3\n0\nx\nzy: index 11 out of range (length 11)' "$l a pointer to a heap block is checked against its payload"
chk "$($vm < tests/programs/enh_ops.zc | md5sum)" "$(md5sum < tests/programs/enh_ops.expected)" "$l enhancement micro-ops on edge values, with variables and with literals"
chk "$($vm < tests/programs/bounds_proof.zc)" $'0\n1\n1' "$l a loop test against a constant drops the fixed-array check; a variable bound keeps it"
chk "$($vm < tests/programs/bounds_hoist.zc 2>&1 | head -5)" $'28\n3\n27\n0 1 2 3 4 5 6 7 8 zy: index 8 out of range (length 8)\n at <stdin>:17 in main' "$l a check against an invariant bound is hoisted to the loop entry and still faults in place"
chk "$($vm < tests/programs/bounds_body.zc 2>&1 | head -1)" "zy: index -2999 out of range (length 4)" "$l a body that moves the loop index keeps the check"
chk "$($vm < tests/programs/bounds_ptr.zc 2>&1 | head -3 | cut -c1-9)" $'120\n240\nzy: index' "$l a pointer from rt.new(n): proved, hoisted, or kept when the body calls"
chk "$($vm --explain-checks < tests/programs/explain_checks.zc | md5sum)" "$(md5sum < tests/programs/explain_checks.expected)" "$l --explain-checks lists the kept checks (format v1)"
chk "$($vm < tests/programs/bounds_prover.zc 2>&1 | head -5)" $'28\n36\n0 1 2 3 4 5 6 zy: index 6 out of range (length 6)\n at <stdin>:17 in main' "$l loop prover: len, cross-array and affine proofs; a too-long constant bound still faults"
chk "$($vm --explain-checks < tests/programs/explain_prover.zc | md5sum)" "$(md5sum < tests/programs/explain_prover.expected)" "$l --explain-checks for the prover cases (proved lines absent, kept lines present)"
chk "$($vm < tests/programs/explain_prover.zc)" "1204" "$l explain_prover runs and prints its checksum"
chk "$($vm --explain-checks a/b.zc < tests/programs/bounds.zc | head -1)" '{"version":1}' "$l --explain-checks starts with the version line"
chk "$($vm < tests/programs/zc0unbounded.zc)" "42" "$l unbounded in the unit, a prefix and a statement"
local r; r=$(bash tests/runerr.sh "$vm" tests/errors | tail -1)
chk "$r" "rejected: $(ls tests/errors/*.zc | wc -l | tr -d ' ') passed, 0 failed" "$l analyzer rejects every bad program"
r=$(bash tests/runerr.sh "$vm" tests/typeerrors | tail -1)
chk "$r" "rejected: $(ls tests/typeerrors/*.zc | wc -l | tr -d ' ') passed, 0 failed" "$l typechecker rejects every bad program"
r=$(bash tests/runerr.sh "$vm" tests/langerrors | tail -1)
chk "$r" "rejected: $(ls tests/langerrors/*.zc | wc -l | tr -d ' ') passed, 0 failed" "$l o3 and array misuse is rejected"
bash tests/exitstatus.sh "$vm" > /tmp/zy-exitstatus.$$ 2>&1; r=$?; grep -v '^ok' /tmp/zy-exitstatus.$$; rm -f /tmp/zy-exitstatus.$$
chk $r 0 "$l a compile error exits 1, a good program and a runtime trap exit 0"
}
s_interp() {
T=$ROOT/interp
$CC -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c $GI -o $T/zy
run $T/zy "interp"
# docs/SPEC.md conformance programs; failures listed in tests/conformance/known.txt do not count.
# not in the quick path (-q, make check): it takes about half a minute
if [ $QUICK = 0 ]; then
bash tests/conformance/run.sh --zy $T/zy -w $T/conformance -q > $T/conformance.out 2>&1; r=$?
grep '^FAIL' $T/conformance.out
chk $r 0 "interp conformance suite: $(grep '^ total' $T/conformance.out | sed 's/ */ /g')"
fi
python3 tests/drivers/array_methods_test.py $T/zy > $T/arrays.out 2>&1; r=$?
grep -v '^ok' $T/arrays.out
chk $r 0 "native array receiver, algorithm and ownership contracts"
# actors are a library: nothing the compiler compiles or reads by default mentions them
chk "$(grep -il actor $(ccparts) src/runtime/rt.zc src/core/core.zc src/lib/std.zc src/lib/icon.zc src/tools/build.zc | wc -l)" "0" "no actor code in the compiler or anything it reads by default"
python3 tests/drivers/actor_test.py $T/zy > $T/actor.out 2>&1; r=$?
grep -v '^ok' $T/actor.out
chk $r 0 "native isolated actor acceptance, rejection and regression fixtures"
python3 tests/drivers/hold_test.py $T/zy > $T/hold.out 2>&1; r=$?
grep -v '^ok' $T/hold.out
chk $r 0 "native hold blocks: monitors, rejections, a race between actors, rank order"
chk "$(ZC_ARG_TEST=ok $T/zy tests/programs/args.zc alpha beta < tests/programs/args.zc)" "4 <eval> beta 1 1" "interp the command line reaches argv, after <eval>"
chk "$($T/zy < tests/programs/cabi.zc | md5sum)" "$(md5sum < tests/programs/cabi.expected)" "interp native calls and callbacks (extern, cfunc)"
chk "$($T/zy < tests/programs/cabi_o3.zc | md5sum)" "$(md5sum < tests/programs/cabi_o3.expected)" "interp native calls from o3 code, more arguments than registers"
chk "$($T/zy < tests/programs/cabi_sized.zc | md5sum)" "$(md5sum < tests/programs/cabi_sized.expected)" "interp native calls with f32 and the sized integers"
chk "$($T/zy < tests/programs/structval.zc)" "34 3520 18 325 810 340" "interp structs by value to a c function (registers, sse, stack)"
chk "$($T/zy < tests/programs/structret.zc)" "3 4 3.500000 4.000000 24 8 1.000000 3.500000" "interp structs returned from a c function (registers, sse, memory)"
chk "$(ZYTRACE=1 $T/zy < tests/programs/o3.zc 2>&1 | grep -c 'micro-ops$')" "8" "every o3 region lifts"
chk "$($T/zy < tests/programs/infer_return.zc)" "3" "an owned return with no .u is inferred from the body"
chk "$($T/zy < tests/programs/discard_m.zc)" "7" "m* discards an unnamed u result"
chk "$($T/zy < tests/programs/closure.zc | tr '\n' ' ')" "31 35 42 2 7 7 109 30 7 16 33 20 101 " "closures: calls through values, captures, nesting, returns"
chk "$($T/zy < tests/programs/decl_undefined.zc 2>&1 | head -1)" "zc: line 3: helper is used but never defined" "a declared function nothing defines fails a build"
if [ "$(uname -s)" = Linux ]; then chk "$($T/zy < tests/programs/rawsys.zc)" "-38" "Host.raw: an unknown syscall number gives -ENOSYS"; else chk "$($T/zy < tests/programs/rawsys.zc)" "-1" "Host.raw: unavailable on this host"; fi
if [ "$(uname -m)" = x86_64 ]; then chk "$($T/zy < tests/programs/rawpid.zc)" "1" "Host.raw: getpid (39 on x86-64) answers"; fi
}
s_micro() {
T=$ROOT/micro
$CC -pthread -DZY_THREADS -O2 -w -fwrapv src/micro/micro.c src/micro/port_linux.c $GI -Isrc/micro -o $T/zym || exit 1
run $T/zym "micro"
python3 tests/drivers/array_methods_test.py $T/zym > $T/arrays.out 2>&1; r=$?
grep -v '^ok' $T/arrays.out
chk $r 0 "micro array receiver, algorithm and ownership contracts"
python3 tests/drivers/actor_test.py $T/zym > $T/actor.out 2>&1; r=$?
grep -v '^ok' $T/actor.out
chk $r 0 "micro isolated actor acceptance, rejection and regression fixtures"
python3 tests/drivers/hold_test.py $T/zym > $T/hold.out 2>&1; r=$?
grep -v '^ok' $T/hold.out
chk $r 0 "micro hold blocks: monitors, rejections, a race between actors, rank order"
if command -v node >/dev/null && command -v tsc >/dev/null && node src/js/mklayout.js --map $MAP/memmap.h --out $T/jsvm >/dev/null \
&& cp $ROOT/s1/genome.bin $T/jsvm/ && tsc src/js/tinyvm.ts --target es2020 --lib es2020,dom --module commonjs --outDir $T/jsvm; then
python3 tests/drivers/fuzz_compiler.py $ROOT/zy $T/zym --js $T/jsvm/tinyvm.js > $T/fuzz.out 2>&1; r=$?
else
python3 tests/drivers/fuzz_compiler.py $ROOT/zy $T/zym > $T/fuzz.out 2>&1; r=$?
fi
grep -v '^ok' $T/fuzz.out
chk $r 0 "compiler/runtime/stdlib differential fuzz across available hosts"
python3 tests/drivers/fuzz_malformed.py $ROOT/zy $T/zym > $T/fuzzmalformed.out 2>&1; r=$?
grep -v '^ok' $T/fuzzmalformed.out
chk $r 0 "malformed compiler input fuzz and host agreement"
selfc $T/zym $T/gm.bin
cmp -s $T/g1.bin $T/gm.bin && chk 1 1 "microcore self-compile matches" || chk 0 1 "microcore self-compile matches"
$CC -ffreestanding -w -c src/micro/micro.c $GI -Isrc/micro -o $T/micro.o && $CC -ffreestanding -w -c src/micro/port_stub.c $GI -Isrc/micro -o $T/stub.o && chk 1 1 "microcore and the stub port compile freestanding" || chk 0 1 "microcore and the stub port compile freestanding"
$CC -pthread -O2 -w -fwrapv -DJTYPE=int -DZY_SOFTFLOAT -DZYINTERP src/core/core.c src/core/io_linux.c $GI -o $T/zysoft || exit 1
chk "$($T/zysoft < tests/programs/float.zc)" "4.000000 4.500000 3.000000 2.500000 2.500000 0.001500 0.100000 -0.125000 inf -inf nan 1 1 1 0 0 3 -3 3.000000 -2.000000 2" "soft-float fallback matches the hardware line"
chk "$($T/zysoft < tests/programs/ftruth.zc)" "00111000110107" "soft-float negative zero is false"
chk "$($T/zysoft < tests/programs/fo3.zc)" "5997 5997 4.000000 nan 0 3.250000 1 0 0" "soft-float o3 float ops match"
chk "$($T/zysoft < tests/programs/ftext.zc)" "1e+308 1e-10 -0 inf -inf nan 0.1 1.50 1.250e+0 100000000000000000000.000000 1e+40 1111111111" "soft-float text matches"
}
s_small() {
T=$ROOT/small
# smaller machines. addresses are literals, so each size is its own genome.
$CC -O2 -w -fwrapv src/tools/genmap.c $GI -o $T/genmap || exit 1
$T/genmap --preset default --check >/dev/null && chk 1 1 "default map matches the checked-in sources" || chk 0 1 "default map matches the checked-in sources"
$T/genmap --preset small -o $T/small || exit 1
$T/genmap --mode compiler --name small --heap-lo 8192 --heap 20480 --types 8192 \
--genome 393216 --frame 2048 --return 512 --mark 512 --data 3072 \
--snap-cap 1000 --quote-cap 300 -o $T/small-flags || exit 1
cmp -s $T/small/memmap.h $T/small-flags/memmap.h && cmp -s $T/small/rt.zc $T/small-flags/rt.zc \
&& cmp -s $T/small/compiler.zc $T/small-flags/compiler.zc && cmp -s $T/small/map.txt $T/small-flags/map.txt \
&& chk 1 1 "compiler flags reproduce the small map" || chk 0 1 "compiler flags reproduce the small map"
cp src/tools/zc0.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $T/small/
$CC -O1 -w -fwrapv $T/small/zc0.c -o $T/zc0s || exit 1
cat $T/small/rt.zc src/core/core.zc $T/small/compiler.zc | $T/zc0s > $T/small/genome.bin || exit 1
cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $T/small/
$CC -pthread -DZY_THREADS -O2 -w -fwrapv $T/small/micro.c $T/small/port_linux.c -o $T/zyms || exit 1
$CC -pthread -O2 -w -fwrapv -DJTYPE=int $T/small/core.c $T/small/io_linux.c -o $T/zys || exit 1
$CC -ffreestanding -w -c $T/small/micro.c -o $T/micro_s.o && $CC -ffreestanding -w -c $T/small/port_stub.c -o $T/stub_s.o && chk 1 1 "small microcore compiles freestanding" || chk 0 1 "small microcore compiles freestanding"
sameout() { # $1 = other vm, $2 = label, $3 = source file
local a b
a=$($T/zy < "$3" 2>&1 | tr '\n' '/')
b=$($1 < "$3" 2>&1 | tr '\n' '/')
chk "$b" "$a" "$2"
}
for f in examples/hello.zc examples/fact.zc examples/lists.zc examples/typed.zc examples/wiring.zc examples/life.zc \
tests/programs/basics.zc tests/programs/wide.zc tests/programs/types.zc tests/programs/alias.zc tests/programs/meta.zc tests/programs/arrays.zc \
tests/programs/joins.zc tests/programs/enhance.zc tests/programs/o3.zc tests/programs/csyn.zc tests/programs/umd.zc tests/programs/quarantine.zc tests/programs/roots.zc \
tests/programs/float.zc tests/programs/ftruth.zc tests/programs/ftype.zc tests/programs/fo3.zc tests/programs/ftext.zc tests/programs/bytes.zc \
tests/programs/strings.zc examples/strings.zc tests/programs/share.zc tests/programs/share_dbg.zc; do
sameout $T/zyms "small $(basename "$f" .zc)" "$f"
sameout $T/zys "small core $(basename "$f" .zc)" "$f"
done
# code literals can look like pointers on a compact map. test collection and
# the retained root without assuming the default map's exact reclaim count.
for vm in $T/zyms $T/zys; do
out=$(sed -E 's/f >= [0-9]+/f > 0/' tests/programs/gc.zc | $vm | tr '\n' '/')
chk "$out" "1000 1 900 1 199900/" "small collector makes progress and preserves its root"
done
$T/genmap --preset run -o $T/run || exit 1
$T/genmap --mode run --words 20480 -o $T/run-flags || exit 1
cmp -s $T/run/memmap.h $T/run-flags/memmap.h && cmp -s $T/run/rt.zc $T/run-flags/rt.zc \
&& cmp -s $T/run/map.txt $T/run-flags/map.txt \
&& chk 1 1 "run flags reproduce the growing run-only map" || chk 0 1 "run flags reproduce the growing run-only map"
}
s_runonly() {
T=$ROOT/runonly
python3 tests/drivers/runtime_image_test.py --host $T/zy --mkgenome $ROOT/mkg > $T/images.out 2>&1; r=$?
grep -v '^ok' $T/images.out
chk $r 0 "self-hosted run-only images install enhancements and preserve generic array methods"
# its own run map: the run-only image is built against this one, and the
# small-machine section lays out its own rather than sharing this
$T/genmap --preset run -o $T/run || exit 1
cp src/tools/zc0.c src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $T/run/
$CC -O1 -w -fwrapv $T/run/zc0.c -o $T/zc0r || exit 1
runonly() { # $1 label, $2 source. the program is already in the image, so it reads no source.
# the map is sized to the program: src/tools/automap.sh lays it out for the image's own length
local a b d=$T/run-$1 input=$2
if [ "$1" = gc ]; then input=$T/collector-progress.zc; sed -E 's/f >= [0-9]+/f > 0/' "$2" > "$input"; fi
GENMAP=$T/genmap bash src/tools/automap.sh run $d src/runtime/run.zc "$input" >/dev/null || { chk 0 1 "run $1 builds"; return; }
cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $d/
$CC -pthread -DZY_THREADS -O2 -w -fwrapv $d/micro.c $d/port_linux.c -o $T/zymr || { chk 0 1 "run $1 links"; return; }
a=$($T/zy < "$input" 2>&1 | sed "s#<stdin>#$input#g" | tr '\n' '/')
b=$($T/zymr </dev/null 2>&1 | tr '\n' '/')
chk "$b" "$a" "run $1"
}
runonly hello examples/hello.zc
runonly fact examples/fact.zc
runonly wide tests/programs/wide.zc
runonly selfpatch examples/selfpatch.zc
runonly gc tests/programs/gc.zc
runonly zc0unbounded tests/programs/zc0unbounded.zc # zc0 accepts unbounded in all three places and ignores it
runonly voidmain tests/programs/void_main.zc
runonly trace tests/programs/trace_run.zc # the image carries line tables: a fault and rt.trace() print the same backtrace as the resident compiler's
runonly float tests/programs/float.zc
runonly ftruth tests/programs/ftruth.zc
runonly ftext tests/programs/ftext.zc
runonly bytes tests/programs/bytes.zc
runonly strings tests/programs/strings.zc
runonly strings-ex examples/strings.zc
runonly share tests/programs/share.zc
runonly embed tests/programs/embed_top.zc
runonly zc0bstr tests/programs/zc0bstr.zc
runonly zc0umd tests/programs/zc0umd.zc
runonly wiring examples/wiring.zc
d=$T/run-echo; GENMAP=$T/genmap bash src/tools/automap.sh run $d src/runtime/run.zc examples/echo.zc >/dev/null && cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $d/ \
&& $CC -pthread -DZY_THREADS -O2 -w -fwrapv $d/micro.c $d/port_linux.c -o $T/zymr \
&& chk "$(printf 'abc\n' | $T/zymr | tr '\n' '/')" "$( (cat examples/echo.zc; printf '`abc\n') | $T/zy | tr '\n' '/')" "run echo" \
|| chk 0 1 "run echo"
# zcc: a program becomes a static binary that runs without stdin and with a held-open pipe
if src/tools/zcc -o $T/zcc-hello examples/hello.zc >/dev/null 2>&1; then
chk "$($T/zcc-hello < /dev/null)" "hello, world!" "zcc: hello, static"
chk "$(sleep 2 | timeout 5 $T/zcc-hello; echo $?)" "hello, world!
0" "zcc: a program that never reads stdin does not wait for it"
if [ "$(uname -s)" = Linux ]; then chk "$(file -b $T/zcc-hello | grep -c 'statically linked')" "1" "zcc: the binary is statically linked"; else echo "skip zcc static linkage (unavailable on this host)"; fi
else chk 0 1 "zcc builds examples/hello.zc"; fi
if src/tools/zcc -o $T/zcc-trace tests/programs/trace_run.zc >/dev/null 2>&1; then
chk "$($T/zcc-trace </dev/null 2>&1 | sed "s#$PWD/##g" | md5sum)" "$($T/zy < tests/programs/trace_run.zc 2>&1 | sed 's#<stdin>#tests/programs/trace_run.zc#g' | md5sum)" "zcc: a fault in a compiled program prints its backtrace"
else chk 0 1 "zcc builds tests/programs/trace_run.zc"; fi
printf 'fn main() {\n\tput_n(1\n\treturn 0;\n}\n' > $T/zcc-bad.zc
src/tools/zcc -o $T/zcc-bad $T/zcc-bad.zc </dev/null >/dev/null 2>&1; r=$?
chk "$r $( [ -e $T/zcc-bad ] && echo yes || echo no)" "1 no" "zcc: a bad program exits 1 and writes no binary"
$CC -ffreestanding -w -c $T/run-echo/micro.c -o $T/micro_r.o && $CC -ffreestanding -w -c $T/run-echo/port_stub.c -o $T/stub_r.o && chk 1 1 "run-only microcore compiles freestanding" || chk 0 1 "run-only microcore compiles freestanding"
}
s_bare() {
T=$ROOT/bare
bare() { # $1 target, $2 run|compile, $3 source, $4 label. compare UART stdout to the hosted interpreter.
local a b
a=$($T/zy < "$3" 2>&1 | tr '\n' '/')
b=$(bash src/baremetal/run.sh "$1" "$2" "$3" 2>/dev/null | tr '\n' '/')
chk "$b" "$a" "$4"
}
bareio() { # clock, RAM file, random, BOARD, MW, a long echo, and exit status
local mw
mw=$(GENMAP=$T/genmap bash src/tools/automap.sh run $T/run-bareio src/runtime/run.zc tests/programs/bareio.zc | sed -n 's/.*MW \([0-9]*\) .*/\1/p')
local t="$1" pay a b out st
pay=abcdefghijklmnopqrstuvwxyz0123456789
a=$( (cat examples/echo.zc; printf '`%s' "$pay") | $T/zy | tr -d '\n')
b=$(printf '%s' "$pay" | bash src/baremetal/run.sh "$t" io examples/echo.zc 2>/dev/null | tr -d '\n')
chk "$b" "$a" "bare $t echo until eof"
b=$(bash src/baremetal/run.sh "$t" run tests/programs/bareio.zc 2>/dev/null | tr -d '\n')
chk "$b" "tick 2 zy rand board $mw" "bare $t clock, files, random, memory"
out=$(bash src/baremetal/run.sh "$t" run tests/programs/bareexit.zc 2>/dev/null)
st=$?
chk "$(printf '%s' "$out" | tr -d '\n')" "bye" "bare $t exit status text"
chk "$st" "3" "bare $t exit status code"
}
if bash src/baremetal/run.sh ready riscv; then
bare riscv run examples/hello.zc "bare riscv hello"
bare riscv run examples/fact.zc "bare riscv fact"
bare riscv run tests/programs/wide.zc "bare riscv wide"
bare riscv run tests/programs/gc.zc "bare riscv gc"
bare riscv run tests/programs/float.zc "bare riscv float"
bare riscv run tests/programs/ftruth.zc "bare riscv negative zero"
bare riscv run tests/programs/ftext.zc "bare riscv float text"
bare riscv run tests/programs/bytes.zc "bare riscv bytes"
bare riscv run tests/programs/strings.zc "bare riscv strings"
bare riscv run tests/programs/share.zc "bare riscv share"
bare riscv compile tests/programs/float.zc "bare riscv compile float"
bare riscv compile tests/programs/ftruth.zc "bare riscv compile negative zero"
bare riscv compile tests/programs/ftype.zc "bare riscv compile float type"
bare riscv compile tests/programs/fo3.zc "bare riscv compile o3 floats"
bare riscv compile tests/programs/ftext.zc "bare riscv compile float text"
bare riscv compile tests/programs/bytes.zc "bare riscv compile bytes"
bare riscv compile tests/programs/strings.zc "bare riscv compile strings"
bare riscv compile tests/programs/share.zc "bare riscv compile share"
bare riscv compile examples/hello.zc "bare riscv compile hello"
bare riscv compile examples/fact.zc "bare riscv compile fact"
bare riscv compile tests/programs/wide.zc "bare riscv compile wide"
bareio riscv
else echo "skip baremetal riscv (no riscv64-linux-gnu-gcc or qemu-system-riscv64)"; fi
if bash src/baremetal/run.sh ready aarch64; then
bare aarch64 run examples/hello.zc "bare aarch64 hello"
bare aarch64 run examples/fact.zc "bare aarch64 fact"
bare aarch64 run tests/programs/wide.zc "bare aarch64 wide"
bare aarch64 run tests/programs/gc.zc "bare aarch64 gc"
bare aarch64 run tests/programs/float.zc "bare aarch64 float"
bare aarch64 run tests/programs/ftruth.zc "bare aarch64 negative zero"
bare aarch64 run tests/programs/ftext.zc "bare aarch64 float text"
bare aarch64 run tests/programs/bytes.zc "bare aarch64 bytes"
bare aarch64 run tests/programs/strings.zc "bare aarch64 strings"
bare aarch64 run tests/programs/share.zc "bare aarch64 share"
bare aarch64 compile tests/programs/float.zc "bare aarch64 compile float"
bare aarch64 compile tests/programs/ftruth.zc "bare aarch64 compile negative zero"
bare aarch64 compile tests/programs/ftype.zc "bare aarch64 compile float type"
bare aarch64 compile tests/programs/fo3.zc "bare aarch64 compile o3 floats"
bare aarch64 compile tests/programs/ftext.zc "bare aarch64 compile float text"
bare aarch64 compile tests/programs/bytes.zc "bare aarch64 compile bytes"
bare aarch64 compile tests/programs/strings.zc "bare aarch64 compile strings"
bare aarch64 compile tests/programs/share.zc "bare aarch64 compile share"
bare aarch64 compile examples/hello.zc "bare aarch64 compile hello"
bare aarch64 compile examples/fact.zc "bare aarch64 compile fact"
bare aarch64 compile tests/programs/wide.zc "bare aarch64 compile wide"
bareio aarch64
else echo "skip baremetal aarch64 (no aarch64-linux-gnu-gcc or qemu-system-aarch64)"; fi
}
s_jit() {
T=$ROOT/jit
if command -v aarch64-linux-gnu-gcc >/dev/null && command -v qemu-aarch64 >/dev/null; then
aarch64-linux-gnu-gcc -pthread -O2 -w -fwrapv -DJTYPE=int -static src/core/core.c src/core/io_linux.c $GI -o $T/zyj || exit 1
printf '#!/bin/sh\nexec qemu-aarch64 %s "$@"\n' $T/zyj > $T/jit; chmod +x $T/jit
run $T/jit "jit"
chk "$(ZYTRACE=1 $T/jit < tests/programs/o3.zc 2>&1 | grep -c 'bytes of arm64')" "8" "jit compiles every o3 region to arm64"
selfc $T/jit $T/gj.bin; cmp -s $T/g1.bin $T/gj.bin && chk 1 1 "jit self-compile matches" || chk 0 1 "jit self-compile matches"
# native calls need a dynamic binary (a static one has no dlsym), run against the aarch64 libc
if [ -d /usr/aarch64-linux-gnu/lib ] && aarch64-linux-gnu-gcc -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c $GI -o $T/zyjd -ldl 2>/dev/null; then
chk "$(qemu-aarch64 -L /usr/aarch64-linux-gnu $T/zyjd < tests/programs/cabi.zc | md5sum)" "$(md5sum < tests/programs/cabi.expected)" "jit native calls and callbacks (extern, cfunc)"
chk "$(qemu-aarch64 -L /usr/aarch64-linux-gnu $T/zyjd < tests/programs/cabi_o3.zc | md5sum)" "$(md5sum < tests/programs/cabi_o3.expected)" "jit native calls from o3 code, stack arguments"
chk "$(qemu-aarch64 -L /usr/aarch64-linux-gnu $T/zyjd < tests/programs/cabi_sized.zc | md5sum)" "$(md5sum < tests/programs/cabi_sized.expected)" "jit native calls with f32 and the sized integers"
# structs by value: the helper library has to be arm64, and cload reads build/sbv.so from the working directory
R=$(pwd); aarch64-linux-gnu-gcc -shared -fPIC -w tests/data/sbv.c -o $T/sbv_arm.so && mkdir -p $T/build && cp $T/sbv_arm.so $T/build/sbv.so
chk "$(cd $T && qemu-aarch64 -L /usr/aarch64-linux-gnu $T/zyjd < $R/tests/programs/structval.zc)" "34 3520 18 325 810 340" "jit structs by value to a c function (aapcs64: registers, hfa, reference, stack)"
chk "$(cd $T && qemu-aarch64 -L /usr/aarch64-linux-gnu $T/zyjd < $R/tests/programs/structret.zc)" "3 4 3.500000 4.000000 24 8 1.000000 3.500000" "jit structs returned from a c function (aapcs64 results)"
fi
else echo "skip jit (no aarch64 toolchain or qemu)"; fi
# the x86-64 jit against the interpreter, every program (about a minute; not in the quick path)
if [ "$(uname -s)-$(uname -m)" = Linux-x86_64 ] && [ $QUICK = 0 ]; then
$CC -pthread -O2 -w -fwrapv -DJTYPE=int -DZYINTERP src/core/core.c src/core/io_linux.c $GI -o $T/zyi || exit 1
$CC -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c $GI -o $T/zyx || exit 1
bash tests/drivers/jit_x64_test.sh $T/zyi $T/zyx > $T/jit_x64.out 2>&1; r=$?
grep '^DIFF' $T/jit_x64.out
chk $r 0 "x86-64 jit agrees with the interpreter: $(tail -n 1 $T/jit_x64.out)"
python3 tests/drivers/hold_test.py $T/zyx > $T/hold_x64.out 2>&1; r=$?
grep -v '^ok' $T/hold_x64.out
chk $r 0 "x86-64 jit hold blocks"
chk "$(ZYNOENH=1 $T/zyx < tests/programs/enh_ops.zc | md5sum)" "$(md5sum < tests/programs/enh_ops.expected)" "x86-64 jit with enhancements called through xrun (ZYNOENH=1)"
chk "$(ZYTRACE=1 $T/zyx < tests/programs/o3.zc 2>&1 | grep -c 'bytes of x86-64')" "7" "x86-64 jit compiles the o3 regions it can (one has too many live values)"
chk "$(ZYTRACE=1 $T/zyx < tests/programs/o3_freelist.zc 2>&1 | grep -c ' inline at ')" "11" "x86-64 jit inlines new_k and recycle_leaf in compiled o3 regions"
chk "$(ZYNOFASTALLOC=1 $T/zyx < tests/programs/o3_freelist.zc 2>&1)" "$($T/zyx < tests/programs/o3_freelist.zc 2>&1)" "x86-64 o3 inline allocation matches the plain calls (ZYNOFASTALLOC=1)"
for p in o3 o3copy o3licm o3push o3bytes fo3 o3call o3deep o3_freelist; do
chk "$($T/zyx < tests/programs/$p.zc 2>&1)" "$(ZYO3INTERP=1 $T/zyx < tests/programs/$p.zc 2>&1)" "x86-64 o3 code matches the region interpreter (ZYO3INTERP=1): $p"
done
fi
}
s_llvm() {
T=$ROOT/llvm
# llvm-config can exist without the headers and static libs (a runtime-only install), so the gate is a real build
llvm_ok=0
# LLVM_CONFIG picks the llvm build when the one on PATH has no headers (e.g. /usr/lib/llvm-20/bin/llvm-config)
local lc=${LLVM_CONFIG:-llvm-config}
if command -v $lc >/dev/null && $CC -pthread -O2 -w -fwrapv -DJTYPE=int -DZYLLVM $($lc --cflags) src/core/core.c src/core/io_linux.c $GI -o $T/zyl $($lc --ldflags --libs) 2>/dev/null; then llvm_ok=1; fi
if [ $llvm_ok = 1 ]; then
run $T/zyl "llvm"
chk "$(ZYTRACE=1 $T/zyl < tests/programs/o3.zc 2>&1 | grep -c 'compiled by llvm')" "8" "llvm compiles every o3 region"
python3 tests/drivers/hold_test.py $T/zyl > $T/hold.out 2>&1; r=$?
grep -v '^ok' $T/hold.out
chk $r 0 "llvm hold blocks"
printf '#!/bin/sh\nZYHOT=1 exec %s "$@"\n' $T/zyl > $T/llall; chmod +x $T/llall
chk "$($T/zyl < tests/programs/structval.zc)" "34 3520 18 325 810 340" "llvm structs by value (the call goes through the interpreter's native call)"
chk "$($T/zyl < tests/programs/structret.zc)" "3 4 3.500000 4.000000 24 8 1.000000 3.500000" "llvm structs returned from a c function"
chk "$($T/llall < tests/programs/types.zc | md5sum)" "$($T/zy < tests/programs/types.zc | md5sum)" "llvm compiling every block agrees"
chk "$($T/llall < tests/programs/float.zc)" "4.000000 4.500000 3.000000 2.500000 2.500000 0.001500 0.100000 -0.125000 inf -inf nan 1 1 1 0 0 3 -3 3.000000 -2.000000 2" "llvm compiling every block agrees on floats"
chk "$($T/llall < tests/programs/ftruth.zc)" "00111000110107" "llvm compiling every block agrees on negative zero"
chk "$($T/llall < tests/programs/ftype.zc)" "3.500000 10.500000 3.500000 4.250000 5.250000 4.250000 6.500000 2 4 4.250000 8.500000 1 4" "llvm compiling every block agrees on the float type"
chk "$($T/llall < tests/programs/fo3.zc)" "5997 5997 4.000000 nan 0 3.250000 1 0 0" "llvm compiling every block agrees on o3 floats"
chk "$($T/llall < tests/programs/ftext.zc)" "1e+308 1e-10 -0 inf -inf nan 0.1 1.50 1.250e+0 100000000000000000000.000000 1e+40 1111111111" "llvm compiling every block agrees on float text"
chk "$($T/llall < tests/programs/bytes.zc)" "17 34 43981 16909060 1 205 171 -3674937295934316015 1108152156331 0 0 30768
ABC" "llvm compiling every block agrees on bytes"
chk "$($T/llall < tests/programs/strings.zc)" "hi! 3 3 104 i! 1 1 1 -42 42 -42 11 1 -9223372036854775808 0 1 3 10 1 1 1 W ab" "llvm compiling every block agrees on strings"
chk "$($T/llall < tests/programs/share.zc)" "1 2 1 4 1 1 1 1 42 1 1 1 6 0" "llvm compiling every block agrees on shared cells"
chk "$($T/zyl < tests/programs/cabi.zc | md5sum)" "$(md5sum < tests/programs/cabi.expected)" "llvm native calls and callbacks (extern, cfunc)"
chk "$($T/llall < tests/programs/cabi.zc | md5sum)" "$(md5sum < tests/programs/cabi.expected)" "llvm compiling every block agrees on native calls"
chk "$($T/zyl < tests/programs/cabi_o3.zc | md5sum)" "$(md5sum < tests/programs/cabi_o3.expected)" "llvm calls natives from o3 regions directly"
chk "$(ZYTRACE=1 $T/zyl < tests/programs/cabi_o3.zc 2>&1 | grep -c 'compiled by llvm')" "2" "llvm compiles the o3 regions that call natives"
chk "$($T/llall < tests/programs/cabi_o3.zc | md5sum)" "$(md5sum < tests/programs/cabi_o3.expected)" "llvm compiling every block agrees on o3 native calls"
chk "$($T/zyl < tests/programs/cabi_sized.zc | md5sum)" "$(md5sum < tests/programs/cabi_sized.expected)" "llvm native calls with f32 and the sized integers"
chk "$($T/llall < tests/programs/sized.zc | md5sum)" "$(md5sum < tests/programs/sized.expected)" "llvm compiling every block agrees on sized integers"
chk "$($T/llall < tests/programs/bitops.zc | md5sum)" "$(md5sum < tests/programs/bitops.expected)" "llvm compiling every block agrees on the new micro-ops"
chk "$($T/llall < tests/programs/f32.zc | md5sum)" "$(md5sum < tests/programs/f32.expected)" "llvm compiling every block agrees on f32"
chk "$($T/llall < tests/programs/sizedvec.zc | md5sum)" "$(md5sum < tests/programs/sizedvec.expected)" "llvm compiling every block agrees on growable sized arrays"
chk "$($T/llall < tests/programs/packedfields.zc | md5sum)" "$(md5sum < tests/programs/packedfields.expected)" "llvm compiling every block agrees on packed fields"
chk "$($T/llall < tests/programs/generics.zc | md5sum)" "$(md5sum < tests/programs/generics.expected)" "llvm compiling every block agrees on generic instances"
chk "$($T/llall < tests/programs/genmeth.zc | md5sum)" "$(md5sum < tests/programs/genmeth.expected)" "llvm compiling every block agrees on generic struct methods"
chk "$($T/llall < tests/programs/o3push.zc | md5sum)" "$(md5sum < tests/programs/o3push.expected)" "llvm compiling every block agrees on inline push and pop"
selfc $T/zyl $T/gl.bin; cmp -s $T/g1.bin $T/gl.bin && chk 1 1 "llvm self-compile matches" || chk 0 1 "llvm self-compile matches"
else echo "skip llvm (no llvm-config, or its headers and libraries are missing)"; fi
}
s_lsp() {
T=$ROOT/lsp
# the language server: the compiler itself in check mode, so these are the real compiler's findings
if bash src/tools/mklsp.sh $T/lsp >/dev/null 2>&1; then
lsp=$T/lsp/zclsp
chk "$($lsp < examples/hello.zc)" "no errors" "lsp: a clean program"
chk "$($lsp < tests/errors/back_to_m.zc | head -1 | cut -d' ' -f2-)" "error: $(grep -m1 '^// expect: ' tests/errors/back_to_m.zc | sed 's#^// expect: ##')" "lsp: the compiler's own message"
h=$($lsp < examples/opt_test.zc)
for w in "is never read" "is never reassigned; make it a const" "is a shift; write << 3" "unannotated numeric literal 1234" "new inside a loop" "stack buffer"; do
case "$h" in *"$w"*) chk 1 1 "lsp hint: $w";; *) chk 0 1 "lsp hint: $w";; esac
done
chk "$($lsp < examples/struct_closure_opt.zc | grep -c error)" "0" "lsp: methods and closures check clean"
case "$($lsp < tests/data/drop_hint.zc)" in *"value with drop is never bound; it drops at the end of this statement"*) chk 1 1 "lsp hint: a value with drop that is never bound";; *) chk 0 1 "lsp hint: a value with drop that is never bound";; esac
case "$($lsp < tests/data/reassign_hint.zc)" in *"p: reassigning frees the old value"*) chk 1 1 "lsp hint: reassigning an owner frees the old value";; *) chk 0 1 "lsp hint: reassigning an owner frees the old value";; esac
case "$($lsp < tests/data/spawn_hint.zc)" in *"r: has drop and is live at spawn; the worker's copy drops it too"*) chk 1 1 "lsp hint: a value with drop live at spawn";; *) chk 0 1 "lsp hint: a value with drop live at spawn";; esac
# a file of a larger build checks on its own: its bodyless declarations are not errors in check mode
for f in src/runtime/rt.zc src/runtime/run.zc src/lsp/server.zc; do chk "$($lsp < $f | grep -c ': error:')" "0" "lsp: $f checks alone"; done
# the compiler is several files that only make sense together: check them as one document
chk "$(cat $(ccparts) | $lsp | grep -c ': error:')" "0" "lsp: the compiler (src/compiler/parts) checks alone"
chk "$($lsp < tests/programs/decl_undefined.zc)" "no errors" "lsp: a bodyless declaration is not an error in check mode"
chk "$($lsp < tests/programs/undefined_call.zc | grep -c ': error:')" "1" "lsp: a call to a name nothing defines is still an error"
chk "$($lsp --annotate < tests/programs/annotate.zc | md5sum)" "$(md5sum < tests/programs/annotate.expected)" "lsp --annotate writes the types the compiler can see into a program"
chk "$($lsp --annotate < tests/programs/annotate.zc | $T/zy)" "$($T/zy < tests/programs/annotate.zc)" "an annotated program means what the original did"
chk "$($lsp --types < tests/programs/annotate.zc | head -3 | tr '\n' '/')" "9:1 3 int/10:1 3 char*/11:1 3 int/" "lsp --types lists the edits without making them"
chk "$($lsp --annotate < tests/programs/annotate.expected | md5sum)" "$(md5sum < tests/programs/annotate.expected)" "annotating an annotated program changes nothing more"
printf 'Content-Length: 40\r\n\r\n{"jsonrpc": [2.0", "method": "x"}' | timeout 10 $lsp > /dev/null 2>&1; chk $? 0 "lsp: a stray brace in an array ends the message, and the server exits"
if [ $QUICK = 1 ]; then echo "skip lsp protocol and corpus tests (quick)"
elif command -v node >/dev/null; then
node tests/drivers/fuzz_lsp.js $lsp > $T/fuzzlsp.out 2>&1; r=$?
grep -v '^ok' $T/fuzzlsp.out
chk $r 0 "lsp fuzz: malformed recovery, long-session churn and cache invalidation"
node tests/drivers/storage_analysis_test.js $lsp > $T/storage.out 2>&1; r=$?
grep -v '^ok' $T/storage.out
chk $r 0 "lsp: definite storage warnings and reference lifetime hovers"
node tests/drivers/hints_test.js $lsp > $T/hints.out 2>&1; r=$?
grep -v '^ok' $T/hints.out
chk $r 0 "lsp: hints are information diagnostics and obey hints on, small and off"
node tests/drivers/stream_test.js $lsp > $T/stream.out 2>&1; r=$?
grep -v '^ok' $T/stream.out
chk $r 0 "lsp: large checks stream and a stale check is dropped"
node tests/drivers/format_test.js $lsp > $T/format.out 2>&1; r=$?
grep -v '^ok' $T/format.out
chk $r 0 "lsp: the formatter keeps tokens, is stable and follows its options"
node tests/drivers/include_test.js $lsp > $T/include.out 2>&1; r=$?
grep -v '^ok' $T/include.out
chk $r 0 "lsp: relative includes, string diagnostics and explicit std"
for group in quickfix modulehover namespacecompletion navigation inference qualifiers; do
CONTRACT_GROUP=$group node tests/drivers/toolchain_lsp_contract_test.js $lsp > $T/contracts-$group.out 2>&1; r=$?
grep -v '^ok' $T/contracts-$group.out
chk $r 0 "lsp: $group contracts"
done
node tests/drivers/hint_fixes_test.js $lsp > $T/hintfixes.out 2>&1; r=$?
grep -v '^ok' $T/hintfixes.out
chk $r 0 "lsp: hint and import quick fixes keep the program's meaning"
node tests/drivers/codeactions_client_test.js > $T/codeactions-client.out 2>&1; r=$?
grep -v '^ok' $T/codeactions-client.out
chk $r 0 "lsp: versioned import quick-fix edits"
node tests/drivers/hold_lsp_test.js $lsp > $T/holdlsp.out 2>&1; r=$?
cat $T/holdlsp.out | grep -v passed
chk $r 0 "lsp hold blocks: hover, completion and diagnostics"
node tests/drivers/completion_test.js $lsp > $T/completion.out 2>&1; r=$?
grep -v '^ok' $T/completion.out
chk $r 0 "lsp: fuzzy completions, signatures, scope and expired lifetimes"
$CC -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c $GI -o $T/zy
ZY=$T/zy node tests/drivers/borrow_diag_test.js $lsp > $T/borrowdiag.out 2>&1; r=$?
grep -v '^ok' $T/borrowdiag.out
chk $r 0 "lsp: borrow errors are zy's own messages, with the use's range and the owner as related information"
node tests/drivers/analysis_cache_test.js $lsp > $T/analysiscache.out 2>&1; r=$?
grep -v '^ok' $T/analysiscache.out
chk $r 0 "lsp: analysis cache reuse and invalidation"
node tests/drivers/hover_surface_test.js $lsp > $T/hoversurface.out 2>&1; r=$?
grep -v '^ok' $T/hoversurface.out
chk $r 0 "lsp: embedded declarations, constant values, asm and std hovers"
node tests/drivers/nav_test.js $lsp > $T/nav.out 2>&1; r=$?
grep -v '^ok' $T/nav.out
chk $r 0 "lsp: definition and references across includes"
node tests/drivers/lsp_test.js $lsp > $T/lsp.out 2>&1; r=$?
grep -v '^ok' $T/lsp.out
chk $r 0 "lsp: protocol and corpus tests ($(grep -c '^ok' $T/lsp.out) checks)"
node tests/drivers/lsp_live.js $lsp > $T/lsplive.out 2>&1; r=$?
grep -v '^ok' $T/lsplive.out
chk $r 0 "lsp: the native server answers while the client keeps the pipe open"
node tests/drivers/lsp_sandbox.js $lsp > $T/lspsb.out 2>&1; r=$?
grep -v '^ok' $T/lspsb.out
chk $r 0 "lsp: compile-time code in a checked file cannot write files"
bash src/tools/xref_selftest.sh $lsp > $T/xref.out 2>&1; r=$?
grep -v '^ok' $T/xref.out
chk $r 0 "xref: --check passes on tests/xref.baseline and fails on a missing writer"
# the diagnostics cache: its key rules, then the extension's client end to end on the built-in server
node tests/drivers/diagcache_test.js > $T/dcache.out 2>&1; r=$?
grep -v '^ok' $T/dcache.out
chk $r 0 "lsp: the diagnostics cache keys and store ($(grep -c '^ok' $T/dcache.out) checks)"
# the same server as WebAssembly, through the extension's host (needs clang)
if sh src/tools/findcc.sh --wasm >/dev/null 2>&1 && LSP_BUILD_DIR=$T/lsp LSP_REUSE_BUILD=1 bash src/tools/mklspwasm.sh $T/lsp/lsp.wasm >/dev/null 2>&1; then
node tests/drivers/hover_surface_test.js --wasm $T/lsp/lsp.wasm > $T/hoversurfacewasm.out 2>&1; r=$?
grep -v '^ok' $T/hoversurfacewasm.out
chk $r 0 "lsp: embedded and asm hovers through the wasm host"
node tests/drivers/completion_test.js --wasm $T/lsp/lsp.wasm > $T/completionwasm.out 2>&1; r=$?
grep -v '^ok' $T/completionwasm.out
chk $r 0 "lsp: completions through the wasm host"
node tests/drivers/lsp_wasm.js $T/lsp/lsp.wasm > $T/lspw.out 2>&1; r=$?
grep -v '^ok' $T/lspw.out
chk $r 0 "lsp: wasm server through the extension's host ($(grep -c '^ok' $T/lspw.out) checks)"
else echo "skip lsp wasm tests (no clang with wasm32)"; fi
# the same server run by the javascript vm, the extension's fallback when wasm is not there.
# the vm starts at the image's heap and grows on the heap's request, so a long document is the test
node src/js/extract_lsp.js --lsp $T/lsp --out $T/vmserver >/dev/null && node src/js/mklayout.js --map $MAP/memmap.h --out $T/vmserver >/dev/null \
&& tsc src/js/tinyvm.ts --target es2020 --lib es2020,dom --module commonjs --outDir $T/vmserver
node tests/drivers/hover_surface_test.js --vm $T/vmserver > $T/hoversurfacevm.out 2>&1; r=$?
grep -v '^ok' $T/hoversurfacevm.out
chk $r 0 "lsp: embedded and asm hovers through the javascript host"
node tests/drivers/completion_test.js --vm $T/vmserver > $T/completionvm.out 2>&1; r=$?
grep -v '^ok' $T/completionvm.out
chk $r 0 "lsp: completions through the javascript host"
node tests/drivers/lsp_vm.js $T/vmserver > $T/lspvm.out 2>&1; r=$?
grep -v '^ok' $T/lspvm.out
chk $r 0 "lsp: the server in the javascript vm, through the extension's host ($(grep -c '^ok' $T/lspvm.out) checks)"
if [ -f $T/lsp/lsp.wasm ]; then
node tests/drivers/stream_host_test.js $T/lsp/lsp.wasm $T/vmserver > $T/streamhost.out 2>&1; r=$?
grep -v '^ok' $T/streamhost.out
chk $r 0 "lsp: the wasm and vm servers stream and drop stale checks"
fi
# the extension's client end to end, with the server files the package would carry
mkdir -p $T/extserver && cp $T/vmserver/tinyvm.js $T/vmserver/layout.js $T/vmserver/lsp.json $T/vmserver/lsp.bin $T/extserver/
[ -f $T/lsp/lsp.wasm ] && cp $T/lsp/lsp.wasm $T/extserver/
node tests/drivers/ext_cache_test.js $T/extserver > $T/ecache.out 2>&1; r=$?
grep -v '^ok' $T/ecache.out
chk $r 0 "lsp: the extension's cache, end to end ($(grep -c '^ok' $T/ecache.out) checks)"
else echo "skip lsp protocol tests (no node)"; fi
else chk 0 1 "lsp server builds"; fi
}
s_js() {
T=$ROOT/js
# the javascript vm, and the microcore as webassembly. both run the same genome
if command -v node >/dev/null && command -v tsc >/dev/null; then
# the vm as make js builds it, with the fixpoint genome beside it
node src/js/mklayout.js --map $MAP/memmap.h --out $T/jsvm >/dev/null && cp $ROOT/s1/genome.bin $T/jsvm/genome.bin \
&& tsc src/js/tinyvm.ts --target es2020 --lib es2020,dom --module commonjs --outDir $T/jsvm || chk 0 1 "js vm builds"
chk "$(node $T/jsvm/tinyvm.js examples/hello.zc)" "hello, world!" "js vm: hello"
chk "$(node $T/jsvm/tinyvm.js examples/fact.zc | tail -1)" "3628800" "js vm: factorial"
chk "$(node $T/jsvm/tinyvm.js examples/primes.zc | tail -1)" "widest gap: 72, after 31397" "js vm: primes"
chk "$(node $T/jsvm/tinyvm.js tests/programs/growone.zc)" "12 1" "js vm: a block past the initial heap grows the machine"
chk "$(node $T/jsvm/tinyvm.js tests/programs/trace.zc 2>&1 | md5sum)" "$(md5sum < tests/programs/trace.expected)" "js vm: backtraces read the return stack through gate op 56"
chk "$(node $T/jsvm/tinyvm.js tests/programs/replace_owner.zc)" "$(cat tests/programs/replace_owner.expected)" "js vm: replacement ownership and cleanup"
chk "$(node $T/jsvm/tinyvm.js tests/programs/embed.zc | tr '\n' '/')" "hello/world 11 42 5 255 8 -1 0 119 15 5 255 3 98 321 63/" "js vm: embed declarations read their files through node"
if sh src/tools/findcc.sh --wasm >/dev/null 2>&1 && command -v wasm-ld >/dev/null; then
GENOME_DIR=$ROOT/s1 MAP_DIR=$MAP bash src/web/build.sh $T/zc.wasm >/dev/null && node tests/drivers/wasm_test.js $T/zc.wasm > $T/wasm.out 2>&1; r=$?
grep -v '^ok' $T/wasm.out
chk $r 0 "wasm: the microcore in webassembly ($(grep -c '^ok' $T/wasm.out) checks)"
node tests/drivers/fuzz_wasm.js $T/zc.wasm > $T/fuzzw.out 2>&1; r=$?
grep -v '^ok' $T/fuzzw.out
chk $r 0 "wasm: compiler/runtime/stdlib differential fuzz"
else echo "skip wasm (no clang with the wasm32 target and #embed, or no wasm-ld)"; fi
else echo "skip js and wasm (no node or tsc)"; fi
}
s_make() {
T=$ROOT/make
# the makefile builds the programs and the run-only image tool
if command -v make >/dev/null; then
# from an empty build directory, as a fresh checkout would be
make -s B=$T/mbuild all >/dev/null 2>&1 && chk "$($T/mbuild/bin/zy < examples/hello.zc)" "hello, world!" "make: build/bin/zy runs a program" || chk 0 1 "make: all builds"
python3 tests/drivers/cli_help_test.py --group binaries --bin-dir $T/mbuild/bin > $T/help.out 2>&1; r=$?
grep -v '^ok' $T/help.out
chk $r 0 "command-line help, invalid options and existing lsp source modes"
python3 tests/drivers/cli_help_test.py --group scripts > $T/scripthelp.out 2>&1; r=$?
grep -v '^ok' $T/scripthelp.out
chk $r 0 "build-script help exits without reading input or starting a build"
make -s B=$T/mbuild run PROG=examples/hello.zc >/dev/null 2>&1 && chk "$($T/mbuild/run/zymr </dev/null)" "hello, world!" "make: run PROG= builds a run-only image" || chk 0 1 "make: run builds"
else echo "skip make (not installed)"; fi
}
# docs/LEARN.md: every example it shows runs and prints what the guide says, and
# every block in it is one of those examples (tests/drivers/learn.py)
s_learn() {
T=$ROOT/learn
$CC -pthread -O2 -w -fwrapv -DJTYPE=int src/core/core.c src/core/io_linux.c $GI -o $T/zy
# learn.py prints its own ok and FAIL lines, which the tally below counts
python3 tests/drivers/learn.py $T/zy; true
}
# ---- run the sections ----
# each section runs in its own subshell with its own counters and its own log,
# so several can share the machine. the logs are printed afterwards in the
# order below, which is the order the checks used to run in.
pids=(); names=()
reap(){
local p=${pids[0]} n=${names[0]} st
wait "$p"; st=$?
[ "$st" = 0 ] || echo "FAIL $n: the section exited with status $st" >> $T/log.$n
pids=("${pids[@]:1}"); names=("${names[@]:1}")
}
sec(){ # $1 = the name the section reports under, $2 = the function to run
local n=$1
"$2" > $T/log.$n 2>&1 &
pids+=($!); names+=("$n")
[ ${#pids[@]} -ge $JOBS ] && reap
return 0
}
# the bootstrap's own checks stay counted; the sections are tallied from their
# logs below, so a section that dies half way still reports what it got through.
b_ok=$ok; b_bad=$bad; ok=0; bad=0
for n in $SECS; do sec $n s_$n; done
while [ ${#pids[@]} -gt 0 ]; do reap; done
for n in $SECS; do
cat $T/log.$n
ok=$((ok + $(grep -c '^ok ' $T/log.$n)))
bad=$((bad + $(grep -c '^FAIL' $T/log.$n)))
done
ok=$((ok + b_ok)); bad=$((bad + b_bad))
echo "$ok passed, $bad failed"; [ $bad = 0 ]
|