Created
April 22, 2023 23:07
-
-
Save tyfkda/28755ec9beda4af047f09e4a727fd6ee to your computer and use it in GitHub Desktop.
NaN Boxing, referred to CLox (Crafting Interpreters)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Ref. https://craftinginterpreters.com/ | |
| #include <assert.h> | |
| #include <inttypes.h> // PRIx64 | |
| #include <stdbool.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> // malloc | |
| #include <stdint.h> | |
| #include <string.h> | |
| // value.h | |
| typedef uint64_t Value; | |
| #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. | |
| #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)) | |
| #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))) | |
| 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; | |
| } | |
| typedef struct Obj Obj; | |
| typedef struct ObjString ObjString; | |
| // object.h | |
| #define OBJ_TYPE(value) (AS_OBJ(value)->type) | |
| #define IS_STRING(value) isObjType(value, OBJ_STRING) | |
| #define AS_STRING(value) ((ObjString*)AS_OBJ(value)) | |
| #define AS_CSTRING(value) (((ObjString*)AS_OBJ(value))->chars) | |
| typedef enum { | |
| // 他にも色々あるが、省略 | |
| OBJ_STRING, | |
| } ObjType; | |
| struct Obj { | |
| ObjType type; | |
| // bool isMarked; | |
| // struct Obj* next; | |
| }; | |
| struct ObjString { | |
| Obj obj; | |
| int length; | |
| char* chars; | |
| // uint32_t hash; | |
| }; | |
| #define ALLOCATE(type, count) \ | |
| (type*)reallocate(NULL, 0, sizeof(type) * (count)) | |
| #define reallocate(ptr, oldSize, newSize) realloc(ptr, newSize) | |
| #define ALLOCATE_OBJ(type, objectType) \ | |
| (type*)allocateObject(sizeof(type), objectType) | |
| static Obj* allocateObject(size_t size, ObjType type) { | |
| Obj* object = (Obj*)reallocate(NULL, 0, size); | |
| object->type = type; | |
| // object->isMarked = false; | |
| // object->next = vm.objects; | |
| // vm.objects = object; | |
| return object; | |
| } | |
| static ObjString* allocateString(char* chars, int length /*, uint32_t hash*/) { | |
| ObjString* string = ALLOCATE_OBJ(ObjString, OBJ_STRING); | |
| string->length = length; | |
| string->chars = chars; | |
| // string->hash = hash; | |
| // push(OBJ_VAL(string)); | |
| // tableSet(&vm.strings, string, NIL_VAL); | |
| // pop(); | |
| return string; | |
| } | |
| ObjString* copyString(const char* chars, int length) { | |
| // uint32_t hash = hashString(chars, length); | |
| // ObjString* interned = tableFindString(&vm.strings, chars, length, | |
| // hash); | |
| // if (interned != NULL) return interned; | |
| char* heapChars = ALLOCATE(char, length + 1); | |
| memcpy(heapChars, chars, length); | |
| heapChars[length] = '\0'; | |
| return allocateString(heapChars, length /*, hash*/); | |
| } | |
| void printObject(Value value) { | |
| switch (OBJ_TYPE(value)) { | |
| case OBJ_STRING: | |
| printf("\"%s\"", AS_CSTRING(value)); | |
| break; | |
| default: assert(false); break; | |
| } | |
| } | |
| void printValue(Value value) { | |
| printf("%016" PRIx64 ": ", value); | |
| 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 { | |
| assert(!"illegal value"); | |
| } | |
| } | |
| int main(void) { | |
| char s[] = "Hello, world!"; | |
| Value str = OBJ_VAL(copyString(s, strlen(s))); | |
| Value values[] = { | |
| NIL_VAL, | |
| FALSE_VAL, | |
| TRUE_VAL, | |
| NUMBER_VAL(1.234), | |
| NUMBER_VAL(-0.789e5), | |
| NUMBER_VAL(0.0), | |
| NUMBER_VAL(1.0 / 0.0), | |
| NUMBER_VAL(-1.0 / 0.0), | |
| NUMBER_VAL(0.0 / 0.0), | |
| str, | |
| }; | |
| for (size_t i = 0; i < sizeof(values) / sizeof(*values); ++i) { | |
| printValue(values[i]); | |
| printf("\n"); | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment