unicode.c (5700B)
1 /* gramunicode.c - UTF-8 and scalar helpers for Unicode-aware lexing. */ 2 #include <kit/gram_unicode.h> 3 4 static bool is_cont(unsigned char b) { return kit_gram_utf8_is_cont(b); } 5 6 static bool is_ignored_property_key_char(unsigned char c) { 7 return c == '-' || c == '_' || c == ' ' || c == '\t' || c == '\n' || 8 c == '\r' || c == '\f' || c == '\v'; 9 } 10 11 static unsigned char lower_ascii(unsigned char c) { 12 return (c >= 'A' && c <= 'Z') ? (unsigned char)(c - 'A' + 'a') : c; 13 } 14 15 bool kit_gram_unicode_is_surrogate(uint32_t cp) { 16 return cp >= 0xD800u && cp <= 0xDFFFu; 17 } 18 19 bool kit_gram_unicode_is_scalar(uint32_t cp) { 20 return cp <= KIT_GRAM_UNICODE_MAX_SCALAR && !kit_gram_unicode_is_surrogate(cp); 21 } 22 23 bool kit_gram_unicode_is_noncharacter(uint32_t cp) { 24 if (cp >= 0xFDD0u && cp <= 0xFDEFu) return true; 25 return cp <= KIT_GRAM_UNICODE_MAX_SCALAR && (cp & 0xFFFEu) == 0xFFFEu; 26 } 27 28 bool kit_gram_unicode_is_line_break(uint32_t cp) { 29 return cp == 0x000Au || cp == 0x000Bu || cp == 0x000Cu || cp == 0x000Du || 30 cp == 0x0085u || cp == 0x2028u || cp == 0x2029u; 31 } 32 33 size_t kit_gram_utf8_encoded_len(uint32_t cp) { 34 if (!kit_gram_unicode_is_scalar(cp)) return 0; 35 if (cp <= 0x7Fu) return 1; 36 if (cp <= 0x7FFu) return 2; 37 if (cp <= 0xFFFFu) return 3; 38 return 4; 39 } 40 41 size_t kit_gram_utf8_encode(uint32_t cp, unsigned char out[4]) { 42 size_t n = kit_gram_utf8_encoded_len(cp); 43 if (!n || !out) return 0; 44 if (n == 1) { 45 out[0] = (unsigned char)cp; 46 } else if (n == 2) { 47 out[0] = (unsigned char)(0xC0u | (cp >> 6)); 48 out[1] = (unsigned char)(0x80u | (cp & 0x3Fu)); 49 } else if (n == 3) { 50 out[0] = (unsigned char)(0xE0u | (cp >> 12)); 51 out[1] = (unsigned char)(0x80u | ((cp >> 6) & 0x3Fu)); 52 out[2] = (unsigned char)(0x80u | (cp & 0x3Fu)); 53 } else { 54 out[0] = (unsigned char)(0xF0u | (cp >> 18)); 55 out[1] = (unsigned char)(0x80u | ((cp >> 12) & 0x3Fu)); 56 out[2] = (unsigned char)(0x80u | ((cp >> 6) & 0x3Fu)); 57 out[3] = (unsigned char)(0x80u | (cp & 0x3Fu)); 58 } 59 return n; 60 } 61 62 KitGramUtf8Status kit_gram_utf8_decode_one(const unsigned char* bytes, size_t len, 63 uint32_t* cp, size_t* nbytes) { 64 if (!cp || !nbytes) return KIT_GRAM_UTF8_INVALID; 65 *cp = 0; 66 *nbytes = 0; 67 if (!len) return KIT_GRAM_UTF8_NEED_MORE; 68 if (!bytes) return KIT_GRAM_UTF8_INVALID; 69 70 unsigned char b0 = bytes[0]; 71 if (b0 <= 0x7Fu) { 72 *cp = b0; 73 *nbytes = 1; 74 return KIT_GRAM_UTF8_OK; 75 } 76 77 if (b0 >= 0xC2u && b0 <= 0xDFu) { 78 if (len < 2) return KIT_GRAM_UTF8_NEED_MORE; 79 unsigned char b1 = bytes[1]; 80 if (!is_cont(b1)) return KIT_GRAM_UTF8_INVALID; 81 *cp = ((uint32_t)(b0 & 0x1Fu) << 6) | (uint32_t)(b1 & 0x3Fu); 82 *nbytes = 2; 83 return KIT_GRAM_UTF8_OK; 84 } 85 86 if (b0 >= 0xE0u && b0 <= 0xEFu) { 87 if (len < 2) return KIT_GRAM_UTF8_NEED_MORE; 88 unsigned char b1 = bytes[1]; 89 if (!is_cont(b1)) return KIT_GRAM_UTF8_INVALID; 90 if (b0 == 0xE0u && b1 < 0xA0u) return KIT_GRAM_UTF8_INVALID; 91 if (b0 == 0xEDu && b1 > 0x9Fu) return KIT_GRAM_UTF8_INVALID; 92 if (len < 3) return KIT_GRAM_UTF8_NEED_MORE; 93 unsigned char b2 = bytes[2]; 94 if (!is_cont(b2)) return KIT_GRAM_UTF8_INVALID; 95 *cp = ((uint32_t)(b0 & 0x0Fu) << 12) | ((uint32_t)(b1 & 0x3Fu) << 6) | 96 (uint32_t)(b2 & 0x3Fu); 97 *nbytes = 3; 98 return KIT_GRAM_UTF8_OK; 99 } 100 101 if (b0 >= 0xF0u && b0 <= 0xF4u) { 102 if (len < 2) return KIT_GRAM_UTF8_NEED_MORE; 103 unsigned char b1 = bytes[1]; 104 if (!is_cont(b1)) return KIT_GRAM_UTF8_INVALID; 105 if (b0 == 0xF0u && b1 < 0x90u) return KIT_GRAM_UTF8_INVALID; 106 if (b0 == 0xF4u && b1 > 0x8Fu) return KIT_GRAM_UTF8_INVALID; 107 if (len < 3) return KIT_GRAM_UTF8_NEED_MORE; 108 unsigned char b2 = bytes[2]; 109 if (!is_cont(b2)) return KIT_GRAM_UTF8_INVALID; 110 if (len < 4) return KIT_GRAM_UTF8_NEED_MORE; 111 unsigned char b3 = bytes[3]; 112 if (!is_cont(b3)) return KIT_GRAM_UTF8_INVALID; 113 *cp = ((uint32_t)(b0 & 0x07u) << 18) | ((uint32_t)(b1 & 0x3Fu) << 12) | 114 ((uint32_t)(b2 & 0x3Fu) << 6) | (uint32_t)(b3 & 0x3Fu); 115 *nbytes = 4; 116 return KIT_GRAM_UTF8_OK; 117 } 118 119 return KIT_GRAM_UTF8_INVALID; 120 } 121 122 void kit_gram_unicode_pos_init(KitGramUnicodePos* pos) { 123 if (!pos) return; 124 *pos = (KitGramUnicodePos){.line = 1, .col = 1, .after_cr = false}; 125 } 126 127 void kit_gram_unicode_pos_advance(KitGramUnicodePos* pos, uint32_t cp) { 128 if (!pos) return; 129 if (cp == 0x000Au && pos->after_cr) { 130 pos->after_cr = false; 131 return; 132 } 133 if (cp == 0x000Du) { 134 pos->line++; 135 pos->col = 1; 136 pos->after_cr = true; 137 return; 138 } 139 pos->after_cr = false; 140 if (kit_gram_unicode_is_line_break(cp)) { 141 pos->line++; 142 pos->col = 1; 143 } else { 144 pos->col++; 145 } 146 } 147 148 KitGramUtf8Status kit_gram_unicode_pos_advance_utf8(KitGramUnicodePos* pos, 149 const unsigned char* bytes, 150 size_t len, size_t* nbytes) { 151 uint32_t cp = 0; 152 size_t n = 0; 153 KitGramUtf8Status st = kit_gram_utf8_decode_one(bytes, len, &cp, &n); 154 if (nbytes) *nbytes = n; 155 if (st != KIT_GRAM_UTF8_OK) return st; 156 kit_gram_unicode_pos_advance(pos, cp); 157 return KIT_GRAM_UTF8_OK; 158 } 159 160 size_t kit_gram_unicode_fold_property_key(const char* in, char* out, 161 size_t out_cap) { 162 size_t n = 0; 163 if (out_cap) out[0] = '\0'; 164 if (!in) return 0; 165 for (const unsigned char* p = (const unsigned char*)in; *p; p++) { 166 if (is_ignored_property_key_char(*p)) continue; 167 unsigned char c = lower_ascii(*p); 168 if (out_cap && n + 1 < out_cap) out[n] = (char)c; 169 n++; 170 } 171 if (out_cap) { 172 size_t end = n < out_cap ? n : out_cap - 1; 173 out[end] = '\0'; 174 } 175 return n; 176 }