@@ -1,46 +1,135 @@ ---- kcore/type.h.m → +--- kcore/type.h.m → --- ~ lexi hale --- this file gathers information on the environment it's --- being compiled in, defining types that our code --- needs. it will be emitted as . --- vim: ft=c +#ifndef KItype +#define KItype + +typedef unsigned char kc_uint_min; +typedef signed char kc_sint_min; +typedef unsigned long long kc_uint_max; +typedef signed long long kc_sint_max; + +[ifdef type_bit8] + typedef unsigned [type_bit8] u8; + typedef signed [type_bit8] s8; +[else] + typedef kc_uint_min u8; + typedef kc_sint_min s8; +[endif] + +[ifdef type_bit16] + typedef unsigned [type_bit16] u16; + typedef signed [type_bit16] s16; +[else] + typedef kc_uint_max u16; + typedef kc_sint_max s16; +[endif] + +[ifdef type_bit32] + typedef unsigned [type_bit32] u32; + typedef signed [type_bit32] s32; +[else] + typedef kc_uint_max u32; + typedef kc_sint_max s32; +[endif] + +[ifdef type_bit64] + typedef unsigned [type_bit64] u64; + typedef signed [type_bit64] s64; + [ifndef type_bit128] +# if defined(__GNUC__) || defined(__clang__) + typedef unsigned __int128_t u128; + typedef signed __int128_t s128; +# else + typedef kc_uint_max u128; + typedef kc_sint_max s128; +# endif + [endif] +[else] + typedef kc_uint_max u64; + typedef kc_sint_max s64; + + typedef kc_uint_max u128; + typedef kc_sint_max s128; +[endif] + +[ifdef type_bit128] + typedef unsigned [type_bit128] u128; + typedef signed [type_bit128] s128; +[endif] + +enum /* max-min values of each type */ { + /* assuming two's complement. TODO: check math */ + /* TODO: figure out how to calc min */ + kc_byte_bits = [byte_bits], + u8_min = 0, u8_max = ((u8)-1), + u16_min = 0, u16_max = ((u16)-1), + u32_min = 0, u32_max = ((u32)-1), + u64_min = 0, u32_max = ((u64)-1), + u128_min = 0, u128_max = ((u128)-1), + + [define merge: $1$2] + [define [sspec type]: + [merge [type],_min] = 0 - ((1 << sizeof([type]) * kc_byte_bits) / 2), + [merge [type],_max] = (1 << sizeof([type]) * kc_byte_bits) / 2 - 1] + + [sspec s8], [sspec s16], [sspec s32], + [sspec s64], [sspec s128], + + kc_min_uchar = 0, kc_max_uchar = [type_max_u_char], + kc_min_ushort = 0, kc_max_ushort = [type_max_u_short], + kc_min_uint = 0, kc_max_uint = [type_max_u_int], + kc_min_ulong = 0, kc_max_ulong = [type_max_u_long], + kc_min_ullong = 0, kc_max_ullong = [type_max_u_llong], + + kc_min_schar = [type_min_s_char], kc_max_schar = [type_max_s_char], + kc_min_sshort = [type_min_s_short], kc_max_sshort = [type_max_s_short], + kc_min_sint = [type_min_s_int], kc_max_sint = [type_max_s_int], + kc_min_slong = [type_min_s_long], kc_max_slong = [type_max_s_long], + kc_min_sllong = [type_min_s_llong], kc_max_sllong = [type_max_s_llong], +}; -// arch bit length [atom_target_bits] ---- make some gigantic fucking assumptions -[if [atom_target_bits] >= 8] - typedef unsigned char u8; - typedef signed char s8; - [if [atom_target_bits] >= 16] - typedef unsigned short u16; - typedef signed short s16; - [if [atom_target_bits] >= 32] - typedef unsigned long u32; - typedef signed long s32; - [if [atom_target_bits] >= 64] - typedef unsigned long long u64; - typedef signed long long s64; - [if [atom_target_arch] == x86] - #if defined(__GNUC__) || defined(__clang__) - typedef __uint128_t u128; - typedef __int128_t s128; - #endif - [endif] - [endif] - [endif] - [endif] +[ifdef type_sz] + typedef [type_sz] sz; +[else] +# ifdef __cplusplus + /* C++ gives us a clean, standardized way to do this */ + typedef decltype (sizeof(char)) sz; +# else +# if defined(__GNUC__) || defined(__clang__) + typedef __typeof__ (sizeof(char)) sz; +# else + /* we're stumped - set sz to the safest possible value under + * the circumstances, and warn the user. */ +# warning no authoritative sz (size_t) type definition \ + available; defaulting to largest unsigned integer type + typedef kc_uint_max sz; +# endif +# endif [endif] -typedef u[atom_target_bits] sz; -typedef s[atom_target_bits] ssz; - ---- make sure something unlikely doesn't happen -[define [maxtype name, n]: - [if [n] > [atom_target_bits]] - typedef u[atom_target_bits] [name] - [else] - typedef u[n] [name] - [endif]] +[ifdef type_offset] + typedef [type_offset] offset; +[else] +# ifdef __cplusplus + /* C++ gives us a clean, standardized way to do this */ + typedef decltype (((void*)-1) - 1) offset; +# else +# if defined(__GNUC__) || defined(__clang__) + typedef __typeof__ (((void*)10) - ((void*)5)) offset; +# else + /* no dice - set offset to the safest possible value under + * the circumstances, and warn the user. */ +# warning no authoritative offset (ptrdiff_t) type definition \ + available; defaulting to largest unsigned integer type + typedef kc_sint_max offset; +# endif +# endif +[endif] // exit status integer types - pls use kbad in instead [if [target_posix] == yes] /* by convention, posix return values are 8-bit, @@ -47,17 +136,19 @@ * but note that many modern UNIXes do technically * support higher-bit values. for this reason, * longstat is defined differently under posix. */ typedef u8 stat; - [maxtype longstat, 32]; + typedef u32 stat_long; [else] [if ([atom_target_os] == win) || ([atom_target_os] == vms)] - [maxtype stat, 32] + typedef u32 stat; [else] typedef u8 stat; /* we don't know a specific exit status type * for your arch so we're going with a sane * default. if this is wrong, help us fix it! */ [endif] - typedef stat longstat; + typedef stat stat_long; [endif] + +#endif