minor refactoring, added inc and dec operators

This commit is contained in:
CPunch 2020-11-19 14:41:21 -06:00
parent 3727d6bb7c
commit 46b99ab390
12 changed files with 248 additions and 47 deletions

View File

@ -8,8 +8,8 @@ class Test
end
end
-- stressing the GC
for (var i = 0; ; i=i+1) do
// stressing the GC
for (var i = 0; ; i++) do
var x = Test("Hello world " .. i)
x.print()
end

View File

@ -1,7 +1,7 @@
-- crafts a dummy class
// crafts a dummy class
class test end
-- instance of test
// instance of test
var obj = test()
test.__index = function(self, key)
@ -11,4 +11,4 @@ test.__index = function(self, key)
end
end
print(obj["lol"]) -- should print 9001?
print(obj["lol"]) // should print 9001?

View File

@ -12,16 +12,26 @@ int simpleInstruction(const char *name, int offset) {
return offset + 1; // consume opcode
}
int shortOperandInstruction(const char *name, CChunk *chunk, int offset) {
int u8OperandInstruction(const char *name, CChunk *chunk, int offset) {
printf("%-16s [%03d]", name, readu8Chunk(chunk, offset + 1));
return offset + 2;
}
int longOperandInstruction(const char *name, CChunk *chunk, int offset) {
int u16OperandInstruction(const char *name, CChunk *chunk, int offset) {
printf("%-16s [%05d]", name, readu16Chunk(chunk, offset + 1));
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION));
}
int u8u8OperandInstruction(const char *name, CChunk *chunk, int offset) {
printf("%-16s [%03d] [%03d]", name, readu8Chunk(chunk, offset + 1), readu8Chunk(chunk, offset + 2));
return offset + 3; // op + u8 + u8
}
int u8u16OperandInstruction(const char *name, CChunk *chunk, int offset) {
printf("%-16s [%03d] [%05d]", name, readu8Chunk(chunk, offset + 1), readu16Chunk(chunk, offset + 2));
return offset + 4; // op + u8 + u16
}
int constInstruction(const char *name, CChunk *chunk, int offset, int indent) {
int index = readu16Chunk(chunk, offset + 1);
printf("%-16s [%05d] - ", name, index);
@ -65,25 +75,25 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
case OP_GETGLOBAL:
return constInstruction("OP_GETGLOBAL", chunk, offset, indent);
case OP_SETLOCAL:
return shortOperandInstruction("OP_SETLOCAL", chunk, offset);
return u8OperandInstruction("OP_SETLOCAL", chunk, offset);
case OP_GETLOCAL:
return shortOperandInstruction("OP_GETLOCAL", chunk, offset);
return u8OperandInstruction("OP_GETLOCAL", chunk, offset);
case OP_SETUPVAL:
return shortOperandInstruction("OP_SETUPVAL", chunk, offset);
return u8OperandInstruction("OP_SETUPVAL", chunk, offset);
case OP_GETUPVAL:
return shortOperandInstruction("OP_GETUPVAL", chunk, offset);
return u8OperandInstruction("OP_GETUPVAL", chunk, offset);
case OP_PEJMP:
return longOperandInstruction("OP_PEJMP", chunk, offset);
return u16OperandInstruction("OP_PEJMP", chunk, offset);
case OP_EJMP:
return longOperandInstruction("OP_EJMP", chunk, offset);
return u16OperandInstruction("OP_EJMP", chunk, offset);
case OP_JMP:
return longOperandInstruction("OP_JMP", chunk, offset);
return u16OperandInstruction("OP_JMP", chunk, offset);
case OP_JMPBACK:
return longOperandInstruction("OP_JMPBACK", chunk, offset);
return u16OperandInstruction("OP_JMPBACK", chunk, offset);
case OP_POP:
return shortOperandInstruction("OP_POP", chunk, offset);
return u8OperandInstruction("OP_POP", chunk, offset);
case OP_CALL:
return shortOperandInstruction("OP_CALL", chunk, offset);
return u8OperandInstruction("OP_CALL", chunk, offset);
case OP_CLOSURE: {
int index = readu16Chunk(chunk, offset + 1);
printf("%-16s [%05d] - ", "OP_CLOSURE", index);
@ -109,13 +119,13 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
case OP_CLOSE:
return simpleInstruction("OP_CLOSE", offset);
case OP_NEWOBJECT:
return longOperandInstruction("OP_NEWOBJECT", chunk, offset);
return u16OperandInstruction("OP_NEWOBJECT", chunk, offset);
case OP_GETOBJECT:
return simpleInstruction("OP_GETOBJECT", offset);
case OP_SETOBJECT:
return simpleInstruction("OP_SETOBJECT", offset);
case OP_INVOKE:
return shortOperandInstruction("OP_INVOKE", chunk, offset);
return u8OperandInstruction("OP_INVOKE", chunk, offset);
case OP_ADD:
return simpleInstruction("OP_ADD", offset);
case OP_SUB:
@ -145,7 +155,15 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
case OP_NEGATE:
return simpleInstruction("OP_NEGATE", offset);
case OP_CONCAT:
return shortOperandInstruction("OP_CONCAT", chunk, offset);
return u8OperandInstruction("OP_CONCAT", chunk, offset);
case OP_INCLOCAL:
return u8u8OperandInstruction("OP_INCLOCAL", chunk, offset);
case OP_INCGLOBAL:
return u8u16OperandInstruction("OP_INCGLOBAL", chunk, offset);
case OP_INCUPVAL:
return u8u8OperandInstruction("OP_INCLOCAL", chunk, offset);
case OP_INCOBJECT:
return u8u16OperandInstruction("OP_INCOBJECT", chunk, offset);
case OP_RETURN:
return simpleInstruction("OP_RETURN", offset);
default:

View File

@ -109,8 +109,8 @@ void skipWhitespace(CLexState *state) {
case '\t':
next(state); // consume the whitespace
break;
case '-': // consume comments
if (peekNext(state) == '-') {
case '/': // consume comments
if (peekNext(state) == '/') {
// skip to next line (also let \n be consumed on the next iteration to properly handle that)
while (!isEnd(state) && peek(state) != '\n' && peek(state) != '\0') // if it's not a newline or null terminator
@ -196,14 +196,15 @@ CToken cosmoL_scanToken(CLexState *state) {
case '}': return makeToken(state, TOKEN_RIGHT_BRACE);
case '[': return makeToken(state, TOKEN_LEFT_BRACKET);
case ']': return makeToken(state, TOKEN_RIGHT_BRACKET);
// fall through
case ';': return makeToken(state, TOKEN_EOS);
case ',': return makeToken(state, TOKEN_COMMA);
case '+': return makeToken(state, TOKEN_PLUS);
case '-': return makeToken(state, TOKEN_MINUS);
case '*': return makeToken(state, TOKEN_STAR);
case '/': return makeToken(state, TOKEN_SLASH);
// two character tokens
case '+':
return match(state, '+') ? makeToken(state, TOKEN_PLUS_PLUS) : makeToken(state, TOKEN_PLUS);
case '-':
return match(state, '-') ? makeToken(state, TOKEN_MINUS_MINUS) : makeToken(state, TOKEN_MINUS);
case '.':
return match(state, '.') ? makeToken(state, TOKEN_DOT_DOT) : makeToken(state, TOKEN_DOT);
case '!':

View File

@ -15,7 +15,9 @@ typedef enum {
TOKEN_DOT,
TOKEN_DOT_DOT,
TOKEN_MINUS,
TOKEN_MINUS_MINUS,
TOKEN_PLUS,
TOKEN_PLUS_PLUS,
TOKEN_SLASH,
TOKEN_STAR,
TOKEN_EOS, // end of statement

View File

@ -76,6 +76,8 @@ void tableRemoveWhite(CState *state, CTable *tbl) {
cosmoT_remove(state, tbl, entry->key);
}
}
cosmoT_checkShrink(state, tbl); // recovers the memory we're no longer using
}
void markArray(CState *state, CValueArray *array) {

View File

@ -36,13 +36,16 @@
#define cosmoM_unfreezeGC(state) \
state->freezeGC--; \
printf("unfreezing state at %s:%d [%d]\n", __FILE__, __LINE__, state->freezeGC)
printf("unfreezing state at %s:%d [%d]\n", __FILE__, __LINE__, state->freezeGC); \
cosmoM_checkGarbage(state, 0)
#else
#define cosmoM_freezeGC(state) \
state->freezeGC++
#define cosmoM_unfreezeGC(state) \
state->freezeGC--
state->freezeGC--; \
cosmoM_checkGarbage(state, 0)
#endif
COSMO_API void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize);

View File

@ -29,19 +29,23 @@ typedef enum {
OP_CALL, // calls top[-uint8_t]
OP_CLOSURE,
OP_CLOSE,
OP_NEWOBJECT, //
OP_NEWOBJECT,
OP_GETOBJECT,
OP_SETOBJECT,
OP_INVOKE,
// ARITHMETIC
OP_ADD,
OP_ADD,
OP_SUB,
OP_MULT,
OP_DIV,
OP_NOT,
OP_NEGATE,
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]]
OP_INCUPVAL, // pushes old value to stack, adds (uint8_t-128) to closure->upval[uint8_t]
OP_INCOBJECT, // pushes old value to stack, adds (uint8_t-128) to obj[const[uint16_t]]
// EQUALITY
OP_EQUAL,
@ -56,7 +60,6 @@ typedef enum {
OP_NIL,
OP_RETURN
} COPCODE;
} COPCODE; // there can be a max of 256 instructions
#endif

View File

@ -130,9 +130,7 @@ static void errorAt(CParseState *pstate, CToken *token, const char * msg) {
if (token->type == TOKEN_EOF) {
fprintf(stderr, " at end");
} else if (token->type == TOKEN_ERROR) {
} else {
} else if (!(token->type == TOKEN_ERROR)) {
fprintf(stderr, " at '%.*s'", token->length, token->start);
}
@ -446,22 +444,25 @@ static void _etterOP(CParseState *pstate, uint8_t op, int arg) {
writeu8(pstate, arg);
}
static void namedVariable(CParseState *pstate, CToken name, bool canAssign) {
uint8_t opGet, opSet;
static void namedVariable(CParseState *pstate, CToken name, bool canAssign, bool canIncrement) {
uint8_t opGet, opSet, inc;
int arg = getLocal(pstate->compiler, &name);
if (arg != -1) {
// we found it in out local table!
opGet = OP_GETLOCAL;
opSet = OP_SETLOCAL;
inc = OP_INCLOCAL;
} else if ((arg = getUpvalue(pstate->compiler, &name)) != -1) {
opGet = OP_GETUPVAL;
opSet = OP_SETUPVAL;
inc = OP_INCUPVAL;
} else {
// local & upvalue wasnt' found, assume it's a global!
arg = identifierConstant(pstate, &name);
opGet = OP_GETGLOBAL;
opSet = OP_SETGLOBAL;
inc = OP_INCGLOBAL;
}
if (canAssign && match(pstate, TOKEN_EQUAL)) {
@ -469,7 +470,25 @@ static void namedVariable(CParseState *pstate, CToken name, bool canAssign) {
expression(pstate);
_etterOP(pstate, opSet, arg);
valuePopped(pstate, 1);
} else {
} else if (canIncrement && match(pstate, TOKEN_PLUS_PLUS)) { // i++
// now we increment the value
writeu8(pstate, inc);
writeu8(pstate, 128 + 1); // setting signed values in an unsigned int
if (inc == OP_INCGLOBAL) // globals are stored with a u16
writeu16(pstate, arg);
else
writeu8(pstate, arg);
valuePushed(pstate, 1);
} else if (canIncrement && match(pstate, TOKEN_MINUS_MINUS)) { // i--
// now we increment the value
writeu8(pstate, inc);
writeu8(pstate, 128 - 1); // setting signed values in an unsigned int
if (inc == OP_INCGLOBAL) // globals are stored with a u16
writeu16(pstate, arg);
else
writeu8(pstate, arg);
valuePushed(pstate, 1);
} else {
// getter
_etterOP(pstate, opGet, arg);
valuePushed(pstate, 1);
@ -502,7 +521,7 @@ static void anonFunction(CParseState *pstate, bool canAssign) {
}
static void variable(CParseState *pstate, bool canAssign) {
namedVariable(pstate, pstate->previous, canAssign);
namedVariable(pstate, pstate->previous, canAssign, true);
}
static void concat(CParseState *pstate, bool canAssign) {
@ -577,19 +596,31 @@ static void object(CParseState *pstate, bool canAssign) {
static void dot(CParseState *pstate, bool canAssign) {
consume(pstate, TOKEN_IDENTIFIER, "Expected property name after '.'.");
uint16_t name = identifierConstant(pstate, &pstate->previous);
writeu8(pstate, OP_LOADCONST);
writeu16(pstate, name);
if (canAssign && match(pstate, TOKEN_EQUAL)) {
writeu8(pstate, OP_LOADCONST);
writeu16(pstate, name);
expression(pstate);
writeu8(pstate, OP_SETOBJECT);
valuePopped(pstate, 2); // pops key, value & object
} else if (match(pstate, TOKEN_PLUS_PLUS)) { // increment the field
writeu8(pstate, OP_INCOBJECT);
writeu8(pstate, 128 + 1);
writeu16(pstate, name);
} else if (match(pstate, TOKEN_MINUS_MINUS)) { // decrement the field
writeu8(pstate, OP_INCOBJECT);
writeu8(pstate, 128 - 1);
writeu16(pstate, name);
} else if (match(pstate, TOKEN_LEFT_PAREN)) { // it's an invoked call
writeu8(pstate, OP_LOADCONST);
writeu16(pstate, name);
uint8_t args = parseArguments(pstate);
writeu8(pstate, OP_INVOKE);
writeu8(pstate, args);
valuePopped(pstate, args); // pops the function & the object but pushes a result
} else {
writeu8(pstate, OP_LOADCONST);
writeu16(pstate, name);
writeu8(pstate, OP_GETOBJECT);
// pops key & object but also pushes the field so total popped is 1
}
@ -609,6 +640,63 @@ static void _index(CParseState *pstate, bool canAssign) {
}
}
static void increment(CParseState *pstate, int val) {
CToken name = pstate->previous;
if (match(pstate, TOKEN_DOT)) { // object?
namedVariable(pstate, name, false, false); // just get the object
consume(pstate, TOKEN_IDENTIFIER, "Expected property name after '.'.");
uint16_t name = identifierConstant(pstate, &pstate->previous);
writeu8(pstate, OP_INCOBJECT);
writeu8(pstate, 128 + val); // setting signed values in an unsigned int
writeu16(pstate, name);
valuePopped(pstate, 1); // popped the object off the stack
} else {
uint8_t op;
int arg = getLocal(pstate->compiler, &name);
if (arg != -1) {
// we found it in out local table!
op = OP_INCLOCAL;
} else if ((arg = getUpvalue(pstate->compiler, &name)) != -1) {
op = OP_INCUPVAL;
} else {
// local & upvalue wasnt' found, assume it's a global!
arg = identifierConstant(pstate, &name);
op = OP_INCGLOBAL;
}
writeu8(pstate, op);
writeu8(pstate, 128 + val); // setting signed values in an unsigned int
if (op == OP_INCGLOBAL) // globals are stored with a u16
writeu16(pstate, arg);
else
writeu8(pstate, arg);
}
// increment the old value on the stack
writeConstant(pstate, cosmoV_newNumber(val));
writeu8(pstate, OP_ADD);
}
// ++i
static void preincrement(CParseState *pstate, bool canAssign) {
// expect identifier
consume(pstate, TOKEN_IDENTIFIER, "Expected identifier after '++'");
increment(pstate, 1);
}
// --i
static void predecrement(CParseState *pstate, bool canAssign) {
// expect identifier
consume(pstate, TOKEN_IDENTIFIER, "Expected identifier after '--'");
increment(pstate, -1);
}
ParseRule ruleTable[] = {
[TOKEN_LEFT_PAREN] = {group, call_, PREC_CALL},
[TOKEN_RIGHT_PAREN] = {NULL, NULL, PREC_NONE},
@ -620,7 +708,9 @@ ParseRule ruleTable[] = {
[TOKEN_DOT] = {NULL, dot, PREC_CALL},
[TOKEN_DOT_DOT] = {NULL, concat, PREC_CONCAT},
[TOKEN_MINUS] = {unary, binary, PREC_TERM},
[TOKEN_MINUS_MINUS] = {predecrement, NULL, PREC_TERM},
[TOKEN_PLUS] = {NULL, binary, PREC_TERM},
[TOKEN_PLUS_PLUS] = {preincrement, NULL, PREC_TERM},
[TOKEN_SLASH] = {NULL, binary, PREC_FACTOR},
[TOKEN_STAR] = {NULL, binary, PREC_FACTOR},
[TOKEN_EOS] = {NULL, NULL, PREC_NONE},
@ -996,7 +1086,9 @@ static void forLoop(CParseState *pstate) {
int bodyJmp = writeJmp(pstate, OP_JMP);
int iteratorStart = getChunk(pstate)->count;
int savedPushed = pstate->compiler->pushedValues;
expression(pstate);
alignStack(pstate, savedPushed);
consume(pstate, TOKEN_RIGHT_PAREN, "Expected ')' after iterator");
writeJmpBack(pstate, loopStart);

View File

@ -109,16 +109,11 @@ static CTableEntry *findEntry(CTableEntry *entries, int mask, CValue key) {
static void resizeTbl(CState *state, CTable *tbl, size_t newCapacity) {
size_t size = sizeof(CTableEntry) * newCapacity;
int cachedCount = tbl->count;
cosmoM_checkGarbage(state, size); // if this allocation would cause a GC, run the GC
// if count > 8 and active entries < tombstones
if (tbl->count > MIN_TABLE_CAPACITY && tbl->count - tbl->tombstones < tbl->tombstones) {
int tombs = tbl->tombstones;
tbl->tombstones = 0; // set this to 0 so in our recursive call to resizeTbl() this branch isn't run again
resizeTbl(state, tbl, nextPow2((tbl->count - tombs) * GROW_FACTOR)); // shrink based on active entries to the next pow of 2
cosmoM_updateThreshhold(state); // force a threshhold update since this *could* be such a huge memory difference
if (tbl->count < cachedCount) // the GC removed some objects from this table and resized it, ignore our resize event!
return;
}
CTableEntry *entries = cosmoM_xmalloc(state, size);
int newCount = 0;
@ -151,6 +146,16 @@ static void resizeTbl(CState *state, CTable *tbl, size_t newCapacity) {
tbl->tombstones = 0;
}
bool cosmoT_checkShrink(CState *state, CTable *tbl) {
// if count > 8 and active entries < tombstones
if (tbl->count > MIN_TABLE_CAPACITY && tbl->count - tbl->tombstones < tbl->tombstones) {
resizeTbl(state, tbl, nextPow2((tbl->count - tbl->tombstones) * GROW_FACTOR)); // shrink based on active entries to the next pow of 2
return true;
}
return false;
}
// returns a pointer to the allocated value
COSMO_API CValue* cosmoT_insert(CState *state, CTable *tbl, CValue key) {
// make sure we have enough space allocated

View File

@ -22,6 +22,7 @@ COSMO_API void cosmoT_addTable(CState *state, CTable *from, CTable *to);
COSMO_API CValue *cosmoT_insert(CState *state, CTable *tbl, CValue key);
CObjString *cosmoT_lookupString(CTable *tbl, const char *str, size_t length, uint32_t hash);
bool cosmoT_checkShrink(CState *state, CTable *tbl);
bool cosmoT_get(CTable *tbl, CValue key, CValue *val);
bool cosmoT_remove(CState *state, CTable *tbl, CValue key);

View File

@ -498,6 +498,80 @@ bool cosmoV_execute(CState *state) {
cosmoV_pushValue(state, cosmoV_newObj(result));
break;
}
case OP_INCLOCAL: { // this leaves the value on the stack
int8_t inc = READBYTE() - 128; // ammount we're incrementing by
uint8_t indx = READBYTE();
StkPtr val = &frame->base[indx];
// check that it's a number value
if (val->type == COSMO_TNUMBER) {
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
*val = cosmoV_newNumber(val->val.num + inc);
} else {
cosmoV_error(state, "Expected number!");
}
break;
}
case OP_INCGLOBAL: {
int8_t inc = READBYTE() - 128; // ammount we're incrementing by
uint16_t indx = READUINT();
CValue ident = constants[indx]; // grabs identifier
CValue *val = cosmoT_insert(state, &state->globals, ident);
// check that it's a number value
if (val->type == COSMO_TNUMBER) {
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
*val = cosmoV_newNumber(val->val.num + inc);
} else {
cosmoV_error(state, "Expected number!");
}
break;
}
case OP_INCUPVAL: {
int8_t inc = READBYTE() - 128; // ammount we're incrementing by
uint8_t indx = READBYTE();
CValue *val = frame->closure->upvalues[indx]->val;
// check that it's a number value
if (val->type == COSMO_TNUMBER) {
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
*val = cosmoV_newNumber(val->val.num + inc);
} else {
cosmoV_error(state, "Expected number!");
}
break;
}
case OP_INCOBJECT: {
int8_t inc = READBYTE() - 128; // ammount we're incrementing by
uint16_t indx = READUINT();
StkPtr temp = cosmoV_getTop(state, 0); // object should be at the top of the stack
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!");
break;
}
CObjObject *object = (CObjObject*)temp->val.obj;
CValue *val = cosmoT_insert(state, &object->tbl, ident);
// pop the object off the stack
cosmoV_pop(state);
// check that it's a number value
if (val->type == COSMO_TNUMBER) {
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
*val = cosmoV_newNumber(val->val.num + inc);
} else {
cosmoV_error(state, "Expected number!");
}
break;
}
case OP_EQUAL: {
// pop vals
StkPtr valB = cosmoV_pop(state);