mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-12-04 22:46:31 +00:00
commit
420cd3e856
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
|||||||
# make clean && make && ./bin/cosmo
|
# make clean && make && ./bin/cosmo
|
||||||
|
|
||||||
CC=clang
|
CC=clang
|
||||||
CFLAGS=-fPIE -Wall -Isrc -O3 -std=c99
|
CFLAGS=-fPIE -Wall -Isrc -O3 -std=c99 #-g -fsanitize=address
|
||||||
LDFLAGS=-lm #-fsanitize=address
|
LDFLAGS=-lm #-fsanitize=address
|
||||||
OUT=bin/cosmo
|
OUT=bin/cosmo
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ end
|
|||||||
// instance of test
|
// instance of test
|
||||||
let obj = test()
|
let obj = test()
|
||||||
|
|
||||||
test.__index = function(self, key)
|
test.__index = func(self, key)
|
||||||
print("__index called!")
|
print("__index called!")
|
||||||
if (key == "lol") then
|
if (key == "lol") then
|
||||||
return 9001
|
return 9001
|
||||||
|
25
main.c
25
main.c
@ -45,21 +45,20 @@ int cosmoB_input(CState *state, int nargs, CValue *args)
|
|||||||
|
|
||||||
static bool interpret(CState *state, const char *script, const char *mod)
|
static bool interpret(CState *state, const char *script, const char *mod)
|
||||||
{
|
{
|
||||||
bool ret;
|
|
||||||
|
|
||||||
// cosmoV_compileString pushes the result onto the stack (COBJ_ERROR or COBJ_CLOSURE)
|
// cosmoV_compileString pushes the result onto the stack (COBJ_ERROR or COBJ_CLOSURE)
|
||||||
if (cosmoV_compileString(state, script, mod)) {
|
if (cosmoV_compileString(state, script, mod)) {
|
||||||
// 0 args being passed, 0 results expected
|
// 0 args being passed, 0 results expected
|
||||||
if (!cosmoV_call(state, 0, 0))
|
if (!cosmoV_pcall(state, 0, 0)) {
|
||||||
cosmoV_printError(state, state->error);
|
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cosmoV_pop(state); // pop the error off the stack
|
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
cosmoV_printError(state, state->error);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = state->panic;
|
return true;
|
||||||
state->panic = false; // so our repl isn't broken
|
|
||||||
return !ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void repl(CState *state)
|
static void repl(CState *state)
|
||||||
@ -158,8 +157,7 @@ void compileScript(CState *state, const char *in, const char *out)
|
|||||||
CObjFunction *func = cosmoV_readClosure(*cosmoV_getTop(state, 0))->function;
|
CObjFunction *func = cosmoV_readClosure(*cosmoV_getTop(state, 0))->function;
|
||||||
cosmoD_dump(state, func, fileWriter, (void *)fout);
|
cosmoD_dump(state, func, fileWriter, (void *)fout);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_pop(state); // pop the error off the stack
|
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
cosmoV_printError(state, state->error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(script);
|
free(script);
|
||||||
@ -172,14 +170,13 @@ void loadScript(CState *state, const char *in)
|
|||||||
{
|
{
|
||||||
FILE *file = fopen(in, "rb");
|
FILE *file = fopen(in, "rb");
|
||||||
if (!cosmoV_undump(state, fileReader, file)) {
|
if (!cosmoV_undump(state, fileReader, file)) {
|
||||||
cosmoV_pop(state); // pop the error off the stack
|
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
cosmoV_printError(state, state->error);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
printf("[!] loaded %s!\n", in);
|
printf("[!] loaded %s!\n", in);
|
||||||
if (!cosmoV_call(state, 0, 0))
|
if (!cosmoV_pcall(state, 0, 0))
|
||||||
cosmoV_printError(state, state->error);
|
cosmoV_printError(state, cosmoV_readError(*cosmoV_pop(state)));
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ int cosmoB_assert(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs < 1 || nargs > 2) {
|
if (nargs < 1 || nargs > 2) {
|
||||||
cosmoV_error(state, "assert() expected 1 or 2 arguments, got %d!", nargs);
|
cosmoV_error(state, "assert() expected 1 or 2 arguments, got %d!", nargs);
|
||||||
return 0; // nothing pushed onto the stack to return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_BOOLEAN(args[0]) || (nargs == 2 && !IS_STRING(args[1]))) {
|
if (!IS_BOOLEAN(args[0]) || (nargs == 2 && !IS_STRING(args[1]))) {
|
||||||
@ -40,7 +39,6 @@ int cosmoB_assert(CState *state, int nargs, CValue *args)
|
|||||||
} else {
|
} else {
|
||||||
cosmoV_typeError(state, "assert()", "<boolean>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "assert()", "<boolean>", "%s", cosmoV_typeStr(args[0]));
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cosmoV_readBoolean(args[0])) // expression passed was false, error!
|
if (!cosmoV_readBoolean(args[0])) // expression passed was false, error!
|
||||||
@ -53,7 +51,6 @@ int cosmoB_type(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "type() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "type() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// push the type string to the stack
|
// push the type string to the stack
|
||||||
@ -65,7 +62,6 @@ int cosmoB_pcall(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs < 1) {
|
if (nargs < 1) {
|
||||||
cosmoV_error(state, "pcall() expected at least 1 argument!");
|
cosmoV_error(state, "pcall() expected at least 1 argument!");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// call the passed callable, the passed arguments are already in the
|
// call the passed callable, the passed arguments are already in the
|
||||||
@ -81,7 +77,6 @@ int cosmoB_tonumber(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "tonumber() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "tonumber() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, cosmoV_toNumber(state, args[0]));
|
cosmoV_pushNumber(state, cosmoV_toNumber(state, args[0]));
|
||||||
@ -90,10 +85,8 @@ int cosmoB_tonumber(CState *state, int nargs, CValue *args)
|
|||||||
|
|
||||||
int cosmoB_tostring(CState *state, int nargs, CValue *args)
|
int cosmoB_tostring(CState *state, int nargs, CValue *args)
|
||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1)
|
||||||
cosmoV_error(state, "tostring() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "tostring() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cosmoV_pushRef(state, (CObj *)cosmoV_toString(state, args[0]));
|
cosmoV_pushRef(state, (CObj *)cosmoV_toString(state, args[0]));
|
||||||
return 1;
|
return 1;
|
||||||
@ -103,12 +96,10 @@ int cosmoB_loadstring(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "loadstring() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "loadstring() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_STRING(args[0])) {
|
if (!IS_STRING(args[0])) {
|
||||||
cosmoV_typeError(state, "loadstring()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "loadstring()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -122,12 +113,10 @@ int cosmoB_error(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "error() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "error() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_STRING(args[0])) {
|
if (!IS_STRING(args[0])) {
|
||||||
cosmoV_typeError(state, "error()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "error()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_error(state, "%s", cosmoV_readCString(args[0]));
|
cosmoV_error(state, "%s", cosmoV_readCString(args[0]));
|
||||||
@ -176,10 +165,8 @@ int cosmoB_osetProto(CState *state, int nargs, CValue *args)
|
|||||||
|
|
||||||
int cosmoB_ogetProto(CState *state, int nargs, CValue *args)
|
int cosmoB_ogetProto(CState *state, int nargs, CValue *args)
|
||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1)
|
||||||
cosmoV_error(state, "Expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "Expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cosmoV_pushRef(state, (CObj *)cosmoV_readObject(args[0])->_obj.proto); // just return the proto
|
cosmoV_pushRef(state, (CObj *)cosmoV_readObject(args[0])->_obj.proto); // just return the proto
|
||||||
|
|
||||||
@ -190,13 +177,11 @@ int cosmoB_oisChild(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 2) {
|
if (nargs != 2) {
|
||||||
cosmoV_error(state, "object.ischild() expected 2 arguments, got %d!", nargs);
|
cosmoV_error(state, "object.ischild() expected 2 arguments, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_REF(args[0]) || !IS_OBJECT(args[1])) {
|
if (!IS_REF(args[0]) || !IS_OBJECT(args[1])) {
|
||||||
cosmoV_typeError(state, "object.ischild()", "<reference obj>, <object>", "%s, %s",
|
cosmoV_typeError(state, "object.ischild()", "<reference obj>, <object>", "%s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObj *obj = cosmoV_readRef(args[0]);
|
CObj *obj = cosmoV_readRef(args[0]);
|
||||||
@ -255,12 +240,10 @@ int cosmoB_osRead(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "os.read() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "os.read() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_STRING(args[0])) {
|
if (!IS_STRING(args[0])) {
|
||||||
cosmoV_typeError(state, "os.read()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "os.read()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -301,7 +284,6 @@ int cosmoB_osTime(CState *state, int nargs, CValue *args)
|
|||||||
struct timeval time;
|
struct timeval time;
|
||||||
if (nargs > 0) {
|
if (nargs > 0) {
|
||||||
cosmoV_error(state, "os.time() expected no arguments, got %d!", nargs);
|
cosmoV_error(state, "os.time() expected no arguments, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gettimeofday(&time, NULL);
|
gettimeofday(&time, NULL);
|
||||||
@ -314,12 +296,10 @@ int cosmoB_osSystem(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "os.system() expects 1 argument, got %d!", nargs);
|
cosmoV_error(state, "os.system() expects 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_STRING(args[0])) {
|
if (!IS_STRING(args[0])) {
|
||||||
cosmoV_typeError(state, "os.system()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "os.system()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the command and return the exit code
|
// run the command and return the exit code
|
||||||
@ -354,7 +334,6 @@ int cosmoB_sSub(CState *state, int nargs, CValue *args)
|
|||||||
if (!IS_STRING(args[0]) || !IS_NUMBER(args[1])) {
|
if (!IS_STRING(args[0]) || !IS_NUMBER(args[1])) {
|
||||||
cosmoV_typeError(state, "string.sub()", "<string>, <number>", "%s, %s",
|
cosmoV_typeError(state, "string.sub()", "<string>, <number>", "%s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -364,7 +343,6 @@ int cosmoB_sSub(CState *state, int nargs, CValue *args)
|
|||||||
if (indx < 0 || indx >= str->length) {
|
if (indx < 0 || indx >= str->length) {
|
||||||
cosmoV_error(state, "string.sub() expected index to be 0-%d, got %d!", str->length - 1,
|
cosmoV_error(state, "string.sub() expected index to be 0-%d, got %d!", str->length - 1,
|
||||||
indx);
|
indx);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushLString(state, str->str + ((int)indx), str->length - ((int)indx));
|
cosmoV_pushLString(state, str->str + ((int)indx), str->length - ((int)indx));
|
||||||
@ -373,7 +351,6 @@ int cosmoB_sSub(CState *state, int nargs, CValue *args)
|
|||||||
cosmoV_typeError(state, "string.sub()", "<string>, <number>, <number>", "%s, %s, %s",
|
cosmoV_typeError(state, "string.sub()", "<string>, <number>, <number>", "%s, %s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]),
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]),
|
||||||
cosmoV_typeStr(args[2]));
|
cosmoV_typeStr(args[2]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -385,13 +362,11 @@ int cosmoB_sSub(CState *state, int nargs, CValue *args)
|
|||||||
cosmoV_error(
|
cosmoV_error(
|
||||||
state, "string.sub() expected subbed string goes out of bounds, max length is %d!",
|
state, "string.sub() expected subbed string goes out of bounds, max length is %d!",
|
||||||
str->length);
|
str->length);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushLString(state, str->str + ((int)indx), ((int)length));
|
cosmoV_pushLString(state, str->str + ((int)indx), ((int)length));
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "string.sub() expected 2 or 3 arguments, got %d!", nargs);
|
cosmoV_error(state, "string.sub() expected 2 or 3 arguments, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -404,7 +379,6 @@ int cosmoB_sFind(CState *state, int nargs, CValue *args)
|
|||||||
if (!IS_STRING(args[0]) || !IS_STRING(args[1])) {
|
if (!IS_STRING(args[0]) || !IS_STRING(args[1])) {
|
||||||
cosmoV_typeError(state, "string.find()", "<string>, <string>", "%s, %s",
|
cosmoV_typeError(state, "string.find()", "<string>, <string>", "%s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -425,7 +399,6 @@ int cosmoB_sFind(CState *state, int nargs, CValue *args)
|
|||||||
cosmoV_typeError(state, "string.find()", "<string>, <string>, <number>", "%s, %s, %s",
|
cosmoV_typeError(state, "string.find()", "<string>, <string>, <number>", "%s, %s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]),
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]),
|
||||||
cosmoV_typeStr(args[2]));
|
cosmoV_typeStr(args[2]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -444,7 +417,6 @@ int cosmoB_sFind(CState *state, int nargs, CValue *args)
|
|||||||
cosmoV_pushNumber(state, (cosmo_Number)(indx - str->str));
|
cosmoV_pushNumber(state, (cosmo_Number)(indx - str->str));
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "string.find() expected 2 or 3 arguments, got %d!", nargs);
|
cosmoV_error(state, "string.find() expected 2 or 3 arguments, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -455,13 +427,11 @@ int cosmoB_sSplit(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 2) {
|
if (nargs != 2) {
|
||||||
cosmoV_error(state, "string.split() expected 2 arguments, got %d!", nargs);
|
cosmoV_error(state, "string.split() expected 2 arguments, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_STRING(args[0]) || !IS_STRING(args[1])) {
|
if (!IS_STRING(args[0]) || !IS_STRING(args[1])) {
|
||||||
cosmoV_typeError(state, "string.split()", "<string>, <string>", "%s, %s",
|
cosmoV_typeError(state, "string.split()", "<string>, <string>", "%s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -492,12 +462,10 @@ int cosmoB_sByte(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "string.byte() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "string.byte() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_STRING(args[0])) {
|
if (!IS_STRING(args[0])) {
|
||||||
cosmoV_typeError(state, "string.byte", "<string>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "string.byte", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -518,12 +486,10 @@ int cosmoB_sChar(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "string.char() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "string.char() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "string.char", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "string.char", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// small side effect of truncating the number, but ignoring the decimal instead of throwing an
|
// small side effect of truncating the number, but ignoring the decimal instead of throwing an
|
||||||
@ -533,7 +499,6 @@ int cosmoB_sChar(CState *state, int nargs, CValue *args)
|
|||||||
|
|
||||||
if (num > 255 || num < 0) {
|
if (num > 255 || num < 0) {
|
||||||
cosmoV_error(state, "Character expected to be in range 0-255, got %d!", num);
|
cosmoV_error(state, "Character expected to be in range 0-255, got %d!", num);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// basically, treat the character value on the C stack as an """"array"""" with a length of 1
|
// basically, treat the character value on the C stack as an """"array"""" with a length of 1
|
||||||
@ -545,12 +510,10 @@ int cosmoB_sLen(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs < 1) {
|
if (nargs < 1) {
|
||||||
cosmoV_error(state, "string.len() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "string.len() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_STRING(args[0])) {
|
if (!IS_STRING(args[0])) {
|
||||||
cosmoV_typeError(state, "string.len", "<string>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "string.len", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, (cosmo_Number)strlen(cosmoV_readCString(args[0])));
|
cosmoV_pushNumber(state, (cosmo_Number)strlen(cosmoV_readCString(args[0])));
|
||||||
@ -562,14 +525,12 @@ int cosmoB_sRep(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 2) {
|
if (nargs != 2) {
|
||||||
cosmoV_error(state, "string.rep() expected 2 arguments, got %d!", nargs);
|
cosmoV_error(state, "string.rep() expected 2 arguments, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// expects <string>, <number>
|
// expects <string>, <number>
|
||||||
if (!IS_STRING(args[0]) || !IS_NUMBER(args[1])) {
|
if (!IS_STRING(args[0]) || !IS_NUMBER(args[1])) {
|
||||||
cosmoV_typeError(state, "string.rep", "<string>, <number>", "%s, %s",
|
cosmoV_typeError(state, "string.rep", "<string>, <number>", "%s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjString *str = cosmoV_readString(args[0]);
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
@ -627,12 +588,10 @@ int cosmoB_mAbs(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.abs() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.abs() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.abs", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.abs", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, fabs(cosmoV_readNumber(args[0])));
|
cosmoV_pushNumber(state, fabs(cosmoV_readNumber(args[0])));
|
||||||
@ -644,12 +603,10 @@ int cosmoB_mFloor(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.floor() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.floor() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.floor", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.floor", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, (int)cosmoV_readNumber(args[0]));
|
cosmoV_pushNumber(state, (int)cosmoV_readNumber(args[0]));
|
||||||
@ -661,12 +618,10 @@ int cosmoB_mCeil(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.ceil() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.ceil() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.ceil", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.ceil", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int roundedDown = (int)cosmoV_readNumber(args[0]);
|
int roundedDown = (int)cosmoV_readNumber(args[0]);
|
||||||
@ -685,12 +640,10 @@ int cosmoB_mSin(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.sin() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.sin() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.sin", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.sin", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, sin(cosmoV_readNumber(args[0])));
|
cosmoV_pushNumber(state, sin(cosmoV_readNumber(args[0])));
|
||||||
@ -701,12 +654,10 @@ int cosmoB_mCos(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.cos() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.cos() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.cos", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.cos", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, cos(cosmoV_readNumber(args[0])));
|
cosmoV_pushNumber(state, cos(cosmoV_readNumber(args[0])));
|
||||||
@ -717,12 +668,10 @@ int cosmoB_mTan(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.tan() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.tan() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.tan", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.tan", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, tan(cosmoV_readNumber(args[0])));
|
cosmoV_pushNumber(state, tan(cosmoV_readNumber(args[0])));
|
||||||
@ -733,12 +682,10 @@ int cosmoB_mASin(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.asin() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.asin() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.asin", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.asin", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, asin(cosmoV_readNumber(args[0])));
|
cosmoV_pushNumber(state, asin(cosmoV_readNumber(args[0])));
|
||||||
@ -749,12 +696,10 @@ int cosmoB_mACos(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.acos() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.acos() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.acos", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.acos", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, acos(cosmoV_readNumber(args[0])));
|
cosmoV_pushNumber(state, acos(cosmoV_readNumber(args[0])));
|
||||||
@ -765,12 +710,10 @@ int cosmoB_mATan(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.atan() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.atan() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.atan", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.atan", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushNumber(state, atan(cosmoV_readNumber(args[0])));
|
cosmoV_pushNumber(state, atan(cosmoV_readNumber(args[0])));
|
||||||
@ -781,12 +724,10 @@ int cosmoB_mRad(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.rad() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.rad() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.rad", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.rad", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the degree to radians
|
// convert the degree to radians
|
||||||
@ -798,12 +739,10 @@ int cosmoB_mDeg(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "math.deg() expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "math.deg() expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[0])) {
|
if (!IS_NUMBER(args[0])) {
|
||||||
cosmoV_typeError(state, "math.deg", "<number>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "math.deg", "<number>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the degree to radians
|
// convert the degree to radians
|
||||||
@ -852,13 +791,11 @@ int cosmoB_vsetGlobal(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 2) {
|
if (nargs != 2) {
|
||||||
cosmoV_error(state, "Expected 2 argumenst, got %d!", nargs);
|
cosmoV_error(state, "Expected 2 argumenst, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_TABLE(args[1])) {
|
if (!IS_TABLE(args[1])) {
|
||||||
cosmoV_typeError(state, "vm.__setter[\"globals\"]", "<object>, <table>", "%s, %s",
|
cosmoV_typeError(state, "vm.__setter[\"globals\"]", "<object>, <table>", "%s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this makes me very nervous ngl
|
// this makes me very nervous ngl
|
||||||
@ -874,13 +811,11 @@ int cosmoB_vdisassemble(CState *state, int nargs, CValue *args)
|
|||||||
|
|
||||||
if (nargs != 1) {
|
if (nargs != 1) {
|
||||||
cosmoV_error(state, "Expected 1 argument, got %d!", nargs);
|
cosmoV_error(state, "Expected 1 argument, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the closure
|
// get the closure
|
||||||
if (!IS_CLOSURE(args[0])) {
|
if (!IS_CLOSURE(args[0])) {
|
||||||
cosmoV_typeError(state, "vm.disassemble", "<closure>", "%s", cosmoV_typeStr(args[0]));
|
cosmoV_typeError(state, "vm.disassemble", "<closure>", "%s", cosmoV_typeStr(args[0]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closure = cosmoV_readClosure(args[0]);
|
closure = cosmoV_readClosure(args[0]);
|
||||||
@ -895,13 +830,11 @@ int cosmoB_vindexBProto(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 2) {
|
if (nargs != 2) {
|
||||||
cosmoV_error(state, "Expected 2 arguments, got %d!", nargs);
|
cosmoV_error(state, "Expected 2 arguments, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[1])) {
|
if (!IS_NUMBER(args[1])) {
|
||||||
cosmoV_typeError(state, "baseProtos.__index", "<object>, <number>", "%s, %s",
|
cosmoV_typeError(state, "baseProtos.__index", "<object>, <number>", "%s, %s",
|
||||||
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int indx = (int)cosmoV_readNumber(args[1]);
|
int indx = (int)cosmoV_readNumber(args[1]);
|
||||||
@ -923,14 +856,12 @@ int cosmoB_vnewindexBProto(CState *state, int nargs, CValue *args)
|
|||||||
{
|
{
|
||||||
if (nargs != 3) {
|
if (nargs != 3) {
|
||||||
cosmoV_error(state, "Expected 3 arguments, got %d!", nargs);
|
cosmoV_error(state, "Expected 3 arguments, got %d!", nargs);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_NUMBER(args[1]) || !IS_OBJECT(args[2])) {
|
if (!IS_NUMBER(args[1]) || !IS_OBJECT(args[2])) {
|
||||||
cosmoV_typeError(state, "baseProtos.__newindex", "<object>, <number>, <object>",
|
cosmoV_typeError(state, "baseProtos.__newindex", "<object>, <number>, <object>",
|
||||||
"%s, %s, %s", cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]),
|
"%s, %s, %s", cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]),
|
||||||
cosmoV_typeStr(args[2]));
|
cosmoV_typeStr(args[2]));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int indx = (int)cosmoV_readNumber(args[1]);
|
int indx = (int)cosmoV_readNumber(args[1]);
|
||||||
@ -938,7 +869,6 @@ int cosmoB_vnewindexBProto(CState *state, int nargs, CValue *args)
|
|||||||
|
|
||||||
if (indx >= COBJ_MAX || indx < 0) {
|
if (indx >= COBJ_MAX || indx < 0) {
|
||||||
cosmoV_error(state, "index out of range! expected 0 - %d, got %d!", COBJ_MAX, indx);
|
cosmoV_error(state, "index out of range! expected 0 - %d, got %d!", COBJ_MAX, indx);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_registerProtoObject(state, indx, proto);
|
cosmoV_registerProtoObject(state, indx, proto);
|
||||||
|
@ -27,9 +27,9 @@ void initChunk(CState *state, CChunk *chunk, size_t startCapacity)
|
|||||||
void cleanChunk(CState *state, CChunk *chunk)
|
void cleanChunk(CState *state, CChunk *chunk)
|
||||||
{
|
{
|
||||||
// first, free the chunk buffer
|
// first, free the chunk buffer
|
||||||
cosmoM_freearray(state, INSTRUCTION, chunk->buf, chunk->capacity);
|
cosmoM_freeArray(state, INSTRUCTION, chunk->buf, chunk->capacity);
|
||||||
// then the line info
|
// then the line info
|
||||||
cosmoM_freearray(state, int, chunk->lineInfo, chunk->capacity);
|
cosmoM_freeArray(state, int, chunk->lineInfo, chunk->capacity);
|
||||||
// free the constants
|
// free the constants
|
||||||
cleanValArray(state, &chunk->constants);
|
cleanValArray(state, &chunk->constants);
|
||||||
}
|
}
|
||||||
@ -61,8 +61,8 @@ int addConstant(CState *state, CChunk *chunk, CValue value)
|
|||||||
void writeu8Chunk(CState *state, CChunk *chunk, INSTRUCTION i, int line)
|
void writeu8Chunk(CState *state, CChunk *chunk, INSTRUCTION i, int line)
|
||||||
{
|
{
|
||||||
// does the buffer need to be reallocated?
|
// does the buffer need to be reallocated?
|
||||||
cosmoM_growarray(state, INSTRUCTION, chunk->buf, chunk->count, chunk->capacity);
|
cosmoM_growArray(state, INSTRUCTION, chunk->buf, chunk->count, chunk->capacity);
|
||||||
cosmoM_growarray(state, int, chunk->lineInfo, chunk->count, chunk->lineCapacity);
|
cosmoM_growArray(state, int, chunk->lineInfo, chunk->count, chunk->lineCapacity);
|
||||||
|
|
||||||
// write data to the chunk :)
|
// write data to the chunk :)
|
||||||
chunk->lineInfo[chunk->count] = line;
|
chunk->lineInfo[chunk->count] = line;
|
||||||
|
13
src/clex.c
13
src/clex.c
@ -54,7 +54,7 @@ static void resetBuffer(CLexState *state)
|
|||||||
// cancels the token heap buffer and frees it
|
// cancels the token heap buffer and frees it
|
||||||
static void freeBuffer(CLexState *state)
|
static void freeBuffer(CLexState *state)
|
||||||
{
|
{
|
||||||
cosmoM_freearray(state->cstate, char, state->buffer, state->bufCap);
|
cosmoM_freeArray(state->cstate, char, state->buffer, state->bufCap);
|
||||||
|
|
||||||
resetBuffer(state);
|
resetBuffer(state);
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ static void freeBuffer(CLexState *state)
|
|||||||
// adds character to buffer
|
// adds character to buffer
|
||||||
static void appendBuffer(CLexState *state, char c)
|
static void appendBuffer(CLexState *state, char c)
|
||||||
{
|
{
|
||||||
cosmoM_growarray(state->cstate, char, state->buffer, state->bufCount, state->bufCap);
|
cosmoM_growArray(state->cstate, char, state->buffer, state->bufCount, state->bufCap);
|
||||||
|
|
||||||
state->buffer[state->bufCount++] = c;
|
state->buffer[state->bufCount++] = c;
|
||||||
}
|
}
|
||||||
@ -389,9 +389,8 @@ static CToken parseIdentifier(CLexState *state)
|
|||||||
return makeToken(state, identifierType(state)); // is it a reserved word?
|
return makeToken(state, identifierType(state)); // is it a reserved word?
|
||||||
}
|
}
|
||||||
|
|
||||||
CLexState *cosmoL_newLexState(CState *cstate, const char *source)
|
void cosmoL_initLexState(CState *cstate, CLexState *state, const char *source)
|
||||||
{
|
{
|
||||||
CLexState *state = cosmoM_xmalloc(cstate, sizeof(CLexState));
|
|
||||||
state->startChar = (char *)source;
|
state->startChar = (char *)source;
|
||||||
state->currentChar = (char *)source;
|
state->currentChar = (char *)source;
|
||||||
state->line = 1;
|
state->line = 1;
|
||||||
@ -400,13 +399,11 @@ CLexState *cosmoL_newLexState(CState *cstate, const char *source)
|
|||||||
state->cstate = cstate;
|
state->cstate = cstate;
|
||||||
|
|
||||||
resetBuffer(state);
|
resetBuffer(state);
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoL_freeLexState(CState *state, CLexState *lstate)
|
void cosmoL_cleanupLexState(CState *state, CLexState *lstate)
|
||||||
{
|
{
|
||||||
cosmoM_free(state, CLexState, lstate);
|
// stubbed
|
||||||
}
|
}
|
||||||
|
|
||||||
CToken cosmoL_scanToken(CLexState *state)
|
CToken cosmoL_scanToken(CLexState *state)
|
||||||
|
@ -103,8 +103,8 @@ typedef struct
|
|||||||
CState *cstate;
|
CState *cstate;
|
||||||
} CLexState;
|
} CLexState;
|
||||||
|
|
||||||
CLexState *cosmoL_newLexState(CState *state, const char *source);
|
void cosmoL_initLexState(CState *cstate, CLexState *state, const char *source);
|
||||||
void cosmoL_freeLexState(CState *state, CLexState *lstate);
|
void cosmoL_cleanupLexState(CState *state, CLexState *lstate);
|
||||||
|
|
||||||
CToken cosmoL_scanToken(CLexState *state);
|
CToken cosmoL_scanToken(CLexState *state);
|
||||||
|
|
||||||
|
12
src/cmem.c
12
src/cmem.c
@ -206,7 +206,7 @@ static void markObject(CState *state, CObj *obj)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// we can use cosmoM_growarray because we lock the GC when we entered in cosmoM_collectGarbage
|
// we can use cosmoM_growarray because we lock the GC when we entered in cosmoM_collectGarbage
|
||||||
cosmoM_growarray(state, CObj *, state->grayStack.array, state->grayStack.count,
|
cosmoM_growArray(state, CObj *, state->grayStack.array, state->grayStack.count,
|
||||||
state->grayStack.capacity);
|
state->grayStack.capacity);
|
||||||
|
|
||||||
state->grayStack.array[state->grayStack.count++] = obj;
|
state->grayStack.array[state->grayStack.count++] = obj;
|
||||||
@ -288,9 +288,6 @@ static void markRoots(CState *state)
|
|||||||
// mark the user defined roots
|
// mark the user defined roots
|
||||||
markUserRoots(state);
|
markUserRoots(state);
|
||||||
|
|
||||||
// mark other misc. internally reserved objects
|
|
||||||
markObject(state, (CObj *)state->error);
|
|
||||||
|
|
||||||
for (int i = 0; i < COBJ_MAX; i++)
|
for (int i = 0; i < COBJ_MAX; i++)
|
||||||
markObject(state, (CObj *)state->protoObjects[i]);
|
markObject(state, (CObj *)state->protoObjects[i]);
|
||||||
|
|
||||||
@ -299,12 +296,11 @@ static void markRoots(CState *state)
|
|||||||
|
|
||||||
COSMO_API void cosmoM_collectGarbage(CState *state)
|
COSMO_API void cosmoM_collectGarbage(CState *state)
|
||||||
{
|
{
|
||||||
|
cosmoM_freezeGC(state);
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
printf("-- GC start\n");
|
printf("-- GC start\n");
|
||||||
size_t start = state->allocatedBytes;
|
size_t start = state->allocatedBytes;
|
||||||
#endif
|
#endif
|
||||||
cosmoM_freezeGC(state); // we don't want a recursive garbage collection event!
|
|
||||||
|
|
||||||
markRoots(state);
|
markRoots(state);
|
||||||
|
|
||||||
tableRemoveWhite(
|
tableRemoveWhite(
|
||||||
@ -315,14 +311,12 @@ COSMO_API void cosmoM_collectGarbage(CState *state)
|
|||||||
|
|
||||||
// set our next GC event
|
// set our next GC event
|
||||||
cosmoM_updateThreshhold(state);
|
cosmoM_updateThreshhold(state);
|
||||||
|
|
||||||
state->freezeGC--; // we don't want to use cosmoM_unfreezeGC because that might trigger a GC
|
|
||||||
// event (if GC_STRESS is defined)
|
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
printf("-- GC end, reclaimed %ld bytes (started at %ld, ended at %ld), next garbage collection "
|
printf("-- GC end, reclaimed %ld bytes (started at %ld, ended at %ld), next garbage collection "
|
||||||
"scheduled at %ld bytes\n",
|
"scheduled at %ld bytes\n",
|
||||||
start - state->allocatedBytes, start, state->allocatedBytes, state->nextGC);
|
start - state->allocatedBytes, start, state->allocatedBytes, state->nextGC);
|
||||||
#endif
|
#endif
|
||||||
|
cosmoM_unfreezeGC(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
COSMO_API void cosmoM_updateThreshhold(CState *state)
|
COSMO_API void cosmoM_updateThreshhold(CState *state)
|
||||||
|
10
src/cmem.h
10
src/cmem.h
@ -12,16 +12,16 @@
|
|||||||
#define ARRAY_START 8
|
#define ARRAY_START 8
|
||||||
|
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
# define cosmoM_freearray(state, type, buf, capacity) \
|
# define cosmoM_freeArray(state, type, buf, capacity) \
|
||||||
printf("freeing array %p [size %lu] at %s:%d\n", buf, sizeof(type) * capacity, __FILE__, \
|
printf("freeing array %p [size %lu] at %s:%d\n", buf, sizeof(type) * capacity, __FILE__, \
|
||||||
__LINE__); \
|
__LINE__); \
|
||||||
cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0)
|
cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0)
|
||||||
#else
|
#else
|
||||||
# define cosmoM_freearray(state, type, buf, capacity) \
|
# define cosmoM_freeArray(state, type, buf, capacity) \
|
||||||
cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0)
|
cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define cosmoM_growarray(state, type, buf, count, capacity) \
|
#define cosmoM_growArray(state, type, buf, count, capacity) \
|
||||||
if (count >= capacity || buf == NULL) { \
|
if (count >= capacity || buf == NULL) { \
|
||||||
int old = capacity; \
|
int old = capacity; \
|
||||||
capacity = old * GROW_FACTOR; \
|
capacity = old * GROW_FACTOR; \
|
||||||
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#define cosmoM_isFrozen(state) (state->freezeGC > 0)
|
#define cosmoM_isFrozen(state) (state->freezeGC > 0)
|
||||||
|
|
||||||
|
// cosmoM_freezeGC should only be used in the garbage collector !
|
||||||
// if debugging, print the locations of when the state is frozen/unfrozen
|
// if debugging, print the locations of when the state is frozen/unfrozen
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
# define cosmoM_freezeGC(state) \
|
# define cosmoM_freezeGC(state) \
|
||||||
@ -79,7 +80,4 @@ static inline void *cosmoM_xmalloc(CState *state, size_t sz)
|
|||||||
return cosmoM_reallocate(state, NULL, 0, sz);
|
return cosmoM_reallocate(state, NULL, 0, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #define cosmoM_xmalloc(state, sz) \
|
|
||||||
// (printf("allocating new buffer at %s:%d of size %ld\n", __FILE__, __LINE__, sz), cosmoM_reallocate(state, NULL, 0, sz))
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
45
src/cobj.c
45
src/cobj.c
@ -46,7 +46,7 @@ void cosmoO_free(CState *state, CObj *obj)
|
|||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case COBJ_STRING: {
|
case COBJ_STRING: {
|
||||||
CObjString *objStr = (CObjString *)obj;
|
CObjString *objStr = (CObjString *)obj;
|
||||||
cosmoM_freearray(state, char, objStr->str, objStr->length + 1);
|
cosmoM_freeArray(state, char, objStr->str, objStr->length + 1);
|
||||||
cosmoM_free(state, CObjString, objStr);
|
cosmoM_free(state, CObjString, objStr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -82,13 +82,13 @@ void cosmoO_free(CState *state, CObj *obj)
|
|||||||
}
|
}
|
||||||
case COBJ_ERROR: {
|
case COBJ_ERROR: {
|
||||||
CObjError *err = (CObjError *)obj;
|
CObjError *err = (CObjError *)obj;
|
||||||
cosmoM_freearray(state, CCallFrame, err->frames, err->frameCount);
|
cosmoM_freeArray(state, CCallFrame, err->frames, err->frameCount);
|
||||||
cosmoM_free(state, CObjError, obj);
|
cosmoM_free(state, CObjError, obj);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_CLOSURE: {
|
case COBJ_CLOSURE: {
|
||||||
CObjClosure *closure = (CObjClosure *)obj;
|
CObjClosure *closure = (CObjClosure *)obj;
|
||||||
cosmoM_freearray(state, CObjUpval *, closure->upvalues, closure->upvalueCount);
|
cosmoM_freeArray(state, CObjUpval *, closure->upvalues, closure->upvalueCount);
|
||||||
cosmoM_free(state, CObjClosure, closure);
|
cosmoM_free(state, CObjClosure, closure);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -164,14 +164,12 @@ _eqFail:
|
|||||||
cosmoV_pushValue(state, eq1);
|
cosmoV_pushValue(state, eq1);
|
||||||
cosmoV_pushRef(state, obj1);
|
cosmoV_pushRef(state, obj1);
|
||||||
cosmoV_pushRef(state, obj2);
|
cosmoV_pushRef(state, obj2);
|
||||||
if (!cosmoV_call(state, 2, 1))
|
cosmoV_call(state, 2, 1);
|
||||||
return false;
|
|
||||||
|
|
||||||
// check return value and make sure it's a boolean
|
// check return value and make sure it's a boolean
|
||||||
if (!IS_BOOLEAN(*cosmoV_getTop(state, 0))) {
|
if (!IS_BOOLEAN(*cosmoV_getTop(state, 0))) {
|
||||||
cosmoV_error(state, "__equal expected to return <boolean>, got %s!",
|
cosmoV_error(state, "__equal expected to return <boolean>, got %s!",
|
||||||
cosmoV_typeStr(*cosmoV_pop(state)));
|
cosmoV_typeStr(*cosmoV_pop(state)));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the result
|
// return the result
|
||||||
@ -231,14 +229,13 @@ CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func)
|
|||||||
|
|
||||||
CObjError *cosmoO_newError(CState *state, CValue err)
|
CObjError *cosmoO_newError(CState *state, CValue err)
|
||||||
{
|
{
|
||||||
|
CCallFrame *frames = cosmoM_xmalloc(state, sizeof(CCallFrame) * state->frameCount);
|
||||||
CObjError *cerror = (CObjError *)cosmoO_allocateBase(state, sizeof(CObjError), COBJ_ERROR);
|
CObjError *cerror = (CObjError *)cosmoO_allocateBase(state, sizeof(CObjError), COBJ_ERROR);
|
||||||
cerror->err = err;
|
cerror->err = err;
|
||||||
cerror->frameCount = state->frameCount;
|
cerror->frameCount = state->frameCount;
|
||||||
|
cerror->frames = frames;
|
||||||
cerror->parserError = false;
|
cerror->parserError = false;
|
||||||
|
|
||||||
// allocate the callframe
|
|
||||||
cerror->frames = cosmoM_xmalloc(state, sizeof(CCallFrame) * cerror->frameCount);
|
|
||||||
|
|
||||||
// clone the call frame
|
// clone the call frame
|
||||||
for (int i = 0; i < state->frameCount; i++)
|
for (int i = 0; i < state->frameCount; i++)
|
||||||
cerror->frames[i] = state->callFrame[i];
|
cerror->frames[i] = state->callFrame[i];
|
||||||
@ -308,7 +305,7 @@ CObjString *cosmoO_takeString(CState *state, char *str, size_t length)
|
|||||||
|
|
||||||
// have we already interned this string?
|
// have we already interned this string?
|
||||||
if (lookup != NULL) {
|
if (lookup != NULL) {
|
||||||
cosmoM_freearray(state, char, str,
|
cosmoM_freeArray(state, char, str,
|
||||||
length + 1); // free our passed character array, it's unneeded!
|
length + 1); // free our passed character array, it's unneeded!
|
||||||
return lookup;
|
return lookup;
|
||||||
}
|
}
|
||||||
@ -324,8 +321,7 @@ CObjString *cosmoO_allocateString(CState *state, const char *str, size_t sz, uin
|
|||||||
strObj->length = sz;
|
strObj->length = sz;
|
||||||
strObj->hash = hash;
|
strObj->hash = hash;
|
||||||
|
|
||||||
// we push & pop the string so our GC can find it (we don't use freezeGC/unfreezeGC because we
|
// push/pop to make sure GC doesn't collect it
|
||||||
// *want* a GC event to happen)
|
|
||||||
cosmoV_pushRef(state, (CObj *)strObj);
|
cosmoV_pushRef(state, (CObj *)strObj);
|
||||||
cosmoT_insert(state, &state->strings, cosmoV_newRef((CObj *)strObj));
|
cosmoT_insert(state, &state->strings, cosmoV_newRef((CObj *)strObj));
|
||||||
cosmoV_pop(state);
|
cosmoV_pop(state);
|
||||||
@ -409,9 +405,8 @@ bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *v
|
|||||||
cosmoT_get(state, &cosmoV_readTable(*val)->tbl, key, val)) {
|
cosmoT_get(state, &cosmoV_readTable(*val)->tbl, key, val)) {
|
||||||
cosmoV_pushValue(state, *val); // push function
|
cosmoV_pushValue(state, *val); // push function
|
||||||
cosmoV_pushRef(state, (CObj *)obj); // push object
|
cosmoV_pushRef(state, (CObj *)obj); // push object
|
||||||
if (!cosmoV_call(state, 1, 1)) // call the function with the 1 argument
|
cosmoV_call(state, 1, 1); // call the function with the 1 argument
|
||||||
return false;
|
*val = *cosmoV_pop(state); // set value to the return value of __index
|
||||||
*val = *cosmoV_pop(state); // set value to the return value of __index
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,9 +525,8 @@ bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *v
|
|||||||
cosmoV_pushValue(state, *val); // push function
|
cosmoV_pushValue(state, *val); // push function
|
||||||
cosmoV_pushRef(state, (CObj *)object); // push object
|
cosmoV_pushRef(state, (CObj *)object); // push object
|
||||||
cosmoV_pushValue(state, key); // push key
|
cosmoV_pushValue(state, key); // push key
|
||||||
if (!cosmoV_call(state, 2, 1)) // call the function with the 2 arguments
|
cosmoV_call(state, 2, 1); // call the function with the 2 arguments
|
||||||
return false;
|
*val = *cosmoV_pop(state); // set value to the return value of __index
|
||||||
*val = *cosmoV_pop(state); // set value to the return value of __index
|
|
||||||
return true;
|
return true;
|
||||||
} else { // there's no __index function defined!
|
} else { // there's no __index function defined!
|
||||||
cosmoV_error(state, "Couldn't index object without __index function!");
|
cosmoV_error(state, "Couldn't index object without __index function!");
|
||||||
@ -550,7 +544,8 @@ bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue
|
|||||||
cosmoV_pushRef(state, (CObj *)object); // push object
|
cosmoV_pushRef(state, (CObj *)object); // push object
|
||||||
cosmoV_pushValue(state, key); // push key & value pair
|
cosmoV_pushValue(state, key); // push key & value pair
|
||||||
cosmoV_pushValue(state, val);
|
cosmoV_pushValue(state, val);
|
||||||
return cosmoV_call(state, 3, 0);
|
cosmoV_call(state, 3, 0);
|
||||||
|
return true;
|
||||||
} else { // there's no __newindex function defined
|
} else { // there's no __newindex function defined
|
||||||
cosmoV_error(state, "Couldn't set index on object without __newindex function!");
|
cosmoV_error(state, "Couldn't set index on object without __newindex function!");
|
||||||
}
|
}
|
||||||
@ -567,8 +562,7 @@ CObjString *cosmoO_toString(CState *state, CObj *obj)
|
|||||||
if (protoObject != NULL && cosmoO_getIString(state, protoObject, ISTRING_TOSTRING, &res)) {
|
if (protoObject != NULL && cosmoO_getIString(state, protoObject, ISTRING_TOSTRING, &res)) {
|
||||||
cosmoV_pushValue(state, res);
|
cosmoV_pushValue(state, res);
|
||||||
cosmoV_pushRef(state, (CObj *)obj);
|
cosmoV_pushRef(state, (CObj *)obj);
|
||||||
if (!cosmoV_call(state, 1, 1))
|
cosmoV_call(state, 1, 1);
|
||||||
return cosmoO_copyString(state, "<err>", 5);
|
|
||||||
|
|
||||||
// make sure the __tostring function returned a string
|
// make sure the __tostring function returned a string
|
||||||
StkPtr ret = cosmoV_getTop(state, 0);
|
StkPtr ret = cosmoV_getTop(state, 0);
|
||||||
@ -633,14 +627,12 @@ cosmo_Number cosmoO_toNumber(CState *state, CObj *obj)
|
|||||||
if (proto != NULL && cosmoO_getIString(state, proto, ISTRING_TONUMBER, &res)) {
|
if (proto != NULL && cosmoO_getIString(state, proto, ISTRING_TONUMBER, &res)) {
|
||||||
cosmoV_pushValue(state, res);
|
cosmoV_pushValue(state, res);
|
||||||
cosmoV_pushRef(state, (CObj *)obj);
|
cosmoV_pushRef(state, (CObj *)obj);
|
||||||
if (!cosmoV_call(state, 1, 1)) // call res, expect 1 return val of <number>
|
cosmoV_call(state, 1, 1); // call res, expect 1 return val of <number>
|
||||||
return 0;
|
|
||||||
|
|
||||||
StkPtr temp = cosmoV_getTop(state, 0);
|
StkPtr temp = cosmoV_getTop(state, 0);
|
||||||
if (!IS_NUMBER(*temp)) {
|
if (!IS_NUMBER(*temp)) {
|
||||||
cosmoV_error(state, "__tonumber expected to return <number>, got %s!",
|
cosmoV_error(state, "__tonumber expected to return <number>, got %s!",
|
||||||
cosmoV_typeStr(*temp));
|
cosmoV_typeStr(*temp));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return number
|
// return number
|
||||||
@ -666,8 +658,7 @@ int cosmoO_count(CState *state, CObj *obj)
|
|||||||
if (proto != NULL && cosmoO_getIString(state, proto, ISTRING_COUNT, &res)) {
|
if (proto != NULL && cosmoO_getIString(state, proto, ISTRING_COUNT, &res)) {
|
||||||
cosmoV_pushValue(state, res);
|
cosmoV_pushValue(state, res);
|
||||||
cosmoV_pushRef(state, (CObj *)obj);
|
cosmoV_pushRef(state, (CObj *)obj);
|
||||||
if (!cosmoV_call(state, 1, 1)) // call res, we expect 1 return value of type <number>
|
cosmoV_call(state, 1, 1); // call res, we expect 1 return value of type <number>
|
||||||
return 0;
|
|
||||||
|
|
||||||
StkPtr ret = cosmoV_getTop(state, 0);
|
StkPtr ret = cosmoV_getTop(state, 0);
|
||||||
if (!IS_NUMBER(*ret)) {
|
if (!IS_NUMBER(*ret)) {
|
||||||
@ -769,6 +760,8 @@ const char *cosmoO_typeStr(CObj *obj)
|
|||||||
return "<function>";
|
return "<function>";
|
||||||
case COBJ_CFUNCTION:
|
case COBJ_CFUNCTION:
|
||||||
return "<c function>";
|
return "<c function>";
|
||||||
|
case COBJ_ERROR:
|
||||||
|
return "<error>";
|
||||||
case COBJ_METHOD:
|
case COBJ_METHOD:
|
||||||
return "<method>";
|
return "<method>";
|
||||||
case COBJ_CLOSURE:
|
case COBJ_CLOSURE:
|
||||||
|
@ -136,6 +136,7 @@ struct CObjUpval
|
|||||||
#define cosmoV_readCFunction(x) (((CObjCFunction *)cosmoV_readRef(x))->cfunc)
|
#define cosmoV_readCFunction(x) (((CObjCFunction *)cosmoV_readRef(x))->cfunc)
|
||||||
#define cosmoV_readMethod(x) ((CObjMethod *)cosmoV_readRef(x))
|
#define cosmoV_readMethod(x) ((CObjMethod *)cosmoV_readRef(x))
|
||||||
#define cosmoV_readClosure(x) ((CObjClosure *)cosmoV_readRef(x))
|
#define cosmoV_readClosure(x) ((CObjClosure *)cosmoV_readRef(x))
|
||||||
|
#define cosmoV_readError(x) ((CObjError *)cosmoV_readRef(x))
|
||||||
|
|
||||||
#define cosmoO_readCString(x) ((CObjString *)x)->str
|
#define cosmoO_readCString(x) ((CObjString *)x)->str
|
||||||
#define cosmoO_readType(x) ((CObj *)x)->type
|
#define cosmoO_readType(x) ((CObj *)x)->type
|
||||||
|
94
src/cparse.c
94
src/cparse.c
@ -59,14 +59,15 @@ typedef struct CCompilerState
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
CLexState lex;
|
||||||
CState *state;
|
CState *state;
|
||||||
CLexState *lex;
|
|
||||||
CCompilerState *compiler;
|
CCompilerState *compiler;
|
||||||
CObjString *module; // name of the module
|
CObjString *module; // name of the module
|
||||||
CToken current;
|
CToken current;
|
||||||
CToken previous; // token right after the current token
|
CToken previous; // token right after the current token
|
||||||
bool hadError;
|
int workingStackCount; // we push CValues of objects we need onto the stack so the garbage
|
||||||
bool panic;
|
// collector can see them. this is the count of those values so we'll
|
||||||
|
// know how many to pop off when we're done
|
||||||
} CParseState;
|
} CParseState;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -109,6 +110,12 @@ static CObjFunction *endCompiler(CParseState *pstate);
|
|||||||
|
|
||||||
// ================================================================ [FRONT END/TALK TO LEXER]
|
// ================================================================ [FRONT END/TALK TO LEXER]
|
||||||
|
|
||||||
|
static void keepTrackOf(CParseState *pstate, CValue val)
|
||||||
|
{
|
||||||
|
pstate->workingStackCount++;
|
||||||
|
cosmoV_pushValue(pstate->state, val);
|
||||||
|
}
|
||||||
|
|
||||||
static void initCompilerState(CParseState *pstate, CCompilerState *ccstate, FunctionType type,
|
static void initCompilerState(CParseState *pstate, CCompilerState *ccstate, FunctionType type,
|
||||||
CCompilerState *enclosing)
|
CCompilerState *enclosing)
|
||||||
{
|
{
|
||||||
@ -124,6 +131,8 @@ static void initCompilerState(CParseState *pstate, CCompilerState *ccstate, Func
|
|||||||
ccstate->function = cosmoO_newFunction(pstate->state);
|
ccstate->function = cosmoO_newFunction(pstate->state);
|
||||||
ccstate->function->module = pstate->module;
|
ccstate->function->module = pstate->module;
|
||||||
|
|
||||||
|
keepTrackOf(pstate, cosmoV_newRef((CObj *)ccstate->function));
|
||||||
|
|
||||||
ccstate->loop.scope = -1; // there is no loop yet
|
ccstate->loop.scope = -1; // there is no loop yet
|
||||||
|
|
||||||
if (type != FTYPE_SCRIPT) {
|
if (type != FTYPE_SCRIPT) {
|
||||||
@ -146,27 +155,27 @@ static void initCompilerState(CParseState *pstate, CCompilerState *ccstate, Func
|
|||||||
static void initParseState(CParseState *pstate, CCompilerState *ccstate, CState *s,
|
static void initParseState(CParseState *pstate, CCompilerState *ccstate, CState *s,
|
||||||
const char *source, const char *module)
|
const char *source, const char *module)
|
||||||
{
|
{
|
||||||
pstate->lex = cosmoL_newLexState(s, source);
|
cosmoL_initLexState(s, &pstate->lex, source);
|
||||||
|
|
||||||
pstate->state = s;
|
pstate->state = s;
|
||||||
pstate->hadError = false;
|
|
||||||
pstate->panic = false;
|
|
||||||
pstate->compiler = ccstate;
|
pstate->compiler = ccstate;
|
||||||
pstate->module = cosmoO_copyString(s, module, strlen(module));
|
pstate->module = cosmoO_copyString(s, module, strlen(module));
|
||||||
|
pstate->workingStackCount = 0;
|
||||||
|
|
||||||
|
keepTrackOf(pstate, cosmoV_newRef((CObj *)pstate->module));
|
||||||
initCompilerState(pstate, ccstate, FTYPE_SCRIPT, NULL); // enclosing starts as NULL
|
initCompilerState(pstate, ccstate, FTYPE_SCRIPT, NULL); // enclosing starts as NULL
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeParseState(CParseState *pstate)
|
static void freeParseState(CParseState *pstate)
|
||||||
{
|
{
|
||||||
cosmoL_freeLexState(pstate->state, pstate->lex);
|
cosmoL_cleanupLexState(pstate->state, &pstate->lex);
|
||||||
|
|
||||||
|
// pop our working values off the stack
|
||||||
|
cosmoV_setTop(pstate->state, pstate->workingStackCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void errorAt(CParseState *pstate, CToken *token, const char *format, va_list args)
|
static void errorAt(CParseState *pstate, CToken *token, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
if (pstate->hadError)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (token->type == TOKEN_EOF) {
|
if (token->type == TOKEN_EOF) {
|
||||||
cosmoV_pushString(pstate->state, "At end: ");
|
cosmoV_pushString(pstate->state, "At end: ");
|
||||||
} else if (!(token->type == TOKEN_ERROR)) {
|
} else if (!(token->type == TOKEN_ERROR)) {
|
||||||
@ -177,14 +186,9 @@ static void errorAt(CParseState *pstate, CToken *token, const char *format, va_l
|
|||||||
|
|
||||||
cosmoO_pushVFString(pstate->state, format, args);
|
cosmoO_pushVFString(pstate->state, format, args);
|
||||||
|
|
||||||
cosmoV_concat(pstate->state, 2); // concats the two strings together
|
// throw complete error string
|
||||||
|
cosmoV_concat(pstate->state, 2);
|
||||||
CObjError *err = cosmoV_throw(pstate->state);
|
cosmoV_throw(pstate->state);
|
||||||
err->line = token->line;
|
|
||||||
err->parserError = true;
|
|
||||||
|
|
||||||
pstate->hadError = true;
|
|
||||||
pstate->panic = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void errorAtCurrent(CParseState *pstate, const char *format, ...)
|
static void errorAtCurrent(CParseState *pstate, const char *format, ...)
|
||||||
@ -206,7 +210,7 @@ static void error(CParseState *pstate, const char *format, ...)
|
|||||||
static void advance(CParseState *pstate)
|
static void advance(CParseState *pstate)
|
||||||
{
|
{
|
||||||
pstate->previous = pstate->current;
|
pstate->previous = pstate->current;
|
||||||
pstate->current = cosmoL_scanToken(pstate->lex);
|
pstate->current = cosmoL_scanToken(&pstate->lex);
|
||||||
|
|
||||||
if (pstate->current.type == TOKEN_ERROR) {
|
if (pstate->current.type == TOKEN_ERROR) {
|
||||||
errorAtCurrent(pstate, pstate->current.start);
|
errorAtCurrent(pstate, pstate->current.start);
|
||||||
@ -280,7 +284,6 @@ uint16_t makeConstant(CParseState *pstate, CValue val)
|
|||||||
int indx = addConstant(pstate->state, getChunk(pstate), val);
|
int indx = addConstant(pstate->state, getChunk(pstate), val);
|
||||||
if (indx > UINT16_MAX) {
|
if (indx > UINT16_MAX) {
|
||||||
error(pstate, "UInt overflow! Too many constants in one chunk!");
|
error(pstate, "UInt overflow! Too many constants in one chunk!");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (uint16_t)indx;
|
return (uint16_t)indx;
|
||||||
@ -350,7 +353,6 @@ static void addLocal(CParseState *pstate, CToken name)
|
|||||||
{
|
{
|
||||||
if (pstate->compiler->localCount > UINT8_MAX) {
|
if (pstate->compiler->localCount > UINT8_MAX) {
|
||||||
error(pstate, "UInt overflow! Too many locals in scope!");
|
error(pstate, "UInt overflow! Too many locals in scope!");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Local *local = &pstate->compiler->locals[pstate->compiler->localCount++];
|
Local *local = &pstate->compiler->locals[pstate->compiler->localCount++];
|
||||||
@ -365,7 +367,6 @@ static int addUpvalue(CParseState *pstate, CCompilerState *ccstate, uint8_t indx
|
|||||||
|
|
||||||
if (upvals > UINT8_MAX) {
|
if (upvals > UINT8_MAX) {
|
||||||
error(pstate, "UInt overflow! Too many upvalues in scope!");
|
error(pstate, "UInt overflow! Too many upvalues in scope!");
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check and make sure we haven't already captured it
|
// check and make sure we haven't already captured it
|
||||||
@ -481,6 +482,7 @@ static void string(CParseState *pstate, bool canAssign, Precedence prec)
|
|||||||
{
|
{
|
||||||
CObjString *strObj =
|
CObjString *strObj =
|
||||||
cosmoO_takeString(pstate->state, pstate->previous.start, pstate->previous.length);
|
cosmoO_takeString(pstate->state, pstate->previous.start, pstate->previous.length);
|
||||||
|
keepTrackOf(pstate, cosmoV_newRef((CObj *)strObj));
|
||||||
writeConstant(pstate, cosmoV_newRef((CObj *)strObj));
|
writeConstant(pstate, cosmoV_newRef((CObj *)strObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -768,7 +770,6 @@ static void table(CParseState *pstate, bool canAssign, Precedence prec)
|
|||||||
tblType = 1; // array-like
|
tblType = 1; // array-like
|
||||||
} else {
|
} else {
|
||||||
error(pstate, "Can't change table description type mid-definition!");
|
error(pstate, "Can't change table description type mid-definition!");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entries++;
|
entries++;
|
||||||
@ -818,7 +819,7 @@ static void object(CParseState *pstate, bool canAssign, Precedence prec)
|
|||||||
// "pop" the 1 value
|
// "pop" the 1 value
|
||||||
valuePopped(pstate, 1);
|
valuePopped(pstate, 1);
|
||||||
entries++;
|
entries++;
|
||||||
} while (match(pstate, TOKEN_COMMA) && !pstate->hadError);
|
} while (match(pstate, TOKEN_COMMA));
|
||||||
|
|
||||||
consume(pstate, TOKEN_RIGHT_BRACE, "Expected '}' to end object definition.");
|
consume(pstate, TOKEN_RIGHT_BRACE, "Expected '}' to end object definition.");
|
||||||
}
|
}
|
||||||
@ -1158,9 +1159,6 @@ static uint16_t parseVariable(CParseState *pstate, const char *errorMessage, boo
|
|||||||
|
|
||||||
static void defineVariable(CParseState *pstate, uint16_t global, bool forceLocal)
|
static void defineVariable(CParseState *pstate, uint16_t global, bool forceLocal)
|
||||||
{
|
{
|
||||||
if (pstate->hadError)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pstate->compiler->scopeDepth > 0 || forceLocal) {
|
if (pstate->compiler->scopeDepth > 0 || forceLocal) {
|
||||||
markInitialized(pstate, global);
|
markInitialized(pstate, global);
|
||||||
valuePopped(pstate, 1); // the local stays on the stack!
|
valuePopped(pstate, 1); // the local stays on the stack!
|
||||||
@ -1177,7 +1175,7 @@ static void _proto(CParseState *pstate)
|
|||||||
{
|
{
|
||||||
int entries = 0;
|
int entries = 0;
|
||||||
|
|
||||||
while (!match(pstate, TOKEN_END) && !match(pstate, TOKEN_EOF) && !pstate->hadError) {
|
while (!match(pstate, TOKEN_END) && !match(pstate, TOKEN_EOF)) {
|
||||||
if (match(pstate, TOKEN_FUNC)) {
|
if (match(pstate, TOKEN_FUNC)) {
|
||||||
// define method
|
// define method
|
||||||
consume(pstate, TOKEN_IDENTIFIER, "Expected identifier for method!");
|
consume(pstate, TOKEN_IDENTIFIER, "Expected identifier for method!");
|
||||||
@ -1224,9 +1222,6 @@ static void localProto(CParseState *pstate)
|
|||||||
|
|
||||||
static void popLocals(CParseState *pstate, int toScope)
|
static void popLocals(CParseState *pstate, int toScope)
|
||||||
{
|
{
|
||||||
if (pstate->hadError)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// count the locals in scope to pop
|
// count the locals in scope to pop
|
||||||
int localsToPop = 0;
|
int localsToPop = 0;
|
||||||
|
|
||||||
@ -1376,7 +1371,7 @@ static void endLoop(CParseState *pstate)
|
|||||||
patchJmp(pstate, pstate->compiler->loop.breaks[--pstate->compiler->loop.breakCount]);
|
patchJmp(pstate, pstate->compiler->loop.breaks[--pstate->compiler->loop.breakCount]);
|
||||||
}
|
}
|
||||||
|
|
||||||
cosmoM_freearray(pstate->state, int, pstate->compiler->loop.breaks,
|
cosmoM_freeArray(pstate->state, int, pstate->compiler->loop.breaks,
|
||||||
pstate->compiler->loop.breakCapacity);
|
pstate->compiler->loop.breakCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1665,7 +1660,7 @@ static void breakStatement(CParseState *pstate)
|
|||||||
pstate->compiler->localCount = savedLocals;
|
pstate->compiler->localCount = savedLocals;
|
||||||
|
|
||||||
// add break to loop
|
// add break to loop
|
||||||
cosmoM_growarray(pstate->state, int, pstate->compiler->loop.breaks,
|
cosmoM_growArray(pstate->state, int, pstate->compiler->loop.breaks,
|
||||||
pstate->compiler->loop.breakCount, pstate->compiler->loop.breakCapacity);
|
pstate->compiler->loop.breakCount, pstate->compiler->loop.breakCapacity);
|
||||||
pstate->compiler->loop.breaks[pstate->compiler->loop.breakCount++] = writeJmp(pstate, OP_JMP);
|
pstate->compiler->loop.breaks[pstate->compiler->loop.breakCount++] = writeJmp(pstate, OP_JMP);
|
||||||
}
|
}
|
||||||
@ -1686,18 +1681,6 @@ static void continueStatement(CParseState *pstate)
|
|||||||
writeJmpBack(pstate, pstate->compiler->loop.startBytecode);
|
writeJmpBack(pstate, pstate->compiler->loop.startBytecode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void synchronize(CParseState *pstate)
|
|
||||||
{
|
|
||||||
pstate->panic = false;
|
|
||||||
|
|
||||||
while (pstate->current.type != TOKEN_EOF) {
|
|
||||||
if (pstate->previous.type == TOKEN_EOS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
advance(pstate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int expressionPrecedence(CParseState *pstate, int needed, Precedence prec, bool forceNeeded)
|
static int expressionPrecedence(CParseState *pstate, int needed, Precedence prec, bool forceNeeded)
|
||||||
{
|
{
|
||||||
int lastExpected = pstate->compiler->expectedValues;
|
int lastExpected = pstate->compiler->expectedValues;
|
||||||
@ -1787,10 +1770,6 @@ static void statement(CParseState *pstate)
|
|||||||
static void declaration(CParseState *pstate)
|
static void declaration(CParseState *pstate)
|
||||||
{
|
{
|
||||||
statement(pstate);
|
statement(pstate);
|
||||||
|
|
||||||
// if we paniced, skip the whole statement!
|
|
||||||
if (pstate->panic)
|
|
||||||
synchronize(pstate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static CObjFunction *endCompiler(CParseState *pstate)
|
static CObjFunction *endCompiler(CParseState *pstate)
|
||||||
@ -1812,7 +1791,6 @@ CObjFunction *cosmoP_compileString(CState *state, const char *source, const char
|
|||||||
{
|
{
|
||||||
CParseState parser;
|
CParseState parser;
|
||||||
CCompilerState compiler;
|
CCompilerState compiler;
|
||||||
cosmoM_freezeGC(state); // ignore all GC events while compiling
|
|
||||||
initParseState(&parser, &compiler, state, source, module);
|
initParseState(&parser, &compiler, state, source, module);
|
||||||
|
|
||||||
advance(&parser);
|
advance(&parser);
|
||||||
@ -1825,24 +1803,10 @@ CObjFunction *cosmoP_compileString(CState *state, const char *source, const char
|
|||||||
|
|
||||||
popLocals(&parser, 0);
|
popLocals(&parser, 0);
|
||||||
|
|
||||||
if (parser.hadError) { // we don't free the function, the state already has a reference to it in
|
|
||||||
// it's linked list of objects!
|
|
||||||
endCompiler(&parser);
|
|
||||||
freeParseState(&parser);
|
|
||||||
|
|
||||||
cosmoM_unfreezeGC(state);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CObjFunction *resFunc = compiler.function;
|
CObjFunction *resFunc = compiler.function;
|
||||||
|
|
||||||
// finally free out parser states
|
// finally free out parser states
|
||||||
endCompiler(&parser);
|
endCompiler(&parser);
|
||||||
freeParseState(&parser);
|
freeParseState(&parser);
|
||||||
|
|
||||||
// push the funciton onto the stack so if we cause an GC event, it won't be free'd
|
|
||||||
cosmoV_pushRef(state, (CObj *)resFunc);
|
|
||||||
cosmoM_unfreezeGC(state);
|
|
||||||
cosmoV_pop(state);
|
|
||||||
return resFunc;
|
return resFunc;
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
#include "clex.h"
|
#include "clex.h"
|
||||||
#include "cosmo.h"
|
#include "cosmo.h"
|
||||||
|
|
||||||
// compiles source into CChunk, if NULL is returned, a syntaxical error has occurred and pushed onto
|
// compiles source into CChunk
|
||||||
// the stack
|
|
||||||
CObjFunction *cosmoP_compileString(CState *state, const char *source, const char *module);
|
CObjFunction *cosmoP_compileString(CState *state, const char *source, const char *module);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
26
src/cstate.c
26
src/cstate.c
@ -7,6 +7,25 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
CPanic *cosmoV_newPanic(CState *state)
|
||||||
|
{
|
||||||
|
CPanic *panic = cosmoM_xmalloc(state, sizeof(CPanic));
|
||||||
|
panic->top = state->top;
|
||||||
|
panic->frameCount = state->frameCount;
|
||||||
|
panic->prev = state->panic;
|
||||||
|
state->panic = panic;
|
||||||
|
|
||||||
|
return panic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cosmoV_freePanic(CState *state)
|
||||||
|
{
|
||||||
|
CPanic *panic = state->panic;
|
||||||
|
state->panic = panic->prev;
|
||||||
|
|
||||||
|
cosmoM_free(state, CPanic, panic);
|
||||||
|
}
|
||||||
|
|
||||||
CState *cosmoV_newState()
|
CState *cosmoV_newState()
|
||||||
{
|
{
|
||||||
// we use C's malloc because we don't want to trigger a GC with an invalid state
|
// we use C's malloc because we don't want to trigger a GC with an invalid state
|
||||||
@ -17,8 +36,8 @@ CState *cosmoV_newState()
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
state->panic = false;
|
|
||||||
state->freezeGC = 1; // we start frozen
|
state->freezeGC = 1; // we start frozen
|
||||||
|
state->panic = NULL;
|
||||||
|
|
||||||
// GC
|
// GC
|
||||||
state->objects = NULL;
|
state->objects = NULL;
|
||||||
@ -34,8 +53,6 @@ CState *cosmoV_newState()
|
|||||||
state->frameCount = 0;
|
state->frameCount = 0;
|
||||||
state->openUpvalues = NULL;
|
state->openUpvalues = NULL;
|
||||||
|
|
||||||
state->error = NULL;
|
|
||||||
|
|
||||||
// set default proto objects
|
// set default proto objects
|
||||||
for (int i = 0; i < COBJ_MAX; i++)
|
for (int i = 0; i < COBJ_MAX; i++)
|
||||||
state->protoObjects[i] = NULL;
|
state->protoObjects[i] = NULL;
|
||||||
@ -80,7 +97,6 @@ void cosmoV_freeState(CState *state)
|
|||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
printf("state %p is being free'd!\n", state);
|
printf("state %p is being free'd!\n", state);
|
||||||
#endif
|
#endif
|
||||||
cosmoM_freezeGC(state);
|
|
||||||
|
|
||||||
// frees all the objects
|
// frees all the objects
|
||||||
CObj *objs = state->objects;
|
CObj *objs = state->objects;
|
||||||
@ -104,7 +120,7 @@ void cosmoV_freeState(CState *state)
|
|||||||
cosmoT_clearTable(state, &state->strings);
|
cosmoT_clearTable(state, &state->strings);
|
||||||
|
|
||||||
// free our gray stack & finally free the state structure
|
// free our gray stack & finally free the state structure
|
||||||
cosmoM_freearray(state, CObj *, state->grayStack.array, state->grayStack.capacity);
|
cosmoM_freeArray(state, CObj *, state->grayStack.array, state->grayStack.capacity);
|
||||||
|
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
if (state->allocatedBytes != 0) {
|
if (state->allocatedBytes != 0) {
|
||||||
|
55
src/cstate.h
55
src/cstate.h
@ -6,6 +6,8 @@
|
|||||||
#include "ctable.h"
|
#include "ctable.h"
|
||||||
#include "cvalue.h"
|
#include "cvalue.h"
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
struct CCallFrame
|
struct CCallFrame
|
||||||
{
|
{
|
||||||
CObjClosure *closure;
|
CObjClosure *closure;
|
||||||
@ -38,36 +40,47 @@ typedef struct ArrayCObj
|
|||||||
int capacity;
|
int capacity;
|
||||||
} ArrayCObj;
|
} ArrayCObj;
|
||||||
|
|
||||||
|
typedef struct CPanic
|
||||||
|
{
|
||||||
|
jmp_buf jmp;
|
||||||
|
StkPtr top;
|
||||||
|
struct CPanic *prev;
|
||||||
|
int frameCount;
|
||||||
|
} CPanic;
|
||||||
|
|
||||||
struct CState
|
struct CState
|
||||||
{
|
{
|
||||||
bool panic;
|
|
||||||
int freezeGC; // when > 0, GC events will be ignored (for internal use)
|
|
||||||
int frameCount;
|
|
||||||
|
|
||||||
CObjError *error; // NULL, unless panic is true
|
|
||||||
CObj *objects; // tracks all of our allocated objects
|
|
||||||
CObj *userRoots; // user definable roots, this holds CObjs that should be considered "roots",
|
|
||||||
// lets the VM know you are holding a reference to a CObj in your code
|
|
||||||
ArrayCObj grayStack; // keeps track of which objects *haven't yet* been traversed in our GC, but
|
|
||||||
// *have been* found
|
|
||||||
size_t allocatedBytes;
|
|
||||||
size_t nextGC; // when allocatedBytes reaches this threshhold, trigger a GC event
|
|
||||||
|
|
||||||
CObjUpval *openUpvalues; // tracks all of our still open (meaning still on the stack) upvalues
|
|
||||||
CTable strings;
|
|
||||||
CObjTable *globals;
|
|
||||||
|
|
||||||
CValue *top; // top of the stack
|
|
||||||
CObjObject *protoObjects[COBJ_MAX]; // proto object for each COBJ type [NULL = no default proto]
|
|
||||||
CObjString *iStrings[ISTRING_MAX]; // strings used internally by the VM, eg. __init, __index
|
|
||||||
CCallFrame callFrame[FRAME_MAX]; // call frames
|
CCallFrame callFrame[FRAME_MAX]; // call frames
|
||||||
CValue stack[STACK_MAX]; // stack
|
CValue stack[STACK_MAX]; // stack
|
||||||
|
CObjObject *protoObjects[COBJ_MAX]; // proto object for each COBJ type [NULL = no default proto]
|
||||||
|
CObjString *iStrings[ISTRING_MAX]; // strings used internally by the VM, eg. __init, __index
|
||||||
|
CTable strings;
|
||||||
|
ArrayCObj grayStack; // keeps track of which objects *haven't yet* been traversed in our GC, but
|
||||||
|
// *have been* found
|
||||||
|
|
||||||
|
CObjUpval *openUpvalues; // tracks all of our still open (meaning still on the stack) upvalues
|
||||||
|
CObjTable *globals;
|
||||||
|
CValue *top; // top of the stack
|
||||||
|
CObj *objects; // tracks all of our allocated objects
|
||||||
|
CObj *userRoots; // user definable roots, this holds CObjs that should be considered "roots",
|
||||||
|
// lets the VM know you are holding a reference to a CObj in your code
|
||||||
|
CPanic *panic;
|
||||||
|
|
||||||
|
int freezeGC; // when > 0, GC events will be ignored (for internal use)
|
||||||
|
int frameCount;
|
||||||
|
size_t allocatedBytes;
|
||||||
|
size_t nextGC; // when allocatedBytes reaches this threshhold, trigger a GC event
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CPanic *cosmoV_newPanic(CState *state);
|
||||||
|
void cosmoV_freePanic(CState *state);
|
||||||
|
|
||||||
COSMO_API CState *cosmoV_newState();
|
COSMO_API CState *cosmoV_newState();
|
||||||
|
COSMO_API void cosmoV_freeState(CState *state);
|
||||||
|
|
||||||
// expects 2*pairs values on the stack, each pair should consist of 1 key and 1 value
|
// expects 2*pairs values on the stack, each pair should consist of 1 key and 1 value
|
||||||
COSMO_API void cosmoV_register(CState *state, int pairs);
|
COSMO_API void cosmoV_register(CState *state, int pairs);
|
||||||
COSMO_API void cosmoV_freeState(CState *state);
|
|
||||||
COSMO_API void cosmoV_printStack(CState *state);
|
COSMO_API void cosmoV_printStack(CState *state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,7 +61,7 @@ void cosmoT_addTable(CState *state, CTable *from, CTable *to)
|
|||||||
|
|
||||||
void cosmoT_clearTable(CState *state, CTable *tbl)
|
void cosmoT_clearTable(CState *state, CTable *tbl)
|
||||||
{
|
{
|
||||||
cosmoM_freearray(state, CTableEntry, tbl->table, cosmoT_getCapacity(tbl));
|
cosmoM_freeArray(state, CTableEntry, tbl->table, cosmoT_getCapacity(tbl));
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t getObjectHash(CObj *obj)
|
static uint32_t getObjectHash(CObj *obj)
|
||||||
@ -165,7 +165,7 @@ static void resizeTbl(CState *state, CTable *tbl, int newCapacity, bool canShrin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// free the old table
|
// free the old table
|
||||||
cosmoM_freearray(state, CTableEntry, tbl->table, oldCap);
|
cosmoM_freeArray(state, CTableEntry, tbl->table, oldCap);
|
||||||
|
|
||||||
tbl->table = entries;
|
tbl->table = entries;
|
||||||
tbl->capacityMask = newCapacity - 1;
|
tbl->capacityMask = newCapacity - 1;
|
||||||
|
@ -13,12 +13,12 @@ void initValArray(CState *state, CValueArray *val, size_t startCapacity)
|
|||||||
|
|
||||||
void cleanValArray(CState *state, CValueArray *array)
|
void cleanValArray(CState *state, CValueArray *array)
|
||||||
{
|
{
|
||||||
cosmoM_freearray(state, CValue, array->values, array->capacity);
|
cosmoM_freeArray(state, CValue, array->values, array->capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendValArray(CState *state, CValueArray *array, CValue val)
|
void appendValArray(CState *state, CValueArray *array, CValue val)
|
||||||
{
|
{
|
||||||
cosmoM_growarray(state, CValue, array->values, array->count, array->capacity);
|
cosmoM_growArray(state, CValue, array->values, array->count, array->capacity);
|
||||||
|
|
||||||
array->values[array->count++] = val;
|
array->values[array->count++] = val;
|
||||||
}
|
}
|
||||||
|
142
src/cvm.c
142
src/cvm.c
@ -10,6 +10,8 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#define cosmoV_protect(panic) setjmp(panic->jmp) == 0
|
||||||
|
|
||||||
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...)
|
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
@ -36,9 +38,6 @@ COSMO_API bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud)
|
|||||||
CObjFunction *func;
|
CObjFunction *func;
|
||||||
|
|
||||||
if (cosmoD_undump(state, reader, ud, &func)) {
|
if (cosmoD_undump(state, reader, ud, &func)) {
|
||||||
// fail recovery
|
|
||||||
state->panic = false;
|
|
||||||
cosmoV_pushRef(state, (CObj *)state->error);
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,15 +52,20 @@ COSMO_API bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns false if failed, error will be on the top of the stack. true if successful, closure will
|
||||||
|
// be on the top of the stack
|
||||||
COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *name)
|
COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *name)
|
||||||
{
|
{
|
||||||
CObjFunction *func;
|
CObjFunction *func;
|
||||||
|
CPanic *panic = cosmoV_newPanic(state);
|
||||||
|
|
||||||
if ((func = cosmoP_compileString(state, src, name)) != NULL) {
|
if (cosmoV_protect(panic)) {
|
||||||
// success
|
func = cosmoP_compileString(state, src, name);
|
||||||
#ifdef VM_DEBUG
|
#ifdef VM_DEBUG
|
||||||
disasmChunk(&func->chunk, func->module->str, 0);
|
disasmChunk(&func->chunk, func->module->str, 0);
|
||||||
#endif
|
#endif
|
||||||
|
cosmoV_freePanic(state);
|
||||||
|
|
||||||
// push function onto the stack so it doesn't it cleaned up by the GC, at the same stack
|
// push function onto the stack so it doesn't it cleaned up by the GC, at the same stack
|
||||||
// location put our closure
|
// location put our closure
|
||||||
cosmoV_pushRef(state, (CObj *)func);
|
cosmoV_pushRef(state, (CObj *)func);
|
||||||
@ -69,9 +73,7 @@ COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fail recovery
|
cosmoV_freePanic(state);
|
||||||
state->panic = false;
|
|
||||||
cosmoV_pushRef(state, (CObj *)state->error);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,30 +111,29 @@ COSMO_API void cosmoV_printError(CState *state, CObjError *err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
takes value on top of the stack and wraps an CObjError around it, state->error is set to that
|
takes value on top of the stack and wraps an CObjError around it, then throws it
|
||||||
value the value on the stack is *expected* to be a string, but not required, so yes, this means
|
|
||||||
you could throw a nil value if you really wanted too..
|
|
||||||
*/
|
*/
|
||||||
CObjError *cosmoV_throw(CState *state)
|
void cosmoV_throw(CState *state)
|
||||||
{
|
{
|
||||||
StkPtr temp = cosmoV_getTop(state, 0);
|
StkPtr temp = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
CObjError *error = cosmoO_newError(state, *temp);
|
CObjError *error = cosmoO_newError(state, *temp);
|
||||||
state->error = error;
|
|
||||||
state->panic = true;
|
|
||||||
|
|
||||||
cosmoV_pop(state); // pops thrown value off the stack
|
CValue val = cosmoV_newRef((CObj *)cosmoO_newError(state, *temp));
|
||||||
return error;
|
if (state->panic) {
|
||||||
|
state->top = state->panic->top;
|
||||||
|
state->frameCount = state->panic->frameCount;
|
||||||
|
cosmoV_pushValue(state, val);
|
||||||
|
longjmp(state->panic->jmp, 1);
|
||||||
|
} else {
|
||||||
|
cosmoV_pushValue(state, val);
|
||||||
|
fprintf(stderr, "Unhandled panic! ");
|
||||||
|
cosmoV_printError(state, error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_error(CState *state, const char *format, ...)
|
void cosmoV_error(CState *state, const char *format, ...)
|
||||||
{
|
{
|
||||||
if (state->panic)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// i set panic before calling cosmoO_pushVFString, since that can also call cosmoV_error
|
|
||||||
state->panic = true;
|
|
||||||
|
|
||||||
// format the error string and push it onto the stack
|
// format the error string and push it onto the stack
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
@ -237,18 +238,16 @@ void cosmoV_concat(CState *state, int vals)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int cosmoV_execute(CState *state);
|
int cosmoV_execute(CState *state);
|
||||||
bool invokeMethod(CState *state, CObj *obj, CValue func, int args, int nresults, int offset);
|
void invokeMethod(CState *state, CObj *obj, CValue func, int args, int nresults, int offset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
calls a native C Function with # args on the stack, nresults are pushed onto the stack upon
|
calls a native C Function with # args on the stack, nresults are pushed onto the stack upon
|
||||||
return.
|
return.
|
||||||
|
|
||||||
returns:
|
state->top is moved to base + offset + nresults, with nresults pushed onto the stack
|
||||||
false: state paniced during C Function, error is at state->error
|
from base + offset
|
||||||
true: state->top is moved to base + offset + nresults, with nresults pushed onto the stack
|
|
||||||
from base + offset
|
|
||||||
*/
|
*/
|
||||||
static bool callCFunction(CState *state, CosmoCFunction cfunc, int args, int nresults, int offset)
|
static void callCFunction(CState *state, CosmoCFunction cfunc, int args, int nresults, int offset)
|
||||||
{
|
{
|
||||||
StkPtr savedBase = cosmoV_getTop(state, args);
|
StkPtr savedBase = cosmoV_getTop(state, args);
|
||||||
|
|
||||||
@ -260,13 +259,8 @@ static bool callCFunction(CState *state, CosmoCFunction cfunc, int args, int nre
|
|||||||
|
|
||||||
// remember where the return values are
|
// remember where the return values are
|
||||||
StkPtr results = cosmoV_getTop(state, nres - 1);
|
StkPtr results = cosmoV_getTop(state, nres - 1);
|
||||||
|
|
||||||
state->top = savedBase + offset; // set stack
|
state->top = savedBase + offset; // set stack
|
||||||
|
|
||||||
// if the state paniced during the c function, return false
|
|
||||||
if (state->panic)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// push the return value back onto the stack
|
// push the return value back onto the stack
|
||||||
memmove(state->top, results,
|
memmove(state->top, results,
|
||||||
sizeof(CValue) * nres); // copies the return values to the top of the stack
|
sizeof(CValue) * nres); // copies the return values to the top of the stack
|
||||||
@ -275,20 +269,16 @@ static bool callCFunction(CState *state, CosmoCFunction cfunc, int args, int nre
|
|||||||
// now, if the caller function expected more return values, push nils onto the stack
|
// now, if the caller function expected more return values, push nils onto the stack
|
||||||
for (int i = nres; i < nresults; i++)
|
for (int i = nres; i < nresults; i++)
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
calls a raw closure object with # args on the stack, nresults are pushed onto the stack upon
|
calls a raw closure object with # args on the stack, nresults are pushed onto the stack upon
|
||||||
return.
|
return.
|
||||||
|
|
||||||
returns:
|
stack->top is moved to base + offset + nresults, with nresults pushed onto the stack
|
||||||
false: state paniced, error is at state->error
|
from base + offset
|
||||||
true: stack->top is moved to base + offset + nresults, with nresults pushed onto the stack
|
|
||||||
from base + offset
|
|
||||||
*/
|
*/
|
||||||
static bool rawCall(CState *state, CObjClosure *closure, int args, int nresults, int offset)
|
static void rawCall(CState *state, CObjClosure *closure, int args, int nresults, int offset)
|
||||||
{
|
{
|
||||||
CObjFunction *func = closure->function;
|
CObjFunction *func = closure->function;
|
||||||
|
|
||||||
@ -312,7 +302,6 @@ static bool rawCall(CState *state, CObjClosure *closure, int args, int nresults,
|
|||||||
cosmoV_error(state, "Expected %d arguments for %s, got %d!", closure->function->args,
|
cosmoV_error(state, "Expected %d arguments for %s, got %d!", closure->function->args,
|
||||||
closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str,
|
closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str,
|
||||||
args);
|
args);
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
// load function into callframe
|
// load function into callframe
|
||||||
pushCallFrame(state, closure, func->args);
|
pushCallFrame(state, closure, func->args);
|
||||||
@ -330,9 +319,6 @@ static bool rawCall(CState *state, CObjClosure *closure, int args, int nresults,
|
|||||||
// pop the callframe and return results :)
|
// pop the callframe and return results :)
|
||||||
popCallFrame(state, offset);
|
popCallFrame(state, offset);
|
||||||
|
|
||||||
if (state->panic) // panic state
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// push the return values back onto the stack
|
// push the return values back onto the stack
|
||||||
for (int i = 0; i < nres; i++) {
|
for (int i = 0; i < nres; i++) {
|
||||||
state->top[i] = results[i];
|
state->top[i] = results[i];
|
||||||
@ -342,12 +328,10 @@ static bool rawCall(CState *state, CObjClosure *closure, int args, int nresults,
|
|||||||
// now, if the caller function expected more return values, push nils onto the stack
|
// now, if the caller function expected more return values, push nils onto the stack
|
||||||
for (int i = nres; i < nresults; i++)
|
for (int i = nres; i < nresults; i++)
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if successful, false if error
|
// returns true if successful, false if error
|
||||||
bool callCValue(CState *state, CValue func, int args, int nresults, int offset)
|
void callCValue(CState *state, CValue func, int args, int nresults, int offset)
|
||||||
{
|
{
|
||||||
#ifdef VM_DEBUG
|
#ifdef VM_DEBUG
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@ -358,17 +342,19 @@ bool callCValue(CState *state, CValue func, int args, int nresults, int offset)
|
|||||||
|
|
||||||
if (!IS_REF(func)) {
|
if (!IS_REF(func)) {
|
||||||
cosmoV_error(state, "Cannot call non-callable type %s!", cosmoV_typeStr(func));
|
cosmoV_error(state, "Cannot call non-callable type %s!", cosmoV_typeStr(func));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cosmoV_readRef(func)->type) {
|
switch (cosmoV_readRef(func)->type) {
|
||||||
case COBJ_CLOSURE:
|
case COBJ_CLOSURE:
|
||||||
return rawCall(state, cosmoV_readClosure(func), args, nresults, offset);
|
rawCall(state, cosmoV_readClosure(func), args, nresults, offset);
|
||||||
|
break;
|
||||||
case COBJ_CFUNCTION:
|
case COBJ_CFUNCTION:
|
||||||
return callCFunction(state, cosmoV_readCFunction(func), args, nresults, offset);
|
callCFunction(state, cosmoV_readCFunction(func), args, nresults, offset);
|
||||||
|
break;
|
||||||
case COBJ_METHOD: {
|
case COBJ_METHOD: {
|
||||||
CObjMethod *method = (CObjMethod *)cosmoV_readRef(func);
|
CObjMethod *method = (CObjMethod *)cosmoV_readRef(func);
|
||||||
return invokeMethod(state, method->obj, method->func, args, nresults, offset + 1);
|
invokeMethod(state, method->obj, method->func, args, nresults, offset + 1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case COBJ_OBJECT: { // object is being instantiated, making another object
|
case COBJ_OBJECT: { // object is being instantiated, making another object
|
||||||
CObjObject *protoObj = (CObjObject *)cosmoV_readRef(func);
|
CObjObject *protoObj = (CObjObject *)cosmoV_readRef(func);
|
||||||
@ -381,12 +367,10 @@ bool callCValue(CState *state, CValue func, int args, int nresults, int offset)
|
|||||||
|
|
||||||
// check if they defined an initializer (we accept 0 return values)
|
// check if they defined an initializer (we accept 0 return values)
|
||||||
if (cosmoO_getIString(state, protoObj, ISTRING_INIT, &ret)) {
|
if (cosmoO_getIString(state, protoObj, ISTRING_INIT, &ret)) {
|
||||||
if (!invokeMethod(state, (CObj *)newObj, ret, args, 0, offset + 1))
|
invokeMethod(state, (CObj *)newObj, ret, args, 0, offset + 1);
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
// no default initializer
|
// no default initializer
|
||||||
cosmoV_error(state, "Expected __init() in proto, object cannot be instantiated!");
|
cosmoV_error(state, "Expected __init() in proto, object cannot be instantiated!");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nresults > 0) {
|
if (nresults > 0) {
|
||||||
@ -402,19 +386,16 @@ bool callCValue(CState *state, CValue func, int args, int nresults, int offset)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
cosmoV_error(state, "Cannot call non-callable type %s!", cosmoV_typeStr(func));
|
cosmoV_error(state, "Cannot call non-callable type %s!", cosmoV_typeStr(func));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool invokeMethod(CState *state, CObj *obj, CValue func, int args, int nresults, int offset)
|
void invokeMethod(CState *state, CObj *obj, CValue func, int args, int nresults, int offset)
|
||||||
{
|
{
|
||||||
// first, set the first argument to the object
|
// first, set the first argument to the object
|
||||||
StkPtr temp = cosmoV_getTop(state, args);
|
StkPtr temp = cosmoV_getTop(state, args);
|
||||||
*temp = cosmoV_newRef(obj);
|
*temp = cosmoV_newRef(obj);
|
||||||
|
|
||||||
return callCValue(state, func, args + 1, nresults, offset);
|
callCValue(state, func, args + 1, nresults, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wraps cosmoV_call in a protected state, CObjError will be pushed onto the stack if function call
|
// wraps cosmoV_call in a protected state, CObjError will be pushed onto the stack if function call
|
||||||
@ -422,34 +403,34 @@ bool invokeMethod(CState *state, CObj *obj, CValue func, int args, int nresults,
|
|||||||
// returns false if function call failed, true if function call succeeded
|
// returns false if function call failed, true if function call succeeded
|
||||||
bool cosmoV_pcall(CState *state, int args, int nresults)
|
bool cosmoV_pcall(CState *state, int args, int nresults)
|
||||||
{
|
{
|
||||||
StkPtr base = cosmoV_getTop(state, args);
|
CPanic *panic = cosmoV_newPanic(state);
|
||||||
|
|
||||||
if (!callCValue(state, *base, args, nresults, 0)) {
|
if (cosmoV_protect(panic)) {
|
||||||
// restore panic state
|
cosmoV_call(state, args, nresults);
|
||||||
state->panic = false;
|
cosmoV_freePanic(state);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// if cosmoV_protect returns false, the error is already on the top of the stack
|
||||||
|
|
||||||
if (nresults > 0) {
|
if (nresults > 0) {
|
||||||
cosmoV_pushRef(state, (CObj *)state->error);
|
|
||||||
|
|
||||||
// push other expected results onto the stack
|
// push other expected results onto the stack
|
||||||
for (int i = 0; i < nresults - 1; i++)
|
for (int i = 0; i < nresults - 1; i++)
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
cosmoV_pushValue(state, cosmoV_newNil());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cosmoV_freePanic(state);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// calls a callable object at stack->top - args - 1, passing the # of args to the callable, and
|
// calls a callable object at stack->top - args - 1, passing the # of args to the callable, and
|
||||||
// ensuring nresults are returned
|
// ensuring nresults are returned
|
||||||
// returns false if an error was thrown, else true if successful
|
// returns false if an error was thrown, else true if successful
|
||||||
bool cosmoV_call(CState *state, int args, int nresults)
|
void cosmoV_call(CState *state, int args, int nresults)
|
||||||
{
|
{
|
||||||
StkPtr val = cosmoV_getTop(state, args); // function will always be right above the args
|
StkPtr val = cosmoV_getTop(state, args); // function will always be right above the args
|
||||||
|
|
||||||
return callCValue(state, *val, args, nresults, 0);
|
callCValue(state, *val, args, nresults, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isFalsey(StkPtr val)
|
static inline bool isFalsey(StkPtr val)
|
||||||
@ -725,7 +706,7 @@ int cosmoV_execute(CState *state)
|
|||||||
CCallFrame *frame = &state->callFrame[state->frameCount - 1]; // grabs the current frame
|
CCallFrame *frame = &state->callFrame[state->frameCount - 1]; // grabs the current frame
|
||||||
CValue *constants = frame->closure->function->chunk.constants.values; // cache the pointer :)
|
CValue *constants = frame->closure->function->chunk.constants.values; // cache the pointer :)
|
||||||
|
|
||||||
while (!state->panic) {
|
for (;;) {
|
||||||
#ifdef VM_DEBUG
|
#ifdef VM_DEBUG
|
||||||
cosmoV_printStack(state);
|
cosmoV_printStack(state);
|
||||||
disasmInstr(&frame->closure->function->chunk,
|
disasmInstr(&frame->closure->function->chunk,
|
||||||
@ -809,9 +790,7 @@ int cosmoV_execute(CState *state)
|
|||||||
{
|
{
|
||||||
uint8_t args = READBYTE(frame);
|
uint8_t args = READBYTE(frame);
|
||||||
uint8_t nres = READBYTE(frame);
|
uint8_t nres = READBYTE(frame);
|
||||||
if (!cosmoV_call(state, args, nres)) {
|
cosmoV_call(state, args, nres);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
CASE(OP_CLOSURE) :
|
CASE(OP_CLOSURE) :
|
||||||
{
|
{
|
||||||
@ -1036,10 +1015,9 @@ int cosmoV_execute(CState *state)
|
|||||||
cosmoV_pop(state); // pop the object from the stack
|
cosmoV_pop(state); // pop the object from the stack
|
||||||
cosmoV_pushValue(state, val);
|
cosmoV_pushValue(state, val);
|
||||||
cosmoV_pushRef(state, (CObj *)obj);
|
cosmoV_pushRef(state, (CObj *)obj);
|
||||||
if (!cosmoV_call(
|
cosmoV_call(
|
||||||
state, 1,
|
state, 1,
|
||||||
1)) // we expect 1 return value on the stack, the iterable object
|
1); // we expect 1 return value on the stack, the iterable object
|
||||||
return -1;
|
|
||||||
|
|
||||||
StkPtr iObj = cosmoV_getTop(state, 0);
|
StkPtr iObj = cosmoV_getTop(state, 0);
|
||||||
|
|
||||||
@ -1097,8 +1075,7 @@ int cosmoV_execute(CState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cosmoV_pushValue(state, *temp);
|
cosmoV_pushValue(state, *temp);
|
||||||
if (!cosmoV_call(state, 0, nresults))
|
cosmoV_call(state, 0, nresults);
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (IS_NIL(*(cosmoV_getTop(
|
if (IS_NIL(*(cosmoV_getTop(
|
||||||
state, 0)))) { // __next returned a nil, which means to exit the loop
|
state, 0)))) { // __next returned a nil, which means to exit the loop
|
||||||
@ -1356,7 +1333,6 @@ int cosmoV_execute(CState *state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we'll only reach this if state->panic is true
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
src/cvm.h
16
src/cvm.h
@ -13,16 +13,19 @@
|
|||||||
cosmoV_execute by about 20% from benchmarking. of course, if you know
|
cosmoV_execute by about 20% from benchmarking. of course, if you know
|
||||||
your compiler supports computed gotos, you can define VM_JUMPTABLE
|
your compiler supports computed gotos, you can define VM_JUMPTABLE
|
||||||
|
|
||||||
|
although, this is disabled when VM_DEBUG is defined, since it can cause
|
||||||
|
issues with debugging
|
||||||
|
|
||||||
BTW: be weary of maliciously crafted cosmo dumps!! it's very easy to crash
|
BTW: be weary of maliciously crafted cosmo dumps!! it's very easy to crash
|
||||||
cosmo with this enabled and reading invalid opcodes due to us just using the
|
cosmo with this enabled and reading invalid opcodes due to us just using the
|
||||||
opcode as an index into the jump table
|
opcode as an index into the jump table
|
||||||
*/
|
*/
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if (defined(__GNUC__) || defined(__clang__)) && !defined(VM_DEBUG)
|
||||||
# define VM_JUMPTABLE
|
# define VM_JUMPTABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// args = # of pass parameters, nresults = # of expected results
|
// args = # of pass parameters, nresults = # of expected results
|
||||||
COSMO_API bool cosmoV_call(CState *state, int args, int nresults);
|
COSMO_API void cosmoV_call(CState *state, int args, int nresults);
|
||||||
COSMO_API bool cosmoV_pcall(CState *state, int args, int nresults);
|
COSMO_API bool cosmoV_pcall(CState *state, int args, int nresults);
|
||||||
|
|
||||||
// pushes new object onto the stack & returns a pointer to the new object
|
// pushes new object onto the stack & returns a pointer to the new object
|
||||||
@ -31,7 +34,7 @@ COSMO_API void cosmoV_makeTable(CState *state, int pairs);
|
|||||||
COSMO_API void cosmoV_concat(CState *state, int vals);
|
COSMO_API void cosmoV_concat(CState *state, int vals);
|
||||||
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...);
|
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...);
|
||||||
COSMO_API void cosmoV_printError(CState *state, CObjError *err);
|
COSMO_API void cosmoV_printError(CState *state, CObjError *err);
|
||||||
COSMO_API CObjError *cosmoV_throw(CState *state);
|
COSMO_API void cosmoV_throw(CState *state);
|
||||||
COSMO_API void cosmoV_error(CState *state, const char *format, ...);
|
COSMO_API void cosmoV_error(CState *state, const char *format, ...);
|
||||||
COSMO_API void cosmo_insert(CState *state, int indx, CValue val);
|
COSMO_API void cosmo_insert(CState *state, int indx, CValue val);
|
||||||
|
|
||||||
@ -97,13 +100,6 @@ static inline void cosmoV_pushValue(CState *state, CValue val)
|
|||||||
|
|
||||||
// we reserve 8 slots for the error string and whatever c api we might be in
|
// we reserve 8 slots for the error string and whatever c api we might be in
|
||||||
if (stackSize >= STACK_MAX - 8) {
|
if (stackSize >= STACK_MAX - 8) {
|
||||||
if (state->panic) { // we're in a panic state, let the 8 reserved slots be filled
|
|
||||||
if (stackSize < STACK_MAX)
|
|
||||||
*(state->top++) = val;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cosmoV_error(state, "Stack overflow!");
|
cosmoV_error(state, "Stack overflow!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user