mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-22 07:20:05 +00:00
minor refactoring, added inc and dec operators
This commit is contained in:
parent
3727d6bb7c
commit
46b99ab390
@ -8,8 +8,8 @@ class Test
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- stressing the GC
|
// stressing the GC
|
||||||
for (var i = 0; ; i=i+1) do
|
for (var i = 0; ; i++) do
|
||||||
var x = Test("Hello world " .. i)
|
var x = Test("Hello world " .. i)
|
||||||
x.print()
|
x.print()
|
||||||
end
|
end
|
@ -1,7 +1,7 @@
|
|||||||
-- crafts a dummy class
|
// crafts a dummy class
|
||||||
class test end
|
class test end
|
||||||
|
|
||||||
-- instance of test
|
// instance of test
|
||||||
var obj = test()
|
var obj = test()
|
||||||
|
|
||||||
test.__index = function(self, key)
|
test.__index = function(self, key)
|
||||||
@ -11,4 +11,4 @@ test.__index = function(self, key)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
print(obj["lol"]) -- should print 9001?
|
print(obj["lol"]) // should print 9001?
|
48
src/cdebug.c
48
src/cdebug.c
@ -12,16 +12,26 @@ int simpleInstruction(const char *name, int offset) {
|
|||||||
return offset + 1; // consume opcode
|
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));
|
printf("%-16s [%03d]", name, readu8Chunk(chunk, offset + 1));
|
||||||
return offset + 2;
|
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));
|
printf("%-16s [%05d]", name, readu16Chunk(chunk, offset + 1));
|
||||||
return offset + 1 + (sizeof(uint16_t) / sizeof(INSTRUCTION));
|
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 constInstruction(const char *name, CChunk *chunk, int offset, int indent) {
|
||||||
int index = readu16Chunk(chunk, offset + 1);
|
int index = readu16Chunk(chunk, offset + 1);
|
||||||
printf("%-16s [%05d] - ", name, index);
|
printf("%-16s [%05d] - ", name, index);
|
||||||
@ -65,25 +75,25 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
|
|||||||
case OP_GETGLOBAL:
|
case OP_GETGLOBAL:
|
||||||
return constInstruction("OP_GETGLOBAL", chunk, offset, indent);
|
return constInstruction("OP_GETGLOBAL", chunk, offset, indent);
|
||||||
case OP_SETLOCAL:
|
case OP_SETLOCAL:
|
||||||
return shortOperandInstruction("OP_SETLOCAL", chunk, offset);
|
return u8OperandInstruction("OP_SETLOCAL", chunk, offset);
|
||||||
case OP_GETLOCAL:
|
case OP_GETLOCAL:
|
||||||
return shortOperandInstruction("OP_GETLOCAL", chunk, offset);
|
return u8OperandInstruction("OP_GETLOCAL", chunk, offset);
|
||||||
case OP_SETUPVAL:
|
case OP_SETUPVAL:
|
||||||
return shortOperandInstruction("OP_SETUPVAL", chunk, offset);
|
return u8OperandInstruction("OP_SETUPVAL", chunk, offset);
|
||||||
case OP_GETUPVAL:
|
case OP_GETUPVAL:
|
||||||
return shortOperandInstruction("OP_GETUPVAL", chunk, offset);
|
return u8OperandInstruction("OP_GETUPVAL", chunk, offset);
|
||||||
case OP_PEJMP:
|
case OP_PEJMP:
|
||||||
return longOperandInstruction("OP_PEJMP", chunk, offset);
|
return u16OperandInstruction("OP_PEJMP", chunk, offset);
|
||||||
case OP_EJMP:
|
case OP_EJMP:
|
||||||
return longOperandInstruction("OP_EJMP", chunk, offset);
|
return u16OperandInstruction("OP_EJMP", chunk, offset);
|
||||||
case OP_JMP:
|
case OP_JMP:
|
||||||
return longOperandInstruction("OP_JMP", chunk, offset);
|
return u16OperandInstruction("OP_JMP", chunk, offset);
|
||||||
case OP_JMPBACK:
|
case OP_JMPBACK:
|
||||||
return longOperandInstruction("OP_JMPBACK", chunk, offset);
|
return u16OperandInstruction("OP_JMPBACK", chunk, offset);
|
||||||
case OP_POP:
|
case OP_POP:
|
||||||
return shortOperandInstruction("OP_POP", chunk, offset);
|
return u8OperandInstruction("OP_POP", chunk, offset);
|
||||||
case OP_CALL:
|
case OP_CALL:
|
||||||
return shortOperandInstruction("OP_CALL", chunk, offset);
|
return u8OperandInstruction("OP_CALL", chunk, offset);
|
||||||
case OP_CLOSURE: {
|
case OP_CLOSURE: {
|
||||||
int index = readu16Chunk(chunk, offset + 1);
|
int index = readu16Chunk(chunk, offset + 1);
|
||||||
printf("%-16s [%05d] - ", "OP_CLOSURE", index);
|
printf("%-16s [%05d] - ", "OP_CLOSURE", index);
|
||||||
@ -109,13 +119,13 @@ 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:
|
case OP_NEWOBJECT:
|
||||||
return longOperandInstruction("OP_NEWOBJECT", chunk, offset);
|
return u16OperandInstruction("OP_NEWOBJECT", chunk, offset);
|
||||||
case OP_GETOBJECT:
|
case OP_GETOBJECT:
|
||||||
return simpleInstruction("OP_GETOBJECT", offset);
|
return simpleInstruction("OP_GETOBJECT", offset);
|
||||||
case OP_SETOBJECT:
|
case OP_SETOBJECT:
|
||||||
return simpleInstruction("OP_SETOBJECT", offset);
|
return simpleInstruction("OP_SETOBJECT", offset);
|
||||||
case OP_INVOKE:
|
case OP_INVOKE:
|
||||||
return shortOperandInstruction("OP_INVOKE", chunk, offset);
|
return u8OperandInstruction("OP_INVOKE", chunk, offset);
|
||||||
case OP_ADD:
|
case OP_ADD:
|
||||||
return simpleInstruction("OP_ADD", offset);
|
return simpleInstruction("OP_ADD", offset);
|
||||||
case OP_SUB:
|
case OP_SUB:
|
||||||
@ -145,7 +155,15 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
|
|||||||
case OP_NEGATE:
|
case OP_NEGATE:
|
||||||
return simpleInstruction("OP_NEGATE", offset);
|
return simpleInstruction("OP_NEGATE", offset);
|
||||||
case OP_CONCAT:
|
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:
|
case OP_RETURN:
|
||||||
return simpleInstruction("OP_RETURN", offset);
|
return simpleInstruction("OP_RETURN", offset);
|
||||||
default:
|
default:
|
||||||
|
11
src/clex.c
11
src/clex.c
@ -109,8 +109,8 @@ void skipWhitespace(CLexState *state) {
|
|||||||
case '\t':
|
case '\t':
|
||||||
next(state); // consume the whitespace
|
next(state); // consume the whitespace
|
||||||
break;
|
break;
|
||||||
case '-': // consume comments
|
case '/': // consume comments
|
||||||
if (peekNext(state) == '-') {
|
if (peekNext(state) == '/') {
|
||||||
|
|
||||||
// skip to next line (also let \n be consumed on the next iteration to properly handle that)
|
// 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
|
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_RIGHT_BRACE);
|
||||||
case '[': return makeToken(state, TOKEN_LEFT_BRACKET);
|
case '[': return makeToken(state, TOKEN_LEFT_BRACKET);
|
||||||
case ']': return makeToken(state, TOKEN_RIGHT_BRACKET);
|
case ']': return makeToken(state, TOKEN_RIGHT_BRACKET);
|
||||||
// fall through
|
|
||||||
case ';': return makeToken(state, TOKEN_EOS);
|
case ';': return makeToken(state, TOKEN_EOS);
|
||||||
case ',': return makeToken(state, TOKEN_COMMA);
|
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_STAR);
|
||||||
case '/': return makeToken(state, TOKEN_SLASH);
|
case '/': return makeToken(state, TOKEN_SLASH);
|
||||||
// two character tokens
|
// 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 '.':
|
case '.':
|
||||||
return match(state, '.') ? makeToken(state, TOKEN_DOT_DOT) : makeToken(state, TOKEN_DOT);
|
return match(state, '.') ? makeToken(state, TOKEN_DOT_DOT) : makeToken(state, TOKEN_DOT);
|
||||||
case '!':
|
case '!':
|
||||||
|
@ -15,7 +15,9 @@ typedef enum {
|
|||||||
TOKEN_DOT,
|
TOKEN_DOT,
|
||||||
TOKEN_DOT_DOT,
|
TOKEN_DOT_DOT,
|
||||||
TOKEN_MINUS,
|
TOKEN_MINUS,
|
||||||
|
TOKEN_MINUS_MINUS,
|
||||||
TOKEN_PLUS,
|
TOKEN_PLUS,
|
||||||
|
TOKEN_PLUS_PLUS,
|
||||||
TOKEN_SLASH,
|
TOKEN_SLASH,
|
||||||
TOKEN_STAR,
|
TOKEN_STAR,
|
||||||
TOKEN_EOS, // end of statement
|
TOKEN_EOS, // end of statement
|
||||||
|
@ -76,6 +76,8 @@ void tableRemoveWhite(CState *state, CTable *tbl) {
|
|||||||
cosmoT_remove(state, tbl, entry->key);
|
cosmoT_remove(state, tbl, entry->key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cosmoT_checkShrink(state, tbl); // recovers the memory we're no longer using
|
||||||
}
|
}
|
||||||
|
|
||||||
void markArray(CState *state, CValueArray *array) {
|
void markArray(CState *state, CValueArray *array) {
|
||||||
|
@ -36,13 +36,16 @@
|
|||||||
|
|
||||||
#define cosmoM_unfreezeGC(state) \
|
#define cosmoM_unfreezeGC(state) \
|
||||||
state->freezeGC--; \
|
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
|
#else
|
||||||
#define cosmoM_freezeGC(state) \
|
#define cosmoM_freezeGC(state) \
|
||||||
state->freezeGC++
|
state->freezeGC++
|
||||||
|
|
||||||
#define cosmoM_unfreezeGC(state) \
|
#define cosmoM_unfreezeGC(state) \
|
||||||
state->freezeGC--
|
state->freezeGC--; \
|
||||||
|
cosmoM_checkGarbage(state, 0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
COSMO_API void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize);
|
COSMO_API void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize);
|
||||||
|
@ -29,7 +29,7 @@ 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_NEWOBJECT,
|
||||||
OP_GETOBJECT,
|
OP_GETOBJECT,
|
||||||
OP_SETOBJECT,
|
OP_SETOBJECT,
|
||||||
OP_INVOKE,
|
OP_INVOKE,
|
||||||
@ -42,6 +42,10 @@ typedef enum {
|
|||||||
OP_NOT,
|
OP_NOT,
|
||||||
OP_NEGATE,
|
OP_NEGATE,
|
||||||
OP_CONCAT, // concats uint8_t vars on the stack
|
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
|
// EQUALITY
|
||||||
OP_EQUAL,
|
OP_EQUAL,
|
||||||
@ -56,7 +60,6 @@ typedef enum {
|
|||||||
OP_NIL,
|
OP_NIL,
|
||||||
|
|
||||||
OP_RETURN
|
OP_RETURN
|
||||||
|
} COPCODE; // there can be a max of 256 instructions
|
||||||
} COPCODE;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
108
src/cparse.c
108
src/cparse.c
@ -130,9 +130,7 @@ static void errorAt(CParseState *pstate, CToken *token, const char * msg) {
|
|||||||
|
|
||||||
if (token->type == TOKEN_EOF) {
|
if (token->type == TOKEN_EOF) {
|
||||||
fprintf(stderr, " at end");
|
fprintf(stderr, " at end");
|
||||||
} else if (token->type == TOKEN_ERROR) {
|
} else if (!(token->type == TOKEN_ERROR)) {
|
||||||
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, " at '%.*s'", token->length, token->start);
|
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);
|
writeu8(pstate, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void namedVariable(CParseState *pstate, CToken name, bool canAssign) {
|
static void namedVariable(CParseState *pstate, CToken name, bool canAssign, bool canIncrement) {
|
||||||
uint8_t opGet, opSet;
|
uint8_t opGet, opSet, inc;
|
||||||
int arg = getLocal(pstate->compiler, &name);
|
int arg = getLocal(pstate->compiler, &name);
|
||||||
|
|
||||||
if (arg != -1) {
|
if (arg != -1) {
|
||||||
// we found it in out local table!
|
// we found it in out local table!
|
||||||
opGet = OP_GETLOCAL;
|
opGet = OP_GETLOCAL;
|
||||||
opSet = OP_SETLOCAL;
|
opSet = OP_SETLOCAL;
|
||||||
|
inc = OP_INCLOCAL;
|
||||||
} else if ((arg = getUpvalue(pstate->compiler, &name)) != -1) {
|
} else if ((arg = getUpvalue(pstate->compiler, &name)) != -1) {
|
||||||
opGet = OP_GETUPVAL;
|
opGet = OP_GETUPVAL;
|
||||||
opSet = OP_SETUPVAL;
|
opSet = OP_SETUPVAL;
|
||||||
|
inc = OP_INCUPVAL;
|
||||||
} else {
|
} else {
|
||||||
// local & upvalue wasnt' found, assume it's a global!
|
// local & upvalue wasnt' found, assume it's a global!
|
||||||
arg = identifierConstant(pstate, &name);
|
arg = identifierConstant(pstate, &name);
|
||||||
opGet = OP_GETGLOBAL;
|
opGet = OP_GETGLOBAL;
|
||||||
opSet = OP_SETGLOBAL;
|
opSet = OP_SETGLOBAL;
|
||||||
|
inc = OP_INCGLOBAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAssign && match(pstate, TOKEN_EQUAL)) {
|
if (canAssign && match(pstate, TOKEN_EQUAL)) {
|
||||||
@ -469,6 +470,24 @@ static void namedVariable(CParseState *pstate, CToken name, bool canAssign) {
|
|||||||
expression(pstate);
|
expression(pstate);
|
||||||
_etterOP(pstate, opSet, arg);
|
_etterOP(pstate, opSet, arg);
|
||||||
valuePopped(pstate, 1);
|
valuePopped(pstate, 1);
|
||||||
|
} 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 {
|
} else {
|
||||||
// getter
|
// getter
|
||||||
_etterOP(pstate, opGet, arg);
|
_etterOP(pstate, opGet, arg);
|
||||||
@ -502,7 +521,7 @@ static void anonFunction(CParseState *pstate, bool canAssign) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void variable(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) {
|
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) {
|
static void dot(CParseState *pstate, bool canAssign) {
|
||||||
consume(pstate, TOKEN_IDENTIFIER, "Expected property name after '.'.");
|
consume(pstate, TOKEN_IDENTIFIER, "Expected property name after '.'.");
|
||||||
uint16_t name = identifierConstant(pstate, &pstate->previous);
|
uint16_t name = identifierConstant(pstate, &pstate->previous);
|
||||||
writeu8(pstate, OP_LOADCONST);
|
|
||||||
writeu16(pstate, name);
|
|
||||||
|
|
||||||
if (canAssign && match(pstate, TOKEN_EQUAL)) {
|
if (canAssign && match(pstate, TOKEN_EQUAL)) {
|
||||||
|
writeu8(pstate, OP_LOADCONST);
|
||||||
|
writeu16(pstate, name);
|
||||||
expression(pstate);
|
expression(pstate);
|
||||||
writeu8(pstate, OP_SETOBJECT);
|
writeu8(pstate, OP_SETOBJECT);
|
||||||
valuePopped(pstate, 2); // pops key, value & object
|
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
|
} else if (match(pstate, TOKEN_LEFT_PAREN)) { // it's an invoked call
|
||||||
|
writeu8(pstate, OP_LOADCONST);
|
||||||
|
writeu16(pstate, name);
|
||||||
uint8_t args = parseArguments(pstate);
|
uint8_t args = parseArguments(pstate);
|
||||||
writeu8(pstate, OP_INVOKE);
|
writeu8(pstate, OP_INVOKE);
|
||||||
writeu8(pstate, args);
|
writeu8(pstate, args);
|
||||||
valuePopped(pstate, args); // pops the function & the object but pushes a result
|
valuePopped(pstate, args); // pops the function & the object but pushes a result
|
||||||
} else {
|
} else {
|
||||||
|
writeu8(pstate, OP_LOADCONST);
|
||||||
|
writeu16(pstate, name);
|
||||||
writeu8(pstate, OP_GETOBJECT);
|
writeu8(pstate, OP_GETOBJECT);
|
||||||
// pops key & object but also pushes the field so total popped is 1
|
// 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[] = {
|
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},
|
||||||
@ -620,7 +708,9 @@ ParseRule ruleTable[] = {
|
|||||||
[TOKEN_DOT] = {NULL, dot, PREC_CALL},
|
[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_MINUS_MINUS] = {predecrement, NULL, PREC_TERM},
|
||||||
[TOKEN_PLUS] = {NULL, binary, PREC_TERM},
|
[TOKEN_PLUS] = {NULL, binary, PREC_TERM},
|
||||||
|
[TOKEN_PLUS_PLUS] = {preincrement, NULL, PREC_TERM},
|
||||||
[TOKEN_SLASH] = {NULL, binary, PREC_FACTOR},
|
[TOKEN_SLASH] = {NULL, binary, PREC_FACTOR},
|
||||||
[TOKEN_STAR] = {NULL, binary, PREC_FACTOR},
|
[TOKEN_STAR] = {NULL, binary, PREC_FACTOR},
|
||||||
[TOKEN_EOS] = {NULL, NULL, PREC_NONE},
|
[TOKEN_EOS] = {NULL, NULL, PREC_NONE},
|
||||||
@ -996,7 +1086,9 @@ static void forLoop(CParseState *pstate) {
|
|||||||
int bodyJmp = writeJmp(pstate, OP_JMP);
|
int bodyJmp = writeJmp(pstate, OP_JMP);
|
||||||
|
|
||||||
int iteratorStart = getChunk(pstate)->count;
|
int iteratorStart = getChunk(pstate)->count;
|
||||||
|
int savedPushed = pstate->compiler->pushedValues;
|
||||||
expression(pstate);
|
expression(pstate);
|
||||||
|
alignStack(pstate, savedPushed);
|
||||||
consume(pstate, TOKEN_RIGHT_PAREN, "Expected ')' after iterator");
|
consume(pstate, TOKEN_RIGHT_PAREN, "Expected ')' after iterator");
|
||||||
|
|
||||||
writeJmpBack(pstate, loopStart);
|
writeJmpBack(pstate, loopStart);
|
||||||
|
19
src/ctable.c
19
src/ctable.c
@ -109,16 +109,11 @@ static CTableEntry *findEntry(CTableEntry *entries, int mask, CValue key) {
|
|||||||
|
|
||||||
static void resizeTbl(CState *state, CTable *tbl, size_t newCapacity) {
|
static void resizeTbl(CState *state, CTable *tbl, size_t newCapacity) {
|
||||||
size_t size = sizeof(CTableEntry) * 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
|
cosmoM_checkGarbage(state, size); // if this allocation would cause a GC, run the GC
|
||||||
|
|
||||||
// if count > 8 and active entries < tombstones
|
if (tbl->count < cachedCount) // the GC removed some objects from this table and resized it, ignore our resize event!
|
||||||
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
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
CTableEntry *entries = cosmoM_xmalloc(state, size);
|
CTableEntry *entries = cosmoM_xmalloc(state, size);
|
||||||
int newCount = 0;
|
int newCount = 0;
|
||||||
@ -151,6 +146,16 @@ static void resizeTbl(CState *state, CTable *tbl, size_t newCapacity) {
|
|||||||
tbl->tombstones = 0;
|
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
|
// returns a pointer to the allocated value
|
||||||
COSMO_API CValue* cosmoT_insert(CState *state, CTable *tbl, CValue key) {
|
COSMO_API CValue* cosmoT_insert(CState *state, CTable *tbl, CValue key) {
|
||||||
// make sure we have enough space allocated
|
// make sure we have enough space allocated
|
||||||
|
@ -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);
|
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);
|
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_get(CTable *tbl, CValue key, CValue *val);
|
||||||
bool cosmoT_remove(CState *state, CTable *tbl, CValue key);
|
bool cosmoT_remove(CState *state, CTable *tbl, CValue key);
|
||||||
|
|
||||||
|
74
src/cvm.c
74
src/cvm.c
@ -498,6 +498,80 @@ bool cosmoV_execute(CState *state) {
|
|||||||
cosmoV_pushValue(state, cosmoV_newObj(result));
|
cosmoV_pushValue(state, cosmoV_newObj(result));
|
||||||
break;
|
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: {
|
case OP_EQUAL: {
|
||||||
// pop vals
|
// pop vals
|
||||||
StkPtr valB = cosmoV_pop(state);
|
StkPtr valB = cosmoV_pop(state);
|
||||||
|
Loading…
Reference in New Issue
Block a user