|
| 1 | +// Generates src/util/unicode_case_data.h — the case-mapping tables used by the |
| 2 | +// driver's Unicode-aware lower()/upper() SQL functions. |
| 3 | +// |
| 4 | +// The tables are generated from THIS Node's String.prototype.toLowerCase / |
| 5 | +// toUpperCase. That makes the C implementation match JavaScript's (context-free) |
| 6 | +// case conversion by construction — which is exactly the consistency the |
| 7 | +// client-side IVM matcher (toLowerCase) and the zqlite replica rely on. Case |
| 8 | +// mappings are stable across Unicode versions, so this only needs regenerating |
| 9 | +// on a deliberate Unicode bump. |
| 10 | +// |
| 11 | +// Usage: node deps/gen-unicode-case.mjs > src/util/unicode_case_data.h |
| 12 | + |
| 13 | +const MAX = 0x10ffff; |
| 14 | + |
| 15 | +function mappings(method) { |
| 16 | + const rows = []; |
| 17 | + for (let cp = 0; cp <= MAX; cp++) { |
| 18 | + if (cp >= 0xd800 && cp <= 0xdfff) continue; // lone surrogates |
| 19 | + const ch = String.fromCodePoint(cp); |
| 20 | + const mapped = ch[method](); |
| 21 | + if (mapped === ch) continue; |
| 22 | + const to = Array.from(mapped, c => c.codePointAt(0)); |
| 23 | + if (to.length > 3) throw new Error(`mapping for U+${cp.toString(16)} > 3 cps`); |
| 24 | + rows.push([cp, to]); |
| 25 | + } |
| 26 | + return rows; |
| 27 | +} |
| 28 | + |
| 29 | +function emit(name, rows) { |
| 30 | + const lines = rows.map(([from, to]) => { |
| 31 | + const t = [...to, 0, 0, 0].slice(0, 3).map(c => `0x${c.toString(16)}u`); |
| 32 | + return ` {0x${from.toString(16)}u, {${t.join(', ')}}, ${to.length}},`; |
| 33 | + }); |
| 34 | + return ( |
| 35 | + `static const ZeroCaseMap ${name}[] = {\n${lines.join('\n')}\n};\n` + |
| 36 | + `static const int ${name}Len = ${rows.length};\n` |
| 37 | + ); |
| 38 | +} |
| 39 | + |
| 40 | +const lower = mappings('toLowerCase'); |
| 41 | +const upper = mappings('toUpperCase'); |
| 42 | + |
| 43 | +process.stdout.write( |
| 44 | + `// AUTO-GENERATED by deps/gen-unicode-case.mjs — DO NOT EDIT.\n` + |
| 45 | + `// Source: Node ${process.versions.node} (Unicode ${process.versions.unicode}).\n` + |
| 46 | + `// Each row maps one source code point to 1-3 target code points, matching\n` + |
| 47 | + `// JavaScript String.prototype.toLowerCase/toUpperCase (context-free).\n` + |
| 48 | + `#ifndef ZERO_UNICODE_CASE_DATA_H\n#define ZERO_UNICODE_CASE_DATA_H\n\n` + |
| 49 | + `typedef struct ZeroCaseMap {\n` + |
| 50 | + ` unsigned int from;\n unsigned int to[3];\n unsigned char n;\n` + |
| 51 | + `} ZeroCaseMap;\n\n` + |
| 52 | + emit('kZeroLowerMap', lower) + |
| 53 | + `\n` + |
| 54 | + emit('kZeroUpperMap', upper) + |
| 55 | + `\n#endif /* ZERO_UNICODE_CASE_DATA_H */\n`, |
| 56 | +); |
0 commit comments