Skip to content
Merged
196 changes: 195 additions & 1 deletion src/v1/stage0/src/namespace_wave_admission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,201 @@ pub struct TransitionAdmission {
/// gunbc#9896 proved both rows consumed at the base. This change touches the roster to teach the
/// wall that ambient kernel identities are resolved, so the roster's own next-touch obligation
/// deletes both receipts. The roster is empty and remains fail-closed for new namespace motion.
pub const NAMESPACE_TRANSITION_ADMISSIONS: &[TransitionAdmission] = &[];
/// ELEVENTH TRANSITION, AND THE FIRST WHOSE SUBJECT IS A REQUALIFICATION RATHER THAN A MOVE
/// (2026-09-01, XL-0T, gunbc#9907). `v2.compiler.tokenize` and `v2.std.compilers.lexing` name the
/// structural text carrier EXPLICITLY where they previously wrote the bare spelling: `String` in
/// those positions resolved to the kernel identity and now resolves to `v2.std.text`, whose
/// `String` is `FreeMonoid<Char>`. No declaration moved and no name was minted -- the destination
/// is written where the module already meant it -- so every one of the seventeen arrives as
/// `TargetChanged binding`, base `{<kernel>}` -> head `{v2.std.text}`.
///
/// THE POPULATION IS EXACTLY SEVENTEEN AND THE RUN SAYS SO. On run 33501228511 the phase reported
/// `modules_compared=4475 modules_added=1 modules_removed=0 closure_rows_moved=0 deltas=17`: one
/// module added (the ingress witness this change enrolls), nothing removed, and no closure motion
/// at all. That is what makes seventeen a population rather than a count -- the denominators are
/// beside it, and a delta this roster does not name still refuses.
///
/// EVERY ROW NAMES ONE EXACT (module, declaration, spelling) TRIPLE. No wildcard, no prefix rule,
/// no row admitting a module or a spelling in general: an unintended requalification of `String`
/// anywhere else in either module -- or anywhere in the corpus -- still refuses as UNADJUDICATED.
/// The fifteen `v2.compiler.tokenize` rows and the two `v2.std.compilers.lexing` rows are the
/// whole change to this spelling.
///
/// DISSOLVE-ON: #9907 merging. Base and head then both carry the qualification, no run can produce
/// these deltas, all seventeen report stale, and they are removed by that trigger exactly as the
/// ten shrinks above were -- a stale row here refuses every unrelated PR in the repository.
pub const NAMESPACE_TRANSITION_ADMISSIONS: &[TransitionAdmission] = &[
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "DelimitedState",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "LexMatchResult",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "LexMatchThunk",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "LexRuleApply",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "LexWalkAcc",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "RepeatState",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_match_char_pred",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_match_prefix",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_strip_prefix",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_try_compiled",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_try_rule",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_try_rules",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_walk",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_walk_artifact",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.compiler.tokenize",
in_declaration: "lex_walk_init",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.std.compilers.lexing",
in_declaration: "LexPattern",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
TransitionAdmission {
label: "XL-0T structural text qualification 2026-09-01 (gunbc#9907)",
subject: AdmissionSubject::Binding {
module: "v2.std.compilers.lexing",
in_declaration: "LexPatternFold",
spelling: "String",
target: "v2.std.text",
},
disposition: NamespaceDeltaDisposition::TargetChanged,
},
];

/// The denominators a green must name (DESIGN §5): a run that cannot say what it covered is an
/// instrument failure wearing coverage's clothes.
Expand Down
66 changes: 45 additions & 21 deletions src/v2/compiler/01_tokenize.dag
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ import v2.std.compilers.lexing {
}

type LexMatchResult
= LexMatchAccepted { remaining: String, lexeme: String }
= LexMatchAccepted { remaining: v2.std.text.String, lexeme: v2.std.text.String }
| LexMatchRejected

type LexRuleApply
= LexRuleNoMatch
| LexRuleToken { class: Symbol, lexeme: String, remaining: String }
| LexRuleTrivia { lexeme: String, remaining: String }
| LexRuleAnnotation { class: Symbol, lexeme: String, remaining: String }
| LexRuleToken { class: Symbol, lexeme: v2.std.text.String, remaining: v2.std.text.String }
| LexRuleTrivia { lexeme: v2.std.text.String, remaining: v2.std.text.String }
| LexRuleAnnotation { class: Symbol, lexeme: v2.std.text.String, remaining: v2.std.text.String }

type LexMatchThunk {
apply: fn(String) -> LexMatchResult
apply: fn(v2.std.text.String) -> LexMatchResult
}

fn tokenize_lex_e0_source_not_exhausted_diagnostic(at: Locus) -> Diagnostic {
Expand Down Expand Up @@ -97,7 +97,7 @@ fn char_in_class(c: Char, class: LexCharClass) -> Bool {
}
}

fn lex_strip_prefix(prefix: String, source: String) -> ListTailResult<Char> {
fn lex_strip_prefix(prefix: v2.std.text.String, source: v2.std.text.String) -> ListTailResult<Char> {
fold_list(
xs: prefix,
empty: TailFound { tail: source },
Expand All @@ -110,7 +110,7 @@ fn lex_strip_prefix(prefix: String, source: String) -> ListTailResult<Char> {
)
}

fn lex_match_prefix(prefix: String, source: String) -> LexMatchResult {
fn lex_match_prefix(prefix: v2.std.text.String, source: v2.std.text.String) -> LexMatchResult {
if is_prefix_of(prefix: prefix, xs: source, eq: fn(a, b) { a == b }) {
match lex_strip_prefix(prefix: prefix, source: source) {
TailFound { tail: rem } => LexMatchAccepted { remaining: rem, lexeme: prefix }
Expand All @@ -122,14 +122,14 @@ fn lex_match_prefix(prefix: String, source: String) -> LexMatchResult {
}

type RepeatState {
remaining: String
lexeme: String
remaining: v2.std.text.String
lexeme: v2.std.text.String
done: Bool
}

type DelimitedState {
remaining: String
lexeme: String
remaining: v2.std.text.String
lexeme: v2.std.text.String
done: Bool
failed: Bool
}
Expand All @@ -142,7 +142,7 @@ fn lex_rule_pattern(rule: LexRule) -> LexPattern {
}
}

fn lex_match_char_pred(pred: fn(Char) -> Bool, source: String) -> LexMatchResult {
fn lex_match_char_pred(pred: fn(Char) -> Bool, source: v2.std.text.String) -> LexMatchResult {
match string_is_empty(s: source) {
true => LexMatchRejected
false =>
Expand Down Expand Up @@ -345,7 +345,7 @@ fn lex_rule_thunk(rule: LexRule) -> LexMatchThunk {
)
}

fn lex_try_compiled(compiled: CompiledLexRule, source: String) -> LexRuleApply {
fn lex_try_compiled(compiled: CompiledLexRule, source: v2.std.text.String) -> LexRuleApply {
match compiled.thunk.apply(source) {
LexMatchRejected => LexRuleNoMatch
LexMatchAccepted { remaining: remaining, lexeme: lexeme } =>
Expand All @@ -371,7 +371,7 @@ fn lex_compile_rules(rules: List<LexRule>) -> List<CompiledLexRule> {
reversed.reverse()
}

fn lex_try_rule(rule: LexRule, source: String) -> LexRuleApply {
fn lex_try_rule(rule: LexRule, source: v2.std.text.String) -> LexRuleApply {
lex_try_compiled(
compiled: CompiledLexRule { rule: rule, thunk: lex_rule_thunk(rule: rule) },
source: source
Expand Down Expand Up @@ -403,7 +403,7 @@ fn lex_try_rules_prefer_longer(acc: LexRuleApply, candidate: LexRuleApply) -> Le
}
}

fn lex_try_rules(rules: List<CompiledLexRule>, source: String) -> LexRuleApply {
fn lex_try_rules(rules: List<CompiledLexRule>, source: v2.std.text.String) -> LexRuleApply {
fold_list(
xs: rules,
empty: LexRuleNoMatch,
Expand All @@ -418,7 +418,7 @@ fn lex_try_rules(rules: List<CompiledLexRule>, source: String) -> LexRuleApply {

// The walk carries `line_prefix_indent_only` and advances it with the raw text of EVERY consumed lexeme — token, trivia, and annotation alike — through the shared std.source_annotation authority. It is not a `has a semantic token appeared on this line` flag, and the difference is not cosmetic: a token lexeme may itself contain line feeds, so a grammar whose tokens span lines has line boundaries INSIDE tokens rather than only in trivia. Resetting on trivia alone misclassifies every annotation following such a token.
type LexWalkAcc {
remaining: String
remaining: v2.std.text.String
tokens: List<Token>
annotations: List<UnboundSourceAnnotation>
line_prefix_indent_only: Bool
Expand All @@ -429,7 +429,7 @@ type LexWalkAcc {
rules: List<CompiledLexRule>
}

fn lex_walk_init(src: String, file: Symbol, rules: LexRuleSet) -> LexWalkAcc {
fn lex_walk_init(src: v2.std.text.String, file: Symbol, rules: LexRuleSet) -> LexWalkAcc {
LexWalkAcc {
remaining: src,
tokens: std.algebra.Empty,
Expand Down Expand Up @@ -588,7 +588,7 @@ fn lex_walk_source_algebra(file: Symbol, rules: LexRuleSet) -> SourceFold<LexWal
}

// lex_walk_artifact is the authored result; lex_walk is its SEMANTIC PROJECTION and is what every existing caller keeps using. The direction matters: the projection is derived from the artifact by dropping the annotation channel, never the reverse, so a semantic consumer cannot reach annotation text and an annotation-aware consumer does not have to re-lex. Both fold the same walk exactly once — this is one traversal read two ways, not two traversals (DESIGN 4c erasure boundary at the lexical layer, mirroring AuthoredParseArtifact at the parse layer).
fn lex_walk_artifact(source: String, file: Symbol, rules: LexRuleSet) -> Outcome<LexArtifact> {
fn lex_walk_artifact(source: v2.std.text.String, file: Symbol, rules: LexRuleSet) -> Outcome<LexArtifact> {
let result = fold_source(
src: source,
algebra: lex_walk_source_algebra(file: file, rules: rules)
Expand All @@ -607,7 +607,7 @@ fn lex_walk_artifact(source: String, file: Symbol, rules: LexRuleSet) -> Outcome
}
}

fn lex_walk(source: String, file: Symbol, rules: LexRuleSet) -> Outcome<TokenStream> {
fn lex_walk(source: v2.std.text.String, file: Symbol, rules: LexRuleSet) -> Outcome<TokenStream> {
match lex_walk_artifact(source: source, file: file, rules: rules) {
v2.std.diagnostic.Rejected { diagnostics: ds } =>
v2.std.diagnostic.Rejected { diagnostics: ds }
Expand All @@ -616,20 +616,44 @@ fn lex_walk(source: String, file: Symbol, rules: LexRuleSet) -> Outcome<TokenStr
}
}

// THE ONE SOURCE-TEXT INGRESS, AND THE ONLY PLACE HOST TEXT BECOMES STRUCTURAL TEXT IN THIS MODULE.
//
// `text` is host-valued ON PURPOSE and its spelling is not an oversight: the filesystem REPORTS
// source text, so what reaches this parameter is what a read returned. v2.compiler.source_authority
// hands over exactly the value it hashed, and the read boundary performs no lexical interpretation
// — deciding what a character IS belongs to the lexer, which is here.
//
// `chars` is the SAME scalar decomposition the literal elaborator uses. v1.compiler.infer
// unfold_scalar_sequence_image builds the UnicodeScalarSequenceUnfold image by calling it, so the
// runtime converter and the literal elaborator are two producers deriving one meaning from one
// authority rather than two loops that agree by coincidence. Scalar values, never UTF-8 bytes and
// never UTF-16 code units — an ad hoc byte loop would agree with this on ASCII and diverge on the
// first non-ASCII source file, which is precisely the divergence a shared authority forecloses.
//
// EXACTLY ONCE, ABOVE EVERYTHING. Both arms below read the converted value, so no lexical callback,
// prefix operation, walk state or fold ever receives the host form. A second conversion further in
// would be a second answer to a question already answered.
//
// THIS AUTHORIZES ONE CONVERSION AT ONE INGRESS AND NOTHING WIDER. It is not permission for
// arbitrary host Strings to inhabit structural text: gunbc.rung_drop's
// text_boundary_identity_wall stands, its subject is the non-literal host value crossing an exact
// structural-text boundary through permissive compatibility, and this named morphism does not
// retire it. A green ingress here is not that wall coming down.
fn tokenize(text: String, file: Symbol, rules: LexRules) -> Outcome<TokenStream> {
let source = chars(s: text)
let at = Textual {
file: file,
extent: WholeFile
}
match rules {
VoidLexRules =>
if is_empty(xs: text) {
if is_empty(xs: source) {
v2.std.diagnostic.Accepted { value: token_stream_empty(), diagnostics: v2.std.diagnostic.None }
} else {
v2.std.diagnostic.Rejected { diagnostics: diagnostics_singleton(d: tokenize_lex_e0_source_not_exhausted_diagnostic(at: at)) }
}
ModeledLexRules { root: rule_set } =>
lex_walk(source: text, file: file, rules: rule_set)
lex_walk(source: source, file: file, rules: rule_set)
}
}

Expand Down
Loading
Loading