Files
scriptc/tests/corpus/5609-string-switch-optional.ts
T
Chris Tate ba8849a269 Speed up native string character tests, optional-string switches, fromCharCode and long-string length
`s.charAt(i) === "c"`, and `s[i] === "c"` where the index is proven in
bounds, built a one-character string to compare with the literal. When
the literal is one UTF-16 code unit, the comparison now reads
`s.charCodeAt(i)` and compares the number. charCodeAt converts the index
the same way charAt does, and an index out of range answers NaN, which
equals no unit, as "" equals no one-unit literal. A switch on
`s.charAt(i)` whose case tests are all one-unit literals switches on the
code unit the same way.

A switch on a `string | undefined` value with string literal cases, such
as an array element or an optional field, lowered to a chain of union
equalities. It now tests for undefined, which matches no case, and
dispatches the string through the string switch: by byte length, then by
the literal's leading bytes.

`String.fromCharCode(a, b, ...)` with up to sixteen arguments passes the
codes to the runtime in a stack array instead of a heap f64[], and up to
64 code units encode into a stack buffer instead of a heap scratch block.

`.length` of a string that is not ASCII counts its UTF-16 units. The
string index keeps four entries, so a program that read the lengths of
more long texts than that in turn (the text of every source file) walked
each whole string on every read. Lengths of non-ASCII strings longer than
64 bytes now go into a 1024-slot table keyed by address, allocated by
the first length it records. A slot is dropped when the string is freed
or reallocated and when an append changes it in place, which is where
the index drops its facts.
2026-10-20 01:11:36 -05:00

58 lines
1.6 KiB
TypeScript

// switch on a string | undefined value with string literal cases: array
// reads, optional fields and Map lookups that may be undefined, matching
// and missing values, the empty string, non-ASCII and long literals,
// duplicate cases, fallthrough, default in the middle, and few cases.
interface Token {
text?: string;
}
function kind(t: string | undefined): string {
switch (t) {
case "function":
case "class":
return "decl";
case "":
return "empty";
case "naïve":
return "unicode";
case "a-much-longer-keyword-than-eight-bytes":
return "long";
case "function":
return "duplicate";
default:
return t === undefined ? "missing" : "other";
case "return":
return "flow";
}
}
function fallthrough(t: string | undefined): number {
let n = 0;
switch (t) {
case "a":
n += 1;
case "b":
n += 2;
break;
default:
n += 8;
case "c":
n += 4;
}
return n;
}
function few(t: string | undefined): string {
switch (t) {
case "x":
return "x";
}
return "none";
}
const words = ["function", "class", "", "naïve", "a-much-longer-keyword-than-eight-bytes", "return", "other", "Function"];
for (let i = 0; i <= words.length; i++) {
const w: string | undefined = words[i];
console.log(i, kind(w), fallthrough(w), few(w));
}
const tokens: Token[] = [{ text: "a" }, {}, { text: "c" }, { text: "x" }];
console.log(tokens.map((t) => `${kind(t.text)}:${fallthrough(t.text)}:${few(t.text)}`).join(" "));
const table = new Map<string, string>([["k", "return"], ["e", ""]]);
console.log(["k", "e", "z"].map((key) => kind(table.get(key))).join(" "));