Skip to content

Commit 0ea359b

Browse files
olwangclaude
andcommitted
feat(selfhost): Step 3 spans — lexer tier-1 (line/col) + tier-2 (length) complete
The rss tokenizer already tracked per-char line/col (used by statement_end); added a `len` field to Tok (= the consumed source span j-i, matching the Rust lexer's index-start) and taught lexer.rss to emit the real `<line>:<col>:<len>` prefix instead of the `0:0:0` placeholder. Result: lexer_parity_corpus is byte-exact at ALL THREE tiers over 576 files — tier 0 (kind+payload), tier 1 (+line/col), tier 2 (+length), token-mismatches 0 each. The lexer span ladder is fully closed; string/char/multiline/interp delimiter spans and the max(1) cases all match. Tok.len is additive (only lexer.rss reads it); parser/checker/astdump parity unaffected (all samples green). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent e8141f9 commit 0ea359b

2 files changed

Lines changed: 16 additions & 5 deletions

File tree

selfhost/lexer.rss

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ fn kind_name(k: read Int) -> String {
2424
return "UnknownKind"
2525
}
2626

27+
// Source char length of a token (span length), tier-2 field.
28+
fn tok_len(t: read Tok) -> Int {
29+
return t.len
30+
}
31+
2732
fn main() -> Unit {
2833
let source = Args.get_or_default(index: 0, default: read "")
2934
let toks = tokenize(source: read source)
@@ -33,9 +38,14 @@ fn main() -> Unit {
3338
let t = List.get(list: read toks, index: read i)
3439
let kn = kind_name(k: read t.kind)
3540
let esc = escape(s: read t.text)
36-
let a = String.concat(left: read "0:0:0\t", right: read kn)
37-
let b = String.concat(left: read a, right: read "\t")
38-
let line = String.concat(left: read b, right: read esc)
41+
// <line>:<col>:<len> — line/col are real (tier 1); len is the token's
42+
// char length (tier 2), 0 for the synthetic EOF.
43+
let pos = String.concat(left: read String.concat(left: read String.concat(left: read String.from_int(value: t.line), right: read ":"), right: read String.from_int(value: t.col)), right: read ":")
44+
let plen = String.concat(left: read pos, right: read String.from_int(value: tok_len(t: read t)))
45+
let a = String.concat(left: read plen, right: read "\t")
46+
let b = String.concat(left: read a, right: read kn)
47+
let c = String.concat(left: read b, right: read "\t")
48+
let line = String.concat(left: read c, right: read esc)
3949
Log.write(message: read line)
4050
i = i + 1
4151
}

selfhost/scan.rss

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct Tok {
3232
val: Int
3333
line: Int
3434
col: Int
35+
len: Int
3536
text: String
3637
}
3738

@@ -559,7 +560,7 @@ fn tokenize(source: read String) -> fresh List<Tok> {
559560
}
560561
}
561562
if kind != 0 {
562-
let t = Tok(kind: kind, val: val, line: startLine, col: startCol, text: text)
563+
let t = Tok(kind: kind, val: val, line: startLine, col: startCol, len: (j - i), text: text)
563564
List.push(list: mut toks, value: read t)
564565
}
565566
// Advance line/col over the consumed span [i, j).
@@ -576,7 +577,7 @@ fn tokenize(source: read String) -> fresh List<Tok> {
576577
}
577578
i = j
578579
}
579-
let eof = Tok(kind: TOK_EOF, val: 0, line: curLine, col: curCol, text: "")
580+
let eof = Tok(kind: TOK_EOF, val: 0, line: curLine, col: curCol, len: 0, text: "")
580581
List.push(list: mut toks, value: read eof)
581582
return toks
582583
}

0 commit comments

Comments
 (0)