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.
58 lines
1.6 KiB
TypeScript
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(" "));
|