feat: REPL environment
This commit is contained in:
parent
9b7c2a7e99
commit
87f3a94155
8 changed files with 150 additions and 84 deletions
71
README.md
71
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
107
src/main.c
107
src/main.c
|
@ -1,5 +1,8 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -18,5 +18,8 @@ struct StateContainer* state_init()
|
|||
|
||||
ptr->running = 1;
|
||||
|
||||
ptr->lastEvaluationType = TYPE_NULL;
|
||||
ptr->lastEvaluationResult = 0;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ struct StateContainer {
|
|||
|
||||
// struct FunctionStore* funcStore;
|
||||
// struct StringStore* strStore ??
|
||||
|
||||
int lastEvaluationResult;
|
||||
byte lastEvaluationType;
|
||||
};
|
||||
|
||||
struct StateContainer* state_init();
|
||||
|
|
Loading…
Reference in a new issue