#pragma once #include #include #include #include #include #include #include #include #include #include"str.h" #define LTAG_MASK 0xFFFF000000000000ULL #define LTAG_NAN 0xFFF8000000000001ULL #define LTAG_NIL 0xFFF8000000000002ULL #define LTAG_FALSE 0xFFF8000000000003ULL #define LTAG_TRUE 0xFFF8000000000004ULL #define LTAG_I32 0xFFF9000000000000ULL #define LTAG_TABLE 0xFFFA000000000000ULL #define LTAG_USERDATA 0xFFFB000000000000ULL #define LTAG_FUNCTION 0xFFFC000000000000ULL #define LTAG_FLOAT 0xFFFD000000000000ULL #define LTAG_STRING 0xFFFE000000000000ULL typedef enum { LT_NIL, LT_STRING, LT_NUMBER, LT_INTEGER, LT_TABLE, LT_USERDATA, LT_BOOLEAN, LT_FUNCTION, } LType; typedef union { double f; uint64_t u; } LValue; static inline uint64_t lhash64(uint64_t val) { val ^= (val >> 33); val *= 0xff51afd7ed558ccdUL; val ^= (val >> 33); val *= 0xc4ceb9fe1a85ec53UL; val ^= (val >> 33); return val; } static inline LValue lvalue_from_double(double f) { LValue v; if(isnan(f)) { // Normalize v.u = LTAG_NAN; } else { v.f = f; } return (LValue) {.f = f}; } static inline LValue lvalue_from_int32(int32_t i) { return (LValue) {.u = LTAG_I32 | (uint32_t) i}; } static inline LValue lvalue_from_bool(bool b) { return (LValue) {.u = b ? LTAG_TRUE : LTAG_FALSE}; } static inline LValue lvalue_from_nil() { return (LValue) {.u = LTAG_NIL}; } struct LTable; static inline LValue lvalue_from_table(struct LTable *tbl) { return (LValue) {.u = LTAG_TABLE | (uintptr_t) tbl}; } struct LString; static inline LValue lvalue_from_string(struct LString *str) { return (LValue) {.u = LTAG_STRING | (uintptr_t) str}; } struct LFunc; static inline LValue lvalue_from_func(struct LFunc *f) { return (LValue) {.u = LTAG_FUNCTION | (uintptr_t) f}; } static inline int32_t lvalue_to_int32(LValue v) { return v.u & ~LTAG_MASK; } static inline uint64_t lvalue_tag(LValue v) { return v.u & LTAG_MASK; } static inline LValue lvalue_raw(uint64_t tag, uint64_t rawval) { assert(rawval == (rawval & ~LTAG_MASK)); return (LValue) {.u = tag | rawval}; } static inline uint64_t lvalue_hash(LValue lv) { if(lvalue_tag(lv) == LTAG_STRING) { LString *str = (LString*) (lv.u & ~LTAG_MASK); uint64_t h = 0; for(size_t i = 0; i < (str->length & ~7); i += 8) { h = lhash64(h ^ *(uint64_t*) &str->data[i]); } uint64_t last = 0; memcpy(&last, str->data + (str->length & ~7), str->length - (str->length & ~7)); h = lhash64(h ^ last); return h; } return lhash64(lv.u); } bool lvalue_eq(LValue, LValue);