mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-12-22 14:30:05 +00:00
added basic objects
This commit is contained in:
parent
fe93a0b715
commit
e1d33855c3
4
Makefile
4
Makefile
@ -1,8 +1,8 @@
|
||||
# make clean && make && ./bin/cosmo
|
||||
|
||||
CC=clang
|
||||
CFLAGS=-fPIE -O3 #-g3
|
||||
LDFLAGS=#-fsanitize=address
|
||||
CFLAGS=-fPIE -g3 #-O3
|
||||
LDFLAGS=-fsanitize=address
|
||||
OUT=bin/cosmo
|
||||
|
||||
CHDR=\
|
||||
|
@ -116,6 +116,12 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
|
||||
}
|
||||
case OP_CLOSE:
|
||||
return simpleInstruction("OP_CLOSE", offset);
|
||||
case OP_NEWOBJECT:
|
||||
return shortOperandInstruction("OP_NEWOBJECT", chunk, offset);
|
||||
case OP_GETOBJECT:
|
||||
return simpleInstruction("OP_GETOBJECT", offset);
|
||||
case OP_SETOBJECT:
|
||||
return simpleInstruction("OP_SETOBJECT", offset);
|
||||
case OP_ADD:
|
||||
return simpleInstruction("OP_ADD", offset);
|
||||
case OP_SUB:
|
||||
|
@ -80,7 +80,7 @@ void markArray(CState *state, CValueArray *array) {
|
||||
void blackenObject(CState *state, CObj *obj) {
|
||||
switch (obj->type) {
|
||||
case COBJ_STRING:
|
||||
case COBJ_TABLE: // TODO: when metatables are added, make sure they're marked
|
||||
case COBJ_OBJECT: // TODO: when metatables are added, make sure they're marked
|
||||
case COBJ_CFUNCTION:
|
||||
// stubbed
|
||||
break;
|
||||
|
20
src/cobj.c
20
src/cobj.c
@ -42,10 +42,10 @@ void cosmoO_freeObject(CState *state, CObj* obj) {
|
||||
cosmoM_free(state, CObjString, objStr);
|
||||
break;
|
||||
}
|
||||
case COBJ_TABLE: {
|
||||
CObjTable *objTbl = (CObjTable*)obj;
|
||||
case COBJ_OBJECT: {
|
||||
CObjObject *objTbl = (CObjObject*)obj;
|
||||
cosmoT_clearTable(state, &objTbl->tbl);
|
||||
cosmoM_free(state, CObjTable, objTbl);
|
||||
cosmoM_free(state, CObjObject, objTbl);
|
||||
break;
|
||||
}
|
||||
case COBJ_UPVALUE: {
|
||||
@ -88,10 +88,10 @@ bool cosmoO_equalObject(CObj* obj1, CObj* obj2) {
|
||||
}
|
||||
}
|
||||
|
||||
CObjTable *cosmoO_newTable(CState *state) {
|
||||
CObjTable *tbl = (CObjTable*)cosmoO_allocateObject(state, sizeof(CObjTable), COBJ_TABLE);
|
||||
CObjObject *cosmoO_newObject(CState *state, int startCap) {
|
||||
CObjObject *tbl = (CObjObject*)cosmoO_allocateObject(state, sizeof(CObjObject), COBJ_OBJECT);
|
||||
|
||||
cosmoT_initTable(state, &tbl->tbl, 8); // start the table at 8
|
||||
cosmoT_initTable(state, &tbl->tbl, startCap);
|
||||
return tbl;
|
||||
}
|
||||
|
||||
@ -188,9 +188,9 @@ CObjString *cosmoO_toString(CState *state, CObj *val) {
|
||||
CObjFunction *func = (CObjFunction*)val;
|
||||
return func->name != NULL ? func->name : cosmoO_copyString(state, UNNAMEDCHUNK, strlen(UNNAMEDCHUNK));
|
||||
}
|
||||
case COBJ_TABLE: { // TODO: maybe not safe??
|
||||
case COBJ_OBJECT: { // TODO: maybe not safe??
|
||||
char buf[64];
|
||||
int sz = sprintf(buf, "<tbl> %p", val) + 1; // +1 for the null character
|
||||
int sz = sprintf(buf, "<obj> %p", val) + 1; // +1 for the null character
|
||||
return cosmoO_copyString(state, buf, sz);
|
||||
}
|
||||
default:
|
||||
@ -205,8 +205,8 @@ void printObject(CObj *o) {
|
||||
printf("\"%.*s\"", objStr->length, objStr->str);
|
||||
break;
|
||||
}
|
||||
case COBJ_TABLE: {
|
||||
printf("<tbl> %p", o);
|
||||
case COBJ_OBJECT: {
|
||||
printf("<obj> %p", o);
|
||||
return;
|
||||
}
|
||||
case COBJ_UPVALUE: {
|
||||
|
14
src/cobj.h
14
src/cobj.h
@ -10,7 +10,7 @@ typedef struct CState CState;
|
||||
|
||||
typedef enum {
|
||||
COBJ_STRING,
|
||||
COBJ_TABLE,
|
||||
COBJ_OBJECT,
|
||||
COBJ_FUNCTION,
|
||||
COBJ_CFUNCTION,
|
||||
// internal use
|
||||
@ -35,11 +35,11 @@ typedef struct CObjString {
|
||||
uint32_t hash; // for hashtable lookup
|
||||
} CObjString;
|
||||
|
||||
typedef struct CObjTable {
|
||||
typedef struct CObjObject {
|
||||
CommonHeader; // "is a" CObj
|
||||
CTable tbl;
|
||||
//struct CObjTable *meta; // metatable, used to describe table behavior
|
||||
} CObjTable;
|
||||
//struct CObjObject *meta; // metaobject, used to describe object behavior
|
||||
} CObjObject;
|
||||
|
||||
typedef struct CObjFunction {
|
||||
CommonHeader; // "is a" CObj
|
||||
@ -69,13 +69,13 @@ typedef struct CObjUpval {
|
||||
} CObjUpval;
|
||||
|
||||
#define IS_STRING(x) isObjType(x, COBJ_STRING)
|
||||
#define IS_TABLE(x) isObjType(x, COBJ_TABLE)
|
||||
#define IS_TABLE(x) isObjType(x, COBJ_OBJECT)
|
||||
#define IS_FUNCTION(x) isObjType(x, COBJ_FUNCTION)
|
||||
#define IS_CFUNCTION(x) isObjType(x, COBJ_CFUNCTION)
|
||||
#define IS_CLOSURE(x) isObjType(x, COBJ_CLOSURE)
|
||||
|
||||
#define cosmoV_readString(x) ((CObjString*)cosmoV_readObj(x))
|
||||
#define cosmoV_readTable(x) ((CObjTable*)cosmoV_readObj(x))
|
||||
#define cosmoV_readObject(x) ((CObjObject*)cosmoV_readObj(x))
|
||||
#define cosmoV_readFunction(x) ((CObjFunction*)cosmoV_readObj(x))
|
||||
#define cosmoV_readCFunction(x) (((CObjCFunction*)cosmoV_readObj(x))->cfunc)
|
||||
#define cosmoV_readClosure(x) ((CObjClosure*)cosmoV_readObj(x))
|
||||
@ -89,7 +89,7 @@ void cosmoO_freeObject(CState *state, CObj* obj);
|
||||
|
||||
bool cosmoO_equalObject(CObj* obj1, CObj* obj2);
|
||||
|
||||
CObjTable *cosmoO_newTable(CState *state);
|
||||
CObjObject *cosmoO_newObject(CState *state, int startCap);
|
||||
CObjFunction *cosmoO_newFunction(CState *state);
|
||||
CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func);
|
||||
CObjClosure *cosmoO_newClosure(CState *state, CObjFunction *func);
|
||||
|
@ -29,6 +29,9 @@ typedef enum {
|
||||
OP_CALL, // calls top[-uint8_t]
|
||||
OP_CLOSURE,
|
||||
OP_CLOSE,
|
||||
OP_NEWOBJECT,
|
||||
OP_GETOBJECT,
|
||||
OP_SETOBJECT,
|
||||
|
||||
// ARITHMETIC
|
||||
OP_ADD,
|
||||
|
33
src/cparse.c
33
src/cparse.c
@ -30,6 +30,7 @@ typedef enum {
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * /
|
||||
PREC_UNARY, // ! -
|
||||
PREC_OBJ, // {}
|
||||
PREC_CALL, // . ()
|
||||
PREC_PRIMARY // everything else
|
||||
} Precedence;
|
||||
@ -502,13 +503,41 @@ static void call_(CParseState *pstate, bool canAssign) {
|
||||
}
|
||||
}
|
||||
|
||||
static void object(CParseState *pstate, bool canAssign) {
|
||||
// already consumed the beginning '{'
|
||||
int entries = 0;
|
||||
|
||||
consume(pstate, TOKEN_RIGHT_BRACE, "Expected '}' to end object definition!");
|
||||
|
||||
writeu8(pstate, OP_NEWOBJECT);
|
||||
writeu8(pstate, entries);
|
||||
valuePushed(pstate, 1);
|
||||
}
|
||||
|
||||
static void dot(CParseState *pstate, bool canAssign) {
|
||||
consume(pstate, TOKEN_IDENTIFIER, "Expect property name after '.'.");
|
||||
uint8_t name = identifierConstant(pstate, &pstate->previous);
|
||||
writeu8(pstate, OP_LOADCONST);
|
||||
writeu16(pstate, name);
|
||||
valuePushed(pstate, 1);
|
||||
|
||||
if (canAssign && match(pstate, TOKEN_EQUAL)) {
|
||||
expression(pstate);
|
||||
writeu8(pstate, OP_SETOBJECT);
|
||||
valuePopped(pstate, 3); // pops key, value & object
|
||||
} else {
|
||||
writeu8(pstate, OP_GETOBJECT);
|
||||
valuePopped(pstate, 1); // pops key & object but also pushes the field so total popped is 1
|
||||
}
|
||||
}
|
||||
|
||||
ParseRule ruleTable[] = {
|
||||
[TOKEN_LEFT_PAREN] = {group, call_, PREC_CALL},
|
||||
[TOKEN_RIGHT_PAREN] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_LEFT_BRACE] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_LEFT_BRACE] = {object, NULL, PREC_OBJ},
|
||||
[TOKEN_RIGHT_BRACE] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_COMMA] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_DOT] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_DOT] = {NULL, dot, PREC_CALL},
|
||||
[TOKEN_DOT_DOT] = {NULL, concat, PREC_CONCAT},
|
||||
[TOKEN_MINUS] = {unary, binary, PREC_TERM},
|
||||
[TOKEN_PLUS] = {NULL, binary, PREC_TERM},
|
||||
|
@ -8,13 +8,13 @@
|
||||
#define MAX_TABLE_FILL 0.75
|
||||
|
||||
void cosmoT_initTable(CState *state, CTable *tbl, int startCap) {
|
||||
tbl->capacity = startCap;
|
||||
tbl->capacity = startCap != 0 ? startCap : ARRAY_START; // sanity check :P
|
||||
tbl->count = 0;
|
||||
tbl->table = NULL; // to let out GC know we're initalizing
|
||||
tbl->table = cosmoM_xmalloc(state, sizeof(CTableEntry) * startCap);
|
||||
tbl->table = cosmoM_xmalloc(state, sizeof(CTableEntry) * tbl->capacity);
|
||||
|
||||
// init everything to NIL
|
||||
for (int i = 0; i < startCap; i++) {
|
||||
for (int i = 0; i < tbl->capacity; i++) {
|
||||
tbl->table[i].key = cosmoV_newNil();
|
||||
tbl->table[i].val = cosmoV_newNil();
|
||||
}
|
||||
|
57
src/cvm.c
57
src/cvm.c
@ -317,6 +317,63 @@ int cosmoV_execute(CState *state) {
|
||||
cosmoV_pop(state);
|
||||
break;
|
||||
}
|
||||
case OP_NEWOBJECT: {
|
||||
uint8_t entries = READBYTE();
|
||||
StkPtr key, val;
|
||||
CObjObject *newObj = cosmoO_newObject(state, entries * 3); // start the table with enough space to hopefully prevent reallocation since that's costly
|
||||
cosmoV_pushValue(state, cosmoV_newObj(newObj)); // so our GC doesn't free our new object
|
||||
|
||||
for (int i = 0; i < entries; i++) {
|
||||
val = cosmoV_getTop(state, (i*2) + 2);
|
||||
key = cosmoV_getTop(state, (i*2) + 1);
|
||||
|
||||
// set key/value pair
|
||||
CValue *newVal = cosmoT_insert(state, &newObj->tbl, *key);
|
||||
*newVal = *val;
|
||||
}
|
||||
|
||||
// once done, pop everything off the stack + push new object
|
||||
cosmoV_setTop(state, (entries * 2) + 1);
|
||||
cosmoV_pushValue(state, cosmoV_newObj(newObj));
|
||||
break;
|
||||
}
|
||||
case OP_GETOBJECT: {
|
||||
StkPtr key = cosmoV_getTop(state, 0); // key should be the top of the stack
|
||||
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the object
|
||||
|
||||
// sanity check
|
||||
if (!(temp->type == COSMO_TOBJ) || !(temp->val.obj->type == COBJ_OBJECT)) {
|
||||
runtimeError(state, "Couldn't get from non-object!");
|
||||
break;
|
||||
}
|
||||
|
||||
CObjObject *object = (CObjObject*)temp->val.obj;
|
||||
CValue val; // to hold our value
|
||||
|
||||
cosmoT_get(&object->tbl, *key, &val);
|
||||
cosmoV_setTop(state, 2); // pops the object & the key
|
||||
cosmoV_pushValue(state, val); // pushes the field result
|
||||
break;
|
||||
}
|
||||
case OP_SETOBJECT: {
|
||||
StkPtr value = cosmoV_getTop(state, 0); // value is at the top of the stack
|
||||
StkPtr key = cosmoV_getTop(state, 1);
|
||||
StkPtr temp = cosmoV_getTop(state, 2); // object is after the key
|
||||
|
||||
// sanity check
|
||||
if (!(temp->type == COSMO_TOBJ) || !(temp->val.obj->type == COBJ_OBJECT)) {
|
||||
runtimeError(state, "Couldn't set a field on a non-object!");
|
||||
break;
|
||||
}
|
||||
|
||||
CObjObject *object = (CObjObject*)temp->val.obj;
|
||||
CValue *newVal = cosmoT_insert(state, &object->tbl, *key);
|
||||
*newVal = *value;
|
||||
|
||||
// pop everything off the stack
|
||||
cosmoV_setTop(state, 3);
|
||||
break;
|
||||
}
|
||||
case OP_ADD: { // pop 2 values off the stack & try to add them together
|
||||
BINARYOP(cosmoV_newNumber, +);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user