parseNormalized
Parses an RFC 9535 §2.7 Normalized Path, and only a Normalized Path.
The inverse of VariantPath.toNormalizedPath, strict on purpose. This is the direction in which a location arrives from somewhere else, and a lenient reader is what makes two implementations disagree later: accepting $.a beside $['a'], or A beside a, would give one location several spellings and quietly undo the single-rendering property the normalized form exists for.
So each of these is rejected rather than understood — a dot step, a wildcard, a slice, a filter, a double-quoted name, a raw control character, an unpaired surrogate, an escape §2.7 does not name, an uppercase hexadecimal digit, a \u escape for a character that has a named escape, and an index carrying a sign or a leading zero. parse is the lenient sibling, and it is the one that reads the engine's own spelling.
An index is additionally bounded by Int.MAX_VALUE rather than by §2.7's 2^53-1, because that is what a VariantPathStep.Index holds.
Throws
with the offending position, for anything else.