diff --git a/lib/ascii/ascii.ww b/lib/ascii/ascii.ww index 5904f9a3..81a7b620 100644 --- a/lib/ascii/ascii.ww +++ b/lib/ascii/ascii.ww @@ -53,33 +53,6 @@ export fn isxdigit(c: rune) bool = { return false; }; -// digitval — value of `c` as a hex/decimal digit. void variant means -// `c` isn't a hex digit. Useful when scanning numeric literals. -export fn digitval(c: rune) (i32 | void) = { - if (isdigit(c)) { return (c - 48): i32; }; - if (c >= 65) { - if (c <= 70) { return ((c - 65) + 10): i32; }; - }; - if (c >= 97) { - if (c <= 102) { return ((c - 97) + 10): i32; }; - }; - return; -}; - -// isidstart / isidpart — identifier classes used by the lexer. -// Alpha or '_' starts; alnum or '_' continues. -export fn isidstart(c: rune) bool = { - if (isalpha(c)) { return true; }; - if (c == 95) { return true; }; // '_' - return false; -}; - -export fn isidpart(c: rune) bool = { - if (isalnum(c)) { return true; }; - if (c == 95) { return true; }; - return false; -}; - // tolower / toupper — fold ASCII case. Non-letters pass through. export fn tolower(c: rune) rune = { if (isupper(c)) { return c + 32; }; diff --git a/lib/bytes/bytes.ww b/lib/bytes/bytes.ww index 8d3979b4..fe11e25d 100644 --- a/lib/bytes/bytes.ww +++ b/lib/bytes/bytes.ww @@ -21,17 +21,6 @@ export fn indexbyte(s: []u8, c: u8) (i32 | void) = { return; }; -export fn copy(dst: []u8, src: []u8) i32 = { - let n: i32 = dst.len; - if (src.len < n) { n = src.len; }; - let i: i32 = 0; - for (i < n) { - dst[i] = src[i]; - i += 1; - }; - return n; -}; - // index — first index of `sub` in `s`. Mirrors Hare's bytes::index // (the []u8 needle variant; the u8 needle stays as indexbyte until we // have union-arg dispatch). Empty `sub` matches at 0. diff --git a/lib/fmt/fmt.ww b/lib/fmt/fmt.ww index 2bb19697..bd87a3d0 100644 --- a/lib/fmt/fmt.ww +++ b/lib/fmt/fmt.ww @@ -58,19 +58,3 @@ export fn fprintint(fd: i32, v: i64) void = { os.write(fd, buf.ptr, n: u64); }; -// errpos — write "::: \n" to fd 2. The shape -// every compiler diagnostic uses; centralised so the format stays -// consistent across phases. -export fn errpos(file: str, line: i32, col: i32, msg: str) void = { - os.write(2, file.ptr, file.len: u64); - os.write(2, ":".ptr, 1u64); - let buf: [32]u8; - let n: i32 = strconv.i64tos(buf[0:32], line: i64); - os.write(2, buf.ptr, n: u64); - os.write(2, ":".ptr, 1u64); - n = strconv.i64tos(buf[0:32], col: i64); - os.write(2, buf.ptr, n: u64); - os.write(2, ": ".ptr, 2u64); - os.write(2, msg.ptr, msg.len: u64); - os.write(2, "\n".ptr, 1u64); -}; diff --git a/lib/ww/lex/lex.ww b/lib/ww/lex/lex.ww index ed24f727..1b53aaf4 100644 --- a/lib/ww/lex/lex.ww +++ b/lib/ww/lex/lex.ww @@ -16,6 +16,34 @@ use ascii; use mem; use tok; +// isidstart / isidpart — identifier classification. Lexer-local +// because the "alpha or '_' / alnum or '_'" set isn't part of Hare's +// ascii::; ascii::isalpha + the '_' check live here instead. +fn isidstart(c: rune) bool = { + if (ascii.isalpha(c)) { return true; }; + if (c == 95) { return true; }; // '_' + return false; +}; + +fn isidpart(c: rune) bool = { + if (ascii.isalnum(c)) { return true; }; + if (c == 95) { return true; }; + return false; +}; + +// hexval — value of `c` as a hex digit (0..15) or void if not a hex +// digit. Used by string-literal `\xHH` escapes. +fn hexval(c: rune) (i32 | void) = { + if (ascii.isdigit(c)) { return (c - 48): i32; }; + if (c >= 65) { + if (c <= 70) { return ((c - 65) + 10): i32; }; // 'A'..'F' + }; + if (c >= 97) { + if (c <= 102) { return ((c - 97) + 10): i32; }; // 'a'..'f' + }; + return; +}; + type lex = struct { file: str, src: *u8, // raw bytes; not necessarily NUL-terminated @@ -245,8 +273,8 @@ fn escape(l: *lex, out: *i32) bool = { // keeps the explicit "return false on impossible-void" path // for symmetry with the other lexer error sites. Use `!` // once we have a panic-with-position helper. - let h: i32 = ascii.digitval(hi: rune)!; - let lv: i32 = ascii.digitval(lo: rune)!; + let h: i32 = hexval(hi: rune)!; + let lv: i32 = hexval(lo: rune)!; *out = (h << 4) | lv; return true; }; @@ -489,12 +517,12 @@ fn lexnum(l: *lex, start: *pos, out: *tok) void = { let pc: i32 = lpeek(l, 0u64); if (pc >= 0) { - if (ascii.isidstart(pc: rune)) { + if (isidstart(pc: rune)) { let sb: u64 = l.lpos; for (true) { let cc: i32 = lpeek(l, 0u64); if (cc < 0) { break; }; - if (!ascii.isidpart(cc: rune)) { break; }; + if (!isidpart(cc: rune)) { break; }; lget(l); }; let sl: u64 = l.lpos - sb; @@ -538,7 +566,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = { for (true) { let c: i32 = lpeek(l, 0u64); if (c < 0) { break; }; - if (!ascii.isidpart(c: rune)) { break; }; + if (!isidpart(c: rune)) { break; }; lget(l); }; let n: u64 = l.lpos - begin; @@ -687,7 +715,7 @@ export fn lexnext(l: *lex, out: *tok) void = { let c: i32 = lpeek(l, 0u64); if (c >= 0) { - if (ascii.isidstart(c: rune)) { lexident(l, &start, out); return; }; + if (isidstart(c: rune)) { lexident(l, &start, out); return; }; if (ascii.isdigit(c: rune)) { lexnum(l, &start, out); return; }; }; diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index c4dc8aab..5fbebcdd 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -1000,33 +1000,6 @@ export fn isxdigit(c: rune) bool = { return false; }; -// digitval — value of `c` as a hex/decimal digit. void variant means -// `c` isn't a hex digit. Useful when scanning numeric literals. -export fn digitval(c: rune) (i32 | void) = { - if (isdigit(c)) { return (c - 48): i32; }; - if (c >= 65) { - if (c <= 70) { return ((c - 65) + 10): i32; }; - }; - if (c >= 97) { - if (c <= 102) { return ((c - 97) + 10): i32; }; - }; - return; -}; - -// isidstart / isidpart — identifier classes used by the lexer. -// Alpha or '_' starts; alnum or '_' continues. -export fn isidstart(c: rune) bool = { - if (isalpha(c)) { return true; }; - if (c == 95) { return true; }; // '_' - return false; -}; - -export fn isidpart(c: rune) bool = { - if (isalnum(c)) { return true; }; - if (c == 95) { return true; }; - return false; -}; - // tolower / toupper — fold ASCII case. Non-letters pass through. export fn tolower(c: rune) rune = { if (isupper(c)) { return c + 32; }; @@ -1057,6 +1030,34 @@ use ascii; use mem; use tok; +// isidstart / isidpart — identifier classification. Lexer-local +// because the "alpha or '_' / alnum or '_'" set isn't part of Hare's +// ascii::; ascii::isalpha + the '_' check live here instead. +fn isidstart(c: rune) bool = { + if (ascii.isalpha(c)) { return true; }; + if (c == 95) { return true; }; // '_' + return false; +}; + +fn isidpart(c: rune) bool = { + if (ascii.isalnum(c)) { return true; }; + if (c == 95) { return true; }; + return false; +}; + +// hexval — value of `c` as a hex digit (0..15) or void if not a hex +// digit. Used by string-literal `\xHH` escapes. +fn hexval(c: rune) (i32 | void) = { + if (ascii.isdigit(c)) { return (c - 48): i32; }; + if (c >= 65) { + if (c <= 70) { return ((c - 65) + 10): i32; }; // 'A'..'F' + }; + if (c >= 97) { + if (c <= 102) { return ((c - 97) + 10): i32; }; // 'a'..'f' + }; + return; +}; + type lex = struct { file: str, src: *u8, // raw bytes; not necessarily NUL-terminated @@ -1286,8 +1287,8 @@ fn escape(l: *lex, out: *i32) bool = { // keeps the explicit "return false on impossible-void" path // for symmetry with the other lexer error sites. Use `!` // once we have a panic-with-position helper. - let h: i32 = ascii.digitval(hi: rune)!; - let lv: i32 = ascii.digitval(lo: rune)!; + let h: i32 = hexval(hi: rune)!; + let lv: i32 = hexval(lo: rune)!; *out = (h << 4) | lv; return true; }; @@ -1530,12 +1531,12 @@ fn lexnum(l: *lex, start: *pos, out: *tok) void = { let pc: i32 = lpeek(l, 0u64); if (pc >= 0) { - if (ascii.isidstart(pc: rune)) { + if (isidstart(pc: rune)) { let sb: u64 = l.lpos; for (true) { let cc: i32 = lpeek(l, 0u64); if (cc < 0) { break; }; - if (!ascii.isidpart(cc: rune)) { break; }; + if (!isidpart(cc: rune)) { break; }; lget(l); }; let sl: u64 = l.lpos - sb; @@ -1579,7 +1580,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = { for (true) { let c: i32 = lpeek(l, 0u64); if (c < 0) { break; }; - if (!ascii.isidpart(c: rune)) { break; }; + if (!isidpart(c: rune)) { break; }; lget(l); }; let n: u64 = l.lpos - begin; @@ -1728,7 +1729,7 @@ export fn lexnext(l: *lex, out: *tok) void = { let c: i32 = lpeek(l, 0u64); if (c >= 0) { - if (ascii.isidstart(c: rune)) { lexident(l, &start, out); return; }; + if (isidstart(c: rune)) { lexident(l, &start, out); return; }; if (ascii.isdigit(c: rune)) { lexnum(l, &start, out); return; }; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index ecb033c6..fdae41ae 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -1000,33 +1000,6 @@ export fn isxdigit(c: rune) bool = { return false; }; -// digitval — value of `c` as a hex/decimal digit. void variant means -// `c` isn't a hex digit. Useful when scanning numeric literals. -export fn digitval(c: rune) (i32 | void) = { - if (isdigit(c)) { return (c - 48): i32; }; - if (c >= 65) { - if (c <= 70) { return ((c - 65) + 10): i32; }; - }; - if (c >= 97) { - if (c <= 102) { return ((c - 97) + 10): i32; }; - }; - return; -}; - -// isidstart / isidpart — identifier classes used by the lexer. -// Alpha or '_' starts; alnum or '_' continues. -export fn isidstart(c: rune) bool = { - if (isalpha(c)) { return true; }; - if (c == 95) { return true; }; // '_' - return false; -}; - -export fn isidpart(c: rune) bool = { - if (isalnum(c)) { return true; }; - if (c == 95) { return true; }; - return false; -}; - // tolower / toupper — fold ASCII case. Non-letters pass through. export fn tolower(c: rune) rune = { if (isupper(c)) { return c + 32; }; @@ -1057,6 +1030,34 @@ use ascii; use mem; use tok; +// isidstart / isidpart — identifier classification. Lexer-local +// because the "alpha or '_' / alnum or '_'" set isn't part of Hare's +// ascii::; ascii::isalpha + the '_' check live here instead. +fn isidstart(c: rune) bool = { + if (ascii.isalpha(c)) { return true; }; + if (c == 95) { return true; }; // '_' + return false; +}; + +fn isidpart(c: rune) bool = { + if (ascii.isalnum(c)) { return true; }; + if (c == 95) { return true; }; + return false; +}; + +// hexval — value of `c` as a hex digit (0..15) or void if not a hex +// digit. Used by string-literal `\xHH` escapes. +fn hexval(c: rune) (i32 | void) = { + if (ascii.isdigit(c)) { return (c - 48): i32; }; + if (c >= 65) { + if (c <= 70) { return ((c - 65) + 10): i32; }; // 'A'..'F' + }; + if (c >= 97) { + if (c <= 102) { return ((c - 97) + 10): i32; }; // 'a'..'f' + }; + return; +}; + type lex = struct { file: str, src: *u8, // raw bytes; not necessarily NUL-terminated @@ -1286,8 +1287,8 @@ fn escape(l: *lex, out: *i32) bool = { // keeps the explicit "return false on impossible-void" path // for symmetry with the other lexer error sites. Use `!` // once we have a panic-with-position helper. - let h: i32 = ascii.digitval(hi: rune)!; - let lv: i32 = ascii.digitval(lo: rune)!; + let h: i32 = hexval(hi: rune)!; + let lv: i32 = hexval(lo: rune)!; *out = (h << 4) | lv; return true; }; @@ -1530,12 +1531,12 @@ fn lexnum(l: *lex, start: *pos, out: *tok) void = { let pc: i32 = lpeek(l, 0u64); if (pc >= 0) { - if (ascii.isidstart(pc: rune)) { + if (isidstart(pc: rune)) { let sb: u64 = l.lpos; for (true) { let cc: i32 = lpeek(l, 0u64); if (cc < 0) { break; }; - if (!ascii.isidpart(cc: rune)) { break; }; + if (!isidpart(cc: rune)) { break; }; lget(l); }; let sl: u64 = l.lpos - sb; @@ -1579,7 +1580,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = { for (true) { let c: i32 = lpeek(l, 0u64); if (c < 0) { break; }; - if (!ascii.isidpart(c: rune)) { break; }; + if (!isidpart(c: rune)) { break; }; lget(l); }; let n: u64 = l.lpos - begin; @@ -1728,7 +1729,7 @@ export fn lexnext(l: *lex, out: *tok) void = { let c: i32 = lpeek(l, 0u64); if (c >= 0) { - if (ascii.isidstart(c: rune)) { lexident(l, &start, out); return; }; + if (isidstart(c: rune)) { lexident(l, &start, out); return; }; if (ascii.isdigit(c: rune)) { lexnum(l, &start, out); return; }; }; diff --git a/selfhost/test/smoke.combined.ww b/selfhost/test/smoke.combined.ww index f9df694c..70ed417e 100644 --- a/selfhost/test/smoke.combined.ww +++ b/selfhost/test/smoke.combined.ww @@ -473,33 +473,6 @@ export fn isxdigit(c: rune) bool = { return false; }; -// digitval — value of `c` as a hex/decimal digit. void variant means -// `c` isn't a hex digit. Useful when scanning numeric literals. -export fn digitval(c: rune) (i32 | void) = { - if (isdigit(c)) { return (c - 48): i32; }; - if (c >= 65) { - if (c <= 70) { return ((c - 65) + 10): i32; }; - }; - if (c >= 97) { - if (c <= 102) { return ((c - 97) + 10): i32; }; - }; - return; -}; - -// isidstart / isidpart — identifier classes used by the lexer. -// Alpha or '_' starts; alnum or '_' continues. -export fn isidstart(c: rune) bool = { - if (isalpha(c)) { return true; }; - if (c == 95) { return true; }; // '_' - return false; -}; - -export fn isidpart(c: rune) bool = { - if (isalnum(c)) { return true; }; - if (c == 95) { return true; }; - return false; -}; - // tolower / toupper — fold ASCII case. Non-letters pass through. export fn tolower(c: rune) rune = { if (isupper(c)) { return c + 32; }; @@ -654,14 +627,10 @@ export fn main() i32 = { if (!ascii.isdigit(53)) { return 14; }; // '5' if (ascii.isdigit(65)) { return 15; }; // 'A' is not a digit if (!ascii.isalpha(122)) { return 16; }; // 'z' - if (!ascii.isidstart(95)) { return 17; }; // '_' - if (!ascii.isidpart(48)) { return 18; }; // '0' is part - let dv: (i32 | void) = ascii.digitval(70); - match (dv) { - case let v: i32 => { if (v != 15) { return 19; }; }; // 'F' = 15 - case void => { return 19; }; - }; - if (ascii.tolower(65) != 97) { return 20; }; // 'A' -> 'a' + if (!ascii.isxdigit(70)) { return 17; }; // 'F' + if (ascii.isxdigit(71)) { return 18; }; // 'G' is not hex + if (ascii.tolower(65) != 97) { return 19; }; // 'A' -> 'a' + if (ascii.toupper(122) != 90) { return 20; }; // 'z' -> 'Z' // Probe 7 — file open/read via the new os APIs. /proc/self/cmdline // always exists on Linux, no write side, and is non-empty. diff --git a/selfhost/test/smoke.ww b/selfhost/test/smoke.ww index 1c8ddb4c..88dcf31c 100644 --- a/selfhost/test/smoke.ww +++ b/selfhost/test/smoke.ww @@ -140,14 +140,10 @@ export fn main() i32 = { if (!ascii.isdigit(53)) { return 14; }; // '5' if (ascii.isdigit(65)) { return 15; }; // 'A' is not a digit if (!ascii.isalpha(122)) { return 16; }; // 'z' - if (!ascii.isidstart(95)) { return 17; }; // '_' - if (!ascii.isidpart(48)) { return 18; }; // '0' is part - let dv: (i32 | void) = ascii.digitval(70); - match (dv) { - case let v: i32 => { if (v != 15) { return 19; }; }; // 'F' = 15 - case void => { return 19; }; - }; - if (ascii.tolower(65) != 97) { return 20; }; // 'A' -> 'a' + if (!ascii.isxdigit(70)) { return 17; }; // 'F' + if (ascii.isxdigit(71)) { return 18; }; // 'G' is not hex + if (ascii.tolower(65) != 97) { return 19; }; // 'A' -> 'a' + if (ascii.toupper(122) != 90) { return 20; }; // 'z' -> 'Z' // Probe 7 — file open/read via the new os APIs. /proc/self/cmdline // always exists on Linux, no write side, and is non-empty.