2020-10-28 05:16:30 +00:00
|
|
|
#include "cosmo.h"
|
|
|
|
#include "cchunk.h"
|
|
|
|
#include "cdebug.h"
|
|
|
|
#include "cvm.h"
|
|
|
|
#include "cparse.h"
|
|
|
|
#include "cbaselib.h"
|
|
|
|
|
|
|
|
#include "cmem.h"
|
|
|
|
|
2020-11-10 01:44:12 +00:00
|
|
|
static bool _ACTIVE = false;
|
2020-10-28 23:38:50 +00:00
|
|
|
|
2020-12-13 03:53:12 +00:00
|
|
|
int cosmoB_quitRepl(CState *state, int nargs, CValue *args) {
|
2020-10-28 23:38:50 +00:00
|
|
|
_ACTIVE = false;
|
|
|
|
|
2020-12-13 03:53:12 +00:00
|
|
|
return 0; // we don't return anything
|
2020-10-28 23:38:50 +00:00
|
|
|
}
|
|
|
|
|
2020-12-13 03:53:12 +00:00
|
|
|
int cosmoB_input(CState *state, int nargs, CValue *args) {
|
2020-11-13 02:06:38 +00:00
|
|
|
// input() accepts the same params as print()!
|
|
|
|
for (int i = 0; i < nargs; i++) {
|
|
|
|
CObjString *str = cosmoV_toString(state, args[i]);
|
|
|
|
printf("%s", cosmoO_readCString(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
// but, we return user input instead!
|
|
|
|
char line[1024];
|
|
|
|
fgets(line, sizeof(line), stdin);
|
|
|
|
|
2021-01-25 21:04:16 +00:00
|
|
|
cosmoV_pushObj(state, (CObj*)cosmoO_copyString(state, line, strlen(line)-1)); // -1 for the \n
|
2020-12-13 03:53:12 +00:00
|
|
|
|
|
|
|
return 1; // 1 return value
|
2020-11-13 02:06:38 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 18:23:16 +00:00
|
|
|
static void interpret(CState *state, const char *script, const char *mod) {
|
2021-01-10 20:38:53 +00:00
|
|
|
// cosmoV_compileString pushes the result onto the stack (COBJ_ERROR or COBJ_CLOSURE)
|
|
|
|
if (cosmoV_compileString(state, script, mod)) {
|
2020-12-13 03:53:12 +00:00
|
|
|
COSMOVMRESULT res = cosmoV_call(state, 0, 0); // 0 args being passed, 0 results expected
|
2020-10-28 05:16:30 +00:00
|
|
|
|
2020-11-10 01:44:12 +00:00
|
|
|
if (res == COSMOVM_RUNTIME_ERR)
|
Added CObjError, cosmoV_throw(), pcall(), and cosmoV_printError()
Errors are now handled very differently, parser errors and VM errors are now treated the same.
When cosmoV_error is called, cosmoV_throw is also called, which formats the error object and sets the panic state.
state->error now points to the latest CObjError when state->panic is true. To get a nice formatted Objection message, use
cosmoV_printError() and pass the state->error. pcall() was added to the standard base library. When called, the first argument
passed is called with the subsequent arguments given. If the call completed successfully, `true`,`nil` is returned. However
when an error occurs during the call, `false`,`<error>` is returned. Simply print the `<error>` to retrieve the error string.
2021-01-06 04:27:59 +00:00
|
|
|
cosmoV_printError(state, state->error);
|
|
|
|
} else {
|
2021-01-10 20:38:53 +00:00
|
|
|
cosmoV_pop(state); // pop the error off the stack
|
Added CObjError, cosmoV_throw(), pcall(), and cosmoV_printError()
Errors are now handled very differently, parser errors and VM errors are now treated the same.
When cosmoV_error is called, cosmoV_throw is also called, which formats the error object and sets the panic state.
state->error now points to the latest CObjError when state->panic is true. To get a nice formatted Objection message, use
cosmoV_printError() and pass the state->error. pcall() was added to the standard base library. When called, the first argument
passed is called with the subsequent arguments given. If the call completed successfully, `true`,`nil` is returned. However
when an error occurs during the call, `false`,`<error>` is returned. Simply print the `<error>` to retrieve the error string.
2021-01-06 04:27:59 +00:00
|
|
|
cosmoV_printError(state, state->error);
|
2020-10-28 05:16:30 +00:00
|
|
|
}
|
Added CObjError, cosmoV_throw(), pcall(), and cosmoV_printError()
Errors are now handled very differently, parser errors and VM errors are now treated the same.
When cosmoV_error is called, cosmoV_throw is also called, which formats the error object and sets the panic state.
state->error now points to the latest CObjError when state->panic is true. To get a nice formatted Objection message, use
cosmoV_printError() and pass the state->error. pcall() was added to the standard base library. When called, the first argument
passed is called with the subsequent arguments given. If the call completed successfully, `true`,`nil` is returned. However
when an error occurs during the call, `false`,`<error>` is returned. Simply print the `<error>` to retrieve the error string.
2021-01-06 04:27:59 +00:00
|
|
|
|
|
|
|
state->panic = false; // so our repl isn't broken
|
2020-10-28 05:16:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void repl() {
|
|
|
|
char line[1024];
|
2020-10-28 23:38:50 +00:00
|
|
|
_ACTIVE = true;
|
2020-10-28 05:16:30 +00:00
|
|
|
|
2020-10-28 23:38:50 +00:00
|
|
|
CState *state = cosmoV_newState();
|
2020-11-13 05:04:09 +00:00
|
|
|
cosmoB_loadLibrary(state);
|
|
|
|
cosmoB_loadDebug(state);
|
2020-10-28 23:38:50 +00:00
|
|
|
|
2020-12-22 21:13:11 +00:00
|
|
|
// add our custom REPL functions
|
2020-12-20 03:15:12 +00:00
|
|
|
cosmoV_pushString(state, "quit");
|
|
|
|
cosmoV_pushCFunction(state, cosmoB_quitRepl);
|
|
|
|
|
|
|
|
cosmoV_pushString(state, "input");
|
|
|
|
cosmoV_pushCFunction(state, cosmoB_input);
|
|
|
|
|
|
|
|
cosmoV_register(state, 2);
|
2020-10-28 23:38:50 +00:00
|
|
|
|
|
|
|
while (_ACTIVE) {
|
2020-10-28 05:16:30 +00:00
|
|
|
printf("> ");
|
|
|
|
|
|
|
|
if (!fgets(line, sizeof(line), stdin)) { // better than gets()
|
|
|
|
printf("\n> ");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-12-09 18:23:16 +00:00
|
|
|
interpret(state, line, "REPL");
|
2020-10-28 05:16:30 +00:00
|
|
|
}
|
2020-10-28 23:38:50 +00:00
|
|
|
|
|
|
|
cosmoV_freeState(state);
|
2020-10-28 05:16:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *readFile(const char* path) {
|
|
|
|
FILE* file = fopen(path, "rb");
|
|
|
|
if (file == NULL) {
|
|
|
|
fprintf(stderr, "Could not open file \"%s\".\n", path);
|
|
|
|
exit(74);
|
|
|
|
}
|
|
|
|
|
|
|
|
// first, we need to know how big our file is
|
|
|
|
fseek(file, 0L, SEEK_END);
|
|
|
|
size_t fileSize = ftell(file);
|
|
|
|
rewind(file);
|
|
|
|
|
|
|
|
char *buffer = (char*)malloc(fileSize + 1); // make room for the null byte
|
|
|
|
if (buffer == NULL) {
|
|
|
|
fprintf(stderr, "failed to allocate!");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t bytesRead = fread(buffer, sizeof(char), fileSize, file);
|
|
|
|
|
|
|
|
if (bytesRead < fileSize) {
|
|
|
|
printf("failed to read file \"%s\"!\n", path);
|
|
|
|
exit(74);
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer[bytesRead] = '\0'; // place our null terminator
|
|
|
|
|
|
|
|
// close the file handler and return the script buffer
|
|
|
|
fclose(file);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void runFile(const char* fileName) {
|
|
|
|
char* script = readFile(fileName);
|
2020-10-28 23:38:50 +00:00
|
|
|
CState *state = cosmoV_newState();
|
2020-11-13 05:04:09 +00:00
|
|
|
cosmoB_loadLibrary(state);
|
2020-10-28 05:16:30 +00:00
|
|
|
|
2020-12-22 21:13:11 +00:00
|
|
|
// add our input() function to the global table
|
|
|
|
cosmoV_pushString(state, "input");
|
|
|
|
cosmoV_pushCFunction(state, cosmoB_input);
|
|
|
|
|
|
|
|
cosmoV_register(state, 1);
|
|
|
|
|
2020-12-09 18:23:16 +00:00
|
|
|
interpret(state, script, fileName);
|
2020-10-28 23:38:50 +00:00
|
|
|
|
|
|
|
cosmoV_freeState(state);
|
2020-10-28 05:16:30 +00:00
|
|
|
free(script);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, const char *argv[]) {
|
|
|
|
if (argc == 1) {
|
|
|
|
repl();
|
|
|
|
} else if (argc >= 2) { // they passed a file (or more lol)
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
runFile(argv[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2021-01-02 05:06:24 +00:00
|
|
|
}
|