lib/types,wcc/ww: export the limit constants (#48)
lib/types limit consts were bare `def`s, so the .wwi (sep-compile's
interface) correctly omitted them while the flat combined.ww let a
cross-package user (lib/strings splitn → types.I32_MAX) reach the
private def — sep-compile then failed (wwstage `asserttyped: dot
'I32_MAX'`; cstage undefined-ref). Hare exports types::I32_MAX and the
whole limit family (ref/hare/types/limits.ha, arch+x86_64.ha); ww not
exporting them was the divergence.
export the 24 existing limit defs ({I,U}{8,16,32,64}_{MIN,MAX},
INT/UINT/SIZE/UINTPTR_{MIN,MAX}) and the existing RUNE_MIN, and add
exported RUNE_MAX. ww's derived machine-word int/uint/size/uintptr
VALUES are kept verbatim (user-ratified 64-bit-int divergence); fidelity
here is the NAME SET + export-visibility, not the values. RUNE_MAX is
written `0x10ffff: rune` — same codepoint as Hare's '\U0010ffff', forced
because ww's lexer has no \u/\U escape (#50).
Exporting the consts made `w6c -I` walk them and fatal on RUNE_MIN
('\0'): the .wwi const-expr unparser had no N_RUNELIT arm. Add one,
both stages (wwi_rune / wwirune), rendering a \xHH-escaped rune literal
(>0xFF fails loud, #50). Const casts need no arm — the checker folds
them to integer literals before the producer runs. 989_m2wwi_run gains
a types.wwi gate (byte-id + re-parse + asserts export def I32_MAX and
RUNE_MAX reach the interface). byte-id-neutral: a def emits no symbol.
This commit is contained in:
@@ -164,6 +164,31 @@ wwi_quote(FILE *of, const char *s, u64 n)
|
||||
fputc('"', of);
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_rune(FILE *of, u64 cp)
|
||||
{
|
||||
/* The lexer's rune escapes stop at \xHH (no \u/\U — task #50), so a
|
||||
* codepoint above 0xff can't render as a re-parseable rune literal;
|
||||
* fail loud rather than emit a malformed one. No exported def names
|
||||
* such a rune today (RUNE_MAX is written as an int-cast for the same
|
||||
* reason). */
|
||||
if (cp > 0xff)
|
||||
fatal("wwi: rune codepoint U+%llx exceeds \\xHH (task #50)",
|
||||
(unsigned long long)cp);
|
||||
unsigned char c = (unsigned char)cp;
|
||||
fputc('\'', of);
|
||||
switch (c) {
|
||||
case '\'': fputs("\\'", of); break;
|
||||
case '\\': fputs("\\\\", of); break;
|
||||
case '\n': fputs("\\n", of); break;
|
||||
case '\t': fputs("\\t", of); break;
|
||||
default:
|
||||
if (c < 0x20 || c >= 0x7f) fprintf(of, "\\x%02x", c);
|
||||
else fputc(c, of);
|
||||
}
|
||||
fputc('\'', of);
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_param(FILE *of, Node *p)
|
||||
{
|
||||
@@ -296,6 +321,11 @@ wwi_expr(FILE *of, Node *e)
|
||||
case N_FALSE: fputs("false", of); break;
|
||||
case N_NIL: fputs("nil", of); break;
|
||||
case N_STRLIT: wwi_quote(of, e->str, e->strlen); break;
|
||||
/* A bare rune literal in a const-expr (types::RUNE_MIN = '\0'); casts
|
||||
* never reach here — the checker folds a const cast to an integer
|
||||
* literal before the producer runs (RUNE_MAX `0x10ffff: rune` emits
|
||||
* as the plain int 1114111). */
|
||||
case N_RUNELIT: wwi_rune(of, e->uval); break;
|
||||
case N_BIN:
|
||||
wwi_expr(of, e->lhs);
|
||||
fprintf(of, " %s ", tokname(e->op));
|
||||
|
||||
@@ -4,40 +4,44 @@
|
||||
|
||||
package types;
|
||||
|
||||
def I8_MAX: i8 = 127;
|
||||
def I16_MAX: i16 = 32767;
|
||||
def I32_MAX: i32 = 2147483647;
|
||||
def I64_MAX: i64 = 9223372036854775807;
|
||||
export def I8_MAX: i8 = 127;
|
||||
export def I16_MAX: i16 = 32767;
|
||||
export def I32_MAX: i32 = 2147483647;
|
||||
export def I64_MAX: i64 = 9223372036854775807;
|
||||
|
||||
def I8_MIN: i8 = -128;
|
||||
def I16_MIN: i16 = -32768;
|
||||
def I32_MIN: i32 = -2147483648;
|
||||
def I64_MIN: i64 = -9223372036854775808;
|
||||
export def I8_MIN: i8 = -128;
|
||||
export def I16_MIN: i16 = -32768;
|
||||
export def I32_MIN: i32 = -2147483648;
|
||||
export def I64_MIN: i64 = -9223372036854775808;
|
||||
|
||||
def U8_MAX: u8 = 255;
|
||||
def U16_MAX: u16 = 65535;
|
||||
def U32_MAX: u32 = 4294967295;
|
||||
def U64_MAX: u64 = 18446744073709551615;
|
||||
export def U8_MAX: u8 = 255;
|
||||
export def U16_MAX: u16 = 65535;
|
||||
export def U32_MAX: u32 = 4294967295;
|
||||
export def U64_MAX: u64 = 18446744073709551615;
|
||||
|
||||
def U8_MIN: u8 = 0;
|
||||
def U16_MIN: u16 = 0;
|
||||
def U32_MIN: u32 = 0;
|
||||
def U64_MIN: u64 = 0;
|
||||
export def U8_MIN: u8 = 0;
|
||||
export def U16_MIN: u16 = 0;
|
||||
export def U32_MIN: u32 = 0;
|
||||
export def U64_MIN: u64 = 0;
|
||||
|
||||
// int/uint are machine-word (Go-style, type.c:58); limits derived from
|
||||
// size(int) per #114 + user ruling; cf Go math.MaxInt; diverges from
|
||||
// Hare's per-arch literal (arch+x86_64.ha) because ww's int is 64-bit.
|
||||
def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
def UINT_MIN: uint = 0;
|
||||
def UINT_MAX: uint = ~(0: uint);
|
||||
export def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
export def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
export def UINT_MIN: uint = 0;
|
||||
export def UINT_MAX: uint = ~(0: uint);
|
||||
|
||||
// size is 8B on amd64; no cast needed (size ∈ unsigned class per #113).
|
||||
def SIZE_MIN: size = U64_MIN;
|
||||
def SIZE_MAX: size = U64_MAX;
|
||||
export def SIZE_MIN: size = U64_MIN;
|
||||
export def SIZE_MAX: size = U64_MAX;
|
||||
|
||||
// uintptr not in the unsigned class, so the cast is required (Hare's form).
|
||||
def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
export def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
export def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
|
||||
def RUNE_MIN: rune = '\0';
|
||||
export def RUNE_MIN: rune = '\0';
|
||||
// Hare spells this `'\U0010ffff'` (ref/hare/types/limits.ha:57); ww's lexer
|
||||
// has no \U/\u escape (cmd/wcc/lex.c escape(): \xHH only, max 0xFF) so the
|
||||
// codepoint is written as an int-cast — same value, forced spelling. #50.
|
||||
export def RUNE_MAX: rune = 0x10ffff: rune;
|
||||
|
||||
@@ -866,43 +866,47 @@ export fn exists(path: str) bool = {
|
||||
|
||||
package types;
|
||||
|
||||
def I8_MAX: i8 = 127;
|
||||
def I16_MAX: i16 = 32767;
|
||||
def I32_MAX: i32 = 2147483647;
|
||||
def I64_MAX: i64 = 9223372036854775807;
|
||||
export def I8_MAX: i8 = 127;
|
||||
export def I16_MAX: i16 = 32767;
|
||||
export def I32_MAX: i32 = 2147483647;
|
||||
export def I64_MAX: i64 = 9223372036854775807;
|
||||
|
||||
def I8_MIN: i8 = -128;
|
||||
def I16_MIN: i16 = -32768;
|
||||
def I32_MIN: i32 = -2147483648;
|
||||
def I64_MIN: i64 = -9223372036854775808;
|
||||
export def I8_MIN: i8 = -128;
|
||||
export def I16_MIN: i16 = -32768;
|
||||
export def I32_MIN: i32 = -2147483648;
|
||||
export def I64_MIN: i64 = -9223372036854775808;
|
||||
|
||||
def U8_MAX: u8 = 255;
|
||||
def U16_MAX: u16 = 65535;
|
||||
def U32_MAX: u32 = 4294967295;
|
||||
def U64_MAX: u64 = 18446744073709551615;
|
||||
export def U8_MAX: u8 = 255;
|
||||
export def U16_MAX: u16 = 65535;
|
||||
export def U32_MAX: u32 = 4294967295;
|
||||
export def U64_MAX: u64 = 18446744073709551615;
|
||||
|
||||
def U8_MIN: u8 = 0;
|
||||
def U16_MIN: u16 = 0;
|
||||
def U32_MIN: u32 = 0;
|
||||
def U64_MIN: u64 = 0;
|
||||
export def U8_MIN: u8 = 0;
|
||||
export def U16_MIN: u16 = 0;
|
||||
export def U32_MIN: u32 = 0;
|
||||
export def U64_MIN: u64 = 0;
|
||||
|
||||
// int/uint are machine-word (Go-style, type.c:58); limits derived from
|
||||
// size(int) per #114 + user ruling; cf Go math.MaxInt; diverges from
|
||||
// Hare's per-arch literal (arch+x86_64.ha) because ww's int is 64-bit.
|
||||
def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
def UINT_MIN: uint = 0;
|
||||
def UINT_MAX: uint = ~(0: uint);
|
||||
export def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
export def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
export def UINT_MIN: uint = 0;
|
||||
export def UINT_MAX: uint = ~(0: uint);
|
||||
|
||||
// size is 8B on amd64; no cast needed (size ∈ unsigned class per #113).
|
||||
def SIZE_MIN: size = U64_MIN;
|
||||
def SIZE_MAX: size = U64_MAX;
|
||||
export def SIZE_MIN: size = U64_MIN;
|
||||
export def SIZE_MAX: size = U64_MAX;
|
||||
|
||||
// uintptr not in the unsigned class, so the cast is required (Hare's form).
|
||||
def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
export def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
export def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
|
||||
def RUNE_MIN: rune = '\0';
|
||||
export def RUNE_MIN: rune = '\0';
|
||||
// Hare spells this `'\U0010ffff'` (ref/hare/types/limits.ha:57); ww's lexer
|
||||
// has no \U/\u escape (cmd/wcc/lex.c escape(): \xHH only, max 0xFF) so the
|
||||
// codepoint is written as an int-cast — same value, forced spelling. #50.
|
||||
export def RUNE_MAX: rune = 0x10ffff: rune;
|
||||
|
||||
//ww:module bytes
|
||||
// bytes — slice operations over []u8. Mirrors Hare's bytes module
|
||||
|
||||
@@ -866,43 +866,47 @@ export fn exists(path: str) bool = {
|
||||
|
||||
package types;
|
||||
|
||||
def I8_MAX: i8 = 127;
|
||||
def I16_MAX: i16 = 32767;
|
||||
def I32_MAX: i32 = 2147483647;
|
||||
def I64_MAX: i64 = 9223372036854775807;
|
||||
export def I8_MAX: i8 = 127;
|
||||
export def I16_MAX: i16 = 32767;
|
||||
export def I32_MAX: i32 = 2147483647;
|
||||
export def I64_MAX: i64 = 9223372036854775807;
|
||||
|
||||
def I8_MIN: i8 = -128;
|
||||
def I16_MIN: i16 = -32768;
|
||||
def I32_MIN: i32 = -2147483648;
|
||||
def I64_MIN: i64 = -9223372036854775808;
|
||||
export def I8_MIN: i8 = -128;
|
||||
export def I16_MIN: i16 = -32768;
|
||||
export def I32_MIN: i32 = -2147483648;
|
||||
export def I64_MIN: i64 = -9223372036854775808;
|
||||
|
||||
def U8_MAX: u8 = 255;
|
||||
def U16_MAX: u16 = 65535;
|
||||
def U32_MAX: u32 = 4294967295;
|
||||
def U64_MAX: u64 = 18446744073709551615;
|
||||
export def U8_MAX: u8 = 255;
|
||||
export def U16_MAX: u16 = 65535;
|
||||
export def U32_MAX: u32 = 4294967295;
|
||||
export def U64_MAX: u64 = 18446744073709551615;
|
||||
|
||||
def U8_MIN: u8 = 0;
|
||||
def U16_MIN: u16 = 0;
|
||||
def U32_MIN: u32 = 0;
|
||||
def U64_MIN: u64 = 0;
|
||||
export def U8_MIN: u8 = 0;
|
||||
export def U16_MIN: u16 = 0;
|
||||
export def U32_MIN: u32 = 0;
|
||||
export def U64_MIN: u64 = 0;
|
||||
|
||||
// int/uint are machine-word (Go-style, type.c:58); limits derived from
|
||||
// size(int) per #114 + user ruling; cf Go math.MaxInt; diverges from
|
||||
// Hare's per-arch literal (arch+x86_64.ha) because ww's int is 64-bit.
|
||||
def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
def UINT_MIN: uint = 0;
|
||||
def UINT_MAX: uint = ~(0: uint);
|
||||
export def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
export def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
export def UINT_MIN: uint = 0;
|
||||
export def UINT_MAX: uint = ~(0: uint);
|
||||
|
||||
// size is 8B on amd64; no cast needed (size ∈ unsigned class per #113).
|
||||
def SIZE_MIN: size = U64_MIN;
|
||||
def SIZE_MAX: size = U64_MAX;
|
||||
export def SIZE_MIN: size = U64_MIN;
|
||||
export def SIZE_MAX: size = U64_MAX;
|
||||
|
||||
// uintptr not in the unsigned class, so the cast is required (Hare's form).
|
||||
def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
export def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
export def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
|
||||
def RUNE_MIN: rune = '\0';
|
||||
export def RUNE_MIN: rune = '\0';
|
||||
// Hare spells this `'\U0010ffff'` (ref/hare/types/limits.ha:57); ww's lexer
|
||||
// has no \U/\u escape (cmd/wcc/lex.c escape(): \xHH only, max 0xFF) so the
|
||||
// codepoint is written as an int-cast — same value, forced spelling. #50.
|
||||
export def RUNE_MAX: rune = 0x10ffff: rune;
|
||||
|
||||
//ww:module bytes
|
||||
// bytes — slice operations over []u8. Mirrors Hare's bytes module
|
||||
@@ -45528,6 +45532,44 @@ fn wwicheckdecl(c: *checker, d: *node) i32 = {
|
||||
|
||||
// --- type-expr + const-expr unparser (rob §2.2/§2.4) ------------------
|
||||
|
||||
// The lexer's rune escapes stop at \xHH (no \u/\U — task #50), so a
|
||||
// codepoint above 0xff can't render as a re-parseable rune literal; fail
|
||||
// loud rather than emit a malformed one. No exported def names such a rune
|
||||
// today (RUNE_MAX is written as an int-cast for the same reason).
|
||||
fn wwirune(fd: i32, cp: u64) void = {
|
||||
if (cp > 255u64) {
|
||||
wputs(2, "wwi: rune codepoint exceeds \\xHH (task #50)\n");
|
||||
os.exit(1);
|
||||
};
|
||||
let c: u8 = cp: u8;
|
||||
wputb(fd, '\'');
|
||||
if (c == '\'') {
|
||||
wputs(fd, "\\'");
|
||||
} else { if (c == '\\') {
|
||||
wputs(fd, "\\\\");
|
||||
} else { if (c == '\n') {
|
||||
wputs(fd, "\\n");
|
||||
} else { if (c == '\t') {
|
||||
wputs(fd, "\\t");
|
||||
} else { if (c < 32u8 || c >= 127u8) {
|
||||
let hi: u8 = c >> 4u8;
|
||||
let lo: u8 = c & 15u8;
|
||||
let h: u8 = 0u8;
|
||||
let l: u8 = 0u8;
|
||||
if (hi < 10u8) { h = hi + 48u8; } else { h = (hi - 10u8) + 97u8; };
|
||||
if (lo < 10u8) { l = lo + 48u8; } else { l = (lo - 10u8) + 97u8; };
|
||||
let buf: [4]u8;
|
||||
buf[0] = 92u8;
|
||||
buf[1] = 120u8;
|
||||
buf[2] = h;
|
||||
buf[3] = l;
|
||||
os.write(fd, buf.ptr, 4u64);
|
||||
} else {
|
||||
wputb(fd, c);
|
||||
};};};};};
|
||||
wputb(fd, '\'');
|
||||
};
|
||||
|
||||
fn wwiexpr(fd: i32, e: *node) void = {
|
||||
if (e == nil) { return; };
|
||||
if (e.kind == nkind.N_INTLIT) {
|
||||
@@ -45547,6 +45589,12 @@ fn wwiexpr(fd: i32, e: *node) void = {
|
||||
wputs(fd, "nil");
|
||||
} else { if (e.kind == nkind.N_STRLIT) {
|
||||
wquote(fd, e.str);
|
||||
} else { if (e.kind == nkind.N_RUNELIT) {
|
||||
// A bare rune literal in a const-expr (types.RUNE_MIN = '\0');
|
||||
// casts never reach here — the checker folds a const cast to an
|
||||
// integer literal before the producer runs (RUNE_MAX
|
||||
// `0x10ffff: rune` emits as the plain int 1114111).
|
||||
wwirune(fd, e.uval);
|
||||
} else { if (e.kind == nkind.N_BIN) {
|
||||
wwiexpr(fd, e.lhs);
|
||||
wputb(fd, 32u8);
|
||||
@@ -45559,7 +45607,7 @@ fn wwiexpr(fd: i32, e: *node) void = {
|
||||
} else {
|
||||
wputs(2, "wwi: unhandled const-expr node kind\n");
|
||||
os.exit(1);
|
||||
};};};};};};};};};
|
||||
};};};};};};};};};};
|
||||
};
|
||||
|
||||
fn wwiparam(fd: i32, p: *node) void = {
|
||||
|
||||
@@ -866,43 +866,47 @@ export fn exists(path: str) bool = {
|
||||
|
||||
package types;
|
||||
|
||||
def I8_MAX: i8 = 127;
|
||||
def I16_MAX: i16 = 32767;
|
||||
def I32_MAX: i32 = 2147483647;
|
||||
def I64_MAX: i64 = 9223372036854775807;
|
||||
export def I8_MAX: i8 = 127;
|
||||
export def I16_MAX: i16 = 32767;
|
||||
export def I32_MAX: i32 = 2147483647;
|
||||
export def I64_MAX: i64 = 9223372036854775807;
|
||||
|
||||
def I8_MIN: i8 = -128;
|
||||
def I16_MIN: i16 = -32768;
|
||||
def I32_MIN: i32 = -2147483648;
|
||||
def I64_MIN: i64 = -9223372036854775808;
|
||||
export def I8_MIN: i8 = -128;
|
||||
export def I16_MIN: i16 = -32768;
|
||||
export def I32_MIN: i32 = -2147483648;
|
||||
export def I64_MIN: i64 = -9223372036854775808;
|
||||
|
||||
def U8_MAX: u8 = 255;
|
||||
def U16_MAX: u16 = 65535;
|
||||
def U32_MAX: u32 = 4294967295;
|
||||
def U64_MAX: u64 = 18446744073709551615;
|
||||
export def U8_MAX: u8 = 255;
|
||||
export def U16_MAX: u16 = 65535;
|
||||
export def U32_MAX: u32 = 4294967295;
|
||||
export def U64_MAX: u64 = 18446744073709551615;
|
||||
|
||||
def U8_MIN: u8 = 0;
|
||||
def U16_MIN: u16 = 0;
|
||||
def U32_MIN: u32 = 0;
|
||||
def U64_MIN: u64 = 0;
|
||||
export def U8_MIN: u8 = 0;
|
||||
export def U16_MIN: u16 = 0;
|
||||
export def U32_MIN: u32 = 0;
|
||||
export def U64_MIN: u64 = 0;
|
||||
|
||||
// int/uint are machine-word (Go-style, type.c:58); limits derived from
|
||||
// size(int) per #114 + user ruling; cf Go math.MaxInt; diverges from
|
||||
// Hare's per-arch literal (arch+x86_64.ha) because ww's int is 64-bit.
|
||||
def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
def UINT_MIN: uint = 0;
|
||||
def UINT_MAX: uint = ~(0: uint);
|
||||
export def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
export def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
export def UINT_MIN: uint = 0;
|
||||
export def UINT_MAX: uint = ~(0: uint);
|
||||
|
||||
// size is 8B on amd64; no cast needed (size ∈ unsigned class per #113).
|
||||
def SIZE_MIN: size = U64_MIN;
|
||||
def SIZE_MAX: size = U64_MAX;
|
||||
export def SIZE_MIN: size = U64_MIN;
|
||||
export def SIZE_MAX: size = U64_MAX;
|
||||
|
||||
// uintptr not in the unsigned class, so the cast is required (Hare's form).
|
||||
def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
export def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
export def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
|
||||
def RUNE_MIN: rune = '\0';
|
||||
export def RUNE_MIN: rune = '\0';
|
||||
// Hare spells this `'\U0010ffff'` (ref/hare/types/limits.ha:57); ww's lexer
|
||||
// has no \U/\u escape (cmd/wcc/lex.c escape(): \xHH only, max 0xFF) so the
|
||||
// codepoint is written as an int-cast — same value, forced spelling. #50.
|
||||
export def RUNE_MAX: rune = 0x10ffff: rune;
|
||||
|
||||
//ww:module bytes
|
||||
// bytes — slice operations over []u8. Mirrors Hare's bytes module
|
||||
|
||||
@@ -201,6 +201,44 @@ fn wwicheckdecl(c: *checker, d: *node) i32 = {
|
||||
|
||||
// --- type-expr + const-expr unparser (rob §2.2/§2.4) ------------------
|
||||
|
||||
// The lexer's rune escapes stop at \xHH (no \u/\U — task #50), so a
|
||||
// codepoint above 0xff can't render as a re-parseable rune literal; fail
|
||||
// loud rather than emit a malformed one. No exported def names such a rune
|
||||
// today (RUNE_MAX is written as an int-cast for the same reason).
|
||||
fn wwirune(fd: i32, cp: u64) void = {
|
||||
if (cp > 255u64) {
|
||||
wputs(2, "wwi: rune codepoint exceeds \\xHH (task #50)\n");
|
||||
os.exit(1);
|
||||
};
|
||||
let c: u8 = cp: u8;
|
||||
wputb(fd, '\'');
|
||||
if (c == '\'') {
|
||||
wputs(fd, "\\'");
|
||||
} else { if (c == '\\') {
|
||||
wputs(fd, "\\\\");
|
||||
} else { if (c == '\n') {
|
||||
wputs(fd, "\\n");
|
||||
} else { if (c == '\t') {
|
||||
wputs(fd, "\\t");
|
||||
} else { if (c < 32u8 || c >= 127u8) {
|
||||
let hi: u8 = c >> 4u8;
|
||||
let lo: u8 = c & 15u8;
|
||||
let h: u8 = 0u8;
|
||||
let l: u8 = 0u8;
|
||||
if (hi < 10u8) { h = hi + 48u8; } else { h = (hi - 10u8) + 97u8; };
|
||||
if (lo < 10u8) { l = lo + 48u8; } else { l = (lo - 10u8) + 97u8; };
|
||||
let buf: [4]u8;
|
||||
buf[0] = 92u8;
|
||||
buf[1] = 120u8;
|
||||
buf[2] = h;
|
||||
buf[3] = l;
|
||||
os.write(fd, buf.ptr, 4u64);
|
||||
} else {
|
||||
wputb(fd, c);
|
||||
};};};};};
|
||||
wputb(fd, '\'');
|
||||
};
|
||||
|
||||
fn wwiexpr(fd: i32, e: *node) void = {
|
||||
if (e == nil) { return; };
|
||||
if (e.kind == nkind.N_INTLIT) {
|
||||
@@ -220,6 +258,12 @@ fn wwiexpr(fd: i32, e: *node) void = {
|
||||
wputs(fd, "nil");
|
||||
} else { if (e.kind == nkind.N_STRLIT) {
|
||||
wquote(fd, e.str);
|
||||
} else { if (e.kind == nkind.N_RUNELIT) {
|
||||
// A bare rune literal in a const-expr (types.RUNE_MIN = '\0');
|
||||
// casts never reach here — the checker folds a const cast to an
|
||||
// integer literal before the producer runs (RUNE_MAX
|
||||
// `0x10ffff: rune` emits as the plain int 1114111).
|
||||
wwirune(fd, e.uval);
|
||||
} else { if (e.kind == nkind.N_BIN) {
|
||||
wwiexpr(fd, e.lhs);
|
||||
wputb(fd, 32u8);
|
||||
@@ -232,7 +276,7 @@ fn wwiexpr(fd: i32, e: *node) void = {
|
||||
} else {
|
||||
wputs(2, "wwi: unhandled const-expr node kind\n");
|
||||
os.exit(1);
|
||||
};};};};};};};};};
|
||||
};};};};};};};};};};
|
||||
};
|
||||
|
||||
fn wwiparam(fd: i32, p: *node) void = {
|
||||
|
||||
@@ -866,43 +866,47 @@ export fn exists(path: str) bool = {
|
||||
|
||||
package types;
|
||||
|
||||
def I8_MAX: i8 = 127;
|
||||
def I16_MAX: i16 = 32767;
|
||||
def I32_MAX: i32 = 2147483647;
|
||||
def I64_MAX: i64 = 9223372036854775807;
|
||||
export def I8_MAX: i8 = 127;
|
||||
export def I16_MAX: i16 = 32767;
|
||||
export def I32_MAX: i32 = 2147483647;
|
||||
export def I64_MAX: i64 = 9223372036854775807;
|
||||
|
||||
def I8_MIN: i8 = -128;
|
||||
def I16_MIN: i16 = -32768;
|
||||
def I32_MIN: i32 = -2147483648;
|
||||
def I64_MIN: i64 = -9223372036854775808;
|
||||
export def I8_MIN: i8 = -128;
|
||||
export def I16_MIN: i16 = -32768;
|
||||
export def I32_MIN: i32 = -2147483648;
|
||||
export def I64_MIN: i64 = -9223372036854775808;
|
||||
|
||||
def U8_MAX: u8 = 255;
|
||||
def U16_MAX: u16 = 65535;
|
||||
def U32_MAX: u32 = 4294967295;
|
||||
def U64_MAX: u64 = 18446744073709551615;
|
||||
export def U8_MAX: u8 = 255;
|
||||
export def U16_MAX: u16 = 65535;
|
||||
export def U32_MAX: u32 = 4294967295;
|
||||
export def U64_MAX: u64 = 18446744073709551615;
|
||||
|
||||
def U8_MIN: u8 = 0;
|
||||
def U16_MIN: u16 = 0;
|
||||
def U32_MIN: u32 = 0;
|
||||
def U64_MIN: u64 = 0;
|
||||
export def U8_MIN: u8 = 0;
|
||||
export def U16_MIN: u16 = 0;
|
||||
export def U32_MIN: u32 = 0;
|
||||
export def U64_MIN: u64 = 0;
|
||||
|
||||
// int/uint are machine-word (Go-style, type.c:58); limits derived from
|
||||
// size(int) per #114 + user ruling; cf Go math.MaxInt; diverges from
|
||||
// Hare's per-arch literal (arch+x86_64.ha) because ww's int is 64-bit.
|
||||
def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
def UINT_MIN: uint = 0;
|
||||
def UINT_MAX: uint = ~(0: uint);
|
||||
export def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
export def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
export def UINT_MIN: uint = 0;
|
||||
export def UINT_MAX: uint = ~(0: uint);
|
||||
|
||||
// size is 8B on amd64; no cast needed (size ∈ unsigned class per #113).
|
||||
def SIZE_MIN: size = U64_MIN;
|
||||
def SIZE_MAX: size = U64_MAX;
|
||||
export def SIZE_MIN: size = U64_MIN;
|
||||
export def SIZE_MAX: size = U64_MAX;
|
||||
|
||||
// uintptr not in the unsigned class, so the cast is required (Hare's form).
|
||||
def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
export def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
export def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
|
||||
def RUNE_MIN: rune = '\0';
|
||||
export def RUNE_MIN: rune = '\0';
|
||||
// Hare spells this `'\U0010ffff'` (ref/hare/types/limits.ha:57); ww's lexer
|
||||
// has no \U/\u escape (cmd/wcc/lex.c escape(): \xHH only, max 0xFF) so the
|
||||
// codepoint is written as an int-cast — same value, forced spelling. #50.
|
||||
export def RUNE_MAX: rune = 0x10ffff: rune;
|
||||
|
||||
//ww:module bytes
|
||||
// bytes — slice operations over []u8. Mirrors Hare's bytes module
|
||||
|
||||
@@ -2388,43 +2388,47 @@ let POW5_TABLE: [26]u64 = [
|
||||
|
||||
package types;
|
||||
|
||||
def I8_MAX: i8 = 127;
|
||||
def I16_MAX: i16 = 32767;
|
||||
def I32_MAX: i32 = 2147483647;
|
||||
def I64_MAX: i64 = 9223372036854775807;
|
||||
export def I8_MAX: i8 = 127;
|
||||
export def I16_MAX: i16 = 32767;
|
||||
export def I32_MAX: i32 = 2147483647;
|
||||
export def I64_MAX: i64 = 9223372036854775807;
|
||||
|
||||
def I8_MIN: i8 = -128;
|
||||
def I16_MIN: i16 = -32768;
|
||||
def I32_MIN: i32 = -2147483648;
|
||||
def I64_MIN: i64 = -9223372036854775808;
|
||||
export def I8_MIN: i8 = -128;
|
||||
export def I16_MIN: i16 = -32768;
|
||||
export def I32_MIN: i32 = -2147483648;
|
||||
export def I64_MIN: i64 = -9223372036854775808;
|
||||
|
||||
def U8_MAX: u8 = 255;
|
||||
def U16_MAX: u16 = 65535;
|
||||
def U32_MAX: u32 = 4294967295;
|
||||
def U64_MAX: u64 = 18446744073709551615;
|
||||
export def U8_MAX: u8 = 255;
|
||||
export def U16_MAX: u16 = 65535;
|
||||
export def U32_MAX: u32 = 4294967295;
|
||||
export def U64_MAX: u64 = 18446744073709551615;
|
||||
|
||||
def U8_MIN: u8 = 0;
|
||||
def U16_MIN: u16 = 0;
|
||||
def U32_MIN: u32 = 0;
|
||||
def U64_MIN: u64 = 0;
|
||||
export def U8_MIN: u8 = 0;
|
||||
export def U16_MIN: u16 = 0;
|
||||
export def U32_MIN: u32 = 0;
|
||||
export def U64_MIN: u64 = 0;
|
||||
|
||||
// int/uint are machine-word (Go-style, type.c:58); limits derived from
|
||||
// size(int) per #114 + user ruling; cf Go math.MaxInt; diverges from
|
||||
// Hare's per-arch literal (arch+x86_64.ha) because ww's int is 64-bit.
|
||||
def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
def UINT_MIN: uint = 0;
|
||||
def UINT_MAX: uint = ~(0: uint);
|
||||
export def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
export def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
export def UINT_MIN: uint = 0;
|
||||
export def UINT_MAX: uint = ~(0: uint);
|
||||
|
||||
// size is 8B on amd64; no cast needed (size ∈ unsigned class per #113).
|
||||
def SIZE_MIN: size = U64_MIN;
|
||||
def SIZE_MAX: size = U64_MAX;
|
||||
export def SIZE_MIN: size = U64_MIN;
|
||||
export def SIZE_MAX: size = U64_MAX;
|
||||
|
||||
// uintptr not in the unsigned class, so the cast is required (Hare's form).
|
||||
def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
export def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
export def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
|
||||
def RUNE_MIN: rune = '\0';
|
||||
export def RUNE_MIN: rune = '\0';
|
||||
// Hare spells this `'\U0010ffff'` (ref/hare/types/limits.ha:57); ww's lexer
|
||||
// has no \U/\u escape (cmd/wcc/lex.c escape(): \xHH only, max 0xFF) so the
|
||||
// codepoint is written as an int-cast — same value, forced spelling. #50.
|
||||
export def RUNE_MAX: rune = 0x10ffff: rune;
|
||||
|
||||
//ww:module bytes
|
||||
// bytes — slice operations over []u8. Mirrors Hare's bytes module
|
||||
|
||||
@@ -2388,43 +2388,47 @@ let POW5_TABLE: [26]u64 = [
|
||||
|
||||
package types;
|
||||
|
||||
def I8_MAX: i8 = 127;
|
||||
def I16_MAX: i16 = 32767;
|
||||
def I32_MAX: i32 = 2147483647;
|
||||
def I64_MAX: i64 = 9223372036854775807;
|
||||
export def I8_MAX: i8 = 127;
|
||||
export def I16_MAX: i16 = 32767;
|
||||
export def I32_MAX: i32 = 2147483647;
|
||||
export def I64_MAX: i64 = 9223372036854775807;
|
||||
|
||||
def I8_MIN: i8 = -128;
|
||||
def I16_MIN: i16 = -32768;
|
||||
def I32_MIN: i32 = -2147483648;
|
||||
def I64_MIN: i64 = -9223372036854775808;
|
||||
export def I8_MIN: i8 = -128;
|
||||
export def I16_MIN: i16 = -32768;
|
||||
export def I32_MIN: i32 = -2147483648;
|
||||
export def I64_MIN: i64 = -9223372036854775808;
|
||||
|
||||
def U8_MAX: u8 = 255;
|
||||
def U16_MAX: u16 = 65535;
|
||||
def U32_MAX: u32 = 4294967295;
|
||||
def U64_MAX: u64 = 18446744073709551615;
|
||||
export def U8_MAX: u8 = 255;
|
||||
export def U16_MAX: u16 = 65535;
|
||||
export def U32_MAX: u32 = 4294967295;
|
||||
export def U64_MAX: u64 = 18446744073709551615;
|
||||
|
||||
def U8_MIN: u8 = 0;
|
||||
def U16_MIN: u16 = 0;
|
||||
def U32_MIN: u32 = 0;
|
||||
def U64_MIN: u64 = 0;
|
||||
export def U8_MIN: u8 = 0;
|
||||
export def U16_MIN: u16 = 0;
|
||||
export def U32_MIN: u32 = 0;
|
||||
export def U64_MIN: u64 = 0;
|
||||
|
||||
// int/uint are machine-word (Go-style, type.c:58); limits derived from
|
||||
// size(int) per #114 + user ruling; cf Go math.MaxInt; diverges from
|
||||
// Hare's per-arch literal (arch+x86_64.ha) because ww's int is 64-bit.
|
||||
def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
def UINT_MIN: uint = 0;
|
||||
def UINT_MAX: uint = ~(0: uint);
|
||||
export def INT_MAX: int = (1 << (size(int)*8 - 1)) - 1;
|
||||
export def INT_MIN: int = -1 << (size(int)*8 - 1);
|
||||
export def UINT_MIN: uint = 0;
|
||||
export def UINT_MAX: uint = ~(0: uint);
|
||||
|
||||
// size is 8B on amd64; no cast needed (size ∈ unsigned class per #113).
|
||||
def SIZE_MIN: size = U64_MIN;
|
||||
def SIZE_MAX: size = U64_MAX;
|
||||
export def SIZE_MIN: size = U64_MIN;
|
||||
export def SIZE_MAX: size = U64_MAX;
|
||||
|
||||
// uintptr not in the unsigned class, so the cast is required (Hare's form).
|
||||
def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
export def UINTPTR_MIN: uintptr = U64_MIN: uintptr;
|
||||
export def UINTPTR_MAX: uintptr = U64_MAX: uintptr;
|
||||
|
||||
def RUNE_MIN: rune = '\0';
|
||||
export def RUNE_MIN: rune = '\0';
|
||||
// Hare spells this `'\U0010ffff'` (ref/hare/types/limits.ha:57); ww's lexer
|
||||
// has no \U/\u escape (cmd/wcc/lex.c escape(): \xHH only, max 0xFF) so the
|
||||
// codepoint is written as an int-cast — same value, forced spelling. #50.
|
||||
export def RUNE_MAX: rune = 0x10ffff: rune;
|
||||
|
||||
//ww:module bytes
|
||||
// bytes — slice operations over []u8. Mirrors Hare's bytes module
|
||||
|
||||
@@ -323,6 +323,65 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* #48 gate: the lib/types limit constants are `export def`s (Hare exports
|
||||
* types::I32_MAX &c). Produce types.wwi on both stages directly from the
|
||||
* real lib source (no imports → its own primary unit), assert byte-id +
|
||||
* re-parse + that the exported limits actually appear in the .wwi (a non-
|
||||
* exported def is omitted, so this proves the export reached the interface
|
||||
* a cross-package sep-compile consumer reads). Returns 0 on pass. */
|
||||
static int
|
||||
typesexport(const char *bin, const char *cwd)
|
||||
{
|
||||
char td[64], cmd[4096], src[1024];
|
||||
int rc = -1;
|
||||
|
||||
snprintf(td, sizeof td, "/tmp/wwm2typ_%d", getpid());
|
||||
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
|
||||
runwait(cmd);
|
||||
mkdir(td, 0755);
|
||||
|
||||
snprintf(src, sizeof src, "%s/lib/types/types.ww", cwd);
|
||||
char cs[1100], ws[1100];
|
||||
snprintf(cs, sizeof cs, "%s/cs.wwi", td);
|
||||
snprintf(ws, sizeof ws, "%s/ww.wwi", td);
|
||||
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"timeout 180 %s/w6c -I %s %s >/dev/null 2>&1", bin, cs, src);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "m2wwi FAIL: types — w6c -I rejected\n");
|
||||
goto out;
|
||||
}
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"timeout 180 %s/w6c_ww -I %s %s >/dev/null 2>&1", bin, ws, src);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "m2wwi FAIL: types — w6c_ww -I rejected\n");
|
||||
goto out;
|
||||
}
|
||||
if (files_eq(cs, ws) != 0) {
|
||||
fprintf(stderr, "m2wwi FAIL: types — cs.wwi != ww.wwi\n");
|
||||
goto out;
|
||||
}
|
||||
if (file_contains(cs, "export def I32_MAX") != 0
|
||||
|| file_contains(cs, "export def RUNE_MAX") != 0) {
|
||||
fprintf(stderr, "m2wwi FAIL: types — limit consts not exported "
|
||||
"into the .wwi (cross-package sep-compile would not see "
|
||||
"types.I32_MAX)\n");
|
||||
goto out;
|
||||
}
|
||||
snprintf(cmd, sizeof cmd,
|
||||
"timeout 180 %s/wwdump -a %s >/dev/null 2>&1", bin, cs);
|
||||
if (runwait(cmd) != 0) {
|
||||
fprintf(stderr, "m2wwi FAIL: types — emitted .wwi does not "
|
||||
"re-parse (wwdump -a)\n");
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
out:
|
||||
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
|
||||
runwait(cmd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
@@ -339,6 +398,8 @@ main(void)
|
||||
}
|
||||
if (synth(bin) != 0) fail++;
|
||||
else npos++;
|
||||
if (typesexport(bin, cwd) != 0) fail++;
|
||||
else npos++;
|
||||
if (negative(bin) != 0) fail++;
|
||||
|
||||
if (fail) {
|
||||
|
||||
Reference in New Issue
Block a user