test: prove package initialization semantics
This commit is contained in:
11
Makefile
11
Makefile
@@ -349,7 +349,7 @@ $(PACKAGE_TEST_BIN): $(PACKAGE_TEST_SRC) $(WWTEST_BIN) \
|
|||||||
test-package: $(PACKAGE_TEST_BIN) $(WWTEST_BIN) $(BIN)/ww $(BIN)/ww_ww \
|
test-package: $(PACKAGE_TEST_BIN) $(WWTEST_BIN) $(BIN)/ww $(BIN)/ww_ww \
|
||||||
$(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6a_ww \
|
$(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6a_ww \
|
||||||
$(BIN)/w6l $(BIN)/w6l_ww $(LIB)/libwwrt.a
|
$(BIN)/w6l $(BIN)/w6l_ww $(LIB)/libwwrt.a
|
||||||
@WW_PACKAGE_REPO=$(CURDIR) $(CURDIR)/$(PACKAGE_TEST_BIN)
|
@WW_PACKAGE_REPO=$(CURDIR) $(CURDIR)/$(PACKAGE_TEST_BIN) -timeout-ms=120000
|
||||||
|
|
||||||
# ---- directories -------------------------------------------------------
|
# ---- directories -------------------------------------------------------
|
||||||
$(BIN) $(LIB) $(OBJ)/wcc $(OBJ)/ww $(OBJ)/wwdump $(OBJ)/w6c $(OBJ)/w6a $(OBJ)/w6l $(OBJ)/rt:
|
$(BIN) $(LIB) $(OBJ)/wcc $(OBJ)/ww $(OBJ)/wwdump $(OBJ)/w6c $(OBJ)/w6a $(OBJ)/w6l $(OBJ)/rt:
|
||||||
@@ -384,10 +384,17 @@ BYTEID_WW_TARGETS = $(BYTEID_WW_TESTS:%=wwtest/%)
|
|||||||
# export arguments, link rejects), NOT byteid suites: they run under
|
# export arguments, link rejects), NOT byteid suites: they run under
|
||||||
# test-compiler beside the surviving residual carriers.
|
# test-compiler beside the surviving residual carriers.
|
||||||
SEP_WW_TESTS = test/sep/sepbuild_test.ww test/sep/sepimport_test.ww \
|
SEP_WW_TESTS = test/sep/sepbuild_test.ww test/sep/sepimport_test.ww \
|
||||||
test/sep/seplink_test.ww test/sep/sepscratch_test.ww \
|
test/sep/seplink_test.ww test/sep/sepinit_test.ww \
|
||||||
|
test/sep/sepscratch_test.ww \
|
||||||
test/sep/septest_test.ww test/sep/m3sep_test.ww \
|
test/sep/septest_test.ww test/sep/m3sep_test.ww \
|
||||||
test/sep/localbuild_test.ww test/sep/importdir_test.ww
|
test/sep/localbuild_test.ww test/sep/importdir_test.ww
|
||||||
SEP_WW_TARGETS = $(SEP_WW_TESTS:%=wwtest/%)
|
SEP_WW_TARGETS = $(SEP_WW_TESTS:%=wwtest/%)
|
||||||
|
SEP_LIMITEXEC_BIN = $(BIN)/sep-limitexec
|
||||||
|
|
||||||
|
$(SEP_LIMITEXEC_BIN): test/sep/limitexec.c | $(BIN)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
wwtest/test/sep/sepinit_test.ww: $(SEP_LIMITEXEC_BIN)
|
||||||
# Ww-native lib env/OS arranger observers: the env contracts of the
|
# Ww-native lib env/OS arranger observers: the env contracts of the
|
||||||
# lib/os and lib/dirs suites (getenv cohorts, XDG cohorts, the dirs
|
# lib/os and lib/dirs suites (getenv cohorts, XDG cohorts, the dirs
|
||||||
# too-long abort) need per-row env construction ww cannot self-arrange
|
# too-long abort) need per-row env construction ww cannot self-arrange
|
||||||
|
|||||||
@@ -3078,11 +3078,13 @@ binding is identical before reusing its compile action. A different binding is
|
|||||||
a deterministic package-resolution failure for the roots that reach it, rather
|
a deterministic package-resolution failure for the roots that reach it, rather
|
||||||
than a first-root-wins build.
|
than a first-root-wins build.
|
||||||
|
|
||||||
A production action failure blocks exactly the roots that reach it. A
|
A production action failure is attributed to exactly the roots that reach it,
|
||||||
root-local compile or link failure does not suppress a successfully built
|
but the complete command is one publication transaction. The driver may
|
||||||
sibling product: the command records completion per product, and the
|
continue enough of the already validated plan to retain deterministic action
|
||||||
coordinator can run and report successful siblings while attributing each
|
and product diagnostics, but one failed producer, linker, status stage, or
|
||||||
missing product as a build failure. The single union build and completed test
|
commit suppresses every new action voucher, tool record, product, and status
|
||||||
|
from that request. The coordinator therefore runs no sibling test binary from
|
||||||
|
a rejected union build. After one successful union build, the completed test
|
||||||
products share the coordinator's existing `-j` process bound; captured output
|
products share the coordinator's existing `-j` process bound; captured output
|
||||||
is still emitted only in byte-sorted directory/package order.
|
is still emitted only in byte-sorted directory/package order.
|
||||||
|
|
||||||
@@ -3153,11 +3155,11 @@ compiler-owned dispatcher with empty output is reported as `[no tests]`.
|
|||||||
|
|
||||||
Persistent workdirs keep a global driver/compiler/assembler/stamp identity and
|
Persistent workdirs keep a global driver/compiler/assembler/stamp identity and
|
||||||
per-action committed units. When that global identity is stale, the command
|
per-action committed units. When that global identity is stale, the command
|
||||||
first removes every old `.unit.ww` voucher while leaving artifacts recoverable.
|
forces every requested action cold while preserving the complete old generation
|
||||||
It can then commit the new identity even if one root fails: successful actions
|
as rollback state. New tool records, artifacts, units, products, statuses, and
|
||||||
have freshly committed units, whereas failed or no-longer-requested actions
|
the new stamp become visible only in the request-wide commit after every product
|
||||||
cannot be reused. A retry therefore recompiles the failed action without
|
has staged successfully. A rejected request leaves the old generation
|
||||||
discarding unchanged canonical packages built for independent products.
|
byte-identical, and a retry cannot reuse any uncommitted work from the rejection.
|
||||||
|
|
||||||
Warm reuse compares the staged owner-only unit, committed artifacts, and the
|
Warm reuse compares the staged owner-only unit, committed artifacts, and the
|
||||||
actual bytes of each direct dependency export. A changed shared dependency is
|
actual bytes of each direct dependency export. A changed shared dependency is
|
||||||
@@ -4176,12 +4178,13 @@ succeeds; a rejected request therefore leaves neither directory behind.
|
|||||||
|
|
||||||
Resolution, identity collision checks, contextual legality, dependency-failure
|
Resolution, identity collision checks, contextual legality, dependency-failure
|
||||||
propagation, cycles, command kind, publication paths, and action closures all
|
propagation, cycles, command kind, publication paths, and action closures all
|
||||||
finish before cold scratch acquisition, product status removal, stale-voucher
|
finish before cold scratch acquisition, tool identity staging, producer
|
||||||
invalidation, tool identity records, producer execution, publication, or
|
execution, publication, or runtime execution. A request whose every product is
|
||||||
runtime execution. A request whose every product is already invalid returns
|
already invalid returns without acquiring scratch. If a later producer or
|
||||||
without acquiring scratch; independent valid sibling products retain the
|
product fails, otherwise viable siblings may have been produced only into the
|
||||||
existing isolated-build behavior. A forbidden warm request leaves committed
|
same transaction; none is committed or executed. A forbidden or otherwise
|
||||||
vouchers, status files, tool records, and products byte-unchanged.
|
rejected warm request leaves committed vouchers, status files, tool records,
|
||||||
|
and products byte-unchanged.
|
||||||
|
|
||||||
This is only manifest-free local source-tree behavior. It does not implement
|
This is only manifest-free local source-tree behavior. It does not implement
|
||||||
Go modules, module vendor mode, `go.mod`, `vendor/modules.txt`, importcfg, build
|
Go modules, module vendor mode, `go.mod`, `vendor/modules.txt`, importcfg, build
|
||||||
@@ -4557,20 +4560,15 @@ qualifier or canonical dependency. A package-scope declaration collides with
|
|||||||
an equal import binding from any contributing file, matching Go's reconciliation
|
an equal import binding from any contributing file, matching Go's reconciliation
|
||||||
of package and file scopes. Conflicting production package clauses remain a
|
of package and file scopes. Conflicting production package clauses remain a
|
||||||
loader-owned deterministic error before producers. Compiler-owned scope or use
|
loader-owned deterministic error before producers. Compiler-owned scope or use
|
||||||
errors may invoke the compiler, but the driver removes that action's staged
|
errors may invoke the compiler, but every action artifact remains staged under
|
||||||
`.new` unit/export/assembly/object/archive files instead of renaming them. No
|
an adjacent `.new` name. No completion/status marker is written and no product
|
||||||
completion/status marker is written, and no publication occurs after a failed
|
is published after a failed compile. Once every action and product has staged,
|
||||||
compile. If an artifact rename itself fails after an earlier rename has
|
the driver preserves each existing destination under a request-owned backup,
|
||||||
published part of a new generation, the driver removes every committed unit
|
installs the complete new generation, and rolls all installed destinations back
|
||||||
voucher as well as the remaining staged files. Before the first artifact
|
if any installation fails. Unit vouchers and the global stamp are transaction
|
||||||
rename, it must successfully remove the workdir identity stamp; failure is a
|
members rather than early invalidation markers. Thus a rejected or interrupted
|
||||||
pre-commit rejection that leaves the prior artifact generation untouched. The
|
request leaves the previous committed generation byte-identical and removes all
|
||||||
stamp remains absent after any partial commit, and later actions in that
|
remaining stages; a mixed `.wwi`/object/archive generation is never reusable.
|
||||||
invocation cannot take the freshness shortcut. Each non-reusable action also
|
|
||||||
loses its old unit voucher before its producers run. The next request must
|
|
||||||
therefore rebuild the incomplete action set and reconsider direct importers; a
|
|
||||||
partly replaced `.wwi` or a failed importer can never make an old importer
|
|
||||||
voucher look fresh.
|
|
||||||
|
|
||||||
Package kind follows the declaration. `package main`, not a path component,
|
Package kind follows the declaration. `package main`, not a path component,
|
||||||
marks a command. A path ending in `main` remains importable when it declares a
|
marks a command. A path ending in `main` remains importable when it declares a
|
||||||
@@ -4690,8 +4688,8 @@ The behavior follows pinned official Go 1.26.5 source at commit
|
|||||||
[`cmd/go/internal/test/test.go`, lines 1133–1226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1226)).
|
[`cmd/go/internal/test/test.go`, lines 1133–1226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1226)).
|
||||||
|
|
||||||
Section 11.19 completes ordinary explicit aliases while retaining dotted,
|
Section 11.19 completes ordinary explicit aliases while retaining dotted,
|
||||||
unquoted paths. Grouped, quoted, dot, and blank imports remain deliberately
|
unquoted paths. Section 11.20 adds blank side-effect imports without adding a
|
||||||
unimplemented.
|
name. Grouped, quoted, and dot imports remain deliberately unimplemented.
|
||||||
|
|
||||||
The focused native observer
|
The focused native observer
|
||||||
`declared_name_identity_and_file_import_scope` generates every tree
|
`declared_name_identity_and_file_import_scope` generates every tree
|
||||||
@@ -4820,19 +4818,21 @@ Go's leaf comparison: a binding equal to the path leaf says `imported and not
|
|||||||
used`; any other binding, including an unusual default declared name, says
|
used`; any other binding, including an unusual default declared name, says
|
||||||
`imported as <name> and not used`.
|
`imported as <name> and not used`.
|
||||||
|
|
||||||
`_` is rejected at parse time as `blank import alias _ is not implemented`.
|
`_` selects the no-binding side-effect mode completed in section 11.20. It is
|
||||||
Grouped imports, quoted paths, dot imports, and blank imports are deliberately
|
never an ordinary effective qualifier and therefore neither collides with
|
||||||
deferred rather than partially implemented.
|
another `_` occurrence nor receives an unused diagnostic. Grouped imports,
|
||||||
|
quoted paths, and dot imports remain deliberately deferred.
|
||||||
|
|
||||||
#### Graph, export, artifact, and persistence identity
|
#### Graph, export, artifact, and persistence identity
|
||||||
|
|
||||||
The imports-only parser and full parser share one import-spec routine and retain
|
The imports-only parser and full parser share one import-spec routine and retain
|
||||||
alias and dotted path separately. Both drivers sort and resolve occurrences by
|
ordinary alias, blank mode, and dotted path separately. Both drivers sort and
|
||||||
the dotted spelling, perform contextual internal and nearest-first vendor checks
|
resolve occurrences by the dotted spelling, perform contextual internal and
|
||||||
at every real site, and intern the expanded canonical action. `sepbind` and
|
nearest-first vendor checks at every real site, and intern the expanded
|
||||||
`--import-map` continue to mean source dotted spelling to expanded vendor
|
canonical action. `sepbind` and `--import-map` continue to mean source dotted
|
||||||
identity; neither contains the alias. Repeated occurrences remain separate
|
spelling to expanded vendor identity; neither contains the alias or `_`.
|
||||||
scope facts but form one sorted canonical edge/action.
|
Repeated occurrences remain separate file facts but form one sorted canonical
|
||||||
|
edge/action.
|
||||||
|
|
||||||
The compiler independently reads the direct dependency's declared name. It
|
The compiler independently reads the direct dependency's declared name. It
|
||||||
installs the explicit alias when present or that declared name otherwise, while
|
installs the explicit alias when present or that declared name otherwise, while
|
||||||
@@ -4877,7 +4877,7 @@ unchanged semantic bytes stop reverse rebuilding.
|
|||||||
Parser, identity, alias, declaration, binding, and scope failures occur before
|
Parser, identity, alias, declaration, binding, and scope failures occur before
|
||||||
publication. Compiler-owned failures may start the compiler, but staged unit,
|
publication. Compiler-owned failures may start the compiler, but staged unit,
|
||||||
interface, assembly, object, archive, voucher, stamp, status, and product state
|
interface, assembly, object, archive, voucher, stamp, status, and product state
|
||||||
is discarded or invalidated under section 11.18's partial-commit protocol.
|
is discarded under section 11.20's request transaction.
|
||||||
|
|
||||||
#### Stage and observer ownership
|
#### Stage and observer ownership
|
||||||
|
|
||||||
@@ -4896,11 +4896,300 @@ artifact, `.wwi`, and rejection-state matrix. The existing
|
|||||||
`declared_name_identity_and_file_import_scope` observer owns default-versus-
|
`declared_name_identity_and_file_import_scope` observer owns default-versus-
|
||||||
stable-alias invalidation and propagation. Existing directory, command-test,
|
stable-alias invalidation and propagation. Existing directory, command-test,
|
||||||
vendor, recursive, exact-argv, link-closure, persistent-workdir, and
|
vendor, recursive, exact-argv, link-closure, persistent-workdir, and
|
||||||
partial-commit observers retain their broader variant and action ownership.
|
request-transaction observers retain their broader variant and action ownership.
|
||||||
Every applicable proof runs Cstage and WWstage from independent cold roots and
|
Every applicable proof runs Cstage and WWstage from independent cold roots and
|
||||||
compares diagnostics, normalized tool arguments, artifacts, binaries, and
|
compares diagnostics, normalized tool arguments, artifacts, binaries, and
|
||||||
runtime output.
|
runtime output.
|
||||||
|
|
||||||
|
### 11.20 Implemented blank side-effect imports and package initialization
|
||||||
|
|
||||||
|
WW now completes the third file-local import mode and the package
|
||||||
|
initialization path needed to give it meaning:
|
||||||
|
|
||||||
|
```ww
|
||||||
|
import acme.codec; // qualifier from the dependency declaration
|
||||||
|
import stable acme.codec; // explicit file-local qualifier stable
|
||||||
|
import _ acme.codec; // no qualifier; initialization side effect only
|
||||||
|
```
|
||||||
|
|
||||||
|
A blank occurrence retains its dotted source spelling, owning file, line,
|
||||||
|
column, source section, and resolved canonical action, but creates no source
|
||||||
|
binding and is exempt from unused-import checking. It exposes neither
|
||||||
|
`wire.Name`, `codec.Name`, nor bare `Name`. Resolution always uses
|
||||||
|
`acme.codec`, never `_`: missing-package, self-import, cycle, final-`internal`,
|
||||||
|
nearest-first vendor, vendor-spelling, and imported-`main` checks run at every
|
||||||
|
blank site exactly as they do for a named occurrence. A vendored blank import
|
||||||
|
therefore keeps a source-to-expanded-identity `--import-map`; `_` enters no
|
||||||
|
map, action key, task symbol, artifact, voucher, stamp, variant, or link input.
|
||||||
|
|
||||||
|
Repeated blank imports of one path, in one file or several files, are valid.
|
||||||
|
A blank occurrence may coexist with the default binding or any explicit alias
|
||||||
|
of the same path. Every named occurrence remains independently subject to its
|
||||||
|
ordinary duplicate-binding and usage rules. All occurrences survive in the
|
||||||
|
owner unit and per-site validation data, while their package-wide union still
|
||||||
|
forms one sorted canonical dependency edge, one package action, and one direct
|
||||||
|
compiler export input.
|
||||||
|
|
||||||
|
#### Pinned Go evidence
|
||||||
|
|
||||||
|
The reference is official Go 1.26.5 at commit
|
||||||
|
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||||
|
|
||||||
|
- `ast.ImportSpec` keeps an optional local `Name`, including `_`, independent
|
||||||
|
from `Path`, and the parser reads that optional name before the path
|
||||||
|
([`go/ast/ast.go`, lines 908–915 and 939–955](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/ast/ast.go#L908-L955),
|
||||||
|
[`go/parser/parser.go`, lines 2509–2546](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2509-L2546)).
|
||||||
|
Function parsing treats `init` as an ordinary syntactic function name; its
|
||||||
|
special meaning is assigned later
|
||||||
|
([`go/parser/parser.go`, lines 2784–2842](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2784-L2842)).
|
||||||
|
- `go/types` creates an import object for each occurrence, inserts no binding
|
||||||
|
for `_`, exempts `_` from unused checking, and keeps a valid `init` function
|
||||||
|
out of package scope while checking its body and signature
|
||||||
|
([`go/types/decl.go`, lines 16–33](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/decl.go#L16-L33),
|
||||||
|
[`go/types/resolver.go`, lines 103–124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L103-L124),
|
||||||
|
[lines 279–350](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L279-L350),
|
||||||
|
[lines 400–433](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L400-L433),
|
||||||
|
[lines 701–716](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L701-L716)).
|
||||||
|
The production compiler equivalent is
|
||||||
|
[`cmd/compile/internal/types2/resolver.go`, lines 90–111](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L90-L111),
|
||||||
|
[lines 264–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L264-L335),
|
||||||
|
[lines 416–444](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L416-L444)
|
||||||
|
and
|
||||||
|
[lines 706–721](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L721).
|
||||||
|
- Official import testdata accepts repeated blanks and blank plus default or
|
||||||
|
explicit named imports of the same path, while diagnosing only the unused
|
||||||
|
named occurrences
|
||||||
|
([`internal/types/testdata/check/importdecl0/importdecl0a.go`, lines 9–31 and 43–52](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L52)).
|
||||||
|
Multiple valid init declarations, invalid signatures, and direct
|
||||||
|
invisibility are pinned by
|
||||||
|
[`test/init.go`, lines 12–18](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/init.go#L12-L18),
|
||||||
|
[`test/noinit.go`, lines 315–326](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/noinit.go#L315-L326),
|
||||||
|
[`internal/types/testdata/check/decls0.go`, lines 40–46](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/decls0.go#L40-L46),
|
||||||
|
and
|
||||||
|
[`decls1.go`, lines 141–146](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/decls1.go#L141-L146).
|
||||||
|
- After constants, variable initialization chooses the declaration with the
|
||||||
|
fewest unresolved variable dependencies and uses source order as its tie;
|
||||||
|
references through functions are dependencies. Cycle reporting is
|
||||||
|
deterministic, and graph removal continues so later independent cycles are
|
||||||
|
also diagnosed
|
||||||
|
([`go/types/initorder.go`, lines 19–185 and 226–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/initorder.go#L19-L335),
|
||||||
|
[`cmd/compile/internal/types2/initorder.go`, lines 16–182 and 223–332](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/initorder.go#L16-L332)).
|
||||||
|
Source ties and calls are exercised by
|
||||||
|
[`go/types/api_test.go`, lines 1408–1619](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/api_test.go#L1408-L1619),
|
||||||
|
with cycle ordering in
|
||||||
|
[`internal/types/testdata/check/init0.go`, lines 22–89](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/init0.go#L22-L89).
|
||||||
|
- The compiler first attempts static initialization and serializes remaining
|
||||||
|
ordered assignments into a compiler-generated init function. It then emits
|
||||||
|
one package task whose dependency tasks are separate `R_INITORDER`
|
||||||
|
relocations and whose payload is an ordered function-pointer list
|
||||||
|
([`cmd/compile/internal/staticinit/sched.go`, lines 34–145](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/staticinit/sched.go#L34-L145),
|
||||||
|
[`cmd/compile/internal/noder/writer.go`, lines 2717–2773](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/writer.go#L2717-L2773),
|
||||||
|
[`cmd/compile/internal/noder/reader.go`, lines 3288–3345](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/reader.go#L3288-L3345),
|
||||||
|
[lines 3389–3416](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/reader.go#L3389-L3416),
|
||||||
|
[`cmd/compile/internal/pkginit/init.go`, lines 20–145](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/pkginit/init.go#L20-L145)).
|
||||||
|
The requested historical `cmd/compile/internal/walk/init.go` path does not
|
||||||
|
exist at this tag; the noder, `staticinit`, and `pkginit` files above are the
|
||||||
|
active implementation.
|
||||||
|
- The linker schedules ready tasks by canonical task symbol and emits each
|
||||||
|
exactly once, and the runtime executes those tasks before user main
|
||||||
|
([`cmd/link/internal/ld/inittask.go`, lines 19–39 and 104–180](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/inittask.go#L19-L180),
|
||||||
|
[`cmd/link/internal/ld/heap.go`, lines 56–99](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/heap.go#L56-L99),
|
||||||
|
[`runtime/proc.go`, lines 203–290](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/runtime/proc.go#L203-L290),
|
||||||
|
[lines 8049–8124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/runtime/proc.go#L8049-L8124)).
|
||||||
|
The `issue31636` packages exercise imports written out of order, while the
|
||||||
|
linker queue above—not that fixture's stale comment—pins lexical ready-task
|
||||||
|
order
|
||||||
|
([`test/fixedbugs/issue31636.dir/main.go`, lines 7–17](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/issue31636.dir/main.go#L7-L17)).
|
||||||
|
- `go/build` specifies sorted directory presentation; its default path obtains
|
||||||
|
byte-sorted names and then classifies production, internal-test, and
|
||||||
|
external-test files/imports separately
|
||||||
|
([`go/build/build.go`, lines 108–111 and 193–207](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L108-L207),
|
||||||
|
[`os/dir.go`, lines 109–125](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/dir.go#L109-L125),
|
||||||
|
[`go/build/build.go`, lines 948–1040](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L948-L1040),
|
||||||
|
[lines 1061–1063](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1061-L1063),
|
||||||
|
[lines 1512–1518](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1512-L1518)).
|
||||||
|
The test loader constructs and rewrites canonical internal, external, and
|
||||||
|
generated-main variants before work actions. In the internal variant it
|
||||||
|
presents the already-sorted production category first and the already-sorted
|
||||||
|
internal-test category second, rather than globally sorting the merge; its
|
||||||
|
effective-test-cycle rule is pinned by
|
||||||
|
[`cmd/go/internal/load/test.go`, lines 85–101, 175–293, and 421–550](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L550)
|
||||||
|
and
|
||||||
|
[`cmd/go/testdata/script/list_test_cycle.txt`, lines 1–20](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_test_cycle.txt#L1-L20).
|
||||||
|
Compile/link action ownership remains canonical in
|
||||||
|
[`cmd/go/internal/work/action.go`, lines 437–455, 628–708, and 919–1068](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L1068),
|
||||||
|
while `go test` rejects a bad test graph before creating those actions
|
||||||
|
([`cmd/go/internal/test/test.go`, lines 1185–1226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1185-L1226)).
|
||||||
|
- Unified export data separates public objects from private bodies/init data;
|
||||||
|
a blank import declaration serializes no declaration, and import readers
|
||||||
|
consume the semantic package export independently of that local spelling
|
||||||
|
([`cmd/compile/internal/noder/unified.go`, lines 314–353](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L314-L353),
|
||||||
|
[lines 463–570](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L463-L570),
|
||||||
|
[`cmd/compile/internal/noder/writer.go`, lines 2742–2749](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/writer.go#L2742-L2749),
|
||||||
|
[`cmd/compile/internal/importer/ureader.go`, lines 41–62](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L41-L62)).
|
||||||
|
Together with the resolver's omission from package scope, that public/private
|
||||||
|
split is why another package cannot select `pkg.init`.
|
||||||
|
- Loader import checks, build-root action ownership, direct compiler import
|
||||||
|
inputs, and transitive linker inputs remain per canonical package rather
|
||||||
|
than per local import name
|
||||||
|
([`cmd/go/internal/load/pkg.go`, lines 787–805](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L787-L805),
|
||||||
|
[`cmd/go/internal/work/build.go`, lines 519–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L519-L558),
|
||||||
|
[`cmd/go/internal/work/exec.go`, lines 864–884](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L864-L884),
|
||||||
|
[lines 1592–1653](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1592-L1653),
|
||||||
|
[`cmd/go/internal/work/gc.go`, lines 136–177](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/gc.go#L136-L177),
|
||||||
|
[lines 590–672](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/gc.go#L590-L672)).
|
||||||
|
|
||||||
|
#### Declaration and package-variable semantics
|
||||||
|
|
||||||
|
`fn init() void = { ... };` is a special initializer declaration. It must have
|
||||||
|
a body, no parameters, no result, no `export`, and no attribute. Multiple valid
|
||||||
|
declarations are accepted in one file and across files. No declaration of
|
||||||
|
another kind may claim `init`; a rejected non-function form is not inserted
|
||||||
|
into scope, so later references still fail lookup. A valid init retains its
|
||||||
|
file, source section, and position, but is never installed as a callable
|
||||||
|
declaration: `init()` and `pkg.init` fail lookup, it is absent from `.wwi`, and
|
||||||
|
it cannot affect canonical package identity.
|
||||||
|
|
||||||
|
Mutable package-level `let` is WW's Go-variable analogue. An initializer that
|
||||||
|
the existing static-data emitter can represent remains static. Every other
|
||||||
|
otherwise valid expression—including calls, allocation, and supported nested
|
||||||
|
array, struct, tuple, and slice values—is evaluated once by a hidden
|
||||||
|
package-owned helper and assigned to zero-backed package storage. Runtime slice
|
||||||
|
literals use canonical writable backing storage rather than escaping a helper
|
||||||
|
stack. `def` and `const` retain their existing compile-time/static rules and are
|
||||||
|
not broadened by this implementation.
|
||||||
|
|
||||||
|
The checker orders all initialized mutable lets by their checked declaration
|
||||||
|
dependencies. References through package functions are transparent edges.
|
||||||
|
Among remaining declarations, the one with the fewest unresolved dependencies
|
||||||
|
wins and original declaration order breaks ties. Files arrive byte-sorted
|
||||||
|
inside each loader category; a combined internal-test variant presents its
|
||||||
|
production category before its internal-test category, and declarations retain
|
||||||
|
source order inside each file. A cycle is
|
||||||
|
reported on the same deterministic walk as the pinned type checkers; removal
|
||||||
|
continues to expose later independent cycles, but any cycle suppresses all init
|
||||||
|
lowering and publication. Runtime variable assignments execute in that order,
|
||||||
|
then every special init function executes in owner-file/source order.
|
||||||
|
|
||||||
|
Each semantic package action owns one hidden task symbol:
|
||||||
|
|
||||||
|
```text
|
||||||
|
__ww..pkg.p.<canonical-path>.v<variant>.r<role>.init
|
||||||
|
```
|
||||||
|
|
||||||
|
The reversible empty-owner form is likewise variant/role qualified. Neither a
|
||||||
|
declared package name, default qualifier, explicit alias, blank spelling, path
|
||||||
|
leaf, physical directory, request ordinal, nor output name contributes to this
|
||||||
|
symbol. Compiler argv supplies it with
|
||||||
|
`--package-init-symbol <symbol>`. Only an executable command root or generated
|
||||||
|
test main additionally receives `--init-dispatch-symbol __ww..dispatch`, and
|
||||||
|
its compiler-generated entry calls that dispatcher before source `main` or the
|
||||||
|
generated test main body.
|
||||||
|
|
||||||
|
#### Product graph, variants, artifacts, and persistence
|
||||||
|
|
||||||
|
Before any producer, the driver forms the effective reachable graph for each
|
||||||
|
product, including internal-test replacement, and rejects a cycle introduced by
|
||||||
|
that replacement. It repeatedly chooses the byte-lexically smallest ready
|
||||||
|
canonical path, then variant and role, while blocking every importer on its
|
||||||
|
dependencies. The resulting root-owned dispatcher calls each effective package
|
||||||
|
task exactly once. Thus dependencies precede importers, a shared diamond task
|
||||||
|
runs once per product, independent ties ignore source import order and linker
|
||||||
|
argv order, and the root task completes before user main or tests.
|
||||||
|
|
||||||
|
An ordinary library object/archive contains its hidden task but building the
|
||||||
|
library does not execute it. An executable or generated-main root archive has
|
||||||
|
two deterministic members, `pkg.o/` followed by `init.o/`; the second member is
|
||||||
|
the root-owned dispatcher. Dependency archives remain ordinary `pkg.o/`
|
||||||
|
archives. Both driver stages stream member bytes through the same bounded
|
||||||
|
transfer buffer instead of retaining archive-sized allocations. Existing
|
||||||
|
linker archive fixpoint extraction pulls the dispatcher and
|
||||||
|
all referenced package tasks without a new linker format or free-floating
|
||||||
|
artifact. Logical linker argv is still the canonical root archive followed by
|
||||||
|
the reachable archive closure and runtime/native inputs; no `.wwi`, alias,
|
||||||
|
blank spelling, or dispatcher sidecar appears.
|
||||||
|
|
||||||
|
Production, production-plus-internal-test, external `_test`, test support, and
|
||||||
|
generated main retain separate action identities. An internal product replaces
|
||||||
|
the colocated production task with its combined variant and includes test-only
|
||||||
|
blank edges/init declarations exactly once. An external product initializes
|
||||||
|
ordinary production and its production dependencies before the external task.
|
||||||
|
Support is an ordinary dependency task; generated main owns only the final
|
||||||
|
dispatcher call and cannot duplicate a tested task. Test-file-only imports,
|
||||||
|
runtime lets, and init functions never enter production. A blank import cannot
|
||||||
|
bypass imported-`main` rejection, including through vendor expansion.
|
||||||
|
|
||||||
|
`.wwi` contains neither blank-only spelling, init declarations/bodies, hidden
|
||||||
|
variable helpers, slice backing symbols, package tasks, nor dispatcher facts.
|
||||||
|
It continues to encode only semantic exported declarations and their canonical
|
||||||
|
reachable type/constant facts. Consequently an init-body-only edit rebuilds the
|
||||||
|
owning object/archive and relinks affected products, while unchanged `.wwi`
|
||||||
|
bytes prevent importer recompilation. Adding or removing a blank edge rebuilds
|
||||||
|
the owning source action and changes exactly the affected reachable dispatcher;
|
||||||
|
a dispatcher-only change rebuilds the root `init.o/` member/archive without
|
||||||
|
recompiling an unchanged root source object. Reverse propagation stops at the
|
||||||
|
first regenerated byte-identical semantic export.
|
||||||
|
|
||||||
|
The owner source voucher remains `<action>.unit.ww`; a linked product root also
|
||||||
|
owns `<root>.init.unit.ww` for its dispatcher unit, `.init.s`, `.init.o`, and
|
||||||
|
two-member archive. Current persistent formats are build 17 and test 16. Warm
|
||||||
|
consumers select a dependency's staged `.wwi.new` or `.a.new` when that exact
|
||||||
|
action changed in the same request. All action artifacts, init artifacts, tool
|
||||||
|
identity copies, stamp, library/executable publications, and test statuses are
|
||||||
|
then one rollback-capable request transaction. No destination changes unless
|
||||||
|
every product stages successfully; a compiler, checker, init-order,
|
||||||
|
dispatcher, assembler, archiver, linker, allocation, status, or installation
|
||||||
|
failure removes remaining stages and restores the complete prior generation.
|
||||||
|
Before scratch acquisition or producer execution, `lstat`-style no-follow
|
||||||
|
checks reserve every action, tool, product, interface, status, and rollback
|
||||||
|
name; a dangling staging or backup symlink is an occupied structural conflict
|
||||||
|
and is never followed or removed. A committed dispatcher voucher must itself
|
||||||
|
be a regular file before it can authorize reuse. Compiler assembly and
|
||||||
|
interface bytes are first generated through anonymous files with checked full
|
||||||
|
writes and then published as their own rollback group. A non-regular compiler
|
||||||
|
destination is rejected before preservation, and installation—not cleanup of
|
||||||
|
a recoverable old backup—is the commit point. Cold rejection removes the exact
|
||||||
|
request-owned scratch tree. Stale init code, stale closure metadata, and mixed
|
||||||
|
committed generations therefore cannot be reused.
|
||||||
|
|
||||||
|
#### Stage and observer ownership
|
||||||
|
|
||||||
|
The shared syntax AST, C parser, and WW parser own blank/init facts and source
|
||||||
|
positions. Both imports-only driver scans resolve the dotted path and retain
|
||||||
|
per-site legality; neither treats `_` as an alias. The C and WW checkers own
|
||||||
|
special-init validation, invisibility, mutable-let dependency ordering, cycle
|
||||||
|
diagnostics, and runtime lowering. The interface writers omit initialization
|
||||||
|
implementation; the code generators emit static storage, runtime helpers,
|
||||||
|
package tasks, canonical slice backings, and the entry dispatcher call. The two
|
||||||
|
drivers own task identity, effective test graphs, global dispatcher ordering,
|
||||||
|
exact direct compiler inputs, archive membership, link closure, persistence,
|
||||||
|
and the request transaction. The assemblers consume the dynamically sized
|
||||||
|
canonical symbols. Both linkers are unchanged and use their existing iterative
|
||||||
|
archive extraction. `internal/wwpackage` and `cmd/wwtest` retain package/test
|
||||||
|
classification and execution coordination; they do not parse imports, invent
|
||||||
|
tasks, or call init manually.
|
||||||
|
|
||||||
|
The focused native `test/sep/sepinit_test.ww` observer generates every source
|
||||||
|
tree temporarily and proves runtime let/init order, dependency chains,
|
||||||
|
diamonds, independent lexical ties, aggregate and allocation initialization,
|
||||||
|
multiple-cycle diagnostics, special-init rejection, test-variant isolation,
|
||||||
|
canonical task/dispatcher/archive bytes, init-only invalidation, and warm
|
||||||
|
invalid-init rollback across independent Cstage and WWstage roots. Direct and
|
||||||
|
recursive test legs compare variant dispatcher/archive bytes and observable
|
||||||
|
production-dependency order; exact task counts include support and generated
|
||||||
|
main. Rejection rows compare complete normalized diagnostics and prove cold
|
||||||
|
scratch absence. The observer also uses a repository-built `setrlimit` launcher
|
||||||
|
to find one shared bounded-memory ceiling at which both drivers fail before a
|
||||||
|
producer, and proves no-follow atomic rejection of dangling driver staging and
|
||||||
|
compiler rollback names, non-regular compiler destinations, and compiler
|
||||||
|
output-write failures. The extended
|
||||||
|
`explicit_import_alias_binding_modes` observer owns repeated blank/default/
|
||||||
|
alias/file-scope combinations and no-binding/unused behavior. Existing
|
||||||
|
internal, vendor, imported-command, recursive, exact-argv, link-closure,
|
||||||
|
persistent-workdir, rejection-state, byte-identity, and bootstrap observers own
|
||||||
|
their unchanged broader boundaries. Grouped imports, quoted imports, and dot
|
||||||
|
imports remain deliberately unimplemented.
|
||||||
|
|
||||||
## 12. Candidate architectures and hard-gate decision
|
## 12. Candidate architectures and hard-gate decision
|
||||||
|
|
||||||
Five candidates were developed as coherent systems, not as feature bins.
|
Five candidates were developed as coherent systems, not as feature bins.
|
||||||
|
|||||||
59
docs/spec.md
59
docs/spec.md
@@ -246,7 +246,8 @@ does not return (e.g. a call to `abort`).
|
|||||||
```
|
```
|
||||||
SourceFile = PackageClause { ImportDecl } { TopDecl } .
|
SourceFile = PackageClause { ImportDecl } { TopDecl } .
|
||||||
PackageClause = "package" ident ";" .
|
PackageClause = "package" ident ";" .
|
||||||
ImportDecl = "import" ( ImportPath | ident ImportPath ) ";" .
|
ImportDecl = "import" ( ImportPath | ImportName ImportPath ) ";" .
|
||||||
|
ImportName = ident .
|
||||||
ImportPath = ident { "." ident } .
|
ImportPath = ident { "." ident } .
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -263,8 +264,18 @@ ImportPath = ident { "." ident } .
|
|||||||
Neither form exposes an imported declaration as a bare `Name`; ordinary
|
Neither form exposes an imported declaration as a bare `Name`; ordinary
|
||||||
unqualified lookup remains limited to lexical, builtin, and same-package
|
unqualified lookup remains limited to lexical, builtin, and same-package
|
||||||
declarations.
|
declarations.
|
||||||
|
- `import _ acme.codec;` is a blank side-effect import. The lone `_` creates no
|
||||||
|
qualifier, exposes no bare declaration, and is never diagnosed as unused.
|
||||||
|
It is nevertheless a real import occurrence: resolution and all missing,
|
||||||
|
self-import, cycle, `internal`, vendor, and imported-command checks use the
|
||||||
|
dotted path, and the dependency participates in executable and test package
|
||||||
|
initialization. Repeated blank occurrences and blank plus default/explicit
|
||||||
|
named occurrences of one path are valid; every named occurrence remains
|
||||||
|
independently subject to duplicate-binding and unused checks.
|
||||||
The package dependency graph is the sorted, deduplicated union of the real
|
The package dependency graph is the sorted, deduplicated union of the real
|
||||||
imports in all eligible files. Self-import is rejected.
|
imports in all eligible files. Occurrences retain their owning file and
|
||||||
|
position, but equal canonical targets create one graph edge/package action.
|
||||||
|
Self-import is rejected.
|
||||||
- An executable package is one declared `package main` and containing a
|
- An executable package is one declared `package main` and containing a
|
||||||
`fn main`; path and directory spelling do not classify commands. An ordinary
|
`fn main`; path and directory spelling do not classify commands. An ordinary
|
||||||
import of a package declared `main` is rejected, except for the toolchain's
|
import of a package declared `main` is rejected, except for the toolchain's
|
||||||
@@ -272,8 +283,8 @@ ImportPath = ident { "." ident } .
|
|||||||
- Only names marked `export` (§5) are visible across module boundaries.
|
- Only names marked `export` (§5) are visible across module boundaries.
|
||||||
|
|
||||||
Import paths remain unquoted and dotted. Grouped imports, quoted import paths,
|
Import paths remain unquoted and dotted. Grouped imports, quoted import paths,
|
||||||
dot imports, and blank imports are not implemented. In particular, `_` is
|
and dot imports are not implemented. `_` is reserved here for the blank form;
|
||||||
rejected as an alias rather than being treated as a blank import.
|
it is not an ordinary alias.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -298,23 +309,42 @@ The `=` between signature and body is required. A bodiless fn (`;`
|
|||||||
terminator) declares an external symbol (C FFI); the bare `...` C-style
|
terminator) declares an external symbol (C FFI); the bare `...` C-style
|
||||||
variadic is legal only on a bodiless declaration (§6.3).
|
variadic is legal only on a bodiless declaration (§6.3).
|
||||||
|
|
||||||
|
At package scope, exactly `fn init() void = Block;` declares a special package
|
||||||
|
initializer. It must have a body, no parameters, no result, no `export`, and no
|
||||||
|
attribute. Multiple init declarations are permitted and retain owner-file and
|
||||||
|
source order. `init` is not inserted into ordinary package scope: it cannot be
|
||||||
|
called as `init()`, selected as `pkg.init`, exported, or used by another kind
|
||||||
|
of declaration. Package-variable initialization completes before these
|
||||||
|
functions run.
|
||||||
|
|
||||||
### 5.2 `let`
|
### 5.2 `let`
|
||||||
|
|
||||||
```
|
```
|
||||||
LetDecl = "let" ident ":" Type [ "=" Expr ] ";" .
|
LetDecl = "let" ident ":" Type [ "=" Expr ] ";" .
|
||||||
```
|
```
|
||||||
|
|
||||||
A mutable binding. Without an initialiser the storage is uninitialised.
|
A mutable binding. Without an initialiser, package-level storage is
|
||||||
|
zero-backed; an uninitialized function-local binding retains the existing
|
||||||
|
uninitialized-local rule.
|
||||||
A `static` qualifier (`static let …`) gives function-local storage
|
A `static` qualifier (`static let …`) gives function-local storage
|
||||||
static lifetime.
|
static lifetime.
|
||||||
|
|
||||||
|
For a package-level `let` with an initializer, values representable by the
|
||||||
|
static-data emitter are installed statically. Every other otherwise valid
|
||||||
|
initializer is evaluated exactly once at runtime. Checked references through
|
||||||
|
package functions contribute variable-dependency edges; dependencies precede
|
||||||
|
dependents, and source declaration order breaks ready ties. Initialization
|
||||||
|
cycles are errors. Runtime package lets execute after imported package tasks and
|
||||||
|
before the package's init functions. `const` and `def` are not broadened by
|
||||||
|
this runtime path.
|
||||||
|
|
||||||
### 5.3 `const`
|
### 5.3 `const`
|
||||||
|
|
||||||
`const` introduces an immutable binding of the same shape as `let`.
|
`const` introduces an immutable storage binding of the same declaration shape
|
||||||
|
as `let`; assignment to it is rejected. At package scope its initializer stays
|
||||||
TODO(spec): pin the exact `const` vs `def` boundary against `cmd/wcc`
|
within the existing static-data forms. A `const` is not entered into the
|
||||||
(both keywords exist; this text takes `def` = compile-time constant
|
runtime package-variable schedule described above; use mutable `let` when an
|
||||||
[Hare's `def`] and `const` = immutable runtime binding — confirm).
|
otherwise valid initializer requires runtime evaluation.
|
||||||
|
|
||||||
### 5.4 `def`
|
### 5.4 `def`
|
||||||
|
|
||||||
@@ -561,6 +591,15 @@ the program. Two placements, following the Go `foo` / `foo_test` model:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Production, production-plus-white-box-test, external black-box-test, test
|
||||||
|
support, and generated test main are distinct package actions. Before a test
|
||||||
|
function runs, the generated test product initializes its exact reachable
|
||||||
|
variant graph dependency-first and once per canonical action. A white-box
|
||||||
|
variant replaces the colocated production task rather than initializing both;
|
||||||
|
an external variant depends on ordinary production. Imports, runtime lets, and
|
||||||
|
init declarations found only in `*_test.ww` never enter an ordinary production
|
||||||
|
build.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11. Concurrency (reserved)
|
## 11. Concurrency (reserved)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ categories out of the ordinary developer target.
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Arena, lexer, parser, checker, module-decl parse, narrow codegen | Six in-process C unit binaries |
|
| Arena, lexer, parser, checker, module-decl parse, narrow codegen | Six in-process C unit binaries |
|
||||||
| Compile success/rejection, stage-routed diagnostics, and runtime exit | `test/wcc/data/*/case.ww`, executed by `wwfixture` |
|
| Compile success/rejection, stage-routed diagnostics, and runtime exit | `test/wcc/data/*/case.ww`, executed by `wwfixture` |
|
||||||
| Package semantics | `test/package` and the native package-test coordinator |
|
| Package semantics | `test/package`, `test/sep/sepinit_test.ww`, and the native package-test coordinator |
|
||||||
| Language behavior | `test/lang/*_test.ww` through the language `@test` runtime |
|
| Language behavior | `test/lang/*_test.ww` through the language `@test` runtime |
|
||||||
| Library behavior | The package coordinator's `lib/...` tree walk (`ww test -j N lib/...`) |
|
| Library behavior | The package coordinator's `lib/...` tree walk (`ww test -j N lib/...`) |
|
||||||
| Standalone library-source compilation | Three import-free real source paths named by `LIBRARY_STANDALONE_SOURCES`, compiled directly by both frontends |
|
| Standalone library-source compilation | Three import-free real source paths named by `LIBRARY_STANDALONE_SOURCES`, compiled directly by both frontends |
|
||||||
@@ -236,25 +236,41 @@ qualifier remain distinct. The alias matrix covers default and explicit-only
|
|||||||
qualification, bare function/type/def/const/variable rejection with exact
|
qualification, bare function/type/def/const/variable rejection with exact
|
||||||
unused-before-undefined diagnostics, same-file duplicate bindings, accepted
|
unused-before-undefined diagnostics, same-file duplicate bindings, accepted
|
||||||
same-path imports under distinct bindings, alias reuse across files, sibling
|
same-path imports under distinct bindings, alias reuse across files, sibling
|
||||||
scope isolation, package-declaration collisions, unused aliases, and explicit
|
scope isolation, package-declaration collisions, unused aliases, blank
|
||||||
blank-alias rejection. It also pins canonical `.wwi` spelling, archive/action
|
side-effect imports, repeated blank/default/explicit combinations, and blank
|
||||||
ownership, stage-equal diagnostics and binaries, and clean rejection state.
|
no-binding/no-unused behavior. It also pins canonical `.wwi` spelling,
|
||||||
|
archive/action ownership, one canonical direct edge for repeated occurrences,
|
||||||
|
stage-equal diagnostics and binaries, and clean rejection state.
|
||||||
The declared-name observer proves imports are file-scoped while dependency
|
The declared-name observer proves imports are file-scoped while dependency
|
||||||
edges are the package-wide sorted union; command and
|
edges are the package-wide sorted union; command and
|
||||||
production/internal/external/generated-main variants retain canonical action
|
production/internal/external/generated-main variants retain canonical action
|
||||||
ownership; vendor expansion changes identity but not the effective qualifier;
|
ownership; vendor expansion changes identity but not the effective qualifier;
|
||||||
compiler argv contains only direct `.wwi` inputs; and its named rejected
|
compiler argv contains only direct `.wwi` inputs; and its named rejected
|
||||||
actions leave neither committed nor staged action artifacts or a published
|
actions leave neither committed nor staged action artifacts or a published
|
||||||
binary. It also forces a staged multi-artifact commit to fail after the
|
binary. It also forces a request transaction to reject after dependency work
|
||||||
interface rename, then proves that both stages invalidate old unit vouchers and
|
has staged, then proves that both stages restore every prior artifact, unit,
|
||||||
reconsider the importer rather than accepting a mixed warm generation. A
|
tool record, stamp, and product rather than accepting a mixed warm generation.
|
||||||
separate injected stamp-removal failure proves the pre-commit gate leaves all
|
|
||||||
previously committed artifacts byte-identical.
|
|
||||||
Together with the existing directory, recursive, vendor,
|
Together with the existing directory, recursive, vendor,
|
||||||
exact-argv, command, and persistent-workdir observers, the package suite proves
|
exact-argv, command, and persistent-workdir observers, the package suite proves
|
||||||
archive-only link argv and exact warm/rejection-state behavior without
|
archive-only link argv and exact warm/rejection-state behavior without
|
||||||
duplicating those broader mechanisms in this observer.
|
duplicating those broader mechanisms in this observer.
|
||||||
|
|
||||||
|
`test/sep/sepinit_test.ww` is the single focused package-initialization owner.
|
||||||
|
It generates all source trees temporarily and runs independent cold/persistent
|
||||||
|
Cstage and WWstage legs. Its matrix covers blank-only reachability; dependency,
|
||||||
|
diamond, and independent ready-task order; runtime call/allocation and aggregate
|
||||||
|
package lets; multiple init declarations and invalid forms; direct/qualified
|
||||||
|
init invisibility; initialization cycles and diagnostic order; command,
|
||||||
|
internal-test, external-test, support, and generated-main ownership; canonical
|
||||||
|
task and dispatcher symbols; deterministic one- and two-member archives;
|
||||||
|
`.wwi` exclusion; byte-identical artifacts/binaries; init-only invalidation;
|
||||||
|
warm invalid-init rollback; direct/recursive variant equivalence; exact
|
||||||
|
production, support, and generated-main task ordering; complete normalized
|
||||||
|
rejection diagnostics; dangling staging/rollback no-follow rejection; and
|
||||||
|
checked compiler-output failure/non-regular-destination rollback; and
|
||||||
|
bounded-memory allocation-failure parity under one shared ceiling supplied by
|
||||||
|
the repository-built `sep-limitexec` helper.
|
||||||
|
|
||||||
`ww build`, an explicit single-file `ww test -o <stem>`, and each successful
|
`ww build`, an explicit single-file `ww test -o <stem>`, and each successful
|
||||||
directory-package `ww test -c` build publish `<stem>.sepwork` as a caller-owned
|
directory-package `ww test -c` build publish `<stem>.sepwork` as a caller-owned
|
||||||
artifact directory. The driver acquires it with one fresh `mkdir` and refuses
|
artifact directory. The driver acquires it with one fresh `mkdir` and refuses
|
||||||
@@ -279,13 +295,17 @@ no hashes, every decision reproducible with `cmp` against plain files. The
|
|||||||
driver identity covers graph construction, owner-unit composition,
|
driver identity covers graph construction, owner-unit composition,
|
||||||
direct-export argument construction, archive creation, and commit algorithms
|
direct-export argument construction, archive creation, and commit algorithms
|
||||||
that neither unit bytes nor compiler identity can name.
|
that neither unit bytes nor compiler identity can name.
|
||||||
Recompiled artifacts land at staged `.new` names and commit by rename with the
|
Recompiled artifacts, dispatcher artifacts, products, statuses, tool copies,
|
||||||
unit renamed last, so an interrupted build forces a recompile rather than a
|
and the stamp land at staged `.new` names. After every requested product stages
|
||||||
false reuse; the link always reruns. One workdir serves one invocation at a
|
successfully, one rollback-capable transaction installs the whole generation;
|
||||||
time and may hold the complete command-global action universe for all selected
|
any producer or installation failure preserves the prior committed bytes and
|
||||||
roots and isolated variants; semantic identity, rather than request shape,
|
removes remaining stages. An interrupted or rejected request therefore cannot
|
||||||
controls reuse. Both driver stages implement the identical contract. This is
|
create false reuse or a mixed generation; a successful executable link still
|
||||||
build staleness in the Make/mk/Go sense, not a result cache:
|
reruns when required. One workdir serves one invocation at a time and may hold
|
||||||
|
the complete command-global action universe for all selected roots and isolated
|
||||||
|
variants; semantic identity, rather than request shape, controls reuse. Both
|
||||||
|
driver stages implement the identical contract. This is build staleness in the
|
||||||
|
Make/mk/Go sense, not a result cache:
|
||||||
tests always run, and the byte-identity and bootstrap gates keep building on
|
tests always run, and the byte-identity and bootstrap gates keep building on
|
||||||
fresh scratch. `make clean` reclaims every workdir under `out/`.
|
fresh scratch. `make clean` reclaims every workdir under `out/`.
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
sink.zero = zero;
|
sink.zero = zero;
|
||||||
let rb: [1]u8;
|
let rb: [1]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(&sink.vt, rb[0:1], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(&sink.vt, rb[0:1], wb[0:4]);
|
||||||
let src: [4]u8;
|
let src: [4]u8;
|
||||||
let _: i32 = sputstr("ABCD", src[0:4], 0);
|
let _: i32 = sputstr("ABCD", src[0:4], 0);
|
||||||
let wr: (size | io.error) = io.write(&b.vt, src[0:4]);
|
let wr: (size | io.error) = io.write(&b.vt, src[0:4]);
|
||||||
@@ -109,7 +109,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [8]u8;
|
let rb: [8]u8;
|
||||||
let wb: [8]u8;
|
let wb: [8]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:8], wb[0:8]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:8], wb[0:8]);
|
||||||
|
|
||||||
// Write under the buffer limit — nothing reaches src.
|
// Write under the buffer limit — nothing reaches src.
|
||||||
let buf: [5]u8;
|
let buf: [5]u8;
|
||||||
@@ -139,7 +139,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:4]);
|
||||||
|
|
||||||
// 10B payload through a 4B wbuf: bwrite must flush twice mid-write.
|
// 10B payload through a 4B wbuf: bwrite must flush twice mid-write.
|
||||||
let buf: [10]u8;
|
let buf: [10]u8;
|
||||||
@@ -170,7 +170,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [16]u8;
|
let wb: [16]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:16]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:16]);
|
||||||
|
|
||||||
let p: io.stream = &b.vt;
|
let p: io.stream = &b.vt;
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [16]u8;
|
let wb: [16]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:16]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:16]);
|
||||||
let nilbs: [1]u8;
|
let nilbs: [1]u8;
|
||||||
bufio.setflush(&b, nilbs[0:0]);
|
bufio.setflush(&b, nilbs[0:0]);
|
||||||
|
|
||||||
@@ -245,7 +245,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:4]);
|
||||||
|
|
||||||
assert(!(!bufio.isbuffered(&b.vt)));
|
assert(!(!bufio.isbuffered(&b.vt)));
|
||||||
assert(!(bufio.isbuffered(m)));
|
assert(!(bufio.isbuffered(m)));
|
||||||
@@ -264,7 +264,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [8]u8;
|
let rb: [8]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:8], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:8], wb[0:4]);
|
||||||
|
|
||||||
let p: io.stream = &b.vt;
|
let p: io.stream = &b.vt;
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [8]u8;
|
let rb: [8]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:8], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:8], wb[0:4]);
|
||||||
|
|
||||||
let p: io.stream = &b.vt;
|
let p: io.stream = &b.vt;
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [8]u8;
|
let rb: [8]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:8], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:8], wb[0:4]);
|
||||||
|
|
||||||
let p: io.stream = &b.vt;
|
let p: io.stream = &b.vt;
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let _: i32 = sputstr("ABCD", rb[0:4], 0);
|
let _: i32 = sputstr("ABCD", rb[0:4], 0);
|
||||||
let wb: [1]u8;
|
let wb: [1]u8;
|
||||||
let b: bufio.stream = bufio.init(&mem.vt, rb[0:4], wb[0:1]);
|
let b: bufio.stream = bufio.newstream(&mem.vt, rb[0:4], wb[0:1]);
|
||||||
bufio.unread(&b, rb[0:3]);
|
bufio.unread(&b, rb[0:3]);
|
||||||
let out: [3]u8;
|
let out: [3]u8;
|
||||||
let r: (size | io.eof | io.error) = io.read(&b.vt, out[0:3]);
|
let r: (size | io.eof | io.error) = io.read(&b.vt, out[0:3]);
|
||||||
@@ -406,7 +406,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [16]u8;
|
let rb: [16]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:16], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:16], wb[0:4]);
|
||||||
|
|
||||||
let push: [3]u8;
|
let push: [3]u8;
|
||||||
push[0] = 88u8; push[1] = 89u8; push[2] = 90u8; // "XYZ"
|
push[0] = 88u8; push[1] = 89u8; push[2] = 90u8; // "XYZ"
|
||||||
@@ -437,7 +437,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:4]);
|
||||||
|
|
||||||
let r: (void | io.error) = bufio.flush(&b);
|
let r: (void | io.error) = bufio.flush(&b);
|
||||||
match (r) {
|
match (r) {
|
||||||
@@ -454,7 +454,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:4]);
|
||||||
let nilbs: [1]u8;
|
let nilbs: [1]u8;
|
||||||
bufio.setflush(&b, nilbs[0:0]); // suppress the default '\n' detector
|
bufio.setflush(&b, nilbs[0:0]); // suppress the default '\n' detector
|
||||||
|
|
||||||
@@ -490,7 +490,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [4]u8;
|
let wb: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(src, rb[0:4], wb[0:4]);
|
let b: bufio.stream = bufio.newstream(src, rb[0:4], wb[0:4]);
|
||||||
let nilbs: [1]u8;
|
let nilbs: [1]u8;
|
||||||
bufio.setflush(&b, nilbs[0:0]); // suppress the default '\n' detector
|
bufio.setflush(&b, nilbs[0:0]); // suppress the default '\n' detector
|
||||||
|
|
||||||
@@ -524,7 +524,7 @@ fn checkpartialflush(zero: bool) void = {
|
|||||||
|
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [16]u8;
|
let wb: [16]u8;
|
||||||
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:16]);
|
let b: bufio.stream = bufio.newstream(m, rb[0:4], wb[0:16]);
|
||||||
let bs: [1]u8;
|
let bs: [1]u8;
|
||||||
bs[0] = 32u8; // ' '
|
bs[0] = 32u8; // ' '
|
||||||
bufio.setflush(&b, bs[0:1]);
|
bufio.setflush(&b, bs[0:1]);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import math.random;
|
|||||||
import test;
|
import test;
|
||||||
|
|
||||||
@test fn seq() void = {
|
@test fn seq() void = {
|
||||||
let r: random.random = random.init(1234567u64);
|
let r: random.random = random.fromseed(1234567u64);
|
||||||
assert(!(random.next(&r) != 6457827717110365317u64));
|
assert(!(random.next(&r) != 6457827717110365317u64));
|
||||||
assert(!(random.next(&r) != 3203168211198807973u64));
|
assert(!(random.next(&r) != 3203168211198807973u64));
|
||||||
assert(!(random.next(&r) != 9817491932198370423u64));
|
assert(!(random.next(&r) != 9817491932198370423u64));
|
||||||
@@ -13,8 +13,8 @@ import test;
|
|||||||
};
|
};
|
||||||
|
|
||||||
@test fn deterministic() void = {
|
@test fn deterministic() void = {
|
||||||
let a: random.random = random.init(42u64);
|
let a: random.random = random.fromseed(42u64);
|
||||||
let b: random.random = random.init(42u64);
|
let b: random.random = random.fromseed(42u64);
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < 32) {
|
for (i < 32) {
|
||||||
assert(!(random.next(&a) != random.next(&b)));
|
assert(!(random.next(&a) != random.next(&b)));
|
||||||
@@ -23,7 +23,7 @@ import test;
|
|||||||
};
|
};
|
||||||
|
|
||||||
@test fn u32n_inrange() void = {
|
@test fn u32n_inrange() void = {
|
||||||
let r: random.random = random.init(7u64);
|
let r: random.random = random.fromseed(7u64);
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < 200) {
|
for (i < 200) {
|
||||||
let v: u32 = random.u32n(&r, 17u32);
|
let v: u32 = random.u32n(&r, 17u32);
|
||||||
@@ -35,7 +35,7 @@ import test;
|
|||||||
};
|
};
|
||||||
|
|
||||||
@test fn u64n_pow2() void = {
|
@test fn u64n_pow2() void = {
|
||||||
let r: random.random = random.init(99u64);
|
let r: random.random = random.fromseed(99u64);
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < 200) {
|
for (i < 200) {
|
||||||
let v: u64 = random.u64n(&r, 16u64);
|
let v: u64 = random.u64n(&r, 16u64);
|
||||||
@@ -45,7 +45,7 @@ import test;
|
|||||||
};
|
};
|
||||||
|
|
||||||
@test fn u64n_nonpow2() void = {
|
@test fn u64n_nonpow2() void = {
|
||||||
let r: random.random = random.init(123u64);
|
let r: random.random = random.fromseed(123u64);
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < 200) {
|
for (i < 200) {
|
||||||
let v: u64 = random.u64n(&r, 100u64);
|
let v: u64 = random.u64n(&r, 100u64);
|
||||||
@@ -60,12 +60,12 @@ import test;
|
|||||||
|
|
||||||
@test fn u32n_zero_aborts() void = {
|
@test fn u32n_zero_aborts() void = {
|
||||||
test.expectabort();
|
test.expectabort();
|
||||||
let r: random.random = random.init(1u64);
|
let r: random.random = random.fromseed(1u64);
|
||||||
random.u32n(&r, 0u32);
|
random.u32n(&r, 0u32);
|
||||||
};
|
};
|
||||||
|
|
||||||
@test fn u64n_zero_aborts() void = {
|
@test fn u64n_zero_aborts() void = {
|
||||||
test.expectabort();
|
test.expectabort();
|
||||||
let r: random.random = random.init(1u64);
|
let r: random.random = random.fromseed(1u64);
|
||||||
random.u64n(&r, 0u64);
|
random.u64n(&r, 0u64);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -75,31 +75,6 @@ fn astrow(label: str, src: str, needles: []str) void = {
|
|||||||
testenv.clean(td);
|
testenv.clean(td);
|
||||||
};
|
};
|
||||||
|
|
||||||
fn rejectrow(label: str, src: str, needle: str) void = {
|
|
||||||
let td: str = testenv.fresh();
|
|
||||||
testenv.writefile(strings.concat(td, "/a.ww"), src);
|
|
||||||
let tools: []str = ["wwdump", "wwdump_ww"];
|
|
||||||
let stages: []str = ["cstage", "wwstage"];
|
|
||||||
let errors: []str = ["", ""];
|
|
||||||
let i: i32 = 0;
|
|
||||||
for (i < tools.len) {
|
|
||||||
let av: []str = [testenv.driver(tools[i]), "-a",
|
|
||||||
strings.concat(td, "/a.ww")];
|
|
||||||
let co: testenv.commandout;
|
|
||||||
testenv.runcommand(td, td, stages[i], av, tmo(), &co);
|
|
||||||
if (co.termination != exec.termination.EXIT || co.code == 0
|
|
||||||
|| !testenv.has(co.stderr, needle)) {
|
|
||||||
fail(label, strings.concat(stages[i], " accepted rejected import"));
|
|
||||||
};
|
|
||||||
errors[i] = strings.dup(co.stderr);
|
|
||||||
i += 1;
|
|
||||||
};
|
|
||||||
if (!testenv.same(errors[0], errors[1])) {
|
|
||||||
fail(label, "cs/ww parse diagnostics DIFFER");
|
|
||||||
};
|
|
||||||
testenv.clean(td);
|
|
||||||
};
|
|
||||||
|
|
||||||
@test fn astproof() void = {
|
@test fn astproof() void = {
|
||||||
let trailing: []str = ["(dot \"x\"", "(structlit",
|
let trailing: []str = ["(dot \"x\"", "(structlit",
|
||||||
"(tname \"pkg.point\""];
|
"(tname \"pkg.point\""];
|
||||||
@@ -127,9 +102,11 @@ fn rejectrow(label: str, src: str, needle: str) void = {
|
|||||||
"package main;\n",
|
"package main;\n",
|
||||||
"import stable acme.codec;\n",
|
"import stable acme.codec;\n",
|
||||||
"fn main() i32 = { return 0; };\n"), aliased);
|
"fn main() i32 = { return 0; };\n"), aliased);
|
||||||
rejectrow("blank-alias", strings.concat(
|
// A blank N_USE deliberately has no `.str` qualifier, so astprint's
|
||||||
|
// `(use` line has no quoted binding while remaining a real use node.
|
||||||
|
let blank: []str = ["(use\n"];
|
||||||
|
astrow("blank-import", strings.concat(
|
||||||
"package main;\n",
|
"package main;\n",
|
||||||
"import _ acme.codec;\n",
|
"import _ acme.codec;\n",
|
||||||
"fn main() i32 = { return 0; };\n"),
|
"fn main() i32 = { return 0; };\n"), blank);
|
||||||
"blank import alias _ is not implemented");
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1157,12 +1157,16 @@ fn hexbytes(value: str) str = {
|
|||||||
assert(!has(externalproduction, "//ww:module "));
|
assert(!has(externalproduction, "//ww:module "));
|
||||||
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
|
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
|
||||||
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
|
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
|
||||||
assert(same(samemainunit, strings.concat(
|
assert(strings.hasprefix(samemainunit, strings.concat(
|
||||||
"//ww:module-reset __wwtestmain.pkg.internal.main\n",
|
"//ww:module-reset __wwtestmain.pkg.internal.main\n",
|
||||||
"package main;\nimport pkg;\nimport test;\n")));
|
"package main;\nimport pkg;\nimport test;\n")));
|
||||||
assert(same(externalmainunit, strings.concat(
|
assert(strings.hasprefix(externalmainunit, strings.concat(
|
||||||
"//ww:module-reset __wwtestmain.pkg_test.external.main\n",
|
"//ww:module-reset __wwtestmain.pkg_test.external.main\n",
|
||||||
"package main;\nimport pkg_test;\nimport test;\n")));
|
"package main;\nimport pkg_test;\nimport test;\n")));
|
||||||
|
assert(has(samemainunit, "//ww:direct-export pkg "));
|
||||||
|
assert(has(samemainunit, "//ww:direct-export test "));
|
||||||
|
assert(has(externalmainunit, "//ww:direct-export pkg_test "));
|
||||||
|
assert(has(externalmainunit, "//ww:direct-export test "));
|
||||||
assert(!has(samemainunit, "PACKAGE_PRODUCTION"));
|
assert(!has(samemainunit, "PACKAGE_PRODUCTION"));
|
||||||
assert(!has(samemainunit, "SAME_TEST_SOURCE"));
|
assert(!has(samemainunit, "SAME_TEST_SOURCE"));
|
||||||
assert(!has(externalmainunit, "EXTERNAL_TEST_SOURCE"));
|
assert(!has(externalmainunit, "EXTERNAL_TEST_SOURCE"));
|
||||||
@@ -1221,13 +1225,15 @@ fn hexbytes(value: str) str = {
|
|||||||
let productioncompile: str = linecontaining(ctrace,
|
let productioncompile: str = linecontaining(ctrace,
|
||||||
"/pkg.unit.ww");
|
"/pkg.unit.ww");
|
||||||
assert(same(samecompile, strings.concat(
|
assert(same(samecompile, strings.concat(
|
||||||
"--test-package -c --import __same ",
|
"--test-package --package-init-symbol ",
|
||||||
|
"__ww..pkg.p.pkg.v1.r0.init -c --import __same ",
|
||||||
sharedwork, "__same.wwi --import api ", sharedwork,
|
sharedwork, "__same.wwi --import api ", sharedwork,
|
||||||
"api.wwi -I ", sharedwork, "pkg-internal-test.wwi -o ",
|
"api.wwi -I ", sharedwork, "pkg-internal-test.wwi -o ",
|
||||||
sharedwork, "pkg-internal-test.s ", sharedwork,
|
sharedwork, "pkg-internal-test.s ", sharedwork,
|
||||||
"pkg-internal-test.unit.ww")));
|
"pkg-internal-test.unit.ww")));
|
||||||
assert(same(externalcompile, strings.concat(
|
assert(same(externalcompile, strings.concat(
|
||||||
"--test-package -c --import __external ",
|
"--test-package --package-init-symbol ",
|
||||||
|
"__ww..pkg.p.pkg_test.v2.r0.init -c --import __external ",
|
||||||
sharedwork, "__external.wwi --import pkg ", sharedwork,
|
sharedwork, "__external.wwi --import pkg ", sharedwork,
|
||||||
"pkg.wwi -I ", sharedwork,
|
"pkg.wwi -I ", sharedwork,
|
||||||
"pkg_test-external-test.wwi -o ", sharedwork,
|
"pkg_test-external-test.wwi -o ", sharedwork,
|
||||||
@@ -1239,7 +1245,9 @@ fn hexbytes(value: str) str = {
|
|||||||
"pkg_test-external-test-main.unit.ww");
|
"pkg_test-external-test-main.unit.ww");
|
||||||
assert(same(samemaincompile, strings.concat(
|
assert(same(samemaincompile, strings.concat(
|
||||||
"-T --entry --test-support-module test ",
|
"-T --entry --test-support-module test ",
|
||||||
"--test-target-package pkg -c --import pkg ",
|
"--test-target-package pkg --package-init-symbol ",
|
||||||
|
"__ww..pkg.p.__wwtestmain.pkg.internal.main.v3.r2.init ",
|
||||||
|
"--init-dispatch-symbol __ww..dispatch -c --import pkg ",
|
||||||
sharedwork, "pkg-internal-test.wwi --import test ",
|
sharedwork, "pkg-internal-test.wwi --import test ",
|
||||||
sharedwork, "test.wwi -I ", sharedwork,
|
sharedwork, "test.wwi -I ", sharedwork,
|
||||||
"pkg-internal-test-main.wwi -o ", sharedwork,
|
"pkg-internal-test-main.wwi -o ", sharedwork,
|
||||||
@@ -1247,22 +1255,25 @@ fn hexbytes(value: str) str = {
|
|||||||
"pkg-internal-test-main.unit.ww")));
|
"pkg-internal-test-main.unit.ww")));
|
||||||
assert(same(externalmaincompile, strings.concat(
|
assert(same(externalmaincompile, strings.concat(
|
||||||
"-T --entry --test-support-module test ",
|
"-T --entry --test-support-module test ",
|
||||||
"--test-target-package pkg_test -c --import pkg_test ",
|
"--test-target-package pkg_test --package-init-symbol ",
|
||||||
|
"__ww..pkg.p.__wwtestmain.pkg_test.external.main.v3.r2.init ",
|
||||||
|
"--init-dispatch-symbol __ww..dispatch -c --import pkg_test ",
|
||||||
sharedwork, "pkg_test-external-test.wwi --import test ",
|
sharedwork, "pkg_test-external-test.wwi --import test ",
|
||||||
sharedwork, "test.wwi -I ", sharedwork,
|
sharedwork, "test.wwi -I ", sharedwork,
|
||||||
"pkg_test-external-test-main.wwi -o ", sharedwork,
|
"pkg_test-external-test-main.wwi -o ", sharedwork,
|
||||||
"pkg_test-external-test-main.s ", sharedwork,
|
"pkg_test-external-test-main.s ", sharedwork,
|
||||||
"pkg_test-external-test-main.unit.ww")));
|
"pkg_test-external-test-main.unit.ww")));
|
||||||
assert(same(productioncompile, strings.concat(
|
assert(same(productioncompile, strings.concat(
|
||||||
|
"--package-init-symbol __ww..pkg.p.pkg.v0.r0.init ",
|
||||||
"-c --import api ", sharedwork, "api.wwi -I ", sharedwork,
|
"-c --import api ", sharedwork, "api.wwi -I ", sharedwork,
|
||||||
"pkg.wwi -o ", sharedwork,
|
"pkg.wwi -o ", sharedwork,
|
||||||
"pkg.s ", sharedwork, "pkg.unit.ww")));
|
"pkg.s ", sharedwork, "pkg.unit.ww")));
|
||||||
let ltrace: str = readfile(linkertrace);
|
let ltrace: str = readfile(linkertrace);
|
||||||
assert(occurrences(ltrace, "\n") == 2);
|
assert(occurrences(ltrace, "\n") == 2);
|
||||||
let samelink: str = linecontaining(ltrace,
|
let samelink: str = linecontaining(ltrace,
|
||||||
strings.concat("-o ", samebin, " "));
|
strings.concat("-o ", samebin, ".new "));
|
||||||
let externallink: str = linecontaining(ltrace,
|
let externallink: str = linecontaining(ltrace,
|
||||||
strings.concat("-o ", externalbin, " "));
|
strings.concat("-o ", externalbin, ".new "));
|
||||||
assert(has(samelink, strings.concat(sharedwork, "api.a")));
|
assert(has(samelink, strings.concat(sharedwork, "api.a")));
|
||||||
assert(has(samelink,
|
assert(has(samelink,
|
||||||
strings.concat(sharedwork, "implementation.a")));
|
strings.concat(sharedwork, "implementation.a")));
|
||||||
@@ -1848,7 +1859,7 @@ fn hexbytes(value: str) str = {
|
|||||||
ri = 0;
|
ri = 0;
|
||||||
for (ri < bins.len) {
|
for (ri < bins.len) {
|
||||||
let link: str = linecontaining(ltrace,
|
let link: str = linecontaining(ltrace,
|
||||||
strings.concat("-o ", bins[ri], " "));
|
strings.concat("-o ", bins[ri], ".new "));
|
||||||
assert(has(link, strings.concat(sharedwork, mainkeys[ri], ".a")));
|
assert(has(link, strings.concat(sharedwork, mainkeys[ri], ".a")));
|
||||||
assert(has(link, strings.concat(sharedwork, rootkeys[ri], ".a")));
|
assert(has(link, strings.concat(sharedwork, rootkeys[ri], ".a")));
|
||||||
assert(!has(link, ".wwi"));
|
assert(!has(link, ".wwi"));
|
||||||
@@ -2403,13 +2414,13 @@ fn hexbytes(value: str) str = {
|
|||||||
let links: str = readfile(linktrace);
|
let links: str = readfile(linktrace);
|
||||||
assert(occurrences(links, "\n") == 4);
|
assert(occurrences(links, "\n") == 4);
|
||||||
let namedsame: str = linecontaining(links,
|
let namedsame: str = linecontaining(links,
|
||||||
strings.concat("-o ", bins[0], " "));
|
strings.concat("-o ", bins[0], ".new "));
|
||||||
let namedexternal: str = linecontaining(links,
|
let namedexternal: str = linecontaining(links,
|
||||||
strings.concat("-o ", bins[1], " "));
|
strings.concat("-o ", bins[1], ".new "));
|
||||||
let consumersame: str = linecontaining(links,
|
let consumersame: str = linecontaining(links,
|
||||||
strings.concat("-o ", bins[2], " "));
|
strings.concat("-o ", bins[2], ".new "));
|
||||||
let consumerexternal: str = linecontaining(links,
|
let consumerexternal: str = linecontaining(links,
|
||||||
strings.concat("-o ", bins[3], " "));
|
strings.concat("-o ", bins[3], ".new "));
|
||||||
assert(has(namedsame, strings.concat(work, "__wwtest.a")));
|
assert(has(namedsame, strings.concat(work, "__wwtest.a")));
|
||||||
assert(!has(namedsame, strings.concat(work, "test.a")));
|
assert(!has(namedsame, strings.concat(work, "test.a")));
|
||||||
assert(has(namedexternal, strings.concat(work, "test.a")));
|
assert(has(namedexternal, strings.concat(work, "test.a")));
|
||||||
@@ -2595,19 +2606,22 @@ fn hexbytes(value: str) str = {
|
|||||||
let atrace: str = readfile(assemblertraces[si]);
|
let atrace: str = readfile(assemblertraces[si]);
|
||||||
let ltrace: str = readfile(linkertraces[si]);
|
let ltrace: str = readfile(linkertraces[si]);
|
||||||
assert(occurrences(ctrace, "\n") == packagecount + 1);
|
assert(occurrences(ctrace, "\n") == packagecount + 1);
|
||||||
assert(occurrences(atrace, "\n") == packagecount + 1);
|
assert(occurrences(atrace, "\n") == packagecount + 2);
|
||||||
assert(occurrences(ltrace, "\n") == 1);
|
assert(occurrences(ltrace, "\n") == 1);
|
||||||
let rootline: str = linecontaining(ctrace,
|
let rootline: str = linecontaining(ctrace,
|
||||||
strings.concat("/", rootaction, ".unit.new"));
|
strings.concat("/", rootaction, ".unit.new"));
|
||||||
assert(occurrences(rootline, "<--import>") == packagecount);
|
assert(occurrences(rootline, "<--import>") == packagecount);
|
||||||
let expectedroot: str = "BEGIN<--entry><-c>";
|
let expectedroot: str = strings.concat(
|
||||||
|
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
|
||||||
|
rootaction, ".v0.r0.init><--init-dispatch-symbol>",
|
||||||
|
"<__ww..dispatch><-c>");
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < packagecount) {
|
for (i < packagecount) {
|
||||||
let name: str = boundarypkgname(i);
|
let name: str = boundarypkgname(i);
|
||||||
expectedroot = strings.concat(expectedroot, "<--import><", name,
|
expectedroot = strings.concat(expectedroot, "<--import><", name,
|
||||||
"><", works[si], "/", name, ".wwi>");
|
"><", works[si], "/", name, ".wwi.new>");
|
||||||
assert(occurrences(rootline, strings.concat("<", name, "><",
|
assert(occurrences(rootline, strings.concat("<", name, "><",
|
||||||
works[si], "/", name, ".wwi>")) == 1);
|
works[si], "/", name, ".wwi.new>")) == 1);
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
expectedroot = strings.concat(expectedroot, "<-I><", works[si], "/",
|
expectedroot = strings.concat(expectedroot, "<-I><", works[si], "/",
|
||||||
@@ -2617,12 +2631,14 @@ fn hexbytes(value: str) str = {
|
|||||||
i = 0;
|
i = 0;
|
||||||
for (i < packagecount) {
|
for (i < packagecount) {
|
||||||
let name: str = boundarypkgname(i);
|
let name: str = boundarypkgname(i);
|
||||||
let expectedcompile: str = "BEGIN<-c>";
|
let expectedcompile: str = strings.concat(
|
||||||
|
"BEGIN<--package-init-symbol><__ww..pkg.p.", name,
|
||||||
|
".v0.r0.init><-c>");
|
||||||
if (i + 1 < packagecount) {
|
if (i + 1 < packagecount) {
|
||||||
let next: str = boundarypkgname(i + 1);
|
let next: str = boundarypkgname(i + 1);
|
||||||
expectedcompile = strings.concat(expectedcompile,
|
expectedcompile = strings.concat(expectedcompile,
|
||||||
"<--import><", next, "><", works[si], "/", next,
|
"<--import><", next, "><", works[si], "/", next,
|
||||||
".wwi>");
|
".wwi.new>");
|
||||||
};
|
};
|
||||||
expectedcompile = strings.concat(expectedcompile, "<-I><",
|
expectedcompile = strings.concat(expectedcompile, "<-I><",
|
||||||
works[si], "/", name, ".wwi.new><-o><", works[si], "/",
|
works[si], "/", name, ".wwi.new><-o><", works[si], "/",
|
||||||
@@ -2634,7 +2650,7 @@ fn hexbytes(value: str) str = {
|
|||||||
assert(same(linecontaining(atrace,
|
assert(same(linecontaining(atrace,
|
||||||
strings.concat("/", name, ".o.new")), expectedassemble));
|
strings.concat("/", name, ".o.new")), expectedassemble));
|
||||||
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
||||||
name, ".a>")) == 1);
|
name, ".a.new>")) == 1);
|
||||||
assert(os.exists(strings.concat(works[si], "/", name, ".wwi")));
|
assert(os.exists(strings.concat(works[si], "/", name, ".wwi")));
|
||||||
assert(os.exists(strings.concat(works[si], "/", name, ".s")));
|
assert(os.exists(strings.concat(works[si], "/", name, ".s")));
|
||||||
assert(os.exists(strings.concat(works[si], "/", name, ".o")));
|
assert(os.exists(strings.concat(works[si], "/", name, ".o")));
|
||||||
@@ -2652,35 +2668,47 @@ fn hexbytes(value: str) str = {
|
|||||||
};
|
};
|
||||||
let z: str = strings.concat("package ", name, ";\n// OWNER_Z_",
|
let z: str = strings.concat("package ", name, ";\n// OWNER_Z_",
|
||||||
name, "\nfn private_value() i32 = { return value(); };\n");
|
name, "\nfn private_value() i32 = { return value(); };\n");
|
||||||
assert(same(readfile(strings.concat(works[si], "/", name,
|
let unit: str = readfile(strings.concat(works[si], "/", name,
|
||||||
".unit.ww")), strings.concat("//ww:module-reset ", name,
|
".unit.ww"));
|
||||||
"\n", a, "\n//ww:module-reset ", name, "\n", z, "\n")));
|
assert(strings.hasprefix(unit, strings.concat("//ww:module-reset ",
|
||||||
|
name, "\n", a, "\n//ww:module-reset ", name, "\n", z, "\n")));
|
||||||
|
if (i + 1 < packagecount) {
|
||||||
|
assert(has(unit, strings.concat("//ww:direct-export ",
|
||||||
|
boundarypkgname(i + 1), " ")));
|
||||||
|
};
|
||||||
assert(strings.hasprefix(readfile(strings.concat(works[si], "/",
|
assert(strings.hasprefix(readfile(strings.concat(works[si], "/",
|
||||||
name, ".wwi")), strings.concat("//ww:module ", name, "\n")));
|
name, ".wwi")), strings.concat("//ww:module ", name, "\n")));
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
||||||
rootaction, ".a>")) == 1);
|
rootaction, ".a.new>")) == 1);
|
||||||
assert(!has(ltrace, ".wwi>"));
|
assert(!has(ltrace, ".wwi>"));
|
||||||
let expectedlink: str = strings.concat("BEGIN<-o><", bins[si], "><",
|
let expectedlink: str = strings.concat("BEGIN<-o><", bins[si], ".new><",
|
||||||
works[si], "/", rootaction, ".a>");
|
works[si], "/", rootaction, ".a.new>");
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < packagecount) {
|
for (i < packagecount) {
|
||||||
expectedlink = strings.concat(expectedlink, "<", works[si], "/",
|
expectedlink = strings.concat(expectedlink, "<", works[si], "/",
|
||||||
boundarypkgname(i), ".a>");
|
boundarypkgname(i), ".a.new>");
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
expectedlink = strings.concat(expectedlink, "<", repo(),
|
expectedlink = strings.concat(expectedlink, "<", repo(),
|
||||||
"/out/bin/../lib/libwwrt.a>\n");
|
"/out/bin/../lib/libwwrt.a>\n");
|
||||||
assert(same(ltrace, expectedlink));
|
assert(same(ltrace, expectedlink));
|
||||||
assert(same(readfile(strings.concat(works[si], "/", rootaction,
|
let rootunit: str = readfile(strings.concat(works[si], "/", rootaction,
|
||||||
".unit.ww")),
|
".unit.ww"));
|
||||||
|
assert(strings.hasprefix(rootunit,
|
||||||
strings.concat("//ww:module-reset target\n", roota,
|
strings.concat("//ww:module-reset target\n", roota,
|
||||||
"\n//ww:module-reset target\n", rootz, "\n")));
|
"\n//ww:module-reset target\n", rootz, "\n")));
|
||||||
|
assert(occurrences(rootunit, "//ww:direct-export p") == packagecount);
|
||||||
let rootassemble: str = strings.concat("BEGIN<-o><", works[si], "/",
|
let rootassemble: str = strings.concat("BEGIN<-o><", works[si], "/",
|
||||||
rootaction, ".o.new><", works[si], "/", rootaction, ".s.new>");
|
rootaction, ".o.new><", works[si], "/", rootaction, ".s.new>");
|
||||||
assert(same(linecontaining(atrace,
|
assert(same(linecontaining(atrace,
|
||||||
strings.concat("/", rootaction, ".o.new")), rootassemble));
|
strings.concat("/", rootaction, ".o.new")), rootassemble));
|
||||||
|
let dispatchassemble: str = strings.concat("BEGIN<-o><", works[si],
|
||||||
|
"/", rootaction, ".init.o.new><", works[si], "/", rootaction,
|
||||||
|
".init.s.new>");
|
||||||
|
assert(same(linecontaining(atrace,
|
||||||
|
strings.concat("/", rootaction, ".init.o.new")), dispatchassemble));
|
||||||
|
|
||||||
// Repeating the same semantic request in the persistent work root may
|
// Repeating the same semantic request in the persistent work root may
|
||||||
// relink the requested binary, but must not compile or assemble any action.
|
// relink the requested binary, but must not compile or assemble any action.
|
||||||
@@ -2711,16 +2739,21 @@ fn hexbytes(value: str) str = {
|
|||||||
let adelta: str = strings.sub(chainatrace, chainabefore, chainatrace.len);
|
let adelta: str = strings.sub(chainatrace, chainabefore, chainatrace.len);
|
||||||
let ldelta: str = strings.sub(chainltrace, chainlbefore, chainltrace.len);
|
let ldelta: str = strings.sub(chainltrace, chainlbefore, chainltrace.len);
|
||||||
assert(occurrences(cdelta, "\n") == 1);
|
assert(occurrences(cdelta, "\n") == 1);
|
||||||
assert(occurrences(adelta, "\n") == 1);
|
assert(occurrences(adelta, "\n") == 2);
|
||||||
assert(occurrences(ldelta, "\n") == 1);
|
assert(occurrences(ldelta, "\n") == 1);
|
||||||
assert(same(cdelta, strings.concat("BEGIN<--entry><-c><--import><p000><",
|
assert(same(cdelta, strings.concat(
|
||||||
|
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
|
||||||
|
chainaction, ".v0.r0.init><--init-dispatch-symbol>",
|
||||||
|
"<__ww..dispatch><-c><--import><p000><",
|
||||||
works[si], "/p000.wwi><-I><", works[si], "/", chainaction,
|
works[si], "/p000.wwi><-I><", works[si], "/", chainaction,
|
||||||
".wwi.new><-o><", works[si], "/", chainaction, ".s.new><",
|
".wwi.new><-o><", works[si], "/", chainaction, ".s.new><",
|
||||||
works[si], "/", chainaction, ".unit.new>\n")));
|
works[si], "/", chainaction, ".unit.new>\n")));
|
||||||
assert(same(adelta, strings.concat("BEGIN<-o><", works[si], "/",
|
assert(same(adelta, strings.concat("BEGIN<-o><", works[si], "/",
|
||||||
chainaction, ".o.new><", works[si], "/", chainaction, ".s.new>\n")));
|
chainaction, ".o.new><", works[si], "/", chainaction, ".s.new>\n",
|
||||||
|
"BEGIN<-o><", works[si], "/", chainaction, ".init.o.new><",
|
||||||
|
works[si], "/", chainaction, ".init.s.new>\n")));
|
||||||
let expectedchainlink: str = strings.concat("BEGIN<-o><", chainbins[si],
|
let expectedchainlink: str = strings.concat("BEGIN<-o><", chainbins[si],
|
||||||
"><", works[si], "/", chainaction, ".a>");
|
".new><", works[si], "/", chainaction, ".a.new>");
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < packagecount) {
|
for (i < packagecount) {
|
||||||
expectedchainlink = strings.concat(expectedchainlink, "<", works[si],
|
expectedchainlink = strings.concat(expectedchainlink, "<", works[si],
|
||||||
@@ -2731,9 +2764,11 @@ fn hexbytes(value: str) str = {
|
|||||||
"/out/bin/../lib/libwwrt.a>\n");
|
"/out/bin/../lib/libwwrt.a>\n");
|
||||||
assert(same(ldelta, expectedchainlink));
|
assert(same(ldelta, expectedchainlink));
|
||||||
assert(!has(ldelta, ".wwi>"));
|
assert(!has(ldelta, ".wwi>"));
|
||||||
assert(same(readfile(strings.concat(works[si], "/", chainaction,
|
let chainunit: str = readfile(strings.concat(works[si], "/", chainaction,
|
||||||
".unit.ww")), strings.concat("//ww:module-reset chain\n",
|
".unit.ww"));
|
||||||
chainsource, "\n")));
|
assert(strings.hasprefix(chainunit, strings.concat(
|
||||||
|
"//ww:module-reset chain\n", chainsource, "\n")));
|
||||||
|
assert(has(chainunit, "//ww:direct-export p000 "));
|
||||||
let chainrun: []str = [chainbins[si]];
|
let chainrun: []str = [chainbins[si]];
|
||||||
runcommand(root, strings.concat("boundary-chain-run-", stages[si]),
|
runcommand(root, strings.concat("boundary-chain-run-", stages[si]),
|
||||||
chainrun, (60i64 * (time.second: i64)): time.duration, &out);
|
chainrun, (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
@@ -3308,26 +3343,20 @@ fn hexbytes(value: str) str = {
|
|||||||
runcommand(root, strings.concat("multidir-failure-", stages[i]), av,
|
runcommand(root, strings.concat("multidir-failure-", stages[i]), av,
|
||||||
(120i64 * (time.second: i64)): time.duration, &out);
|
(120i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 1);
|
expectexit(&out, 1);
|
||||||
assert(has(out.stdout, "alpha_same_survives ... ok\n"));
|
assert(out.stdout.len == 0);
|
||||||
assert(has(out.stdout, "beta_same_survives ... ok\n"));
|
|
||||||
assert(has(out.stdout, "beta_external_survives ... ok\n"));
|
|
||||||
assert(has(out.stdout, strings.concat("ok ", alpha,
|
|
||||||
" [alpha, same-package]\n")));
|
|
||||||
assert(has(out.stdout, strings.concat("ok ", beta,
|
|
||||||
" [beta, same-package]\n")));
|
|
||||||
assert(has(out.stdout, strings.concat("ok ", beta,
|
|
||||||
" [beta_test, external]\n")));
|
|
||||||
assert(!has(out.stdout, "alpha_external_fails ..."));
|
|
||||||
assert(has(out.stderr, "has no exported declaration 'hidden'"));
|
assert(has(out.stderr, "has no exported declaration 'hidden'"));
|
||||||
|
assert(has(out.stderr, strings.concat("FAIL ", alpha,
|
||||||
|
" [alpha] (build exit 1)\n")));
|
||||||
assert(has(out.stderr, strings.concat("FAIL ", alpha,
|
assert(has(out.stderr, strings.concat("FAIL ", alpha,
|
||||||
" [alpha_test] (build exit 1)\n")));
|
" [alpha_test] (build exit 1)\n")));
|
||||||
assert(!has(out.stderr, strings.concat("FAIL ", alpha,
|
assert(has(out.stderr, strings.concat("FAIL ", beta,
|
||||||
" [alpha]")));
|
" [beta] (build exit 1)\n")));
|
||||||
assert(!has(out.stderr, strings.concat("FAIL ", beta, " [")));
|
assert(has(out.stderr, strings.concat("FAIL ", beta,
|
||||||
let alphapos: i32 = pos(out.stdout, strings.concat("ok ", alpha,
|
" [beta_test] (build exit 1)\n")));
|
||||||
" [alpha, same-package]\n"));
|
let alphapos: i32 = pos(out.stderr, strings.concat("FAIL ", alpha,
|
||||||
let betapos: i32 = pos(out.stdout, strings.concat("ok ", beta,
|
" [alpha] (build exit 1)\n"));
|
||||||
" [beta, same-package]\n"));
|
let betapos: i32 = pos(out.stderr, strings.concat("FAIL ", beta,
|
||||||
|
" [beta] (build exit 1)\n"));
|
||||||
assert(alphapos >= 0 && alphapos < betapos);
|
assert(alphapos >= 0 && alphapos < betapos);
|
||||||
diagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
diagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
||||||
if (i == 0) { referenceout = strings.dup(out.stdout); }
|
if (i == 0) { referenceout = strings.dup(out.stdout); }
|
||||||
@@ -3338,8 +3367,8 @@ fn hexbytes(value: str) str = {
|
|||||||
clean(root);
|
clean(root);
|
||||||
};
|
};
|
||||||
|
|
||||||
// One failing root is a product failure, not permission for the shared build
|
// Roots remain independently diagnosed and may be staged in parallel, but one
|
||||||
// request to suppress an independently compilable sibling root.
|
// failing product rejects publication and execution of the entire request.
|
||||||
@test fn sibling_test_variant_failures_are_isolated() void = {
|
@test fn sibling_test_variant_failures_are_isolated() void = {
|
||||||
let root: str = fresh();
|
let root: str = fresh();
|
||||||
let badexternal: str = strings.concat(root, "/badexternal");
|
let badexternal: str = strings.concat(root, "/badexternal");
|
||||||
@@ -3380,15 +3409,15 @@ fn hexbytes(value: str) str = {
|
|||||||
runcommand(root, strings.concat("isolated-external-", tags[i]),
|
runcommand(root, strings.concat("isolated-external-", tags[i]),
|
||||||
externalav, (120i64 * (time.second: i64)): time.duration, &out);
|
externalav, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 1);
|
expectexit(&out, 1);
|
||||||
assert(has(out.stdout, "valid_same_runs ... ok\n"));
|
assert(out.stdout.len == 0);
|
||||||
assert(has(out.stdout, "[badexternal, same-package]\n"));
|
|
||||||
assert(has(out.stderr,
|
assert(has(out.stderr,
|
||||||
"has no exported declaration 'hidden'"));
|
"has no exported declaration 'hidden'"));
|
||||||
|
assert(has(out.stderr,
|
||||||
|
strings.concat("FAIL ", badexternal,
|
||||||
|
" [badexternal] (build exit 1)\n")));
|
||||||
assert(has(out.stderr,
|
assert(has(out.stderr,
|
||||||
strings.concat("FAIL ", badexternal,
|
strings.concat("FAIL ", badexternal,
|
||||||
" [badexternal_test] (build exit 1)\n")));
|
" [badexternal_test] (build exit 1)\n")));
|
||||||
assert(!has(out.stderr, strings.concat("FAIL ", badexternal,
|
|
||||||
" [badexternal]")));
|
|
||||||
externaldiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
externaldiagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
||||||
|
|
||||||
let sameav: []str = [driver(stages[i]), "test", "-I", root,
|
let sameav: []str = [driver(stages[i]), "test", "-I", root,
|
||||||
@@ -3396,23 +3425,20 @@ fn hexbytes(value: str) str = {
|
|||||||
runcommand(root, strings.concat("isolated-same-", tags[i]), sameav,
|
runcommand(root, strings.concat("isolated-same-", tags[i]), sameav,
|
||||||
(120i64 * (time.second: i64)): time.duration, &out);
|
(120i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 1);
|
expectexit(&out, 1);
|
||||||
assert(has(out.stdout, "valid_external_runs ... ok\n"));
|
assert(out.stdout.len == 0);
|
||||||
assert(has(out.stdout, "[badsame_test, external]\n"));
|
|
||||||
assert(has(out.stderr, "undefined: missing"));
|
assert(has(out.stderr, "undefined: missing"));
|
||||||
assert(has(out.stderr, strings.concat("FAIL ", badsame,
|
assert(has(out.stderr, strings.concat("FAIL ", badsame,
|
||||||
" [badsame] (build exit 1)\n")));
|
" [badsame] (build exit 1)\n")));
|
||||||
assert(!has(out.stderr, strings.concat("FAIL ", badsame,
|
assert(has(out.stderr, strings.concat("FAIL ", badsame,
|
||||||
" [badsame_test]")));
|
" [badsame_test] (build exit 1)\n")));
|
||||||
samediagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
samediagnostics[i] = strings.dup(primarydiagnostic(out.stderr));
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
assert(same(externaldiagnostics[0], externaldiagnostics[1]));
|
assert(same(externaldiagnostics[0], externaldiagnostics[1]));
|
||||||
assert(same(samediagnostics[0], samediagnostics[1]));
|
assert(same(samediagnostics[0], samediagnostics[1]));
|
||||||
|
|
||||||
// A first persistent union pass may contain a root-local compiler failure.
|
// A persistent request is one publication transaction. A rejection leaves
|
||||||
// Its successfully committed actions still become reusable: only the
|
// no reusable generation, so every staged action is reconsidered next time.
|
||||||
// uncommitted failing root is compiled again on the next request in both
|
|
||||||
// driver stages.
|
|
||||||
let warmroot: str = strings.concat(root, "/warm-partial");
|
let warmroot: str = strings.concat(root, "/warm-partial");
|
||||||
assert(os.mkdir(warmroot, 448i32) == 0);
|
assert(os.mkdir(warmroot, 448i32) == 0);
|
||||||
let trace: str = strings.concat(root, "/warm-partial.trace");
|
let trace: str = strings.concat(root, "/warm-partial.trace");
|
||||||
@@ -3452,9 +3478,14 @@ fn hexbytes(value: str) str = {
|
|||||||
expectexit(&out, 1);
|
expectexit(&out, 1);
|
||||||
let secondtrace: str = readfile(trace);
|
let secondtrace: str = readfile(trace);
|
||||||
assert(occurrences(secondtrace,
|
assert(occurrences(secondtrace,
|
||||||
"/badexternal-internal-test.unit.new") == 1);
|
"/badexternal-internal-test.unit.new") == 2);
|
||||||
assert(occurrences(secondtrace,
|
assert(occurrences(secondtrace,
|
||||||
"/badexternal_test-external-test.unit.new") == 2);
|
"/badexternal_test-external-test.unit.new") == 2);
|
||||||
|
assert(!os.exists(strings.concat(warmroot,
|
||||||
|
"/badexternal-internal-test.unit.ww")));
|
||||||
|
assert(!os.exists(strings.concat(warmroot,
|
||||||
|
"/badexternal_test-external-test.unit.ww")));
|
||||||
|
assert(!os.exists(strings.concat(warmroot, "/.wwtool.stamp")));
|
||||||
|
|
||||||
let wwtracebin: str = strings.concat(repo(), "/out/partial-trace-",
|
let wwtracebin: str = strings.concat(repo(), "/out/partial-trace-",
|
||||||
workescape(root));
|
workescape(root));
|
||||||
@@ -3502,9 +3533,14 @@ fn hexbytes(value: str) str = {
|
|||||||
expectexit(&out, 1);
|
expectexit(&out, 1);
|
||||||
let wwsecond: str = readfile(wwtrace);
|
let wwsecond: str = readfile(wwtrace);
|
||||||
assert(occurrences(wwsecond,
|
assert(occurrences(wwsecond,
|
||||||
"/badexternal-internal-test.unit.new") == 1);
|
"/badexternal-internal-test.unit.new") == 2);
|
||||||
assert(occurrences(wwsecond,
|
assert(occurrences(wwsecond,
|
||||||
"/badexternal_test-external-test.unit.new") == 2);
|
"/badexternal_test-external-test.unit.new") == 2);
|
||||||
|
assert(!os.exists(strings.concat(wwwarmroot,
|
||||||
|
"/badexternal-internal-test.unit.ww")));
|
||||||
|
assert(!os.exists(strings.concat(wwwarmroot,
|
||||||
|
"/badexternal_test-external-test.unit.ww")));
|
||||||
|
assert(!os.exists(strings.concat(wwwarmroot, "/.wwtool.stamp")));
|
||||||
clean(wwtracebin);
|
clean(wwtracebin);
|
||||||
clean(root);
|
clean(root);
|
||||||
};
|
};
|
||||||
@@ -3850,8 +3886,10 @@ fn hexbytes(value: str) str = {
|
|||||||
let wantsecret: str = strings.concat(
|
let wantsecret: str = strings.concat(
|
||||||
"//ww:module-reset domain.internal.secret\n", secreta,
|
"//ww:module-reset domain.internal.secret\n", secreta,
|
||||||
"\n//ww:module-reset domain.internal.secret\n", secretz, "\n");
|
"\n//ww:module-reset domain.internal.secret\n", secretz, "\n");
|
||||||
assert(same(readfile(strings.concat(works[si],
|
let secretunit: str = readfile(strings.concat(works[si],
|
||||||
"/domain.internal.secret.unit.ww")), wantsecret));
|
"/domain.internal.secret.unit.ww"));
|
||||||
|
assert(strings.hasprefix(secretunit, wantsecret));
|
||||||
|
assert(has(secretunit, "//ww:direct-export domain.leaf "));
|
||||||
let ai: i32 = 0;
|
let ai: i32 = 0;
|
||||||
for (ai < artifacts.len) {
|
for (ai < artifacts.len) {
|
||||||
let xi: i32 = 0;
|
let xi: i32 = 0;
|
||||||
@@ -3869,8 +3907,13 @@ fn hexbytes(value: str) str = {
|
|||||||
let atrace: str = readfile(assemblertraces[si]);
|
let atrace: str = readfile(assemblertraces[si]);
|
||||||
let ltrace: str = readfile(linkertraces[si]);
|
let ltrace: str = readfile(linkertraces[si]);
|
||||||
assert(occurrences(ctrace, "\n") == 3);
|
assert(occurrences(ctrace, "\n") == 3);
|
||||||
assert(occurrences(atrace, "\n") == 3);
|
assert(occurrences(atrace, "\n") == 4);
|
||||||
assert(occurrences(ltrace, "\n") == 1);
|
assert(occurrences(ltrace, "\n") == 1);
|
||||||
|
let dispatchline: str = strings.concat("BEGIN<-o><", works[si],
|
||||||
|
"/domain.client.init.o.new><", works[si],
|
||||||
|
"/domain.client.init.s.new>");
|
||||||
|
assert(same(linecontaining(atrace, "/domain.client.init.o.new"),
|
||||||
|
dispatchline));
|
||||||
let secretline: str = linecontaining(ctrace,
|
let secretline: str = linecontaining(ctrace,
|
||||||
"domain.internal.secret.unit.new");
|
"domain.internal.secret.unit.new");
|
||||||
assert(occurrences(secretline, "domain.leaf.wwi") == 1);
|
assert(occurrences(secretline, "domain.leaf.wwi") == 1);
|
||||||
@@ -4420,7 +4463,16 @@ fn hexbytes(value: str) str = {
|
|||||||
for (ui < unitartifacts.len) {
|
for (ui < unitartifacts.len) {
|
||||||
let unit: str = readfile(strings.concat(work, unitartifacts[ui],
|
let unit: str = readfile(strings.concat(work, unitartifacts[ui],
|
||||||
".unit.ww"));
|
".unit.ww"));
|
||||||
assert(same(unit, wantunits[ui]));
|
assert(strings.hasprefix(unit, wantunits[ui]));
|
||||||
|
if (ui == 1 || ui == 2) {
|
||||||
|
assert(has(unit, strings.concat("//ww:direct-export ",
|
||||||
|
baseidentity, " ")));
|
||||||
|
} else { if (ui == 3) {
|
||||||
|
assert(has(unit, strings.concat("//ww:direct-export ",
|
||||||
|
leftidentity, " ")));
|
||||||
|
assert(has(unit, strings.concat("//ww:direct-export ",
|
||||||
|
rightidentity, " ")));
|
||||||
|
}; };
|
||||||
assert(!has(unit, "//ww:module "));
|
assert(!has(unit, "//ww:module "));
|
||||||
if (si == 0) { referenceunits[ui] = strings.dup(unit); }
|
if (si == 0) { referenceunits[ui] = strings.dup(unit); }
|
||||||
else { assert(same(referenceunits[ui], unit)); };
|
else { assert(same(referenceunits[ui], unit)); };
|
||||||
@@ -4458,23 +4510,32 @@ fn hexbytes(value: str) str = {
|
|||||||
let atrace: str = readfile(assemblertrace);
|
let atrace: str = readfile(assemblertrace);
|
||||||
let ltrace: str = readfile(linkertrace);
|
let ltrace: str = readfile(linkertrace);
|
||||||
assert(occurrences(ctrace, "\n") == 4);
|
assert(occurrences(ctrace, "\n") == 4);
|
||||||
let baseline: str = strings.concat("BEGIN<-c><-I><", work,
|
let baseline: str = strings.concat(
|
||||||
|
"BEGIN<--package-init-symbol><__ww..pkg.p.", baseidentity,
|
||||||
|
".v0.r0.init><-c><-I><", work,
|
||||||
artifacts[0], ".wwi><-o><", work,
|
artifacts[0], ".wwi><-o><", work,
|
||||||
artifacts[0], ".s><", work,
|
artifacts[0], ".s><", work,
|
||||||
artifacts[0], ".unit.ww>");
|
artifacts[0], ".unit.ww>");
|
||||||
let leftline: str = strings.concat("BEGIN<-c><--import>",
|
let leftline: str = strings.concat(
|
||||||
|
"BEGIN<--package-init-symbol><__ww..pkg.p.", leftidentity,
|
||||||
|
".v0.r0.init><-c><--import>",
|
||||||
"<", baseidentity, "><", work,
|
"<", baseidentity, "><", work,
|
||||||
artifacts[0], ".wwi><-I><", work,
|
artifacts[0], ".wwi><-I><", work,
|
||||||
artifacts[1], ".wwi><-o><", work,
|
artifacts[1], ".wwi><-o><", work,
|
||||||
artifacts[1], ".s><", work,
|
artifacts[1], ".s><", work,
|
||||||
artifacts[1], ".unit.ww>");
|
artifacts[1], ".unit.ww>");
|
||||||
let rightline: str = strings.concat("BEGIN<-c><--import>",
|
let rightline: str = strings.concat(
|
||||||
|
"BEGIN<--package-init-symbol><__ww..pkg.p.", rightidentity,
|
||||||
|
".v0.r0.init><-c><--import>",
|
||||||
"<", baseidentity, "><", work,
|
"<", baseidentity, "><", work,
|
||||||
artifacts[0], ".wwi><-I><", work,
|
artifacts[0], ".wwi><-I><", work,
|
||||||
artifacts[2], ".wwi><-o><", work,
|
artifacts[2], ".wwi><-o><", work,
|
||||||
artifacts[2], ".s><", work,
|
artifacts[2], ".s><", work,
|
||||||
artifacts[2], ".unit.ww>");
|
artifacts[2], ".unit.ww>");
|
||||||
let rootline: str = strings.concat("BEGIN<--entry><-c><--import>",
|
let rootline: str = strings.concat(
|
||||||
|
"BEGIN<--entry><--package-init-symbol><__ww..pkg.p.",
|
||||||
|
rootidentity, ".v0.r0.init><--init-dispatch-symbol>",
|
||||||
|
"<__ww..dispatch><-c><--import>",
|
||||||
"<", leftidentity, "><", work,
|
"<", leftidentity, "><", work,
|
||||||
artifacts[1], ".wwi><--import>",
|
artifacts[1], ".wwi><--import>",
|
||||||
"<", rightidentity, "><", work,
|
"<", rightidentity, "><", work,
|
||||||
@@ -4520,7 +4581,7 @@ fn hexbytes(value: str) str = {
|
|||||||
expectexit(&out, 1);
|
expectexit(&out, 1);
|
||||||
assert(same(out.stderr, strings.concat("w6c: import ", leftidentity,
|
assert(same(out.stderr, strings.concat("w6c: import ", leftidentity,
|
||||||
": export owner mismatch in ", work, artifacts[0], ".wwi\n")));
|
": export owner mismatch in ", work, artifacts[0], ".wwi\n")));
|
||||||
assert(occurrences(atrace, "\n") == 4);
|
assert(occurrences(atrace, "\n") == 5);
|
||||||
ai = 0;
|
ai = 0;
|
||||||
for (ai < artifacts.len) {
|
for (ai < artifacts.len) {
|
||||||
let assemblerline: str = strings.concat("BEGIN<-o><", work,
|
let assemblerline: str = strings.concat("BEGIN<-o><", work,
|
||||||
@@ -4529,8 +4590,12 @@ fn hexbytes(value: str) str = {
|
|||||||
artifacts[ai], ".o")), assemblerline));
|
artifacts[ai], ".o")), assemblerline));
|
||||||
ai += 1;
|
ai += 1;
|
||||||
};
|
};
|
||||||
|
let dispatcherline: str = strings.concat("BEGIN<-o><", work,
|
||||||
|
artifacts[3], ".init.o><", work, artifacts[3], ".init.s>");
|
||||||
|
assert(same(linecontaining(atrace, strings.concat(work,
|
||||||
|
artifacts[3], ".init.o")), dispatcherline));
|
||||||
assert(occurrences(ltrace, "\n") == 1);
|
assert(occurrences(ltrace, "\n") == 1);
|
||||||
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, ".new><", work,
|
||||||
artifacts[3], ".a>")));
|
artifacts[3], ".a>")));
|
||||||
ai = 0;
|
ai = 0;
|
||||||
for (ai < artifacts.len) {
|
for (ai < artifacts.len) {
|
||||||
@@ -4842,17 +4907,17 @@ fn hexbytes(value: str) str = {
|
|||||||
let externalline: str = linecontaining(ctrace,
|
let externalline: str = linecontaining(ctrace,
|
||||||
strings.concat(artifacts[2], ".unit.new"));
|
strings.concat(artifacts[2], ".unit.new"));
|
||||||
assert(has(externalline, strings.concat("<--import><", commandid,
|
assert(has(externalline, strings.concat("<--import><", commandid,
|
||||||
"><", work, artifacts[0], ".wwi>")));
|
"><", work, artifacts[0], ".wwi.new>")));
|
||||||
let internalmainline: str = linecontaining(ctrace,
|
let internalmainline: str = linecontaining(ctrace,
|
||||||
strings.concat(artifacts[3], ".unit.new"));
|
strings.concat(artifacts[3], ".unit.new"));
|
||||||
let externalmainline: str = linecontaining(ctrace,
|
let externalmainline: str = linecontaining(ctrace,
|
||||||
strings.concat(artifacts[4], ".unit.new"));
|
strings.concat(artifacts[4], ".unit.new"));
|
||||||
assert(has(internalmainline, strings.concat("<--import><", internalid,
|
assert(has(internalmainline, strings.concat("<--import><", internalid,
|
||||||
"><", work, artifacts[1], ".wwi>")));
|
"><", work, artifacts[1], ".wwi.new>")));
|
||||||
assert(has(internalmainline, strings.concat(
|
assert(has(internalmainline, strings.concat(
|
||||||
"<--test-target-package><", internalid, ">")));
|
"<--test-target-package><", internalid, ">")));
|
||||||
assert(has(externalmainline, strings.concat("<--import><", externalid,
|
assert(has(externalmainline, strings.concat("<--import><", externalid,
|
||||||
"><", work, artifacts[2], ".wwi>")));
|
"><", work, artifacts[2], ".wwi.new>")));
|
||||||
assert(has(externalmainline, strings.concat(
|
assert(has(externalmainline, strings.concat(
|
||||||
"<--test-target-package><", externalid, ">")));
|
"<--test-target-package><", externalid, ">")));
|
||||||
assert(occurrences(ctrace, strings.concat("<", work, artifacts[0],
|
assert(occurrences(ctrace, strings.concat("<", work, artifacts[0],
|
||||||
@@ -5470,27 +5535,37 @@ fn hexbytes(value: str) str = {
|
|||||||
let commandatrace: str = readfile(commandassemblertraces[commandstage]);
|
let commandatrace: str = readfile(commandassemblertraces[commandstage]);
|
||||||
let commandltrace: str = readfile(commandlinkertraces[commandstage]);
|
let commandltrace: str = readfile(commandlinkertraces[commandstage]);
|
||||||
assert(occurrences(commandctrace, "\n") == 3);
|
assert(occurrences(commandctrace, "\n") == 3);
|
||||||
assert(occurrences(commandatrace, "\n") == 3);
|
assert(occurrences(commandatrace, "\n") == 5);
|
||||||
assert(occurrences(commandltrace, "\n") == 2);
|
assert(occurrences(commandltrace, "\n") == 2);
|
||||||
let commandalphacompile: str = linecontaining(commandctrace,
|
let commandalphacompile: str = linecontaining(commandctrace,
|
||||||
strings.concat(commandalphaid, ".unit.new"));
|
strings.concat(commandalphaid, ".unit.new"));
|
||||||
assert(occurrences(commandalphacompile, strings.concat(
|
assert(occurrences(commandalphacompile, strings.concat(
|
||||||
"<--import><library><", commandwork, "library.wwi>")) == 1);
|
"<--import><library><", commandwork, "library.wwi.new>")) == 1);
|
||||||
assert(!has(commandalphacompile, "cmd-zeta.wwi"));
|
assert(!has(commandalphacompile, "cmd-zeta.wwi"));
|
||||||
|
let alphaassembly: str = strings.concat("BEGIN<-o><", commandwork,
|
||||||
|
commandalphaid, ".init.o.new><", commandwork, commandalphaid,
|
||||||
|
".init.s.new>");
|
||||||
|
let zetaassembly: str = strings.concat("BEGIN<-o><", commandwork,
|
||||||
|
commandzetaid, ".init.o.new><", commandwork, commandzetaid,
|
||||||
|
".init.s.new>");
|
||||||
|
assert(same(linecontaining(commandatrace, strings.concat(commandalphaid,
|
||||||
|
".init.o.new")), alphaassembly));
|
||||||
|
assert(same(linecontaining(commandatrace, strings.concat(commandzetaid,
|
||||||
|
".init.o.new")), zetaassembly));
|
||||||
let commandalphalink: str = linecontaining(commandltrace,
|
let commandalphalink: str = linecontaining(commandltrace,
|
||||||
strings.concat("<-o><", commandbins[commandstage], "/cmd-alpha>"));
|
strings.concat("<-o><", commandbins[commandstage], "/cmd-alpha.new>"));
|
||||||
let commandzetalink: str = linecontaining(commandltrace,
|
let commandzetalink: str = linecontaining(commandltrace,
|
||||||
strings.concat("<-o><", commandbins[commandstage], "/cmd-zeta>"));
|
strings.concat("<-o><", commandbins[commandstage], "/cmd-zeta.new>"));
|
||||||
assert(occurrences(commandalphalink, strings.concat("<", commandwork,
|
assert(occurrences(commandalphalink, strings.concat("<", commandwork,
|
||||||
commandalphaid, ".a>")) == 1);
|
commandalphaid, ".a.new>")) == 1);
|
||||||
assert(occurrences(commandalphalink, strings.concat("<", commandwork,
|
assert(occurrences(commandalphalink, strings.concat("<", commandwork,
|
||||||
"library.a>")) == 1);
|
"library.a.new>")) == 1);
|
||||||
assert(!has(commandalphalink, strings.concat(commandzetaid, ".a")));
|
assert(!has(commandalphalink, strings.concat(commandzetaid, ".a")));
|
||||||
assert(!has(commandalphalink, ".wwi>"));
|
assert(!has(commandalphalink, ".wwi>"));
|
||||||
assert(has(commandalphalink, strings.concat("<-L><", repo(),
|
assert(has(commandalphalink, strings.concat("<-L><", repo(),
|
||||||
"/out/lib><-l><wcc>")));
|
"/out/lib><-l><wcc>")));
|
||||||
assert(has(commandzetalink, strings.concat("<", commandwork,
|
assert(has(commandzetalink, strings.concat("<", commandwork,
|
||||||
commandzetaid, ".a>")));
|
commandzetaid, ".a.new>")));
|
||||||
assert(!has(commandzetalink, "library.a"));
|
assert(!has(commandzetalink, "library.a"));
|
||||||
assert(!has(commandzetalink, ".wwi>"));
|
assert(!has(commandzetalink, ".wwi>"));
|
||||||
let normalizedcommandcompiler: str = normalizedtrace(commandctrace,
|
let normalizedcommandcompiler: str = normalizedtrace(commandctrace,
|
||||||
@@ -7276,8 +7351,10 @@ fn runtimepath(relative: str) str = {
|
|||||||
"//ww:module-reset ", expanded, "\n", neara, "\n",
|
"//ww:module-reset ", expanded, "\n", neara, "\n",
|
||||||
"//ww:module-reset ", expanded, "\n", nearz, "\n",
|
"//ww:module-reset ", expanded, "\n", nearz, "\n",
|
||||||
"//ww:vendor-dir ", hexbytes(nearest), "\n");
|
"//ww:vendor-dir ", hexbytes(nearest), "\n");
|
||||||
assert(same(readfile(strings.concat(works[si], "/", expanded,
|
let nearunit: str = readfile(strings.concat(works[si], "/", expanded,
|
||||||
".unit.ww")), wantnear));
|
".unit.ww"));
|
||||||
|
assert(strings.hasprefix(nearunit, wantnear));
|
||||||
|
assert(has(nearunit, "//ww:direct-export lib.leaf "));
|
||||||
let clientunit: str = readfile(strings.concat(works[si],
|
let clientunit: str = readfile(strings.concat(works[si],
|
||||||
"/domain.app.client.unit.ww"));
|
"/domain.app.client.unit.ww"));
|
||||||
assert(has(clientunit, strings.concat("//ww:import-map lib.math ",
|
assert(has(clientunit, strings.concat("//ww:import-map lib.math ",
|
||||||
@@ -7299,8 +7376,14 @@ fn runtimepath(relative: str) str = {
|
|||||||
let atrace: str = readfile(assemblertraces[si]);
|
let atrace: str = readfile(assemblertraces[si]);
|
||||||
let ltrace: str = readfile(linkertraces[si]);
|
let ltrace: str = readfile(linkertraces[si]);
|
||||||
assert(occurrences(ctrace, "\n") == 3);
|
assert(occurrences(ctrace, "\n") == 3);
|
||||||
assert(occurrences(atrace, "\n") == 3);
|
assert(occurrences(atrace, "\n") == 4);
|
||||||
assert(occurrences(ltrace, "\n") == 1);
|
assert(occurrences(ltrace, "\n") == 1);
|
||||||
|
assert(has(ltrace, strings.concat("BEGIN<-o><", bins[si], ".new>")));
|
||||||
|
let dispatchline: str = strings.concat("BEGIN<-o><", works[si],
|
||||||
|
"/domain.app.client.init.o.new><", works[si],
|
||||||
|
"/domain.app.client.init.s.new>");
|
||||||
|
assert(same(linecontaining(atrace,
|
||||||
|
"/domain.app.client.init.o.new"), dispatchline));
|
||||||
let nearline: str = linecontaining(ctrace,
|
let nearline: str = linecontaining(ctrace,
|
||||||
strings.concat(expanded, ".unit.new"));
|
strings.concat(expanded, ".unit.new"));
|
||||||
assert(occurrences(nearline, "<--import><lib.leaf>") == 1);
|
assert(occurrences(nearline, "<--import><lib.leaf>") == 1);
|
||||||
@@ -7308,16 +7391,16 @@ fn runtimepath(relative: str) str = {
|
|||||||
let clientline: str = linecontaining(ctrace,
|
let clientline: str = linecontaining(ctrace,
|
||||||
"domain.app.client.unit.new");
|
"domain.app.client.unit.new");
|
||||||
assert(occurrences(clientline, strings.concat("<--import><", expanded,
|
assert(occurrences(clientline, strings.concat("<--import><", expanded,
|
||||||
"><", works[si], "/", expanded, ".wwi>")) == 1);
|
"><", works[si], "/", expanded, ".wwi.new>")) == 1);
|
||||||
assert(occurrences(clientline, strings.concat(
|
assert(occurrences(clientline, strings.concat(
|
||||||
"<--import-map><lib.math><", expanded, ">")) == 1);
|
"<--import-map><lib.math><", expanded, ">")) == 1);
|
||||||
assert(!has(clientline, "lib.leaf.wwi"));
|
assert(!has(clientline, "lib.leaf.wwi"));
|
||||||
assert(occurrences(ltrace, strings.concat("<", works[si],
|
assert(occurrences(ltrace, strings.concat("<", works[si],
|
||||||
"/domain.app.client.a>")) == 1);
|
"/domain.app.client.a.new>")) == 1);
|
||||||
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
assert(occurrences(ltrace, strings.concat("<", works[si], "/",
|
||||||
expanded, ".a>")) == 1);
|
expanded, ".a.new>")) == 1);
|
||||||
assert(occurrences(ltrace, strings.concat("<", works[si],
|
assert(occurrences(ltrace, strings.concat("<", works[si],
|
||||||
"/lib.leaf.a>")) == 1);
|
"/lib.leaf.a.new>")) == 1);
|
||||||
assert(!has(ltrace, ".wwi>"));
|
assert(!has(ltrace, ".wwi>"));
|
||||||
let nc: str = normalizedtrace(ctrace,
|
let nc: str = normalizedtrace(ctrace,
|
||||||
strings.concat(works[si], "/"), bins[si]);
|
strings.concat(works[si], "/"), bins[si]);
|
||||||
@@ -7732,9 +7815,9 @@ fn runtimepath(relative: str) str = {
|
|||||||
let externalline: str = linecontaining(testtrace,
|
let externalline: str = linecontaining(testtrace,
|
||||||
"domain.app.testclient_test-external-test.unit.new");
|
"domain.app.testclient_test-external-test.unit.new");
|
||||||
assert(occurrences(internalline, strings.concat("<--import><", expanded,
|
assert(occurrences(internalline, strings.concat("<--import><", expanded,
|
||||||
"><", testwork, expanded, ".wwi>")) == 1);
|
"><", testwork, expanded, ".wwi.new>")) == 1);
|
||||||
assert(occurrences(externalline, strings.concat("<--import><", expanded,
|
assert(occurrences(externalline, strings.concat("<--import><", expanded,
|
||||||
"><", testwork, expanded, ".wwi>")) == 1);
|
"><", testwork, expanded, ".wwi.new>")) == 1);
|
||||||
assert(occurrences(internalline, strings.concat(
|
assert(occurrences(internalline, strings.concat(
|
||||||
"<--import-map><lib.math><", expanded, ">")) == 1);
|
"<--import-map><lib.math><", expanded, ">")) == 1);
|
||||||
assert(occurrences(externalline, strings.concat(
|
assert(occurrences(externalline, strings.concat(
|
||||||
@@ -8029,15 +8112,7 @@ fn runtimepath(relative: str) str = {
|
|||||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||||
"\"$WW_NAME_COMPILER_TRACE\"; done\n",
|
"\"$WW_NAME_COMPILER_TRACE\"; done\n",
|
||||||
"printf '\\n' >> \"$WW_NAME_COMPILER_TRACE\"\n",
|
"printf '\\n' >> \"$WW_NAME_COMPILER_TRACE\"\n",
|
||||||
"\"$WW_NAME_REAL_COMPILER\" \"$@\"\n",
|
"exec \"$WW_NAME_REAL_COMPILER\" \"$@\"\n"));
|
||||||
"status=$?\n",
|
|
||||||
"if [ \"$status\" -eq 0 ] && ",
|
|
||||||
"[ -n \"$WW_COMMIT_BLOCK_STAMP\" ]; then\n",
|
|
||||||
" mv -- \"$WW_COMMIT_BLOCK_STAMP\" ",
|
|
||||||
"\"$WW_COMMIT_BLOCK_STAMP.saved\" || exit 97\n",
|
|
||||||
" mkdir -- \"$WW_COMMIT_BLOCK_STAMP\" || exit 98\n",
|
|
||||||
"fi\n",
|
|
||||||
"exit \"$status\"\n"));
|
|
||||||
|
|
||||||
let stages: []str = ["ww", "ww_ww"];
|
let stages: []str = ["ww", "ww_ww"];
|
||||||
let compilers: []str = ["w6c", "w6c_ww"];
|
let compilers: []str = ["w6c", "w6c_ww"];
|
||||||
@@ -8059,8 +8134,6 @@ fn runtimepath(relative: str) str = {
|
|||||||
strings.concat(root, "/ww-commit-work")];
|
strings.concat(root, "/ww-commit-work")];
|
||||||
let commitcoldbins: []str = [strings.concat(root, "/c-commit-cold"),
|
let commitcoldbins: []str = [strings.concat(root, "/c-commit-cold"),
|
||||||
strings.concat(root, "/ww-commit-cold")];
|
strings.concat(root, "/ww-commit-cold")];
|
||||||
let commitblockbins: []str = [strings.concat(root, "/c-commit-block"),
|
|
||||||
strings.concat(root, "/ww-commit-block")];
|
|
||||||
let commitrejectbins: []str = [strings.concat(root, "/c-commit-reject"),
|
let commitrejectbins: []str = [strings.concat(root, "/c-commit-reject"),
|
||||||
strings.concat(root, "/ww-commit-reject")];
|
strings.concat(root, "/ww-commit-reject")];
|
||||||
let commitfixedbins: []str = [strings.concat(root, "/c-commit-fixed"),
|
let commitfixedbins: []str = [strings.concat(root, "/c-commit-fixed"),
|
||||||
@@ -8087,8 +8160,6 @@ fn runtimepath(relative: str) str = {
|
|||||||
let repeatedtraceref: str = "";
|
let repeatedtraceref: str = "";
|
||||||
let changedtraceref: str = "";
|
let changedtraceref: str = "";
|
||||||
let aliastraceref: str = "";
|
let aliastraceref: str = "";
|
||||||
let commitfailref: str = "";
|
|
||||||
let commitpreflightref: str = "";
|
|
||||||
let commitbindingref: str = "";
|
let commitbindingref: str = "";
|
||||||
let commitbinref: str = "";
|
let commitbinref: str = "";
|
||||||
let initialwwiref: str = "";
|
let initialwwiref: str = "";
|
||||||
@@ -8115,9 +8186,7 @@ fn runtimepath(relative: str) str = {
|
|||||||
&& !strings.hasprefix(baseenv[ei],
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
"WW_NAME_COMPILER_TRACE=")
|
"WW_NAME_COMPILER_TRACE=")
|
||||||
&& !strings.hasprefix(baseenv[ei],
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
"WW_NAME_REAL_COMPILER=")
|
"WW_NAME_REAL_COMPILER=")) {
|
||||||
&& !strings.hasprefix(baseenv[ei],
|
|
||||||
"WW_COMMIT_BLOCK_STAMP=")) {
|
|
||||||
append(env, baseenv[ei]);
|
append(env, baseenv[ei]);
|
||||||
};
|
};
|
||||||
ei += 1;
|
ei += 1;
|
||||||
@@ -8168,11 +8237,10 @@ fn runtimepath(relative: str) str = {
|
|||||||
(30i64 * (time.second: i64)): time.duration, &out);
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 42);
|
expectexit(&out, 42);
|
||||||
|
|
||||||
// A failed multi-file artifact rename may have published a new
|
// The package and command form one publication transaction. A changed
|
||||||
// interface before a later rename fails. It invalidates every old unit
|
// declared name is visible to the importer through the staged .wwi, but
|
||||||
// voucher and the workdir identity, so the next request must reconsider
|
// its resulting semantic rejection must preserve the complete prior
|
||||||
// an importer even when the regenerated dependency export now compares
|
// generation and force the next request to reconsider both actions.
|
||||||
// equal to that partially published interface.
|
|
||||||
let commitcoldav: []str = [driver(stages[si]), "build", "-w",
|
let commitcoldav: []str = [driver(stages[si]), "build", "-w",
|
||||||
commitworks[si], "-I", source, "-o", commitcoldbins[si], commitapp];
|
commitworks[si], "-I", source, "-o", commitcoldbins[si], commitapp];
|
||||||
runcommandenv(root, strings.concat("name-commit-cold-", stages[si]),
|
runcommandenv(root, strings.concat("name-commit-cold-", stages[si]),
|
||||||
@@ -8182,96 +8250,72 @@ fn runtimepath(relative: str) str = {
|
|||||||
runcommand(root, strings.concat("name-commit-cold-run-", stages[si]),
|
runcommand(root, strings.concat("name-commit-cold-run-", stages[si]),
|
||||||
commitrun, (30i64 * (time.second: i64)): time.duration, &out);
|
commitrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 42);
|
expectexit(&out, 42);
|
||||||
|
let commitpaths: []str = ["/.wwtool.ww", "/.wwtool.w6c",
|
||||||
|
"/.wwtool.w6a", "/.wwtool.stamp", "/commit.codec.unit.ww",
|
||||||
|
"/commit.codec.wwi", "/commit.codec.s", "/commit.codec.o",
|
||||||
|
"/commit.codec.a", "/cmd.commit.unit.ww", "/cmd.commit.wwi",
|
||||||
|
"/cmd.commit.s", "/cmd.commit.o", "/cmd.commit.a",
|
||||||
|
"/cmd.commit.init.unit.ww", "/cmd.commit.init.s",
|
||||||
|
"/cmd.commit.init.o"];
|
||||||
|
let commitsnapshots: []str = alloc([], commitpaths.len: u64)!;
|
||||||
|
let cpi: i32 = 0;
|
||||||
|
for (cpi < commitpaths.len) {
|
||||||
|
append(commitsnapshots, readfile(strings.concat(commitworks[si],
|
||||||
|
commitpaths[cpi])));
|
||||||
|
cpi += 1;
|
||||||
|
};
|
||||||
|
let commitcoldbytes: str = readfile(commitcoldbins[si]);
|
||||||
rewritefile(commitcodecfile, cablebody);
|
rewritefile(commitcodecfile, cablebody);
|
||||||
let commitstamp: str = strings.concat(commitworks[si],
|
|
||||||
"/.wwtool.stamp");
|
|
||||||
let savedstamp: str = strings.concat(commitstamp, ".saved");
|
|
||||||
let oldcommitwwi: str = readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.wwi"));
|
|
||||||
let oldcommits: str = readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.s"));
|
|
||||||
let oldcommito: str = readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.o"));
|
|
||||||
let oldcommita: str = readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.a"));
|
|
||||||
let blockenv: []str = alloc([], (env.len + 1): u64)!;
|
|
||||||
let bei: i32 = 0;
|
|
||||||
for (bei < env.len) { append(blockenv, env[bei]); bei += 1; };
|
|
||||||
append(blockenv, strings.concat("WW_COMMIT_BLOCK_STAMP=", commitstamp));
|
|
||||||
let commitblockav: []str = [driver(stages[si]), "build", "-w",
|
|
||||||
commitworks[si], "-I", source, "-o", commitblockbins[si],
|
|
||||||
commitapp];
|
|
||||||
runcommandenv(root, strings.concat("name-commit-preflight-", stages[si]),
|
|
||||||
commitblockav, blockenv,
|
|
||||||
(120i64 * (time.second: i64)): time.duration, &out);
|
|
||||||
expectexit(&out, 1);
|
|
||||||
assert(has(out.stderr, "ww: cannot invalidate package workdir\n"));
|
|
||||||
if (si == 0) { commitpreflightref = strings.dup(out.stderr); }
|
|
||||||
else { assert(same(commitpreflightref, out.stderr)); };
|
|
||||||
assert(same(oldcommitwwi, readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.wwi"))));
|
|
||||||
assert(same(oldcommits, readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.s"))));
|
|
||||||
assert(same(oldcommito, readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.o"))));
|
|
||||||
assert(same(oldcommita, readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.a"))));
|
|
||||||
assert(!os.exists(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.unit.ww")));
|
|
||||||
assert(!os.exists(commitblockbins[si]));
|
|
||||||
assert(os.rmdir(commitstamp) == 0);
|
|
||||||
assert(os.rename(savedstamp, commitstamp) == 0);
|
|
||||||
|
|
||||||
// With the stamp preflight restored, force a later artifact rename to
|
|
||||||
// fail after the changed interface has already been published.
|
|
||||||
let blockedasm: str = strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.s");
|
|
||||||
assert(os.remove(blockedasm) == 0);
|
|
||||||
assert(os.mkdir(blockedasm, 448i32) == 0);
|
|
||||||
let commitrejectav: []str = [driver(stages[si]), "build", "-w",
|
let commitrejectav: []str = [driver(stages[si]), "build", "-w",
|
||||||
commitworks[si], "-I", source, "-o", commitrejectbins[si],
|
commitworks[si], "-I", source, "-o", commitrejectbins[si],
|
||||||
commitapp];
|
commitapp];
|
||||||
runcommandenv(root, strings.concat("name-commit-partial-", stages[si]),
|
|
||||||
commitrejectav, env,
|
|
||||||
(120i64 * (time.second: i64)): time.duration, &out);
|
|
||||||
expectexit(&out, 1);
|
|
||||||
assert(has(out.stderr, "ww: cannot commit commit.codec\n"));
|
|
||||||
if (si == 0) { commitfailref = strings.dup(out.stderr); }
|
|
||||||
else { assert(same(commitfailref, out.stderr)); };
|
|
||||||
assert(has(readfile(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.wwi")),
|
|
||||||
"//ww:module commit.codec\npackage cable;\n"));
|
|
||||||
assert(!os.exists(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.unit.ww")));
|
|
||||||
assert(!os.exists(strings.concat(commitworks[si],
|
|
||||||
"/cmd.commit.unit.ww")));
|
|
||||||
assert(!os.exists(strings.concat(commitworks[si], "/.wwtool.stamp")));
|
|
||||||
let partialsuffixes: []str = [".unit.new", ".wwi.new", ".s.new",
|
let partialsuffixes: []str = [".unit.new", ".wwi.new", ".s.new",
|
||||||
".o.new", ".a.new"];
|
".o.new", ".a.new", ".init.unit.new", ".init.s.new",
|
||||||
let psi: i32 = 0;
|
".init.o.new"];
|
||||||
for (psi < partialsuffixes.len) {
|
let rejectedactions: []str = ["commit.codec", "cmd.commit"];
|
||||||
assert(!os.exists(strings.concat(commitworks[si],
|
let attemptlabels: []str = ["0", "1"];
|
||||||
"/commit.codec", partialsuffixes[psi])));
|
let attempt: i32 = 0;
|
||||||
psi += 1;
|
for (attempt < 2) {
|
||||||
|
rewritefile(traces[si], "");
|
||||||
|
runcommandenv(root, strings.concat("name-commit-reject-",
|
||||||
|
stages[si], "-", attemptlabels[attempt]),
|
||||||
|
commitrejectav, env,
|
||||||
|
(120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stderr, "imported as cable and not used"));
|
||||||
|
assert(has(out.stderr, "undefined: wire"));
|
||||||
|
assert(has(out.stderr, "ww: w6c failed for cmd.commit\n"));
|
||||||
|
let ncommitbinding: str = normalizedtrace(out.stderr,
|
||||||
|
strings.concat(commitworks[si], "/"), commitrejectbins[si]);
|
||||||
|
if (si == 0 && attempt == 0) {
|
||||||
|
commitbindingref = strings.dup(ncommitbinding);
|
||||||
|
} else { assert(same(commitbindingref, ncommitbinding)); };
|
||||||
|
let rejecttrace: str = readfile(traces[si]);
|
||||||
|
assert(occurrences(rejecttrace,
|
||||||
|
"/commit.codec.unit.new") == 1);
|
||||||
|
assert(occurrences(rejecttrace,
|
||||||
|
"/cmd.commit.unit.new") == 1);
|
||||||
|
cpi = 0;
|
||||||
|
for (cpi < commitpaths.len) {
|
||||||
|
assert(same(commitsnapshots[cpi], readfile(strings.concat(
|
||||||
|
commitworks[si], commitpaths[cpi]))));
|
||||||
|
cpi += 1;
|
||||||
|
};
|
||||||
|
assert(same(commitcoldbytes, readfile(commitcoldbins[si])));
|
||||||
|
let rai: i32 = 0;
|
||||||
|
for (rai < rejectedactions.len) {
|
||||||
|
let psi: i32 = 0;
|
||||||
|
for (psi < partialsuffixes.len) {
|
||||||
|
assert(!os.exists(strings.concat(commitworks[si], "/",
|
||||||
|
rejectedactions[rai], partialsuffixes[psi])));
|
||||||
|
psi += 1;
|
||||||
|
};
|
||||||
|
rai += 1;
|
||||||
|
};
|
||||||
|
assert(!os.exists(commitrejectbins[si]));
|
||||||
|
assert(!os.exists(strings.concat(commitrejectbins[si], ".new")));
|
||||||
|
attempt += 1;
|
||||||
};
|
};
|
||||||
assert(!os.exists(commitrejectbins[si]));
|
|
||||||
assert(os.rmdir(blockedasm) == 0);
|
|
||||||
rewritefile(traces[si], "");
|
|
||||||
runcommandenv(root, strings.concat("name-commit-reconsider-", stages[si]),
|
|
||||||
commitrejectav, env,
|
|
||||||
(120i64 * (time.second: i64)): time.duration, &out);
|
|
||||||
expectexit(&out, 1);
|
|
||||||
assert(has(out.stderr, "undefined: wire"));
|
|
||||||
let ncommitbinding: str = normalizedtrace(out.stderr,
|
|
||||||
strings.concat(commitworks[si], "/"), commitrejectbins[si]);
|
|
||||||
if (si == 0) { commitbindingref = strings.dup(ncommitbinding); }
|
|
||||||
else { assert(same(commitbindingref, ncommitbinding)); };
|
|
||||||
assert(has(readfile(traces[si]), "/cmd.commit.unit.new"));
|
|
||||||
assert(os.exists(strings.concat(commitworks[si],
|
|
||||||
"/commit.codec.unit.ww")));
|
|
||||||
assert(!os.exists(strings.concat(commitworks[si],
|
|
||||||
"/cmd.commit.unit.ww")));
|
|
||||||
assert(!os.exists(commitrejectbins[si]));
|
|
||||||
rewritefile(commitappfile, strings.concat(
|
rewritefile(commitappfile, strings.concat(
|
||||||
"package main;\nimport commit.codec;\n",
|
"package main;\nimport commit.codec;\n",
|
||||||
"fn main() i32 = { return cable.value(); };\n"));
|
"fn main() i32 = { return cable.value(); };\n"));
|
||||||
@@ -8285,6 +8329,10 @@ fn runtimepath(relative: str) str = {
|
|||||||
runcommand(root, strings.concat("name-commit-fixed-run-", stages[si]),
|
runcommand(root, strings.concat("name-commit-fixed-run-", stages[si]),
|
||||||
commitfixedrun, (30i64 * (time.second: i64)): time.duration, &out);
|
commitfixedrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||||
expectexit(&out, 42);
|
expectexit(&out, 42);
|
||||||
|
assert(has(readfile(strings.concat(commitworks[si],
|
||||||
|
"/commit.codec.wwi")),
|
||||||
|
"//ww:module commit.codec\npackage cable;\n"));
|
||||||
|
assert(same(commitcoldbytes, readfile(commitcoldbins[si])));
|
||||||
let commitbinbytes: str = readfile(commitfixedbins[si]);
|
let commitbinbytes: str = readfile(commitfixedbins[si]);
|
||||||
if (si == 0) { commitbinref = strings.dup(commitbinbytes); }
|
if (si == 0) { commitbinref = strings.dup(commitbinbytes); }
|
||||||
else { assert(same(commitbinref, commitbinbytes)); };
|
else { assert(same(commitbinref, commitbinbytes)); };
|
||||||
@@ -8614,10 +8662,12 @@ fn runtimepath(relative: str) str = {
|
|||||||
let one: str = strings.concat(source, "/pkg/one");
|
let one: str = strings.concat(source, "/pkg/one");
|
||||||
let two: str = strings.concat(source, "/pkg/two");
|
let two: str = strings.concat(source, "/pkg/two");
|
||||||
let positives: []str = ["default", "alias", "reuse", "repeatok",
|
let positives: []str = ["default", "alias", "reuse", "repeatok",
|
||||||
"repeatedfiles"];
|
"repeatedfiles", "blankalias", "blankrepeat", "blankdefault",
|
||||||
|
"blankexplicit", "blankfiles"];
|
||||||
let negatives: []str = ["barefn", "baretype", "baredef", "bareconst",
|
let negatives: []str = ["barefn", "baretype", "baredef", "bareconst",
|
||||||
"barevar", "aliasbad", "aliasleak", "repeatdup", "aliasdup",
|
"barevar", "aliasbad", "aliasleak", "repeatdup", "aliasdup",
|
||||||
"defaultalias", "declcollision", "unusedalias", "blankalias"];
|
"defaultalias", "declcollision", "unusedalias", "blankqual",
|
||||||
|
"blankbare", "blankordinaryunused"];
|
||||||
let dirs: []str = [one, two];
|
let dirs: []str = [one, two];
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < positives.len) {
|
for (i < positives.len) {
|
||||||
@@ -8673,6 +8723,24 @@ fn runtimepath(relative: str) str = {
|
|||||||
"fn second() i32 = { return right.value(); };\n"));
|
"fn second() i32 = { return right.value(); };\n"));
|
||||||
writefile(strings.concat(source, "/cmd/repeatedfiles/main.ww"),
|
writefile(strings.concat(source, "/cmd/repeatedfiles/main.ww"),
|
||||||
"package main;\nfn main() i32 = { return first() + second(); };\n");
|
"package main;\nfn main() i32 = { return first() + second(); };\n");
|
||||||
|
writefile(strings.concat(source, "/cmd/blankalias/main.ww"),
|
||||||
|
"package main;\nimport _ pkg.one;\nfn main() i32 = { return 0; };\n");
|
||||||
|
writefile(strings.concat(source, "/cmd/blankrepeat/main.ww"),
|
||||||
|
strings.concat("package main;\nimport _ pkg.one;\n",
|
||||||
|
"import _ pkg.one;\nfn main() i32 = { return 0; };\n"));
|
||||||
|
writefile(strings.concat(source, "/cmd/blankdefault/main.ww"),
|
||||||
|
strings.concat("package main;\nimport _ pkg.one;\nimport pkg.one;\n",
|
||||||
|
"fn main() i32 = { return wire.value(); };\n"));
|
||||||
|
writefile(strings.concat(source, "/cmd/blankexplicit/main.ww"),
|
||||||
|
strings.concat("package main;\nimport _ pkg.one;\n",
|
||||||
|
"import stable pkg.one;\n",
|
||||||
|
"fn main() i32 = { return stable.value(); };\n"));
|
||||||
|
writefile(strings.concat(source, "/cmd/blankfiles/a.ww"),
|
||||||
|
"package main;\nimport _ pkg.one;\n");
|
||||||
|
writefile(strings.concat(source, "/cmd/blankfiles/b.ww"),
|
||||||
|
"package main;\nimport _ pkg.one;\n");
|
||||||
|
writefile(strings.concat(source, "/cmd/blankfiles/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return 0; };\n");
|
||||||
|
|
||||||
let bareexprs: []str = ["value()", "take(7)", "DEFINED", "CONSTANT",
|
let bareexprs: []str = ["value()", "take(7)", "DEFINED", "CONSTANT",
|
||||||
"VARIABLE"];
|
"VARIABLE"];
|
||||||
@@ -8716,22 +8784,29 @@ fn runtimepath(relative: str) str = {
|
|||||||
"fn main() i32 = { return stable(); };\n"));
|
"fn main() i32 = { return stable(); };\n"));
|
||||||
writefile(strings.concat(source, "/cmd/unusedalias/main.ww"),
|
writefile(strings.concat(source, "/cmd/unusedalias/main.ww"),
|
||||||
"package main;\nimport stable pkg.one;\nfn main() i32 = { return 0; };\n");
|
"package main;\nimport stable pkg.one;\nfn main() i32 = { return 0; };\n");
|
||||||
writefile(strings.concat(source, "/cmd/blankalias/main.ww"),
|
writefile(strings.concat(source, "/cmd/blankqual/main.ww"),
|
||||||
"package main;\nimport _ pkg.one;\nfn main() i32 = { return 0; };\n");
|
strings.concat("package main;\nimport _ pkg.one;\n",
|
||||||
|
"fn main() i32 = { return wire.value(); };\n"));
|
||||||
|
writefile(strings.concat(source, "/cmd/blankbare/main.ww"),
|
||||||
|
strings.concat("package main;\nimport _ pkg.one;\n",
|
||||||
|
"fn main() i32 = { return value(); };\n"));
|
||||||
|
writefile(strings.concat(source, "/cmd/blankordinaryunused/main.ww"),
|
||||||
|
strings.concat("package main;\nimport _ pkg.one;\nimport pkg.one;\n",
|
||||||
|
"fn main() i32 = { return 0; };\n"));
|
||||||
|
|
||||||
let stages: []str = ["ww", "ww_ww"];
|
let stages: []str = ["ww", "ww_ww"];
|
||||||
let expected: []i32 = [83, 83, 40, 33, 22];
|
let expected: []i32 = [83, 83, 40, 33, 22, 0, 0, 11, 11, 0];
|
||||||
let binaryrefs: []str = ["", "", "", "", ""];
|
let binaryrefs: []str = ["", "", "", "", "", "", "", "", "", ""];
|
||||||
let diagrefs: []str = ["", "", "", "", "", "", "", "", "",
|
let diagrefs: []str = ["", "", "", "", "", "", "", "", "",
|
||||||
"", "", "", ""];
|
"", "", "", "", "", ""];
|
||||||
let needles: []str = ["undefined: value", "unknown type 'Thing'",
|
let needles: []str = ["undefined: value", "unknown type 'Thing'",
|
||||||
"undefined: DEFINED", "undefined: CONSTANT", "undefined: VARIABLE",
|
"undefined: DEFINED", "undefined: CONSTANT", "undefined: VARIABLE",
|
||||||
"unknown type 'wire.Thing'", "package 'stable' is not directly imported",
|
"unknown type 'wire.Thing'", "package 'stable' is not directly imported",
|
||||||
"wire redeclared in this block", "stable redeclared in this block",
|
"wire redeclared in this block", "stable redeclared in this block",
|
||||||
"wire redeclared in this block",
|
"wire redeclared in this block",
|
||||||
"stable already declared through import of package stable",
|
"stable already declared through import of package stable",
|
||||||
"\"pkg.one\" imported as stable and not used",
|
"\"pkg.one\" imported as stable and not used", "undefined: wire",
|
||||||
"blank import alias _ is not implemented"];
|
"undefined: value", "\"pkg.one\" imported as wire and not used"];
|
||||||
let exactdiags: []str = [
|
let exactdiags: []str = [
|
||||||
strings.concat(
|
strings.concat(
|
||||||
"$WORK/cmd.barefn.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n",
|
"$WORK/cmd.barefn.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n",
|
||||||
@@ -8777,8 +8852,7 @@ fn runtimepath(relative: str) str = {
|
|||||||
strings.concat(
|
strings.concat(
|
||||||
"$WORK/cmd.unusedalias.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n",
|
"$WORK/cmd.unusedalias.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n",
|
||||||
"ww: w6c failed for cmd.unusedalias\n"),
|
"ww: w6c failed for cmd.unusedalias\n"),
|
||||||
strings.concat(source,
|
"", "", "",
|
||||||
"/cmd/blankalias/main.ww:2:8: error: blank import alias _ is not implemented\n"),
|
|
||||||
];
|
];
|
||||||
let si: i32 = 0;
|
let si: i32 = 0;
|
||||||
for (si < stages.len) {
|
for (si < stages.len) {
|
||||||
@@ -8820,6 +8894,26 @@ fn runtimepath(relative: str) str = {
|
|||||||
let repeatedunit: str = readfile(strings.concat(work,
|
let repeatedunit: str = readfile(strings.concat(work,
|
||||||
"/cmd.repeatedfiles.unit.ww"));
|
"/cmd.repeatedfiles.unit.ww"));
|
||||||
assert(occurrences(repeatedunit, "pkg.one;") == 2);
|
assert(occurrences(repeatedunit, "pkg.one;") == 2);
|
||||||
|
let blankunit: str = readfile(strings.concat(work,
|
||||||
|
"/cmd.blankalias.unit.ww"));
|
||||||
|
assert(has(blankunit, "import _ pkg.one;"));
|
||||||
|
let blankwwi: str = readfile(strings.concat(work,
|
||||||
|
"/cmd.blankalias.wwi"));
|
||||||
|
assert(!has(blankwwi, "import _") && !has(blankwwi, "__ww.."));
|
||||||
|
let blankrepeat: str = readfile(strings.concat(work,
|
||||||
|
"/cmd.blankrepeat.unit.ww"));
|
||||||
|
assert(occurrences(blankrepeat, "import _ pkg.one;") == 2);
|
||||||
|
assert(occurrences(blankrepeat,
|
||||||
|
"//ww:direct-export pkg.one ") == 1);
|
||||||
|
let blankfiles: str = readfile(strings.concat(work,
|
||||||
|
"/cmd.blankfiles.unit.ww"));
|
||||||
|
assert(occurrences(blankfiles, "import _ pkg.one;") == 2);
|
||||||
|
assert(occurrences(blankfiles,
|
||||||
|
"//ww:direct-export pkg.one ") == 1);
|
||||||
|
let blankdispatch: str = readfile(strings.concat(work,
|
||||||
|
"/cmd.blankdefault.init.unit.ww"));
|
||||||
|
assert(occurrences(blankdispatch,
|
||||||
|
"//ww:init-call __ww..pkg.p.pkg.one.v0.r0.init") == 1);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < negatives.len) {
|
for (i < negatives.len) {
|
||||||
|
|||||||
36
test/sep/limitexec.c
Normal file
36
test/sep/limitexec.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* Test-only deterministic launcher for allocation-failure observers. Keeping
|
||||||
|
* setrlimit in a repository-built helper avoids depending on util-linux paths
|
||||||
|
* or shell-specific ulimit syntax. */
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 3) {
|
||||||
|
fputs("usage: sep-limitexec bytes program [arg ...]\n", stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
|
char *end = NULL;
|
||||||
|
unsigned long long value = strtoull(argv[1], &end, 10);
|
||||||
|
if (errno != 0 || end == argv[1] || *end != '\0') {
|
||||||
|
fputs("sep-limitexec: invalid limit\n", stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
struct rlimit limit;
|
||||||
|
limit.rlim_cur = (rlim_t)value;
|
||||||
|
limit.rlim_max = (rlim_t)value;
|
||||||
|
if (setrlimit(RLIMIT_AS, &limit) != 0) {
|
||||||
|
fputs("sep-limitexec: setrlimit failed\n", stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
execv(argv[2], &argv[2]);
|
||||||
|
fputs("sep-limitexec: exec failed\n", stderr);
|
||||||
|
return 127;
|
||||||
|
}
|
||||||
1421
test/sep/sepinit_test.ww
Normal file
1421
test/sep/sepinit_test.ww
Normal file
File diff suppressed because it is too large
Load Diff
@@ -140,6 +140,7 @@ main(void)
|
|||||||
"import io;",
|
"import io;",
|
||||||
"import io.bufio;",
|
"import io.bufio;",
|
||||||
"import stable io.bufio;",
|
"import stable io.bufio;",
|
||||||
|
"import _ io.bufio;",
|
||||||
"def MAX: i32 = 4096;",
|
"def MAX: i32 = 4096;",
|
||||||
"export def MAX: i32 = 4096;",
|
"export def MAX: i32 = 4096;",
|
||||||
"type point = struct { x: i32, y: i32 };",
|
"type point = struct { x: i32, y: i32 };",
|
||||||
@@ -149,6 +150,7 @@ main(void)
|
|||||||
"type arr = [16]u8;",
|
"type arr = [16]u8;",
|
||||||
|
|
||||||
"fn nop() void = {};",
|
"fn nop() void = {};",
|
||||||
|
"fn init() void = {}; fn init() void = {};",
|
||||||
"export fn id(x: i32) i32 = { return x; };",
|
"export fn id(x: i32) i32 = { return x; };",
|
||||||
"fn add(a: i32, b: i32) i32 = { return a + b; };",
|
"fn add(a: i32, b: i32) i32 = { return a + b; };",
|
||||||
"@symbol(\"malloc\") fn cmalloc(n: u64) *void;",
|
"@symbol(\"malloc\") fn cmalloc(n: u64) *void;",
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ struct row { const char *src, *expect; };
|
|||||||
|
|
||||||
static const struct row rows[] = {
|
static const struct row rows[] = {
|
||||||
{ "fn main() void = {};", "ok" },
|
{ "fn main() void = {};", "ok" },
|
||||||
|
{ "fn init() void = {}; fn init() void = {};", "ok" },
|
||||||
|
{ "fn init(x: i32) void = {};", "func init must have no arguments and no return values" },
|
||||||
|
{ "fn init() i32 = { return 1; };", "func init must have no arguments and no return values" },
|
||||||
|
{ "fn init() void;", "func init must have a body" },
|
||||||
|
{ "export fn init() void = {};", "func init cannot be exported" },
|
||||||
|
{ "fn init() void = {}; fn f() void = { init(); };", "undefined: init" },
|
||||||
|
{ "fn make() i32 = { return 7; }; let state: i32 = make();", "ok" },
|
||||||
|
{ "fn left() i32 = { return right; }; let first: i32 = left(); let right: i32 = 3;", "ok" },
|
||||||
|
{ "fn readb() i32 = { return b; }; let a: i32 = readb(); let b: i32 = a;", "initialization cycle for a" },
|
||||||
{ "fn id(x: i32) i32 = { return x; };", "ok" },
|
{ "fn id(x: i32) i32 = { return x; };", "ok" },
|
||||||
{ "fn add(a: i32, b: i32) i32 = { return a + b; };", "ok" },
|
{ "fn add(a: i32, b: i32) i32 = { return a + b; };", "ok" },
|
||||||
{ "def MAX: i32 = 4096;", "ok" },
|
{ "def MAX: i32 = 4096;", "ok" },
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
//ww:run-exit 42
|
//ww:run-exit 42
|
||||||
package main;
|
package main;
|
||||||
type bs = struct { rbuf: []u8, mark: i32 };
|
type bs = struct { rbuf: []u8, mark: i32 };
|
||||||
fn init(b: *bs, rbuf: []u8) void = { b.rbuf = rbuf; b.mark = 9; };
|
fn setup(b: *bs, rbuf: []u8) void = { b.rbuf = rbuf; b.mark = 9; };
|
||||||
fn main() i32 = {
|
fn main() i32 = {
|
||||||
let raw: [8]u8; raw[0] = 0u8; let b: bs; init(&b, raw[0:5]);
|
let raw: [8]u8; raw[0] = 0u8; let b: bs; setup(&b, raw[0:5]);
|
||||||
if (b.rbuf.len != 5) { return 1; }; if (b.rbuf.cap != 8) { return 2; };
|
if (b.rbuf.len != 5) { return 1; }; if (b.rbuf.cap != 8) { return 2; };
|
||||||
if (b.mark != 9) { return 3; }; return 42;
|
if (b.mark != 9) { return 3; }; return 42;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export fn main() i32 = {
|
|||||||
if (sel == 0) { src = &mstB.vt; };
|
if (sel == 0) { src = &mstB.vt; };
|
||||||
let rbuf: [4]u8;
|
let rbuf: [4]u8;
|
||||||
let wbuf: [4]u8;
|
let wbuf: [4]u8;
|
||||||
let bc: bufio.stream = bufio.init(src, rbuf[0:4], wbuf[0:4]);
|
let bc: bufio.stream = bufio.newstream(src, rbuf[0:4], wbuf[0:4]);
|
||||||
let vs: io.stream = &bc.vt;
|
let vs: io.stream = &bc.vt;
|
||||||
let out: [4]u8;
|
let out: [4]u8;
|
||||||
let rd = io.read(vs, out[0:4]);
|
let rd = io.read(vs, out[0:4]);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export fn main() i32 = {
|
|||||||
let msrc: io.stream = &mst.vt;
|
let msrc: io.stream = &mst.vt;
|
||||||
let rbuf: [4]u8;
|
let rbuf: [4]u8;
|
||||||
let wbuf: [4]u8;
|
let wbuf: [4]u8;
|
||||||
let bc: bufio.stream = bufio.init(msrc, rbuf[0:4], wbuf[0:4]);
|
let bc: bufio.stream = bufio.newstream(msrc, rbuf[0:4], wbuf[0:4]);
|
||||||
let vs: io.stream = &bc.vt;
|
let vs: io.stream = &bc.vt;
|
||||||
if (!bufio.isbuffered(vs)) { return 91; };
|
if (!bufio.isbuffered(vs)) { return 91; };
|
||||||
if (bufio.isbuffered(msrc)) { return 92; };
|
if (bufio.isbuffered(msrc)) { return 92; };
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export fn main() i32 = {
|
|||||||
let msrc: io.stream = &mst.vt;
|
let msrc: io.stream = &mst.vt;
|
||||||
let rbuf: [4]u8;
|
let rbuf: [4]u8;
|
||||||
let wbuf: [4]u8;
|
let wbuf: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(msrc, rbuf[0:4], wbuf[0:4]);
|
let b: bufio.stream = bufio.newstream(msrc, rbuf[0:4], wbuf[0:4]);
|
||||||
let vsbuf: io.stream = &b.vt;
|
let vsbuf: io.stream = &b.vt;
|
||||||
let buf2: [4]u8;
|
let buf2: [4]u8;
|
||||||
let st2: memio.stream = memio.fixed(buf2[0:4]);
|
let st2: memio.stream = memio.fixed(buf2[0:4]);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export fn main() i32 = {
|
|||||||
let msrc: io.stream = &mst.vt;
|
let msrc: io.stream = &mst.vt;
|
||||||
let rbuf: [8]u8;
|
let rbuf: [8]u8;
|
||||||
let wbuf: [4]u8;
|
let wbuf: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(msrc, rbuf[0:8], wbuf[0:4]);
|
let b: bufio.stream = bufio.newstream(msrc, rbuf[0:8], wbuf[0:4]);
|
||||||
let vs: io.stream = &b.vt;
|
let vs: io.stream = &b.vt;
|
||||||
let out: [4]u8;
|
let out: [4]u8;
|
||||||
let rd1 = io.read(vs, out[0:3]);
|
let rd1 = io.read(vs, out[0:3]);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export fn main() i32 = {
|
|||||||
let sinkvs: io.stream = &sink.vt;
|
let sinkvs: io.stream = &sink.vt;
|
||||||
let rb: [4]u8;
|
let rb: [4]u8;
|
||||||
let wb: [8]u8;
|
let wb: [8]u8;
|
||||||
let b: bufio.stream = bufio.init(sinkvs, rb[0:4], wb[0:8]);
|
let b: bufio.stream = bufio.newstream(sinkvs, rb[0:4], wb[0:8]);
|
||||||
let bvs: io.stream = &b.vt;
|
let bvs: io.stream = &b.vt;
|
||||||
let semi: [1]u8;
|
let semi: [1]u8;
|
||||||
semi[0] = 59u8;
|
semi[0] = 59u8;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export fn main() i32 = {
|
|||||||
let vs: io.stream = &mst.vt;
|
let vs: io.stream = &mst.vt;
|
||||||
let rbuf: [4]u8;
|
let rbuf: [4]u8;
|
||||||
let wbuf: [4]u8;
|
let wbuf: [4]u8;
|
||||||
let b: bufio.stream = bufio.init(vs, rbuf[0:4], wbuf[0:4]);
|
let b: bufio.stream = bufio.newstream(vs, rbuf[0:4], wbuf[0:4]);
|
||||||
let bvs: io.stream = &b.vt;
|
let bvs: io.stream = &b.vt;
|
||||||
let out: [4]u8;
|
let out: [4]u8;
|
||||||
let rd = io.read(bvs, out[0:3]);
|
let rd = io.read(bvs, out[0:3]);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export fn main() i32 = {
|
|||||||
let msrc: io.stream = &mst.vt;
|
let msrc: io.stream = &mst.vt;
|
||||||
let rbuf: [8]u8;
|
let rbuf: [8]u8;
|
||||||
let wbuf: [8]u8;
|
let wbuf: [8]u8;
|
||||||
let b: bufio.stream = bufio.init(msrc, rbuf[0:8], wbuf[0:8]);
|
let b: bufio.stream = bufio.newstream(msrc, rbuf[0:8], wbuf[0:8]);
|
||||||
let vs: io.stream = &b.vt;
|
let vs: io.stream = &b.vt;
|
||||||
let payload: [5]u8;
|
let payload: [5]u8;
|
||||||
payload[0] = 104u8; payload[1] = 105u8;
|
payload[0] = 104u8; payload[1] = 105u8;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
package main;
|
package main;
|
||||||
import math.random;
|
import math.random;
|
||||||
export fn main() int = {
|
export fn main() int = {
|
||||||
let g: random.random = random.init(1u64);
|
let g: random.random = random.fromseed(1u64);
|
||||||
let x: u32 = random.u32n(&g, 1u32);
|
let x: u32 = random.u32n(&g, 1u32);
|
||||||
if (x >= 1u32) { return 1; };
|
if (x >= 1u32) { return 1; };
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
package main;
|
package main;
|
||||||
import math.random;
|
import math.random;
|
||||||
export fn main() int = {
|
export fn main() int = {
|
||||||
let g: random.random = random.init(1u64);
|
let g: random.random = random.fromseed(1u64);
|
||||||
let x: u32 = random.u32n(&g, 10u32);
|
let x: u32 = random.u32n(&g, 10u32);
|
||||||
if (x >= 10u32) { return 1; };
|
if (x >= 10u32) { return 1; };
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
package main;
|
package main;
|
||||||
import math.random;
|
import math.random;
|
||||||
export fn main() int = {
|
export fn main() int = {
|
||||||
let g: random.random = random.init(1u64);
|
let g: random.random = random.fromseed(1u64);
|
||||||
let x: u64 = random.u64n(&g, 1u64);
|
let x: u64 = random.u64n(&g, 1u64);
|
||||||
if (x >= 1u64) { return 1; };
|
if (x >= 1u64) { return 1; };
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
package main;
|
package main;
|
||||||
import math.random;
|
import math.random;
|
||||||
export fn main() int = {
|
export fn main() int = {
|
||||||
let g: random.random = random.init(1u64);
|
let g: random.random = random.fromseed(1u64);
|
||||||
let x: u64 = random.u64n(&g, 10u64);
|
let x: u64 = random.u64n(&g, 10u64);
|
||||||
if (x >= 10u64) { return 1; };
|
if (x >= 10u64) { return 1; };
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user