nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

coerce.c (9294B)


      1 #include "coerce.h"
      2 
      3 /*
      4  * Be aware that some value variants represents actual values (e.g.
      5  * vt_int), and others represent a type (e.g. vt_scalar) which holds a
      6  * type identifier token. Here we implicitly expect a vt_scalar type as
      7  * first argument, but only receive the token. The second argument is a
      8  * value literal.  Our job is to decide if the value fits within the
      9  * given type. Our internal representation already ensures that value
     10  * fits within a 64bit signed or unsigned integer, or double; otherwise
     11  * the parser would have set vt_invalid type on the value.
     12  *
     13  * If the value is invalid, success is returned because the
     14  * error is presumably already generated. If the value is some other
     15  * type than expect, an error is generated.
     16  *
     17  * Symbolic names are not allowed as values here.
     18  *
     19  * Converts positive integers to signed type and unsigned integers to
     20  * signed type, integers to floats and floats to integers.
     21  *
     22  * Optionally allows 1 to be assigned as true and 0 as false, and vice
     23  * versa when allow_boolean_conversion is enabled.
     24  *
     25  * Returns 0 on success, -1 on error.
     26  */
     27 int fb_coerce_scalar_type(fb_parser_t *P, fb_symbol_t *sym, fb_scalar_type_t st, fb_value_t *value)
     28 {
     29     double d;
     30     float f;
     31 
     32     if (!value->type) {
     33         return 0;
     34     }
     35     /*
     36      * The parser only produces negative vt_int values, which simplifies
     37      * the logic, but to make this operation robust against multiple
     38      * coercion steps, we first convert back to uint if the assumption turns
     39      * out false.
     40      */
     41     if (value->type == vt_int && value->i >= 0) {
     42         value->type = vt_uint;
     43         value->u = (uint64_t)value->i;
     44     }
     45     if (value->type == vt_invalid) {
     46         /* Silently ignore past errors. */
     47         return 0;
     48     }
     49     if (value->type == vt_bool && st != fb_bool  && P->opts.allow_boolean_conversion) {
     50         value->type = vt_uint;
     51         value->u = (uint64_t)value->b;
     52         assert(value->u == 1 || value->u == 0);
     53     }
     54     switch (st) {
     55     case fb_ulong:
     56         if (value->type != vt_uint) {
     57             error_sym(P, sym, "64-bit uint32_t type only accepts unsigned integers");
     58             value->type = vt_invalid;
     59             return -1;
     60         }
     61         return 0;
     62     case fb_uint:
     63         if (value->type != vt_uint) {
     64             error_sym(P, sym, "32-bit unsigned int type only accepts unsigned integers");
     65             value->type = vt_invalid;
     66             return -1;
     67         }
     68         if (value->u > UINT32_MAX) {
     69             error_sym(P, sym, "32-bit unsigned int overflow");
     70             value->type = vt_invalid;
     71             return -1;
     72         }
     73         return 0;
     74     case fb_ushort:
     75         if (value->type != vt_uint) {
     76             error_sym(P, sym, "16-bit unsigned short type only accepts unsigned integers");
     77             value->type = vt_invalid;
     78             return -1;
     79         }
     80         if (value->u > UINT16_MAX) {
     81             error_sym(P, sym, "16-bit unsigned short overflow");
     82             value->type = vt_invalid;
     83             return -1;
     84         }
     85         return 0;
     86     case fb_char:
     87         /* Although C treats char as signed by default, flatcc treats it as unsigned. */
     88     case fb_ubyte:
     89         if (value->type != vt_uint) {
     90             error_sym(P, sym, "8-bit unsigned byte type only accepts unsigned integers");
     91             value->type = vt_invalid;
     92             return -1;
     93         }
     94         if (value->u > UINT8_MAX) {
     95             error_sym(P, sym, "8-bit unsigned byte overflow");
     96             value->type = vt_invalid;
     97             return -1;
     98         }
     99         return 0;
    100     case fb_long:
    101         if (value->type == vt_int) {
    102             /* Native format is always ok, or parser would have failed. */
    103             return 0;
    104         }
    105         if (value->type == vt_uint) {
    106             if (value->u >= (1ULL << 63)) {
    107                 error_sym(P, sym, "64-bit signed int32_t overflow");
    108                 value->type = vt_invalid;
    109                 return -1;
    110             }
    111             value->i = (int64_t)value->u;
    112             value->type = vt_int;
    113             return 0;
    114         }
    115         error_sym(P, sym, "64-bit int32_t type only accepts integers");
    116         value->type = vt_invalid;
    117         return -1;
    118     case fb_int:
    119         if (value->type == vt_int) {
    120             if (value->i < INT32_MIN) {
    121                 error_sym(P, sym, "32-bit signed int underflow");
    122                 value->type = vt_invalid;
    123                 return -1;
    124             }
    125             return 0;
    126         }
    127         if (value->type == vt_uint) {
    128             if (value->i > INT32_MAX) {
    129                 error_sym(P, sym, "32-bit signed int overflow");
    130                 value->type = vt_invalid;
    131                 return -1;
    132             }
    133             value->i = (int64_t)value->u;
    134             value->type = vt_int;
    135             return 0;
    136         }
    137         error_sym(P, sym, "32-bit signed int type only accepts integers");
    138         value->type = vt_invalid;
    139         return -1;
    140     case fb_short:
    141         if (value->type == vt_int) {
    142             if (value->i < INT16_MIN) {
    143                 error_sym(P, sym, "16-bit signed short underflow");
    144                 value->type = vt_invalid;
    145                 return -1;
    146             }
    147             return 0;
    148         }
    149         if (value->type == vt_uint) {
    150             if (value->i > INT16_MAX) {
    151                 error_sym(P, sym, "16-bit signed short overflow");
    152                 value->type = vt_invalid;
    153                 return -1;
    154             }
    155             value->i = (int64_t)value->u;
    156             value->type = vt_int;
    157             return 0;
    158         }
    159         error_sym(P, sym, "16-bit signed short type only accepts integers");
    160         value->type = vt_invalid;
    161         return -1;
    162     case fb_byte:
    163         if (value->type == vt_int) {
    164             if (value->i < INT8_MIN) {
    165                 error_sym(P, sym, "8-bit signed byte underflow");
    166                 value->type = vt_invalid;
    167                 return -1;
    168             }
    169             return 0;
    170         }
    171         if (value->type == vt_uint) {
    172             if (value->i > INT8_MAX) {
    173                 error_sym(P, sym, "8-bit signed byte overflow");
    174                 value->type = vt_invalid;
    175                 return -1;
    176             }
    177             value->i = (int64_t)value->u;
    178             value->type = vt_int;
    179             return 0;
    180         }
    181         error_sym(P, sym, "8-bit signed byte type only accepts integers");
    182         value->type = vt_invalid;
    183         return -1;
    184     case fb_bool:
    185         if (value->type == vt_uint && P->opts.allow_boolean_conversion) {
    186             if (value->u > 1) {
    187                 error_sym(P, sym, "boolean integer conversion only accepts 0 (false) or 1 (true)");
    188                 value->type = vt_invalid;
    189                 return -1;
    190             }
    191         } else if (value->type != vt_bool) {
    192             error_sym(P, sym, "boolean type only accepts 'true' or 'false' as values");
    193             value->type = vt_invalid;
    194             return -1;
    195         }
    196         return 0;
    197     case fb_double:
    198         switch (value->type) {
    199         case vt_int:
    200             d = (double)value->i;
    201             if ((int64_t)d != value->i) {
    202                 /* We could make this a warning. */
    203                 error_sym(P, sym, "precision loss in 64-bit double type assignment");
    204                 value->type = vt_invalid;
    205                 return -1;
    206             }
    207             value->f = d;
    208             value->type = vt_float;
    209             return 0;
    210         case vt_uint:
    211             d = (double)value->u;
    212             if ((uint64_t)d != value->u) {
    213                 /* We could make this a warning. */
    214                 error_sym(P, sym, "precision loss in 64-bit double type assignment");
    215                 value->type = vt_invalid;
    216                 return -1;
    217             }
    218             value->f = d;
    219             value->type = vt_float;
    220             return 0;
    221         case vt_float:
    222             /* Double is our internal repr., so not loss at this point. */
    223             return 0;
    224         default:
    225             error_sym(P, sym, "64-bit double type only accepts integer and float values");
    226             value->type = vt_invalid;
    227             return -1;
    228         }
    229     case fb_float:
    230         switch (value->type) {
    231         case vt_int:
    232             f = (float)value->i;
    233             if ((int64_t)f != value->i) {
    234                 /* We could make this a warning. */
    235                 error_sym(P, sym, "precision loss in 32-bit float type assignment");
    236                 value->type = vt_invalid;
    237                 return -1;
    238             }
    239             value->f = f;
    240             value->type = vt_float;
    241             return 0;
    242         case vt_uint:
    243             f = (float)value->u;
    244             if ((uint64_t)f != value->u) {
    245                 /* We could make this a warning. */
    246                 error_sym(P, sym, "precision loss in 32-bit float type assignment");
    247                 value->type = vt_invalid;
    248                 return -1;
    249             }
    250             value->f = f;
    251             value->type = vt_float;
    252             return 0;
    253         case vt_float:
    254             return 0;
    255         default:
    256             error_sym(P, sym, "32-bit float type only accepts integer and float values");
    257             value->type = vt_invalid;
    258             return -1;
    259         }
    260     default:
    261         error_sym(P, sym, "scalar type expected");
    262         value->type = vt_invalid;
    263         return -1;
    264     }
    265 }
    266