## xstack expression evaluator tests ## Covers every eframe state in eval_expression0_xstack: ## HAWK_EF_BIN_LEFT/RIGHT - binary operators ## HAWK_EF_LAND_LEFT/RIGHT - logical && with short-circuit ## HAWK_EF_LOR_LEFT/RIGHT - logical || with short-circuit ## HAWK_EF_UNARY - unary operators ## HAWK_EF_CND - ternary conditional ## HAWK_EF_ASS_RHS - simple assignment ## HAWK_EF_ASS_LHS - compound assignment (read-modify-write) @pragma entry main @pragma implicit off @include "tap.inc"; ## ----------------------------------------------------------------------- ## binary arithmetic operators ## ----------------------------------------------------------------------- function test_binary_arith( x) { tap_ensure(2 + 3, 5, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(10 - 4, 6, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(3 * 7, 21, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(15 / 4, 3.75, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(17 % 5, 2, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(2 ^ 10, 1024, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(17 \ 5, 3, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(-17 \ 5, -3, @SCRIPTNAME, @SCRIPTLINE); ## string concatenation (binary) tap_ensure("hello" " " "world", "hello world", @SCRIPTNAME, @SCRIPTLINE); tap_ensure("a" "b" "c", "abc", @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## binary comparison operators ## ----------------------------------------------------------------------- function test_binary_cmp() { tap_ensure((3 < 5), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((5 < 3), 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((3 <= 3), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((4 <= 3), 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((5 > 3), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((3 > 5), 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((3 >= 3), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((2 >= 3), 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((3 == 3), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((3 == 4), 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((3 != 4), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((3 != 3), 0, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## bitwise binary operators ## ----------------------------------------------------------------------- function test_binary_bitwise() { tap_ensure((0xF0 & 0xFF), 240, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((0x0F & 0xFF), 15, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((0xF0 | 0x0F), 255, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((0xFF ^^ 0x0F), 240, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((1 << 4), 16, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((256 >> 3), 32, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((0 << 10), 0, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## deeply chained binary expressions (stress eframe stack growth) ## The eframe stack starts at 0 and grows 64 at a time; these chains ## push many BIN_LEFT frames before resolving any BIN_RIGHT frames. ## ----------------------------------------------------------------------- function test_binary_chain( x) { ## left-associative chain (parser produces left-leaning tree) x = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10; tap_ensure(x, 55, @SCRIPTNAME, @SCRIPTLINE); x = 1 * 2 * 3 * 4 * 5; tap_ensure(x, 120, @SCRIPTNAME, @SCRIPTLINE); ## deeply parenthesised right-associative nesting x = (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + 10))))))))); tap_ensure(x, 55, @SCRIPTNAME, @SCRIPTLINE); ## mix of operators x = 2 * 3 + 4 * 5 - 6 / 2; tap_ensure(x, 23, @SCRIPTNAME, @SCRIPTLINE); ## 20-term sum (forces eframe realloc path) x = 1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20; tap_ensure(x, 210, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## logical AND -- HAWK_EF_LAND_LEFT / HAWK_EF_LAND_RIGHT ## ----------------------------------------------------------------------- function test_logical_and( r, se) { ## short-circuit: right never evaluated when left is false se = 0; r = 0 && (se = 1); tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(se, 0, @SCRIPTNAME, @SCRIPTLINE); ## right NOT evaluated ## both sides evaluated when left is true se = 0; r = 1 && (se = 99); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(se, 99, @SCRIPTNAME, @SCRIPTLINE); ## right WAS evaluated ## false right side r = 1 && 0; tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); ## chained AND r = 1 && 1 && 1; tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); r = 1 && 1 && 0; tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); ## AND with complex subexpressions r = (2 + 3 == 5) && (10 / 2 == 5); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); r = (2 + 3 == 5) && (10 / 2 == 4); tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## logical OR -- HAWK_EF_LOR_LEFT / HAWK_EF_LOR_RIGHT ## ----------------------------------------------------------------------- function test_logical_or( r, se) { ## short-circuit: right never evaluated when left is true se = 0; r = 1 || (se = 1); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(se, 0, @SCRIPTNAME, @SCRIPTLINE); ## right NOT evaluated ## both sides evaluated when left is false se = 0; r = 0 || (se = 77); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(se, 77, @SCRIPTNAME, @SCRIPTLINE); ## right WAS evaluated ## false || false r = 0 || 0; tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); ## chained OR r = 0 || 0 || 1; tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); r = 0 || 0 || 0; tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); ## OR with complex subexpressions r = (1 == 2) || (3 * 3 == 9); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); r = (1 == 2) || (2 + 2 == 5); tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## mixed AND/OR with nested short-circuit ## ----------------------------------------------------------------------- function test_logical_mixed( r, se) { r = (1 && 1) || (0 && 1); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); r = (0 || 0) && (1 || 0); tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); r = (0 || 1) && (1 && 1) && (0 || 1); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); ## right side of AND is never reached because left is short-circuit false se = 0; r = (0 && 1) || (se = 5); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(se, 5, @SCRIPTNAME, @SCRIPTLINE); ## OR's right WAS evaluated ## right side of OR never reached se = 0; r = (1 || (se = 3)) && 1; tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(se, 0, @SCRIPTNAME, @SCRIPTLINE); ## OR's right NOT evaluated } ## ----------------------------------------------------------------------- ## unary operators -- HAWK_EF_UNARY ## ----------------------------------------------------------------------- function test_unary( x) { x = 5; tap_ensure(-x, -5, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(+x, 5, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(!x, 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(!0, 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(~0, -1, @SCRIPTNAME, @SCRIPTLINE); ## bitwise NOT ## nested unary operators (each adds a UNARY frame) tap_ensure(-(-x), 5, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(!!x, 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(!!!x, 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(~(~0), 0, @SCRIPTNAME, @SCRIPTLINE); ## unary applied to binary subexpression tap_ensure(-(2 + 3), -5, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(!(3 < 2), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(-(2 * 3), -6, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(~(0xF0 & 0xFF), -241, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## conditional (ternary) -- HAWK_EF_CND ## ----------------------------------------------------------------------- function test_conditional( a, b, x) { a = 10; b = 20; ## basic true/false branch selection tap_ensure((a < b ? "lt" : "ge"), "lt", @SCRIPTNAME, @SCRIPTLINE); tap_ensure((a > b ? "gt" : "le"), "le", @SCRIPTNAME, @SCRIPTLINE); tap_ensure((a == 10 ? a : b), 10, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((a == 99 ? a : b), 20, @SCRIPTNAME, @SCRIPTLINE); ## nested ternary (each level adds a CND frame) x = (a < b) ? (b < 30 ? "lt30" : "ge30") : "no"; tap_ensure(x, "lt30", @SCRIPTNAME, @SCRIPTLINE); x = (a > b) ? "no" : (b > 15 ? "gt15" : "le15"); tap_ensure(x, "gt15", @SCRIPTNAME, @SCRIPTLINE); ## ternary with binary expressions in all three positions x = (a + b == 30) ? (a * b) : (a - b); tap_ensure(x, 200, @SCRIPTNAME, @SCRIPTLINE); x = (a + b == 99) ? (a * b) : (a - b); tap_ensure(x, -10, @SCRIPTNAME, @SCRIPTLINE); ## ternary result used in larger expression tap_ensure((a < b ? a : b) + (a > b ? a : b), 30, @SCRIPTNAME, @SCRIPTLINE); ## ternary inside AND/OR tap_ensure((1 && (a < b ? 1 : 0)), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((0 || (a > b ? 1 : 0)), 0, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## simple assignment -- HAWK_EF_ASS_RHS (opcode == NONE path) ## ----------------------------------------------------------------------- function test_simple_assign( x, y, z) { x = 42; tap_ensure(x, 42, @SCRIPTNAME, @SCRIPTLINE); ## assignment with complex RHS (exercises BIN/UNARY/CND inside ASS_RHS) x = 3 * 4 + 5; tap_ensure(x, 17, @SCRIPTNAME, @SCRIPTLINE); x = (2 < 3 ? 10 : 20) + 5; tap_ensure(x, 15, @SCRIPTNAME, @SCRIPTLINE); x = !(1 == 2); tap_ensure(x, 1, @SCRIPTNAME, @SCRIPTLINE); ## chained assignment (right-to-left: z=7, y=7, x=7) x = y = z = 7; tap_ensure(x, 7, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(y, 7, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(z, 7, @SCRIPTNAME, @SCRIPTLINE); ## assignment used as expression in larger context tap_ensure((x = 5) + 3, 8, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(x, 5, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## compound assignment -- HAWK_EF_ASS_LHS (opcode != NONE path) ## ----------------------------------------------------------------------- function test_compound_assign( x) { x = 10; x += 5; tap_ensure(x, 15, @SCRIPTNAME, @SCRIPTLINE); x -= 3; tap_ensure(x, 12, @SCRIPTNAME, @SCRIPTLINE); x *= 4; tap_ensure(x, 48, @SCRIPTNAME, @SCRIPTLINE); x /= 6; tap_ensure(x, 8, @SCRIPTNAME, @SCRIPTLINE); x %= 3; tap_ensure(x, 2, @SCRIPTNAME, @SCRIPTLINE); x ^= 8; tap_ensure(x, 256, @SCRIPTNAME, @SCRIPTLINE); x \= 10; tap_ensure(x, 25, @SCRIPTNAME, @SCRIPTLINE); ## compound with complex RHS (BIN evaluator inside ASS_RHS) x = 5; x += 2 * 3; tap_ensure(x, 11, @SCRIPTNAME, @SCRIPTLINE); x = 100; x -= (3 + 7); tap_ensure(x, 90, @SCRIPTNAME, @SCRIPTLINE); x = 4; x *= (1 + 1); tap_ensure(x, 8, @SCRIPTNAME, @SCRIPTLINE); ## bitwise compound assignments x = 0xFF; x &= 0x0F; tap_ensure(x, 15, @SCRIPTNAME, @SCRIPTLINE); x = 0xF0; x |= 0x0F; tap_ensure(x, 255, @SCRIPTNAME, @SCRIPTLINE); x = 0xFF; x ^^= 0x0F; tap_ensure(x, 240, @SCRIPTNAME, @SCRIPTLINE); x = 1; x <<= 4; tap_ensure(x, 16, @SCRIPTNAME, @SCRIPTLINE); x >>= 2; tap_ensure(x, 4, @SCRIPTNAME, @SCRIPTLINE); ## string concatenation compound assignment x = "hello"; x = x " " "world"; tap_ensure(x, "hello world", @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## function calls with complex argument expressions ## (exercises push_arg_from_nde_xstack for each argument) ## ----------------------------------------------------------------------- function add3(a, b, c) { return a + b + c; } function mul_add(a, b, c) { return a * b + c; } function identity(x) { return x; } function choose(flag, a, b){ return flag ? a : b; } function noop() { return 0; } function test_fncall_args( r, tmp) { ## args are binary expressions r = add3(1 + 2, 3 * 4, 5 - 1); tap_ensure(r, 19, @SCRIPTNAME, @SCRIPTLINE); ## 3 + 12 + 4 ## arg is a conditional r = choose(1 > 0, "yes", "no"); tap_ensure(r, "yes", @SCRIPTNAME, @SCRIPTLINE); r = choose(0 > 1, "yes", "no"); tap_ensure(r, "no", @SCRIPTNAME, @SCRIPTLINE); ## arg is a unary expression r = identity(-(3 + 4)); tap_ensure(r, -7, @SCRIPTNAME, @SCRIPTLINE); ## arg is itself a function call with complex args r = identity(add3(1, 2, 3)); tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE); ## arg mixing AND with function call r = choose(1 && 1, add3(1, 2, 3), 0); tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE); r = choose(1 && 0, add3(1, 2, 3), 99); tap_ensure(r, 99, @SCRIPTNAME, @SCRIPTLINE); ## arg that is an assignment expression (side-effect) tmp = 0; r = add3((tmp = 10), tmp + 1, tmp + 2); tap_ensure(r, 33, @SCRIPTNAME, @SCRIPTLINE); ## 10 + 11 + 12 tap_ensure(tmp, 10, @SCRIPTNAME, @SCRIPTLINE); ## deeply nested call in arg r = mul_add(add3(1, 1, 1), identity(4), noop() + 2); tap_ensure(r, 14, @SCRIPTNAME, @SCRIPTLINE); ## 3*4 + 2 } ## ----------------------------------------------------------------------- ## recursive user-defined functions ## (each call goes through evalcall/evalcall_xstack) ## ----------------------------------------------------------------------- function fib(n) { return n <= 1 ? n : fib(n - 1) + fib(n - 2); } function fact(n) { return n <= 1 ? 1 : n * fact(n - 1); } function sum_to(n) { return n <= 0 ? 0 : n + sum_to(n - 1); } function ack(m, n) { if (m == 0) return n + 1; if (n == 0) return ack(m - 1, 1); return ack(m - 1, ack(m, n - 1)); } function test_recursive() { @local r; tap_ensure(fib(0), 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(fib(1), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(fib(10), 55, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(fib(15), 610, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(fact(0), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(fact(1), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(fact(10), 3628800, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(sum_to(0), 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(sum_to(100), 5050, @SCRIPTNAME, @SCRIPTLINE); ## Ackermann: moderate values to avoid stack overflow tap_ensure(ack(0, 0), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(ack(1, 1), 3, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(ack(2, 2), 7, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(ack(3, 3), 61, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## deeply nested mixed expressions ## (combines BIN, UNARY, CND, ASS — many eframe levels at once) ## ----------------------------------------------------------------------- function test_deep_mixed() { @local t, a, b, c, x; a = 3; b = 4; c = 5; ## Pythagorean triple check x = (a*a + b*b == c*c) ? "right" : "wrong"; tap_ensure(x, "right", @SCRIPTNAME, @SCRIPTLINE); ## deeply nested: binary inside conditional inside assignment x = (a < b) ? (b < c ? a + b + c : a * b) : (a - b) * c; tap_ensure(x, 12, @SCRIPTNAME, @SCRIPTLINE); ## a+b+c = 12 ## right-associated depth 10 x = (1+(2+(3+(4+(5+(6+(7+(8+(9+10))))))))); tap_ensure(x, 55, @SCRIPTNAME, @SCRIPTLINE); ## logical chains mixed with arithmetic x = (a > 0 && b > 0 && c > 0) ? a * b * c : 0; tap_ensure(x, 60, @SCRIPTNAME, @SCRIPTLINE); ## unary inside conditional inside AND x = (!(a > b)) && (-(a - b) > 0); tap_ensure(x, 1, @SCRIPTNAME, @SCRIPTLINE); ## !(3>4)=1, -(3-4)=1 > 0 ## assignment inside binary x = (t = a + b) * (t - a); tap_ensure(x, 28, @SCRIPTNAME, @SCRIPTLINE); ## t=7, 7*4=28 tap_ensure(t, 7, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## in operator (delegated to eval_binop_in, not iterative) ## Verify the default-case delegation path in eval_expression0_xstack. ## ----------------------------------------------------------------------- function test_in_operator() { @local m, r; m["x"] = 1; m["y"] = 2; tap_ensure(("x" in m), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(("z" in m), 0, @SCRIPTNAME, @SCRIPTLINE); ## 'in' inside AND/OR (both iterative and delegated evaluators) tap_ensure((("x" in m) && ("y" in m)), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((("x" in m) && ("z" in m)), 0, @SCRIPTNAME, @SCRIPTLINE); tap_ensure((("z" in m) || ("x" in m)), 1, @SCRIPTNAME, @SCRIPTLINE); ## 'in' inside conditional r = ("x" in m) ? m["x"] : -1; tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); r = ("z" in m) ? m["z"] : -1; tap_ensure(r, -1, @SCRIPTNAME, @SCRIPTLINE); ## 'in' inside unary tap_ensure(!("z" in m), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(!("x" in m), 0, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## pre/post increment and decrement ## (delegated to original eval_expression0 via default: branch) ## ----------------------------------------------------------------------- function test_incr_decr( x, r) { x = 5; r = ++x; tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(x, 6, @SCRIPTNAME, @SCRIPTLINE); r = x++; tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE); ## returns old value tap_ensure(x, 7, @SCRIPTNAME, @SCRIPTLINE); r = --x; tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(x, 6, @SCRIPTNAME, @SCRIPTLINE); r = x--; tap_ensure(r, 6, @SCRIPTNAME, @SCRIPTLINE); ## returns old value tap_ensure(x, 5, @SCRIPTNAME, @SCRIPTLINE); ## incr/decr result used in binary expression x = 10; r = (++x) + (++x); tap_ensure(r, 23, @SCRIPTNAME, @SCRIPTLINE); ## 11 + 12 tap_ensure(x, 12, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## positional variable ($n) — delegated path ## ----------------------------------------------------------------------- function test_positional() { @local r; $1 = "hello"; $2 = "world"; r = $1 " " $2; tap_ensure(r, "hello world", @SCRIPTNAME, @SCRIPTLINE); ## positional in conditional (force numeric comparison with +0) $1 = 10; r = ($1 + 0 > 5 ? $1 * 2 : $1 / 2); tap_ensure(r, 20, @SCRIPTNAME, @SCRIPTLINE); ## positional in compound assignment $1 = 3; $1 += 7; tap_ensure($1, 10, @SCRIPTNAME, @SCRIPTLINE); } ## ----------------------------------------------------------------------- ## match/no-match operators (delegated to eval_binop_ma / eval_binop_nm) ## ----------------------------------------------------------------------- function test_match_ops() { @local r; r = ("hello" ~ /ell/); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); r = ("hello" ~ /xyz/); tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); r = ("hello" !~ /xyz/); tap_ensure(r, 1, @SCRIPTNAME, @SCRIPTLINE); r = ("hello" !~ /ell/); tap_ensure(r, 0, @SCRIPTNAME, @SCRIPTLINE); ## match result in AND/OR tap_ensure(("abc" ~ /a/) && ("xyz" ~ /x/), 1, @SCRIPTNAME, @SCRIPTLINE); tap_ensure(("abc" ~ /z/) || ("xyz" ~ /x/), 1, @SCRIPTNAME, @SCRIPTLINE); ## match result in conditional r = ("hawk" ~ /awk/) ? "yes" : "no"; tap_ensure(r, "yes", @SCRIPTNAME, @SCRIPTLINE); } function main() { test_binary_arith(); test_binary_cmp(); test_binary_bitwise(); test_binary_chain(); test_logical_and(); test_logical_or(); test_logical_mixed(); test_unary(); test_conditional(); test_simple_assign(); test_compound_assign(); test_fncall_args(); test_recursive(); test_deep_mixed(); test_in_operator(); test_incr_decr(); test_positional(); test_match_ops(); tap_end(); }