@pragma entry main
@pragma implicit off

@include "tap.inc";

function main()
{

	## call by reference. change an argument to array in the callee
	{
		@local ini, foo1, foo2, foo3, foo4;

		test1(foo1);
		test2(foo2);
		test3(foo3);
		test4(foo4);
		tap_ensure (hawk::typename(foo1), "map", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::typename(foo2), "map", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::typename(foo3), "nil", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::typename(foo4), "nil", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (foo1[1], 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (foo2[1], 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (foo3[1], ini, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (foo4[1], ini, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::type('a'), hawk::VAL_CHAR, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::type(@b'b'), hawk::VAL_BCHAR, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::type("a"), hawk::VAL_STR, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::type(@b"a"), hawk::VAL_MBS, @SCRIPTNAME, @SCRIPTLINE);
	}

	## gsub
	{
		@local w, x, y, z, z1, z2;
		x = y = "x\\y";
		gsub(/\\\\/, "A", x);
		gsub("\\\\", "A", y);
		tap_ensure (x, "x\\y", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, "xAy", @SCRIPTNAME, @SCRIPTLINE);

		x = y = "x\\y";
		gsub(/\\\\/, 'A', x);
		gsub("\\\\", 'A', y);
		tap_ensure (x, "x\\y", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, "xAy", @SCRIPTNAME, @SCRIPTLINE);

		x = y = "x\\\\y";
		gsub(/\\\\/, "A", x);
		gsub("\\\\", "A", y);
		tap_ensure (x, "xAy", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, "xAAy", @SCRIPTNAME, @SCRIPTLINE);


		x = y = @b"x\\\\y";
		gsub(/\\\\/, "A", x);
		gsub("\\\\", "A", y);
		tap_ensure (x === @b"xAy", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y === @b"xAAy", 1, @SCRIPTNAME, @SCRIPTLINE);

		x = y = @b"x\\\\y";
		gsub(/\\\\/, 'A', x);
		gsub("\\\\", 'A', y);
		tap_ensure (x === @b"xAy", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y === @b"xAAy", 1, @SCRIPTNAME, @SCRIPTLINE);

		x = y = "x\\\\y";
		gsub(/\\\\/, @b'A', x);
		gsub("\\\\", @b'A', y);
		tap_ensure (x === "xAy", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y === "xAAy", 1, @SCRIPTNAME, @SCRIPTLINE);

		x = y = "x\\\\y";
		gsub(/\\\\/, @b"A", x);
		gsub("\\\\", @b"A", y);
		tap_ensure (x === "xAy", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y === "xAAy", 1, @SCRIPTNAME, @SCRIPTLINE);

		x = y = '\\';
		gsub(/\\/, @b"A", x);
		gsub("\\\\", @b"A", y);
		tap_ensure (x === "A", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y === "A", 1, @SCRIPTNAME, @SCRIPTLINE);

		x = y = '\\';
		gsub(/\\/, @b'A', x);
		gsub("\\\\", @b'A', y);
		tap_ensure (x === "A", 1, @SCRIPTNAME, @SCRIPTLINE);

		x = y = @b'\\';
		gsub(/\\/, @b"A", x);
		gsub("\\\\", @b"A", y);
		tap_ensure (x === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE);

		x = y = @b'\\';
		gsub(/\\/, @b'A', x);
		gsub("\\\\", @b'A', y);
		tap_ensure (x === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE);
	}

	## gsub - POSIX rule for &, \&, \\&, \\\&
	{
		@local w, x, y, z, z1, z2, z3;
		w = x = y = z = z1 = z2 = "xax";

		gsub(/a/, "\&", w);  # gsub sees &
		gsub(/a/, "\\&", x);   # gsub sees \&
		gsub(/a/, "\\\&", y);   # gsub sees \&

		gsub(/a/, "\\\\&", z);  # gsub sees \\&
		gsub(/a/, "\\\\\&", z1); # gsub sees \\&
		gsub(/a/, "\\\\\\&", z2); # gsub sees \\\&

		tap_ensure (w, "xax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (x, "x&x", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, "x&x", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z, "x\\ax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z1, "x\\ax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z2, "x\\&x", @SCRIPTNAME, @SCRIPTLINE);

		w = x = y = z = z1 = z2 = "xaax";

		gsub(/a/, "\&", w);  # gsub sees &
		gsub(/a/, "\\&", x);   # gsub sees \&
		gsub(/a/, "\\\&", y);   # gsub sees \&

		gsub(/a/, "\\\\&", z);  # gsub sees \\&
		gsub(/a/, "\\\\\&", z1); # gsub sees \\&
		gsub(/a/, "\\\\\\&", z2); # gsub sees \\\&

		tap_ensure (w, "xaax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (x, "x&&x", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, "x&&x", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z, "x\\a\\ax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z1, "x\\a\\ax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z2, "x\\&\\&x", @SCRIPTNAME, @SCRIPTLINE);
	}

	## gsub - POSIX rule for &, \&, \\&, \\\&  - express the same test with a raw string literal
	{
		@local w, x, y, z;
		w = x = y = z = "xax";

		gsub(/a/, @r"&", w);  # gsub sees &
		gsub(/a/, @r"\&", x);   # gsub sees \&

		gsub(/a/, @r"\\&", y);  # gsub sees \\&
		gsub(/a/, @r"\\\&", z); # gsub sees \\\&

		tap_ensure (w, "xax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (x, "x&x", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, @r"x\ax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z, @r"x\&x", @SCRIPTNAME, @SCRIPTLINE);

		w = x = y = z = "xaax";

		gsub(/a/, @r"&", w);  # gsub sees &
		gsub(/a/, @r"\&", x);   # gsub sees \&

		gsub(/a/, @r"\\&", y);  # gsub sees \\&
		gsub(/a/, @r"\\\&", z); # gsub sees \\\&

		tap_ensure (w, "xaax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (x, "x&&x", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, @r"x\a\ax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z, @r"x\&\&x", @SCRIPTNAME, @SCRIPTLINE);
	}

	## sub - POSIX rule for &, \&, \\&, \\\&  - express the same test with a raw string literal
	{
		@local w, x, y, z;
		w = x = y = z = "xax";

		sub(/a/, @r"&", w);
		sub(/a/, @r"\&", x);

		sub(/a/, @r"\\&", y);
		sub(/a/, @r"\\\&", z);

		tap_ensure (w, "xax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (x, "x&x", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, @r"x\ax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z, @r"x\&x", @SCRIPTNAME, @SCRIPTLINE);

		w = x = y = z = "xaax";

		sub(/a/, @r"&", w);
		sub(/a/, @r"\&", x);

		sub(/a/, @r"\\&", y);
		sub(/a/, @r"\\\&", z);

		tap_ensure (w, "xaax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (x, "x&ax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (y, @r"x\aax", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (z, @r"x\&ax", @SCRIPTNAME, @SCRIPTLINE);
	}

	## gensub
	{
		@local x;
		x = gensub(/(tiger|dog)/, "\\1-\\1", "g", "the tiger pounces on the dog");
		tap_ensure (x, "the tiger-tiger pounces on the dog-dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|dog)/, "\\1-\\1", 'G', "the tiger pounces on the dog");
		tap_ensure (x, "the tiger-tiger pounces on the dog-dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|dog)/, "\\1-\\1", 'G', @b"the tiger pounces on the dog");
		tap_ensure (x, @b"the tiger-tiger pounces on the dog-dog", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::typename(x), "mbs", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|dog)/, "\\1-\\1", 1, "the tiger pounces on the dog");
		tap_ensure (x, "the tiger-tiger pounces on the dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|dog)/, "\\1-\\1", 2, "the tiger pounces on the dog");
		tap_ensure (x, "the tiger pounces on the dog-dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|dog)/, "\\1-\\1", 2, @b"the tiger pounces on the dog");
		tap_ensure (x, @b"the tiger pounces on the dog-dog", @SCRIPTNAME, @SCRIPTLINE);

		## 0 as the third argument is same as not passing "g"/"G" or a positive occurrence number.
		x = gensub(/(tiger|dog)/, "\\1-\\1", 0, "the tiger pounces on the dog");
		tap_ensure (x, "the tiger-tiger pounces on the dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|dog)/, "\\1-\\1", "", "the tiger pounces on the dog");
		tap_ensure (x, "the tiger-tiger pounces on the dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|dog)/, "\\1-\\1", 10, "the tiger pounces on the dog");
		tap_ensure (x, "the tiger pounces on the dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|(dog))/, "\\1-\\2", 'g', "the tiger pounces on the dog");
		tap_ensure (x, "the tiger- pounces on the dog-dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|(dog))/, "\\1-\\2", 'g', @b"the tiger pounces on the dog");
		tap_ensure (x, @b"the tiger- pounces on the dog-dog", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|(dog))/, "[&]", 'g', "the tiger pounces on the dog");
		tap_ensure (x, "the [tiger] pounces on the [dog]", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/(tiger|(dog))/, "[\\0]", 'g', "the tiger pounces on the dog");
		tap_ensure (x, "the [tiger] pounces on the [dog]", @SCRIPTNAME, @SCRIPTLINE);
		x = gensub(/((apple)|(turtle)|(orange)|(tiger)|(dog))/, "[\\6]", 'g', "the tiger pounces on the dog");
		tap_ensure (x, "the [] pounces on the [dog]", @SCRIPTNAME, @SCRIPTLINE);
	}

	{
		@local pi, e, tmp;

		pi = 3.1415927;

		tap_ensure (sprintf("%.10d:%.10x", 5, 14), "0000000005:000000000e", @SCRIPTNAME,  @SCRIPTLINE);

		tap_ensure (sprintf("cos(%f) = %f", pi/4, cos(pi/4)), "cos(0.785398) = 0.707107", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("sin(%f) = %f", pi/4, sin(pi/4)), "sin(0.785398) = 0.707107", @SCRIPTNAME, @SCRIPTLINE);

		e = exp(1);
		tap_ensure (sprintf("e = %f", e), "e = 2.718282", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("log(e) = %f", log(e)), "log(e) = 1.000000", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("sqrt(pi ^ 2) = %f", sqrt(pi ^ 2)), "sqrt(pi ^ 2) = 3.141593", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("atan2(1, 1) = %f", atan2(1, 1)), "atan2(1, 1) = 0.785398", @SCRIPTNAME, @SCRIPTLINE);

		tmp = sprintf("%s", "hello");
		tap_ensure ((tmp === @b"hello"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp === "hello"),   1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp == @b"hello"),  1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp == "hello"),    1, @SCRIPTNAME, @SCRIPTLINE);

		tmp = sprintf("%s", @b"hello");
		tap_ensure ((tmp === @b"hello"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp === "hello"),   1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp == @b"hello"),  1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp == "hello"),    1, @SCRIPTNAME, @SCRIPTLINE);

		tmp = sprintf(@b"%s", "hello");
		tap_ensure ((tmp === @b"hello"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp === "hello"),   0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp == @b"hello"),  1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp == "hello"),    1, @SCRIPTNAME, @SCRIPTLINE);

		tmp = sprintf(@b"%s", @b"hello");
		tap_ensure ((tmp === @b"hello"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp === "hello"),   0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp == @b"hello"),  1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure ((tmp == "hello"),    1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (sprintf("%0d", 0),            "0",          @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%0.d", 0),           "",           @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%.d", 0),            "",           @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%.*d", 0, 0),        "",           @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%.*d", 1, 0),        "0",          @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%*d", 0, 0),         "0",          @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%*.*d", 0, 0, 0),    "",           @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%-*.*d", 0, 0, 0),   "",           @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%*.*d", 1, 0, 0),    " ",          @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%*.*d", 0, 3, 0),    "000",        @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%-*d", 0, 0),        "0",          @SCRIPTNAME,  @SCRIPTLINE);

		tap_ensure (sprintf(@b"%0d", 0),          @b"0",        @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%0.d", 0),         @b"",         @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%.d", 0),          @b"",         @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%.*d", 0, 0),      @b"",         @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%.*d", 1, 0),      @b"0",        @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*d", 0, 0),       @b"0",        @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*.*d", 0, 0, 0),  @b"",         @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%-*.*d", 0, 0, 0), @b"",         @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*.*d", 1, 0, 0),  @b" ",        @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*.*d", 0, 3, 0),  @b"000",      @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%-*d", 0, 0),      @b"0",        @SCRIPTNAME,  @SCRIPTLINE);

		tap_ensure (sprintf("%5d", 5),            "    5",      @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%-5d", 5),           "5    ",      @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%*d", 5, 5),         "    5",      @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%*d", -5, 5),        "5    ",      @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%-*d", 5, 5),        "5    ",      @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf("%-*d", -5, 5),       "5    ",      @SCRIPTNAME,  @SCRIPTLINE);

		tap_ensure (sprintf(@b"%5d", 5),          @b"    5",    @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%-5d", 5),         @b"5    ",    @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*d", 5, 5),       @b"    5",    @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*d", -5, 5),      @b"5    ",    @SCRIPTNAME,  @SCRIPTLINE);
		tap_ensure (sprintf(@b"%-*d", 5, 5),      @b"5    ",    @SCRIPTNAME,  @SCRIPTLINE);

		tap_ensure (sprintf("%*sworld", 20, "hello"),        "               helloworld",   @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("%*sworld", -20, "hello"),       "hello               world",   @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("%-*sworld", 20, "hello"),       "hello               world",   @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("%-*sworld", -20, "hello"),      "hello               world",   @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (sprintf(@b"%*sworld", 20, "hello"),      @b"               helloworld", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*sworld", -20, "hello"),     @b"hello               world", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%-*sworld", 20, "hello"),     @b"hello               world", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%-*sworld", -20, "hello"),    @b"hello               world", @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (sprintf("%0s", "hello"),                 "hello",                       @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("%.0s", "hello"),                "",                            @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("%0.0s", "hello"),               "",                            @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("%1.0s", "hello"),               " ",                           @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("%*.*s", 20, 0, "hello"),        "                    ",        @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf("%*.*s", 20, 2, "hello"),        "                  he",        @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (sprintf(@b"%0s", "hello"),               @b"hello",                     @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%.0s", "hello"),              @b"",                          @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%0.0s", "hello"),             @b"",                          @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%1.0s", "hello"),             @b" ",                         @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*.*s", 20, 0, "hello"),      @b"                    ",      @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%*.*s", 20, 2, "hello"),      @b"                  he",      @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (sprintf("%+d %d", 3, 4),                 "+3 4",                        @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf(@b"%+d %d", 3, 4),               @b"+3 4",                      @SCRIPTNAME, @SCRIPTLINE);


		tap_ensure (sprintf(@b'A') === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (sprintf('A') === "A", 1, @SCRIPTNAME, @SCRIPTLINE);
	}

	{
		@local bool, b, c;

		tap_ensure ((c === @nil), 1, @SCRIPTNAME, @SCRIPTLINE); ## tap_ensure local variable initialization

		bool = ((b = 1) in c);
		tap_ensure (bool, 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (b, 1, @SCRIPTNAME, @SCRIPTLINE);
	}


	{
		tap_ensure (substr(1000+"5000", 2) === "000",          1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr(1000+"10000", 2) === "1000",        1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr(1000+"5000", 2) === "000",          1,  @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (substr("5000" + 1000, 2) === "000",        1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr("10000" + 1000, 2) === "1000",      1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr("5000" + 1000, 2) === "000",        1,  @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (substr(@b"5000" + 1000, 2) === "000",      1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr(@b"10000" + 1000, 2) === "1000",    1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr(@b"5000" + 1000, 2) === "000",      1,  @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (substr(@b"5000", 2) === @b"000",           1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr(@b"10000", 2) === @b"0000",         1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr(@b"5000", 2) === @b"000",           1,  @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (substr(1000+5000, 2) === "000",            1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr(1000+10000, 2) === "1000",          1,  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (substr(1000+5000, 2) === "000",            1,  @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::subchar("abc", -1) === @nil,          1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("abc", 0) === @nil,           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("abc", 1) === 'a',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("abc", 2) === 'b',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("abc", 3) === 'c',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("abc", 4) === @nil,           1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::subchar("☕⛄", -1) === @nil,          1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("☕⛄", 0) === @nil,           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("☕⛄", 1) === '☕',           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("☕⛄", 2) === '⛄',           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("☕⛄", 3) === @nil,           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar("☕⛄", 4) === @nil,           1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::subchar(@b"abc", -1) === @nil,          1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(@b"abc", 0) === @nil,           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(@b"abc", 1) === @b'a',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(@b"abc", 2) === @b'b',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(@b"abc", 3) === @b'c',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(@b"abc", 4) === @nil,           1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::subchar('a', 0) === @nil,            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar('a', 1) === 'a',             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar('a', 2) === @nil,            1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::subchar(@b'a', 0) === @nil,            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(@b'a', 1) === @b'a',           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(@b'a', 2) === @nil,            1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::subchar(123, 0) === @nil,             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(123, 1) === '1',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(123, 2) === '2',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(123, 3) === '3',            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::subchar(123, 4) === @nil,            1, @SCRIPTNAME, @SCRIPTLINE);
	}

	{
		tap_ensure (str::substr("☕Q⛄", 0) === "☕Q⛄",         1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::substr("☕Q⛄", 1) === "☕Q⛄",         1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::substr("☕Q⛄", 2) === "Q⛄",           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::substr("☕Q⛄", 3) === "⛄",            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::substr("☕Q⛄", 4) === "",            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::substr("☕Q⛄", 1, 2) === "☕Q",         1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::substr("☕Q⛄", 1, 4) === "☕Q⛄",         1, @SCRIPTNAME, @SCRIPTLINE);
		###tap_ensure (str::substr("☕Q⛄", -1, 1) === "⛄",         1, @SCRIPTNAME, @SCRIPTLINE); ## not supported yet
		tap_ensure (str::substr('☕', 1, 4) === "☕",         1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::substr(@b"\xAD\xAA\xBB\CC", 2, 2) === @b"\xAA\xBB", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::substr(@b'\xAD', 1, 1) === @b"\xAD", 1, @SCRIPTNAME, @SCRIPTLINE);
	}

	{
		tap_ensure (str::index("☕Q⛄X⛄Z", '⛄'),  3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index("☕Q⛄X⛄Z", "⛄"),  3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index("☕Q⛄X⛄Z", "Q⛄"),  2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::rindex("☕Q⛄X⛄Z", '⛄'),  5, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::rindex("☕Q⛄X⛄Z", "⛄"),  5, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::rindex("☕Q⛄X⛄Z", "Q⛄"),  2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::rindex("☕Q⛄X⛄Z", "Q⛄Q"),  0, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::index(@b"\xFFQ\xABX\xABZ", @b'\xAB'),  3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index(@b"\xFFQ\xABX\xABZ", @b"\xAB"),  3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index(@b"\xFFQ\xABX\xABZ", @b"Q\xAB"),  2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::rindex(@b"\xFFQ\xABX\xABZ", @b'\xAB'),  5, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::rindex(@b"\xFFQ\xABX\xABZ", @b"\xAB"),  5, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::rindex(@b"\xFFQ\xABX\xABZ", @b"Q\xAB"),  2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::rindex(@b"\xFFQ\xABX\xABZ", @b"Q\xABQ"),  0, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::index(str::frombcharcode(65), @b"B"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index(str::frombcharcode(65), @b"A"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index(str::frombcharcode(65), @b"B"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index(str::frombcharcode(65), @b"A"), 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::index(@b'A', @b"B"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index(@b'A', @b"A"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index('A', @b"B"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::index('A', @b"A"), 1, @SCRIPTNAME, @SCRIPTLINE);
	}

	{
		# split, str::split, str::splita
		@local a, str;

		tap_ensure (split("Here===Is=Some=====Data", a, "=+"),     4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === "Here",                               1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === "Is",                                 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === "Some",                               1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === "Data",                               1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (split(@b"Here===Is=Some=====Data", a, @b"=+"), 4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === @b"Here",                             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === @b"Is",                               1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === @b"Some",                             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === @b"Data",                             1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (split(@b"Here===Is=Some=====Data", a, /=+/),    4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === @b"Here",                             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === @b"Is",                               1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === @b"Some",                             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === @b"Data",                             1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (split("[Here] : [Is]  : [So\\]me] :[Da:ta]", a, "?:\\[]"), 4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === "Here",                               1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === "Is",                                 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === "So]me",                              1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === "Da:ta",                              1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (split(@b"[Here] : [Is]  : [So\\]me] :[Da:ta]", a, "?:\\[]"), 4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === @b"Here",                             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === @b"Is",                               1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === @b"So]me",                            1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === @b"Da:ta",                            1, @SCRIPTNAME, @SCRIPTLINE);

		## the splitter begins with a question mark and contains 4 characters
		## (separator, escaper, left-quote, right-qoute) after it.
		tap_ensure (split(@b"sea of people, brandy, coke, dark\\,age", a, "?,\\\"\""), 4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === @b"sea of people",                    1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === @b"brandy",                           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === @b"coke",                             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === @b"dark,age",                         1, @SCRIPTNAME, @SCRIPTLINE);

		## escape doubling scheme - useful for csv-like files
		## if escaper, left-quote, right-quote are the same, escape doubling scheme is turned on
		tap_ensure (split(@b"sea of people, brandy, coke, \"\"\"dark\"\", age\"", a, "?,\"\"\""), 4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === @b"sea of people",                    1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === @b"brandy",                           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === @b"coke",                             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === @b"\"dark\", age",                    1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (split(@b"sea of people, brandy, coke, |||dark||, age|", a, "?,|||"), 4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === @b"sea of people",                    1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === @b"brandy",                           1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === @b"coke",                             1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === @b"|dark|, age",                      1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (split("Here===Is=Some=====Data", a, ""),       23,     @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::typename(a),                             "map",  @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::splita("Here===Is=Some=====Data", a, ""),  23,    @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (hawk::typename(a),                             "array",@SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::split("Here  Is Some   Data", a, / /),    7, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::split("Here  Is Some   Data", a, " "),    4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === "Here",                               1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === "Is",                                 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3] === "Some",                               1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4] === "Data",                               1, @SCRIPTNAME, @SCRIPTLINE);

		str = "a   b\t\tc d";
		tap_ensure (str::splita(str, a, " "), 4,              @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1],               "a",            @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2],               "b",            @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3],               "c",            @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4],               "d",            @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::splita(str, a, / /), 5, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1],               "a",            @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2],               "",             @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[3],               "",             @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[4],               "b\t\tc",       @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[5],               "d",            @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::split('a', a, /a/), 2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === "", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === "", 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::split('a', a, 'a'), 2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === "", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === "", 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::split('a', a, @b'a'), 2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === "", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === "", 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::split(@b'a', a, /a/), 2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === @b"", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === @b"", 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::split(@b'a', a, @b'a'), 2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1] === @b"", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2] === @b"", 1, @SCRIPTNAME, @SCRIPTLINE);
	}


	{
		## back reference in a regular expression - use the character class
		## notation to avoid escaping - \1[2]
		tap_ensure (("a2b" ~ /(a)\1[2]b/), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (("aa2b" ~ /(a)\1[2]b/), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (("aaa2b" ~ /(a)\1[2]b/), 1, @SCRIPTNAME, @SCRIPTLINE);
	}


	{
		## character class functions in the str modules
		tap_ensure (str::isalnum('a'), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isalpha('a'), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isblank('a'), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::iscntrl('a'), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isdigit('a'), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isgraph('a'), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::islower('a'), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isprint('a'), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::ispunct('a'), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isspace('a'), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isupper('a'), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isxdigit('a'), 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::toupper('a') === 'A', 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tolower('A') === 'a', 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::isalnum("a"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isalpha("a"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isblank("a"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::iscntrl("a"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isdigit("a"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isgraph("a"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::islower("a"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isprint("a"), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::ispunct("a"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isspace("a"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isupper("a"), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::isxdigit("a"), 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::toupper("abc") === "ABC", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tolower("ABC") === "abc", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::toupper(@b"abc") === @b"ABC", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tolower(@b"ABC") === @b"abc", 1, @SCRIPTNAME, @SCRIPTLINE);
	}

	{
		tap_ensure (str::tocharcode(@b'\xFF'), 0xFF, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tocharcode('\u3321'), 0x3321, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tocharcode(@b'\xFF', 0), @nil, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tocharcode('\u3321', 0), @nil, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tocharcode(@b'\xFF', 1), 0xFF, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tocharcode('\u3321', 1), 0x3321, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tocharcode(@b'\xFF', 2), @nil, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tocharcode('\u3321', 2), @nil, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::tocharcode(str::fromcharcode('2')), 2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::tonum('a', 16), 10, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::fromcharcode(65, 66, 67) === "ABC", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::frombcharcode(65, 66, 67) === @b"ABC", 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::trim("  hello  world  ") === "hello  world", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::trim("  hello  world  ", str::TRIM_PAC_SPACES) === "hello world", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::trim(@b"  hello  world  ") === @b"hello  world", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (str::trim(@b"  hello  world  ", str::TRIM_PAC_SPACES) === @b"hello world", 1, @SCRIPTNAME, @SCRIPTLINE);
	}


	{
		@local a, b, c, d;
		sys::pack(a, ">hhl", 1, 2, 3);
		tap_ensure (a === @b"\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03", 1, @SCRIPTNAME, @SCRIPTLINE);

		sys::pack(a, ">ciI", @b'*', 0x12131415, 0x22334455);
		tap_ensure (a === @b"*\x12\x13\x14\x15\x22\x33\x44\x55", 1, @SCRIPTNAME, @SCRIPTLINE);

		sys::pack(a, ">ic", 0x12131415, @b"*+-");
		tap_ensure (a === @b"\x12\x13\x14\x15*", 1, @SCRIPTNAME, @SCRIPTLINE);

		sys::pack(a, "3c", @b"*+-", 't', "pack");
		tap_ensure (a === @b"*tp", 1, @SCRIPTNAME, @SCRIPTLINE);

		sys::unpack (@b"raymond   \x32\x12\x08\x01\x08", "<10sHHb", a, b, c, d);
		tap_ensure (a === @b"raymond   ", 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (b === 4658, 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (c === 264, 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (d === 8, 1, @SCRIPTNAME, @SCRIPTLINE);

		sys::unpack (@b"raymond", "3c", a, b, c);
		tap_ensure (a === @b'r' , 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (b === @b'a' , 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (c === @b'y' , 1, @SCRIPTNAME, @SCRIPTLINE);
	}


	{
		@local a, b, f;

		RSTART=99;
		RLENGTH=99;
		tap_ensure (match("world", /hello/), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RSTART, 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RLENGTH, -1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (match(@b"world", /hello/), 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RSTART, 0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RLENGTH, -1, @SCRIPTNAME, @SCRIPTLINE);

		## match() doesn't support the start index.
		## the result goes to the third argument.
		tap_ensure (match("hello, world", /l/), 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RSTART, 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RLENGTH, 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (match(@b"hello, world", /l/), 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RSTART, 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RLENGTH, 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (match("hello, world", /(l)lo.*(l)/, a), 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RSTART, 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RLENGTH, 9, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (length(a), 9, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[0,"start"], RSTART, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[0,"length"], RLENGTH, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1,"start"], 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1,"length"], 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2,"start"], 11, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2,"length"], 1, @SCRIPTNAME, @SCRIPTLINE);

		## start::match() support the start index via the third parameter.
		## the result goes to the fourth argument.
		tap_ensure (str::match("hello, world", /(l)lo.*(l)/, 1, a), 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RSTART, 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RLENGTH, 9, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (length(a), 9, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[0,"start"], RSTART, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[0,"length"], RLENGTH, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1,"start"], 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1,"length"], 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2,"start"], 11, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2,"length"], 1, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (str::match("hello, world, hello, world", /(l)lo.*(l)/, 4, a), 17, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RSTART, 17, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RLENGTH, 9, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (length(a), 9, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[0,"start"], RSTART, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[0,"length"], RLENGTH, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1,"start"], 17, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[1,"length"], 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2,"start"], 25, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (a[2,"length"], 1, @SCRIPTNAME, @SCRIPTLINE);


		b = 291210;
		tap_ensure (str::match(b @b"what is this", /10/, 1, a), 5, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RSTART, 5, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (RLENGTH, 2, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure (test5(10, 20, 30),  10, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test6(),  2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test6(11, 11, 11),  3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test7(),  0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test7(11, 11, 11),  3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),  54, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test9(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),  55, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),  55, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test11("aa", "bb", "cc"),  0, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure (test11("aa", "bb", "cc", "dd"),  1, @SCRIPTNAME, @SCRIPTLINE);

		f = test11;
		tap_ensure (f("aa", "bb", "cc", "dd"),  1, @SCRIPTNAME, @SCRIPTLINE);

		f = test10
		tap_ensure (f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),  55, @SCRIPTNAME, @SCRIPTLINE);
	}


	{
		tap_ensure(test12(2,5), -3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test12(3,5), 8, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure(test13(1), 1, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test13(2), 2, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test13(3), 3, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test13(4), 4, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test13(5), 5, @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test13(6), 1005, @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure(test14("hello"), "world", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test14("donkey"), "rankey", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test14("speed"), "unknown", @SCRIPTNAME, @SCRIPTLINE);

		tap_ensure(test15("hello"), "world", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test15("donkey"), "[rankey012]", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test15("skunk"), "stinks", @SCRIPTNAME, @SCRIPTLINE);
		tap_ensure(test15("speed"), "unknown", @SCRIPTNAME, @SCRIPTLINE);
	}

	tap_end ();
}

function test1(&foo) { test2(foo) }
function test2(&bar) { bar[1] = 1 }
function test3(foo) { test2(foo) }
function test4(bar) { bar[1] = 1 }

function test5(a, b, ...) {
	return a;
}

function test6(a, b, ...) {
	return @argc;
}

function test7(...) {
	return @argc;
}

function test8(a, ...) {
	@local i, x
	x = 0
	for (i = 0; i < @argc; i++) x += @argv[i];
	return x - a;
}

function test9(...) {
	@local i, x
	x = 0
	for (i = 0; i < @argc; i++) x += @argv[i];
	return x;
}

function test10(...) {
	@local i, x
	x = 0
	for (i in @argv) x += @argv[i];
	return x;
}

function test11(...) {
	return (3 in @argv);
}

function test12(...) {
	switch(@argv[0] * @argv[1]) {
	case 10:
		return @argv[0] - @argv[1];

	default:
		return @argv[0] + @argv[1];
	}
}

function test13(x) {
	@local a;

	a = 0;

	switch(x) {
	default:
		a = 1000;

	case 5:
		a++;

	case 4:
		a++;

	case 3:
		a++;

	case 2:
		a++;

	case 1:
		a++;
		break;
	}

	return a;
}

function test14(x) {
	switch(x) {
	case "hello":
		return "world";

	case "donkey":
		return "rankey";

	default:
		return "unknown";
	
	}
}


function test15(x) {
	@local a, i;

	switch(x) {
	case "hello":
		a =  "world";
		break;

	case "donkey":
	{
		@local l;
		a = "rankey";
		l = length(a);	
		for (i = 0; i < l; i++) {
			if (i == 3) break;
			a = sprintf("%s%d", a, i);
		}
		a = sprintf("[%s]", a);
		break;
	}

	default:
		if (x == "skunk") a = "stinks";
		else a = "unknown";
		break;	
	}

	return a;
}

