ww source: align UTF-8 BOM placement
This commit is contained in:
@@ -8427,6 +8427,124 @@ Rejected source creates no persisted byte contract, while valid source bytes
|
||||
are unchanged. Build workdir format remains `18`, test workdir format remains
|
||||
`19`, and semantic storage format remains `3`.
|
||||
|
||||
### 11.42 Implemented per-source UTF-8 BOM placement
|
||||
|
||||
Every eligible physical WW source may begin with one UTF-8-encoded U+FEFF byte
|
||||
order mark (`EF BB BF`). That marker is ignored, and the following token keeps
|
||||
its three-byte source position at line 1, column 4. U+FEFF at any later raw
|
||||
source position is
|
||||
rejected once as `invalid BOM in the middle of the file`, including inside a
|
||||
line/block comment, string, or rune. Two leading markers therefore ignore the
|
||||
first and reject the second. A truncated marker or another invalid UTF-8 byte
|
||||
sequence retains the ordinary byte-error path; UTF-16 source is not introduced.
|
||||
|
||||
#### Pinned Go evidence and applicability
|
||||
|
||||
The sole authority is official Go 1.26.5 at commit
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- compiler reader `(*source).nextch` decodes UTF-8, skips U+FEFF at its first
|
||||
source position, and reports `invalid BOM in the middle of the file`
|
||||
elsewhere
|
||||
([`cmd/compile/internal/syntax/source.go`, lines 113–165](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/source.go#L113-L165));
|
||||
- public scanner `(*Scanner).next` rejects later U+FEFF and `(*Scanner).Init`
|
||||
consumes the first one
|
||||
([`go/scanner/scanner.go`, lines 58–100 and 128–164](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner.go#L58-L164));
|
||||
- scanner tests assert the ignored first marker and later markers between
|
||||
tokens, in comments, runes, and strings
|
||||
([`go/scanner/scanner_test.go`, lines 371–374 and 812–815](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner_test.go#L371-L374),
|
||||
[`go/scanner/scanner_test.go`, lines 812–815](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner_test.go#L812-L815));
|
||||
- compiler-scanner `TestScanErrors` asserts the positioned later-marker error
|
||||
([`cmd/compile/internal/syntax/scanner_test.go`, lines 587–599](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner_test.go#L587-L599)); and
|
||||
- official command testdata places the marker before `package main` and loads
|
||||
that source's imports and embedded file
|
||||
([`cmd/go/testdata/script/build_ignore_leading_bom.txt`, lines 1–25](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_ignore_leading_bom.txt#L1-L25)).
|
||||
|
||||
Those source branches and assertions are **behavior directly implemented or
|
||||
asserted by pinned Go**. Applying the first position independently to every WW
|
||||
physical source before its existing synthetic aggregate boundary is **behavior
|
||||
derived from the pinned implementation**. The pre-fix Cstage/WWstage failures
|
||||
on leading markers and successes for markers in comments/strings were
|
||||
**directly measured WW behavior**.
|
||||
|
||||
The behavior honestly applies inside WW's local, dotted-import, manifest-free
|
||||
model: it is source representation before package and import interpretation.
|
||||
It requires no module, manifest, registry, lock, cache, database, CAS, network
|
||||
resolution, generalized import syntax, build expression, or normalized
|
||||
identity.
|
||||
|
||||
#### Ownership and four-axis result
|
||||
|
||||
`lexinit`, `lpeek`, `lget`, and `lexnext` in `cmd/wcc/lex.c`, with their twins
|
||||
in `lib/ww/syntax/lex.ww`, are the language owners. They skip the exact initial
|
||||
marker while advancing the logical column by its encoded width, recognize a
|
||||
later marker as one code point in every lexical context, and emit one
|
||||
stage-identical diagnostic.
|
||||
`sep_emit_body` in `cmd/ww/main.c` and `sepemitbody` in
|
||||
`selfhost/cmd/ww/main.ww` replace the optional marker with three spaces in every
|
||||
physical body placed after a synthetic `//ww:module-reset`, preserving columns;
|
||||
direct and imports-only lexer input remains independently correct. The shared package
|
||||
coordinator's `pkgclause` in `internal/wwpackage/package.ww` begins its
|
||||
pre-discovery package-name scan after the same optional marker. It does not
|
||||
replace the complete stage-driver scan.
|
||||
|
||||
- **Go-like build:** a selected command, library, or imported dependency may
|
||||
use the marker in each eligible source. Multiple physical marked sources
|
||||
compose normally, command publication succeeds, and the executable runs
|
||||
normally. A later marker rejects during source loading before graph/action
|
||||
construction or compiler, assembler, archiver, linker, install, or runtime
|
||||
work. A source error keeps precedence over a missing import.
|
||||
- **Go-like test:** production, same-package, external-package, and test-only
|
||||
files each receive the offset-zero allowance. Valid variants build and run
|
||||
through the ordinary single directory product. A later marker yields the
|
||||
existing attributable `FAIL\n` result without a variant, generated main,
|
||||
test process, accounting, or retained binary.
|
||||
- **Go-like package:** package-clause recognition now begins at the pinned
|
||||
logical source start in direct compilers, directory drivers, and the shared
|
||||
coordinator. Declared names, source roles, package conflicts, command/test
|
||||
family selection, and canonical identity do not change.
|
||||
- **Go-like import:** imports following a legal marker and imports in a marked
|
||||
dependency retain their exact source spelling, file scope, qualifier,
|
||||
contextual local/vendor resolution, case-sensitive canonical dotted
|
||||
identity, visibility, cycle, and initialization behavior. The marker never
|
||||
becomes an edge or identity component.
|
||||
|
||||
Fixed-target filename selection remains earlier than parsing: an excluded
|
||||
`_windows.ww` or `_windows_test.ww` contributes no marker diagnostic, package,
|
||||
import, graph, action, artifact, or invalidation state. For valid inputs, graph
|
||||
nodes, scheduling, producer arguments, initialization, runtime, result order,
|
||||
and publication are unchanged. Legal marker bytes become three
|
||||
position-preserving spaces only in the synthetic unit. Adding or removing the
|
||||
marker therefore changes unit content and invalidates source-derived actions,
|
||||
while semantic interface, assembly, object, archive, initializer, and
|
||||
executable content remains the same; every form remains Cstage/WWstage
|
||||
byte-identical.
|
||||
|
||||
Cold rejection leaves no product, work generation, adjacent scratch, capture,
|
||||
`.new`, `.install`, or `.wwtxn.*`. A warm later-marker edit preserves the
|
||||
entire committed generation, tool vouchers, stamp, and public executable.
|
||||
Restoring the exact legal leading form recreates the same unit and reuses committed
|
||||
compiler/assembler/archive work before the normal link/publication boundary.
|
||||
Concurrent valid and invalid requests keep independent lexer/coordinator state,
|
||||
workdirs, captures, diagnostics, and products. Because later-marker rejection
|
||||
occurs before a producer or test child, producer/runtime failure, signals,
|
||||
timeouts, interruption, and process-group cleanup gain no new branch; their
|
||||
existing owners remain authoritative.
|
||||
|
||||
The C lexer unit, WW syntax unit, and WW-native
|
||||
`utf8_bom_is_per_source_and_only_first` observer prove initial position,
|
||||
later-marker lexical contexts, direct frontend diagnostics and assembly,
|
||||
selected/imported multi-source build, wrong-target exclusion, every test source
|
||||
role, test-only execution, syntax-before-resolution precedence, cold cleanup,
|
||||
warm rollback and reuse, concurrent isolation, publication/runtime behavior,
|
||||
and complete stage diagnostic/artifact parity.
|
||||
|
||||
No persisted format changes. Previously valid marker-free bytes are
|
||||
unchanged; previously leading-marked requests could not commit a generation;
|
||||
and diagnostic text is not a persisted-byte contract. Build workdir format
|
||||
remains `18`, test workdir format remains `19`, and semantic storage format
|
||||
remains `3`.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
Five candidates were developed as coherent systems, not as feature bins.
|
||||
|
||||
@@ -52,8 +52,13 @@ classes from §2 (`ident`, `int_lit`, …).
|
||||
|
||||
### 2.1 Source representation
|
||||
|
||||
Source is UTF-8. The lexer operates on bytes; non-ASCII bytes are legal
|
||||
only inside string and rune literals and comments.
|
||||
Source is UTF-8. One UTF-8-encoded byte order mark (U+FEFF, bytes
|
||||
`EF BB BF`) is ignored when it is the first code point of a physical source
|
||||
file. Its three encoded bytes still count in source positions, so a following
|
||||
token on the first line begins at column 4. U+FEFF is invalid at
|
||||
every other source position, including inside string and rune literals and
|
||||
comments. Apart from that marker rule, the lexer operates on bytes and
|
||||
non-ASCII bytes are legal only inside string and rune literals and comments.
|
||||
|
||||
### 2.2 Comments
|
||||
|
||||
|
||||
@@ -415,6 +415,20 @@ generation. The directory command retains its existing attributable final
|
||||
diagnostic. This ordering state is per source and never package, import,
|
||||
variant, action, artifact, publication, or persistence identity.
|
||||
|
||||
Every eligible source also owns an independent source-start position. An exact
|
||||
UTF-8 BOM (`EF BB BF`) at byte offset zero is ignored before package-clause and
|
||||
import parsing, so production, same-package, external-package, and test-only
|
||||
sources all count the marker's three bytes and begin the following token at
|
||||
logical line 1 column 4. The same code point anywhere else,
|
||||
including a comment or literal, is a source error before variant actions,
|
||||
generated main, producers, test runtime, accounting, or retained publication.
|
||||
The shared coordinator applies the offset-zero rule while classifying package
|
||||
clauses; the selected stage driver scans the complete source and preserves the
|
||||
per-file rule while composing package units. Wrong-target files remain excluded
|
||||
before either operation. The marker is source representation only and never
|
||||
package/import/action/artifact/publication/persistence identity; no test result
|
||||
is cached.
|
||||
|
||||
After that eligibility boundary and the coordinator's required package-clause
|
||||
classification and production `@test` validation parses, the delegated loader
|
||||
performs selected-basename Go 1.26.5 simple-fold preflight before its graph
|
||||
|
||||
Reference in New Issue
Block a user