mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-02 07:43:42 +08:00
`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.
96 lines
2.1 KiB
TypeScript
96 lines
2.1 KiB
TypeScript
// switch on one character of a string with one-unit case literals: the
|
|
// index and charAt forms, indexes out of range, negative, fractional and
|
|
// NaN, astral text and lone surrogates, duplicate cases, fallthrough, a
|
|
// switch without default, few and many cases, and an index expression
|
|
// with a side effect.
|
|
function classify(ch: string): string {
|
|
return ch;
|
|
}
|
|
function kind(s: string, i: number): string {
|
|
switch (s[i]) {
|
|
case "(":
|
|
case ")":
|
|
return "paren";
|
|
case "{":
|
|
return "brace";
|
|
case "é":
|
|
return "e-acute";
|
|
case "\uD83D":
|
|
return "high";
|
|
case "\uDE00":
|
|
return "low";
|
|
case "\uD800":
|
|
return "lone";
|
|
case "(":
|
|
return "duplicate";
|
|
case " ":
|
|
return "space";
|
|
default:
|
|
return "other";
|
|
}
|
|
}
|
|
function few(s: string, i: number): number {
|
|
let n = 0;
|
|
switch (s.charAt(i)) {
|
|
case "a":
|
|
n += 1;
|
|
case "b":
|
|
n += 2;
|
|
break;
|
|
case "c":
|
|
n += 4;
|
|
}
|
|
return n;
|
|
}
|
|
const samples = ["(x) {é}", "😀", "\uD800", "", "abc", " "];
|
|
const indexes = [0, 1, 2, 3, -1, 0.5, NaN, 100];
|
|
for (const s of samples) {
|
|
console.log(
|
|
JSON.stringify(s),
|
|
indexes.map((i) => kind(s, i)).join(","),
|
|
indexes.map((i) => few(s, i)).join(","),
|
|
);
|
|
}
|
|
let calls = 0;
|
|
const text = "abc";
|
|
const next = (): number => calls++;
|
|
for (let r = 0; r < 4; r++) {
|
|
switch (text.charAt(next())) {
|
|
case "a":
|
|
console.log("a", calls);
|
|
break;
|
|
case "c":
|
|
console.log("c", calls);
|
|
break;
|
|
default:
|
|
console.log("default", calls);
|
|
}
|
|
}
|
|
function tokens(text: string): string {
|
|
const out: string[] = [];
|
|
for (let i = 0; i < text.length; i++) {
|
|
switch (text[i]) {
|
|
case "(":
|
|
case ")":
|
|
out.push("p");
|
|
break;
|
|
case "+":
|
|
case "-":
|
|
case "*":
|
|
case "/":
|
|
out.push("o");
|
|
break;
|
|
case "\uD83D":
|
|
out.push("h");
|
|
break;
|
|
case " ":
|
|
break;
|
|
default:
|
|
out.push(text[i]);
|
|
}
|
|
}
|
|
return out.join("");
|
|
}
|
|
console.log(tokens("(a + b) * c / d - é"), tokens("x😀y"), tokens(""));
|
|
console.log(classify("ok"));
|