kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }