diff --git a/README.md b/README.md index f05c83c..641e266 100644 --- a/README.md +++ b/README.md @@ -17,47 +17,50 @@ I didn't really study how others languages works beforehand, I'm just guessing h ToDo List: -- [X] pow operator -- [X] binary operators -- [X] implement basic math functions -- [X] implement random_int(min, max) -- [X] implement print_number(message) -- [X] add unit tests -- [X] allow to set variables -- [X] read line comments -- [X] add modulus operator '%' -- [X] add input_number() std function -- [X] add NULL type (dirty way to handle no returns and some errors) -- [X] add type() std function and others type checking functions -- [X] add ceil() and floor() std functions -- [X] base of the CLI -- [X] read a file -- [X] if statements -- [X] while statements (with break and continue) +- [X] feat: pow operator +- [X] feat: binary operators +- [X] feat: basic math functions +- [X] feat: random_int(min, max) +- [X] feat: print_number(message) +- [X] base of unit tests +- [X] feat: set variables +- [X] feat: read line comments +- [X] feat: modulus operator '%' +- [X] feat: input_number() std function +- [X] feat: NULL type (dirty way to handle no returns and some errors) +- [X] feat: type() std function and others type checking functions +- [X] feat: ceil() and floor() std functions +- [X] feat: base of the CLI +- [X] feat: process from a file +- [X] feat: if statements +- [X] feat: while statements (with break and continue) -- [ ] add multiple characters operators -- [ ] add inclusive operators like '!=', '>=', '<=' -- [ ] add functions support -- [ ] add priority operators -- [ ] add multiline expressions -- [ ] add short hand if without 'end' -- [ ] add repeat statement -- [ ] add static string support (just for ui) -- [ ] add print_string function -- [ ] add basic number list support -- [ ] add fully features strings support -- [ ] add function to access to environment variables +- [ ] feat(Evaluator): multiple characters operators +- [ ] feat(Evaluator): inclusive operators like '!=', '>=', '<=' +- [ ] feat: functions support +- [ ] feat(Evaluator): priority operators +- [ ] feat: multiline expressions +- [ ] feat: short hand if statement without 'end' +- [ ] feat: repeat statement +- [ ] feat: static string support (just for ui) +- [ ] feat: print_string function +- [ ] feat: basic number list support +- [ ] feat: fully features strings support +- [ ] feat: function to access to environment variables -- [ ] add REPL environment +- [X] feat: REPL environment +- [ ] feat: add history to REPL - [ ] evaluate expression from stdin -- [X] add config header file +- [X] feat: config header file - [X] ability to modify keywords and customize the lang -- [ ] add more config options +- [ ] more config options - [ ] add [classic problem solving](https://rosettacode.org) with code examples -- [ ] add Web Assembly support and publish a demo website +- [ ] feat: web Assembly support and publish a demo website -- [ ] refactor: use malloc for list +- [ ] refactor: add 'Literal' struct with type and data +- [ ] refactor(Evaluator): if branching around token identification +- [ ] refactor(List): use malloc - [ ] refactor: remove inconsistency on how functions returns error codes ## Installation diff --git a/sandbox.c b/sandbox.c index d6f20d5..bf60179 100644 --- a/sandbox.c +++ b/sandbox.c @@ -12,6 +12,11 @@ int main () { struct VariableStore* store = var_store_init(); printf("%d", var_store_hash_name(store, "print_number index")); + + int i = -1; + if (i < 0) { + printf("lol jpp \n"); + } return 0; //struct List l1; diff --git a/src/config.h b/src/config.h index 691bb59..01e1ec0 100644 --- a/src/config.h +++ b/src/config.h @@ -13,6 +13,7 @@ #if SYNTAX_PRESET == PRESET_ENGLISH #define SYNTAX_END "end" + #define SYNTAX_EXIT "exit" #define SYNTAX_SET_START "set" #define SYNTAX_SET_STOP "to" @@ -29,6 +30,7 @@ #if SYNTAX_PRESET == PRESET_FRENCH #define SYNTAX_END "fin" + #define SYNTAX_EXIT "sortir" #define SYNTAX_SET_START "definir" #define SYNTAX_SET_STOP "comme" diff --git a/src/evaluator.c b/src/evaluator.c index 97b8736..a787813 100644 --- a/src/evaluator.c +++ b/src/evaluator.c @@ -532,6 +532,7 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig } } + // FIXME: refactor to better branching if (st != 0) { // identify token // first try a variable then a func name diff --git a/src/line_processing.c b/src/line_processing.c index eb01a87..b32fe3c 100644 --- a/src/line_processing.c +++ b/src/line_processing.c @@ -309,34 +309,12 @@ int process_line(struct StateContainer* state, char* str) { if (LINE_PROCESSING_DEBUG_LEVEL >= 1) printf("\n ======= PROCESSING LINE '%s' =======\n", str); if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("skipping: %d, blockStackLen: %d \n", state->skipping, state->blockStack->length); - // process + + state->lastEvaluationType = TYPE_NULL; + state->lastEvaluationResult = 0; + int len = strlen(str); - // int startPos = 0; - // int stopPos = len-1; - // // modifiy the start and stop pos to trim spaces - // int startTrimOffset = 0; - // int stopTrimOffset = 0; - // for (int z = 0; z < len; z++) { - // if (inputStr[startPos+z] != ' ') { - // break; - // } - // startTrimOffset++; - // } - // for (int z = 1; z < len; z++) { - // if (inputStr[stopPos-z] != ' ') { - // break; - // } - // stopTrimOffset++; - // } - // startPos += startTrimOffset; - // stopPos -= stopTrimOffset; - // check for comment - // if (str[startPos] == '#') { - // return; - // } - - //int stat = 0; if (recognize_comment_statement(str)) { if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Comment recognized \n"); state->linePtr++; @@ -448,6 +426,12 @@ int process_line(struct StateContainer* state, char* str) return 1; } + if (recognize_word(str, SYNTAX_EXIT)) { + // exit the whole script + state->running = 0; + return 1; + } + if (recognize_word(str, SYNTAX_CONTINUE)) { int lastLoopLine; if (!int_stack_pop(state->loopStack, &lastLoopLine)) { @@ -468,6 +452,7 @@ int process_line(struct StateContainer* state, char* str) return 1; } + if (recognize_word(str, SYNTAX_BREAK)) { int lastLoopLine; if (!int_stack_pop(state->loopStack, &lastLoopLine)) { @@ -527,7 +512,7 @@ int process_line(struct StateContainer* state, char* str) return 1; } - // we evaluate but we dont care about the result + // we evaluate the expression and we register it in the state in case of a REPL that want to get the result of the expression int res; byte resType; int evalStat = evaluate(state, str, &res, &resType); @@ -535,6 +520,9 @@ int process_line(struct StateContainer* state, char* str) printf("Error: could not evaluate expression \"%s\".\n", str); return 0; } + + state->lastEvaluationType = resType; + state->lastEvaluationResult = res; state->linePtr++; return 1; } diff --git a/src/main.c b/src/main.c index 7768e92..d54a538 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,8 @@ +#include #include #include +#include +#include #include #include "./config.h" #include "./types.h" @@ -12,6 +15,11 @@ #include "./var_store.h" #include "./line_processing.h" +/** +This is the binding of the interpreter to a CLI +The interpreter should be uncoupled from the rest of the code +*/ + #define HELP_FLAG 1 #define VERSION_FLAG 4 #define INTERACTIVE_FLAG 8 @@ -34,8 +42,36 @@ int version_mode() { } int interactive_mode() { - printf("Interactive not implemented yet ¯\\_(ツ)_/¯ \n"); - return 1; + struct StateContainer* state = state_init(); + + while (state->running) { + printf("? "); + + char* line; + size_t len = 0; + size_t lineSize = 0; + + lineSize = getline(&line, &len, stdin); + if (lineSize == (size_t) -1) { + // we received some kind of interrupt? + printf("\n"); + return EXIT_SUCCESS; + } + + char toEvaluate[lineSize+1]; + // remove the new line at the end + str_extract((char*) toEvaluate, line, 0, lineSize-1); + + int stat = process_line(state, toEvaluate); + if (!stat) { + printf("Processing that line failed.\n"); + } + if (state->lastEvaluationType != TYPE_NULL) { + printf("%s\n", get_repr(state->lastEvaluationType, &state->lastEvaluationResult)); + } + } + + return EXIT_SUCCESS; } int stdin_expression_mode() { @@ -43,31 +79,56 @@ int stdin_expression_mode() { return 1; } -int file_mode(char* fileName) { - FILE* f = fopen(fileName, "rb"); - if (!f) { - fprintf(stderr, "Cannot load file '%s' status: %d\n", fileName, (int) f); - return 1; - } - fseek(f, 0, SEEK_END); - long length = ftell(f); - fseek(f, 0, SEEK_SET); +char* slurp_file(char* filePath, size_t* size) { + char* buffer = NULL; + + FILE* f = fopen(filePath, "rb"); + if (f == NULL) goto error; + + if (fseek(f, 0, SEEK_END) < 0) goto error; + + long m = ftell(f); + if (m < 0) goto error; + + buffer = malloc(sizeof(char) * m); + if (buffer == NULL) goto error; + + if (fseek(f, 0, SEEK_SET) < 0) goto error; + + size_t n = fread(buffer, 1, m, f); + assert(n == (size_t) m); + + if (ferror(f)) goto error; + + if (size) *size = n; - char* buff = (char*) malloc(length); - if (!buff) { - fprintf(stderr, "Could not allocate buffer to process file content\n"); - return 1; - } - if (buff) { - fread(buff, 1, length, f); - } fclose(f); - + + return buffer; + +error: + if (f) fclose(f); + + if (buffer) free(buffer); + + return NULL; +} + +int file_mode(char* fileName) { + // printf("Open file mode...\n"); + size_t size; + char* buff = slurp_file(fileName, &size); + + if (!buff) { + fprintf(stderr, "Error: Cannot load file '%s' errno: %d '%s'.\n", fileName, errno, strerror(errno)); + return EXIT_FAILURE; + } + struct StateContainer* state = state_init(); process_script(state, buff); - return 0; + return EXIT_SUCCESS; } int main (int argc, char** argv) { @@ -97,7 +158,7 @@ int main (int argc, char** argv) { // no flag match if (str_starts_with("--", argv[i])) { fprintf(stderr, "Invalid flag '%s'\n", argv[i]); - return 1; + return EXIT_FAILURE; } nonFlagArgumentCount++; nonFlagArgumentPos = i; @@ -110,5 +171,5 @@ int main (int argc, char** argv) { if (flags & STDIN_EXP_FLAG) return stdin_expression_mode(); help_mode(cmdName); - return 1; + return EXIT_FAILURE; } diff --git a/src/state.c b/src/state.c index e36e16f..c2f422f 100644 --- a/src/state.c +++ b/src/state.c @@ -18,5 +18,8 @@ struct StateContainer* state_init() ptr->running = 1; + ptr->lastEvaluationType = TYPE_NULL; + ptr->lastEvaluationResult = 0; + return ptr; } diff --git a/src/state.h b/src/state.h index 377b08a..f7169c9 100644 --- a/src/state.h +++ b/src/state.h @@ -32,6 +32,9 @@ struct StateContainer { // struct FunctionStore* funcStore; // struct StringStore* strStore ?? + + int lastEvaluationResult; + byte lastEvaluationType; }; struct StateContainer* state_init();