do not edit — generated by btf.
git.druid.rocksindexdruid520nscctest/run.sh

test/run.sh


#!/bin/sh
# nscc test suite: compile each tNN.nsc, link, run, and check the exit
# code against the expected value; the neg cases instead check that a
# deliberately broken program fails to compile, with the given message
# fragment in its err:. t12 and t23 pair translation units (and t23
# shares a global across files) to prove extern-style linking works.
# run with -j to keep intermediates for eyeballing; the default run
# cleans up after itself. needs a built tree first (sh mk/b.sh).
set -e
d=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
NSCC="${NSCC:-$d/../out/nscc}"
cd "$d"
 
[ -x "$NSCC" ] || { echo "err: no $NSCC, run sh mk/b.sh first." >&2; exit 1; }
 
jflag=
[ "${1:-}" = "-j" ] && jflag=-j
 
fails=0
checks=0
 
run_case() {
	# $1 = expected exit, rest = the .nsc files to link together.
	expect=$1
	shift
	checks=$((checks + 1))
	name=$(basename "$1" .nsc)
	objs=
	for src in "$@"; do
		base=$(basename "$src" .nsc)
		"$NSCC" $jflag -o "$base.s" "$src"
		gcc -no-pie -c "$base.s" -o "$base.o"
		objs="$objs $base.o"
		[ -n "$jflag" ] || rm -f "$base.s"
	done
	gcc -no-pie $objs -o "$name.bin"
	[ -n "$jflag" ] || rm -f $objs
	set +e
	"./$name.bin"
	got=$?
	set -e
	if [ "$got" = "$expect" ]; then
		echo "ok: $name (exit $got)"
	else
		echo "fail: $name: expected exit $expect, got $got"
		fails=$((fails + 1))
	fi
	[ -n "$jflag" ] || rm -f "$name.bin"
}
 
run_standalone() {
	# $1 = expected exit, $2 = source: compiled with -s and linked
	# freestanding (no crt1, no libc -- our own _start does the
	# exit syscall), proving the -s output stands alone.
	expect=$1
	src=$2
	checks=$((checks + 1))
	name=$(basename "$src" .nsc)
	"$NSCC" -s -o "$name.s" "$src"
	gcc -no-pie -nostdlib -nostartfiles "$name.s" -o "$name.bin"
	[ -n "$jflag" ] || rm -f "$name.s"
	set +e
	"./$name.bin"
	got=$?
	set -e
	if [ "$got" = "$expect" ]; then
		echo "ok: $name (exit $got)"
	else
		echo "fail: $name: expected exit $expect, got $got"
		fails=$((fails + 1))
	fi
	[ -n "$jflag" ] || rm -f "$name.bin"
}
 
run_neg() {
	# $1 = case name, $2 = expected message fragment, $3 = source.
	# reported like the positive cases -- exit code, not the err
	# text itself (a passing run's log should never look like it
	# contains errors; the expected fragment is still checked).
	name=$1
	frag=$2
	src=$3
	checks=$((checks + 1))
	echo "$src" > "/tmp/nscc-neg-$name.nsc"
	set +e
	"$NSCC" -o "/tmp/nscc-neg-$name.s" "/tmp/nscc-neg-$name.nsc" 2> "/tmp/nscc-neg-$name.err"
	rc=$?
	set -e
	if [ $rc -eq 0 ]; then
		echo "fail: $name: expected a compile error, got none"
		fails=$((fails + 1))
	elif grep -q "$frag" "/tmp/nscc-neg-$name.err"; then
		echo "ok: $name (exit $rc)"
	else
		echo "fail: $name: exit $rc but the error did not mention '$frag':"
		head -1 "/tmp/nscc-neg-$name.err"
		fails=$((fails + 1))
	fi
	rm -f "/tmp/nscc-neg-$name.nsc" "/tmp/nscc-neg-$name.s" "/tmp/nscc-neg-$name.err"
}
 
run_case 42 t01_ret42.nsc
run_case 55 t02_sum.nsc
run_case 60 t03_ops.nsc
run_case 55 t04_calls.nsc
run_case 7  t05_ptr.nsc
run_case 20 t06_switch.nsc
run_case 108 t07_cast.nsc
run_case 17 t08_tern.nsc
run_case 14 t09_incdec.nsc
run_case 41 t10_glob.nsc
run_case 44 t11_str.nsc
run_case 42 t12_main.nsc t12_helper.nsc
run_case 12 t13_break.nsc
run_case 2  t14_misc.nsc
run_case 5  t15_rec.nsc
run_case 5  t16_strecho.nsc
run_case 42 t17_ptrs.nsc
run_case 24 t18_gcd.nsc
run_case 16 t19_bits.nsc
run_case 30 t20_nested.nsc
run_case 33 t21_i64.nsc
run_case 215 t22_chars.nsc
run_case 53 t23_main.nsc t23_bump.nsc
run_case 89 t24_prec.nsc
run_case 64 t25_edge.nsc
run_case 40 t26_deep.nsc
run_case 5  t27_void.nsc
run_case 4  t28_incmix.nsc
run_case 4  t29_short.nsc
run_case 1  t30_addr.nsc
run_case 33 t31_condstmt.nsc
run_case 62 t32_collatz.nsc
run_case 1  t36_typedef.nsc
run_case 11 t37_enum.nsc
run_case 19 t38_unsigned.nsc
run_case 13 t39_struct.nsc
run_case 33 t40_structfn.nsc
run_case 7  t41_arrow.nsc
run_case 96 t42_array.nsc
run_case 6  t43_const.nsc
run_case 16 t44_structglobal.nsc
run_case 15 t45_signcast.nsc
run_case 19 t46_garray.nsc
run_case 21 t47_i8buf.nsc
run_case 3 t48_uninitglobal.nsc
run_case 42 t49_bighex.nsc
run_case 42 t50_include_main.nsc t50_include_impl.nsc
run_case 3 t51_gvar_linkage_upgrade.nsc
run_case 3 t52_while_shortcircuit.nsc
run_case 56 t53_funcptr.nsc
run_standalone 13 t33_standalone.nsc
run_case 27 t34_sizeof.nsc
run_case 13 t35_strdedup.nsc
 
# determinism: the pipeline is a pure function of its input -- two
# runs of the same compile are byte-identical, with and without -s.
checks=$((checks + 1))
"$NSCC" -o /tmp/nscc-a.s t01_ret42.nsc
"$NSCC" -o /tmp/nscc-b.s t01_ret42.nsc
NSCC_OS=NetBSD NSCC_OSVER=10.99.12 "$NSCC" -s -o /tmp/nscc-a2.s t33_standalone.nsc
NSCC_OS=NetBSD NSCC_OSVER=10.99.12 "$NSCC" -s -o /tmp/nscc-b2.s t33_standalone.nsc
if cmp -s /tmp/nscc-a.s /tmp/nscc-b.s && cmp -s /tmp/nscc-a2.s /tmp/nscc-b2.s; then
	echo "ok: deterministic (A/B outputs byte-identical)"
else
	echo "fail: deterministic: A/B outputs differ"
	fails=$((fails + 1))
fi
rm -f /tmp/nscc-a.s /tmp/nscc-b.s /tmp/nscc-a2.s /tmp/nscc-b2.s
 
# -s platform behavior: the _start exit syscall number matches the
# detected os, and netbsd gets the .note.netbsd.ident section with
# the version encoded netbsd's way (10.99.12 -> 1099001200).
checks=$((checks + 1))
if NSCC_OS=Linux "$NSCC" -s -o /tmp/nscc-note.s t33_standalone.nsc \
	&& grep -q 'movl \$60, %eax' /tmp/nscc-note.s; then
	echo "ok: s_linux_start (exit syscall 60)"
else
	echo "fail: s_linux_start: no linux exit syscall 60 in -s output"
	fails=$((fails + 1))
fi
checks=$((checks + 1))
if NSCC_OS=NetBSD NSCC_OSVER=10.99.12 "$NSCC" -s -o /tmp/nscc-note.s t33_standalone.nsc \
	&& grep -q 'movl \$1, %eax' /tmp/nscc-note.s \
	&& grep -q '\.section .note.netbsd.ident' /tmp/nscc-note.s \
	&& grep -q '\.long 1099001200' /tmp/nscc-note.s; then
	echo "ok: s_netbsd_note (exit syscall 1, ident note 10.99.12)"
else
	echo "fail: s_netbsd_note: bad netbsd -s output"
	fails=$((fails + 1))
fi
rm -f /tmp/nscc-note.s
 
run_neg neg_undeclared "use of undeclared identifier 'nope'" 'global i32 main(void) { return nope; }'
run_neg neg_redef "redefinition of function 'main'" 'global i32 main(void) { return 1; }
global i32 main(void) { return 2; }'
run_neg neg_break "outside any loop or switch" 'global i32 main(void) { break; }'
run_neg neg_ptrmul "ptr may only be used" 'global i32 main(void) { i32 x = 1; ptr p = &x; return p * 2; }'
run_neg neg_voidret "bare 'return' in a non-void" 'i32 f(void) { return; }
global i32 main(void) { return f(); }'
run_neg neg_args "params exceed 6 words" 'global i32 f(i32 a, i32 b, i32 c, i32 d, i32 e, i32 f2, i32 g2) { return a; }
global i32 main(void) { return f(1,2,3,4,5,6,7); }'
run_neg neg_syntax "expected ';'" 'global i32 main(void) { return 1 '
run_neg neg_dupcase "duplicate case value 1" 'global i32 main(void) { switch (1) { case 1: return 1; case 1: return 2; } return 0; }'
run_neg neg_voidval "used as a value" 'void f(void) { }
global i32 main(void) { i32 x = f(); return x; }'
run_neg neg_exprstmt "expression statement must be" 'global i32 main(void) { 1 + 2; return 0; }'
run_neg neg_comment "unterminated comment" 'global i32 main(void) { /* nope'
run_neg neg_float "expected a field name" 'global i32 main(void) { return 1.5; }'
run_neg neg_emptyparams "empty parameter list" 'global i32 main() { return 1; }'
run_neg neg_voidmain "main must return i32" 'global void main(void) { }'
run_neg neg_localmain "main must be global" 'i32 main(void) { return 1; }'
run_neg neg_badmainsig "main must be i32 main(void)" 'global i32 main(i64 x) { return 1; }'
run_neg neg_ptrsets0 "implicit int-to-ptr" 'global i32 main(void) { ptr p = 0; return 1; }'
run_neg neg_i64litcast "i64 literal does not fit" 'global i32 main(void) { i32 x = (i32)5000000000; return x; }'
run_neg neg_shiftrange "shift count 64 is out of range" 'global i32 main(void) { return 1 << 64; }'
run_neg neg_divzero "division by zero" 'global i32 main(void) { return 1 / 0; }'
run_neg neg_intmin "traps for i32" 'global i32 main(void) { return (-2147483647 - 1) / -1; }'
run_neg neg_falloff "must end in a return" 'i32 f(void) { if (1) { return 1; } }
global i32 main(void) { return f(); }'
run_neg neg_doublescore "reserved (double underscore)" 'global i32 main(void) { i32 __x = 1; return __x; }'
run_neg neg_slashcomment "unexpected token '/'" 'global i32 main(void) { return 1; // nope }'
run_neg neg_reserved "spelled u8/u16/u32/u64" 'global i32 main(void) { unsigned x = 1; return x; }'
run_neg neg_voidvar "cannot have type void" 'global i32 main(void) { void x; return 1; }'
run_neg neg_sizeofvoid "cannot take sizeof void" 'global i32 main(void) { return (i32)sizeof(void); }'
run_neg neg_mixedsign "mixed signed/unsigned" 'global i32 main(void) { i32 x = 1; u32 y = 2; return x + y; }'
run_neg neg_constassign "assignment to a const" 'global i32 main(void) { const i32 c = 1; c = 2; return c; }'
run_neg neg_structeq "comparison of incompatible operands" 'struct p { i32 x; };
global i32 main(void) { struct p a; struct p b; a.x = 1; b.x = 2; return a == b; }'
run_neg neg_arridx "out of bounds" 'global i32 main(void) { i32 a[3]; a[5] = 1; return a[0]; }'
run_neg neg_structret "too big to return" 'struct big { i32 a; i32 b; i32 c; };
struct big f(void) { struct big r; r.a = 1; r.b = 2; r.c = 3; return r; }
global i32 main(void) { struct big r = f(); return r.a; }'
run_neg neg_initcount "3 elements, expected 2" 'struct p { i32 x; i32 y; };
global i32 main(void) { struct p a = { 1, 2, 3 }; return a.x; }'
run_neg neg_member "needs a struct operand" 'global i32 main(void) { i32 x = 1; return x.f; }'
run_neg neg_typedefdup "redefinition of type name" 'typedef i32 T;
typedef i32 T;
global i32 main(void) { T x = 1; return x; }'
run_neg neg_enumcycle "enumerator value cycle" 'enum E { A = B, B = A };
global i32 main(void) { return A; }'
run_neg neg_arrayval "struct or array value here" 'global i32 main(void) { i32 a[3]; a[0] = 1; return a; }'
run_neg neg_structscalar "arithmetic on non-int operands" 'struct p { i32 x; };
global i32 main(void) { struct p a; a.x = 1; return a + 1; }'
run_neg neg_voidmain2 "main must be i32 main(void)" 'global i32 main(i32 x) { return x; }'
run_neg neg_sigbind "implicit signed/unsigned conversion" 'global i32 main(void) { i8 x = 1; u8 y = x; return (i32)y; }'
run_neg neg_sigcmp2 "mixed signed/unsigned compound assign" 'global i32 main(void) { u8 x = 1; i8 y = 2; x += y; return (i32)x; }'
run_neg neg_arrparam "array parameters are not allowed" 'i32 f(i32 a[3]) { return a[0]; }
global i32 main(void) { return f((i32)0); }'
run_neg neg_constfield "const struct fields are not supported" 'struct p { const i32 x; };
global i32 main(void) { return 1; }'
run_neg neg_structarr "array elements must be scalar" 'struct p { i32 x; };
global i32 main(void) { struct p a[2]; return a[0].x; }'
run_neg neg_icallint "call through a non-ptr expression" 'global i32 main(void) { i32 f = 1; return (i32)f(2); }'
run_neg neg_icallderef "call through a non-ptr expression (got i64)" 'i32 one(void) { return 1; }
global i32 main(void) { ptr fp = &one; return (i32)(*fp)(); }'
run_neg neg_funcvalue "is a function, not a value" 'i32 one(void) { return 1; }
global i32 main(void) { ptr fp = one; return (i32)fp(); }'
run_neg neg_icallstruct "args must be scalars" 'struct p { i32 x; };
i32 one(struct p a) { return a.x; }
global i32 main(void) { struct p a; a.x = 1; ptr fp = &one; return (i32)fp(a); }'
 
# the no-gnu-extensions claim, held honest: every generated .s must
# also assemble with bare as (no gcc involvement at all).
for src in t*.nsc; do
	base=$(basename "$src" .nsc)
	"$NSCC" -o "/tmp/nscc-as.s" "$src"
	if as "/tmp/nscc-as.s" -o "/tmp/nscc-as.o" 2> "/tmp/nscc-as.err"; then
		checks=$((checks + 1))
		echo "ok: as_$base (bare as)"
	else
		checks=$((checks + 1))
		echo "fail: as_$base: $(head -1 "/tmp/nscc-as.err")"
		fails=$((fails + 1))
	fi
	rm -f "/tmp/nscc-as.s" "/tmp/nscc-as.o" "/tmp/nscc-as.err"
done
 
echo
echo "$checks tests, $fails failed"
exit $((fails > 0))
powered by btf.