lib: drop non-Hare extras (ascii.digitval, bytes.copy, fmt.errpos)

ascii.digitval/isidstart/isidpart are lexer-private, not Hare-stdlib.
Moved into lib/ww/lex/lex.ww as fn (renamed digitval to hexval since
its sole job is the \\xHH escape decoder).

bytes.copy and fmt.errpos have no Hare counterpart and no external
callers; gone.
This commit is contained in:
2026-05-13 03:24:33 +09:00
parent f4743dc5d5
commit 9bc973dc96
8 changed files with 110 additions and 169 deletions

View File

@@ -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; };

View File

@@ -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.

View File

@@ -58,19 +58,3 @@ export fn fprintint(fd: i32, v: i64) void = {
os.write(fd, buf.ptr, n: u64);
};
// errpos — write "<file>:<line>:<col>: <msg>\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);
};

View File

@@ -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; };
};

View File

@@ -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; };
};

View File

@@ -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; };
};

View File

@@ -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.

View File

@@ -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.