test: prove ordinary import binding modes

This commit is contained in:
2026-08-14 10:56:54 +09:00
parent 792b6ecbe5
commit 10e02a00ee
20 changed files with 1284 additions and 672 deletions

View File

@@ -17,19 +17,19 @@ import path;
let i: i32 = 0;
for (i < 4) {
let got: i32 = 0;
if (abs(ins[i])) { got = 1; };
if (path.abs(ins[i])) { got = 1; };
assert(!(got != want[i]));
i += 1;
};
// buffer-arm: &buf ptr-ident-widens into the union.
let buf = buffer { ... };
assert(!(abs(&buf))); // empty → false
assert(!(push(&buf, "/foo")! != "/foo"));
assert(!(!abs(&buf))); // "/foo" → true
let buf: path.buffer;
assert(!(path.abs(&buf))); // empty → false
assert(!(path.push(&buf, "/foo")! != "/foo"));
assert(!(!path.abs(&buf))); // "/foo" → true
buf.end = 0;
assert(!(push(&buf, "foo")! != "foo"));
assert(!(abs(&buf))); // "foo" → false
assert(!(path.push(&buf, "foo")! != "foo"));
assert(!(path.abs(&buf))); // "foo" → false
};
// ref/hare/path/buffer.ha:44-51. Both arms: str (== sepstr) and *buffer
@@ -37,24 +37,24 @@ import path;
// inline; str-arm rows table-driven.
@test fn isroot_cases() void = {
let buf = buffer { ... };
let buf: path.buffer;
// empty buffer (end 0)
assert(!(isroot(&buf)));
assert(!(path.isroot(&buf)));
// "/" — root. local() is c3, so seed the SEP byte directly.
buf.buf[0] = SEP; buf.end = 1;
assert(!(!isroot(&buf)));
assert(!(string(&buf) != "/"));
buf.buf[0] = path.SEP; buf.end = 1;
assert(!(!path.isroot(&buf)));
assert(!(path.string(&buf) != "/"));
// "foo" — relative, not root.
buf.end = 0;
assert(!(push(&buf, "foo")! != "foo"));
assert(!(isroot(&buf)));
assert(!(path.push(&buf, "foo")! != "foo"));
assert(!(path.isroot(&buf)));
// "/foo" — absolute but not root.
buf.buf[0] = SEP; buf.end = 1;
assert(!(push(&buf, "foo")! != "/foo"));
assert(!(isroot(&buf)));
buf.buf[0] = path.SEP; buf.end = 1;
assert(!(path.push(&buf, "foo")! != "/foo"));
assert(!(path.isroot(&buf)));
// str-arm (buffer.ha:47): only the bare separator is root.
let ins: [4]str;
@@ -66,7 +66,7 @@ import path;
let i: i32 = 0;
for (i < 4) {
let got: i32 = 0;
if (isroot(ins[i])) { got = 1; };
if (path.isroot(ins[i])) { got = 1; };
assert(!(got != want[i]));
i += 1;
};
@@ -76,10 +76,10 @@ import path;
// buffer views the byte prefix.
@test fn string_cases() void = {
let buf = buffer { ... };
assert(!(string(&buf) != "."));
assert(!(push(&buf, "foo")! != "foo"));
assert(!(string(&buf) != "foo"));
let buf: path.buffer;
assert(!(path.string(&buf) != "."));
assert(!(path.push(&buf, "foo")! != "foo"));
assert(!(path.string(&buf) != "foo"));
};
// ref/hare/path/buffer.ha:55-77. Rewrites '/'→SEP into a static buffer;
@@ -95,7 +95,7 @@ import path;
ins[3]=""; want[3]="";
let i: i32 = 0;
for (i < 4) {
assert(!(local(ins[i])! != want[i]));
assert(!(path.local(ins[i])! != want[i]));
i += 1;
};
};

View File

@@ -29,8 +29,8 @@ import path;
inputs[9]="/home//dwc//test"; wantdir[9]="/home//dwc"; wantbase[9]="test";
let i: i32 = 0;
for (i < 10) {
assert(!(dirname(inputs[i]) != wantdir[i]));
assert(!(basename(inputs[i]) != wantbase[i]));
assert(!(path.dirname(inputs[i]) != wantdir[i]));
assert(!(path.basename(inputs[i]) != wantbase[i]));
i += 1;
};
};

View File

@@ -19,8 +19,8 @@ import path;
// appendnorm @test is needed.
@test fn push_cases() void = {
let buf = buffer { ... };
assert(!(string(&buf) != "."));
let buf: path.buffer;
assert(!(path.string(&buf) != "."));
// current-dir + parent-dir invariants (stack.ha:82-88). Single
// segment per row → table-driven sequential apply.
@@ -33,13 +33,13 @@ import path;
segs[4]="."; wants[4]="..";
let i: i32 = 0;
for (i < 5) {
assert(!(push(&buf, segs[i])! != wants[i]));
assert(!(path.push(&buf, segs[i])! != wants[i]));
i += 1;
};
// set(&buf) resets to "." (stack.ha:91). set forwards an EMPTY
// variadic into push (KEN-oracle flag 1: zero-arg gather+forward).
assert(!(set(&buf)! != "."));
assert(!(path.set(&buf)! != "."));
// regular path + parent (stack.ha:101-104, minus the local() row).
let segs2: [3]str;
@@ -49,25 +49,25 @@ import path;
segs2[2]=".."; wants2[2]=".";
let k: i32 = 0;
for (k < 3) {
assert(!(push(&buf, segs2[k])! != wants2[k]));
assert(!(path.push(&buf, segs2[k])! != wants2[k]));
k += 1;
};
// multi-segment (stack.ha:107-111). Variadic arity varies (1 or 2)
// → inline.
assert(!(push(&buf, "a", "b")! != "a/b"));
assert(!(push(&buf, "..", "c")! != "a/c"));
assert(!(push(&buf, "..")! != "a"));
assert(!(path.push(&buf, "a", "b")! != "a/b"));
assert(!(path.push(&buf, "..", "c")! != "a/c"));
assert(!(path.push(&buf, "..")! != "a"));
// stack.ha:110; local()→literal, SEP='/' on Linux, proper local() rides c3
assert(!(push(&buf, "/d")! != "a/d"));
assert(!(push(&buf, "..", "..")! != ".")); // stack.ha:111
assert(!(path.push(&buf, "/d")! != "a/d"));
assert(!(path.push(&buf, "..", "..")! != ".")); // stack.ha:111
// leading-SEP segment into an EMPTY buffer exercises push's
// `j==0 && buf.end==0` root-seed arm (stack.ha:18-20), unreached
// by the relative rows above. Hare covers it via local("/")-seeded
// rows that defer to c3; literal "/foo" stands in (SEP='/' on Linux).
assert(!(set(&buf)! != "."));
assert(!(push(&buf, "/foo")! != "/foo"));
assert(!(path.set(&buf)! != "."));
assert(!(path.push(&buf, "/foo")! != "/foo"));
};
// ref/hare/path/stack.ha:172-180. Parent dir; root → root; empty → "..".
@@ -76,7 +76,7 @@ import path;
// not "") can share the table.
@test fn parent_cases() void = {
let buf = buffer { ... };
let buf: path.buffer;
let ins: [5]str;
let want: [5]str;
ins[0]="/usr/lib"; want[0]="/usr";
@@ -87,8 +87,8 @@ import path;
let i: i32 = 0;
for (i < 5) {
buf.end = 0;
push(&buf, ins[i])!;
assert(!(parent(&buf)! != want[i]));
path.push(&buf, ins[i])!;
assert(!(path.parent(&buf)! != want[i]));
i += 1;
};
};
@@ -99,30 +99,30 @@ import path;
// #48 respelling didn't smuggle in pop's buf.end mutation.
@test fn popsplit_cases() void = {
let buf = buffer { ... };
let buf: path.buffer;
// empty
assert(!(!(pop(&buf) is void)));
assert(!(string(&buf) != "."));
assert(!(!(path.pop(&buf) is void)));
assert(!(path.string(&buf) != "."));
// root dir
buf.end = 0;
assert(!(push(&buf, "/")! != "/"));
assert(!(!(pop(&buf) is void)));
assert(!(string(&buf) != "/"));
assert(!(path.push(&buf, "/")! != "/"));
assert(!(!(path.pop(&buf) is void)));
assert(!(path.string(&buf) != "/"));
// relative file — peek is NON-mutating
buf.end = 0;
assert(!(push(&buf, "foo")! != "foo"));
assert(!(peek(&buf) as str != "foo"));
assert(!(string(&buf) != "foo"));
assert(!(pop(&buf) as str != "foo"));
assert(!(string(&buf) != "."));
assert(!(path.push(&buf, "foo")! != "foo"));
assert(!(path.peek(&buf) as str != "foo"));
assert(!(path.string(&buf) != "foo"));
assert(!(path.pop(&buf) as str != "foo"));
assert(!(path.string(&buf) != "."));
// absolute file
buf.end = 0;
assert(!(push(&buf, "/foo")! != "/foo"));
assert(!(peek(&buf) as str != "foo"));
assert(!(pop(&buf) as str != "foo"));
assert(!(string(&buf) != "/"));
assert(!(path.push(&buf, "/foo")! != "/foo"));
assert(!(path.peek(&buf) as str != "foo"));
assert(!(path.pop(&buf) as str != "foo"));
assert(!(path.string(&buf) != "/"));
};

View File

@@ -21,12 +21,10 @@
// the regex/capture struct shapes, and finish(). A failing row aborts
// via the assert/abort builtin (task #5 @test conversion).
//
// Struct literals below name the type UNQUALIFIED (`inst_charset { … }`,
// not `regex.inst_charset { … }`): the parser rejects a module-qualified
// name in struct-literal position (#29), and the imported EXPORTED type
// is in scope unqualified. These reach only exported types — the #29
// axis, distinct from the white-box privacy boundary handled by the
// whitebox_test.ww split above.
// The parser rejects a qualified name in struct-literal position (#29), so
// the few struct payload rows below initialize a qualified typed local before
// injecting it into the exported union. This stays distinct from the
// white-box privacy boundary handled by the whitebox_test.ww split above.
package regex_test;
import regex;
@@ -107,7 +105,10 @@ import strings;
// inst_charset carries a struct payload; its fields survive the union
// round-trip.
@test fn charset_payload() void = {
let c: regex.inst = (inst_charset { idx = 3, is_positive = true });
let value: regex.inst_charset;
value.idx = 3;
value.is_positive = true;
let c: regex.inst = value;
match (c) {
case let cs: regex.inst_charset => {
assert(!(cs.idx != (3: size)));
@@ -123,9 +124,12 @@ import strings;
// diverges cs≠ww (#26 — the wwstage frames it wider), so
// asserting the bounds here would seed a rule-10-divergent fixture.
@test fn repeat_payload() void = {
let r: regex.inst = (inst_repeat {
id = 1, origin = 4, min = (2: size), max = void,
});
let value: regex.inst_repeat;
value.id = 1;
value.origin = 4;
value.min = (2: size);
value.max = void;
let r: regex.inst = value;
match (r) {
case let rp: regex.inst_repeat => {
assert(!(rp.id != (1: size)));
@@ -138,13 +142,12 @@ import strings;
// The regex/capture structs hold their fields; finish() is a no-op
// (no-free runtime) and must accept a built regex.
@test fn struct_shapes_and_finish() void = {
let cap: regex.capture = capture {
content = "abc",
start = 0,
start_bytesize = 0,
end = 3,
end_bytesize = 3,
};
let cap: regex.capture;
cap.content = "abc";
cap.start = 0;
cap.start_bytesize = 0;
cap.end = 3;
cap.end_bytesize = 3;
assert(!(cap.content.len != 3));
assert(!(cap.end != (3: size)));
@@ -256,15 +259,18 @@ import strings;
// the documented no-op (no-free runtime), so the header must stay
// readable after — a future real free changes this row consciously.
// The local is spelled []regex.capture, not the regex.result alias:
// wwstage falsely loud-bails appending a struct literal onto an
// alias-typed dst (#20); the alias + signature stay exercised by the
// result_free call itself. Reverts to `regex.result` when #20 lands.
// wwstage falsely loud-bails appending a capture value onto an alias-typed
// dst (#20); the alias + signature stay exercised by result_free itself.
// Reverts to `regex.result` when #20 lands.
@test fn result_free_noop() void = {
let res: []regex.capture;
append(res, capture {
content = "x", start = 0, start_bytesize = 0,
end = 1, end_bytesize = 1,
});
let value: regex.capture;
value.content = "x";
value.start = 0;
value.start_bytesize = 0;
value.end = 1;
value.end_bytesize = 1;
append(res, value);
regex.result_free(res);
assert(!(len(res) != 1));
assert(!(res[0].end != (1: size)));
@@ -872,16 +878,16 @@ type cerow = struct {
// class items as -2 (presence sentinel — fn-ptr address not stable).
// The element binds structurally, not via the `charset` alias — an
// alias-typed slice local's index read mis-scales in wwstage (#68).
fn cssig(cs: [](charset_lit_item | charset_range_item |
charset_class_item), k: size) i64 = {
let cur: (charset_lit_item | charset_range_item |
charset_class_item) = cs[k];
fn cssig(cs: [](regex.charset_lit_item | regex.charset_range_item |
regex.charset_class_item), k: size) i64 = {
let cur: (regex.charset_lit_item | regex.charset_range_item |
regex.charset_class_item) = cs[k];
match (cur) {
case let l: charset_lit_item =>
case let l: regex.charset_lit_item =>
return 1000000 + ((l: rune): i64);
case let range: charset_range_item =>
case let range: regex.charset_range_item =>
return (range.0: i64) * 10000 + (range.1: i64);
case charset_class_item => return -2; // fn-ptr address not stable
case regex.charset_class_item => return -2; // fn-ptr address not stable
case => return -1;
};
};
@@ -928,8 +934,8 @@ type cscase = struct {
match (c) {
case let re: regex.regex => {
assert(!(re.charsets.len != 1));
let cs0: [](charset_lit_item | charset_range_item |
charset_class_item) = re.charsets[0];
let cs0: [](regex.charset_lit_item | regex.charset_range_item |
regex.charset_class_item) = re.charsets[0];
assert(!((len(cs0): i32) != rows[i].ecnt));
let k: i32 = 0;
for (k < rows[i].ecnt) {
@@ -1715,8 +1721,8 @@ type smcase = struct {
match (c) {
case let re: regex.regex => {
assert(!(re.charsets.len != 1));
let cs0: [](charset_lit_item | charset_range_item |
charset_class_item) = re.charsets[0];
let cs0: [](regex.charset_lit_item | regex.charset_range_item |
regex.charset_class_item) = re.charsets[0];
assert(!((len(cs0): i32) != 1));
assert(!(cssig(cs0, 0) != -2));
regex.finish(&re);

View File

@@ -28,25 +28,25 @@ fn fstreq(a: str, b: str) bool = {
};
fn chk(n: f64, want: str) bool = {
return fstreq(f64tos(n), want);
return fstreq(strconv.f64tos(n), want);
};
// rt64 — bit-exact round-trip: render then parse back must reproduce the
// exact bits. The parse-back re-runs strconv's decimal slow path.
fn rt64(x: f64) bool = {
match (stof64(f64tos(x), base.DEC)) {
match (strconv.stof64(strconv.f64tos(x), strconv.base.DEC)) {
case let v: f64 => { return math.f64bits(v) == math.f64bits(x); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
case let e: strconv.invalid => { return false; };
case let e: strconv.overflow => { return false; };
};
return false;
};
fn rt32(x: f32) bool = {
match (stof32(f32tos(x), base.DEC)) {
match (strconv.stof32(strconv.f32tos(x), strconv.base.DEC)) {
case let v: f32 => { return math.f32bits(v) == math.f32bits(x); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
case let e: strconv.invalid => { return false; };
case let e: strconv.overflow => { return false; };
};
return false;
};
@@ -96,7 +96,7 @@ fn rt32(x: f32) bool = {
};
fn chkf32(n: f32, want: str) bool = {
return fstreq(f32tos(n), want);
return fstreq(strconv.f32tos(n), want);
};
// ftos_test.ha tcs G/void rows (the "pass for both f32 and f64" set) —

View File

@@ -14,177 +14,177 @@ package strconv_test;
import strconv;
fn cki(id: i32, s: str, b: base, want: i64) void = {
match (stoi64(s, b)) {
fn cki(id: i32, s: str, b: strconv.base, want: i64) void = {
match (strconv.stoi64(s, b)) {
case let v: i64 => assert(!(v != want));
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
};
fn cki_inv(id: i32, s: str, b: base, idx: i32) void = {
match (stoi64(s, b)) {
fn cki_inv(id: i32, s: str, b: strconv.base, idx: i32) void = {
match (strconv.stoi64(s, b)) {
case let v: i64 => abort();
case let e: invalid => assert(!(e: i32 != idx));
case let e: overflow => abort();
case let e: strconv.invalid => assert(!(e: i32 != idx));
case let e: strconv.overflow => abort();
};
};
fn cki_ovf(id: i32, s: str, b: base) void = {
match (stoi64(s, b)) {
fn cki_ovf(id: i32, s: str, b: strconv.base) void = {
match (strconv.stoi64(s, b)) {
case let v: i64 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
};
fn cku(id: i32, s: str, b: base, want: u64) void = {
match (stou64(s, b)) {
fn cku(id: i32, s: str, b: strconv.base, want: u64) void = {
match (strconv.stou64(s, b)) {
case let v: u64 => assert(!(v != want));
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
};
fn cku_inv(id: i32, s: str, b: base, idx: i32) void = {
match (stou64(s, b)) {
fn cku_inv(id: i32, s: str, b: strconv.base, idx: i32) void = {
match (strconv.stou64(s, b)) {
case let v: u64 => abort();
case let e: invalid => assert(!(e: i32 != idx));
case let e: overflow => abort();
case let e: strconv.invalid => assert(!(e: i32 != idx));
case let e: strconv.overflow => abort();
};
};
fn cku_ovf(id: i32, s: str, b: base) void = {
match (stou64(s, b)) {
fn cku_ovf(id: i32, s: str, b: strconv.base) void = {
match (strconv.stou64(s, b)) {
case let v: u64 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
};
fn cki32_ovf(id: i32, s: str, b: base) void = {
match (stoi32(s, b)) {
fn cki32_ovf(id: i32, s: str, b: strconv.base) void = {
match (strconv.stoi32(s, b)) {
case let v: i32 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
};
fn cki32(id: i32, s: str, b: base, want: i32) void = {
match (stoi32(s, b)) {
fn cki32(id: i32, s: str, b: strconv.base, want: i32) void = {
match (strconv.stoi32(s, b)) {
case let v: i32 => assert(!(v != want));
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
};
fn ck_int(id: i32, s: str, b: base, want: int) void = {
match (stoi(s, b)) {
fn ck_int(id: i32, s: str, b: strconv.base, want: int) void = {
match (strconv.stoi(s, b)) {
case let v: int => assert(!(v != want));
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
};
fn ck_uint(id: i32, s: str, b: base, want: uint) void = {
match (stou(s, b)) {
fn ck_uint(id: i32, s: str, b: strconv.base, want: uint) void = {
match (strconv.stou(s, b)) {
case let v: uint => assert(!(v != want));
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
};
fn ck_size(id: i32, s: str, b: base, want: size) void = {
match (stoz(s, b)) {
fn ck_size(id: i32, s: str, b: strconv.base, want: size) void = {
match (strconv.stoz(s, b)) {
case let v: size => assert(!(v != want));
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
};
fn ck_int_ovf(id: i32, s: str, b: base) void = {
match (stoi(s, b)) {
fn ck_int_ovf(id: i32, s: str, b: strconv.base) void = {
match (strconv.stoi(s, b)) {
case let v: int => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
};
fn ck_uint_ovf(id: i32, s: str, b: base) void = {
match (stou(s, b)) {
fn ck_uint_ovf(id: i32, s: str, b: strconv.base) void = {
match (strconv.stou(s, b)) {
case let v: uint => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
};
// ref/hare/strconv/stoi.ha:56-79.
@test fn test_stoi64() void = {
cki_inv(1, "", base.DEC, 0);
cki_inv(2, "abc", base.DEC, 0);
cki_inv(3, "1a", base.DEC, 1);
cki_inv(4, "+", base.DEC, 1);
cki_inv(5, "-+", base.DEC, 1);
cki_inv(6, "-z", base.DEC, 1);
cki_inv(1, "", strconv.base.DEC, 0);
cki_inv(2, "abc", strconv.base.DEC, 0);
cki_inv(3, "1a", strconv.base.DEC, 1);
cki_inv(4, "+", strconv.base.DEC, 1);
cki_inv(5, "-+", strconv.base.DEC, 1);
cki_inv(6, "-z", strconv.base.DEC, 1);
cki_ovf(7, "9223372036854775808", base.DEC);
cki_ovf(8, "-9223372036854775809", base.DEC);
cki_ovf(7, "9223372036854775808", strconv.base.DEC);
cki_ovf(8, "-9223372036854775809", strconv.base.DEC);
// The last multiply wraps to a value larger than its prefix, so a
// post-arithmetic `n < old` check misses this overflow.
cki_ovf(19, "21000000000000000000", base.DEC);
cki_ovf(19, "21000000000000000000", strconv.base.DEC);
cki(9, "0", base.DEC, 0);
cki(10, "1", base.DEC, 1);
cki(11, "+1", base.DEC, 1);
cki(12, "-1", base.DEC, -1);
cki(13, "9223372036854775807", base.DEC, 9223372036854775807i64);
cki(9, "0", strconv.base.DEC, 0);
cki(10, "1", strconv.base.DEC, 1);
cki(11, "+1", strconv.base.DEC, 1);
cki(12, "-1", strconv.base.DEC, -1);
cki(13, "9223372036854775807", strconv.base.DEC, 9223372036854775807i64);
// I64_MIN. Spelled -I64_MAX-1 (Hare's own two's-complement identity,
// stoi64 comment in stoi.ha:11) because the wwstage mis-lexes the
// direct literal -9223372036854775808 (and types.I64_MIN) to 0 —
// proj #245. The INPUT string is unaffected; stoi64 parses it to the
// correct value on both stages. This isolates the parse test from #245.
cki(14, "-9223372036854775808", base.DEC, -9223372036854775807i64 - 1i64);
cki(14, "-9223372036854775808", strconv.base.DEC, -9223372036854775807i64 - 1i64);
// width wrapper boundaries (ref/hare/strconv/stoi.ha:74-78).
cki32_ovf(15, "2147483648", base.DEC);
cki32_ovf(16, "-2147483649", base.DEC);
cki32(17, "2147483647", base.DEC, 2147483647i32);
cki32(18, "-2147483648", base.DEC, -2147483648i32);
cki32_ovf(15, "2147483648", strconv.base.DEC);
cki32_ovf(16, "-2147483649", strconv.base.DEC);
cki32(17, "2147483647", strconv.base.DEC, 2147483647i32);
cki32(18, "-2147483648", strconv.base.DEC, -2147483648i32);
};
// ref/hare/strconv/stoi.ha:81-86.
@test fn test_stoi64_bases() void = {
cki(20, "-7f", base.HEX, -127i64); // -0x7f
cki(21, "7F", base.HEX, 127i64); // 0x7f
cki(22, "37", base.OCT, 31i64); // 0o37
cki(23, "-110101", base.BIN, -53i64); // -0b110101
cki(20, "-7f", strconv.base.HEX, -127i64); // -0x7f
cki(21, "7F", strconv.base.HEX, 127i64); // 0x7f
cki(22, "37", strconv.base.OCT, 31i64); // 0o37
cki(23, "-110101", strconv.base.BIN, -53i64); // -0b110101
};
// ref/hare/strconv/stou.ha:116-130.
@test fn test_stou64() void = {
cku_inv(30, "", base.DEC, 0);
cku_inv(31, "+", base.DEC, 1);
cku_inv(32, "+a", base.DEC, 1);
cku_inv(33, "abc", base.DEC, 0);
cku_inv(34, "1a", base.DEC, 1);
cku_inv(30, "", strconv.base.DEC, 0);
cku_inv(31, "+", strconv.base.DEC, 1);
cku_inv(32, "+a", strconv.base.DEC, 1);
cku_inv(33, "abc", strconv.base.DEC, 0);
cku_inv(34, "1a", strconv.base.DEC, 1);
cku_ovf(35, "18446744073709551616", base.DEC);
cku_ovf(36, "184467440737095516150", base.DEC);
cku_ovf(37, "-1", base.DEC);
cku_ovf(46, "21000000000000000000", base.DEC);
cku_ovf(35, "18446744073709551616", strconv.base.DEC);
cku_ovf(36, "184467440737095516150", strconv.base.DEC);
cku_ovf(37, "-1", strconv.base.DEC);
cku_ovf(46, "21000000000000000000", strconv.base.DEC);
cku(38, "0", base.DEC, 0u64);
cku(39, "1", base.DEC, 1u64);
cku(40, "18446744073709551615", base.DEC, 18446744073709551615u64);
cku(38, "0", strconv.base.DEC, 0u64);
cku(39, "1", strconv.base.DEC, 1u64);
cku(40, "18446744073709551615", strconv.base.DEC, 18446744073709551615u64);
};
// ref/hare/strconv/stou.ha:132-138.
@test fn test_stou64_bases() void = {
cku(41, "f", base.HEX_LOWER, 15u64); // 0xf
cku(42, "7f", base.HEX, 127u64); // 0x7f
cku(43, "7F", base.HEX, 127u64); // 0x7f
cku(44, "37", base.OCT, 31u64); // 0o37
cku(45, "110101", base.BIN, 53u64); // 0b110101
cku(41, "f", strconv.base.HEX_LOWER, 15u64); // 0xf
cku(42, "7f", strconv.base.HEX, 127u64); // 0x7f
cku(43, "7F", strconv.base.HEX, 127u64); // 0x7f
cku(44, "37", strconv.base.OCT, 31u64); // 0o37
cku(45, "110101", strconv.base.BIN, 53u64); // 0b110101
};
// stoi / stou / stoz — int/uint/size machine-word wrappers
@@ -192,102 +192,102 @@ fn ck_uint_ovf(id: i32, s: str, b: base) void = {
// 8B, so the iN/uN clamp is a no-op: the full i64/u64 range parses with
// no spurious overflow. That no-clamp fidelity is what these check.
@test fn test_stoi_stou_stoz() void = {
ck_int(50, "0", base.DEC, 0);
ck_int(51, "-1", base.DEC, -1);
ck_int(52, "9223372036854775807", base.DEC, 9223372036854775807i64: int); // I64_MAX fits int
ck_int_ovf(53, "9223372036854775808", base.DEC);
ck_int_ovf(54, "-9223372036854775809", base.DEC);
ck_int(50, "0", strconv.base.DEC, 0);
ck_int(51, "-1", strconv.base.DEC, -1);
ck_int(52, "9223372036854775807", strconv.base.DEC, 9223372036854775807i64: int); // I64_MAX fits int
ck_int_ovf(53, "9223372036854775808", strconv.base.DEC);
ck_int_ovf(54, "-9223372036854775809", strconv.base.DEC);
ck_uint(55, "0", base.DEC, 0u64: uint);
ck_uint(56, "18446744073709551615", base.DEC, 18446744073709551615u64: uint); // U64_MAX fits uint
ck_uint_ovf(57, "18446744073709551616", base.DEC);
ck_uint_ovf(58, "-1", base.DEC);
ck_uint(55, "0", strconv.base.DEC, 0u64: uint);
ck_uint(56, "18446744073709551615", strconv.base.DEC, 18446744073709551615u64: uint); // U64_MAX fits uint
ck_uint_ovf(57, "18446744073709551616", strconv.base.DEC);
ck_uint_ovf(58, "-1", strconv.base.DEC);
ck_size(59, "0", base.DEC, 0u64: size);
ck_size(60, "18446744073709551615", base.DEC, 18446744073709551615u64: size); // U64_MAX fits size
ck_size(59, "0", strconv.base.DEC, 0u64: size);
ck_size(60, "18446744073709551615", strconv.base.DEC, 18446744073709551615u64: size); // U64_MAX fits size
// bases route through the same parseint core.
ck_int(61, "-7f", base.HEX, -127i64: int); // -0x7f
ck_uint(62, "110101", base.BIN, 53u64: uint); // 0b110101
ck_int(61, "-7f", strconv.base.HEX, -127i64: int); // -0x7f
ck_uint(62, "110101", strconv.base.BIN, 53u64: uint); // 0b110101
};
@test fn test_narrow_parse_boundaries() void = {
match (stoi16("32767", base.DEC)) {
match (strconv.stoi16("32767", strconv.base.DEC)) {
case let v: i16 => assert(v == 32767i16);
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
match (stoi16("-32768", base.DEC)) {
match (strconv.stoi16("-32768", strconv.base.DEC)) {
case let v: i16 => assert(v == -32768i16);
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
match (stoi16("32768", base.DEC)) {
match (strconv.stoi16("32768", strconv.base.DEC)) {
case let v: i16 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
match (stoi16("-32769", base.DEC)) {
match (strconv.stoi16("-32769", strconv.base.DEC)) {
case let v: i16 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
match (stoi8("127", base.DEC)) {
match (strconv.stoi8("127", strconv.base.DEC)) {
case let v: i8 => assert(v == 127i8);
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
match (stoi8("-128", base.DEC)) {
match (strconv.stoi8("-128", strconv.base.DEC)) {
case let v: i8 => assert(v == -128i8);
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
match (stoi8("128", base.DEC)) {
match (strconv.stoi8("128", strconv.base.DEC)) {
case let v: i8 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
match (stoi8("-129", base.DEC)) {
match (strconv.stoi8("-129", strconv.base.DEC)) {
case let v: i8 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
match (stou16("65535", base.DEC)) {
match (strconv.stou16("65535", strconv.base.DEC)) {
case let v: u16 => assert(v == 65535u16);
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
match (stou16("65536", base.DEC)) {
match (strconv.stou16("65536", strconv.base.DEC)) {
case let v: u16 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
match (stou8("255", base.DEC)) {
match (strconv.stou8("255", strconv.base.DEC)) {
case let v: u8 => assert(v == 255u8);
case let e: invalid => abort();
case let e: overflow => abort();
case let e: strconv.invalid => abort();
case let e: strconv.overflow => abort();
};
match (stou8("256", base.DEC)) {
match (strconv.stou8("256", strconv.base.DEC)) {
case let v: u8 => abort();
case let e: invalid => abort();
case let e: overflow => { };
case let e: strconv.invalid => abort();
case let e: strconv.overflow => { };
};
};
@test fn test_strerror_static() void = {
let inv: invalid = 0: invalid;
let ie: error = inv;
let ia: str = strerror(ie);
let ib: str = strerror(ie);
let inv: strconv.invalid = 0: strconv.invalid;
let ie: strconv.error = inv;
let ia: str = strconv.strerror(ie);
let ib: str = strconv.strerror(ie);
assert(ia.ptr == ib.ptr);
assert(streq(ia, "input is not a valid number"));
let ov: overflow;
let oe: error = ov;
let oa: str = strerror(oe);
let ob: str = strerror(oe);
let ov: strconv.overflow;
let oe: strconv.error = ov;
let oa: str = strconv.strerror(oe);
let ob: str = strconv.strerror(oe);
assert(oa.ptr == ob.ptr);
assert(streq(oa, "input number doesn't fit target type"));
};
@@ -314,48 +314,48 @@ fn cks(id: i32, got: str, want: str) void = {
// ref/hare/strconv/utos.ha:74-83.
@test fn test_u64tos_bases() void = {
cks(70, u64tos(26u64, base.BIN), "11010"); // 0b11010
cks(71, u64tos(342391u64, base.OCT), "1234567"); // 0o1234567
cks(72, u64tos(123456789u64, base.DEC), "123456789");
cks(73, u64tos(81985529216486895u64, base.HEX), "123456789ABCDEF"); // 0x123456789ABCDEF
cks(74, u64tos(81985529216486895u64, base.HEX_UPPER), "123456789ABCDEF");
cks(75, u64tos(81985529216486895u64, base.HEX_LOWER), "123456789abcdef");
cks(76, u64tos(18446744073709551615u64, base.BIN), // U64_MAX
cks(70, strconv.u64tos(26u64, strconv.base.BIN), "11010"); // 0b11010
cks(71, strconv.u64tos(342391u64, strconv.base.OCT), "1234567"); // 0o1234567
cks(72, strconv.u64tos(123456789u64, strconv.base.DEC), "123456789");
cks(73, strconv.u64tos(81985529216486895u64, strconv.base.HEX), "123456789ABCDEF"); // 0x123456789ABCDEF
cks(74, strconv.u64tos(81985529216486895u64, strconv.base.HEX_UPPER), "123456789ABCDEF");
cks(75, strconv.u64tos(81985529216486895u64, strconv.base.HEX_LOWER), "123456789abcdef");
cks(76, strconv.u64tos(18446744073709551615u64, strconv.base.BIN), // U64_MAX
"1111111111111111111111111111111111111111111111111111111111111111");
};
// ref/hare/strconv/utos.ha:85-103.
@test fn test_u64tos() void = {
cks(77, u64tos(1234u64, base.DEC), "1234");
cks(78, u64tos(4321u64, base.DEC), "4321");
cks(79, u64tos(0u64, base.DEC), "0"); // U64_MIN
cks(80, u64tos(18446744073709551615u64, base.DEC), "18446744073709551615"); // U64_MAX
cks(77, strconv.u64tos(1234u64, strconv.base.DEC), "1234");
cks(78, strconv.u64tos(4321u64, strconv.base.DEC), "4321");
cks(79, strconv.u64tos(0u64, strconv.base.DEC), "0"); // U64_MIN
cks(80, strconv.u64tos(18446744073709551615u64, strconv.base.DEC), "18446744073709551615"); // U64_MAX
};
// ref/hare/strconv/itos.ha:54-63.
@test fn test_i64tos_bases() void = {
cks(81, i64tos(26i64, base.BIN), "11010");
cks(82, i64tos(342391i64, base.OCT), "1234567");
cks(83, i64tos(123456789i64, base.DEC), "123456789");
cks(84, i64tos(81985529216486895i64, base.HEX), "123456789ABCDEF");
cks(85, i64tos(81985529216486895i64, base.HEX_UPPER), "123456789ABCDEF");
cks(86, i64tos(81985529216486895i64, base.HEX_LOWER), "123456789abcdef");
cks(81, strconv.i64tos(26i64, strconv.base.BIN), "11010");
cks(82, strconv.i64tos(342391i64, strconv.base.OCT), "1234567");
cks(83, strconv.i64tos(123456789i64, strconv.base.DEC), "123456789");
cks(84, strconv.i64tos(81985529216486895i64, strconv.base.HEX), "123456789ABCDEF");
cks(85, strconv.i64tos(81985529216486895i64, strconv.base.HEX_UPPER), "123456789ABCDEF");
cks(86, strconv.i64tos(81985529216486895i64, strconv.base.HEX_LOWER), "123456789abcdef");
// I64_MIN binary = '1' + 63 zeros, prefixed '-'. Spelled -I64_MAX-1
// (proj #245: wwstage mis-lexes the direct 2^63 / types.I64_MIN literal).
cks(87, i64tos(-9223372036854775807i64 - 1i64, base.BIN),
cks(87, strconv.i64tos(-9223372036854775807i64 - 1i64, strconv.base.BIN),
"-1000000000000000000000000000000000000000000000000000000000000000");
};
// ref/hare/strconv/itos.ha:65-87.
@test fn test_i64tos() void = {
cks(88, i64tos(1234i64, base.DEC), "1234");
cks(89, i64tos(4321i64, base.DEC), "4321");
cks(90, i64tos(-1337i64, base.DEC), "-1337");
cks(91, i64tos(0i64, base.DEC), "0");
cks(92, i64tos(9223372036854775807i64, base.DEC), "9223372036854775807"); // I64_MAX
cks(88, strconv.i64tos(1234i64, strconv.base.DEC), "1234");
cks(89, strconv.i64tos(4321i64, strconv.base.DEC), "4321");
cks(90, strconv.i64tos(-1337i64, strconv.base.DEC), "-1337");
cks(91, strconv.i64tos(0i64, strconv.base.DEC), "0");
cks(92, strconv.i64tos(9223372036854775807i64, strconv.base.DEC), "9223372036854775807"); // I64_MAX
// drew probe-1: NEG-of-I64_MIN + i64→u64 reinterpret preserves the
// two's-complement bit pattern. I64_MIN spelled -I64_MAX-1 (proj #245).
cks(93, i64tos(-9223372036854775807i64 - 1i64, base.DEC),
cks(93, strconv.i64tos(-9223372036854775807i64 - 1i64, strconv.base.DEC),
"-9223372036854775808");
};
@@ -363,11 +363,11 @@ fn cks(id: i32, got: str, want: str) void = {
// all 8B, so the full i64/u64 range renders untruncated. ww-authored
// (Hare's wrappers are trivial aliases): itos.ha:37-52, utos.ha:44-72.
@test fn test_word_wrappers() void = {
cks(94, itos(-1337, base.DEC), "-1337");
cks(95, itos(9223372036854775807i64: int, base.DEC), "9223372036854775807");
cks(96, utos(18446744073709551615u64: uint, base.DEC), "18446744073709551615");
cks(97, ztos(255u64: size, base.HEX), "FF");
cks(98, uptrtos(4096u64: uintptr, base.DEC), "4096");
cks(99, i32tos(-2147483648i32, base.DEC), "-2147483648");
cks(100, u8tos(255u8, base.HEX_LOWER), "ff");
cks(94, strconv.itos(-1337, strconv.base.DEC), "-1337");
cks(95, strconv.itos(9223372036854775807i64: int, strconv.base.DEC), "9223372036854775807");
cks(96, strconv.utos(18446744073709551615u64: uint, strconv.base.DEC), "18446744073709551615");
cks(97, strconv.ztos(255u64: size, strconv.base.HEX), "FF");
cks(98, strconv.uptrtos(4096u64: uintptr, strconv.base.DEC), "4096");
cks(99, strconv.i32tos(-2147483648i32, strconv.base.DEC), "-2147483648");
cks(100, strconv.u8tos(255u8, strconv.base.HEX_LOWER), "ff");
};

View File

@@ -12,75 +12,75 @@ import strconv;
import math;
fn chk64(s: str, b: base, want: f64) bool = {
match (stof64(s, b)) {
fn chk64(s: str, b: strconv.base, want: f64) bool = {
match (strconv.stof64(s, b)) {
case let v: f64 => { return math.f64bits(v) == math.f64bits(want); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
case let e: strconv.invalid => { return false; };
case let e: strconv.overflow => { return false; };
};
return false;
};
fn chk32(s: str, b: base, want: f32) bool = {
match (stof32(s, b)) {
fn chk32(s: str, b: strconv.base, want: f32) bool = {
match (strconv.stof32(s, b)) {
case let v: f32 => { return math.f32bits(v) == math.f32bits(want); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
case let e: strconv.invalid => { return false; };
case let e: strconv.overflow => { return false; };
};
return false;
};
fn ovf64(s: str, b: base) bool = {
match (stof64(s, b)) {
fn ovf64(s: str, b: strconv.base) bool = {
match (strconv.stof64(s, b)) {
case let v: f64 => { return false; };
case let e: invalid => { return false; };
case let e: overflow => { return true; };
case let e: strconv.invalid => { return false; };
case let e: strconv.overflow => { return true; };
};
return false;
};
fn ovf32(s: str, b: base) bool = {
match (stof32(s, b)) {
fn ovf32(s: str, b: strconv.base) bool = {
match (strconv.stof32(s, b)) {
case let v: f32 => { return false; };
case let e: invalid => { return false; };
case let e: overflow => { return true; };
case let e: strconv.invalid => { return false; };
case let e: strconv.overflow => { return true; };
};
return false;
};
// inv64 — the invalid byte-index, or -1 if not invalid.
fn inv64(s: str) i32 = {
match (stof64(s, base.DEC)) {
match (strconv.stof64(s, strconv.base.DEC)) {
case let v: f64 => { return -1; };
case let e: invalid => { return (e: i32); };
case let e: overflow => { return -1; };
case let e: strconv.invalid => { return (e: i32); };
case let e: strconv.overflow => { return -1; };
};
return -1;
};
fn inv32(s: str) i32 = {
match (stof32(s, base.DEC)) {
match (strconv.stof32(s, strconv.base.DEC)) {
case let v: f32 => { return -1; };
case let e: invalid => { return (e: i32); };
case let e: overflow => { return -1; };
case let e: strconv.invalid => { return (e: i32); };
case let e: strconv.overflow => { return -1; };
};
return -1;
};
fn nan64(s: str) bool = {
match (stof64(s, base.DEC)) {
match (strconv.stof64(s, strconv.base.DEC)) {
case let v: f64 => { return math.isnan(v); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
case let e: strconv.invalid => { return false; };
case let e: strconv.overflow => { return false; };
};
return false;
};
fn nan32(s: str) bool = {
match (stof32(s, base.DEC)) {
match (strconv.stof32(s, strconv.base.DEC)) {
case let v: f32 => { return math.isnan((v: f64)); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
case let e: strconv.invalid => { return false; };
case let e: strconv.overflow => { return false; };
};
return false;
};
@@ -93,20 +93,20 @@ fn nan32(s: str) bool = {
let nzero: f64 = math.f64frombits(1u64 << 63u64); // -0.0 (1<<63 dodges the I64_MIN-literal emit bug #144)
let subn: f64 = math.f64frombits(0x0000000000000001u64); // 5e-324
assert(!(!chk64("0", base.DEC, 0.0)));
assert(!(!chk64("200", base.DEC, 200.0)));
assert(!(!chk64("12345", base.DEC, 12345.0)));
assert(!(!chk64("+112233445566778899", base.DEC, 1.122334455667789e17)));
assert(!(!chk64("3.14", base.DEC, 3.14)));
assert(!(!chk64("2.99792458E+8", base.DEC, 299792458.0)));
assert(!(!chk64("6.022e23", base.DEC, 6.022e23)));
assert(!(!ovf64("1e310", base.DEC)));
assert(!(!chk64("9007199254740991", base.DEC, 9007199254740991.0)));
assert(!(!chk64("90071992547409915", base.DEC, 90071992547409920.0)));
assert(!(!chk64("90071992547409925", base.DEC, 90071992547409920.0)));
assert(!(!chk64("2.2250738585072014e-308", base.DEC, 2.2250738585072014e-308)));
assert(!(!chk64("-1e-324", base.DEC, nzero)));
assert(!(!chk64("5e-324", base.DEC, subn)));
assert(!(!chk64("0", strconv.base.DEC, 0.0)));
assert(!(!chk64("200", strconv.base.DEC, 200.0)));
assert(!(!chk64("12345", strconv.base.DEC, 12345.0)));
assert(!(!chk64("+112233445566778899", strconv.base.DEC, 1.122334455667789e17)));
assert(!(!chk64("3.14", strconv.base.DEC, 3.14)));
assert(!(!chk64("2.99792458E+8", strconv.base.DEC, 299792458.0)));
assert(!(!chk64("6.022e23", strconv.base.DEC, 6.022e23)));
assert(!(!ovf64("1e310", strconv.base.DEC)));
assert(!(!chk64("9007199254740991", strconv.base.DEC, 9007199254740991.0)));
assert(!(!chk64("90071992547409915", strconv.base.DEC, 90071992547409920.0)));
assert(!(!chk64("90071992547409925", strconv.base.DEC, 90071992547409920.0)));
assert(!(!chk64("2.2250738585072014e-308", strconv.base.DEC, 2.2250738585072014e-308)));
assert(!(!chk64("-1e-324", strconv.base.DEC, nzero)));
assert(!(!chk64("5e-324", strconv.base.DEC, subn)));
// Decimal-engine edge probes migrated here when the white-box
// decimaltest.ww retired (#16): the external-test idiom can't reach
@@ -117,20 +117,20 @@ fn nan32(s: str) bool = {
// Micro-gap (rule-7, honest): decimal_shift's k=0 early-return no-op
// is a trivial guard, not reached transitively by any slow-path input
// — consciously un-migrated, not silently dropped.
assert(!(!chk64("9999999999999999", base.DEC, 1.0e16)));
assert(!(!chk64("100000000000000000001", base.DEC, 1.0e20)));
assert(!(!chk64("9999999999999999", strconv.base.DEC, 1.0e16)));
assert(!(!chk64("100000000000000000001", strconv.base.DEC, 1.0e20)));
assert(!(inv64("") != 0));
assert(!(inv64("0ZO") != 1));
assert(!(inv64("1.23ezz") != 5));
assert(!(!chk64("Infinity", base.DEC, inf)));
assert(!(!chk64("+Infinity", base.DEC, inf)));
assert(!(!chk64("-Infinity", base.DEC, ninf)));
assert(!(!chk64("infinity", base.DEC, inf)));
assert(!(!chk64("inFinIty", base.DEC, inf)));
assert(!(!chk64("-infinity", base.DEC, ninf)));
assert(!(!chk64("-infiNity", base.DEC, ninf)));
assert(!(!chk64("Infinity", strconv.base.DEC, inf)));
assert(!(!chk64("+Infinity", strconv.base.DEC, inf)));
assert(!(!chk64("-Infinity", strconv.base.DEC, ninf)));
assert(!(!chk64("infinity", strconv.base.DEC, inf)));
assert(!(!chk64("inFinIty", strconv.base.DEC, inf)));
assert(!(!chk64("-infinity", strconv.base.DEC, ninf)));
assert(!(!chk64("-infiNity", strconv.base.DEC, ninf)));
assert(!(!nan64("NaN")));
assert(!(!nan64("nan")));
assert(!(!nan64("naN")));
@@ -144,34 +144,34 @@ fn nan32(s: str) bool = {
let nzero: f32 = math.f32frombits(0x80000000u32); // -0.0
let subn: f32 = math.f32frombits(0x00000001u32); // 1e-45
assert(!(!chk32("0", base.DEC, 0.0f32)));
assert(!(!chk32("1e10", base.DEC, 1.0e10f32)));
assert(!(!chk32("299792458", base.DEC, 299792458.0f32)));
assert(!(!chk32("6.022e23", base.DEC, 6.022e23f32)));
assert(!(!ovf32("1e40", base.DEC)));
assert(!(!chk32("16777215", base.DEC, 16777215.0f32)));
assert(!(!chk32("167772155", base.DEC, 167772160.0f32)));
assert(!(!chk32("167772145", base.DEC, 167772140.0f32)));
assert(!(!chk32("6.62607015e-34", base.DEC, 6.62607015e-34f32)));
assert(!(!chk32("1.1754944e-38", base.DEC, 1.1754944e-38f32)));
assert(!(!chk32("-1e-50", base.DEC, nzero)));
assert(!(!chk32("1e-45", base.DEC, subn)));
assert(!(!chk32("0", strconv.base.DEC, 0.0f32)));
assert(!(!chk32("1e10", strconv.base.DEC, 1.0e10f32)));
assert(!(!chk32("299792458", strconv.base.DEC, 299792458.0f32)));
assert(!(!chk32("6.022e23", strconv.base.DEC, 6.022e23f32)));
assert(!(!ovf32("1e40", strconv.base.DEC)));
assert(!(!chk32("16777215", strconv.base.DEC, 16777215.0f32)));
assert(!(!chk32("167772155", strconv.base.DEC, 167772160.0f32)));
assert(!(!chk32("167772145", strconv.base.DEC, 167772140.0f32)));
assert(!(!chk32("6.62607015e-34", strconv.base.DEC, 6.62607015e-34f32)));
assert(!(!chk32("1.1754944e-38", strconv.base.DEC, 1.1754944e-38f32)));
assert(!(!chk32("-1e-50", strconv.base.DEC, nzero)));
assert(!(!chk32("1e-45", strconv.base.DEC, subn)));
assert(!(inv32("") != 0));
assert(!(inv32("0ZO") != 1));
assert(!(inv32("1.23e-zz") != 6));
assert(!(!chk32("Infinity", base.DEC, inf)));
assert(!(!chk32("+Infinity", base.DEC, inf)));
assert(!(!chk32("-Infinity", base.DEC, ninf)));
assert(!(!chk32("infinity", base.DEC, inf)));
assert(!(!chk32("inFinIty", base.DEC, inf)));
assert(!(!chk32("-infinity", base.DEC, ninf)));
assert(!(!chk32("-infiniTy", base.DEC, ninf)));
assert(!(!chk32("Infinity", strconv.base.DEC, inf)));
assert(!(!chk32("+Infinity", strconv.base.DEC, inf)));
assert(!(!chk32("-Infinity", strconv.base.DEC, ninf)));
assert(!(!chk32("infinity", strconv.base.DEC, inf)));
assert(!(!chk32("inFinIty", strconv.base.DEC, inf)));
assert(!(!chk32("-infinity", strconv.base.DEC, ninf)));
assert(!(!chk32("-infiniTy", strconv.base.DEC, ninf)));
assert(!(!nan32("NaN")));
assert(!(!nan32("nan")));
assert(!(!nan32("naN")));
assert(!(!chk32("9.19100241453305036800e+20", base.DEC, 9.19100241453305036800e+20f32)));
assert(!(!chk32("9.19100241453305036800e+20", strconv.base.DEC, 9.19100241453305036800e+20f32)));
};
// ref/hare/strconv/stof.ha:590. Hex-float surface-form literals (0x1.fp-2,
@@ -179,36 +179,36 @@ fn nan32(s: str) bool = {
// has no hex-float literal lexer / no F*_MAX_NORMAL math consts.
@test fn stof64_hex() void = {
assert(!(!chk64("0p0", base.HEX, 0.0)));
assert(!(!chk64("1p0", base.HEX, 1.0)));
assert(!(!chk64("-1p0", base.HEX_LOWER, -1.0)));
assert(!(!chk64("0p0", strconv.base.HEX, 0.0)));
assert(!(!chk64("1p0", strconv.base.HEX, 1.0)));
assert(!(!chk64("-1p0", strconv.base.HEX_LOWER, -1.0)));
// 0x1.fp-2 = 1.9375 * 2^-2 = 0.484375 (exact).
assert(!(!chk64("1.fp-2", base.HEX, 0.484375)));
assert(!(!chk64("1.fp-2", strconv.base.HEX, 0.484375)));
// F64_MAX_NORMAL.
if (!chk64("1.fffffffffffffp+1023", base.HEX,
if (!chk64("1.fffffffffffffp+1023", strconv.base.HEX,
math.f64frombits(0x7FEFFFFFFFFFFFFFu64))) { abort(); };
// F64_MIN_NORMAL.
if (!chk64("1.0000000000000p-1022", base.HEX,
if (!chk64("1.0000000000000p-1022", strconv.base.HEX,
math.f64frombits(0x0010000000000000u64))) { abort(); };
// F64_MIN_SUBNORMAL.
if (!chk64("0.0000000000001p-1022", base.HEX,
if (!chk64("0.0000000000001p-1022", strconv.base.HEX,
math.f64frombits(0x0000000000000001u64))) { abort(); };
assert(!(!ovf64("1p+1024", base.HEX)));
assert(!(!chk64("0.00000000000001p-1022", base.HEX, 0.0)));
assert(!(!ovf64("1p+1024", strconv.base.HEX)));
assert(!(!chk64("0.00000000000001p-1022", strconv.base.HEX, 0.0)));
};
@test fn stof32_hex() void = {
assert(!(!chk32("0p0", base.HEX, 0.0f32)));
assert(!(!chk32("1p0", base.HEX, 1.0f32)));
assert(!(!chk32("-1p0", base.HEX, -1.0f32)));
assert(!(!chk32("1.fp-2", base.HEX, 0.484375f32)));
assert(!(!chk32("0p0", strconv.base.HEX, 0.0f32)));
assert(!(!chk32("1p0", strconv.base.HEX, 1.0f32)));
assert(!(!chk32("-1p0", strconv.base.HEX, -1.0f32)));
assert(!(!chk32("1.fp-2", strconv.base.HEX, 0.484375f32)));
// F32_MAX_NORMAL.
if (!chk32("1.fffffd586b834p+127", base.HEX,
if (!chk32("1.fffffd586b834p+127", strconv.base.HEX,
math.f32frombits(0x7F7FFFFFu32))) { abort(); };
// F32_MIN_NORMAL.
assert(!(!chk32("1.0p-126", base.HEX, math.f32frombits(0x00800000u32))));
assert(!(!chk32("1.0p-126", strconv.base.HEX, math.f32frombits(0x00800000u32))));
// F32_MIN_SUBNORMAL.
assert(!(!chk32("1.6p-150", base.HEX, math.f32frombits(0x00000001u32))));
assert(!(!ovf32("1.0p+128", base.HEX)));
assert(!(!chk32("1.0p-151", base.HEX, 0.0f32)));
assert(!(!chk32("1.6p-150", strconv.base.HEX, math.f32frombits(0x00000001u32))));
assert(!(!ovf32("1.0p+128", strconv.base.HEX)));
assert(!(!chk32("1.0p-151", strconv.base.HEX, 0.0f32)));
};

View File

@@ -10,90 +10,90 @@ package syntax_test;
import ww.syntax;
fn checknkname(k: nkind, want: str) void = {
assert(!(nkname(k) != want));
fn checknkname(k: syntax.nkind, want: str) void = {
assert(!(syntax.nkname(k) != want));
};
// One row per nkind value — same string the if-ladder returned. The
// final row pins the unknown-kind fallback ("?").
@test fn nkname_cases() void = {
checknkname(nkind.N_NONE, "none");
checknkname(nkind.N_INTLIT, "int");
checknkname(nkind.N_FLOATLIT, "float");
checknkname(nkind.N_STRLIT, "str");
checknkname(nkind.N_RUNELIT, "rune");
checknkname(nkind.N_TRUE, "true");
checknkname(nkind.N_FALSE, "false");
checknkname(nkind.N_NIL, "nil");
checknkname(nkind.N_IDENT, "id");
checknkname(syntax.nkind.N_NONE, "none");
checknkname(syntax.nkind.N_INTLIT, "int");
checknkname(syntax.nkind.N_FLOATLIT, "float");
checknkname(syntax.nkind.N_STRLIT, "str");
checknkname(syntax.nkind.N_RUNELIT, "rune");
checknkname(syntax.nkind.N_TRUE, "true");
checknkname(syntax.nkind.N_FALSE, "false");
checknkname(syntax.nkind.N_NIL, "nil");
checknkname(syntax.nkind.N_IDENT, "id");
checknkname(nkind.N_BIN, "bin");
checknkname(nkind.N_UN, "un");
checknkname(nkind.N_CALL, "call");
checknkname(nkind.N_INDEX, "index");
checknkname(nkind.N_DOT, "dot");
checknkname(nkind.N_CAST, "cast");
checknkname(nkind.N_STRUCTLIT, "structlit");
checknkname(nkind.N_ARRLIT, "arrlit");
checknkname(nkind.N_FIELD, "field");
checknkname(nkind.N_ASSIGN, "assign");
checknkname(nkind.N_ALLOC, "alloc");
checknkname(nkind.N_FREE, "free");
checknkname(nkind.N_RECV, "recv");
checknkname(nkind.N_SLICE, "slice");
checknkname(nkind.N_SPREAD, "spread");
checknkname(syntax.nkind.N_BIN, "bin");
checknkname(syntax.nkind.N_UN, "un");
checknkname(syntax.nkind.N_CALL, "call");
checknkname(syntax.nkind.N_INDEX, "index");
checknkname(syntax.nkind.N_DOT, "dot");
checknkname(syntax.nkind.N_CAST, "cast");
checknkname(syntax.nkind.N_STRUCTLIT, "structlit");
checknkname(syntax.nkind.N_ARRLIT, "arrlit");
checknkname(syntax.nkind.N_FIELD, "field");
checknkname(syntax.nkind.N_ASSIGN, "assign");
checknkname(syntax.nkind.N_ALLOC, "alloc");
checknkname(syntax.nkind.N_FREE, "free");
checknkname(syntax.nkind.N_RECV, "recv");
checknkname(syntax.nkind.N_SLICE, "slice");
checknkname(syntax.nkind.N_SPREAD, "spread");
checknkname(nkind.N_BLOCK, "block");
checknkname(nkind.N_EXPRSTMT, "exprstmt");
checknkname(nkind.N_LET, "let");
checknkname(nkind.N_RETURN, "return");
checknkname(nkind.N_IF, "if");
checknkname(nkind.N_FOR, "for");
checknkname(nkind.N_FORRANGE, "forrange");
checknkname(nkind.N_DEFER, "defer");
checknkname(nkind.N_BREAK, "break");
checknkname(nkind.N_CONTINUE, "continue");
checknkname(nkind.N_SWITCH, "switch");
checknkname(nkind.N_CASE, "case");
checknkname(syntax.nkind.N_BLOCK, "block");
checknkname(syntax.nkind.N_EXPRSTMT, "exprstmt");
checknkname(syntax.nkind.N_LET, "let");
checknkname(syntax.nkind.N_RETURN, "return");
checknkname(syntax.nkind.N_IF, "if");
checknkname(syntax.nkind.N_FOR, "for");
checknkname(syntax.nkind.N_FORRANGE, "forrange");
checknkname(syntax.nkind.N_DEFER, "defer");
checknkname(syntax.nkind.N_BREAK, "break");
checknkname(syntax.nkind.N_CONTINUE, "continue");
checknkname(syntax.nkind.N_SWITCH, "switch");
checknkname(syntax.nkind.N_CASE, "case");
checknkname(nkind.N_FILE, "file");
checknkname(nkind.N_USE, "use");
checknkname(nkind.N_DEF, "def");
checknkname(nkind.N_TYPEDECL, "typedecl");
checknkname(nkind.N_FNDECL, "fn");
checknkname(nkind.N_PARAM, "param");
checknkname(syntax.nkind.N_FILE, "file");
checknkname(syntax.nkind.N_USE, "use");
checknkname(syntax.nkind.N_DEF, "def");
checknkname(syntax.nkind.N_TYPEDECL, "typedecl");
checknkname(syntax.nkind.N_FNDECL, "fn");
checknkname(syntax.nkind.N_PARAM, "param");
checknkname(nkind.N_TNAME, "tname");
checknkname(nkind.N_TPTR, "tptr");
checknkname(nkind.N_TSLICE, "tslice");
checknkname(nkind.N_TARRAY, "tarray");
checknkname(nkind.N_TFN, "tfn");
checknkname(nkind.N_TSTRUCT, "tstruct");
checknkname(nkind.N_TFIELD, "tfield");
checknkname(nkind.N_TCHAN, "tchan");
checknkname(syntax.nkind.N_TNAME, "tname");
checknkname(syntax.nkind.N_TPTR, "tptr");
checknkname(syntax.nkind.N_TSLICE, "tslice");
checknkname(syntax.nkind.N_TARRAY, "tarray");
checknkname(syntax.nkind.N_TFN, "tfn");
checknkname(syntax.nkind.N_TSTRUCT, "tstruct");
checknkname(syntax.nkind.N_TFIELD, "tfield");
checknkname(syntax.nkind.N_TCHAN, "tchan");
checknkname(nkind.N_ATTR, "attr");
checknkname(nkind.N_TTUPLE, "ttuple");
checknkname(nkind.N_TTAGGED, "ttagged");
checknkname(nkind.N_TUPLE, "tuple");
checknkname(nkind.N_MATCH, "match");
checknkname(nkind.N_MCASE, "mcase");
checknkname(nkind.N_TRYPROP, "tryprop");
checknkname(nkind.N_TRYUNW, "tryunw");
checknkname(nkind.N_MLET, "mlet");
checknkname(nkind.N_MASSIGN, "massign");
checknkname(syntax.nkind.N_ATTR, "attr");
checknkname(syntax.nkind.N_TTUPLE, "ttuple");
checknkname(syntax.nkind.N_TTAGGED, "ttagged");
checknkname(syntax.nkind.N_TUPLE, "tuple");
checknkname(syntax.nkind.N_MATCH, "match");
checknkname(syntax.nkind.N_MCASE, "mcase");
checknkname(syntax.nkind.N_TRYPROP, "tryprop");
checknkname(syntax.nkind.N_TRYUNW, "tryunw");
checknkname(syntax.nkind.N_MLET, "mlet");
checknkname(syntax.nkind.N_MASSIGN, "massign");
checknkname(nkind.N_TYPETEST, "typetest");
checknkname(nkind.N_TYPEASSERT, "typeassert");
checknkname(nkind.N_VOIDLIT, "voidlit");
checknkname(nkind.N_TBANG, "tbang");
checknkname(nkind.N_YIELD, "yield");
checknkname(nkind.N_TENUM, "tenum");
checknkname(nkind.N_TENUMMEMBER, "tenummember");
checknkname(nkind.N_TPARAM, "tparam");
checknkname(nkind.N_LAST, "last");
checknkname(syntax.nkind.N_TYPETEST, "typetest");
checknkname(syntax.nkind.N_TYPEASSERT, "typeassert");
checknkname(syntax.nkind.N_VOIDLIT, "voidlit");
checknkname(syntax.nkind.N_TBANG, "tbang");
checknkname(syntax.nkind.N_YIELD, "yield");
checknkname(syntax.nkind.N_TENUM, "tenum");
checknkname(syntax.nkind.N_TENUMMEMBER, "tenummember");
checknkname(syntax.nkind.N_TPARAM, "tparam");
checknkname(syntax.nkind.N_LAST, "last");
// Unknown kind → the post-switch fallback. N_LAST is the highest
// named value (68); 69 is out of band, exercising the "?" tail.
checknkname(69: nkind, "?");
checknkname(69: syntax.nkind, "?");
};

View File

@@ -12,34 +12,34 @@ package syntax_test;
import ww.syntax;
@test fn scope_define_lookup() void = {
let s: *scope = newscope(nil);
let s: *syntax.scope = syntax.newscope(nil);
assert(!(s == nil));
let r1: *sym = scopedefine(s, "foo", skind.SK_VAR, nil, nil);
let r1: *syntax.sym = syntax.scopedefine(s, "foo", syntax.skind.SK_VAR, nil, nil);
assert(!(r1 == nil));
let r2: *sym = scopedefine(s, "bar", skind.SK_TYPE, nil, nil);
let r2: *syntax.sym = syntax.scopedefine(s, "bar", syntax.skind.SK_TYPE, nil, nil);
assert(!(r2 == nil));
let l1: *sym = scopelookup(s, "foo");
let l1: *syntax.sym = syntax.scopelookup(s, "foo");
assert(!(l1 == nil));
assert(!(l1.skind != skind.SK_VAR));
let l2: *sym = scopelookup(s, "bar");
assert(!(l1.skind != syntax.skind.SK_VAR));
let l2: *syntax.sym = syntax.scopelookup(s, "bar");
assert(!(l2 == nil));
assert(!(l2.skind != skind.SK_TYPE));
assert(!(l2.skind != syntax.skind.SK_TYPE));
};
@test fn scope_duplicate_reject() void = {
let s: *scope = newscope(nil);
let s: *syntax.scope = syntax.newscope(nil);
assert(!(s == nil));
let r1: *sym = scopedefine(s, "foo", skind.SK_VAR, nil, nil);
let r1: *syntax.sym = syntax.scopedefine(s, "foo", syntax.skind.SK_VAR, nil, nil);
assert(!(r1 == nil));
let r3: *sym = scopedefine(s, "foo", skind.SK_VAR, nil, nil);
let r3: *syntax.sym = syntax.scopedefine(s, "foo", syntax.skind.SK_VAR, nil, nil);
assert(!(r3 != nil));
};
@test fn scope_notfound_nil() void = {
let s: *scope = newscope(nil);
let s: *syntax.scope = syntax.newscope(nil);
assert(!(s == nil));
let l3: *sym = scopelookup(s, "baz");
let l3: *syntax.sym = syntax.scopelookup(s, "baz");
assert(!(l3 != nil));
};

View File

@@ -23,120 +23,120 @@ import ww.syntax;
import temp;
fn checktokname(k: tkind, want: str) void = {
assert(!(tokname(k) != want));
fn checktokname(k: syntax.tkind, want: str) void = {
assert(!(syntax.tokname(k) != want));
};
// One row per tkind value — same string the if-ladder returned. The
// final row pins the unknown-kind fallback ("<?>").
@test fn tokname_cases() void = {
checktokname(tkind.TK_NONE, "<none>");
checktokname(tkind.TK_EOF, "EOF");
checktokname(tkind.TK_ERR, "ERR");
checktokname(tkind.TK_IDENT, "IDENT");
checktokname(tkind.TK_INT, "INT");
checktokname(tkind.TK_FLOAT, "FLOAT");
checktokname(tkind.TK_RUNE, "RUNE");
checktokname(tkind.TK_STR, "STR");
checktokname(syntax.tkind.TK_NONE, "<none>");
checktokname(syntax.tkind.TK_EOF, "EOF");
checktokname(syntax.tkind.TK_ERR, "ERR");
checktokname(syntax.tkind.TK_IDENT, "IDENT");
checktokname(syntax.tkind.TK_INT, "INT");
checktokname(syntax.tkind.TK_FLOAT, "FLOAT");
checktokname(syntax.tkind.TK_RUNE, "RUNE");
checktokname(syntax.tkind.TK_STR, "STR");
checktokname(tkind.TK_FN, "fn");
checktokname(tkind.TK_LET, "let");
checktokname(tkind.TK_DEF, "def");
checktokname(tkind.TK_IF, "if");
checktokname(tkind.TK_ELSE, "else");
checktokname(tkind.TK_FOR, "for");
checktokname(tkind.TK_SWITCH, "switch");
checktokname(tkind.TK_CASE, "case");
checktokname(tkind.TK_RETURN, "return");
checktokname(tkind.TK_USE, "import");
checktokname(tkind.TK_TYPE, "type");
checktokname(tkind.TK_STRUCT, "struct");
checktokname(tkind.TK_DEFER, "defer");
checktokname(tkind.TK_BREAK, "break");
checktokname(tkind.TK_CONTINUE, "continue");
checktokname(tkind.TK_EXPORT, "export");
checktokname(tkind.TK_PROC, "proc");
checktokname(tkind.TK_CHAN, "chan");
checktokname(tkind.TK_NIL, "nil");
checktokname(tkind.TK_TRUE, "true");
checktokname(tkind.TK_FALSE, "false");
checktokname(tkind.TK_AS, "as");
checktokname(tkind.TK_IS, "is");
checktokname(tkind.TK_VOID, "void");
checktokname(tkind.TK_YIELD, "yield");
checktokname(tkind.TK_STATIC, "static");
checktokname(tkind.TK_MATCH, "match");
checktokname(tkind.TK_CONST, "const");
checktokname(tkind.TK_UNDER, "_");
checktokname(tkind.TK_ENUM, "enum");
checktokname(tkind.TK_MODULE, "package");
checktokname(syntax.tkind.TK_FN, "fn");
checktokname(syntax.tkind.TK_LET, "let");
checktokname(syntax.tkind.TK_DEF, "def");
checktokname(syntax.tkind.TK_IF, "if");
checktokname(syntax.tkind.TK_ELSE, "else");
checktokname(syntax.tkind.TK_FOR, "for");
checktokname(syntax.tkind.TK_SWITCH, "switch");
checktokname(syntax.tkind.TK_CASE, "case");
checktokname(syntax.tkind.TK_RETURN, "return");
checktokname(syntax.tkind.TK_USE, "import");
checktokname(syntax.tkind.TK_TYPE, "type");
checktokname(syntax.tkind.TK_STRUCT, "struct");
checktokname(syntax.tkind.TK_DEFER, "defer");
checktokname(syntax.tkind.TK_BREAK, "break");
checktokname(syntax.tkind.TK_CONTINUE, "continue");
checktokname(syntax.tkind.TK_EXPORT, "export");
checktokname(syntax.tkind.TK_PROC, "proc");
checktokname(syntax.tkind.TK_CHAN, "chan");
checktokname(syntax.tkind.TK_NIL, "nil");
checktokname(syntax.tkind.TK_TRUE, "true");
checktokname(syntax.tkind.TK_FALSE, "false");
checktokname(syntax.tkind.TK_AS, "as");
checktokname(syntax.tkind.TK_IS, "is");
checktokname(syntax.tkind.TK_VOID, "void");
checktokname(syntax.tkind.TK_YIELD, "yield");
checktokname(syntax.tkind.TK_STATIC, "static");
checktokname(syntax.tkind.TK_MATCH, "match");
checktokname(syntax.tkind.TK_CONST, "const");
checktokname(syntax.tkind.TK_UNDER, "_");
checktokname(syntax.tkind.TK_ENUM, "enum");
checktokname(syntax.tkind.TK_MODULE, "package");
checktokname(tkind.TK_LPAREN, "(");
checktokname(tkind.TK_RPAREN, ")");
checktokname(tkind.TK_LBRACE, "{");
checktokname(tkind.TK_RBRACE, "}");
checktokname(tkind.TK_LBRACK, "[");
checktokname(tkind.TK_RBRACK, "]");
checktokname(tkind.TK_COMMA, ",");
checktokname(tkind.TK_SEMI, ";");
checktokname(tkind.TK_COLON, ":");
checktokname(tkind.TK_DOT, ".");
checktokname(tkind.TK_ELLIPSIS, "...");
checktokname(tkind.TK_DOTDOT, "..");
checktokname(tkind.TK_AT, "@");
checktokname(tkind.TK_QUESTION, "?");
checktokname(syntax.tkind.TK_LPAREN, "(");
checktokname(syntax.tkind.TK_RPAREN, ")");
checktokname(syntax.tkind.TK_LBRACE, "{");
checktokname(syntax.tkind.TK_RBRACE, "}");
checktokname(syntax.tkind.TK_LBRACK, "[");
checktokname(syntax.tkind.TK_RBRACK, "]");
checktokname(syntax.tkind.TK_COMMA, ",");
checktokname(syntax.tkind.TK_SEMI, ";");
checktokname(syntax.tkind.TK_COLON, ":");
checktokname(syntax.tkind.TK_DOT, ".");
checktokname(syntax.tkind.TK_ELLIPSIS, "...");
checktokname(syntax.tkind.TK_DOTDOT, "..");
checktokname(syntax.tkind.TK_AT, "@");
checktokname(syntax.tkind.TK_QUESTION, "?");
checktokname(tkind.TK_ASSIGN, "=");
checktokname(tkind.TK_PLUSEQ, "+=");
checktokname(tkind.TK_MINUSEQ, "-=");
checktokname(tkind.TK_STAREQ, "*=");
checktokname(tkind.TK_SLASHEQ, "/=");
checktokname(tkind.TK_PERCENTEQ, "%=");
checktokname(tkind.TK_AMPEQ, "&=");
checktokname(tkind.TK_PIPEEQ, "|=");
checktokname(tkind.TK_CARETEQ, "^=");
checktokname(tkind.TK_LSHIFTEQ, "<<=");
checktokname(tkind.TK_RSHIFTEQ, ">>=");
checktokname(syntax.tkind.TK_ASSIGN, "=");
checktokname(syntax.tkind.TK_PLUSEQ, "+=");
checktokname(syntax.tkind.TK_MINUSEQ, "-=");
checktokname(syntax.tkind.TK_STAREQ, "*=");
checktokname(syntax.tkind.TK_SLASHEQ, "/=");
checktokname(syntax.tkind.TK_PERCENTEQ, "%=");
checktokname(syntax.tkind.TK_AMPEQ, "&=");
checktokname(syntax.tkind.TK_PIPEEQ, "|=");
checktokname(syntax.tkind.TK_CARETEQ, "^=");
checktokname(syntax.tkind.TK_LSHIFTEQ, "<<=");
checktokname(syntax.tkind.TK_RSHIFTEQ, ">>=");
checktokname(tkind.TK_PLUS, "+");
checktokname(tkind.TK_MINUS, "-");
checktokname(tkind.TK_STAR, "*");
checktokname(tkind.TK_SLASH, "/");
checktokname(tkind.TK_PERCENT, "%");
checktokname(tkind.TK_AMP, "&");
checktokname(tkind.TK_PIPE, "|");
checktokname(tkind.TK_CARET, "^");
checktokname(tkind.TK_TILDE, "~");
checktokname(tkind.TK_LSHIFT, "<<");
checktokname(tkind.TK_RSHIFT, ">>");
checktokname(syntax.tkind.TK_PLUS, "+");
checktokname(syntax.tkind.TK_MINUS, "-");
checktokname(syntax.tkind.TK_STAR, "*");
checktokname(syntax.tkind.TK_SLASH, "/");
checktokname(syntax.tkind.TK_PERCENT, "%");
checktokname(syntax.tkind.TK_AMP, "&");
checktokname(syntax.tkind.TK_PIPE, "|");
checktokname(syntax.tkind.TK_CARET, "^");
checktokname(syntax.tkind.TK_TILDE, "~");
checktokname(syntax.tkind.TK_LSHIFT, "<<");
checktokname(syntax.tkind.TK_RSHIFT, ">>");
checktokname(tkind.TK_EQ, "==");
checktokname(tkind.TK_NEQ, "!=");
checktokname(tkind.TK_LT, "<");
checktokname(tkind.TK_LE, "<=");
checktokname(tkind.TK_GT, ">");
checktokname(tkind.TK_GE, ">=");
checktokname(syntax.tkind.TK_EQ, "==");
checktokname(syntax.tkind.TK_NEQ, "!=");
checktokname(syntax.tkind.TK_LT, "<");
checktokname(syntax.tkind.TK_LE, "<=");
checktokname(syntax.tkind.TK_GT, ">");
checktokname(syntax.tkind.TK_GE, ">=");
checktokname(tkind.TK_AND, "&&");
checktokname(tkind.TK_OR, "||");
checktokname(tkind.TK_NOT, "!");
checktokname(syntax.tkind.TK_AND, "&&");
checktokname(syntax.tkind.TK_OR, "||");
checktokname(syntax.tkind.TK_NOT, "!");
checktokname(tkind.TK_LARROW, "<-");
checktokname(tkind.TK_ARROW, "->");
checktokname(tkind.TK_FATARROW, "=>");
checktokname(syntax.tkind.TK_LARROW, "<-");
checktokname(syntax.tkind.TK_ARROW, "->");
checktokname(syntax.tkind.TK_FATARROW, "=>");
checktokname(tkind.TK_MODRESET, "//ww:module-reset");
checktokname(tkind.TK_MODPATH, "//ww:module");
checktokname(tkind.TK_LAST, "<last>");
checktokname(syntax.tkind.TK_MODRESET, "//ww:module-reset");
checktokname(syntax.tkind.TK_MODPATH, "//ww:module");
checktokname(syntax.tkind.TK_LAST, "<last>");
// Unknown kind → the post-switch fallback. TK_LAST is the highest
// named value (89, after TK_MODPATH=88 landed); 90 is out of band,
// exercising the "<?>" tail.
checktokname(90: tkind, "<?>");
checktokname(90: syntax.tkind, "<?>");
};
fn checkkw(s: str, want: tkind) void = {
assert(!(kwlookup(s.ptr, s.len) != want));
fn checkkw(s: str, want: syntax.tkind) void = {
assert(!(syntax.kwlookup(s.ptr, s.len) != want));
};
// Table-driven (parallel-array idiom; tuple rows blocked by #111). The
@@ -153,15 +153,15 @@ fn checkkw(s: str, want: tkind) void = {
"import", "let", "match", "nil", "package", "proc", "return",
"static", "struct", "switch", "true", "type", "void", "yield",
];
let kwexp: [30]tkind = [
tkind.TK_AS, tkind.TK_BREAK, tkind.TK_CASE, tkind.TK_CHAN,
tkind.TK_CONST, tkind.TK_CONTINUE, tkind.TK_DEF, tkind.TK_DEFER,
tkind.TK_ELSE, tkind.TK_ENUM, tkind.TK_EXPORT, tkind.TK_FALSE,
tkind.TK_FN, tkind.TK_FOR, tkind.TK_IF, tkind.TK_IS,
tkind.TK_USE, tkind.TK_LET, tkind.TK_MATCH, tkind.TK_NIL,
tkind.TK_MODULE, tkind.TK_PROC, tkind.TK_RETURN, tkind.TK_STATIC,
tkind.TK_STRUCT, tkind.TK_SWITCH, tkind.TK_TRUE, tkind.TK_TYPE,
tkind.TK_VOID, tkind.TK_YIELD,
let kwexp: [30]syntax.tkind = [
syntax.tkind.TK_AS, syntax.tkind.TK_BREAK, syntax.tkind.TK_CASE, syntax.tkind.TK_CHAN,
syntax.tkind.TK_CONST, syntax.tkind.TK_CONTINUE, syntax.tkind.TK_DEF, syntax.tkind.TK_DEFER,
syntax.tkind.TK_ELSE, syntax.tkind.TK_ENUM, syntax.tkind.TK_EXPORT, syntax.tkind.TK_FALSE,
syntax.tkind.TK_FN, syntax.tkind.TK_FOR, syntax.tkind.TK_IF, syntax.tkind.TK_IS,
syntax.tkind.TK_USE, syntax.tkind.TK_LET, syntax.tkind.TK_MATCH, syntax.tkind.TK_NIL,
syntax.tkind.TK_MODULE, syntax.tkind.TK_PROC, syntax.tkind.TK_RETURN, syntax.tkind.TK_STATIC,
syntax.tkind.TK_STRUCT, syntax.tkind.TK_SWITCH, syntax.tkind.TK_TRUE, syntax.tkind.TK_TYPE,
syntax.tkind.TK_VOID, syntax.tkind.TK_YIELD,
];
let i: i32 = 0;
for (i < len(kwin)) {
@@ -197,7 +197,7 @@ fn checkkw(s: str, want: tkind) void = {
];
let j: i32 = 0;
for (j < len(nk)) {
checkkw(nk[j], tkind.TK_NONE);
checkkw(nk[j], syntax.tkind.TK_NONE);
j += 1;
};
};
@@ -205,9 +205,9 @@ fn checkkw(s: str, want: tkind) void = {
// The fd is RDWR; we lseek to 0
// before each write so earlier (possibly longer) content past want.len
// is irrelevant — only want.len bytes from offset 0 are compared.
fn checkprint(fd: i32, t: *tok, want: str) void = {
fn checkprint(fd: i32, t: *syntax.tok, want: str) void = {
assert(!(os.lseek(fd, 0i64, os.whence.SET) != 0i64));
tokprint(fd, t);
syntax.tokprint(fd, t);
assert(!(os.lseek(fd, 0i64, os.whence.SET) != 0i64));
let rbuf: [256]u8;
let z: i32 = 0;
@@ -233,33 +233,33 @@ fn checkprint(fd: i32, t: *tok, want: str) void = {
};
assert(!(fd < 0));
let t: tok;
let t: syntax.tok;
t.file = "t";
t.line = 1;
t.col = 1;
t.kind = tkind.TK_STR;
t.kind = syntax.tkind.TK_STR;
t.text = "\\\"\n\t\r\x01\x7fA";
checkprint(fd, &t, "t:1:1 STR \"\\\\\\\"\\n\\t\\r\\x01\\x7fA\"\n");
t.kind = tkind.TK_IDENT;
t.kind = syntax.tkind.TK_IDENT;
t.text = "name";
checkprint(fd, &t, "t:1:1 IDENT \"name\"\n");
t.kind = tkind.TK_ERR;
t.kind = syntax.tkind.TK_ERR;
t.text = "oops";
checkprint(fd, &t, "t:1:1 ERR \"oops\"\n");
t.kind = tkind.TK_INT;
t.kind = syntax.tkind.TK_INT;
t.uval = 42u64;
checkprint(fd, &t, "t:1:1 INT 42\n");
t.kind = tkind.TK_RUNE;
t.kind = syntax.tkind.TK_RUNE;
t.uval = 65u64;
checkprint(fd, &t, "t:1:1 RUNE 65\n");
// Default arm: a kind outside the switch appends no value.
t.kind = tkind.TK_NONE;
t.kind = syntax.tkind.TK_NONE;
checkprint(fd, &t, "t:1:1 <none>\n");
assert(!(os.close(fd) != 0));
@@ -267,11 +267,11 @@ fn checkprint(fd: i32, t: *tok, want: str) void = {
};
fn checkfloat(src: str, want: u64) void = {
let l: lex;
lexinit(&l, "t", src.ptr, src.len: u64);
let t: tok;
lexnext(&l, &t);
assert(!(t.kind != tkind.TK_FLOAT));
let l: syntax.lex;
syntax.lexinit(&l, "t", src.ptr, src.len: u64);
let t: syntax.tok;
syntax.lexnext(&l, &t);
assert(!(t.kind != syntax.tkind.TK_FLOAT));
assert(!(t.uval != want));
};
@@ -312,29 +312,29 @@ fn checkfloat(src: str, want: u64) void = {
@test fn intfinalband() void = {
let src: str = "18446744073709551616";
let l: lex;
lexinit(&l, "t", src.ptr, src.len: u64);
let t: tok;
lexnext(&l, &t);
assert(!(t.kind != tkind.TK_ERR));
let l: syntax.lex;
syntax.lexinit(&l, "t", src.ptr, src.len: u64);
let t: syntax.tok;
syntax.lexnext(&l, &t);
assert(!(t.kind != syntax.tkind.TK_ERR));
assert(!(l.errs != 1));
};
@test fn suffixrewindcols() void = {
let src: str = "1foo bar";
let l: lex;
lexinit(&l, "t", src.ptr, src.len: u64);
let t: tok;
lexnext(&l, &t);
assert(!(t.kind != tkind.TK_INT));
let l: syntax.lex;
syntax.lexinit(&l, "t", src.ptr, src.len: u64);
let t: syntax.tok;
syntax.lexnext(&l, &t);
assert(!(t.kind != syntax.tkind.TK_INT));
assert(!(t.col != 1));
assert(!(t.uval != 1u64));
lexnext(&l, &t);
assert(!(t.kind != tkind.TK_IDENT));
syntax.lexnext(&l, &t);
assert(!(t.kind != syntax.tkind.TK_IDENT));
assert(!(t.col != 2));
assert(!(t.text != "foo"));
lexnext(&l, &t);
assert(!(t.kind != tkind.TK_IDENT));
syntax.lexnext(&l, &t);
assert(!(t.kind != syntax.tkind.TK_IDENT));
assert(!(t.col != 6));
assert(!(t.text != "bar"));
};