mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-05 08:10: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
|
# make clean && make && ./bin/cosmo
|
||||||
|
|
||||||
CC=clang
|
CC=clang
|
||||||
CFLAGS=-fPIE -O3 #-g3
|
CFLAGS=-fPIE -g3 #-O3
|
||||||
LDFLAGS=#-fsanitize=address
|
LDFLAGS=-fsanitize=address
|
||||||
OUT=bin/cosmo
|
OUT=bin/cosmo
|
||||||
|
|
||||||
CHDR=\
|
CHDR=\
|
||||||
|
@ -116,6 +116,12 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
|
|||||||
}
|
}
|
||||||
case OP_CLOSE:
|
case OP_CLOSE:
|
||||||
return simpleInstruction("OP_CLOSE", offset);
|
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:
|
case OP_ADD:
|
||||||
return simpleInstruction("OP_ADD", offset);
|
return simpleInstruction("OP_ADD", offset);
|
||||||
case OP_SUB:
|
case OP_SUB:
|
||||||
|
@ -80,7 +80,7 @@ void markArray(CState *state, CValueArray *array) {
|
|||||||
void blackenObject(CState *state, CObj *obj) {
|
void blackenObject(CState *state, CObj *obj) {
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case COBJ_STRING:
|
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:
|
case COBJ_CFUNCTION:
|
||||||
// stubbed
|
// stubbed
|
||||||
break;
|
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);
|
cosmoM_free(state, CObjString, objStr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_TABLE: {
|
case COBJ_OBJECT: {
|
||||||
CObjTable *objTbl = (CObjTable*)obj;
|
CObjObject *objTbl = (CObjObject*)obj;
|
||||||
cosmoT_clearTable(state, &objTbl->tbl);
|
cosmoT_clearTable(state, &objTbl->tbl);
|
||||||
cosmoM_free(state, CObjTable, objTbl);
|
cosmoM_free(state, CObjObject, objTbl);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_UPVALUE: {
|
case COBJ_UPVALUE: {
|
||||||
@ -88,10 +88,10 @@ bool cosmoO_equalObject(CObj* obj1, CObj* obj2) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjTable *cosmoO_newTable(CState *state) {
|
CObjObject *cosmoO_newObject(CState *state, int startCap) {
|
||||||
CObjTable *tbl = (CObjTable*)cosmoO_allocateObject(state, sizeof(CObjTable), COBJ_TABLE);
|
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;
|
return tbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,9 +188,9 @@ CObjString *cosmoO_toString(CState *state, CObj *val) {
|
|||||||
CObjFunction *func = (CObjFunction*)val;
|
CObjFunction *func = (CObjFunction*)val;
|
||||||
return func->name != NULL ? func->name : cosmoO_copyString(state, UNNAMEDCHUNK, strlen(UNNAMEDCHUNK));
|
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];
|
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);
|
return cosmoO_copyString(state, buf, sz);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -205,8 +205,8 @@ void printObject(CObj *o) {
|
|||||||
printf("\"%.*s\"", objStr->length, objStr->str);
|
printf("\"%.*s\"", objStr->length, objStr->str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_TABLE: {
|
case COBJ_OBJECT: {
|
||||||
printf("<tbl> %p", o);
|
printf("<obj> %p", o);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case COBJ_UPVALUE: {
|
case COBJ_UPVALUE: {
|
||||||
|
14
src/cobj.h
14
src/cobj.h
@ -10,7 +10,7 @@ typedef struct CState CState;
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
COBJ_STRING,
|
COBJ_STRING,
|
||||||
COBJ_TABLE,
|
COBJ_OBJECT,
|
||||||
COBJ_FUNCTION,
|
COBJ_FUNCTION,
|
||||||
COBJ_CFUNCTION,
|
COBJ_CFUNCTION,
|
||||||
// internal use
|
// internal use
|
||||||
@ -35,11 +35,11 @@ typedef struct CObjString {
|
|||||||
uint32_t hash; // for hashtable lookup
|
uint32_t hash; // for hashtable lookup
|
||||||
} CObjString;
|
} CObjString;
|
||||||
|
|
||||||
typedef struct CObjTable {
|
typedef struct CObjObject {
|
||||||
CommonHeader; // "is a" CObj
|
CommonHeader; // "is a" CObj
|
||||||
CTable tbl;
|
CTable tbl;
|
||||||
//struct CObjTable *meta; // metatable, used to describe table behavior
|
//struct CObjObject *meta; // metaobject, used to describe object behavior
|
||||||
} CObjTable;
|
} CObjObject;
|
||||||
|
|
||||||
typedef struct CObjFunction {
|
typedef struct CObjFunction {
|
||||||
CommonHeader; // "is a" CObj
|
CommonHeader; // "is a" CObj
|
||||||
@ -69,13 +69,13 @@ typedef struct CObjUpval {
|
|||||||
} CObjUpval;
|
} CObjUpval;
|
||||||
|
|
||||||
#define IS_STRING(x) isObjType(x, COBJ_STRING)
|
#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_FUNCTION(x) isObjType(x, COBJ_FUNCTION)
|
||||||
#define IS_CFUNCTION(x) isObjType(x, COBJ_CFUNCTION)
|
#define IS_CFUNCTION(x) isObjType(x, COBJ_CFUNCTION)
|
||||||
#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_readTable(x) ((CObjTable*)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_readClosure(x) ((CObjClosure*)cosmoV_readObj(x))
|
#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);
|
bool cosmoO_equalObject(CObj* obj1, CObj* obj2);
|
||||||
|
|
||||||
CObjTable *cosmoO_newTable(CState *state);
|
CObjObject *cosmoO_newObject(CState *state, int startCap);
|
||||||
CObjFunction *cosmoO_newFunction(CState *state);
|
CObjFunction *cosmoO_newFunction(CState *state);
|
||||||
CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func);
|
CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func);
|
||||||
CObjClosure *cosmoO_newClosure(CState *state, CObjFunction *func);
|
CObjClosure *cosmoO_newClosure(CState *state, CObjFunction *func);
|
||||||
|
@ -29,6 +29,9 @@ typedef enum {
|
|||||||
OP_CALL, // calls top[-uint8_t]
|
OP_CALL, // calls top[-uint8_t]
|
||||||
OP_CLOSURE,
|
OP_CLOSURE,
|
||||||
OP_CLOSE,
|
OP_CLOSE,
|
||||||
|
OP_NEWOBJECT,
|
||||||
|
OP_GETOBJECT,
|
||||||
|
OP_SETOBJECT,
|
||||||
|
|
||||||
// ARITHMETIC
|
// ARITHMETIC
|
||||||
OP_ADD,
|
OP_ADD,
|
||||||
|
33
src/cparse.c
33
src/cparse.c
@ -30,6 +30,7 @@ typedef enum {
|
|||||||
PREC_TERM, // + -
|
PREC_TERM, // + -
|
||||||
PREC_FACTOR, // * /
|
PREC_FACTOR, // * /
|
||||||
PREC_UNARY, // ! -
|
PREC_UNARY, // ! -
|
||||||
|
PREC_OBJ, // {}
|
||||||
PREC_CALL, // . ()
|
PREC_CALL, // . ()
|
||||||
PREC_PRIMARY // everything else
|
PREC_PRIMARY // everything else
|
||||||
} Precedence;
|
} 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[] = {
|
ParseRule ruleTable[] = {
|
||||||
[TOKEN_LEFT_PAREN] = {group, call_, PREC_CALL},
|
[TOKEN_LEFT_PAREN] = {group, call_, PREC_CALL},
|
||||||
[TOKEN_RIGHT_PAREN] = {NULL, NULL, PREC_NONE},
|
[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_RIGHT_BRACE] = {NULL, NULL, PREC_NONE},
|
||||||
[TOKEN_COMMA] = {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_DOT_DOT] = {NULL, concat, PREC_CONCAT},
|
||||||
[TOKEN_MINUS] = {unary, binary, PREC_TERM},
|
[TOKEN_MINUS] = {unary, binary, PREC_TERM},
|
||||||
[TOKEN_PLUS] = {NULL, binary, PREC_TERM},
|
[TOKEN_PLUS] = {NULL, binary, PREC_TERM},
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
#define MAX_TABLE_FILL 0.75
|
#define MAX_TABLE_FILL 0.75
|
||||||
|
|
||||||
void cosmoT_initTable(CState *state, CTable *tbl, int startCap) {
|
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->count = 0;
|
||||||
tbl->table = NULL; // to let out GC know we're initalizing
|
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
|
// 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].key = cosmoV_newNil();
|
||||||
tbl->table[i].val = 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);
|
cosmoV_pop(state);
|
||||||
break;
|
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
|
case OP_ADD: { // pop 2 values off the stack & try to add them together
|
||||||
BINARYOP(cosmoV_newNumber, +);
|
BINARYOP(cosmoV_newNumber, +);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user