wcc/ww: round-trip @symbol in the .wwi producer (#47)
The M2 .wwi producer rendered an exported fn carrying @symbol("...")
as a bare prototype, dropping the FFI link-symbol binding. A
sep-compiled consumer reading the .wwi then emitted `CALL malloc`
instead of `CALL rt_malloc` for `@symbol("rt_malloc") export fn
malloc`, breaking the bodies-vs-.wwi byte-id and the link. Affects
every package whose closure reaches rt/os.
Emit codegen/link-relevant attributes through a single named
predicate (wwi_attr_relevant / wwiattrrelevant), today true iff the
name is "symbol" — the only such attribute that exists. @align/@offset
are NOT field attributes in ww (the parser parses no field attrs, the
N_TFIELD node has no attr slot); the predicate is named for the class
so they slot in if ww ever grows them (#51). attr is assigned at
exactly one site per stage (parse.c:1351 / decl.ww:168), both inside
parsefn, so only N_FNDECL carries attrs and the fn-decl render path
covers the whole class.
Both stages, byte-identical (rule 10). 989_m2wwi_run synth gate gains
an @symbol fn + a content assertion that the .wwi carries it verbatim.
This commit is contained in:
@@ -310,11 +310,45 @@ wwi_expr(FILE *of, Node *e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Only codegen/link-relevant attributes round-trip into the `.wwi`. Today
|
||||||
|
* that is exactly @symbol (the FFI link-symbol override, read back at cgen
|
||||||
|
* fficollect — dropping it makes sep-compile emit `CALL malloc` for a
|
||||||
|
* `@symbol("rt_malloc")` fn). Named for the class so @align/@offset would
|
||||||
|
* slot in here IF ww ever grows field-layout attributes — it has none
|
||||||
|
* today (task #47 report). @test never reaches a `.wwi` (test fns are not
|
||||||
|
* export-marked), so it needs no exclusion arm. */
|
||||||
|
static int
|
||||||
|
wwi_attr_relevant(const char *nm)
|
||||||
|
{
|
||||||
|
return nm && strcmp(nm, "symbol") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wwi_attrs(FILE *of, Node *d)
|
||||||
|
{
|
||||||
|
for (Node *a = d->attr; a; a = a->next) {
|
||||||
|
if (a->kind != N_ATTR || !wwi_attr_relevant(a->str))
|
||||||
|
continue;
|
||||||
|
fputc('@', of);
|
||||||
|
fputs(a->str, of);
|
||||||
|
if (a->list) {
|
||||||
|
fputc('(', of);
|
||||||
|
for (Node *arg = a->list; arg; arg = arg->next) {
|
||||||
|
if (arg != a->list) fputs(", ", of);
|
||||||
|
wwi_expr(of, arg);
|
||||||
|
}
|
||||||
|
fputc(')', of);
|
||||||
|
}
|
||||||
|
fputc(' ', of);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wwi_decl(FILE *of, Node *d)
|
wwi_decl(FILE *of, Node *d)
|
||||||
{
|
{
|
||||||
switch (d->kind) {
|
switch (d->kind) {
|
||||||
case N_FNDECL:
|
case N_FNDECL:
|
||||||
|
wwi_attrs(of, d);
|
||||||
fputs("export fn ", of);
|
fputs("export fn ", of);
|
||||||
fputs(d->str, of);
|
fputs(d->str, of);
|
||||||
fputc('(', of);
|
fputc('(', of);
|
||||||
|
|||||||
@@ -45676,8 +45676,42 @@ fn wwitype(fd: i32, t: *node) void = {
|
|||||||
};};};};};};};};};};};
|
};};};};};};};};};};};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Only codegen/link-relevant attributes round-trip into the `.wwi`. Today
|
||||||
|
// that is exactly @symbol (the FFI link-symbol override, read back at cgen
|
||||||
|
// fficollect — dropping it makes sep-compile emit `CALL malloc` for a
|
||||||
|
// `@symbol("rt_malloc")` fn). Named for the class so @align/@offset would
|
||||||
|
// slot in here IF ww ever grows field-layout attributes — it has none
|
||||||
|
// today (task #47 report). @test never reaches a `.wwi` (test fns are not
|
||||||
|
// export-marked), so it needs no exclusion arm.
|
||||||
|
fn wwiattrrelevant(nm: str) bool = {
|
||||||
|
return streq(nm, "symbol");
|
||||||
|
};
|
||||||
|
|
||||||
|
fn wwiattrs(fd: i32, d: *node) void = {
|
||||||
|
let a: *node = d.attr;
|
||||||
|
for (a != nil) {
|
||||||
|
if (a.kind == nkind.N_ATTR && wwiattrrelevant(a.str)) {
|
||||||
|
wputb(fd, '@');
|
||||||
|
wputs(fd, a.str);
|
||||||
|
if (a.list != nil) {
|
||||||
|
wputb(fd, '(');
|
||||||
|
let arg: *node = a.list;
|
||||||
|
for (arg != nil) {
|
||||||
|
if (arg != a.list) { wputs(fd, ", "); };
|
||||||
|
wwiexpr(fd, arg);
|
||||||
|
arg = arg.next;
|
||||||
|
};
|
||||||
|
wputb(fd, ')');
|
||||||
|
};
|
||||||
|
wputb(fd, 32u8);
|
||||||
|
};
|
||||||
|
a = a.next;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
fn wwidecl(fd: i32, d: *node) void = {
|
fn wwidecl(fd: i32, d: *node) void = {
|
||||||
if (d.kind == nkind.N_FNDECL) {
|
if (d.kind == nkind.N_FNDECL) {
|
||||||
|
wwiattrs(fd, d);
|
||||||
wputs(fd, "export fn ");
|
wputs(fd, "export fn ");
|
||||||
wputs(fd, d.str);
|
wputs(fd, d.str);
|
||||||
wputb(fd, '(');
|
wputb(fd, '(');
|
||||||
|
|||||||
@@ -349,8 +349,42 @@ fn wwitype(fd: i32, t: *node) void = {
|
|||||||
};};};};};};};};};};};
|
};};};};};};};};};};};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Only codegen/link-relevant attributes round-trip into the `.wwi`. Today
|
||||||
|
// that is exactly @symbol (the FFI link-symbol override, read back at cgen
|
||||||
|
// fficollect — dropping it makes sep-compile emit `CALL malloc` for a
|
||||||
|
// `@symbol("rt_malloc")` fn). Named for the class so @align/@offset would
|
||||||
|
// slot in here IF ww ever grows field-layout attributes — it has none
|
||||||
|
// today (task #47 report). @test never reaches a `.wwi` (test fns are not
|
||||||
|
// export-marked), so it needs no exclusion arm.
|
||||||
|
fn wwiattrrelevant(nm: str) bool = {
|
||||||
|
return streq(nm, "symbol");
|
||||||
|
};
|
||||||
|
|
||||||
|
fn wwiattrs(fd: i32, d: *node) void = {
|
||||||
|
let a: *node = d.attr;
|
||||||
|
for (a != nil) {
|
||||||
|
if (a.kind == nkind.N_ATTR && wwiattrrelevant(a.str)) {
|
||||||
|
wputb(fd, '@');
|
||||||
|
wputs(fd, a.str);
|
||||||
|
if (a.list != nil) {
|
||||||
|
wputb(fd, '(');
|
||||||
|
let arg: *node = a.list;
|
||||||
|
for (arg != nil) {
|
||||||
|
if (arg != a.list) { wputs(fd, ", "); };
|
||||||
|
wwiexpr(fd, arg);
|
||||||
|
arg = arg.next;
|
||||||
|
};
|
||||||
|
wputb(fd, ')');
|
||||||
|
};
|
||||||
|
wputb(fd, 32u8);
|
||||||
|
};
|
||||||
|
a = a.next;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
fn wwidecl(fd: i32, d: *node) void = {
|
fn wwidecl(fd: i32, d: *node) void = {
|
||||||
if (d.kind == nkind.N_FNDECL) {
|
if (d.kind == nkind.N_FNDECL) {
|
||||||
|
wwiattrs(fd, d);
|
||||||
wputs(fd, "export fn ");
|
wputs(fd, "export fn ");
|
||||||
wputs(fd, d.str);
|
wputs(fd, d.str);
|
||||||
wputb(fd, '(');
|
wputb(fd, '(');
|
||||||
|
|||||||
@@ -77,6 +77,17 @@ slurp(const char *path, char **outbuf, size_t *outlen)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_contains(const char *path, const char *needle)
|
||||||
|
{
|
||||||
|
char *b = NULL;
|
||||||
|
size_t n = 0;
|
||||||
|
if (slurp(path, &b, &n) < 0) return -1;
|
||||||
|
int found = (strstr(b, needle) != NULL);
|
||||||
|
free(b);
|
||||||
|
return found ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
files_eq(const char *a, const char *b)
|
files_eq(const char *a, const char *b)
|
||||||
{
|
{
|
||||||
@@ -246,7 +257,11 @@ static const char *synth_src =
|
|||||||
"export fn risky() !i32;\n"
|
"export fn risky() !i32;\n"
|
||||||
"export fn matrix() [LIMIT]u8;\n"
|
"export fn matrix() [LIMIT]u8;\n"
|
||||||
"export fn pair() (i32, i32);\n"
|
"export fn pair() (i32, i32);\n"
|
||||||
"export fn opt(p: *color, b: []u8) (i32 | void);\n";
|
"export fn opt(p: *color, b: []u8) (i32 | void);\n"
|
||||||
|
/* #47: a codegen/link-relevant attribute (@symbol — the FFI link-
|
||||||
|
* symbol override) MUST round-trip into the `.wwi`; dropping it makes
|
||||||
|
* sep-compile emit `CALL ext` for a `@symbol("rt_ext")` fn. */
|
||||||
|
"@symbol(\"rt_ext\") export fn ext(n: i32) i32;\n";
|
||||||
|
|
||||||
static int
|
static int
|
||||||
synth(const char *bin)
|
synth(const char *bin)
|
||||||
@@ -288,6 +303,12 @@ synth(const char *bin)
|
|||||||
"/ decl-kind unparse diverges across stages)\n");
|
"/ decl-kind unparse diverges across stages)\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
/* #47: the @symbol attribute must survive the round-trip verbatim. */
|
||||||
|
if (file_contains(cs, "@symbol(\"rt_ext\") export fn ext") != 0) {
|
||||||
|
fprintf(stderr, "m2wwi FAIL: synth — .wwi dropped @symbol "
|
||||||
|
"(sep-compile would emit the wrong link symbol)\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
snprintf(cmd, sizeof cmd,
|
snprintf(cmd, sizeof cmd,
|
||||||
"timeout 180 %s/wwdump -a %s >/dev/null 2>&1", bin, cs);
|
"timeout 180 %s/wwdump -a %s >/dev/null 2>&1", bin, cs);
|
||||||
if (runwait(cmd) != 0) {
|
if (runwait(cmd) != 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user