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:
56
Makefile
56
Makefile
@@ -173,12 +173,12 @@ $(OBJ)/w6l/%.o: cmd/w6l/%.c cmd/w6l/l.h | $(OBJ)/w6l
|
|||||||
# ---- ww-side wwdump (the frontend dump tool; oracle for 950/994) -------
|
# ---- ww-side wwdump (the frontend dump tool; oracle for 950/994) -------
|
||||||
# Built via the user-facing ww driver. The frontend (lex, tok, ast,
|
# Built via the user-facing ww driver. The frontend (lex, tok, ast,
|
||||||
# parse, typ, sym) is the `syntax` package in lib/ww/syntax/; the
|
# parse, typ, sym) is the `syntax` package in lib/ww/syntax/; the
|
||||||
# compiler-only bits (check, cgen*) stay in selfhost/cmd/wcc/. Output named wwdump_ww
|
# compiler-only bits are the `wcc` directory package in selfhost/cmd/wcc/.
|
||||||
# to avoid colliding with the C-side wwdump in $(BIN).
|
# Output is named wwdump_ww to avoid colliding with the C-side wwdump.
|
||||||
$(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
|
$(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
|
||||||
lib/ww/syntax/lex.ww lib/ww/syntax/tok.ww lib/ww/syntax/ast.ww \
|
lib/ww/syntax/lex.ww lib/ww/syntax/tok.ww lib/ww/syntax/ast.ww \
|
||||||
lib/ww/syntax/parse.ww lib/ww/syntax/expr.ww lib/ww/syntax/stmt.ww lib/ww/syntax/decl.ww lib/ww/syntax/typ.ww lib/ww/syntax/sym.ww \
|
lib/ww/syntax/parse.ww lib/ww/syntax/expr.ww lib/ww/syntax/stmt.ww lib/ww/syntax/decl.ww lib/ww/syntax/typ.ww lib/ww/syntax/sym.ww \
|
||||||
selfhost/cmd/wcc/check.ww \
|
selfhost/cmd/wcc/api.ww selfhost/cmd/wcc/check.ww selfhost/cmd/wcc/wwi.ww \
|
||||||
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
|
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
|
||||||
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
|
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
|
||||||
selfhost/cmd/wcc/cgendecl.ww \
|
selfhost/cmd/wcc/cgendecl.ww \
|
||||||
@@ -188,17 +188,18 @@ $(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
|
|||||||
@mkdir -p $(WWBUILD)/wwdump_ww
|
@mkdir -p $(WWBUILD)/wwdump_ww
|
||||||
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/wwdump_ww \
|
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/wwdump_ww \
|
||||||
-o $(WWBUILD)/wwdump_ww/main \
|
-o $(WWBUILD)/wwdump_ww/main \
|
||||||
-I $(CURDIR)/lib/ww -I $(CURDIR)/selfhost/cmd/wcc \
|
-I $(CURDIR)/lib/ww -I $(CURDIR)/selfhost/cmd \
|
||||||
$(CURDIR)/selfhost/cmd/wwdump/main.ww
|
$(CURDIR)/selfhost/cmd/wwdump/main.ww
|
||||||
@mv $(WWBUILD)/wwdump_ww/main $@
|
@mv $(WWBUILD)/wwdump_ww/main $@
|
||||||
|
|
||||||
# ---- ww-side w6c (compiler port, exercised by 994_w6c_ww) -------------
|
# ---- ww-side w6c (compiler port, exercised by 994_w6c_ww) -------------
|
||||||
# Thin driver: parse + cgen. The frontend (lex/parse/ast/...) is the
|
# Thin driver: parse + cgen. The frontend (lex/parse/ast/...) is the
|
||||||
# `syntax` package in lib/ww/syntax/; cgen + check live in selfhost/cmd/wcc/.
|
# `syntax` package in lib/ww/syntax/; cgen + check are behind the `wcc`
|
||||||
|
# directory package in selfhost/cmd/wcc/.
|
||||||
$(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
|
$(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
|
||||||
lib/ww/syntax/lex.ww lib/ww/syntax/tok.ww lib/ww/syntax/ast.ww \
|
lib/ww/syntax/lex.ww lib/ww/syntax/tok.ww lib/ww/syntax/ast.ww \
|
||||||
lib/ww/syntax/parse.ww lib/ww/syntax/expr.ww lib/ww/syntax/stmt.ww lib/ww/syntax/decl.ww lib/ww/syntax/typ.ww lib/ww/syntax/sym.ww \
|
lib/ww/syntax/parse.ww lib/ww/syntax/expr.ww lib/ww/syntax/stmt.ww lib/ww/syntax/decl.ww lib/ww/syntax/typ.ww lib/ww/syntax/sym.ww \
|
||||||
selfhost/cmd/wcc/check.ww selfhost/cmd/wcc/wwi.ww \
|
selfhost/cmd/wcc/api.ww selfhost/cmd/wcc/check.ww selfhost/cmd/wcc/wwi.ww \
|
||||||
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
|
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
|
||||||
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
|
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
|
||||||
selfhost/cmd/wcc/cgendecl.ww \
|
selfhost/cmd/wcc/cgendecl.ww \
|
||||||
@@ -208,13 +209,13 @@ $(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
|
|||||||
@mkdir -p $(WWBUILD)/w6c_ww
|
@mkdir -p $(WWBUILD)/w6c_ww
|
||||||
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6c_ww \
|
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6c_ww \
|
||||||
-o $(WWBUILD)/w6c_ww/main \
|
-o $(WWBUILD)/w6c_ww/main \
|
||||||
-I $(CURDIR)/lib/ww -I $(CURDIR)/selfhost/cmd/wcc \
|
-I $(CURDIR)/lib/ww -I $(CURDIR)/selfhost/cmd \
|
||||||
$(CURDIR)/selfhost/cmd/w6c/main.ww
|
$(CURDIR)/selfhost/cmd/w6c/main.ww
|
||||||
@mv $(WWBUILD)/w6c_ww/main $@
|
@mv $(WWBUILD)/w6c_ww/main $@
|
||||||
|
|
||||||
# ---- ww-side w6a (assembler port, exercised by 991_w6a_ww) ------------
|
# ---- ww-side w6a (assembler port, exercised by 991_w6a_ww) ------------
|
||||||
# Built like wwdump_ww. Needs -I selfhost/cmd/w6a for the local types/lex/
|
# The whole directory is one executable package; helper source files are not
|
||||||
# parse/asm/obj modules.
|
# importable modules.
|
||||||
$(BIN)/w6a_ww: selfhost/cmd/w6a/main.ww selfhost/cmd/w6a/opcodes.ww \
|
$(BIN)/w6a_ww: selfhost/cmd/w6a/main.ww selfhost/cmd/w6a/opcodes.ww \
|
||||||
selfhost/cmd/w6a/lex.ww selfhost/cmd/w6a/parse.ww \
|
selfhost/cmd/w6a/lex.ww selfhost/cmd/w6a/parse.ww \
|
||||||
selfhost/cmd/w6a/asm.ww selfhost/cmd/w6a/obj.ww \
|
selfhost/cmd/w6a/asm.ww selfhost/cmd/w6a/obj.ww \
|
||||||
@@ -226,13 +227,12 @@ $(BIN)/w6a_ww: selfhost/cmd/w6a/main.ww selfhost/cmd/w6a/opcodes.ww \
|
|||||||
@mkdir -p $(WWBUILD)/w6a_ww
|
@mkdir -p $(WWBUILD)/w6a_ww
|
||||||
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6a_ww \
|
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6a_ww \
|
||||||
-o $(WWBUILD)/w6a_ww/main \
|
-o $(WWBUILD)/w6a_ww/main \
|
||||||
-I $(CURDIR)/selfhost/cmd/w6a \
|
$(CURDIR)/selfhost/cmd/w6a
|
||||||
$(CURDIR)/selfhost/cmd/w6a/main.ww
|
|
||||||
@mv $(WWBUILD)/w6a_ww/main $@
|
@mv $(WWBUILD)/w6a_ww/main $@
|
||||||
|
|
||||||
# ---- ww-side w6l (linker port, exercised by 992_w6l_ww) ---------------
|
# ---- ww-side w6l (linker port, exercised by 992_w6l_ww) ---------------
|
||||||
# Built like 6a_ww. Needs -I selfhost/cmd/w6l for the local sym/obj/pass/
|
# The whole directory is one executable package; helper source files are not
|
||||||
# out modules.
|
# importable modules.
|
||||||
$(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
|
$(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
|
||||||
selfhost/cmd/w6l/obj.ww selfhost/cmd/w6l/dyn.ww \
|
selfhost/cmd/w6l/obj.ww selfhost/cmd/w6l/dyn.ww \
|
||||||
selfhost/cmd/w6l/pass.ww selfhost/cmd/w6l/dynout.ww \
|
selfhost/cmd/w6l/pass.ww selfhost/cmd/w6l/dynout.ww \
|
||||||
@@ -245,8 +245,7 @@ $(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
|
|||||||
@mkdir -p $(WWBUILD)/w6l_ww
|
@mkdir -p $(WWBUILD)/w6l_ww
|
||||||
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6l_ww \
|
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6l_ww \
|
||||||
-o $(WWBUILD)/w6l_ww/main \
|
-o $(WWBUILD)/w6l_ww/main \
|
||||||
-I $(CURDIR)/selfhost/cmd/w6l \
|
$(CURDIR)/selfhost/cmd/w6l
|
||||||
$(CURDIR)/selfhost/cmd/w6l/main.ww
|
|
||||||
@mv $(WWBUILD)/w6l_ww/main $@
|
@mv $(WWBUILD)/w6l_ww/main $@
|
||||||
|
|
||||||
# ---- ww-side ww driver (exercised by 993_ww_ww) ------------------------
|
# ---- ww-side ww driver (exercised by 993_ww_ww) ------------------------
|
||||||
@@ -794,19 +793,18 @@ test-incremental: $(BIN)/ww $(BIN)/ww_ww $(BIN)/w6c $(BIN)/w6c_ww \
|
|||||||
$(LIB)/libwwrt.a
|
$(LIB)/libwwrt.a
|
||||||
@rm -rf $(INCR_DIR)
|
@rm -rf $(INCR_DIR)
|
||||||
@set -e; \
|
@set -e; \
|
||||||
src=$(CURDIR)/selfhost/cmd/w6a/main.ww; \
|
src=$(CURDIR)/selfhost/cmd/w6a; \
|
||||||
inc=$(CURDIR)/selfhost/cmd/w6a; \
|
|
||||||
for stage in cs ws; do \
|
for stage in cs ws; do \
|
||||||
drv=$(CURDIR)/$(BIN)/ww; \
|
drv=$(CURDIR)/$(BIN)/ww; \
|
||||||
if [ $$stage = ws ]; then drv=$(CURDIR)/$(BIN)/ww_ww; fi; \
|
if [ $$stage = ws ]; then drv=$(CURDIR)/$(BIN)/ww_ww; fi; \
|
||||||
w=$(INCR_DIR)/$$stage.w; mkdir -p $$w; \
|
w=$(INCR_DIR)/$$stage.w; mkdir -p $$w; \
|
||||||
$$drv build -w $$w -o $(INCR_DIR)/$$stage.cold -I $$inc $$src; \
|
$$drv build -w $$w -o $(INCR_DIR)/$$stage.cold $$src; \
|
||||||
$$drv build -w $$w -o $(INCR_DIR)/$$stage.warm -I $$inc $$src; \
|
$$drv build -w $$w -o $(INCR_DIR)/$$stage.warm $$src; \
|
||||||
rm $$w/strings.s $$w/strings.o $$w/strings.a; \
|
rm $$w/strings.s $$w/strings.o $$w/strings.a; \
|
||||||
$$drv build -w $$w -o $(INCR_DIR)/$$stage.surg -I $$inc $$src; \
|
$$drv build -w $$w -o $(INCR_DIR)/$$stage.surg $$src; \
|
||||||
: > $$w/bytes.o; \
|
: > $$w/bytes.o; \
|
||||||
$$drv build -w $$w -o $(INCR_DIR)/$$stage.heal -I $$inc $$src; \
|
$$drv build -w $$w -o $(INCR_DIR)/$$stage.heal $$src; \
|
||||||
(cd $(INCR_DIR) && $$drv build -o $$stage.clean -I $$inc $$src); \
|
(cd $(INCR_DIR) && $$drv build -o $$stage.clean $$src); \
|
||||||
for v in cold warm surg heal; do \
|
for v in cold warm surg heal; do \
|
||||||
cmp $(INCR_DIR)/$$stage.$$v $(INCR_DIR)/$$stage.clean || { \
|
cmp $(INCR_DIR)/$$stage.$$v $(INCR_DIR)/$$stage.clean || { \
|
||||||
echo "test-incremental: $$stage.$$v differs from clean" >&2; \
|
echo "test-incremental: $$stage.$$v differs from clean" >&2; \
|
||||||
@@ -863,7 +861,7 @@ clean:
|
|||||||
# fixed, not merely a coincidental two-stage equilibrium.
|
# fixed, not merely a coincidental two-stage equilibrium.
|
||||||
BS = $(OUT)/bootstrap
|
BS = $(OUT)/bootstrap
|
||||||
W6CSRC = selfhost/cmd/w6c/main.ww
|
W6CSRC = selfhost/cmd/w6c/main.ww
|
||||||
W6CINC = -I lib/ww -I selfhost/cmd/wcc
|
W6CINC = -I lib/ww -I selfhost/cmd
|
||||||
bootstrap: all
|
bootstrap: all
|
||||||
@echo "=== stage 0 (Cstage): C-built tools ==="
|
@echo "=== stage 0 (Cstage): C-built tools ==="
|
||||||
@echo " $(BIN)/ww (sep orchestrator) $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l"
|
@echo " $(BIN)/ww (sep orchestrator) $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l"
|
||||||
@@ -961,14 +959,12 @@ nocc:
|
|||||||
@# Pass -I $(CURDIR)/lib so `use os` etc. resolve to source.
|
@# Pass -I $(CURDIR)/lib so `use os` etc. resolve to source.
|
||||||
@cd $(NOCC_BIN) && ./ww build -o main \
|
@cd $(NOCC_BIN) && ./ww build -o main \
|
||||||
-I $(CURDIR)/lib/ww \
|
-I $(CURDIR)/lib/ww \
|
||||||
-I $(CURDIR)/selfhost/cmd/wcc \
|
-I $(CURDIR)/selfhost/cmd \
|
||||||
-I $(CURDIR)/lib $(CURDIR)/selfhost/cmd/w6c/main.ww && mv main w6c_ww1
|
-I $(CURDIR)/lib $(CURDIR)/selfhost/cmd/w6c/main.ww && mv main w6c_ww1
|
||||||
@cd $(NOCC_BIN) && ./ww build -o main -I $(CURDIR)/selfhost/cmd/w6a \
|
@cd $(NOCC_BIN) && ./ww build -o main -I $(CURDIR)/lib \
|
||||||
-I $(CURDIR)/selfhost/cmd/wcc -I $(CURDIR)/lib \
|
$(CURDIR)/selfhost/cmd/w6a && mv main w6a_ww1
|
||||||
$(CURDIR)/selfhost/cmd/w6a/main.ww && mv main w6a_ww1
|
@cd $(NOCC_BIN) && ./ww build -o main -I $(CURDIR)/lib \
|
||||||
@cd $(NOCC_BIN) && ./ww build -o main -I $(CURDIR)/selfhost/cmd/w6l \
|
$(CURDIR)/selfhost/cmd/w6l && mv main w6l_ww1
|
||||||
-I $(CURDIR)/selfhost/cmd/wcc -I $(CURDIR)/lib \
|
|
||||||
$(CURDIR)/selfhost/cmd/w6l/main.ww && mv main w6l_ww1
|
|
||||||
@cd $(NOCC_BIN) && ./ww build -o main -I $(CURDIR)/selfhost/cmd/wcc \
|
@cd $(NOCC_BIN) && ./ww build -o main -I $(CURDIR)/selfhost/cmd/wcc \
|
||||||
-I $(CURDIR)/lib $(CURDIR)/selfhost/cmd/ww/main.ww && mv main ww_ww1
|
-I $(CURDIR)/lib $(CURDIR)/selfhost/cmd/ww/main.ww && mv main ww_ww1
|
||||||
@echo "=== fixed-point gates: rebuilt tools == stage-0 binaries? ==="
|
@echo "=== fixed-point gates: rebuilt tools == stage-0 binaries? ==="
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ backend rather than the C bootstrap one.
|
|||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `lispcore.ww` interpreter module: types, lexer, parser, env,
|
- `lispcore/` interpreter directory package: types, lexer, parser, env,
|
||||||
eval, apply, printer, REPL. Everything the entry
|
eval, apply, printer, REPL. Everything the entry
|
||||||
point and the test driver consume is `export`-ed.
|
point and the test driver consume is `export`-ed.
|
||||||
- `lisp.ww` entry point; `use lispcore;` + `main()`.
|
- `lisp.ww` entry point; `use lispcore;` + `main()`.
|
||||||
@@ -15,12 +15,9 @@ backend rather than the C bootstrap one.
|
|||||||
runs the binary itself.
|
runs the binary itself.
|
||||||
- `test_*.lisp` demo source files (`cat test_X.lisp | ./lisp`).
|
- `test_*.lisp` demo source files (`cat test_X.lisp | ./lisp`).
|
||||||
|
|
||||||
The lispcore.ww + lisp.ww split exists so the tests can `use` the
|
The lispcore/ + lisp.ww split exists so the entry point and tests import
|
||||||
interpreter functions. Both files combine under the same module name
|
one canonical interpreter directory package. Cross-module type prefixes
|
||||||
(the directory's basename, `lisp`), because `ww`'s module resolver
|
like `lispcore.value` don't resolve in the test — use the bare names.
|
||||||
takes the *containing-directory* basename when finding a sibling.
|
|
||||||
Cross-module type prefixes like `lispcore.value` don't resolve in the
|
|
||||||
test — use the bare names.
|
|
||||||
|
|
||||||
## wwstage cgen workarounds at play
|
## wwstage cgen workarounds at play
|
||||||
|
|
||||||
|
|||||||
@@ -3,17 +3,14 @@
|
|||||||
#
|
#
|
||||||
# Layout
|
# Layout
|
||||||
# lisp.ww entry point. `use lispcore;` + `main()` = repl().
|
# lisp.ww entry point. `use lispcore;` + `main()` = repl().
|
||||||
# lispcore.ww interpreter module. Types/functions are `export`-ed
|
# lispcore/ interpreter package. Types/functions are `export`-ed
|
||||||
# so both lisp.ww and lisp_test.ww consume them via
|
# so both lisp.ww and lisp_test.ww consume them via
|
||||||
# the same `use lispcore;`.
|
# the same `use lispcore;`.
|
||||||
# lisp_test.ww in-process test driver, executed by `make test`
|
# lisp_test.ww in-process test driver, executed by `make test`
|
||||||
# (which invokes `ww test`).
|
# (which invokes `ww test`).
|
||||||
#
|
#
|
||||||
# `ww`'s module resolver uses the *directory's basename* as the module
|
# The absolute include root makes `import lispcore` resolve the canonical
|
||||||
# name when finding `lispcore.ww` through `-I <dir>`. Passing the
|
# lispcore/ directory regardless of the caller's working directory.
|
||||||
# absolute path of the current directory keeps that name stable
|
|
||||||
# (otherwise `-I.` collapses to ".", and the cgen mangles symbols as
|
|
||||||
# `..helper`, which then breaks the assembler).
|
|
||||||
|
|
||||||
# Drive the wwstage cgen (w6c_ww) by default. The C-stage cgen has
|
# Drive the wwstage cgen (w6c_ww) by default. The C-stage cgen has
|
||||||
# unfixed silent-miscompilation traps that lispcore used to dodge by
|
# unfixed silent-miscompilation traps that lispcore used to dodge by
|
||||||
@@ -25,7 +22,7 @@ W6CWW := $(shell cd ../..; pwd)/out/bin/w6c_ww
|
|||||||
HERE := $(shell pwd)
|
HERE := $(shell pwd)
|
||||||
WWENV := WW_W6C=$(W6CWW)
|
WWENV := WW_W6C=$(W6CWW)
|
||||||
|
|
||||||
lisp: lisp.ww lispcore.ww
|
lisp: lisp.ww lispcore/lispcore.ww
|
||||||
$(WWENV) $(WW) build lisp.ww -I $(HERE)
|
$(WWENV) $(WW) build lisp.ww -I $(HERE)
|
||||||
|
|
||||||
# `ww test <file.ww>` in single-file mode discards extra args, so we
|
# `ww test <file.ww>` in single-file mode discards extra args, so we
|
||||||
@@ -34,7 +31,7 @@ lisp: lisp.ww lispcore.ww
|
|||||||
test: lisp_test lisp
|
test: lisp_test lisp
|
||||||
./lisp_test
|
./lisp_test
|
||||||
|
|
||||||
lisp_test: lisp_test.ww lispcore.ww
|
lisp_test: lisp_test.ww lispcore/lispcore.ww
|
||||||
$(WWENV) $(WW) build lisp_test.ww -I $(HERE)
|
$(WWENV) $(WW) build lisp_test.ww -I $(HERE)
|
||||||
|
|
||||||
# Demo programs in tree. `make demo` runs every test_*.lisp through
|
# Demo programs in tree. `make demo` runs every test_*.lisp through
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// lisp — entry point. The interpreter lives in `lispcore.ww`; this
|
// lisp — entry point. The interpreter lives in the `lispcore` package; this
|
||||||
// file only wires it to `main()` so `ww build lisp.ww` produces the
|
// file only wires it to `main()` so `ww build lisp.ww` produces the
|
||||||
// REPL binary. The matching tests live in `lisp_test.ww` and pull
|
// REPL binary. The matching tests live in `lisp_test.ww` and pull
|
||||||
// the same module via `use lispcore;`.
|
// the same module via `use lispcore;`.
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
// - `acc /= d` / `acc += f` on f64 locals lower to `acc = d` (drop
|
// - `acc /= d` / `acc += f` on f64 locals lower to `acc = d` (drop
|
||||||
// the OP). Write the explicit form `acc = acc OP d`.
|
// the OP). Write the explicit form `acc = acc OP d`.
|
||||||
|
|
||||||
package lisp;
|
package lispcore;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
@@ -1784,4 +1784,3 @@ export fn repl() i32 = {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package checked_test;
|
package checked_test;
|
||||||
|
|
||||||
// Directory import pulls both checked.ww and saturating.ww (the two
|
// The canonical directory import pulls both checked.ww and saturating.ww;
|
||||||
// files of this module); a bare `import checked` would resolve only to
|
// imported paths never select one source file. Referenced as `checked.*`
|
||||||
// the checked.ww file. Referenced as `checked.*` (last path component).
|
// (last path component).
|
||||||
import math.checked;
|
import math.checked;
|
||||||
import types;
|
import types;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package random_test;
|
package random_test;
|
||||||
|
|
||||||
import random;
|
import math.random;
|
||||||
import test;
|
import test;
|
||||||
|
|
||||||
@test fn seq() void = {
|
@test fn seq() void = {
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
// Port of cmd/w6a/asm.c. Encoding subset matches what w6c emits — see
|
// Port of cmd/w6a/asm.c. Encoding subset matches what w6c emits — see
|
||||||
// cmd/w6a/asm.c for the authoritative list.
|
// cmd/w6a/asm.c for the authoritative list.
|
||||||
|
|
||||||
package w6a;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import opcodes;
|
|
||||||
import strings;
|
import strings;
|
||||||
|
|
||||||
export fn emitbyte(a: *asm_, b: u8) void = {
|
export fn emitbyte(a: *asm_, b: u8) void = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Port of cmd/w6a/lex.c.
|
// Port of cmd/w6a/lex.c.
|
||||||
|
|
||||||
package w6a;
|
package main;
|
||||||
|
|
||||||
export fn isidstart(c: i32) bool = {
|
export fn isidstart(c: i32) bool = {
|
||||||
if (c == 95) { return true; };
|
if (c == 95) { return true; };
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ package main;
|
|||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import strings;
|
import strings;
|
||||||
import opcodes;
|
|
||||||
import lex;
|
|
||||||
import parse;
|
|
||||||
import asm;
|
|
||||||
import obj;
|
|
||||||
|
|
||||||
fn cstreq(a: *u8, lit: str) bool = {
|
fn cstreq(a: *u8, lit: str) bool = {
|
||||||
let n: u64 = lit.len: u64;
|
let n: u64 = lit.len: u64;
|
||||||
|
|||||||
@@ -11,10 +11,9 @@
|
|||||||
//
|
//
|
||||||
// Symtab indices: 0 = STN_UNDEF, 1.. = our syms. Only GLOBAL symbols.
|
// Symtab indices: 0 = STN_UNDEF, 1.. = our syms. Only GLOBAL symbols.
|
||||||
|
|
||||||
package w6a;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import opcodes;
|
|
||||||
|
|
||||||
// Local wrappers around os.writeall's tagged return — collapse the
|
// Local wrappers around os.writeall's tagged return — collapse the
|
||||||
// (i64 | oserror) back to a boolean / int sentinel for 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.
|
// Mirrors cmd/w6a/a.h and cmd/w6c/6.out.h.
|
||||||
|
|
||||||
package w6a;
|
package main;
|
||||||
|
|
||||||
// Registers + operand kinds must stay numerically aligned with the
|
// Registers + operand kinds must stay numerically aligned with the
|
||||||
// 6.out.h C enum so that ww-cgen output (which reads them via
|
// 6.out.h C enum so that ww-cgen output (which reads them via
|
||||||
|
|||||||
@@ -10,12 +10,10 @@
|
|||||||
// instr := \tMNEM\t[OP1[, OP2]]
|
// instr := \tMNEM\t[OP1[, OP2]]
|
||||||
// OP := $NUM | REG | NUM(REG) | (REG) | name(SB) | label
|
// OP := $NUM | REG | NUM(REG) | (REG) | name(SB) | label
|
||||||
|
|
||||||
package w6a;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import strings;
|
import strings;
|
||||||
import lex;
|
|
||||||
import opcodes;
|
|
||||||
|
|
||||||
fn streqlit(p: *u8, n: u64, lit: str) bool = {
|
fn streqlit(p: *u8, n: u64, lit: str) bool = {
|
||||||
if (n != lit.len: u64) { return false; };
|
if (n != lit.len: u64) { return false; };
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import os;
|
|||||||
import rt;
|
import rt;
|
||||||
import strings;
|
import strings;
|
||||||
import syntax;
|
import syntax;
|
||||||
import check;
|
import wcc;
|
||||||
import cgen;
|
|
||||||
import wwi;
|
|
||||||
|
|
||||||
fn cstreq(a: *u8, lit: str) bool = {
|
fn cstreq(a: *u8, lit: str) bool = {
|
||||||
let n: u64 = lit.len: u64;
|
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).
|
// cgen and emits junk asm with a zero exit (silent miscompile).
|
||||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||||
|
|
||||||
// #50: run check before cgen so AST mutations from #42 (size/align/
|
let testmodule: str;
|
||||||
// offset fold) and the audit §1.8 node.type_ population land before
|
if (testsupport != nil) { testmodule = pathstr(testsupport); };
|
||||||
// cgen walks the file. Mirrors cmd/w6c/main.c:73-75. Five precondition
|
let interfaceout: str;
|
||||||
// fixes for fixture cleanliness: #51 cross-module type refs, #52
|
if (wwiout != nil) { interfaceout = pathstr(wwiout); };
|
||||||
// enum↔int reinterpret, #53 N_BLOCK scoping, #55 nominal-first variant
|
return wcc.compilefile(f, testmode, testmodule, sepmode, interfaceout);
|
||||||
// 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;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,12 +4,11 @@
|
|||||||
// exports and which DT_NEEDED entry to record. We do not pull bytes
|
// exports and which DT_NEEDED entry to record. We do not pull bytes
|
||||||
// from the .so; the dynamic loader maps it at runtime.
|
// from the .so; the dynamic loader maps it at runtime.
|
||||||
|
|
||||||
package w6l;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import strings;
|
import strings;
|
||||||
import sym;
|
|
||||||
|
|
||||||
def ET_DYN_SO: u16 = 3u16;
|
def ET_DYN_SO: u16 = 3u16;
|
||||||
def EM_X86_64_SO: u16 = 62u16;
|
def EM_X86_64_SO: u16 = 62u16;
|
||||||
|
|||||||
@@ -22,12 +22,11 @@
|
|||||||
// [gotplt_off] .got.plt (writable; mapped by PT_LOAD #2)
|
// [gotplt_off] .got.plt (writable; mapped by PT_LOAD #2)
|
||||||
// [dynamic_off] .dynamic (writable; covered by PT_DYNAMIC)
|
// [dynamic_off] .dynamic (writable; covered by PT_DYNAMIC)
|
||||||
|
|
||||||
package w6l;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import strings;
|
import strings;
|
||||||
import sym;
|
|
||||||
|
|
||||||
def ET_EXEC_D: u16 = 2u16;
|
def ET_EXEC_D: u16 = 2u16;
|
||||||
def EM_X86_64_D: u16 = 62u16;
|
def EM_X86_64_D: u16 = 62u16;
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ package main;
|
|||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import strings;
|
import strings;
|
||||||
import sym;
|
|
||||||
import obj;
|
|
||||||
import dyn;
|
|
||||||
import pass;
|
|
||||||
import out;
|
|
||||||
|
|
||||||
def BASE: u64 = 4194304u64; // 0x400000
|
def BASE: u64 = 4194304u64; // 0x400000
|
||||||
def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000
|
def CODE_VA_OFF: u64 = 4096u64; // .text starts at base + 0x1000
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
// Port of cmd/w6l/obj.c.
|
// Port of cmd/w6l/obj.c.
|
||||||
|
|
||||||
package w6l;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import strings;
|
import strings;
|
||||||
import sym;
|
|
||||||
|
|
||||||
def ET_REL: i32 = 1;
|
def ET_REL: i32 = 1;
|
||||||
def EM_X86_64: i32 = 62;
|
def EM_X86_64: i32 = 62;
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
// Port of cmd/w6l/out.c.
|
// Port of cmd/w6l/out.c.
|
||||||
|
|
||||||
package w6l;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import rt;
|
import rt;
|
||||||
import sym;
|
|
||||||
import dynout;
|
|
||||||
|
|
||||||
def ET_EXEC: u16 = 2u16;
|
def ET_EXEC: u16 = 2u16;
|
||||||
def EM_X86_64_W: u16 = 62u16;
|
def EM_X86_64_W: u16 = 62u16;
|
||||||
|
|||||||
@@ -3,11 +3,9 @@
|
|||||||
// Supported relocation kinds: PC32 (=2), PLT32 (=4); both are 32-bit
|
// Supported relocation kinds: PC32 (=2), PLT32 (=4); both are 32-bit
|
||||||
// PC-relative displacements (PLT32 == PC32 for static).
|
// PC-relative displacements (PLT32 == PC32 for static).
|
||||||
|
|
||||||
package w6l;
|
package main;
|
||||||
|
|
||||||
import os;
|
import os;
|
||||||
import sym;
|
|
||||||
import dyn;
|
|
||||||
|
|
||||||
def R_X86_64_64: i32 = 1;
|
def R_X86_64_64: i32 = 1;
|
||||||
def R_X86_64_PC32: i32 = 2;
|
def R_X86_64_PC32: i32 = 2;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// Singly-linked list, usually a few hundred entries; hashing isn't
|
// Singly-linked list, usually a few hundred entries; hashing isn't
|
||||||
// worth it yet.
|
// worth it yet.
|
||||||
|
|
||||||
package w6l;
|
package main;
|
||||||
|
|
||||||
import strings;
|
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
|
// Split files. Bundler pulls these in transitively so consumers only
|
||||||
// need `use cgen;`. Order matters for the flat-bundle concat — utils
|
// need `use cgen;`. Order matters for the flat-bundle concat — utils
|
||||||
// first so cgenexpr/stmt/decl can reference helpers defined here.
|
// 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 {...}`
|
// Only direct nkind.N_TNAME aliases are mapped; `type p = struct {...}`
|
||||||
// is handled by collectstructs.
|
// 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
|
// emitdatasection emits the DATA row in the same .s file. Running
|
||||||
// emitletdataw after emitdatasection would flip the (DATA strlits,
|
// emitletdataw after emitdatasection would flip the (DATA strlits,
|
||||||
// DATAW lets) section order and break byte-identity.
|
// 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; };
|
if (file == nil) { return; };
|
||||||
// #49: strlit labels allocated here (static-data initialisers) take
|
// #49: strlit labels allocated here (static-data initialisers) take
|
||||||
// the OWNING decl's module prefix, not the stale last-fn curmod.
|
// 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).
|
// fargregname — XMM scalar-float arg registers (SysV: X0..X7).
|
||||||
// Parallel to argregname / sysv_argregs; float args advance their
|
// Parallel to argregname / sysv_argregs; float args advance their
|
||||||
// own counter so int and float arg slots don't conflict.
|
// 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 == 0) { return "X0"; };
|
||||||
if (i == 1) { return "X1"; };
|
if (i == 1) { return "X1"; };
|
||||||
if (i == 2) { return "X2"; };
|
if (i == 2) { return "X2"; };
|
||||||
|
|||||||
@@ -612,7 +612,7 @@ fn cgfn(c: *cgen, fn_: *syntax.node) void = {
|
|||||||
cgout_flush();
|
cgout_flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn cgfile(c: *cgen, file: *syntax.node) void = {
|
fn cgfile(c: *cgen, file: *syntax.node) void = {
|
||||||
if (file == nil) { return; };
|
if (file == nil) { return; };
|
||||||
c.strlits = nil;
|
c.strlits = nil;
|
||||||
c.strlitseq = 0;
|
c.strlitseq = 0;
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ fn tupsse(i: i32) str = {
|
|||||||
// predicates this absorbs were the #22 neighbor-slot/zeros miscompile.
|
// predicates this absorbs were the #22 neighbor-slot/zeros miscompile.
|
||||||
// Checker twin: check.ww tupleelemslot / check.c N_TTUPLE; cstage twin:
|
// Checker twin: check.ww tupleelemslot / check.c N_TTUPLE; cstage twin:
|
||||||
// tuple_eslot (cmd/w6c/cgen.c).
|
// tuple_eslot (cmd/w6c/cgen.c).
|
||||||
export fn tupeslot(ti: *syntax.tinfo) i32 = {
|
fn tupeslot(ti: *syntax.tinfo) i32 = {
|
||||||
let t: *syntax.tinfo = ti;
|
let t: *syntax.tinfo = ti;
|
||||||
t = tichase(t);
|
t = tichase(t);
|
||||||
if (t == nil) { return 8; };
|
if (t == nil) { return 8; };
|
||||||
@@ -148,7 +148,7 @@ export fn tupeslot(ti: *syntax.tinfo) i32 = {
|
|||||||
return 8;
|
return 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn tupeslotn(n: *syntax.node) i32 = {
|
fn tupeslotn(n: *syntax.node) i32 = {
|
||||||
if (n == nil) { return 8; };
|
if (n == nil) { return 8; };
|
||||||
return tupeslot(n.type_: *syntax.tinfo);
|
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
|
// route a tagged-return call result through the AX/DX/CX/R8 high→low
|
||||||
// push convention rather than the concrete-variant widening path
|
// push convention rather than the concrete-variant widening path
|
||||||
// (which drops DX/CX/R8). See task #21.
|
// (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 == nil) { return 0; };
|
||||||
if (n.kind != syntax.nkind.N_CALL) { return 0; };
|
if (n.kind != syntax.nkind.N_CALL) { return 0; };
|
||||||
// Stamped result type, never a callee-name lookup (#209/#211
|
// 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
|
// reports, with TBANG / TENUM / TNAME-alias chains pre-folded by
|
||||||
// tinfofornode (check.ww:1102-1153 TNAME, 1154-1161 TBANG,
|
// tinfofornode (check.ww:1102-1153 TNAME, 1154-1161 TBANG,
|
||||||
// 1196-1208 TENUM).
|
// 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"; };
|
if (tnode == nil) { return "MOVQ"; };
|
||||||
let ti: *syntax.tinfo = tnode.type_: *syntax.tinfo;
|
let ti: *syntax.tinfo = tnode.type_: *syntax.tinfo;
|
||||||
if (ti == nil) { return "MOVQ"; };
|
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"
|
// cgdot / cgassign at every "field-walk on a struct-typed local"
|
||||||
// site so a transitively-aliased struct name resolves to its
|
// site so a transitively-aliased struct name resolves to its
|
||||||
// fieldinfo list regardless of chain depth.
|
// 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; };
|
if (tn == nil) { return nil; };
|
||||||
// #92: a struct LITERAL's type ref parses as N_IDENT (expression
|
// #92: a struct LITERAL's type ref parses as N_IDENT (expression
|
||||||
// position, lib/ww/parse/expr.ww) where type specs parse N_TNAME
|
// 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;
|
return si;
|
||||||
};
|
};
|
||||||
|
|
||||||
export fn sretretsize(c: *cgen, t: *syntax.node) i32 = {
|
fn sretretsize(c: *cgen, t: *syntax.node) i32 = {
|
||||||
if (t == nil) { return 0; };
|
if (t == nil) { return 0; };
|
||||||
let r: *syntax.node = t;
|
let r: *syntax.node = t;
|
||||||
if (r.kind == syntax.nkind.N_TBANG) {
|
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
|
// > 24B, return its natural size; else 0. Wraps sretretsize over the
|
||||||
// callee's resolved return type, used by cglet / cgassign receive
|
// callee's resolved return type, used by cglet / cgassign receive
|
||||||
// sites and cgcall to detect sret at the receive / emit boundaries.
|
// 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 == nil) { return 0; };
|
||||||
if (n.kind != syntax.nkind.N_CALL) { return 0; };
|
if (n.kind != syntax.nkind.N_CALL) { return 0; };
|
||||||
let callee: *syntax.node = n.lhs;
|
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` /
|
// enum, etc.). Mirrors cstage's `type_isint(t) ? t->size : 0` /
|
||||||
// `type_isunsigned` recursion through TY_NAMED and TY_ENUM. Used by
|
// `type_isunsigned` recursion through TY_NAMED and TY_ENUM. Used by
|
||||||
// cgcast's identity-width identity-sign clamp-skip predicate (#33).
|
// 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: *i32, unsigned_out: *bool) void = {
|
||||||
*sz_out = 0;
|
*sz_out = 0;
|
||||||
*unsigned_out = false;
|
*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
|
// caller treats sz=0 as "not identity", which conservatively keeps
|
||||||
// the clamp. Mirror of cstage's `n->lhs->type` lookup with the same
|
// the clamp. Mirror of cstage's `n->lhs->type` lookup with the same
|
||||||
// TY_NAMED / TY_ENUM recursion through type_isint / type_isunsigned.
|
// 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: *i32, unsigned_out: *bool) void = {
|
||||||
*sz_out = 0;
|
*sz_out = 0;
|
||||||
*unsigned_out = false;
|
*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
|
// 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
|
// tagged-init branch writes past the local and tramples the next
|
||||||
// slot.
|
// 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
|
// `[_]T = arrlit;` inferred-length arrays no longer need a slot-size
|
||||||
// intercept here: the checker (inferarraylen, check.ww) stamps the
|
// intercept here: the checker (inferarraylen, check.ww) stamps the
|
||||||
// real element count onto the array type's length child before cgen
|
// 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
|
// `(invalid | overflow)` node. Use at sites that read variant lists
|
||||||
// or detect nullable folding off a scrutinee — cgmatch, cgtypetest,
|
// or detect nullable folding off a scrutinee — cgmatch, cgtypetest,
|
||||||
// cgtypeassert — so aliased `!(A|B)` shapes still dispatch.
|
// 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);
|
let r: *syntax.node = resolvetype(c, t);
|
||||||
if (r == nil) { return nil; };
|
if (r == nil) { return nil; };
|
||||||
if (r.kind == syntax.nkind.N_TBANG) {
|
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
|
// cgen.c:117 `cg_isfloat`. Dispatches MOVSS/MOVSD-shaped paths across
|
||||||
// cglet, cgident, cgassign, cgbin, cgcast, cgcall, cgreturn, fn-
|
// cglet, cgident, cgassign, cgbin, cgcast, cgcall, cgreturn, fn-
|
||||||
// prologue. Collapsed per A.6.3b (#46).
|
// 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; };
|
if (t == nil) { return false; };
|
||||||
return syntax.typeisfloat(t.type_: *syntax.tinfo);
|
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
|
// isf32type — narrower: true only for f32 (after alias chase). Cite
|
||||||
// cstage cgen.c:188 `type_isf32`. Picks MOVSS vs MOVSD and the SS-
|
// cstage cgen.c:188 `type_isf32`. Picks MOVSS vs MOVSD and the SS-
|
||||||
// variant arithmetic / cast opcodes. Collapsed per A.6.3b (#46).
|
// 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; };
|
if (t == nil) { return false; };
|
||||||
return syntax.typeisf32(t.type_: *syntax.tinfo);
|
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`;
|
// `(*T | null)` semantics. Cite cstage cgen.c:396 `type_isnullable`;
|
||||||
// the .nullable flag lands on tinfo at check.ww:1309-1318 when the
|
// the .nullable flag lands on tinfo at check.ww:1309-1318 when the
|
||||||
// two-variant shape matches. Collapsed per A.6.3b (#46).
|
// 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; };
|
if (t == nil) { return false; };
|
||||||
return syntax.typeisnullable(t.type_: *syntax.tinfo);
|
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
|
// scan ti.params, strip TY_NAMED on each variant, return idx of first
|
||||||
// TY_PTR. Phase 1 (26724fe) populated the chain in tinfofornode's
|
// TY_PTR. Phase 1 (26724fe) populated the chain in tinfofornode's
|
||||||
// TTAGGED arm so this walk could retire the AST-keyed predecessor.
|
// 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; };
|
if (t == nil) { return 0; };
|
||||||
let ti: *syntax.tinfo = t.type_: *syntax.tinfo;
|
let ti: *syntax.tinfo = t.type_: *syntax.tinfo;
|
||||||
if (ti == nil) { return 0; };
|
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
|
// offset), so this is offset-preserving. Leaf out-param is the field's
|
||||||
// stamped *tinfo (was *fieldinfo); the str/slice pseudo-leaf leaves it
|
// stamped *tinfo (was *fieldinfo); the str/slice pseudo-leaf leaves it
|
||||||
// nil and the callers gate on slicedelta>=0 first.
|
// 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,
|
outrootname: *str, outrootoff: *i32, outtotaloff: *i32,
|
||||||
outleaftype: **syntax.tinfo, outslicedelta: *i32,
|
outleaftype: **syntax.tinfo, outslicedelta: *i32,
|
||||||
outisglobal: *bool, outptrroot: *bool) bool = {
|
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.tc = tc;
|
||||||
c.top = syntax.newscope(nil);
|
c.top = syntax.newscope(nil);
|
||||||
c.cur = c.top;
|
c.cur = c.top;
|
||||||
@@ -7493,7 +7493,7 @@ export fn checkinit(c: *checker, tc: *syntax.tctx) void = {
|
|||||||
seedprimitives(c);
|
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 == nil) { return; };
|
||||||
if (file.kind != syntax.nkind.N_FILE) { return; };
|
if (file.kind != syntax.nkind.N_FILE) { return; };
|
||||||
c.file = file;
|
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
|
// §5: check_exported_type FIRST, before any byte — a producer
|
||||||
// without it can emit a dangling `.wwi`.
|
// without it can emit a dangling `.wwi`.
|
||||||
let bad: i32 = 0;
|
let bad: i32 = 0;
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ package main;
|
|||||||
|
|
||||||
import os;
|
import os;
|
||||||
import syntax;
|
import syntax;
|
||||||
import check;
|
import wcc;
|
||||||
import cgen;
|
|
||||||
import strconv;
|
import strconv;
|
||||||
|
|
||||||
// argv strings are always NUL-terminated (kernel-supplied), so the
|
// 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
|
// and the report is printed with rc=0. Mirrors w6c main.ww:162
|
||||||
// / cmd/w6c/main.c.
|
// / cmd/w6c/main.c.
|
||||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||||
let tc: tctx;
|
let nresolved: i32 = 0;
|
||||||
typesinit(&tc);
|
let nunresolved: i32 = 0;
|
||||||
let ck: checker;
|
let checkrc: i32 = wcc.resolvefile(f, 0, &nresolved, &nunresolved);
|
||||||
checkinit(&ck, &tc);
|
|
||||||
// Quiet by default; flip to 1 when debugging missing names.
|
|
||||||
ck.verbose = 0;
|
|
||||||
checkfile(&ck, f);
|
|
||||||
// "<file>: <resolved>/<resolved+unresolved> resolved"
|
// "<file>: <resolved>/<resolved+unresolved> resolved"
|
||||||
os.write(1, argstr(path).ptr, argstrlen(path): u64);
|
os.write(1, argstr(path).ptr, argstrlen(path): u64);
|
||||||
os.write(1, ": ".ptr, 2u64);
|
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, rs.ptr, rs.len: u64);
|
||||||
os.write(1, "/".ptr, 1u64);
|
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);
|
let ts: str = strconv.i64tos(total: i64, strconv.base.DEC);
|
||||||
os.write(1, ts.ptr, ts.len: u64);
|
os.write(1, ts.ptr, ts.len: u64);
|
||||||
os.write(1, " resolved\n".ptr, 10u64);
|
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
|
} else { if (mode == 99) { // '-c' — codegen / emit asm
|
||||||
let ps: parser;
|
let ps: parser;
|
||||||
parserinit(&ps, &l);
|
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
|
// miscompile, and the 994 byte-identity probe ships wrong asm
|
||||||
// silently). Mirrors w6c main.ww:162 / cmd/w6c/main.c.
|
// silently). Mirrors w6c main.ww:162 / cmd/w6c/main.c.
|
||||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||||
// #50: mirror w6c — run check before cgen so AST mutations
|
let empty: str;
|
||||||
// from #42 (size/align/offset fold) and audit §1.8 (node.type_
|
if (wcc.compilefile(f, 0, empty, 0, empty) != 0) { return 1; };
|
||||||
// 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);
|
|
||||||
};};};};
|
};};};};
|
||||||
|
|
||||||
if (l.errs > 0) { return 1; };
|
if (l.errs > 0) { return 1; };
|
||||||
|
|||||||
@@ -112,13 +112,11 @@ main(void)
|
|||||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||||
|
|
||||||
/* #93 sep layout: the selfhost tools no longer leave a single
|
/* #93 sep layout: the selfhost tools no longer leave a single
|
||||||
* next-to-source main.s. Self-build one real tool via the explicit
|
* next-to-source main.s. Self-build one real directory package and
|
||||||
* main.ww compatibility root and feed EVERY emitted
|
* feed EVERY emitted
|
||||||
* <tool>.sepwork/<pkg>.s as
|
* <tool>.sepwork/<pkg>.s as
|
||||||
* the generated-asm corpus — the root tool code plus each dep
|
* the generated-asm corpus — the root tool code plus each dep
|
||||||
* package's .s (richer than the old 3 monolithic main.s). The directory
|
* package's .s (richer than the old 3 monolithic main.s). */
|
||||||
* intentionally contains package main plus legacy file-import packages,
|
|
||||||
* so it is not a directory-package root. */
|
|
||||||
char stem[256], cmd[4096];
|
char stem[256], cmd[4096];
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
@@ -126,11 +124,11 @@ main(void)
|
|||||||
snprintf(stem, sizeof stem, "/tmp/wwa_%d_sh", getpid());
|
snprintf(stem, sizeof stem, "/tmp/wwa_%d_sh", getpid());
|
||||||
snprintf(cmd, sizeof cmd,
|
snprintf(cmd, sizeof cmd,
|
||||||
"timeout 400 %s/ww build -o %s "
|
"timeout 400 %s/ww build -o %s "
|
||||||
"%s/selfhost/cmd/w6a/main.ww >/dev/null 2>&1",
|
"%s/selfhost/cmd/w6a >/dev/null 2>&1",
|
||||||
bin, stem, cwd);
|
bin, stem, cwd);
|
||||||
if (runwait(cmd) != 0) {
|
if (runwait(cmd) != 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"w6a_ww FAIL: cannot sep-build selfhost/cmd/w6a/main.ww\n");
|
"w6a_ww FAIL: cannot sep-build selfhost/cmd/w6a\n");
|
||||||
/* a failed build can leave a partial stem/.sepwork tree. */
|
/* a failed build can leave a partial stem/.sepwork tree. */
|
||||||
fail = 1;
|
fail = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|||||||
@@ -57,9 +57,8 @@ slurp(const char *path, char **outbuf, size_t *outlen)
|
|||||||
* the linkable unit is now the per-package .o + reverse-topo .a set the
|
* the linkable unit is now the per-package .o + reverse-topo .a set the
|
||||||
* sep driver assembles (a raw `w6l <root>.o *.a libwwrt.a` from the test
|
* sep driver assembles (a raw `w6l <root>.o *.a libwwrt.a` from the test
|
||||||
* side fails — `undefined reference` — because it can't reproduce the
|
* side fails — `undefined reference` — because it can't reproduce the
|
||||||
* driver's topo order). The tools are legacy inline-package directories,
|
* driver's topo order). Drive each real directory package through the
|
||||||
* so their explicit main.ww files remain the compatibility roots. Drive
|
* full sep build twice; both compile directly and differ only in the
|
||||||
* the full sep build twice; both compile directly and differ only in the
|
|
||||||
* linker: once with the default C w6l, once with WW_W6L=w6l_ww. Diff
|
* linker: once with the default C w6l, once with WW_W6L=w6l_ww. Diff
|
||||||
* the two real tool binaries. Exercises the full archive two-pass loader
|
* the two real tool binaries. Exercises the full archive two-pass loader
|
||||||
* + reverse-topo .a resolution — a stronger link than the old single
|
* + reverse-topo .a resolution — a stronger link than the old single
|
||||||
@@ -77,7 +76,7 @@ build_and_diff(const char *bin, const char *cwd, const char *tool, int id)
|
|||||||
|
|
||||||
snprintf(cmd, sizeof cmd,
|
snprintf(cmd, sizeof cmd,
|
||||||
"timeout 300 %s/ww build -o %s "
|
"timeout 300 %s/ww build -o %s "
|
||||||
"%s/selfhost/cmd/%s/main.ww >/dev/null 2>&1",
|
"%s/selfhost/cmd/%s >/dev/null 2>&1",
|
||||||
bin, cstem, cwd, tool);
|
bin, cstem, cwd, tool);
|
||||||
if (runwait(cmd) != 0) {
|
if (runwait(cmd) != 0) {
|
||||||
fprintf(stderr, "w6l_ww FAIL: C-link sep-build of %s\n", tool);
|
fprintf(stderr, "w6l_ww FAIL: C-link sep-build of %s\n", tool);
|
||||||
@@ -86,7 +85,7 @@ build_and_diff(const char *bin, const char *cwd, const char *tool, int id)
|
|||||||
}
|
}
|
||||||
snprintf(cmd, sizeof cmd,
|
snprintf(cmd, sizeof cmd,
|
||||||
"WW_W6L=%s/w6l_ww timeout 300 %s/ww build "
|
"WW_W6L=%s/w6l_ww timeout 300 %s/ww build "
|
||||||
"-o %s %s/selfhost/cmd/%s/main.ww >/dev/null 2>&1",
|
"-o %s %s/selfhost/cmd/%s >/dev/null 2>&1",
|
||||||
bin, bin, wstem, cwd, tool);
|
bin, bin, wstem, cwd, tool);
|
||||||
if (runwait(cmd) != 0) {
|
if (runwait(cmd) != 0) {
|
||||||
fprintf(stderr, "w6l_ww FAIL: ww-link sep-build of %s\n", tool);
|
fprintf(stderr, "w6l_ww FAIL: ww-link sep-build of %s\n", tool);
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ main(void)
|
|||||||
static char wwdump_src[2048], wwdump_incs[4096];
|
static char wwdump_src[2048], wwdump_incs[4096];
|
||||||
snprintf(wwdump_src, sizeof wwdump_src, "%s/selfhost/cmd/wwdump/main.ww", cwd);
|
snprintf(wwdump_src, sizeof wwdump_src, "%s/selfhost/cmd/wwdump/main.ww", cwd);
|
||||||
snprintf(wwdump_incs, sizeof wwdump_incs,
|
snprintf(wwdump_incs, sizeof wwdump_incs,
|
||||||
"%s/lib/ww:%s/lib/encoding/utf8:%s/selfhost/cmd/wcc",
|
"%s/lib/ww:%s/lib/encoding/utf8:%s/selfhost/cmd",
|
||||||
cwd, cwd, cwd);
|
cwd, cwd, cwd);
|
||||||
cases[1].src = wwdump_src;
|
cases[1].src = wwdump_src;
|
||||||
cases[1].incs = wwdump_incs;
|
cases[1].incs = wwdump_incs;
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ main(void)
|
|||||||
{
|
{
|
||||||
char inc[4096], cmd[16384];
|
char inc[4096], cmd[16384];
|
||||||
snprintf(inc, sizeof inc,
|
snprintf(inc, sizeof inc,
|
||||||
"-I %s/lib -I %s/lib/ww -I %s/selfhost/cmd/wcc", cwd, cwd, cwd);
|
"-I %s/lib -I %s/lib/ww -I %s/selfhost/cmd", cwd, cwd, cwd);
|
||||||
char root[2048];
|
char root[2048];
|
||||||
snprintf(root, sizeof root, "%s/selfhost/cmd/w6c/main.ww", cwd);
|
snprintf(root, sizeof root, "%s/selfhost/cmd/w6c/main.ww", cwd);
|
||||||
|
|
||||||
|
|||||||
@@ -63,18 +63,15 @@ slurp_eq(const char *a, const char *b)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Each tool builds via `ww_ww build -I <local> -I lib/ww -I selfhost/cmd/wcc src`.
|
/* Each tool builds via `ww_ww build -I lib/ww -I selfhost/cmd src`.
|
||||||
* lib/ww holds the language introspection (lex/tok/ast/parse/typ/sym);
|
* lib/ww holds the language introspection (lex/tok/ast/parse/typ/sym);
|
||||||
* selfhost/cmd/wcc holds the compiler internals (mem/check/cgen*).
|
* selfhost/cmd holds the compiler-internal `wcc` directory package.
|
||||||
* Dotted `import encoding.utf8;` finds lib/encoding/utf8/ via the
|
* Dotted `import encoding.utf8;` finds lib/encoding/utf8/ via the
|
||||||
* driver's default srclib path post-task-#22 dir-enum.
|
* driver's default srclib path post-task-#22 dir-enum.
|
||||||
* Some tools have a local module dir (w6a, w6l with sibling .ww files).
|
|
||||||
* inc_local is "" for tools without one (w6c, ww, wwdump).
|
|
||||||
*/
|
*/
|
||||||
struct buildjob {
|
struct buildjob {
|
||||||
const char *tool;
|
const char *tool;
|
||||||
const char *src_rel;
|
const char *src_rel;
|
||||||
const char *inc_local;
|
|
||||||
char workdir[64];
|
char workdir[64];
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
};
|
};
|
||||||
@@ -99,20 +96,11 @@ spawn_build(const char *bin, const char *cwd, struct buildjob *j)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char cmd[4096];
|
char cmd[4096];
|
||||||
if (j->inc_local && j->inc_local[0]) {
|
snprintf(cmd, sizeof cmd,
|
||||||
snprintf(cmd, sizeof cmd,
|
"cd %s && timeout 180 %s/ww_ww build -o %s/main "
|
||||||
"cd %s && timeout 180 %s/ww_ww build -o %s/main -I %s/%s "
|
"-I %s/lib/ww -I %s/selfhost/cmd "
|
||||||
"-I %s/lib/ww "
|
"%s/%s >/dev/null 2>%s/build.err",
|
||||||
"-I %s/selfhost/cmd/wcc %s/%s >/dev/null 2>%s/build.err",
|
j->workdir, bin, j->workdir, cwd, cwd, cwd, j->src_rel, j->workdir);
|
||||||
j->workdir, bin, j->workdir, cwd, j->inc_local,
|
|
||||||
cwd, cwd, cwd, j->src_rel, j->workdir);
|
|
||||||
} else {
|
|
||||||
snprintf(cmd, sizeof cmd,
|
|
||||||
"cd %s && timeout 180 %s/ww_ww build -o %s/main "
|
|
||||||
"-I %s/lib/ww "
|
|
||||||
"-I %s/selfhost/cmd/wcc %s/%s >/dev/null 2>%s/build.err",
|
|
||||||
j->workdir, bin, j->workdir, cwd, cwd, cwd, j->src_rel, j->workdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t p = fork();
|
pid_t p = fork();
|
||||||
if (p < 0) {
|
if (p < 0) {
|
||||||
@@ -184,11 +172,11 @@ main(void)
|
|||||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||||
|
|
||||||
struct buildjob jobs[] = {
|
struct buildjob jobs[] = {
|
||||||
{ "w6c", "selfhost/cmd/w6c/main.ww", "", {0}, 0 },
|
{ "w6c", "selfhost/cmd/w6c/main.ww", {0}, 0 },
|
||||||
{ "w6a", "selfhost/cmd/w6a/main.ww", "selfhost/cmd/w6a", {0}, 0 },
|
{ "w6a", "selfhost/cmd/w6a", {0}, 0 },
|
||||||
{ "w6l", "selfhost/cmd/w6l/main.ww", "selfhost/cmd/w6l", {0}, 0 },
|
{ "w6l", "selfhost/cmd/w6l", {0}, 0 },
|
||||||
{ "ww", "selfhost/cmd/ww/main.ww", "", {0}, 0 },
|
{ "ww", "selfhost/cmd/ww/main.ww", {0}, 0 },
|
||||||
{ "wwdump", "selfhost/cmd/wwdump/main.ww", "", {0}, 0 },
|
{ "wwdump", "selfhost/cmd/wwdump/main.ww", {0}, 0 },
|
||||||
};
|
};
|
||||||
const int n = (int)(sizeof jobs / sizeof jobs[0]);
|
const int n = (int)(sizeof jobs / sizeof jobs[0]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
// crossmod — sibling module whose probe() takes a param named like the
|
|
||||||
// module `shadowmod` that paramshadowmod (NOT crossmod) imports. The
|
|
||||||
// shadow rule is filtered by the BINDING's own module (src_imports
|
|
||||||
// cur_mod filter): crossmod carries no `import shadowmod`, so this param
|
|
||||||
// must NOT trip even though a sibling module in the same bundle imports
|
|
||||||
// that leaf. Legit-form survivor of the abolished self-import tolerance.
|
|
||||||
|
|
||||||
package crossmod;
|
|
||||||
|
|
||||||
export fn probe(shadowmod: str) i32 = {
|
|
||||||
return shadowmod.len;
|
|
||||||
};
|
|
||||||
11
test/wcc/data/paramshadowmod/crossmod/crossmod.ww
Normal file
11
test/wcc/data/paramshadowmod/crossmod/crossmod.ww
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// crossmod — directory package whose probe() takes a param named like the
|
||||||
|
// module `shadowmod` that paramshadowmod (NOT crossmod) imports. The
|
||||||
|
// shadow rule is filtered by the binding's own module (src_imports
|
||||||
|
// cur_mod filter): crossmod carries no `import shadowmod`, so this param
|
||||||
|
// must NOT trip even though a sibling package imports that leaf.
|
||||||
|
|
||||||
|
package crossmod;
|
||||||
|
|
||||||
|
export fn probe(shadowmod: str) i32 = {
|
||||||
|
return shadowmod.len;
|
||||||
|
};
|
||||||
@@ -133,60 +133,61 @@ fn textcount(s: str, sym: str) i32 = {
|
|||||||
testenv.clean(td);
|
testenv.clean(td);
|
||||||
};
|
};
|
||||||
|
|
||||||
// barevalue (#55 cgen-side sibling) — the migrated 794 carrier
|
// barevalue (#55 cgen-side sibling) — the migrated 794 compiler carrier
|
||||||
// (test/wcc/794_xmod_ident_prefer.c, retired with this row; its header
|
// (test/wcc/794_xmod_ident_prefer.c, retired with this row; its header
|
||||||
// documents both #55 halves). A bare VALUE ident read inside an
|
// documents both #55 halves). A bare VALUE ident read inside an
|
||||||
// imported module must be classified by the checker-stamped type, not
|
// imported module must be classified by the checker-stamped type, not
|
||||||
// a unit-wide leaf table: aa exports `v: i32 = 7` and getv() reads the
|
// a unit-wide leaf table: aa exports `v: i32 = 7` and getv() reads the
|
||||||
// bare `v`; the root declares a same-leaf `fn v() i64`. FLAT layout
|
// bare `v`; the root declares a same-leaf `fn v() i64`. This compiler
|
||||||
// (file-keyed import) is REQUIRED — both files fold into one unit so
|
// collision requires one explicitly composed raw unit; directory packages
|
||||||
// the foreign fn lands in the leaf table; a dir-keyed aa/ compiles aa
|
// correctly isolate the leaf tables and the driver no longer folds source
|
||||||
// as its own sep unit where main.v is invisible and the collision
|
// imports. Pre-fix wwstage cgen took fnretlookup's leaf
|
||||||
// cannot express. Pre-fix wwstage cgen took fnretlookup's leaf
|
|
||||||
// fallback and emitted `LEAQ aa.v(SB)` (fn address, no load) — the
|
// fallback and emitted `LEAQ aa.v(SB)` (fn address, no load) — the
|
||||||
// binary exited 0; cstage loads 7 (LEAQ+MOVSXD). Both drivers must
|
// binary exited 0; cstage loads 7 (LEAQ+MOVSXD). Both compilers must
|
||||||
// build, run 7, and the flat __root.s must be cs==ww byte-identical
|
// emit byte-identical assembly and the raw fixture must run 7.
|
||||||
// (rule 10) — the stronger assertion set the carrier deferred while
|
|
||||||
// the cgen side was open.
|
|
||||||
@test fn barevalue() void = {
|
@test fn barevalue() void = {
|
||||||
let td: str = testenv.fresh();
|
let td: str = testenv.fresh();
|
||||||
testenv.writefile(strings.concat(td, "/aa.ww"), strings.concat(
|
let unit: str = strings.concat(td, "/barevalue.unit.ww");
|
||||||
|
testenv.writefile(unit, strings.concat(
|
||||||
|
"//ww:module aa\n",
|
||||||
"package aa;\n",
|
"package aa;\n",
|
||||||
"export let v: i32 = 7;\n",
|
"export let v: i32 = 7;\n",
|
||||||
"export fn getv() i32 = {\n",
|
"export fn getv() i32 = {\n",
|
||||||
" return v;\n",
|
" return v;\n",
|
||||||
"};\n"));
|
"};\n",
|
||||||
testenv.writefile(strings.concat(td, "/main.ww"), strings.concat(
|
"//ww:module-reset\n",
|
||||||
"package main;\n",
|
"package main;\n",
|
||||||
"import aa;\n",
|
"import aa;\n",
|
||||||
"fn v() i64 = { return 100; };\n",
|
"fn v() i64 = { return 100; };\n",
|
||||||
"export fn main() i32 = {\n",
|
"export fn main() i32 = {\n",
|
||||||
" return aa.getv();\n",
|
" return aa.getv();\n",
|
||||||
"};\n"));
|
"};\n"));
|
||||||
let drvs: []str = ["ww", "ww_ww"];
|
let comps: []str = ["w6c", "w6c_ww"];
|
||||||
let tags: []str = ["cs", "ww"];
|
let tags: []str = ["cs", "ww"];
|
||||||
let asms: []str = ["", ""];
|
let asms: []str = ["", ""];
|
||||||
let s: i32 = 0;
|
let s: i32 = 0;
|
||||||
for (s < 2) {
|
for (s < 2) {
|
||||||
let stem: str = strings.concat(td, "/prog.", tags[s]);
|
asms[s] = strings.concat(td, "/", tags[s], ".s");
|
||||||
let av: []str = [testenv.driver(drvs[s]), "build", "-o", stem,
|
let av: []str = [testenv.driver(comps[s]), "-o", asms[s], unit];
|
||||||
"-I", td, strings.concat(td, "/main.ww")];
|
|
||||||
if (runcode(td, strings.concat("build_", tags[s]), av) != 0) {
|
if (runcode(td, strings.concat("build_", tags[s]), av) != 0) {
|
||||||
fail("barevalue", strings.concat(drvs[s], " build failed"));
|
fail("barevalue", strings.concat(comps[s], " compile failed"));
|
||||||
};
|
};
|
||||||
let rav: []str = [stem];
|
|
||||||
if (runcode(td, strings.concat("run_", tags[s]), rav) != 7) {
|
|
||||||
fail("barevalue", strings.concat(drvs[s], " exit != 7 ",
|
|
||||||
"(bare v in aa.getv must LOAD aa.v, not take the ",
|
|
||||||
"foreign fn's address)"));
|
|
||||||
};
|
|
||||||
asms[s] = testenv.readfile(strings.concat(stem,
|
|
||||||
".sepwork/__root.s"));
|
|
||||||
s += 1;
|
s += 1;
|
||||||
};
|
};
|
||||||
if (!testenv.same(asms[0], asms[1])) {
|
if (!testenv.same(testenv.readfile(asms[0]), testenv.readfile(asms[1]))) {
|
||||||
fail("barevalue", "cs .s != ww .s (rule 10)");
|
fail("barevalue", "cs .s != ww .s (rule 10)");
|
||||||
};
|
};
|
||||||
|
let obj: str = strings.concat(td, "/barevalue.o");
|
||||||
|
let aav: []str = [testenv.driver("w6a"), "-o", obj, asms[0]];
|
||||||
|
if (runcode(td, "assemble", aav) != 0) { fail("barevalue", "w6a failed"); };
|
||||||
|
let prog: str = strings.concat(td, "/barevalue");
|
||||||
|
let lav: []str = [testenv.driver("w6l"), "-o", prog, obj,
|
||||||
|
strings.concat(testenv.repo(), "/out/lib/libwwrt.a")];
|
||||||
|
if (runcode(td, "link", lav) != 0) { fail("barevalue", "w6l failed"); };
|
||||||
|
let rav: []str = [prog];
|
||||||
|
if (runcode(td, "run", rav) != 7) {
|
||||||
|
fail("barevalue", "bare v loaded the foreign fn address");
|
||||||
|
};
|
||||||
testenv.clean(td);
|
testenv.clean(td);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -198,7 +199,8 @@ fn textcount(s: str, sym: str) i32 = {
|
|||||||
// the mirror corner (d) in cgdot. Runtime pre-fix: 141, want 42.
|
// the mirror corner (d) in cgdot. Runtime pre-fix: 141, want 42.
|
||||||
@test fn defshadow() void = {
|
@test fn defshadow() void = {
|
||||||
let td: str = testenv.fresh();
|
let td: str = testenv.fresh();
|
||||||
testenv.writefile(strings.concat(td, "/p5aa.ww"), strings.concat(
|
assert(os.mkdir(strings.concat(td, "/p5aa"), 493) == 0);
|
||||||
|
testenv.writefile(strings.concat(td, "/p5aa/p5aa.ww"), strings.concat(
|
||||||
"package p5aa;\n",
|
"package p5aa;\n",
|
||||||
"export def MSG: i32 = 3;\n"));
|
"export def MSG: i32 = 3;\n"));
|
||||||
testenv.writefile(strings.concat(td, "/main.ww"), strings.concat(
|
testenv.writefile(strings.concat(td, "/main.ww"), strings.concat(
|
||||||
@@ -241,7 +243,8 @@ fn textcount(s: str, sym: str) i32 = {
|
|||||||
// gate (proves the checker stamps the N_DOT fn rvalue as TY_FN).
|
// gate (proves the checker stamps the N_DOT fn rvalue as TY_FN).
|
||||||
@test fn modqualfnval() void = {
|
@test fn modqualfnval() void = {
|
||||||
let td: str = testenv.fresh();
|
let td: str = testenv.fresh();
|
||||||
testenv.writefile(strings.concat(td, "/p6aa.ww"), strings.concat(
|
assert(os.mkdir(strings.concat(td, "/p6aa"), 493) == 0);
|
||||||
|
testenv.writefile(strings.concat(td, "/p6aa/p6aa.ww"), strings.concat(
|
||||||
"package p6aa;\n",
|
"package p6aa;\n",
|
||||||
"export fn hit(x: i32) i32 = { return x + 40; };\n"));
|
"export fn hit(x: i32) i32 = { return x + 40; };\n"));
|
||||||
testenv.writefile(strings.concat(td, "/main.ww"), strings.concat(
|
testenv.writefile(strings.concat(td, "/main.ww"), strings.concat(
|
||||||
|
|||||||
@@ -182,7 +182,8 @@ fn xrow(label: str, esrc: str, msrc: str, expectbuild: bool) void = {
|
|||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < 2) {
|
for (i < 2) {
|
||||||
let td: str = testenv.fresh();
|
let td: str = testenv.fresh();
|
||||||
testenv.writefile(strings.concat(td, "/e.ww"), esrc);
|
assert(os.mkdir(strings.concat(td, "/e"), 493) == 0);
|
||||||
|
testenv.writefile(strings.concat(td, "/e/e.ww"), esrc);
|
||||||
testenv.writefile(strings.concat(td, "/main.ww"), msrc);
|
testenv.writefile(strings.concat(td, "/main.ww"), msrc);
|
||||||
let av: []str = [testenv.driver(drvs[i]), "build", "-I", td,
|
let av: []str = [testenv.driver(drvs[i]), "build", "-I", td,
|
||||||
strings.concat(td, "/main.ww")];
|
strings.concat(td, "/main.ww")];
|
||||||
|
|||||||
Reference in New Issue
Block a user