feat: REPL environment

This commit is contained in:
Matthieu Bessat 2022-05-17 11:37:50 +02:00
parent 9b7c2a7e99
commit 87f3a94155
8 changed files with 150 additions and 84 deletions

View file

@ -17,47 +17,50 @@ I didn't really study how others languages works beforehand, I'm just guessing h
ToDo List: ToDo List:
- [X] pow operator - [X] feat: pow operator
- [X] binary operators - [X] feat: binary operators
- [X] implement basic math functions - [X] feat: basic math functions
- [X] implement random_int(min, max) - [X] feat: random_int(min, max)
- [X] implement print_number(message) - [X] feat: print_number(message)
- [X] add unit tests - [X] base of unit tests
- [X] allow to set variables - [X] feat: set variables
- [X] read line comments - [X] feat: read line comments
- [X] add modulus operator '%' - [X] feat: modulus operator '%'
- [X] add input_number() std function - [X] feat: input_number() std function
- [X] add NULL type (dirty way to handle no returns and some errors) - [X] feat: NULL type (dirty way to handle no returns and some errors)
- [X] add type() std function and others type checking functions - [X] feat: type() std function and others type checking functions
- [X] add ceil() and floor() std functions - [X] feat: ceil() and floor() std functions
- [X] base of the CLI - [X] feat: base of the CLI
- [X] read a file - [X] feat: process from a file
- [X] if statements - [X] feat: if statements
- [X] while statements (with break and continue) - [X] feat: while statements (with break and continue)
- [ ] add multiple characters operators - [ ] feat(Evaluator): multiple characters operators
- [ ] add inclusive operators like '!=', '>=', '<=' - [ ] feat(Evaluator): inclusive operators like '!=', '>=', '<='
- [ ] add functions support - [ ] feat: functions support
- [ ] add priority operators - [ ] feat(Evaluator): priority operators
- [ ] add multiline expressions - [ ] feat: multiline expressions
- [ ] add short hand if without 'end' - [ ] feat: short hand if statement without 'end'
- [ ] add repeat statement - [ ] feat: repeat statement
- [ ] add static string support (just for ui) - [ ] feat: static string support (just for ui)
- [ ] add print_string function - [ ] feat: print_string function
- [ ] add basic number list support - [ ] feat: basic number list support
- [ ] add fully features strings support - [ ] feat: fully features strings support
- [ ] add function to access to environment variables - [ ] feat: function to access to environment variables
- [ ] add REPL environment - [X] feat: REPL environment
- [ ] feat: add history to REPL
- [ ] evaluate expression from stdin - [ ] evaluate expression from stdin
- [X] add config header file - [X] feat: config header file
- [X] ability to modify keywords and customize the lang - [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 [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 - [ ] refactor: remove inconsistency on how functions returns error codes
## Installation ## Installation

View file

@ -13,6 +13,11 @@ int main () {
struct VariableStore* store = var_store_init(); struct VariableStore* store = var_store_init();
printf("%d", var_store_hash_name(store, "print_number index")); printf("%d", var_store_hash_name(store, "print_number index"));
int i = -1;
if (i < 0) {
printf("lol jpp \n");
}
return 0; return 0;
//struct List l1; //struct List l1;

View file

@ -13,6 +13,7 @@
#if SYNTAX_PRESET == PRESET_ENGLISH #if SYNTAX_PRESET == PRESET_ENGLISH
#define SYNTAX_END "end" #define SYNTAX_END "end"
#define SYNTAX_EXIT "exit"
#define SYNTAX_SET_START "set" #define SYNTAX_SET_START "set"
#define SYNTAX_SET_STOP "to" #define SYNTAX_SET_STOP "to"
@ -29,6 +30,7 @@
#if SYNTAX_PRESET == PRESET_FRENCH #if SYNTAX_PRESET == PRESET_FRENCH
#define SYNTAX_END "fin" #define SYNTAX_END "fin"
#define SYNTAX_EXIT "sortir"
#define SYNTAX_SET_START "definir" #define SYNTAX_SET_START "definir"
#define SYNTAX_SET_STOP "comme" #define SYNTAX_SET_STOP "comme"

View file

@ -532,6 +532,7 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
} }
} }
// FIXME: refactor to better branching
if (st != 0) { if (st != 0) {
// identify token // identify token
// first try a variable then a func name // first try a variable then a func name

View file

@ -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 >= 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); 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 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 (recognize_comment_statement(str)) {
if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Comment recognized \n"); if (LINE_PROCESSING_DEBUG_LEVEL >= 2) printf("Comment recognized \n");
state->linePtr++; state->linePtr++;
@ -448,6 +426,12 @@ int process_line(struct StateContainer* state, char* str)
return 1; return 1;
} }
if (recognize_word(str, SYNTAX_EXIT)) {
// exit the whole script
state->running = 0;
return 1;
}
if (recognize_word(str, SYNTAX_CONTINUE)) { if (recognize_word(str, SYNTAX_CONTINUE)) {
int lastLoopLine; int lastLoopLine;
if (!int_stack_pop(state->loopStack, &lastLoopLine)) { if (!int_stack_pop(state->loopStack, &lastLoopLine)) {
@ -468,6 +452,7 @@ int process_line(struct StateContainer* state, char* str)
return 1; return 1;
} }
if (recognize_word(str, SYNTAX_BREAK)) { if (recognize_word(str, SYNTAX_BREAK)) {
int lastLoopLine; int lastLoopLine;
if (!int_stack_pop(state->loopStack, &lastLoopLine)) { if (!int_stack_pop(state->loopStack, &lastLoopLine)) {
@ -527,7 +512,7 @@ int process_line(struct StateContainer* state, char* str)
return 1; 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; int res;
byte resType; byte resType;
int evalStat = evaluate(state, str, &res, &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); printf("Error: could not evaluate expression \"%s\".\n", str);
return 0; return 0;
} }
state->lastEvaluationType = resType;
state->lastEvaluationResult = res;
state->linePtr++; state->linePtr++;
return 1; return 1;
} }

View file

@ -1,5 +1,8 @@
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <string.h> #include <string.h>
#include "./config.h" #include "./config.h"
#include "./types.h" #include "./types.h"
@ -12,6 +15,11 @@
#include "./var_store.h" #include "./var_store.h"
#include "./line_processing.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 HELP_FLAG 1
#define VERSION_FLAG 4 #define VERSION_FLAG 4
#define INTERACTIVE_FLAG 8 #define INTERACTIVE_FLAG 8
@ -34,8 +42,36 @@ int version_mode() {
} }
int interactive_mode() { int interactive_mode() {
printf("Interactive not implemented yet ¯\\_(ツ)_/¯ \n"); struct StateContainer* state = state_init();
return 1;
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() { int stdin_expression_mode() {
@ -43,31 +79,56 @@ int stdin_expression_mode() {
return 1; return 1;
} }
int file_mode(char* fileName) {
FILE* f = fopen(fileName, "rb");
if (!f) { char* slurp_file(char* filePath, size_t* size) {
fprintf(stderr, "Cannot load file '%s' status: %d\n", fileName, (int) f); char* buffer = NULL;
return 1;
} FILE* f = fopen(filePath, "rb");
fseek(f, 0, SEEK_END); if (f == NULL) goto error;
long length = ftell(f);
fseek(f, 0, SEEK_SET); 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); 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(); struct StateContainer* state = state_init();
process_script(state, buff); process_script(state, buff);
return 0; return EXIT_SUCCESS;
} }
int main (int argc, char** argv) { int main (int argc, char** argv) {
@ -97,7 +158,7 @@ int main (int argc, char** argv) {
// no flag match // no flag match
if (str_starts_with("--", argv[i])) { if (str_starts_with("--", argv[i])) {
fprintf(stderr, "Invalid flag '%s'\n", argv[i]); fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
return 1; return EXIT_FAILURE;
} }
nonFlagArgumentCount++; nonFlagArgumentCount++;
nonFlagArgumentPos = i; nonFlagArgumentPos = i;
@ -110,5 +171,5 @@ int main (int argc, char** argv) {
if (flags & STDIN_EXP_FLAG) return stdin_expression_mode(); if (flags & STDIN_EXP_FLAG) return stdin_expression_mode();
help_mode(cmdName); help_mode(cmdName);
return 1; return EXIT_FAILURE;
} }

View file

@ -18,5 +18,8 @@ struct StateContainer* state_init()
ptr->running = 1; ptr->running = 1;
ptr->lastEvaluationType = TYPE_NULL;
ptr->lastEvaluationResult = 0;
return ptr; return ptr;
} }

View file

@ -32,6 +32,9 @@ struct StateContainer {
// struct FunctionStore* funcStore; // struct FunctionStore* funcStore;
// struct StringStore* strStore ?? // struct StringStore* strStore ??
int lastEvaluationResult;
byte lastEvaluationType;
}; };
struct StateContainer* state_init(); struct StateContainer* state_init();