mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-05 08:10:05 +00:00
added support for NaN boxing (8 byte CValues!)
This commit is contained in:
parent
495f1d7272
commit
b936827cc6
@ -98,7 +98,7 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
|
|||||||
int index = readu16Chunk(chunk, offset + 1);
|
int index = readu16Chunk(chunk, offset + 1);
|
||||||
printf("%-16s [%05d] - ", "OP_CLOSURE", index);
|
printf("%-16s [%05d] - ", "OP_CLOSURE", index);
|
||||||
CValue val = chunk->constants.values[index];
|
CValue val = chunk->constants.values[index];
|
||||||
CObjFunction *cobjFunc = (CObjFunction*)val.val.obj;
|
CObjFunction *cobjFunc = (CObjFunction*)cosmoV_readObj(val);
|
||||||
offset += 3; // we consumed the opcode + u16
|
offset += 3; // we consumed the opcode + u16
|
||||||
|
|
||||||
printValue(val);
|
printValue(val);
|
||||||
|
@ -71,7 +71,7 @@ void tableRemoveWhite(CState *state, CTable *tbl) {
|
|||||||
|
|
||||||
for (int i = 0; i < tbl->capacity; i++) {
|
for (int i = 0; i < tbl->capacity; i++) {
|
||||||
CTableEntry *entry = &tbl->table[i];
|
CTableEntry *entry = &tbl->table[i];
|
||||||
if (IS_OBJ(entry->key) && !(entry->key.val.obj)->isMarked) { // if the key is a object and it's white (unmarked), remove it from the table
|
if (IS_OBJ(entry->key) && !(cosmoV_readObj(entry->key))->isMarked) { // if the key is a object and it's white (unmarked), remove it from the table
|
||||||
cosmoT_remove(state, tbl, entry->key);
|
cosmoT_remove(state, tbl, entry->key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
src/cobj.h
12
src/cobj.h
@ -90,12 +90,12 @@ typedef struct CObjUpval {
|
|||||||
#define IS_METHOD(x) isObjType(x, COBJ_METHOD)
|
#define IS_METHOD(x) isObjType(x, COBJ_METHOD)
|
||||||
#define IS_CLOSURE(x) isObjType(x, COBJ_CLOSURE)
|
#define IS_CLOSURE(x) isObjType(x, COBJ_CLOSURE)
|
||||||
|
|
||||||
#define cosmoV_readString(x) ((CObjString*)cosmoV_readObj((x)))
|
#define cosmoV_readString(x) ((CObjString*)cosmoV_readObj(x))
|
||||||
#define cosmoV_readObject(x) ((CObjObject*)cosmoV_readObj((x)))
|
#define cosmoV_readObject(x) ((CObjObject*)cosmoV_readObj(x))
|
||||||
#define cosmoV_readFunction(x) ((CObjFunction*)cosmoV_readObj((x)))
|
#define cosmoV_readFunction(x) ((CObjFunction*)cosmoV_readObj(x))
|
||||||
#define cosmoV_readCFunction(x) (((CObjCFunction*)cosmoV_readObj((x)))->cfunc)
|
#define cosmoV_readCFunction(x) (((CObjCFunction*)cosmoV_readObj(x))->cfunc)
|
||||||
#define cosmoV_readMethod(x) ((CObjMethod*)cosmoV_readObj((x)))
|
#define cosmoV_readMethod(x) ((CObjMethod*)cosmoV_readObj(x))
|
||||||
#define cosmoV_readClosure(x) ((CObjClosure*)cosmoV_readObj((x)))
|
#define cosmoV_readClosure(x) ((CObjClosure*)cosmoV_readObj(x))
|
||||||
|
|
||||||
static inline bool isObjType(CValue val, CObjType type) {
|
static inline bool isObjType(CValue val, CObjType type) {
|
||||||
return IS_OBJ(val) && cosmoV_readObj(val)->type == type;
|
return IS_OBJ(val) && cosmoV_readObj(val)->type == type;
|
||||||
|
@ -7,10 +7,16 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
//#define NAN_BOXXED
|
||||||
|
|
||||||
// forward declare *most* stuff so our headers are cleaner
|
// forward declare *most* stuff so our headers are cleaner
|
||||||
typedef struct CState CState;
|
typedef struct CState CState;
|
||||||
typedef struct CChunk CChunk;
|
typedef struct CChunk CChunk;
|
||||||
|
#ifdef NAN_BOXXED
|
||||||
|
typedef union CValue CValue;
|
||||||
|
#else
|
||||||
typedef struct CValue CValue;
|
typedef struct CValue CValue;
|
||||||
|
#endif
|
||||||
|
|
||||||
// objs
|
// objs
|
||||||
typedef struct CObj CObj;
|
typedef struct CObj CObj;
|
||||||
|
14
src/ctable.c
14
src/ctable.c
@ -62,18 +62,20 @@ uint32_t getObjectHash(CObj *obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getValueHash(CValue *val) {
|
uint32_t getValueHash(CValue *val) {
|
||||||
switch (val->type) {
|
switch (GET_TYPE(*val)) {
|
||||||
case COSMO_TOBJ:
|
case COSMO_TOBJ:
|
||||||
return getObjectHash(val->val.obj);
|
return getObjectHash(cosmoV_readObj(*val));
|
||||||
case COSMO_TNUMBER: {
|
case COSMO_TNUMBER: {
|
||||||
uint32_t buf[sizeof(cosmo_Number)/sizeof(uint32_t)];
|
uint32_t buf[sizeof(cosmo_Number)/sizeof(uint32_t)];
|
||||||
if (val->val.num == 0)
|
cosmo_Number num = cosmoV_readNumber(*val);
|
||||||
|
|
||||||
|
if (num == 0)
|
||||||
return 0;
|
return 0;
|
||||||
memcpy(buf, &val->val.num, sizeof(buf));
|
|
||||||
|
memcpy(buf, &num, sizeof(buf));
|
||||||
for (int i = 0; i < sizeof(cosmo_Number)/sizeof(uint32_t); i++) buf[0] += buf[i];
|
for (int i = 0; i < sizeof(cosmo_Number)/sizeof(uint32_t); i++) buf[0] += buf[i];
|
||||||
return buf[0];
|
return buf[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add support for other types
|
// TODO: add support for other types
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@ -227,7 +229,7 @@ CObjString *cosmoT_lookupString(CTable *tbl, const char *str, size_t length, uin
|
|||||||
return NULL;
|
return NULL;
|
||||||
} else if (IS_STRING(entry->key) && cosmoV_readString(entry->key)->length == length && memcmp(cosmoV_readString(entry->key)->str, str, length) == 0) {
|
} else if (IS_STRING(entry->key) && cosmoV_readString(entry->key)->length == length && memcmp(cosmoV_readString(entry->key)->str, str, length) == 0) {
|
||||||
// it's a match!
|
// it's a match!
|
||||||
return (CObjString*)entry->key.val.obj;
|
return (CObjString*)cosmoV_readObj(entry->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
indx = (indx + 1) & (tbl->capacity - 1); // fast mod here too
|
indx = (indx + 1) & (tbl->capacity - 1); // fast mod here too
|
||||||
|
29
src/cvalue.c
29
src/cvalue.c
@ -1,3 +1,4 @@
|
|||||||
|
#include "cosmo.h"
|
||||||
#include "cmem.h"
|
#include "cmem.h"
|
||||||
#include "cvalue.h"
|
#include "cvalue.h"
|
||||||
#include "cobj.h"
|
#include "cobj.h"
|
||||||
@ -19,14 +20,14 @@ void appendValArray(CState *state, CValueArray *array, CValue val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool cosmoV_equal(CValue valA, CValue valB) {
|
bool cosmoV_equal(CValue valA, CValue valB) {
|
||||||
if (valA.type != valB.type) // are they the same type?
|
if (GET_TYPE(valA) != GET_TYPE(valB)) // are they the same type?
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// compare
|
// compare
|
||||||
switch (valA.type) {
|
switch (GET_TYPE(valA)) {
|
||||||
case COSMO_TBOOLEAN: return valA.val.b == valB.val.b;
|
case COSMO_TBOOLEAN: return cosmoV_readBoolean(valA) == cosmoV_readBoolean(valB);
|
||||||
case COSMO_TNUMBER: return valA.val.num == valB.val.num;
|
case COSMO_TNUMBER: return cosmoV_readNumber(valA) == cosmoV_readNumber(valB);
|
||||||
case COSMO_TOBJ: return cosmoO_equal(valA.val.obj, valB.val.obj);
|
case COSMO_TOBJ: return cosmoO_equal(cosmoV_readObj(valA), cosmoV_readObj(valB));
|
||||||
case COSMO_TNIL: return true;
|
case COSMO_TNIL: return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -34,17 +35,17 @@ bool cosmoV_equal(CValue valA, CValue valB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CObjString *cosmoV_toString(CState *state, CValue val) {
|
CObjString *cosmoV_toString(CState *state, CValue val) {
|
||||||
switch (val.type) {
|
switch (GET_TYPE(val)) {
|
||||||
case COSMO_TNUMBER: {
|
case COSMO_TNUMBER: {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int size = snprintf((char*)&buf, 32, "%.14g", val.val.num);
|
int size = snprintf((char*)&buf, 32, "%.14g", cosmoV_readNumber(val));
|
||||||
return cosmoO_copyString(state, (char*)&buf, size);
|
return cosmoO_copyString(state, (char*)&buf, size);
|
||||||
}
|
}
|
||||||
case COSMO_TBOOLEAN: {
|
case COSMO_TBOOLEAN: {
|
||||||
return val.val.b ? cosmoO_copyString(state, "true", 4) : cosmoO_copyString(state, "false", 5);
|
return cosmoV_readBoolean(val) ? cosmoO_copyString(state, "true", 4) : cosmoO_copyString(state, "false", 5);
|
||||||
}
|
}
|
||||||
case COSMO_TOBJ: {
|
case COSMO_TOBJ: {
|
||||||
return cosmoO_toString(state, val.val.obj);
|
return cosmoO_toString(state, cosmoV_readObj(val));
|
||||||
}
|
}
|
||||||
case COSMO_TNIL: {
|
case COSMO_TNIL: {
|
||||||
return cosmoO_copyString(state, "nil", 3);
|
return cosmoO_copyString(state, "nil", 3);
|
||||||
@ -55,11 +56,11 @@ CObjString *cosmoV_toString(CState *state, CValue val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *cosmoV_typeStr(CValue val) {
|
const char *cosmoV_typeStr(CValue val) {
|
||||||
switch (val.type) {
|
switch (GET_TYPE(val)) {
|
||||||
case COSMO_TNIL: return "<nil>";
|
case COSMO_TNIL: return "<nil>";
|
||||||
case COSMO_TBOOLEAN: return "<bool>";
|
case COSMO_TBOOLEAN: return "<bool>";
|
||||||
case COSMO_TNUMBER: return "<number>";
|
case COSMO_TNUMBER: return "<number>";
|
||||||
case COSMO_TOBJ: return cosmoO_typeStr(val.val.obj);
|
case COSMO_TOBJ: return cosmoO_typeStr(cosmoV_readObj(val));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "<unkn val>";
|
return "<unkn val>";
|
||||||
@ -67,15 +68,15 @@ const char *cosmoV_typeStr(CValue val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void printValue(CValue val) {
|
void printValue(CValue val) {
|
||||||
switch (val.type) {
|
switch (GET_TYPE(val)) {
|
||||||
case COSMO_TNUMBER:
|
case COSMO_TNUMBER:
|
||||||
printf("%g", val.val.num);
|
printf("%g", cosmoV_readNumber(val));
|
||||||
break;
|
break;
|
||||||
case COSMO_TBOOLEAN:
|
case COSMO_TBOOLEAN:
|
||||||
printf(cosmoV_readBoolean(val) ? "true" : "false");
|
printf(cosmoV_readBoolean(val) ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
case COSMO_TOBJ: {
|
case COSMO_TOBJ: {
|
||||||
printObject(val.val.obj);
|
printObject(cosmoV_readObj(val));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COSMO_TNIL:
|
case COSMO_TNIL:
|
||||||
|
98
src/cvalue.h
98
src/cvalue.h
@ -4,10 +4,10 @@
|
|||||||
#include "cosmo.h"
|
#include "cosmo.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
COSMO_TNIL,
|
COSMO_TNUMBER, // number has to be 0 because NaN box
|
||||||
COSMO_TBOOLEAN,
|
COSMO_TBOOLEAN,
|
||||||
COSMO_TNUMBER,
|
COSMO_TOBJ,
|
||||||
COSMO_TOBJ
|
COSMO_TNIL,
|
||||||
} CosmoType;
|
} CosmoType;
|
||||||
|
|
||||||
typedef double cosmo_Number;
|
typedef double cosmo_Number;
|
||||||
@ -15,6 +15,57 @@ typedef double cosmo_Number;
|
|||||||
/*
|
/*
|
||||||
holds primitive cosmo types
|
holds primitive cosmo types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef NAN_BOXXED
|
||||||
|
/*
|
||||||
|
NaN box, this is great for performance on x86_64 or ARM64 architectures. If you don't know how this works please reference these
|
||||||
|
two articles:
|
||||||
|
|
||||||
|
https://leonardschuetz.ch/blog/nan-boxing/ and https://piotrduperas.com/posts/nan-boxing/
|
||||||
|
|
||||||
|
both are great resources :)
|
||||||
|
|
||||||
|
TL;DR: we can store payloads in the NaN value in the IEEE 754 standard.
|
||||||
|
*/
|
||||||
|
typedef union CValue {
|
||||||
|
uint64_t data;
|
||||||
|
cosmo_Number num;
|
||||||
|
} CValue;
|
||||||
|
|
||||||
|
#define MASK_SIGN_BIT ((uint64_t)1 << 63)
|
||||||
|
#define MASK_TYPE ((uint64_t)0xf)
|
||||||
|
#define MASK_PAYLOAD ((uint64_t)0xfffffffffff0)
|
||||||
|
|
||||||
|
#define MAKE_PAYLOAD(x) ((uint64_t)(x) << 4)
|
||||||
|
|
||||||
|
// The bits that must be set to indicate a quiet NaN.
|
||||||
|
#define MASK_QUIETNAN ((uint64_t)0x7ffc000000000000)
|
||||||
|
|
||||||
|
// sadly this requires a bit more than a simple macro :(
|
||||||
|
static inline CosmoType GET_TYPE(CValue val) {
|
||||||
|
// it's not not a number (its a number)
|
||||||
|
if ((((val.data) & MASK_QUIETNAN) != MASK_QUIETNAN))
|
||||||
|
return COSMO_TNUMBER;
|
||||||
|
|
||||||
|
if ((((val.data) & (MASK_QUIETNAN | MASK_SIGN_BIT)) == (MASK_QUIETNAN | MASK_SIGN_BIT)))
|
||||||
|
return COSMO_TOBJ;
|
||||||
|
|
||||||
|
return (val.data & MASK_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define cosmoV_newNumber(x) ((CValue){.num = x})
|
||||||
|
#define cosmoV_newObj(x) ((CValue){.data = MASK_SIGN_BIT | MASK_QUIETNAN | (uint64_t)(uintptr_t)(x)})
|
||||||
|
#define cosmoV_newBoolean(x) ((CValue){.data = MASK_QUIETNAN | MAKE_PAYLOAD(x) | COSMO_TBOOLEAN})
|
||||||
|
#define cosmoV_newNil() ((CValue){.data = MASK_QUIETNAN | COSMO_TNIL})
|
||||||
|
|
||||||
|
#define cosmoV_readNumber(x) ((x).num)
|
||||||
|
#define cosmoV_readBoolean(x) ((bool)((x).data & MASK_PAYLOAD))
|
||||||
|
#define cosmoV_readObj(x) (((CObj*)(uintptr_t)(((x).data) & ~(MASK_SIGN_BIT | MASK_QUIETNAN))))
|
||||||
|
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
Tagged union, this is the best platform independent solution
|
||||||
|
*/
|
||||||
typedef struct CValue {
|
typedef struct CValue {
|
||||||
CosmoType type;
|
CosmoType type;
|
||||||
union {
|
union {
|
||||||
@ -23,6 +74,29 @@ typedef struct CValue {
|
|||||||
CObj *obj;
|
CObj *obj;
|
||||||
} val;
|
} val;
|
||||||
} CValue;
|
} CValue;
|
||||||
|
|
||||||
|
#define GET_TYPE(x) ((x).type)
|
||||||
|
|
||||||
|
// create CValues
|
||||||
|
|
||||||
|
#define cosmoV_newNumber(x) ((CValue){COSMO_TNUMBER, {.num = (x)}})
|
||||||
|
#define cosmoV_newBoolean(x) ((CValue){COSMO_TBOOLEAN, {.b = (x)}})
|
||||||
|
#define cosmoV_newObj(x) ((CValue){COSMO_TOBJ, {.obj = (CObj*)(x)}})
|
||||||
|
#define cosmoV_newNil() ((CValue){COSMO_TNIL, {.num = 0}})
|
||||||
|
|
||||||
|
// read CValues
|
||||||
|
|
||||||
|
#define cosmoV_readNumber(x) ((cosmo_Number)(x).val.num)
|
||||||
|
#define cosmoV_readBoolean(x) ((bool)(x).val.b)
|
||||||
|
#define cosmoV_readObj(x) ((CObj*)(x).val.obj)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IS_NUMBER(x) (GET_TYPE(x) == COSMO_TNUMBER)
|
||||||
|
#define IS_BOOLEAN(x) (GET_TYPE(x) == COSMO_TBOOLEAN)
|
||||||
|
#define IS_NIL(x) (GET_TYPE(x) == COSMO_TNIL)
|
||||||
|
#define IS_OBJ(x) (GET_TYPE(x) == COSMO_TOBJ)
|
||||||
|
|
||||||
typedef CValue* StkPtr;
|
typedef CValue* StkPtr;
|
||||||
|
|
||||||
typedef struct CValueArray {
|
typedef struct CValueArray {
|
||||||
@ -40,22 +114,4 @@ COSMO_API bool cosmoV_equal(CValue valA, CValue valB);
|
|||||||
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val);
|
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val);
|
||||||
COSMO_API const char *cosmoV_typeStr(CValue val); // return constant char array for corresponding type
|
COSMO_API const char *cosmoV_typeStr(CValue val); // return constant char array for corresponding type
|
||||||
|
|
||||||
#define IS_NUMBER(x) (x.type == COSMO_TNUMBER)
|
|
||||||
#define IS_BOOLEAN(x) (x.type == COSMO_TBOOLEAN)
|
|
||||||
#define IS_NIL(x) (x.type == COSMO_TNIL)
|
|
||||||
#define IS_OBJ(x) (x.type == COSMO_TOBJ)
|
|
||||||
|
|
||||||
// create CValues
|
|
||||||
|
|
||||||
#define cosmoV_newNumber(x) ((CValue){COSMO_TNUMBER, {.num = x}})
|
|
||||||
#define cosmoV_newBoolean(x) ((CValue){COSMO_TBOOLEAN, {.b = x}})
|
|
||||||
#define cosmoV_newObj(x) ((CValue){COSMO_TOBJ, {.obj = (CObj*)x}})
|
|
||||||
#define cosmoV_newNil() ((CValue){COSMO_TNIL, {.num = 0}})
|
|
||||||
|
|
||||||
// read CValues
|
|
||||||
|
|
||||||
#define cosmoV_readNumber(x) ((cosmo_Number)x.val.num)
|
|
||||||
#define cosmoV_readBoolean(x) ((bool)x.val.b)
|
|
||||||
#define cosmoV_readObj(x) ((CObj*)x.val.obj)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
68
src/cvm.c
68
src/cvm.c
@ -164,26 +164,26 @@ bool invokeMethod(CState* state, CObjObject *obj, CValue func, int args) {
|
|||||||
COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
||||||
StkPtr val = cosmoV_getTop(state, args); // function will always be right above the args
|
StkPtr val = cosmoV_getTop(state, args); // function will always be right above the args
|
||||||
|
|
||||||
if (val->type != COSMO_TOBJ) {
|
if (GET_TYPE(*val) != COSMO_TOBJ) {
|
||||||
cosmoV_error(state, "Cannot call non-function type %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Cannot call non-function type %s!", cosmoV_typeStr(*val));
|
||||||
return COSMOVM_RUNTIME_ERR;
|
return COSMOVM_RUNTIME_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (val->val.obj->type) {
|
switch (cosmoV_readObj(*val)->type) {
|
||||||
case COBJ_CLOSURE: {
|
case COBJ_CLOSURE: {
|
||||||
CObjClosure *closure = (CObjClosure*)(val->val.obj);
|
CObjClosure *closure = (CObjClosure*)cosmoV_readObj(*val);
|
||||||
if (!call(state, closure, args, 0)) {
|
if (!call(state, closure, args, 0)) {
|
||||||
return COSMOVM_RUNTIME_ERR;
|
return COSMOVM_RUNTIME_ERR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_METHOD: {
|
case COBJ_METHOD: {
|
||||||
CObjMethod *method = (CObjMethod*)val->val.obj;
|
CObjMethod *method = (CObjMethod*)cosmoV_readObj(*val);
|
||||||
invokeMethod(state, method->obj, method->func, args);
|
invokeMethod(state, method->obj, method->func, args);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_OBJECT: {
|
case COBJ_OBJECT: {
|
||||||
CObjObject *protoObj = (CObjObject*)val->val.obj;
|
CObjObject *protoObj = (CObjObject*)cosmoV_readObj(*val);
|
||||||
CObjObject *newObj = cosmoO_newObject(state);
|
CObjObject *newObj = cosmoO_newObject(state);
|
||||||
newObj->proto = protoObj;
|
newObj->proto = protoObj;
|
||||||
CValue ret;
|
CValue ret;
|
||||||
@ -205,7 +205,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
|||||||
}
|
}
|
||||||
case COBJ_CFUNCTION: {
|
case COBJ_CFUNCTION: {
|
||||||
// it's a C function, so call it
|
// it's a C function, so call it
|
||||||
CosmoCFunction cfunc = ((CObjCFunction*)(val->val.obj))->cfunc;
|
CosmoCFunction cfunc = ((CObjCFunction*)cosmoV_readObj(*val))->cfunc;
|
||||||
callCFunction(state, cfunc, args, 0);
|
callCFunction(state, cfunc, args, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -218,7 +218,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isFalsey(StkPtr val) {
|
static inline bool isFalsey(StkPtr val) {
|
||||||
return val->type == COSMO_TNIL || (val->type == COSMO_TBOOLEAN && !val->val.b);
|
return IS_NIL(*val) || (IS_BOOLEAN(*val) && !cosmoV_readBoolean(*val));
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API void cosmoV_pushObject(CState *state, int pairs) {
|
COSMO_API void cosmoV_pushObject(CState *state, int pairs) {
|
||||||
@ -242,12 +242,12 @@ COSMO_API void cosmoV_pushObject(CState *state, int pairs) {
|
|||||||
|
|
||||||
COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val) {
|
COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val) {
|
||||||
if (cosmoO_getObject(state, object, key, val)) {
|
if (cosmoO_getObject(state, object, key, val)) {
|
||||||
if (val->type == COSMO_TOBJ ) {
|
if (IS_OBJ(*val)) {
|
||||||
if (val->val.obj->type == COBJ_CLOSURE) { // is it a function? if so, make it a method to the current object
|
if (cosmoV_readObj(*val)->type == COBJ_CLOSURE) { // is it a function? if so, make it a method to the current object
|
||||||
CObjMethod *method = cosmoO_newMethod(state, (CObjClosure*)val->val.obj, object);
|
CObjMethod *method = cosmoO_newMethod(state, (CObjClosure*)cosmoV_readObj(*val), object);
|
||||||
*val = cosmoV_newObj(method);
|
*val = cosmoV_newObj(method);
|
||||||
} else if (val->val.obj->type == COBJ_CFUNCTION) {
|
} else if (cosmoV_readObj(*val)->type == COBJ_CFUNCTION) {
|
||||||
CObjMethod *method = cosmoO_newCMethod(state, (CObjCFunction*)val->val.obj, object);
|
CObjMethod *method = cosmoO_newCMethod(state, (CObjCFunction*)cosmoV_readObj(*val), object);
|
||||||
*val = cosmoV_newObj(method);
|
*val = cosmoV_newObj(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,9 +261,9 @@ COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, C
|
|||||||
#define NUMBEROP(typeConst, op) \
|
#define NUMBEROP(typeConst, op) \
|
||||||
StkPtr valA = cosmoV_getTop(state, 1); \
|
StkPtr valA = cosmoV_getTop(state, 1); \
|
||||||
StkPtr valB = cosmoV_getTop(state, 0); \
|
StkPtr valB = cosmoV_getTop(state, 0); \
|
||||||
if (valA->type == COSMO_TNUMBER && valB->type == COSMO_TNUMBER) { \
|
if (IS_NUMBER(*valA) && IS_NUMBER(*valB)) { \
|
||||||
cosmoV_setTop(state, 2); /* pop the 2 values */ \
|
cosmoV_setTop(state, 2); /* pop the 2 values */ \
|
||||||
cosmoV_pushValue(state, typeConst((valA->val.num) op (valB->val.num))); \
|
cosmoV_pushValue(state, typeConst(cosmoV_readNumber(*valA) op cosmoV_readNumber(*valB))); \
|
||||||
} else { \
|
} else { \
|
||||||
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA), cosmoV_typeStr(*valB)); \
|
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA), cosmoV_typeStr(*valB)); \
|
||||||
} \
|
} \
|
||||||
@ -393,12 +393,12 @@ bool cosmoV_execute(CState *state) {
|
|||||||
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the object
|
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the object
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) {
|
if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
|
||||||
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjObject *object = (CObjObject*)temp->val.obj;
|
CObjObject *object = (CObjObject*)cosmoV_readObj(*temp);
|
||||||
CValue val; // to hold our value
|
CValue val; // to hold our value
|
||||||
|
|
||||||
cosmoV_getObject(state, object, *key, &val);
|
cosmoV_getObject(state, object, *key, &val);
|
||||||
@ -412,12 +412,12 @@ bool cosmoV_execute(CState *state) {
|
|||||||
StkPtr temp = cosmoV_getTop(state, 2); // object is after the key
|
StkPtr temp = cosmoV_getTop(state, 2); // object is after the key
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) {
|
if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
|
||||||
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjObject *object = (CObjObject*)temp->val.obj;
|
CObjObject *object = (CObjObject*)cosmoV_readObj(*temp);
|
||||||
cosmoO_setObject(state, object, *key, *value);
|
cosmoO_setObject(state, object, *key, *value);
|
||||||
|
|
||||||
// pop everything off the stack
|
// pop everything off the stack
|
||||||
@ -430,12 +430,12 @@ bool cosmoV_execute(CState *state) {
|
|||||||
StkPtr temp = cosmoV_getTop(state, args+1); // grabs object from stack
|
StkPtr temp = cosmoV_getTop(state, args+1); // grabs object from stack
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) {
|
if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
|
||||||
cosmoV_error(state, "Couldn't get from non-object type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't get from non-object type %s!", cosmoV_typeStr(*temp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjObject *object = (CObjObject*)temp->val.obj;
|
CObjObject *object = (CObjObject*)cosmoV_readObj(*temp);
|
||||||
CValue val; // to hold our value
|
CValue val; // to hold our value
|
||||||
|
|
||||||
cosmoO_getObject(state, object, *key, &val); // we use cosmoO_getObject instead of the cosmoV_getObject wrapper so we get the raw value from the object instead of the CObjMethod wrapper
|
cosmoO_getObject(state, object, *key, &val); // we use cosmoO_getObject instead of the cosmoV_getObject wrapper so we get the raw value from the object instead of the CObjMethod wrapper
|
||||||
@ -471,9 +471,9 @@ bool cosmoV_execute(CState *state) {
|
|||||||
case OP_NEGATE: { // pop 1 value off the stack & try to negate
|
case OP_NEGATE: { // pop 1 value off the stack & try to negate
|
||||||
StkPtr val = cosmoV_getTop(state, 0);
|
StkPtr val = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
if (val->type == COSMO_TNUMBER) {
|
if (IS_NUMBER(*val)) {
|
||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
cosmoV_pushNumber(state, -(val->val.num));
|
cosmoV_pushNumber(state, -(cosmoV_readNumber(*val)));
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
}
|
}
|
||||||
@ -482,12 +482,12 @@ bool cosmoV_execute(CState *state) {
|
|||||||
case OP_COUNT: { // pop 1 value off the stack & if it's an object return the ammount of active entries it has
|
case OP_COUNT: { // pop 1 value off the stack & if it's an object return the ammount of active entries it has
|
||||||
StkPtr temp = cosmoV_getTop(state, 0);
|
StkPtr temp = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
if (temp->type != COSMO_TOBJ || ((CObj*)temp->val.obj)->type != COBJ_OBJECT) {
|
if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
|
||||||
cosmoV_error(state, "Expected object, got %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Expected object, got %s!", cosmoV_typeStr(*temp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjObject *obj = (CObjObject*)temp->val.obj;
|
CObjObject *obj = (CObjObject*)cosmoV_readObj(*temp);
|
||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
cosmoV_pushNumber(state, cosmoT_count(&obj->tbl)); // pushes the count onto the stack
|
cosmoV_pushNumber(state, cosmoT_count(&obj->tbl)); // pushes the count onto the stack
|
||||||
break;
|
break;
|
||||||
@ -517,9 +517,9 @@ bool cosmoV_execute(CState *state) {
|
|||||||
StkPtr val = &frame->base[indx];
|
StkPtr val = &frame->base[indx];
|
||||||
|
|
||||||
// check that it's a number value
|
// check that it's a number value
|
||||||
if (val->type == COSMO_TNUMBER) {
|
if (IS_NUMBER(*val)) {
|
||||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||||
*val = cosmoV_newNumber(val->val.num + inc);
|
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
}
|
}
|
||||||
@ -533,9 +533,9 @@ bool cosmoV_execute(CState *state) {
|
|||||||
CValue *val = cosmoT_insert(state, &state->globals, ident);
|
CValue *val = cosmoT_insert(state, &state->globals, ident);
|
||||||
|
|
||||||
// check that it's a number value
|
// check that it's a number value
|
||||||
if (val->type == COSMO_TNUMBER) {
|
if (IS_NUMBER(*val)) {
|
||||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||||
*val = cosmoV_newNumber(val->val.num + inc);
|
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
}
|
}
|
||||||
@ -548,9 +548,9 @@ bool cosmoV_execute(CState *state) {
|
|||||||
CValue *val = frame->closure->upvalues[indx]->val;
|
CValue *val = frame->closure->upvalues[indx]->val;
|
||||||
|
|
||||||
// check that it's a number value
|
// check that it's a number value
|
||||||
if (val->type == COSMO_TNUMBER) {
|
if (IS_NUMBER(*val)) {
|
||||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||||
*val = cosmoV_newNumber(val->val.num + inc);
|
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
}
|
}
|
||||||
@ -564,21 +564,21 @@ bool cosmoV_execute(CState *state) {
|
|||||||
CValue ident = constants[indx]; // grabs identifier
|
CValue ident = constants[indx]; // grabs identifier
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) {
|
if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
|
||||||
cosmoV_error(state, "Couldn't set a field on non-object type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't set a field on non-object type %s!", cosmoV_typeStr(*temp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjObject *object = (CObjObject*)temp->val.obj;
|
CObjObject *object = (CObjObject*)cosmoV_readObj(*temp);
|
||||||
CValue *val = cosmoT_insert(state, &object->tbl, ident);
|
CValue *val = cosmoT_insert(state, &object->tbl, ident);
|
||||||
|
|
||||||
// pop the object off the stack
|
// pop the object off the stack
|
||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
|
|
||||||
// check that it's a number value
|
// check that it's a number value
|
||||||
if (val->type == COSMO_TNUMBER) {
|
if (IS_NUMBER(*val)) {
|
||||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||||
*val = cosmoV_newNumber(val->val.num + inc);
|
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user