mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-12-22 22:40:03 +00:00
added # operator, improved error messages
This commit is contained in:
parent
9dcd1c909a
commit
08c640cd58
@ -154,6 +154,8 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
|
||||
return simpleInstruction("OP_LESS_EQUAL", offset);
|
||||
case OP_NEGATE:
|
||||
return simpleInstruction("OP_NEGATE", offset);
|
||||
case OP_COUNT:
|
||||
return simpleInstruction("OP_COUNT", offset);
|
||||
case OP_CONCAT:
|
||||
return u8OperandInstruction("OP_CONCAT", chunk, offset);
|
||||
case OP_INCLOCAL:
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
CReservedWord reservedWords[] = {
|
||||
{TOKEN_AND, "and", 3},
|
||||
{TOKEN_CLASS, "class", 5},
|
||||
{TOKEN_DO, "do", 2},
|
||||
{TOKEN_ELSE, "else", 4},
|
||||
{TOKEN_ELSEIF, "elseif", 6},
|
||||
@ -12,7 +13,6 @@ CReservedWord reservedWords[] = {
|
||||
{TOKEN_FALSE, "false", 5},
|
||||
{TOKEN_FOR, "for", 3},
|
||||
{TOKEN_FUNCTION, "function", 8},
|
||||
{TOKEN_CLASS, "class", 5},
|
||||
{TOKEN_IF, "if", 2},
|
||||
{TOKEN_LOCAL, "local", 5},
|
||||
{TOKEN_NIL, "nil", 3},
|
||||
@ -304,6 +304,7 @@ CToken cosmoL_scanToken(CLexState *state) {
|
||||
case ';': return makeToken(state, TOKEN_EOS);
|
||||
case ',': return makeToken(state, TOKEN_COMMA);
|
||||
case '*': return makeToken(state, TOKEN_STAR);
|
||||
case '#': return makeToken(state, TOKEN_POUND);
|
||||
case '/': return makeToken(state, TOKEN_SLASH);
|
||||
// two character tokens
|
||||
case '+':
|
||||
|
@ -20,6 +20,7 @@ typedef enum {
|
||||
TOKEN_PLUS_PLUS,
|
||||
TOKEN_SLASH,
|
||||
TOKEN_STAR,
|
||||
TOKEN_POUND,
|
||||
TOKEN_EOS, // end of statement
|
||||
|
||||
// equality operators
|
||||
|
@ -50,7 +50,6 @@ COSMO_API bool cosmoM_checkGarbage(CState *state, size_t needed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void markObject(CState *state, CObj *obj);
|
||||
void markValue(CState *state, CValue val);
|
||||
|
||||
|
15
src/cobj.c
15
src/cobj.c
@ -326,4 +326,19 @@ void printObject(CObj *o) {
|
||||
default:
|
||||
printf("<unkn obj>");
|
||||
}
|
||||
}
|
||||
|
||||
const char *cosmoO_typeStr(CObj* obj) {
|
||||
switch (obj->type) {
|
||||
case COBJ_STRING: return "<string>";
|
||||
case COBJ_OBJECT: return "<object>";
|
||||
case COBJ_FUNCTION: return "<function>";
|
||||
case COBJ_CFUNCTION: return "<c function>";
|
||||
case COBJ_METHOD: return "<method>";
|
||||
case COBJ_CLOSURE: return "<closure>";
|
||||
case COBJ_UPVALUE: return "<upvalue>";
|
||||
|
||||
default:
|
||||
return "<unkn obj>"; // TODO: maybe panic? could be a malformed object :eyes:
|
||||
}
|
||||
}
|
@ -129,6 +129,7 @@ CObjString *cosmoO_takeString(CState *state, char *str, size_t sz);
|
||||
CObjString *cosmoO_allocateString(CState *state, const char *str, size_t sz, uint32_t hash);
|
||||
|
||||
COSMO_API void printObject(CObj *o);
|
||||
const char *cosmoO_typeStr(CObj* obj);
|
||||
|
||||
#define cosmoO_readCString(x) ((CObjString*)x)->str
|
||||
|
||||
|
@ -41,6 +41,7 @@ typedef enum {
|
||||
OP_DIV,
|
||||
OP_NOT,
|
||||
OP_NEGATE,
|
||||
OP_COUNT,
|
||||
OP_CONCAT, // concats uint8_t vars on the stack
|
||||
OP_INCLOCAL, // pushes old value to stack, adds (uint8_t-128) to local[uint8_t]
|
||||
OP_INCGLOBAL, // pushes old value to stack, adds (uint8_t-128) to globals[const[uint16_t]]
|
||||
|
@ -395,6 +395,7 @@ static void unary(CParseState *pstate, bool canAssign) {
|
||||
switch(type) {
|
||||
case TOKEN_MINUS: writeu8Chunk(pstate->state, getChunk(pstate), OP_NEGATE, cachedLine); break;
|
||||
case TOKEN_BANG: writeu8Chunk(pstate->state, getChunk(pstate), OP_NOT, cachedLine); break;
|
||||
case TOKEN_POUND: writeu8Chunk(pstate->state, getChunk(pstate), OP_COUNT, cachedLine); break;
|
||||
default:
|
||||
error(pstate, "Unexpected unary operator!");
|
||||
}
|
||||
@ -718,6 +719,7 @@ ParseRule ruleTable[] = {
|
||||
[TOKEN_PLUS_PLUS] = {preincrement, NULL, PREC_TERM},
|
||||
[TOKEN_SLASH] = {NULL, binary, PREC_FACTOR},
|
||||
[TOKEN_STAR] = {NULL, binary, PREC_FACTOR},
|
||||
[TOKEN_POUND] = {unary, NULL, PREC_NONE},
|
||||
[TOKEN_EOS] = {NULL, NULL, PREC_NONE},
|
||||
[TOKEN_BANG] = {unary, NULL, PREC_NONE},
|
||||
[TOKEN_BANG_EQUAL] = {NULL, binary, PREC_EQUALITY},
|
||||
@ -1219,9 +1221,11 @@ CObjFunction* cosmoP_compileString(CState *state, const char *source) {
|
||||
}
|
||||
|
||||
CObjFunction* resFunc = compiler.function;
|
||||
|
||||
// VM expects the closure on the stack :P (we do this before ending the compiler so our GC doesn't free it)
|
||||
cosmoV_pushValue(state, cosmoV_newObj((CObj*)cosmoO_newClosure(state, resFunc)));
|
||||
|
||||
// finally free out parser states
|
||||
endCompiler(&parser);
|
||||
freeParseState(&parser);
|
||||
cosmoM_unfreezeGC(state);
|
||||
|
@ -209,6 +209,11 @@ bool cosmoT_remove(CState* state, CTable *tbl, CValue key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns the active entry count
|
||||
COSMO_API int cosmoT_count(CTable *tbl) {
|
||||
return tbl->count - tbl->tombstones;
|
||||
}
|
||||
|
||||
CObjString *cosmoT_lookupString(CTable *tbl, const char *str, size_t length, uint32_t hash) {
|
||||
if (tbl->count == 0) return 0; // sanity check
|
||||
uint32_t indx = hash & (tbl->capacity - 1); // since we know the capacity will *always* be a power of 2, we can use bitwise & to perform a MUCH faster mod operation
|
||||
|
@ -20,6 +20,7 @@ COSMO_API void cosmoT_initTable(CState *state, CTable *tbl, int startCap);
|
||||
COSMO_API void cosmoT_clearTable(CState *state, CTable *tbl);
|
||||
COSMO_API void cosmoT_addTable(CState *state, CTable *from, CTable *to);
|
||||
COSMO_API CValue *cosmoT_insert(CState *state, CTable *tbl, CValue key);
|
||||
COSMO_API int cosmoT_count(CTable *tbl);
|
||||
|
||||
CObjString *cosmoT_lookupString(CTable *tbl, const char *str, size_t length, uint32_t hash);
|
||||
bool cosmoT_checkShrink(CState *state, CTable *tbl);
|
||||
|
14
src/cvalue.c
14
src/cvalue.c
@ -33,7 +33,7 @@ bool cosmoV_equal(CValue valA, CValue valB) {
|
||||
}
|
||||
}
|
||||
|
||||
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val) {
|
||||
CObjString *cosmoV_toString(CState *state, CValue val) {
|
||||
switch (val.type) {
|
||||
case COSMO_TNUMBER: {
|
||||
char buf[32];
|
||||
@ -54,6 +54,18 @@ COSMO_API CObjString *cosmoV_toString(CState *state, CValue val) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *cosmoV_typeStr(CValue val) {
|
||||
switch (val.type) {
|
||||
case COSMO_TNIL: return "<nil>";
|
||||
case COSMO_TBOOLEAN: return "<bool>";
|
||||
case COSMO_TNUMBER: return "<number>";
|
||||
case COSMO_TOBJ: return cosmoO_typeStr(val.val.obj);
|
||||
|
||||
default:
|
||||
return "<unkn val>";
|
||||
}
|
||||
}
|
||||
|
||||
void printValue(CValue val) {
|
||||
switch (val.type) {
|
||||
case COSMO_TNUMBER:
|
||||
|
@ -38,6 +38,7 @@ void appendValArray(CState *state, CValueArray *array, CValue val);
|
||||
void printValue(CValue val);
|
||||
COSMO_API bool cosmoV_equal(CValue valA, CValue valB);
|
||||
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val);
|
||||
COSMO_API const char *cosmoV_typeStr(CValue val);
|
||||
|
||||
#define IS_NUMBER(x) (x.type == COSMO_TNUMBER)
|
||||
#define IS_BOOLEAN(x) (x.type == COSMO_TBOOLEAN)
|
||||
|
47
src/cvm.c
47
src/cvm.c
@ -154,7 +154,7 @@ bool invokeMethod(CState* state, CObjObject *obj, CValue func, int args) {
|
||||
} else if (IS_CLOSURE(func)) {
|
||||
call(state, cosmoV_readClosure(func), args+1, 1); // offset = 1 so our stack is properly reset
|
||||
} else {
|
||||
cosmoV_error(state, "Cannot call non-function value!");
|
||||
cosmoV_error(state, "Cannot invoke non-function type %s!", cosmoV_typeStr(func));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -164,8 +164,8 @@ bool invokeMethod(CState* state, CObjObject *obj, CValue func, int args) {
|
||||
COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
||||
StkPtr val = cosmoV_getTop(state, args); // function will always be right above the args
|
||||
|
||||
if (!(val->type == COSMO_TOBJ)) {
|
||||
cosmoV_error(state, "Cannot call non-function value!");
|
||||
if (val->type != COSMO_TOBJ) {
|
||||
cosmoV_error(state, "Cannot call non-function type %s!", cosmoV_typeStr(*val));
|
||||
return COSMOVM_RUNTIME_ERR;
|
||||
}
|
||||
|
||||
@ -265,7 +265,7 @@ COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, C
|
||||
cosmoV_setTop(state, 2); /* pop the 2 values */ \
|
||||
cosmoV_pushValue(state, typeConst((valA->val.num) op (valB->val.num))); \
|
||||
} else { \
|
||||
cosmoV_error(state, "Expected number!"); \
|
||||
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA), cosmoV_typeStr(*valB)); \
|
||||
} \
|
||||
|
||||
// returns false if panic
|
||||
@ -393,8 +393,8 @@ bool cosmoV_execute(CState *state) {
|
||||
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)) {
|
||||
cosmoV_error(state, "Couldn't get from non-object!");
|
||||
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) {
|
||||
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -412,8 +412,8 @@ bool cosmoV_execute(CState *state) {
|
||||
StkPtr temp = cosmoV_getTop(state, 2); // object is after the key
|
||||
|
||||
// sanity check
|
||||
if (!(temp->type == COSMO_TOBJ) || !(temp->val.obj->type == COBJ_OBJECT)) {
|
||||
cosmoV_error(state, "Couldn't set a field on a non-object!");
|
||||
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) {
|
||||
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -430,8 +430,8 @@ bool cosmoV_execute(CState *state) {
|
||||
StkPtr temp = cosmoV_getTop(state, args+1); // grabs object from stack
|
||||
|
||||
// sanity check
|
||||
if (!(temp->type == COSMO_TOBJ) || !(temp->val.obj->type == COBJ_OBJECT)) {
|
||||
cosmoV_error(state, "Couldn't get from non-object!");
|
||||
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) {
|
||||
cosmoV_error(state, "Couldn't get from non-object type %s!", cosmoV_typeStr(*temp));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -475,10 +475,23 @@ bool cosmoV_execute(CState *state) {
|
||||
cosmoV_pop(state);
|
||||
cosmoV_pushValue(state, cosmoV_newNumber(-(val->val.num)));
|
||||
} else {
|
||||
cosmoV_error(state, "Expected number!");
|
||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||
}
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
||||
if (temp->type != COSMO_TOBJ || ((CObj*)temp->val.obj)->type != COBJ_OBJECT) {
|
||||
cosmoV_error(state, "Expected object, got %s!", cosmoV_typeStr(*temp));
|
||||
break;
|
||||
}
|
||||
|
||||
CObjObject *obj = (CObjObject*)temp->val.obj;
|
||||
cosmoV_pop(state);
|
||||
cosmoV_pushNumber(state, cosmoT_count(&obj->tbl)); // pushes the count onto the stack
|
||||
break;
|
||||
}
|
||||
case OP_CONCAT: {
|
||||
uint8_t vals = READBYTE();
|
||||
StkPtr start = state->top - vals;
|
||||
@ -508,7 +521,7 @@ bool cosmoV_execute(CState *state) {
|
||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||
*val = cosmoV_newNumber(val->val.num + inc);
|
||||
} else {
|
||||
cosmoV_error(state, "Expected number!");
|
||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -524,7 +537,7 @@ bool cosmoV_execute(CState *state) {
|
||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||
*val = cosmoV_newNumber(val->val.num + inc);
|
||||
} else {
|
||||
cosmoV_error(state, "Expected number!");
|
||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -539,7 +552,7 @@ bool cosmoV_execute(CState *state) {
|
||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||
*val = cosmoV_newNumber(val->val.num + inc);
|
||||
} else {
|
||||
cosmoV_error(state, "Expected number!");
|
||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -551,8 +564,8 @@ bool cosmoV_execute(CState *state) {
|
||||
CValue ident = constants[indx]; // grabs identifier
|
||||
|
||||
// sanity check
|
||||
if (!(temp->type == COSMO_TOBJ) || !(temp->val.obj->type == COBJ_OBJECT)) {
|
||||
cosmoV_error(state, "Couldn't set a field on a non-object!");
|
||||
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) {
|
||||
cosmoV_error(state, "Couldn't set a field on non-object type %s!", cosmoV_typeStr(*temp));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -567,7 +580,7 @@ bool cosmoV_execute(CState *state) {
|
||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||
*val = cosmoV_newNumber(val->val.num + inc);
|
||||
} else {
|
||||
cosmoV_error(state, "Expected number!");
|
||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||
}
|
||||
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user