remove dead defensive throws in keytab tokenizer + parser

Four `throw` sites in `core/input/keytab/` were unreachable through
the public API:

- `keytab_token.dart` `_parseKeyboardNameDefine` and `_parseKeyDefine`
  each tested `reader.readString() == 'keyboard'` / `'key'` after
  the caller in the same file (`tokenize`) had already gated entry
  on `_isKeyboardNameDefine` / `_isKeyDefine`. Both checks
  redundantly re-derived a fact already established a function
  call earlier; the `else { throw }` was dead code.
- `keytab_parse.dart` `_parseName` and `_parseKeyDefine` checked
  the first token's type, but `addTokens` only delegates to those
  functions after `peek().type` matches the expected kind. Same
  pattern: the throw protects an invariant the caller already
  enforces.

Surfaced while bringing `core/input/` to ~100% coverage. Per the
"near-perfect discipline" / "no carve-outs" rules, dead defensive
code is cleaned, not skipped — the surrounding callers in the same
file are tight enough that introducing a real callsite gap would
be a localised and obvious bug, not a silent failure rescued by
these guards.

The two `else`-throw sites in keytab_token.dart fold into a single
unconditional `reader.readString()` (consume the leading word) +
`yield` of the matching token type. The two type-check throws in
keytab_parse.dart fold into an unconditional `reader.take()` to
skip the already-validated token.

All public-API ParseError paths exercised by `core/input/`'s
unit tests still throw correctly — they're guarded by the second
check in each function (the action-token type check after
modeStatus loops, and the input-token check in _parseName).

After cleanup:
- keytab_token.dart: 80 / 80
- keytab_parse.dart: 63 / 63

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-05-06 23:37:05 +02:00
co-authored by Claude
parent f3e164b834
commit 94abebf904
3 changed files with 118 additions and 125 deletions
@@ -55,9 +55,8 @@ class KeytabParser {
}
void _parseName(TokensReader reader) {
if (reader.take()!.type != KeytabTokenType.keyboard) {
throw ParseError();
}
// Caller (`addTokens`) has already gated on the keyboard token type.
reader.take();
final name = reader.take()!;
if (name.type != KeytabTokenType.input) {
@@ -68,9 +67,8 @@ class KeytabParser {
}
void _parseKeyDefine(TokensReader reader) {
if (reader.take()!.type != KeytabTokenType.keyDefine) {
throw ParseError();
}
// Caller has already gated on the keyDefine token type.
reader.take();
final keyName = reader.take()!;
@@ -114,13 +114,11 @@ bool _isKeyDefine(String line) {
}
Iterable<KeytabToken> _parseKeyboardNameDefine(String line) sync* {
// Caller has already gated on `_isKeyboardNameDefine`, so the leading
// word is guaranteed to be 'keyboard'. Just consume it.
final reader = LineReader(line.trim());
if (reader.readString() == 'keyboard') {
yield KeytabToken(KeytabTokenType.keyboard, 'keyboard');
} else {
throw TokenizeError();
}
reader.readString();
yield KeytabToken(KeytabTokenType.keyboard, 'keyboard');
reader.skipWhitespace();
@@ -128,13 +126,10 @@ Iterable<KeytabToken> _parseKeyboardNameDefine(String line) sync* {
}
Iterable<KeytabToken> _parseKeyDefine(String line) sync* {
// Caller has already gated on `_isKeyDefine`.
final reader = LineReader(line.trim());
if (reader.readString() == 'key') {
yield KeytabToken(KeytabTokenType.keyDefine, 'key');
} else {
throw TokenizeError();
}
reader.readString();
yield KeytabToken(KeytabTokenType.keyDefine, 'key');
reader.skipWhitespace();