M zlox/src/common.h => zlox/src/common.h +1 -0
@@ 5,6 5,7 @@
#include <stddef.h>
#include <stdint.h>
+#define NAN_BOXING
#define DEBUG_PRINT_CODE
#define DEBUG_TRACE_EXECUTION
M zlox/src/value.c => zlox/src/value.c +19 -0
@@ 31,6 31,17 @@ void freeValueArray(ValueArray *array) {
}
void printValue(Value value) {
+#ifdef NAN_BOXING
+ if (IS_BOOL(value)) {
+ printf(AS_BOOL(value) ? "true" : "false");
+ } else if (IS_NIL(value)) {
+ printf("nil");
+ } else if (IS_NUMBER(value)) {
+ printf("%g", AS_NUMBER(value));
+ } else if (IS_OBJ(value)) {
+ printObject(value);
+ }
+#else
switch (value.type) {
case VAL_BOOL:
printf(AS_BOOL(value) ? "true" : "false");
@@ 39,9 50,16 @@ void printValue(Value value) {
case VAL_NUMBER: printf("%g", AS_NUMBER(value)); break;
case VAL_OBJ: printObject(value); break;
}
+#endif
}
bool valuesEqual(Value a, Value b) {
+#ifdef NAN_BOXING
+ if (IS_NUMBER(a) && IS_NUMBER(b)) {
+ return AS_NUMBER(a) == AS_NUMBER(b);
+ }
+ return a == b;
+#else
if (a.type != b.type) return false;
switch (a.type) {
case VAL_BOOL: return AS_BOOL(a) == AS_BOOL(b);
@@ 50,4 68,5 @@ bool valuesEqual(Value a, Value b) {
case VAL_OBJ: return AS_OBJ(a) == AS_OBJ(b);
default: return false; /* Unreachable. */
}
+#endif
}
M zlox/src/value.h => zlox/src/value.h +46 -0
@@ 3,9 3,53 @@
#include "common.h"
+#include <string.h>
+
typedef struct Obj Obj;
typedef struct ObjString ObjString;
+#ifdef NAN_BOXING
+
+#define SIGN_BIT ((uint64_t)0x8000000000000000)
+#define QNAN ((uint64_t)0x7ffc000000000000)
+
+#define TAG_NIL 1 /* 01. */
+#define TAG_FALSE 2 /* 10. */
+#define TAG_TRUE 3 /* 11. */
+
+typedef uint64_t Value;
+
+#define IS_BOOL(value) (((value) | 1) == TRUE_VAL)
+#define IS_NIL(value) ((value) == NIL_VAL)
+#define IS_NUMBER(value) (((value) & QNAN) != QNAN)
+#define IS_OBJ(value) (((value) & (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT))
+
+#define AS_BOOL(value) ((value) == TRUE_VAL)
+#define AS_NUMBER(value) valueToNum(value)
+#define AS_OBJ(value) ((Obj*)(uintptr_t)((value) & ~(SIGN_BIT | QNAN)))
+
+#define BOOL_VAL(b) ((b) ? TRUE_VAL : FALSE_VAL)
+#define FALSE_VAL ((Value)(uint64_t)(QNAN | TAG_FALSE))
+#define TRUE_VAL ((Value)(uint64_t)(QNAN | TAG_TRUE))
+#define NIL_VAL ((Value)(uint64_t)(QNAN | TAG_NIL))
+#define NUMBER_VAL(num) numToValue(num)
+#define OBJ_VAL(obj) \
+ (Value)(SIGN_BIT | QNAN | (uint64_t)(uintptr_t)(obj))
+
+static inline double valueToNum(Value value) {
+ double num;
+ memcpy(&num, &value, sizeof(Value));
+ return num;
+}
+
+static inline Value numToValue(double num) {
+ Value value;
+ memcpy(&value, &num, sizeof(double));
+ return value;
+}
+
+#else
+
typedef enum {
VAL_BOOL,
VAL_NIL,
@@ 36,6 80,8 @@ typedef struct {
#define NUMBER_VAL(value) ((Value){VAL_NUMBER, {.number = value}})
#define OBJ_VAL(object) ((Value){VAL_OBJ, {.obj = (Obj*)object}})
+#endif
+
typedef struct {
int capacity;
int count;