value.h
Go to the documentation of this file.
1 #pragma once
6 #include <stdio.h>
7 #include <string.h>
8 #include "kuroko.h"
9 
10 #ifndef KRK_NO_NAN_BOXING
17 typedef enum {
18  KRK_VAL_BOOLEAN = 0xFFFC,
19  KRK_VAL_INTEGER = 0xFFFD,
20  KRK_VAL_HANDLER = 0xFFFE,
21  KRK_VAL_NONE = 0xFFFF,
22  KRK_VAL_KWARGS = 0x7FFC,
23  KRK_VAL_OBJECT = 0x7FFD,
24  KRK_VAL_NOTIMPL = 0x7FFE,
25 } KrkValueType;
26 
41 typedef uint64_t KrkValue;
42 
43 #define _krk_valuesSame(a,b) (a == b)
44 
45 #else
46 /*
47  * Tagged union, but without the union fun.
48  */
49 typedef enum {
50  KRK_VAL_NONE = 0,
51  KRK_VAL_INTEGER = 1,
52  KRK_VAL_BOOLEAN = 2,
53  KRK_VAL_HANDLER = 4,
54  KRK_VAL_KWARGS = 8,
55  KRK_VAL_OBJECT = 16,
56  KRK_VAL_NOTIMPL = 32,
57  KRK_VAL_FLOATING = 64,
58 } KrkValueType;
59 
60 typedef struct {
61  uint64_t tag;
62  uint64_t val;
63 } KrkValue;
64 
65 #define _krk_valuesSame(a,b) (memcmp(&(a),&(b),sizeof(KrkValue)) == 0)
66 
67 #endif
68 
75 typedef struct {
76  size_t capacity;
77  size_t count;
80 
91 extern void krk_initValueArray(KrkValueArray * array);
92 
103 extern void krk_writeValueArray(KrkValueArray * array, KrkValue value);
104 
116 extern void krk_freeValueArray(KrkValueArray * array);
117 
128 extern int krk_valuesEqual(KrkValue a, KrkValue b);
129 
141 static inline int krk_valuesSame(KrkValue a, KrkValue b) { return _krk_valuesSame(a,b); }
142 
151 extern int krk_valuesSameOrEqual(KrkValue a, KrkValue b);
152 
153 extern KrkValue krk_parse_int(const char * start, size_t width, unsigned int base);
154 extern KrkValue krk_parse_float(const char* start, size_t width);
155 
156 #ifndef KRK_NO_NAN_BOXING
157 
158 typedef union {
159  KrkValue val;
160  double dbl;
161 } KrkValueDbl;
162 
163 /*
164  * The following poorly-named macros define bit patterns for identifying
165  * various boxed types.
166  *
167  * Boxing is done by first setting all of the bits of MASK_NAN. If all of
168  * these bits are set, a value is not a float. If any of them are not set,
169  * then a value is a float - and possibly a real NaN.
170  *
171  * Three other bits - one before and two after the MASK_NAN bits - determine
172  * what type the value actually is. KWARGS sets none of the identifying bits,
173  * NONE sets all of them.
174  */
175 #define KRK_VAL_MASK_BOOLEAN ((uint64_t)0xFFFC000000000000) /* 1..1100 */
176 #define KRK_VAL_MASK_INTEGER ((uint64_t)0xFFFD000000000000) /* 1..1101 */
177 #define KRK_VAL_MASK_HANDLER ((uint64_t)0xFFFE000000000000) /* 1..1110 */
178 #define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000) /* 1..1111 */
179 #define KRK_VAL_MASK_KWARGS ((uint64_t)0x7FFC000000000000) /* 0..1100 */
180 #define KRK_VAL_MASK_OBJECT ((uint64_t)0x7FFD000000000000) /* 0..1101 */
181 #define KRK_VAL_MASK_NOTIMPL ((uint64_t)0x7FFE000000000000) /* 0..1110 */
182 #define KRK_VAL_MASK_NAN ((uint64_t)0x7FFC000000000000)
183 #define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
184 
185 #ifdef KRK_SANITIZE_OBJECT_POINTERS
190 #include <assert.h>
191 static inline uintptr_t _krk_sanitize(uintptr_t input) {
192  assert(input != 0);
193  return input;
194 }
195 #else
196 #define _krk_sanitize(ptr) (ptr)
197 #endif
198 
204 #ifdef KRK_HEAP_TAG_BYTE
205 #define KRK_HEAP_TAG ((uintptr_t)KRK_HEAP_TAG_BYTE << 56)
206 #else
207 #define KRK_HEAP_TAG 0
208 #endif
209 
210 #define NONE_VAL() ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NONE))
211 #define NOTIMPL_VAL() ((KrkValue)(KRK_VAL_MASK_LOW | KRK_VAL_MASK_NOTIMPL))
212 #define BOOLEAN_VAL(value) ((KrkValue)(((uint64_t)(value) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_BOOLEAN))
213 #define INTEGER_VAL(value) ((KrkValue)(((uint64_t)(value) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_INTEGER))
214 #define KWARGS_VAL(value) ((KrkValue)((uint32_t)(value) | KRK_VAL_MASK_KWARGS))
215 #define OBJECT_VAL(value) ((KrkValue)((_krk_sanitize((uintptr_t)(value)) & KRK_VAL_MASK_LOW) | KRK_VAL_MASK_OBJECT))
216 #define HANDLER_VAL(ty,ta) ((KrkValue)((uint64_t)((((uint64_t)ty) << 32) | ((uint32_t)ta)) | KRK_VAL_MASK_HANDLER))
217 #define FLOATING_VAL(value) (((KrkValueDbl){.dbl = (value)}).val)
218 
219 #define KRK_VAL_TYPE(value) ((value) >> 48)
220 
221 #define KRK_IX(value) ((uint64_t)((value) & KRK_VAL_MASK_LOW))
222 #define KRK_SX(value) ((uint64_t)((value) & 0x800000000000))
223 #define AS_INTEGER(value) ((krk_integer_type)(KRK_SX(value) ? (KRK_IX(value) | KRK_VAL_MASK_NONE) : (KRK_IX(value))))
224 #define AS_BOOLEAN(value) AS_INTEGER(value)
225 
226 #define AS_NOTIMPL(value) ((krk_integer_type)((value) & KRK_VAL_MASK_LOW))
227 #define AS_HANDLER(value) ((uint64_t)((value) & KRK_VAL_MASK_LOW))
228 #define AS_OBJECT(value) ((KrkObj*)(uintptr_t)(((value) & KRK_VAL_MASK_LOW) | KRK_HEAP_TAG))
229 #define AS_FLOATING(value) (((KrkValueDbl){.val = (value)}).dbl)
230 
231 /* This is a silly optimization: because of the arrangement of the identifying
232  * bits, (TYPE & MASK_HANDLER) == MASK_BOOLEAN can be used to tell if something
233  * is either an integer or a boolean - and booleans are also integers, so this
234  * is how we check if something is an integer in the general case; for everything
235  * else, we check against MASK_NONE because it sets all the identifying bits. */
236 #define IS_INTEGER(value) ((((value) >> 48L) & (KRK_VAL_MASK_HANDLER >> 48L)) == (KRK_VAL_MASK_BOOLEAN >> 48L))
237 #define IS_BOOLEAN(value) (((value) >> 48L) == (KRK_VAL_MASK_BOOLEAN >> 48L))
238 #define IS_NONE(value) (((value) >> 48L) == (KRK_VAL_MASK_NONE >> 48L))
239 #define IS_HANDLER(value) (((value) >> 48L) == (KRK_VAL_MASK_HANDLER >> 48L))
240 #define IS_OBJECT(value) (((value) >> 48L) == (KRK_VAL_MASK_OBJECT >> 48L))
241 #define IS_KWARGS(value) (((value) >> 48L) == (KRK_VAL_MASK_KWARGS >> 48L))
242 #define IS_NOTIMPL(value) (((value) >> 48L) == (KRK_VAL_MASK_NOTIMPL >> 48L))
243 /* ... and as we said above, if any of the MASK_NAN bits are unset, it's a float. */
244 #define IS_FLOATING(value) (((value) & KRK_VAL_MASK_NAN) != KRK_VAL_MASK_NAN)
245 
246 #else
247 
248 typedef union {
249  uint64_t val;
250  double dbl;
251 } KrkValueDbl;
252 
253 #define NONE_VAL() ((KrkValue){KRK_VAL_NONE,-1})
254 #define NOTIMPL_VAL() ((KrkValue){KRK_VAL_NOTIMPL,0})
255 #define BOOLEAN_VAL(value) ((KrkValue){KRK_VAL_BOOLEAN,!!(value)})
256 #define INTEGER_VAL(value) ((KrkValue){KRK_VAL_INTEGER,((uint64_t)(value)) & 0xFFFFffffFFFFULL})
257 #define KWARGS_VAL(value) ((KrkValue){KRK_VAL_KWARGS,((uint32_t)(value))})
258 #define OBJECT_VAL(value) ((KrkValue){KRK_VAL_OBJECT,((uintptr_t)(value))})
259 #define HANDLER_VAL(ty,ta) ((KrkValue){KRK_VAL_HANDLER,((uint64_t)((((uint64_t)ty) << 32) | ((uint32_t)ta)))})
260 #define FLOATING_VAL(value) ((KrkValue){KRK_VAL_FLOATING,(((KrkValueDbl){.dbl = (value)}).val)})
261 
262 #define KRK_VAL_TYPE(value) ((value).tag)
263 
264 #define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000)
265 #define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
266 #define KRK_IX(value) ((uint64_t)((value).val & KRK_VAL_MASK_LOW))
267 #define KRK_SX(value) ((uint64_t)((value).val & 0x800000000000))
268 #define AS_INTEGER(value) ((krk_integer_type)(KRK_SX(value) ? (KRK_IX(value) | KRK_VAL_MASK_NONE) : (KRK_IX(value))))
269 #define AS_BOOLEAN(value) AS_INTEGER(value)
270 
271 #define AS_HANDLER(value) ((uint64_t)((value)).val)
272 #define AS_OBJECT(value) ((KrkObj*)((uintptr_t)((value).val)))
273 #define AS_FLOATING(value) (((KrkValueDbl){.val = ((value)).val}).dbl)
274 
275 #define IS_INTEGER(value) (!!(((value)).tag & (KRK_VAL_INTEGER|KRK_VAL_BOOLEAN)))
276 #define IS_BOOLEAN(value) (((value)).tag == KRK_VAL_BOOLEAN)
277 #define IS_NONE(value) (((value)).tag == KRK_VAL_NONE)
278 #define IS_HANDLER(value) (((value)).tag == KRK_VAL_HANDLER)
279 #define IS_OBJECT(value) (((value)).tag == KRK_VAL_OBJECT)
280 #define IS_KWARGS(value) (((value)).tag == KRK_VAL_KWARGS)
281 #define IS_NOTIMPL(value) (((value)).tag == KRK_VAL_NOTIMPL)
282 #define IS_FLOATING(value) (((value)).tag == KRK_VAL_FLOATING)
283 
284 #endif
285 
286 
287 #define AS_HANDLER_TYPE(value) (AS_HANDLER(value) >> 32)
288 #define AS_HANDLER_TARGET(value) (AS_HANDLER(value) & 0xFFFFFFFF)
289 #define IS_HANDLER_TYPE(value,type) (IS_HANDLER(value) && AS_HANDLER_TYPE(value) == type)
290 
291 #define KWARGS_SINGLE (INT32_MAX)
292 #define KWARGS_LIST (INT32_MAX-1)
293 #define KWARGS_DICT (INT32_MAX-2)
294 #define KWARGS_NIL (INT32_MAX-3)
295 #define KWARGS_UNSET (0)
296 
297 #define PRIkrk_int "%" PRId64
298 #define PRIkrk_hex "%" PRIx64
299 
Top-level header with configuration macros.
Flexible vector of stack references.
Definition: value.h:75
size_t capacity
Definition: value.h:76
KrkValue * values
Definition: value.h:78
void krk_initValueArray(KrkValueArray *array)
Initialize a value array.
Definition: value.c:11
void krk_freeValueArray(KrkValueArray *array)
Release relesources used by a value array.
Definition: value.c:28
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Definition: value.c:17
size_t count
Definition: value.h:77
Stack reference or primative value.
int krk_valuesEqual(KrkValue a, KrkValue b)
Compare two values for equality.
Definition: value.c:106
static int krk_valuesSame(KrkValue a, KrkValue b)
Compare two values by identity.
Definition: value.h:141
int krk_valuesSameOrEqual(KrkValue a, KrkValue b)
Compare two values by identity, then by equality.
Definition: value.c:96
KrkValue krk_parse_float(const char *start, size_t width)
Parse a string into a float.
Definition: obj_long.c:2820
KrkValueType
Tag enum for basic value types.
Definition: value.h:17