selfhost: migrate tool sources to directory packages
Build w6a and w6l from package-main directories and expose the wcc backend through a narrow package API so w6c and wwdump no longer import implementation files. Retarget the remaining load-bearing fixtures and example sources to directory packages; retain the one intentional flat compiler collision as an explicitly composed raw unit.
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
// Port of cmd/w6a/asm.c. Encoding subset matches what w6c emits — see
|
||||
// cmd/w6a/asm.c for the authoritative list.
|
||||
|
||||
package w6a;
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import rt;
|
||||
import opcodes;
|
||||
import strings;
|
||||
|
||||
export fn emitbyte(a: *asm_, b: u8) void = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Port of cmd/w6a/lex.c.
|
||||
|
||||
package w6a;
|
||||
package main;
|
||||
|
||||
export fn isidstart(c: i32) bool = {
|
||||
if (c == 95) { return true; };
|
||||
|
||||
@@ -7,11 +7,6 @@ package main;
|
||||
import os;
|
||||
import rt;
|
||||
import strings;
|
||||
import opcodes;
|
||||
import lex;
|
||||
import parse;
|
||||
import asm;
|
||||
import obj;
|
||||
|
||||
fn cstreq(a: *u8, lit: str) bool = {
|
||||
let n: u64 = lit.len: u64;
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
//
|
||||
// Symtab indices: 0 = STN_UNDEF, 1.. = our syms. Only GLOBAL symbols.
|
||||
|
||||
package w6a;
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import opcodes;
|
||||
|
||||
// Local wrappers around os.writeall's tagged return — collapse the
|
||||
// (i64 | oserror) back to a boolean / int sentinel for the
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Mirrors cmd/w6a/a.h and cmd/w6c/6.out.h.
|
||||
|
||||
package w6a;
|
||||
package main;
|
||||
|
||||
// Registers + operand kinds must stay numerically aligned with the
|
||||
// 6.out.h C enum so that ww-cgen output (which reads them via
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
// instr := \tMNEM\t[OP1[, OP2]]
|
||||
// OP := $NUM | REG | NUM(REG) | (REG) | name(SB) | label
|
||||
|
||||
package w6a;
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import strings;
|
||||
import lex;
|
||||
import opcodes;
|
||||
|
||||
fn streqlit(p: *u8, n: u64, lit: str) bool = {
|
||||
if (n != lit.len: u64) { return false; };
|
||||
|
||||
@@ -6,9 +6,7 @@ import os;
|
||||
import rt;
|
||||
import strings;
|
||||
import syntax;
|
||||
import check;
|
||||
import cgen;
|
||||
import wwi;
|
||||
import wcc;
|
||||
|
||||
fn cstreq(a: *u8, lit: str) bool = {
|
||||
let n: u64 = lit.len: u64;
|
||||
@@ -178,36 +176,9 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
// cgen and emits junk asm with a zero exit (silent miscompile).
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
|
||||
// #50: run check before cgen so AST mutations from #42 (size/align/
|
||||
// offset fold) and the audit §1.8 node.type_ population land before
|
||||
// cgen walks the file. Mirrors cmd/w6c/main.c:73-75. Five precondition
|
||||
// fixes for fixture cleanliness: #51 cross-module type refs, #52
|
||||
// enum↔int reinterpret, #53 N_BLOCK scoping, #55 nominal-first variant
|
||||
// compare, #56 bare-leaf same-module preference.
|
||||
let tc: tctx;
|
||||
typesinit(&tc);
|
||||
let ck: checker;
|
||||
checkinit(&ck, &tc);
|
||||
ck.istest = testmode;
|
||||
if (testsupport != nil) { ck.testmodule = pathstr(testsupport); };
|
||||
ck.sepmode = sepmode;
|
||||
checkfile(&ck, f);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
|
||||
// M2 export-data: write the `.wwi` after a clean check, before cgen.
|
||||
// Dead on the live path (no existing invocation passes -I); the
|
||||
// producer's check_exported_type may reject a dangling export.
|
||||
if (wwiout != nil) {
|
||||
if (wwiemit(&ck, f, pathstr(wwiout)) != 0) { return 1; };
|
||||
};
|
||||
|
||||
let cg: cgen;
|
||||
cgeninit(&cg);
|
||||
cg.sepmode = sepmode;
|
||||
// #99: wwiout != nil <=> this is a sep DEP unit (the producer passes
|
||||
// -I to deps only; the root's .wwi is stripped per #69). Gates the
|
||||
// bare-`main` carve-out so only the root/link-entry main stays bare.
|
||||
if (wwiout != nil) { cg.sepisdep = 1i32; };
|
||||
cgfile(&cg, f);
|
||||
return 0;
|
||||
let testmodule: str;
|
||||
if (testsupport != nil) { testmodule = pathstr(testsupport); };
|
||||
let interfaceout: str;
|
||||
if (wwiout != nil) { interfaceout = pathstr(wwiout); };
|
||||
return wcc.compilefile(f, testmode, testmodule, sepmode, interfaceout);
|
||||
};
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
// exports and which DT_NEEDED entry to record. We do not pull bytes
|
||||
// from the .so; the dynamic loader maps it at runtime.
|
||||
|
||||
package w6l;
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import rt;
|
||||
import strings;
|
||||
import sym;
|
||||
|
||||
def ET_DYN_SO: u16 = 3u16;
|
||||
def EM_X86_64_SO: u16 = 62u16;
|
||||
|
||||
@@ -22,12 +22,11 @@
|
||||
// [gotplt_off] .got.plt (writable; mapped by PT_LOAD #2)
|
||||
// [dynamic_off] .dynamic (writable; covered by PT_DYNAMIC)
|
||||
|
||||
package w6l;
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import rt;
|
||||
import strings;
|
||||
import sym;
|
||||
|
||||
def ET_EXEC_D: u16 = 2u16;
|
||||
def EM_X86_64_D: u16 = 62u16;
|
||||
|
||||
@@ -7,11 +7,6 @@ package main;
|
||||
import os;
|
||||
import rt;
|
||||
import strings;
|
||||
import sym;
|
||||
import obj;
|
||||
import dyn;
|
||||
import pass;
|
||||
import out;
|
||||
|
||||
def BASE: u64 = 4194304u64; // 0x400000
|
||||
def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// Port of cmd/w6l/obj.c.
|
||||
|
||||
package w6l;
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import rt;
|
||||
import strings;
|
||||
import sym;
|
||||
|
||||
def ET_REL: i32 = 1;
|
||||
def EM_X86_64: i32 = 62;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// Port of cmd/w6l/out.c.
|
||||
|
||||
package w6l;
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import rt;
|
||||
import sym;
|
||||
import dynout;
|
||||
|
||||
def ET_EXEC: u16 = 2u16;
|
||||
def EM_X86_64_W: u16 = 62u16;
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
// Supported relocation kinds: PC32 (=2), PLT32 (=4); both are 32-bit
|
||||
// PC-relative displacements (PLT32 == PC32 for static).
|
||||
|
||||
package w6l;
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import sym;
|
||||
import dyn;
|
||||
|
||||
def R_X86_64_64: i32 = 1;
|
||||
def R_X86_64_PC32: i32 = 2;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Singly-linked list, usually a few hundred entries; hashing isn't
|
||||
// worth it yet.
|
||||
|
||||
package w6l;
|
||||
package main;
|
||||
|
||||
import strings;
|
||||
|
||||
|
||||
40
selfhost/cmd/wcc/api.ww
Normal file
40
selfhost/cmd/wcc/api.ww
Normal file
@@ -0,0 +1,40 @@
|
||||
package wcc;
|
||||
|
||||
import syntax;
|
||||
|
||||
export fn compilefile(file: *syntax.node, testmode: i32, testmodule: str,
|
||||
sepmode: i32, wwiout: str) i32 = {
|
||||
let tc: syntax.tctx;
|
||||
syntax.typesinit(&tc);
|
||||
let ck: checker;
|
||||
checkinit(&ck, &tc);
|
||||
ck.istest = testmode;
|
||||
if (testmodule.len > 0) { ck.testmodule = testmodule; };
|
||||
ck.sepmode = sepmode;
|
||||
checkfile(&ck, file);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
if (wwiout.len > 0) {
|
||||
if (wwiemit(&ck, file, wwiout) != 0) { return 1; };
|
||||
};
|
||||
|
||||
let cg: cgen;
|
||||
cgeninit(&cg);
|
||||
cg.sepmode = sepmode;
|
||||
if (wwiout.len > 0) { cg.sepisdep = 1i32; };
|
||||
cgfile(&cg, file);
|
||||
return 0;
|
||||
};
|
||||
|
||||
export fn resolvefile(file: *syntax.node, verbose: i32,
|
||||
nresolved: *i32, nunresolved: *i32) i32 = {
|
||||
let tc: syntax.tctx;
|
||||
syntax.typesinit(&tc);
|
||||
let ck: checker;
|
||||
checkinit(&ck, &tc);
|
||||
ck.verbose = verbose;
|
||||
checkfile(&ck, file);
|
||||
*nresolved = ck.nresolved;
|
||||
*nunresolved = ck.nunresolved;
|
||||
if (ck.errs > 0 || ck.nunresolved > 0) { return 1; };
|
||||
return 0;
|
||||
};
|
||||
@@ -11,11 +11,6 @@ import memio;
|
||||
// Split files. Bundler pulls these in transitively so consumers only
|
||||
// need `use cgen;`. Order matters for the flat-bundle concat — utils
|
||||
// first so cgenexpr/stmt/decl can reference helpers defined here.
|
||||
import cgenutil;
|
||||
import cgenexpr;
|
||||
import cgenstmt;
|
||||
import cgendecl;
|
||||
|
||||
// Only direct nkind.N_TNAME aliases are mapped; `type p = struct {...}`
|
||||
// is handled by collectstructs.
|
||||
|
||||
@@ -1419,7 +1414,7 @@ fn preinternstrarray(c: *cgen, au: *syntax.tinfo, r: *syntax.node) void = {
|
||||
// emitdatasection emits the DATA row in the same .s file. Running
|
||||
// emitletdataw after emitdatasection would flip the (DATA strlits,
|
||||
// DATAW lets) section order and break byte-identity.
|
||||
export fn letpreintern(c: *cgen, file: *syntax.node) void = {
|
||||
fn letpreintern(c: *cgen, file: *syntax.node) void = {
|
||||
if (file == nil) { return; };
|
||||
// #49: strlit labels allocated here (static-data initialisers) take
|
||||
// the OWNING decl's module prefix, not the stale last-fn curmod.
|
||||
@@ -4033,7 +4028,7 @@ fn argregname(i: i32) str = {
|
||||
// fargregname — XMM scalar-float arg registers (SysV: X0..X7).
|
||||
// Parallel to argregname / sysv_argregs; float args advance their
|
||||
// own counter so int and float arg slots don't conflict.
|
||||
export fn fargregname(i: i32) str = {
|
||||
fn fargregname(i: i32) str = {
|
||||
if (i == 0) { return "X0"; };
|
||||
if (i == 1) { return "X1"; };
|
||||
if (i == 2) { return "X2"; };
|
||||
|
||||
@@ -612,7 +612,7 @@ fn cgfn(c: *cgen, fn_: *syntax.node) void = {
|
||||
cgout_flush();
|
||||
};
|
||||
|
||||
export fn cgfile(c: *cgen, file: *syntax.node) void = {
|
||||
fn cgfile(c: *cgen, file: *syntax.node) void = {
|
||||
if (file == nil) { return; };
|
||||
c.strlits = nil;
|
||||
c.strlitseq = 0;
|
||||
|
||||
@@ -133,7 +133,7 @@ fn tupsse(i: i32) str = {
|
||||
// predicates this absorbs were the #22 neighbor-slot/zeros miscompile.
|
||||
// Checker twin: check.ww tupleelemslot / check.c N_TTUPLE; cstage twin:
|
||||
// tuple_eslot (cmd/w6c/cgen.c).
|
||||
export fn tupeslot(ti: *syntax.tinfo) i32 = {
|
||||
fn tupeslot(ti: *syntax.tinfo) i32 = {
|
||||
let t: *syntax.tinfo = ti;
|
||||
t = tichase(t);
|
||||
if (t == nil) { return 8; };
|
||||
@@ -148,7 +148,7 @@ export fn tupeslot(ti: *syntax.tinfo) i32 = {
|
||||
return 8;
|
||||
};
|
||||
|
||||
export fn tupeslotn(n: *syntax.node) i32 = {
|
||||
fn tupeslotn(n: *syntax.node) i32 = {
|
||||
if (n == nil) { return 8; };
|
||||
return tupeslot(n.type_: *syntax.tinfo);
|
||||
};
|
||||
|
||||
@@ -1461,7 +1461,7 @@ fn pushargsrev(c: *cgen, arg: *syntax.node, param: *syntax.node, memphase: bool,
|
||||
// route a tagged-return call result through the AX/DX/CX/R8 high→low
|
||||
// push convention rather than the concrete-variant widening path
|
||||
// (which drops DX/CX/R8). See task #21.
|
||||
export fn taggedcallslot(c: *cgen, n: *syntax.node) i32 = {
|
||||
fn taggedcallslot(c: *cgen, n: *syntax.node) i32 = {
|
||||
if (n == nil) { return 0; };
|
||||
if (n.kind != syntax.nkind.N_CALL) { return 0; };
|
||||
// Stamped result type, never a callee-name lookup (#209/#211
|
||||
@@ -1913,7 +1913,7 @@ fn storeopsz(sz: i32) str = {
|
||||
// reports, with TBANG / TENUM / TNAME-alias chains pre-folded by
|
||||
// tinfofornode (check.ww:1102-1153 TNAME, 1154-1161 TBANG,
|
||||
// 1196-1208 TENUM).
|
||||
export fn localloadop(c: *cgen, tnode: *syntax.node) str = {
|
||||
fn localloadop(c: *cgen, tnode: *syntax.node) str = {
|
||||
if (tnode == nil) { return "MOVQ"; };
|
||||
let ti: *syntax.tinfo = tnode.type_: *syntax.tinfo;
|
||||
if (ti == nil) { return "MOVQ"; };
|
||||
@@ -2298,7 +2298,7 @@ fn structabisizetn(t: *syntax.tinfo) i32 = {
|
||||
// cgdot / cgassign at every "field-walk on a struct-typed local"
|
||||
// site so a transitively-aliased struct name resolves to its
|
||||
// fieldinfo list regardless of chain depth.
|
||||
export fn structlookupchain(c: *cgen, tn: *syntax.node) *structinfo = {
|
||||
fn structlookupchain(c: *cgen, tn: *syntax.node) *structinfo = {
|
||||
if (tn == nil) { return nil; };
|
||||
// #92: a struct LITERAL's type ref parses as N_IDENT (expression
|
||||
// position, lib/ww/parse/expr.ww) where type specs parse N_TNAME
|
||||
@@ -2325,7 +2325,7 @@ export fn structlookupchain(c: *cgen, tn: *syntax.node) *structinfo = {
|
||||
return si;
|
||||
};
|
||||
|
||||
export fn sretretsize(c: *cgen, t: *syntax.node) i32 = {
|
||||
fn sretretsize(c: *cgen, t: *syntax.node) i32 = {
|
||||
if (t == nil) { return 0; };
|
||||
let r: *syntax.node = t;
|
||||
if (r.kind == syntax.nkind.N_TBANG) {
|
||||
@@ -2490,7 +2490,7 @@ fn sretretsizetn(c: *cgen, t: *syntax.tinfo) i32 = {
|
||||
// > 24B, return its natural size; else 0. Wraps sretretsize over the
|
||||
// callee's resolved return type, used by cglet / cgassign receive
|
||||
// sites and cgcall to detect sret at the receive / emit boundaries.
|
||||
export fn callsretsize(c: *cgen, n: *syntax.node) i32 = {
|
||||
fn callsretsize(c: *cgen, n: *syntax.node) i32 = {
|
||||
if (n == nil) { return 0; };
|
||||
if (n.kind != syntax.nkind.N_CALL) { return 0; };
|
||||
let callee: *syntax.node = n.lhs;
|
||||
@@ -2666,7 +2666,7 @@ fn aliasprimsize(c: *cgen, nm: str) i32 = {
|
||||
// enum, etc.). Mirrors cstage's `type_isint(t) ? t->size : 0` /
|
||||
// `type_isunsigned` recursion through TY_NAMED and TY_ENUM. Used by
|
||||
// cgcast's identity-width identity-sign clamp-skip predicate (#33).
|
||||
export fn typenodeprimresolved(c: *cgen, t: *syntax.node,
|
||||
fn typenodeprimresolved(c: *cgen, t: *syntax.node,
|
||||
sz_out: *i32, unsigned_out: *bool) void = {
|
||||
*sz_out = 0;
|
||||
*unsigned_out = false;
|
||||
@@ -2712,7 +2712,7 @@ export fn typenodeprimresolved(c: *cgen, t: *syntax.node,
|
||||
// caller treats sz=0 as "not identity", which conservatively keeps
|
||||
// the clamp. Mirror of cstage's `n->lhs->type` lookup with the same
|
||||
// TY_NAMED / TY_ENUM recursion through type_isint / type_isunsigned.
|
||||
export fn exprprimresolved(c: *cgen, n: *syntax.node,
|
||||
fn exprprimresolved(c: *cgen, n: *syntax.node,
|
||||
sz_out: *i32, unsigned_out: *bool) void = {
|
||||
*sz_out = 0;
|
||||
*unsigned_out = false;
|
||||
@@ -2885,7 +2885,7 @@ fn inferletcalltype(c: *cgen, rhs: *syntax.node) *syntax.node = {
|
||||
// not the default 8B. Without this, the AX:DX:CX spill in cglet's
|
||||
// tagged-init branch writes past the local and tramples the next
|
||||
// slot.
|
||||
export fn letslotsize(c: *cgen, n: *syntax.node) i32 = {
|
||||
fn letslotsize(c: *cgen, n: *syntax.node) i32 = {
|
||||
// `[_]T = arrlit;` inferred-length arrays no longer need a slot-size
|
||||
// intercept here: the checker (inferarraylen, check.ww) stamps the
|
||||
// real element count onto the array type's length child before cgen
|
||||
@@ -3157,7 +3157,7 @@ fn isslicetype(c: *cgen, t: *syntax.node) bool = {
|
||||
// `(invalid | overflow)` node. Use at sites that read variant lists
|
||||
// or detect nullable folding off a scrutinee — cgmatch, cgtypetest,
|
||||
// cgtypeassert — so aliased `!(A|B)` shapes still dispatch.
|
||||
export fn resolvetagged(c: *cgen, t: *syntax.node) *syntax.node = {
|
||||
fn resolvetagged(c: *cgen, t: *syntax.node) *syntax.node = {
|
||||
let r: *syntax.node = resolvetype(c, t);
|
||||
if (r == nil) { return nil; };
|
||||
if (r.kind == syntax.nkind.N_TBANG) {
|
||||
@@ -3546,7 +3546,7 @@ fn tnodeisagg(t: *syntax.node) bool = {
|
||||
// cgen.c:117 `cg_isfloat`. Dispatches MOVSS/MOVSD-shaped paths across
|
||||
// cglet, cgident, cgassign, cgbin, cgcast, cgcall, cgreturn, fn-
|
||||
// prologue. Collapsed per A.6.3b (#46).
|
||||
export fn isfloattype(c: *cgen, t: *syntax.node) bool = {
|
||||
fn isfloattype(c: *cgen, t: *syntax.node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
return syntax.typeisfloat(t.type_: *syntax.tinfo);
|
||||
};
|
||||
@@ -3554,7 +3554,7 @@ export fn isfloattype(c: *cgen, t: *syntax.node) bool = {
|
||||
// isf32type — narrower: true only for f32 (after alias chase). Cite
|
||||
// cstage cgen.c:188 `type_isf32`. Picks MOVSS vs MOVSD and the SS-
|
||||
// variant arithmetic / cast opcodes. Collapsed per A.6.3b (#46).
|
||||
export fn isf32type(c: *cgen, t: *syntax.node) bool = {
|
||||
fn isf32type(c: *cgen, t: *syntax.node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
return syntax.typeisf32(t.type_: *syntax.tinfo);
|
||||
};
|
||||
@@ -3563,7 +3563,7 @@ export fn isf32type(c: *cgen, t: *syntax.node) bool = {
|
||||
// `(*T | null)` semantics. Cite cstage cgen.c:396 `type_isnullable`;
|
||||
// the .nullable flag lands on tinfo at check.ww:1309-1318 when the
|
||||
// two-variant shape matches. Collapsed per A.6.3b (#46).
|
||||
export fn isnullabletype(t: *syntax.node) bool = {
|
||||
fn isnullabletype(t: *syntax.node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
return syntax.typeisnullable(t.type_: *syntax.tinfo);
|
||||
};
|
||||
@@ -3573,7 +3573,7 @@ export fn isnullabletype(t: *syntax.node) bool = {
|
||||
// scan ti.params, strip TY_NAMED on each variant, return idx of first
|
||||
// TY_PTR. Phase 1 (26724fe) populated the chain in tinfofornode's
|
||||
// TTAGGED arm so this walk could retire the AST-keyed predecessor.
|
||||
export fn nullableptrtag(t: *syntax.node) i32 = {
|
||||
fn nullableptrtag(t: *syntax.node) i32 = {
|
||||
if (t == nil) { return 0; };
|
||||
let ti: *syntax.tinfo = t.type_: *syntax.tinfo;
|
||||
if (ti == nil) { return 0; };
|
||||
@@ -5394,7 +5394,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *syntax.tinfo, src: *syntax.node, slot_of
|
||||
// offset), so this is offset-preserving. Leaf out-param is the field's
|
||||
// stamped *tinfo (was *fieldinfo); the str/slice pseudo-leaf leaves it
|
||||
// nil and the callers gate on slicedelta>=0 first.
|
||||
export fn dotchainresolve(c: *cgen, n: *syntax.node,
|
||||
fn dotchainresolve(c: *cgen, n: *syntax.node,
|
||||
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
||||
outleaftype: **syntax.tinfo, outslicedelta: *i32,
|
||||
outisglobal: *bool, outptrroot: *bool) bool = {
|
||||
|
||||
@@ -7473,7 +7473,7 @@ fn asserttyped(c: *checker, n: *syntax.node, indot: bool) void = {
|
||||
};
|
||||
};
|
||||
|
||||
export fn checkinit(c: *checker, tc: *syntax.tctx) void = {
|
||||
fn checkinit(c: *checker, tc: *syntax.tctx) void = {
|
||||
c.tc = tc;
|
||||
c.top = syntax.newscope(nil);
|
||||
c.cur = c.top;
|
||||
@@ -7493,7 +7493,7 @@ export fn checkinit(c: *checker, tc: *syntax.tctx) void = {
|
||||
seedprimitives(c);
|
||||
};
|
||||
|
||||
export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
if (file == nil) { return; };
|
||||
if (file.kind != syntax.nkind.N_FILE) { return; };
|
||||
c.file = file;
|
||||
|
||||
@@ -903,7 +903,7 @@ fn wwiemitfactimports(fd: i32, file: *syntax.node, owner: str) void = {
|
||||
};
|
||||
};
|
||||
|
||||
export fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
|
||||
fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
|
||||
// §5: check_exported_type FIRST, before any byte — a producer
|
||||
// without it can emit a dangling `.wwi`.
|
||||
let bad: i32 = 0;
|
||||
|
||||
@@ -6,8 +6,7 @@ package main;
|
||||
|
||||
import os;
|
||||
import syntax;
|
||||
import check;
|
||||
import cgen;
|
||||
import wcc;
|
||||
import strconv;
|
||||
|
||||
// argv strings are always NUL-terminated (kernel-supplied), so the
|
||||
@@ -124,24 +123,20 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
// and the report is printed with rc=0. Mirrors w6c main.ww:162
|
||||
// / cmd/w6c/main.c.
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
let tc: tctx;
|
||||
typesinit(&tc);
|
||||
let ck: checker;
|
||||
checkinit(&ck, &tc);
|
||||
// Quiet by default; flip to 1 when debugging missing names.
|
||||
ck.verbose = 0;
|
||||
checkfile(&ck, f);
|
||||
let nresolved: i32 = 0;
|
||||
let nunresolved: i32 = 0;
|
||||
let checkrc: i32 = wcc.resolvefile(f, 0, &nresolved, &nunresolved);
|
||||
// "<file>: <resolved>/<resolved+unresolved> resolved"
|
||||
os.write(1, argstr(path).ptr, argstrlen(path): u64);
|
||||
os.write(1, ": ".ptr, 2u64);
|
||||
let rs: str = strconv.i64tos(ck.nresolved: i64, strconv.base.DEC);
|
||||
let rs: str = strconv.i64tos(nresolved: i64, strconv.base.DEC);
|
||||
os.write(1, rs.ptr, rs.len: u64);
|
||||
os.write(1, "/".ptr, 1u64);
|
||||
let total: i32 = ck.nresolved + ck.nunresolved;
|
||||
let total: i32 = nresolved + nunresolved;
|
||||
let ts: str = strconv.i64tos(total: i64, strconv.base.DEC);
|
||||
os.write(1, ts.ptr, ts.len: u64);
|
||||
os.write(1, " resolved\n".ptr, 10u64);
|
||||
if (ck.nunresolved > 0) { return 1; };
|
||||
if (checkrc != 0) { return 1; };
|
||||
} else { if (mode == 99) { // '-c' — codegen / emit asm
|
||||
let ps: parser;
|
||||
parserinit(&ps, &l);
|
||||
@@ -152,20 +147,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
// miscompile, and the 994 byte-identity probe ships wrong asm
|
||||
// silently). Mirrors w6c main.ww:162 / cmd/w6c/main.c.
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
// #50: mirror w6c — run check before cgen so AST mutations
|
||||
// from #42 (size/align/offset fold) and audit §1.8 (node.type_
|
||||
// population) land before cgen walks. Without this, wwdump -c
|
||||
// (the byte-identity probe for 994) would diverge from w6c_ww
|
||||
// on any program that uses the size/align/offset typed builtins.
|
||||
let tc: tctx;
|
||||
typesinit(&tc);
|
||||
let ck: checker;
|
||||
checkinit(&ck, &tc);
|
||||
checkfile(&ck, f);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
let cg: cgen;
|
||||
cgeninit(&cg);
|
||||
cgfile(&cg, f);
|
||||
let empty: str;
|
||||
if (wcc.compilefile(f, 0, empty, 0, empty) != 0) { return 1; };
|
||||
};};};};
|
||||
|
||||
if (l.errs > 0) { return 1; };
|
||||
|
||||
Reference in New Issue
Block a user