diff --git a/.gitignore b/.gitignore index 461a8c9..78ed071 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,9 @@ # Project exclude paths /cmake-build-debug/ .idea -/.idea/* \ No newline at end of file +/.idea/* +cmake_install.cmake +CMakeCache.txt +Connery +Makefile +/CMakeFiles/ \ No newline at end of file diff --git a/.run/Connery [test.connery].run.xml b/.run/Connery [test.connery].run.xml new file mode 100644 index 0000000..9004d32 --- /dev/null +++ b/.run/Connery [test.connery].run.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.run/Connery.run.xml b/.run/Connery.run.xml new file mode 100644 index 0000000..a093685 --- /dev/null +++ b/.run/Connery.run.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.run/local.run.run.xml b/.run/local.run.run.xml new file mode 100644 index 0000000..d9e6478 --- /dev/null +++ b/.run/local.run.run.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Buildfile b/Buildfile new file mode 100644 index 0000000..02ff9ab --- /dev/null +++ b/Buildfile @@ -0,0 +1,29 @@ +local.install: + sudo apt-get -y install build-essential + sudo apt-get -y install cmake + sudo apt-get -y install libcurl4-openssl-dev + sudo apt-get -y install libedit-dev + +local.build: + cmake src/. + make Connery + +local.clean: + make clean || true + rm cmake_install.cmake || true + rm CMakeCache.txt || true + rm -r CMakeFiles || true + rm -r stdlib || true + rm Makefile || true + +local.run: + ./Connery || cmake src/. && make Connery && ./Connery || sudo apt-get -y install build-essential; sudo apt-get -y install cmake; sudo apt-get -y install libcurl4-openssl-dev; sudo apt-get -y install libedit-dev; cmake src/. && make Connery && ./Connery || echo "There is nothing like a challenge to bring out the best in man." + +docker.build: + docker build --tag connerylang . + +docker.clean: + docker rmi connerylang --force + +docker.run: + docker run -it connerylang || docker build --tag connerylang . && docker run -it connerylang \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..bb4fa3b --- /dev/null +++ b/install.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +connery_install_path=$(eval echo ~$user); +export CONNERY_INSTALL_PATH=$connery_install_path; +export CONNERY_PATH=$connery_install_path"/Connery" + +pushd ./ + +cd "$CONNERY_INSTALL_PATH" || exit && +git clone --single-branch --branch feature/traceback_system https://github.com/willcipriano/Connery.git + + +cd "$CONNERY_PATH" || exit && +make -f Buildfile local.install ; make -f Buildfile local.build + +rm Buildfile || true ; +rm CMakeCache.txt || true ; +rm -rf CMakeFiles || true ; +rm cmake_install.cmake || true ; +rm Dockerfile || true ; +rm -rf Makefile || true ; +rm -rf src || true ; + +export PATH=$PATH:$CONNERY_PATH + + + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dea220b..77fffbf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_C_STANDARD 99) set(CURL_LIBRARY "-lcurl") find_package(CURL REQUIRED) -add_executable(Connery main.c mpc.c util.c util.h hashtable.c hashtable.h cval.h cval.c) +add_executable(Connery main.c mpc.c util.c util.h hashtable.c hashtable.h cval.h cval.c trace.c trace.h) include_directories(${CURL_INCLUDE_DIR}) target_link_libraries(Connery PRIVATE /usr/lib/x86_64-linux-gnu/libedit.so ${CURL_LIBRARIES}) diff --git a/src/cval.c b/src/cval.c index b4610dd..4f28899 100644 --- a/src/cval.c +++ b/src/cval.c @@ -1,10 +1,14 @@ #include "cval.h" +#include "util.h" +#include "trace.h" #include #include #include #include +#include -#define ENV_HASH_TABLE_SIZE 1000 +#define ENV_HASH_TABLE_SIZE 10000 +#define SYSTEM_LANG 1 #define CASSERT(args, cond, fmt, ...) \ if (!(cond)) {\ @@ -24,135 +28,115 @@ if (!(cond)) {\ func, args->count, num) -cval *cval_pop(cval *value, int i); +cval* cval_pop(cval* value, int i); +cval* cval_evaluate(cenv* env,cval* value); +cval* cval_take(cval* value, int i); -cval *cval_evaluate(cenv *env, cval *value); - -cval *cval_take(cval *value, int i); - -char *ctype_name(int t) { - switch (t) { - case CVAL_FUNCTION: - return "Function"; - case CVAL_NUMBER: - return "Number"; - case CVAL_ERROR: - return "Error"; - case CVAL_SYMBOL: - return "Symbol"; - case CVAL_S_EXPRESSION: - return "S-Expression"; - case CVAL_Q_EXPRESSION: - return "Q-Expression"; - case CVAL_STRING: - return "String"; - case CVAL_FLOAT: - return "Float"; - case CVAL_BOOLEAN: - return "Boolean"; - case CVAL_NULL: - return "Null"; - default: - return "Unknown Type"; +char* ctype_name(int t) { + switch(t) { + case CVAL_FUNCTION: return "Function"; + case CVAL_NUMBER: return "Number"; + case CVAL_ERROR: return "Error"; + case CVAL_SYMBOL: return "Symbol"; + case CVAL_S_EXPRESSION: return "S-Expression"; + case CVAL_Q_EXPRESSION: return "Q-Expression"; + case CVAL_STRING: return "String"; + case CVAL_FLOAT: return "Float"; + case CVAL_BOOLEAN: return "Boolean"; + default: return "Unknown Type"; } } -cval *cval_function(cbuiltin func) { - cval *v = malloc(sizeof(cval)); +cval* cval_function(cbuiltin func) { + cval* v = malloc(sizeof(cval)); v->type = CVAL_FUNCTION; v->builtin = func; return v; } -cval *cval_number(long x) { +cval *cval_boolean(bool b) { cval *value = malloc(sizeof(cval)); + value->type = CVAL_BOOLEAN; + value->boolean = b; + value->count = 0; + value->cell = NULL; + return value; +} + +cval* cval_number(long x) { + cval* value = malloc(sizeof(cval)); value->type = CVAL_NUMBER; value->num = x; return value; } -cval *cval_float(long double x) { - cval *value = malloc(sizeof(cval)); +cval* cval_float(long double x) { + cval* value = malloc(sizeof(cval)); value->type = CVAL_FLOAT; value->fnum = x; return value; } -cval *cval_string(char *s) { - cval *v = malloc(sizeof(cval)); +cval* cval_string (char* s) { + cval* v = malloc(sizeof(cval)); v->type = CVAL_STRING; v->str = malloc(strlen(s) + 1); strcpy(v->str, s); return v; } -cval *cval_error(char *fmt, ...) { - cval *value = malloc(sizeof(cval)); +cval* cval_error(char* fmt, ...) { + cval* value = malloc(sizeof(cval)); value->type = CVAL_ERROR; va_list va; va_start(va, fmt); value->err = malloc(512); vsnprintf(value->err, 511, fmt, va); - value->err = realloc(value->err, strlen(value->err) + 1); + value->err = realloc(value->err, strlen(value->err)+1); va_end(va); return value; } -cval *cval_symbol(char *s) { - cval *value = malloc(sizeof(cval)); +cval* cval_symbol(char* s) { + cval* value = malloc(sizeof(cval)); value->type = CVAL_SYMBOL; value->sym = malloc(strlen(s) + 1); strcpy(value->sym, s); return value; } -cval *cval_s_expression(void) { - cval *value = malloc(sizeof(cval)); +cval* cval_s_expression(void) { + cval* value = malloc(sizeof(cval)); value->type = CVAL_S_EXPRESSION; value->count = 0; value->cell = NULL; return value; } -cval *cval_q_expression(void) { - cval *value = malloc(sizeof(cval)); +cval* cval_q_expression(void) { + cval* value = malloc(sizeof(cval)); value->type = CVAL_Q_EXPRESSION; value->count = 0; value->cell = NULL; return value; } -cval *cval_boolean(bool b) { - cval *value = malloc(sizeof(cval)); - value->type = CVAL_BOOLEAN; - value->boolean = b; - value->count = 0; - value->cell = NULL; - return value; -} -cval *cval_null() { - cval *value = malloc(sizeof(cval)); - value->type = CVAL_NULL; - value->count = 0; - value->cell = NULL; - return value; -} -cenv *cenv_new(void) { - cenv *e = malloc(sizeof(cenv)); +cenv* cenv_new(void) { + cenv* e = malloc(sizeof(cenv)); e->par = NULL; e->ht = hash_table_create(ENV_HASH_TABLE_SIZE); return e; } -void cenv_delete(cenv *e) { +void cenv_delete(cenv* e) { hash_table_destroy(e->ht); free(e); } -void cval_delete(cval *value) { - switch (value->type) { +void cval_delete(cval* value) { + switch(value->type) { case CVAL_NUMBER: break; @@ -192,41 +176,41 @@ void cval_delete(cval *value) { free(value); } -cval *cval_take(cval *value, int i) { - cval *x = cval_pop(value, i); +cval* cval_take(cval* value, int i) { + cval* x = cval_pop(value, i); cval_delete(value); return x; } -cval *cval_pop(cval *value, int i) { - cval *x = value->cell[i]; - memmove(&value->cell[i], &value->cell[i + 1], - sizeof(cval *) * (value->count - i - 1)); +cval* cval_pop(cval* value, int i) { + cval* x = value->cell[i]; + memmove(&value->cell[i], &value->cell[i+1], + sizeof(cval*) * (value->count-i-1)); value->count--; - value->cell = realloc(value->cell, sizeof(cval *) * value->count); + value->cell = realloc(value->cell, sizeof(cval*) * value->count); return x; } -cval *builtin_eval(cenv *e, cval *a) { +cval* builtin_eval(cenv* e, cval* a) { CASSERT_NUM("eval", a, 1); CASSERT_TYPE("eval", a, 0, CVAL_Q_EXPRESSION); - cval *x = cval_take(a, 0); + cval* x = cval_take(a, 0); x->type = CVAL_S_EXPRESSION; return cval_evaluate(e, x); } -cenv *cenv_copy(cenv *e) { - cenv *n = malloc(sizeof(cenv)); +cenv* cenv_copy(cenv* e) { + cenv* n = malloc(sizeof(cenv)); n->par = e->par; n->ht = hash_table_copy(e->ht); return n; } -cval *cval_copy(cval *v) { - cval *x = malloc(sizeof(cval)); +cval* cval_copy(cval* v) { + cval* x = malloc(sizeof(cval)); x->type = v->type; switch (v->type) { @@ -262,7 +246,7 @@ cval *cval_copy(cval *v) { case CVAL_S_EXPRESSION: case CVAL_Q_EXPRESSION: x->count = v->count; - x->cell = malloc(sizeof(cval *) * x->count); + x->cell = malloc(sizeof(cval*) * x->count); for (int i = 0; i < x->count; i++) { x->cell[i] = cval_copy(v->cell[i]); } @@ -273,45 +257,45 @@ cval *cval_copy(cval *v) { strcpy(x->str, v->str); break; + case CVAL_BOOLEAN: x->boolean = v->boolean; break; - } return x; } -void cenv_put(cenv *e, cval *k, cval *v) { +void cenv_put(cenv* e, cval* k, cval* v) { hash_table_set(e->ht, k->sym, v); } -cval *builtin_list(cenv *e, cval *a) { +cval* builtin_list(cenv* e, cval* a) { a->type = CVAL_Q_EXPRESSION; return a; } -cval *cval_add(cval *v, cval *x) { +cval* cval_add(cval* v, cval* x) { v->count++; - v->cell = realloc(v->cell, sizeof(cval *) * v->count); - v->cell[v->count - 1] = x; + v->cell = realloc(v->cell, sizeof(cval*) * v->count); + v->cell[v->count-1] = x; return v; } -cval *cval_call(cenv *e, cval *f, cval *a) { - if (f->builtin) { return f->builtin(e, a); } +cval* cval_call(cenv* e, cval* f, cval* a) { + if (f->builtin) {return f->builtin(e, a);} int given = a->count; int total = f->formals->count; while (a->count) { - if (f->formals->count == 0) { + if(f->formals->count == 0) { cval_delete(a); return cval_error("Function pashed too many argumentsh. Got %i, Expected %s", given, total); } - cval *sym = cval_pop(f->formals, 0); + cval* sym = cval_pop(f->formals, 0); if (strcmp(sym->sym, "&") == 0) { @@ -320,14 +304,14 @@ cval *cval_call(cenv *e, cval *f, cval *a) { return cval_error("Function format invalid. shymbol '&' not followed by shingle shymbol."); } - cval *nsym = cval_pop(f->formals, 0); + cval* nsym = cval_pop(f->formals, 0); cenv_put(f->env, nsym, builtin_list(e, a)); cval_delete(sym); cval_delete(nsym); break; } - cval *val = cval_pop(a, 0); + cval* val = cval_pop(a, 0); cenv_put(f->env, sym, val); cval_delete(sym); @@ -344,8 +328,8 @@ cval *cval_call(cenv *e, cval *f, cval *a) { cval_delete(cval_pop(f->formals, 0)); - cval *sym = cval_pop(f->formals, 0); - cval *val = cval_q_expression(); + cval* sym = cval_pop(f->formals, 0); + cval* val = cval_q_expression(); cenv_put(f->env, sym, val); cval_delete(sym); @@ -355,19 +339,20 @@ cval *cval_call(cenv *e, cval *f, cval *a) { if (f->formals->count == 0) { f->env->par = e; return builtin_eval(f->env, cval_add(cval_s_expression(), cval_copy(f->body))); - } else { + } + else { return cval_copy(f); } } -cval *cval_evaluate_s_expression(cenv *env, cval *value) { +cval* cval_evaluate_s_expression(cenv* env, cval* value) { for (int i = 0; i < value->count; i++) { value->cell[i] = cval_evaluate(env, value->cell[i]); } for (int i = 0; i < value->count; i++) { - if (value->cell[i]->type == CVAL_ERROR) { return cval_take(value, i); } + if (value->cell[i]->type == CVAL_ERROR) {return cval_take(value, i);} } if (value->count == 0) { @@ -378,22 +363,20 @@ cval *cval_evaluate_s_expression(cenv *env, cval *value) { return cval_evaluate(env, cval_take(value, 0)); } - cval *f = cval_pop(value, 0); + cval* f = cval_pop(value, 0); if (f->type != CVAL_FUNCTION) { -// cval *err = cval_error("S-Expression starts with incorrect type. Got %s, Expected %s", ctype_name(f->type), -// ctype_name(CVAL_FUNCTION)); - cval_delete(f); - cval_delete(value); - return cval_null(); - } + if (f->type == CVAL_S_EXPRESSION) { + return cval_evaluate_s_expression(env, f); + } + } - cval *result = cval_call(env, f, value); + cval* result = cval_call(env, f, value); cval_delete(f); return result; } -cval *cenv_get(cenv *e, cval *k) { - cval *value = hash_table_get(e->ht, k->sym); +cval* cenv_get(cenv* e, cval* k) { + cval* value = hash_table_get(e->ht, k->sym); if (value != NULL) { return cval_copy(value); } @@ -405,9 +388,9 @@ cval *cenv_get(cenv *e, cval *k) { } } -cval *cval_evaluate(cenv *env, cval *value) { +cval* cval_evaluate(cenv* env, cval* value) { if (value->type == CVAL_SYMBOL) { - cval *x = cenv_get(env, value); + cval* x = cenv_get(env, value); cval_delete(value); return x; } @@ -418,40 +401,39 @@ cval *cval_evaluate(cenv *env, cval *value) { return value; } -void cenv_add_builtin(cenv *e, char *name, cbuiltin func) { - cval *k = cval_symbol(name); - cval *v = cval_function(func); +void cenv_add_builtin(cenv* e, char* name, cbuiltin func) { + cval* k = cval_symbol(name); + cval* v = cval_function(func); cenv_put(e, k, v); cval_delete(k); cval_delete(v); } -void cenv_def(cenv *e, cval *k, cval *v) { + +void cenv_def(cenv* e, cval* k, cval* v) { while (e->par) { e = e->par; } - cenv_put(e, k, v); + cenv_put(e, k , v); } -cval *builtin_var(cenv *e, cval *a, char *func) { +cval* builtin_var(cenv* e, cval* a, char* func) { CASSERT_TYPE("def", a, 0, CVAL_Q_EXPRESSION) - cval *syms = a->cell[0]; + cval* syms = a->cell[0]; for (int i = 0; i < syms->count; i++) { CASSERT_TYPE("def", syms, i, CVAL_SYMBOL) } - CASSERT(a, (syms->count == a->count - 1), - "Function '%s' pashed too many arguments for symbols. Got %i, Expected %i", func, syms->count, - a->count - 1); + CASSERT(a, (syms->count == a->count-1), "Function '%s' pashed too many arguments for symbols. Got %i, Expected %i", func, syms->count, a->count-1); for (int i = 0; i < syms->count; i++) { if (strcmp(func, "def") == 0) { - cenv_def(e, syms->cell[i], a->cell[i + 1]); + cenv_def(e, syms->cell[i], a->cell[i+1]); } if (strcmp(func, "=") == 0) { - cenv_put(e, syms->cell[i], a->cell[i + 1]); + cenv_put(e, syms->cell[i], a->cell[i+1]); } } @@ -459,15 +441,15 @@ cval *builtin_var(cenv *e, cval *a, char *func) { return cval_s_expression(); } -cval *builtin_put(cenv *e, cval *a) { +cval* builtin_put(cenv* e, cval* a) { return builtin_var(e, a, "="); } -cval *builtin_def(cenv *e, cval *a) { +cval* builtin_def(cenv* e, cval* a) { return builtin_var(e, a, "def"); } -cval *cval_join(cval *x, cval *y) { +cval* cval_join(cval* x, cval* y) { for (int i = 0; i < y->count; i++) { x = cval_add(x, y->cell[i]); } @@ -484,26 +466,26 @@ cval *cval_read_boolean(mpc_ast_t *t) { return cval_boolean(false); } -cval *cval_read_num(mpc_ast_t *t) { +cval* cval_read_num(mpc_ast_t* t) { errno = 0; long x = strtol(t->contents, NULL, 10); return errno != ERANGE ? cval_number(x) : cval_error("that'sh an invalid number"); } -cval *cval_read_float(mpc_ast_t *t) { +cval* cval_read_float(mpc_ast_t* t) { errno = 0; long double x = strtold(t->contents, NULL); return errno != ERANGE ? cval_float(x) : cval_error("that'sh a invalid float"); } -cval *cval_read_string(mpc_ast_t *t) { - t->contents[strlen(t->contents) - 1] = '\0'; - char *unescaped = malloc(strlen(t->contents + 1) + 1); - strcpy(unescaped, t->contents + 1); +cval* cval_read_string(mpc_ast_t* t) { + t->contents[strlen(t->contents)-1] = '\0'; + char* unescaped = malloc(strlen(t->contents+1)+1); + strcpy(unescaped, t->contents+1); unescaped = mpcf_unescape(unescaped); - cval *str = cval_string(unescaped); + cval* str = cval_string(unescaped); free(unescaped); return str; } @@ -514,18 +496,17 @@ cval *cval_read_symbol(char *symbol) { return cval_boolean(true); } else if (strcmp(symbol, "False") == 0) { return cval_boolean(false); - } else if (strcmp(symbol, "Null") == 0) { - return cval_null(); } else { return cval_symbol(symbol); } } -cval *cval_read(mpc_ast_t *t) { +cval* cval_read(mpc_ast_t* t) { if (strstr(t->tag, "boolean")) { return cval_read_boolean(t); } + if (strstr(t->tag, "number")) { return cval_read_num(t); } @@ -538,7 +519,7 @@ cval *cval_read(mpc_ast_t *t) { return cval_read_symbol(t->contents); } - cval *x = NULL; + cval* x = NULL; if (strcmp(t->tag, ">") == 0) { x = cval_s_expression(); } @@ -553,22 +534,22 @@ cval *cval_read(mpc_ast_t *t) { } for (int i = 0; i < t->children_num; i++) { - if (strcmp(t->children[i]->contents, "(") == 0) { + if (strcmp(t->children[i]->contents, "(") == 0){ continue; } if (strstr(t->children[i]->tag, "comment")) { continue; } - if (strcmp(t->children[i]->contents, ")") == 0) { + if (strcmp(t->children[i]->contents, ")") == 0){ continue; } - if (strcmp(t->children[i]->contents, "}") == 0) { + if (strcmp(t->children[i]->contents, "}") == 0){ continue; } - if (strcmp(t->children[i]->contents, "{") == 0) { + if (strcmp(t->children[i]->contents, "{") == 0){ continue; } - if (strcmp(t->children[i]->tag, "regex") == 0) { + if (strcmp(t->children[i]->tag, "regex") == 0){ continue; } x = cval_add(x, cval_read(t->children[i])); @@ -577,40 +558,43 @@ cval *cval_read(mpc_ast_t *t) { } -void cval_print_str(cval *v) { - char *escaped = malloc(strlen(v->str) + 1); +void cval_print_str(cval* v) { + char* escaped = malloc(strlen(v->str)+1); strcpy(escaped, v->str); escaped = mpcf_escape(escaped); - printf("\"%s\"", escaped); + printf("%s", v->str); free(escaped); } -void cval_print_ht_str(cval *v, char *key) { - char *escaped = malloc(strlen(v->str) + 1); +void cval_print_ht_str(cval* v, char* key) { + char* escaped = malloc(strlen(v->str)+1); strcpy(escaped, v->str); escaped = mpcf_escape(escaped); printf("%s : \"%s\"", key, escaped); free(escaped); } -void cval_expr_print(cval *value, char open, char close) { +bool cval_expr_print(cval* value, char open, char close) { + if (value->count >= 1) { putchar(open); for (int i = 0; i < value->count; i++) { cval_print(value->cell[i]); - if (i != (value->count - 1)) { + if (i != (value->count-1)) { putchar(' '); } } putchar(close); + return true;} + return false; } -void cval_expr_ht_print(cval *value, char open, char close, char *key) { +void cval_expr_ht_print(cval* value, char open, char close, char* key) { fputs(key, stdout); fputs(" : ", stdout); putchar(open); for (int i = 0; i < value->count; i++) { cval_print(value->cell[i]); - if (i != (value->count - 1)) { + if (i != (value->count-1)) { putchar(' '); } } @@ -618,8 +602,9 @@ void cval_expr_ht_print(cval *value, char open, char close, char *key) { } -void cval_print(cval *value) { +bool cval_print(cval* value) { switch (value->type) { + case CVAL_BOOLEAN: if (value->boolean) { printf("True"); @@ -628,6 +613,7 @@ void cval_print(cval *value) { } break; + case CVAL_NUMBER: printf("%li", value->num); break; @@ -649,7 +635,11 @@ void cval_print(cval *value) { break; case CVAL_ERROR: +#if SYSTEM_LANG==0 printf("shtirred: %s", value->err); +#else + printf("error: %s", value->err); +#endif break; case CVAL_SYMBOL: @@ -657,8 +647,7 @@ void cval_print(cval *value) { break; case CVAL_S_EXPRESSION: - cval_expr_print(value, '(', ')'); - break; + return cval_expr_print(value, '(', ')'); case CVAL_Q_EXPRESSION: cval_expr_print(value, '{', '}'); @@ -668,11 +657,11 @@ void cval_print(cval *value) { cval_print_str(value); break; } -} -void cval_print_line(cval *value) { - cval_print(value); - if (value->type != CVAL_NULL) { + return true; +} +void cval_print_line(cval* value) { + if (cval_print(value)) { putchar('\n'); } } diff --git a/src/cval.h b/src/cval.h index 942530d..f81f66a 100644 --- a/src/cval.h +++ b/src/cval.h @@ -1,9 +1,9 @@ #ifndef CONNERY_CVAL_H #define CONNERY_CVAL_H +#include #include "mpc.h" #include "hashtable.h" -#include typedef struct cval cval; typedef struct cenv cenv; @@ -13,7 +13,7 @@ typedef cval *(*cbuiltin)(cenv *, cval *); enum { CVAL_NUMBER, CVAL_ERROR, CVAL_SYMBOL, CVAL_FUNCTION, CVAL_S_EXPRESSION, CVAL_Q_EXPRESSION, CVAL_STRING, CVAL_FLOAT, - CVAL_BOOLEAN, CVAL_NULL + CVAL_BOOLEAN }; struct cval { @@ -25,6 +25,7 @@ struct cval { char *sym; char *str; bool boolean; + hash_table *ht; cbuiltin builtin; cenv *env; @@ -56,8 +57,6 @@ cval *cval_symbol(char *s); cval *cval_boolean(bool b); -cval *cval_null(); - cval *cval_s_expression(void); cval *cval_q_expression(void); @@ -88,9 +87,9 @@ cval *cval_read(mpc_ast_t *t); void cval_print_line(cval *value); -void cval_expr_print(cval *value, char open, char close); +bool cval_expr_print(cval *value, char open, char close); -void cval_print(cval *value); +bool cval_print(cval *value); void cval_print_ht_str(cval *v, char *key); diff --git a/src/hashtable.c b/src/hashtable.c index 8d2a1cc..269349e 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -168,8 +168,9 @@ hash_table *hash_table_copy(hash_table *target_hash_table) { return new_hash_table; } -void hash_table_print(hash_table *target_hash_table) { +int hash_table_print(hash_table *target_hash_table) { int first_row = 1; + int count = 0; for (long i = 0; i < target_hash_table->table_size; i++) { @@ -227,4 +228,7 @@ void hash_table_print(hash_table *target_hash_table) { } + printf("\ntotal items: "); + return target_hash_table -> items; + } \ No newline at end of file diff --git a/src/hashtable.h b/src/hashtable.h index 22b8ab4..72e2455 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -27,6 +27,6 @@ hash_table *hash_table_copy(hash_table *target_hash_table); void hash_table_entry_delete(hash_table *target_hash_table, const char *key); -void hash_table_print(hash_table *target_hash_table); +int hash_table_print(hash_table *target_hash_table); #endif //CONNERY_HASHTABLE_H diff --git a/src/main.c b/src/main.c index 68df50f..ab49281 100644 --- a/src/main.c +++ b/src/main.c @@ -5,6 +5,13 @@ #include "mpc.h" #include "util.h" #include "cval.h" +#include "hashtable.h" +#include "trace.h" + +#define SYSTEM_LANG 0 +#define CONNERY_VERSION "0.0.2" +#define CONNERY_VER_INT 2 +#define LOG_LEVEL 4 #ifdef _WIN32 #include @@ -24,7 +31,6 @@ void add_history(char* unused) {} #else #include -#include #endif mpc_parser_t *Number; @@ -43,16 +49,31 @@ if (!(cond)) {\ cval_delete(args); \ return err;} +#if SYSTEM_LANG==0 #define CASSERT_TYPE(func, args, index, expect) \ CASSERT(args, args->cell[index]->type == expect, \ "Function '%s' pashed incorrect type for argument %i. " \ "Got %s, Expected %s.", \ func, index, ctype_name(args->cell[index]->type), ctype_name(expect)) +#else +#define CASSERT_TYPE(func, args, index, expect) \ + CASSERT(args, args->cell[index]->type == expect, \ + "Function '%s' passed incorrect type for argument %i. " \ + "Got %s, Expected %s.", \ + func, index, ctype_name(args->cell[index]->type), ctype_name(expect)) +#endif +#if SYSTEM_LANG==0 #define CASSERT_NUM(func, args, num) \ CASSERT(args, args->count == num, \ "function '%s' pashed incorrect number of argumentsh. got %i, expected %i.", \ func, args->count, num) +#else +#define CASSERT_NUM(func, args, num) \ +CASSERT(args, args->count == num, \ + "function '%s' passed incorrect number of arguments. got %i, expected %i.", \ + func, args->count, num) +#endif cval *builtin_op(cenv *e, cval *a, char *op) { int float_support = 0; @@ -107,7 +128,11 @@ cval *builtin_op(cenv *e, cval *a, char *op) { if (y->fnum == 0) { cval_delete(x); cval_delete(y); +#if SYSTEM_LANG==0 x = cval_error("Divishion by zero"); +#else + x = cval_error("Division by zero"); +#endif break; } x->fnum /= y->fnum; @@ -115,7 +140,11 @@ cval *builtin_op(cenv *e, cval *a, char *op) { if (y->num == 0) { cval_delete(x); cval_delete(y); +#if SYSTEM_LANG==0 x = cval_error("Divishion by zero"); +#else + x = cval_error("Division by zero"); +#endif break; } x->fnum /= y->num; @@ -125,14 +154,22 @@ cval *builtin_op(cenv *e, cval *a, char *op) { if (strcmp(op, "mod") == 0) { cval_delete(x); cval_delete(y); +#if SYSTEM_LANG==0 x = cval_error("mod not shupported on floatsh!"); +#else + x = cval_error("mod not supported on floats!"); +#endif break; } if (strcmp(op, "pow") == 0) { cval_delete(x); cval_delete(y); +#if SYSTEM_LANG==0 x = cval_error("pow not shupported on floatsh!"); +#else + x = cval_error("pow not supported on floats!"); +#endif break; } @@ -167,7 +204,11 @@ cval *builtin_op(cenv *e, cval *a, char *op) { if (y->num == 0) { cval_delete(x); cval_delete(y); +#if SYSTEM_LANG==0 x = cval_error("Divishion by zero"); +#else + x = cval_error("Division by zero"); +#endif break; } x->num /= y->num; @@ -214,7 +255,11 @@ cval *builtin_head(cenv *e, cval *a) { } if (a->cell[0]->type == CVAL_Q_EXPRESSION) { +#if SYSTEM_LANG==0 CASSERT(a, a->cell[0]->count != 0, "Function 'head' pashed empty list!"); +#else + CASSERT(a, a->cell[0]->count != 0, "Function 'head' passed empty list!"); +#endif cval *v = cval_take(a, 0); @@ -226,7 +271,24 @@ cval *builtin_head(cenv *e, cval *a) { } cval_delete(a); +#if SYSTEM_LANG==0 return cval_error("Function 'head' pashed unshupported type!"); +#else + return cval_error("Function 'head' passed unsupported type!"); +#endif + +} + +cval *set_trace_data(cenv *e, trace *t) { + hash_table_set(e ->ht, "__STATEMENT_NUMBER__", cval_number(t->current->position)); + + if (t->current->position > 2) { + hash_table_set(e->ht, "__PREV_PREV_EXPRESSION__", hash_table_get(e->ht, "__PREV_EXPRESSION__")); } + + if (t->current->position > 1) { + hash_table_set(e->ht, "__PREV_EXPRESSION__", t->current->prev->data); } + + hash_table_set(e->ht, "__EXPRESSION__", t->current->data); } cval *builtin_tail(cenv *e, cval *a) { @@ -240,12 +302,19 @@ cval *builtin_tail(cenv *e, cval *a) { str++; return (cval_string(str)); } +#if SYSTEM_LANG==0 return (cval_error("Function 'tail' pashed empty shtring!")); +#else + return (cval_error("Function 'tail' passed empty string!")); +#endif } if (a->cell[0]->type == CVAL_Q_EXPRESSION) { +#if SYSTEM_LANG==0 CASSERT(a, a->cell[0]->count != 0, "Function 'tail' pashed empty list!"); - +#else + CASSERT(a, a->cell[0]->count != 0, "Function 'tail' passed empty list!"); +#endif cval *v = cval_take(a, 0); cval_delete(cval_pop(v, 0)); @@ -266,7 +335,11 @@ cval *builtin_tail(cenv *e, cval *a) { cval_delete(a); if (init_digits == 1) { +#if SYSTEM_LANG==0 return cval_error("Function 'tail' pashed shingle digit number!"); +#else + return cval_error("Function 'tail' passed single digit number!"); +#endif } factor = get_factor(init_digits); @@ -286,7 +359,11 @@ cval *builtin_tail(cenv *e, cval *a) { } cval_delete(a); +#if SYSTEM_LANG==0 return cval_error("Function 'head' pashed unshupported type!"); +#else + return cval_error("Function 'head' passed unsupported type!"); +#endif } cval *builtin_rand(cenv *e, cval *a) { @@ -306,7 +383,6 @@ cval *builtin_rand(cenv *e, cval *a) { cval *builtin_join(cenv *e, cval *a) { - if (a->cell[0]->type == CVAL_STRING) { unsigned long new_str_length = 0; @@ -529,21 +605,69 @@ cval *builtin_lambda(cenv *e, cval *a) { return cval_lambda(formals, body); } + cval *builtin_load(cenv *e, cval *a) { CASSERT_NUM("load", a, 1) CASSERT_TYPE("load", a, 0, CVAL_STRING) + trace* t = start_trace(a->cell[0]->str); + + mpc_result_t r; + if (mpc_parse_contents(a->cell[0]->str, Connery, &r)) { + cval *expr = cval_read(r.output); + mpc_ast_delete(r.output); + + + while (expr->count) { + cval *expression = cval_pop(expr, 0); + record_trace(t, expression); + set_trace_data(e, t); + + cval *x = cval_evaluate(e, expression); + + if (x->type == CVAL_ERROR) { + cval_print_line(x); + } + + cval_delete(x); + + } + + cval_delete(expr); + cval_delete(a); + + return cval_s_expression(); + } else { + char *err_msg = mpc_err_string(r.error); + mpc_err_delete(r.error); + + cval *err = cval_error("Could not load library '%s'", err_msg); + free(err_msg); + cval_delete(a); + return err; + } +} + +cval *builtin_traced_load(cenv *e, cval *a,trace* t ) { + CASSERT_NUM("traced_load", a, 1) + CASSERT_TYPE("traced_load", a, 0, CVAL_STRING) + mpc_result_t r; if (mpc_parse_contents(a->cell[0]->str, Connery, &r)) { cval *expr = cval_read(r.output); mpc_ast_delete(r.output); while (expr->count) { - cval *x = cval_evaluate(e, cval_pop(expr, 0)); + cval *expression = cval_pop(expr, 0); + record_trace(t, expression); + set_trace_data(e, t); + + cval *x = cval_evaluate(e, expression); if (x->type == CVAL_ERROR) { cval_print_line(x); } + cval_delete(x); } @@ -560,6 +684,8 @@ cval *builtin_load(cenv *e, cval *a) { cval_delete(a); return err; } + + } cval *builtin_print(cenv *e, cval *a) { @@ -574,9 +700,9 @@ cval *builtin_print(cenv *e, cval *a) { return cval_s_expression(); } -cval *builtin_error(cenv *e, cval *a) { - CASSERT_NUM("error", a, 1); - CASSERT_TYPE("error", a, 0, CVAL_STRING); +cval *builtin_fault(cenv *e, cval *a) { + CASSERT_NUM("fault", a, 1); + CASSERT_TYPE("fault", a, 0, CVAL_STRING); cval *err = cval_error(a->cell[0]->str); @@ -629,7 +755,7 @@ cval *builtin_file(cenv *e, cval *a) { if (success) { fclose(file); cval_delete(a); - return cval_boolean(true); + return cval_number(1); } } cval_delete(a); @@ -647,7 +773,7 @@ cval *builtin_file(cenv *e, cval *a) { if (success) { fclose(file); cval_delete(a); - return cval_boolean(true); + return cval_number(1); } } cval_delete(a); @@ -695,7 +821,7 @@ cval *builtin_find(cenv *e, cval *a) { return cval_number(pos - org); } else { cval_delete(a); - return cval_boolean(false); + return cval_number(0); } } @@ -759,7 +885,12 @@ cval *builtin_length(cenv *e, cval *a) { } cval_delete(a); +#if SYSTEM_LANG==0 return cval_error("Function 'length' pashed unshupported type!"); +#else + return cval_error("Function 'length' passed unsupported type!"); +#endif + } cval *builtin_type(cenv *e, cval *a) { @@ -785,14 +916,8 @@ cval *builtin_type(cenv *e, cval *a) { case CVAL_SYMBOL: return cval_number(5); - case CVAL_FLOAT: - return cval_number(6); - case CVAL_BOOLEAN: - return cval_number(7); - - case CVAL_NULL: - return cval_number(8); + return cval_number(6); default: return cval_error("Type not defined!"); @@ -822,8 +947,10 @@ cval *builtin_http(cenv *e, cval *a) { struct curl_slist *chunk = NULL; curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_response_writer); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); curl_easy_setopt(curl, CURLOPT_USERAGENT, "Connery"); + curl_easy_setopt(curl, CURLOPT_HEADER, 1L); for (int i = 0; i < request_headers->count; i++) { CASSERT_TYPE("http_request_headers", request_headers, i, CVAL_STRING); @@ -835,46 +962,8 @@ cval *builtin_http(cenv *e, cval *a) { curl_easy_setopt(curl, CURLOPT_POSTFIELDS, a->cell[3]->str); } - if (strstr(type, "DOWN")) { - CASSERT_TYPE("http", a, 3, CVAL_STRING); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_download_writer); - } else { - curl_easy_setopt(curl, CURLOPT_HEADER, 1L); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_response_writer); - } - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); - if (strstr(type, "DOWN")) { - bool success = false; - struct stat st = {0}; - char* full_path = malloc(strlen(a->cell[3]->str)); - char* path = malloc(strlen(a->cell[3]->str)); - memcpy(full_path, a->cell[3]->str, strlen(a->cell[3]->str)+1); - - char* pos = strrchr(a->cell[3]->str, '/'); - memcpy(path, a->cell[3]->str, pos-a->cell[3]->str); - - if (stat(path, &st) == -1) { - mkpath(path, 0700); - } - - FILE *pagefile; - pagefile = fopen(full_path, "wb"); - - if (pagefile) { - curl_easy_setopt(curl, CURLOPT_WRITEDATA, pagefile); - curl_easy_perform(curl); - fclose(pagefile); - success = true;} - - cval_delete(a); - curl_easy_cleanup(curl); - free(full_path); - free(path); - - return cval_boolean(success); - } res = curl_easy_perform(curl); if (res == CURLE_OK) { @@ -891,7 +980,6 @@ cval *builtin_http(cenv *e, cval *a) { multi_tok_t x = multiTok_init(); char *header = multi_tok(headers, &x, "\r\n"); - while (header != NULL) { cval_add(headers_list, cval_string(header)); header = multi_tok(NULL, &x, "\r\n"); @@ -900,13 +988,15 @@ cval *builtin_http(cenv *e, cval *a) { cval_add(response_list, headers_list); cval_add(response_list, cval_string(strstr(s.body, "\r\n\r\n") + 4)); } else { - cval_delete(a); cval_delete(response_list); +#if SYSTEM_LANG==0 response_list = cval_error("unable to accesh url!"); +#else + response_list = cval_error("unable to access url!"); +#endif } free(s.body); curl_easy_cleanup(curl); - cval_delete(a); } return response_list; } @@ -917,57 +1007,52 @@ cval *builtin_input(cenv *e, cval *a) { return cval_string(input); } -cval *builtin_exit(cenv *e, cval *a) { - CASSERT_TYPE("exit", a, 0, CVAL_NUMBER); +cval *builtin_convert_string(cenv *e, cval *a) { + if (a->cell[0]->type == CVAL_NUMBER) { + int length = snprintf( NULL, 0, "%ld", a->cell[0]->num ); + char* str = malloc( length + 1 ); + snprintf( str, length + 1, "%ld", a->cell[0]->num ); - int exit_code = a->cell[0]->num; - cval_delete(a); + return cval_string(str); + } - mpc_cleanup(9, Number, Float, Symbol, String, Comment, Sexpr, Qexpr, Expr, Connery); - cenv_delete(e); - exit(exit_code); } -cval *builtin_mkdir(cenv *e, cval *a) { - CASSERT_NUM("mkdir", a, 1); - CASSERT_TYPE("mkdir", a, 0, CVAL_STRING); - char *path = a->cell[0]->str; - struct stat st = {0}; - int result; +cval *builtin_sys(cenv *e, cval *a) { + CASSERT_TYPE("stats", a, 0, CVAL_STRING); + CASSERT_NUM("stats", a, 1); - if (stat(path, &st) == -1) { - result = mkpath(path, 0700); - } else { - result = -1; + char *cmd = a->cell[0]->str; + + if (strcmp(cmd, "VERSION") == 0) { + return cval_string(CONNERY_VERSION); } - cval_delete(a); + if (strcmp(cmd, "VERSION_INT") == 0) { + return cval_number(CONNERY_VER_INT); + } - if (result == 1) { - return cval_boolean(true); - } else { - return cval_boolean(false); + if (strcmp(cmd, "PRINT_ENV") == 0) {; + return cval_number(hash_table_print(e->ht)); } -} -cval *builtin_chkdir(cenv *e, cval *a) { - CASSERT_NUM("chkdir", a, 1); - CASSERT_TYPE("chkdir", a, 0, CVAL_STRING); - struct stat st = {0}; + if (strcmp(cmd, "HARD_EXIT") == 0) { + exit(1); + } - char *path = a->cell[0]->str; - cval* result; + if (strcmp(cmd, "SOFT_EXIT") == 0) { + exit(0); + } - if (stat(path, &st) == -1) { - result = cval_boolean(false); - } else { - result = cval_boolean(true); + if (strcmp(cmd, "SYSTEM_LANGUAGE_INT") == 0) { + return cval_number(SYSTEM_LANG); } - cval_delete(a); - return result; + return cval_error("invalid input to stats"); } + + void cenv_add_builtins(cenv *e) { cenv_add_builtin(e, "\\", builtin_lambda); cenv_add_builtin(e, "def", builtin_def); @@ -978,12 +1063,12 @@ void cenv_add_builtins(cenv *e) { cenv_add_builtin(e, "tail", builtin_tail); cenv_add_builtin(e, "eval", builtin_eval); cenv_add_builtin(e, "join", builtin_join); - cenv_add_builtin(e, "def", builtin_def); cenv_add_builtin(e, "length", builtin_length); cenv_add_builtin(e, "input", builtin_input); cenv_add_builtin(e, "replace", builtin_replace); cenv_add_builtin(e, "find", builtin_find); cenv_add_builtin(e, "split", builtin_split); + cenv_add_builtin(e, "sys", builtin_sys); cenv_add_builtin(e, "+", builtin_add); cenv_add_builtin(e, "-", builtin_sub); @@ -1002,15 +1087,14 @@ void cenv_add_builtins(cenv *e) { cenv_add_builtin(e, "<=", builtin_less_than_or_equal); cenv_add_builtin(e, "load", builtin_load); - cenv_add_builtin(e, "error", builtin_error); cenv_add_builtin(e, "print", builtin_print); cenv_add_builtin(e, "type", builtin_type); cenv_add_builtin(e, "http", builtin_http); + cenv_add_builtin(e, "file", builtin_file); - cenv_add_builtin(e, "exit", builtin_exit); + cenv_add_builtin(e, "convert_string", builtin_convert_string); - cenv_add_builtin(e, "mkdir", builtin_mkdir); - cenv_add_builtin(e, "chkdir", builtin_chkdir); + cenv_add_builtin(e, "__FAULT__", builtin_fault); } void load_standard_lib(cenv *e) { @@ -1033,23 +1117,23 @@ int main(int argc, char **argv) { Connery = mpc_new("connery"); mpca_lang(MPCA_LANG_DEFAULT, - " \ - float : /-?[0-9]*\\.[0-9]+/ ; \ - number : /-?[0-9]+/ ; \ - symbol : /[a-zA-Z0-9_+\\-*\\/\\\\=<>!&]+/ \ - |'+' | '-' | '*' | '/' ; \ - sexpr : '(' * ')' ; \ - qexpr : '{' * '}' ; \ - string : /\"(\\\\.|[^\"])*\"/; \ - comment : /;[^\\r\\n]*/ ; \ - expr : | | \ - | | | | ; \ - connery : /^/ * /$/ ; \ + " \ + float : /-?[0-9]*\\.[0-9]+/ ; \ + number : /-?[0-9]+/ ; \ + symbol : /[a-zA-Z0-9_+\\-*\\/\\\\=<>!&]+/ \ + |'+' | '-' | '*' | '/' ; \ + sexpr : '(' * ')' ; \ + qexpr : '{' * '}' ; \ + string : /\"(\\\\.|[^\"])*\"/; \ + comment : /;[^\\r\\n]*/ ; \ + expr : | | \ + | | | | ;\ + connery : /^/ * /$/ ; \ ", - Float, Number, Symbol, Sexpr, Qexpr, Expr, String, - Comment, Connery); + Float, Number, Symbol, Sexpr, Qexpr, Expr, String, Comment, Connery); cenv *e = cenv_new(); + cenv_add_builtins(e); load_standard_lib(e); @@ -1059,14 +1143,25 @@ int main(int argc, char **argv) { "/ /___/ /_/ / / / / / / / __/ / / /_/ / \n" "\\____/\\____/_/ /_/_/ /_/\\___/_/ \\__, / \n" " /____/ "); - puts("+----- Version 0.0.1 ------+\n"); +#if SYSTEM_LANG==1 + puts("_____________ English Mode _____________"); +#endif + + puts(" Version "CONNERY_VERSION); puts(" ConneryLang.org \n"); + hash_table_set(e ->ht, "__LOG_LEVEL__", cval_number(LOG_LEVEL)); + if (argc == 1) { + hash_table_set(e ->ht, "__SOURCE__", cval_string("INTERACTIVE")); + trace* trace = start_trace("interactive"); while (1) { char *input = readline("connery> "); add_history(input); + record_trace(trace, cval_string(input)); + set_trace_data(e, trace); + mpc_result_t result; if (mpc_parse("", input, Connery, &result)) { cval *output = cval_evaluate(e, cval_read(result.output)); @@ -1083,9 +1178,12 @@ int main(int argc, char **argv) { } if (argc >= 2) { + hash_table_set(e ->ht, "__SOURCE__", cval_string("FILE")); + trace* trace = start_trace("FILE"); for (int i = 1; i < argc; i++) { cval *args = cval_add(cval_s_expression(), cval_string(argv[i])); - cval *x = builtin_load(e, args); + hash_table_set(e ->ht, "__SOURCE_FILE__", cval_string(argv[i])); + cval *x = builtin_traced_load(e, args, trace); if (x->type == CVAL_ERROR) { cval_print_line(x); @@ -1094,7 +1192,7 @@ int main(int argc, char **argv) { } } - mpc_cleanup(9, Number, Float, Symbol, String, Comment, Sexpr, Qexpr, Expr, Connery); + mpc_cleanup(8, Number, Float, Symbol, String, Comment, Sexpr, Qexpr, Expr, Connery); cenv_delete(e); return 0; } \ No newline at end of file diff --git a/src/mpc.c b/src/mpc.c index fc6bea7..2eab5a1 100644 --- a/src/mpc.c +++ b/src/mpc.c @@ -2482,11 +2482,10 @@ mpc_val_t *mpcf_strtrim(mpc_val_t *x) { static const char mpc_escape_input_c[] = { '\a', '\b', '\f', '\n', '\r', - '\t', '\v', '\\', '\'', '\"', '\0'}; + '\t', '\v', '\0'}; static const char *mpc_escape_output_c[] = { - "\\a", "\\b", "\\f", "\\n", "\\r", "\\t", - "\\v", "\\\\", "\\'", "\\\"", "\\0", NULL}; + "\\a", "\\b", "\\f", "\\n", "\\r", "\\t", NULL}; static const char mpc_escape_input_raw_re[] = { '/' }; static const char *mpc_escape_output_raw_re[] = { "\\/", NULL }; diff --git a/src/stdlib/Q.connery b/src/stdlib/Q.connery deleted file mode 100644 index 0f1d4a4..0000000 --- a/src/stdlib/Q.connery +++ /dev/null @@ -1,26 +0,0 @@ -(def {__Q_package_location__} "Q") -(def {__Q_location__} "http://q.connerylang.org") -(def {__Q_package_list_url_slug__} "/packages/packages_list.csv") -(def {__Q_packages__} Null) - -(mkdir __Q_package_location__) - -(fun {__Q_package_scan__ packages package_name} { - if (>= (length packages) 1) - {if (== (first (first (head packages))) package_name) - {first (head packages)} - {__Q_package_scan__ (tail packages) package_name}} - {Null} -}) - -(fun {Q package_name} { - (if (is_null __Q_packages__) - {def {__Q_packages__} (tail (csv (third (http_get (join __Q_location__ __Q_package_list_url_slug__)))))} - {}) - - (= {__package_result__} (__Q_package_scan__ __Q_packages__ package_name)) - - (if (is_null __package_result__) - {error (join "Package " package_name " not found!")} - {print "False"}) -}) \ No newline at end of file diff --git a/src/stdlib/constants.connery b/src/stdlib/constants.connery index d6eb4aa..a601f3d 100644 --- a/src/stdlib/constants.connery +++ b/src/stdlib/constants.connery @@ -4,5 +4,6 @@ (def {Otherwise} True) (def {std_lib_main_location} "stdlib/main.connery") + ; Easter Egg (def {best_kid} "Alice Imogen Cipriano") \ No newline at end of file diff --git a/src/stdlib/csv.connery b/src/stdlib/csv.connery deleted file mode 100644 index d0876e7..0000000 --- a/src/stdlib/csv.connery +++ /dev/null @@ -1,9 +0,0 @@ -(fun {__parse_csv_loop__ csv_lines output}{ - if (== 0 (length csv_lines)) - {output} - {__parse_csv_loop__ (tail csv_lines) (join output (list (delimit "," (eval (head csv_lines)))))} -}) - -(fun {csv csv_string} { - __parse_csv_loop__ (delimit "\n" csv_string) None -}) \ No newline at end of file diff --git a/src/stdlib/errors.connery b/src/stdlib/errors.connery new file mode 100644 index 0000000..a1747ea --- /dev/null +++ b/src/stdlib/errors.connery @@ -0,0 +1,63 @@ +(fun {__STANDARD_ERROR_HANDLER__ msg critical} { + +(if (!= connery_system_lang "Connery Classic") + {(if (!= __STATEMENT_NUMBER__ -1) + {(if (== __SOURCE__ "FILE") + {log_error (join (join (join "during statement: " (convert_string __STATEMENT_NUMBER__)) (join " while attempting to load file: " __SOURCE_FILE__)) (join " with cause: " msg))} + {log_error (join (join "during statement: " (convert_string __STATEMENT_NUMBER__)) (join " with cause: " msg))})} + {(if (== __SOURCE__ "FILE") + {log_error (join (join "during file: " __SOURCE_FILE__) (join " with cause: " msg))} + {log_error (join "with cause: " msg)})})} + + {(if (!= __STATEMENT_NUMBER__ -1) + {(if (== __SOURCE__ "FILE") + {log_error (join (join (join "during shtatement: " (convert_string __STATEMENT_NUMBER__)) (join " while attempting to load file: " __SOURCE_FILE__)) (join " with caushe: " msg))} + {log_error (join (join "during shtatement: " (convert_string __STATEMENT_NUMBER__)) (join " with caushe: " msg))})} + {(if (== __SOURCE__ "FILE") + {log_error (join (join "during file: " __SOURCE_FILE__) (join " with caushe: " msg))} + {log_error (join "with caushe: " msg)})})}) + + (if (>= log_level 4) + { + (print "TRACE: ") + + (if (>= __STATEMENT_NUMBER__ 3) { + (print __PREV_PREV_EXPRESSION__) + }{}) + + (if (>= __STATEMENT_NUMBER__ 2) { + (print __PREV_EXPRESSION__) + }{}) + + (if (>= __STATEMENT_NUMBER__ 1) { + (print __EXPRESSION__) + }{}) } + {}) + +(if (== critical 1) {(log_fatal "critical error") (sys "HARD_EXIT")} {}) +}) + +(fun {__NOOP_ERROR_HANDLER__ msg critical} { }) + +(def {standard_error_handler} __STANDARD_ERROR_HANDLER__) + +(fun {__ERROR__ msg critical} { +(standard_error_handler msg critical) +}) + +(fun {mistakes mistake_bool} { +if (mistake_bool) + {def {standard_error_handler} __STANDARD_ERROR_HANDLER__} + {def {standard_error_handler} __NOOP_ERROR_HANDLER__}}) + +(fun {panic msg} { +if (is_str msg) + {__ERROR__ msg 1} + {__ERROR__ (string_convert msg) 1} +}) + +(fun {error msg} { +if (is_str msg) + {__ERROR__ msg 0} + {__ERROR__ (string_convert msg) 0} +}) \ No newline at end of file diff --git a/src/stdlib/functional.connery b/src/stdlib/functional.connery index e0ed151..bc04457 100644 --- a/src/stdlib/functional.connery +++ b/src/stdlib/functional.connery @@ -12,4 +12,12 @@ {if (first (first cs)) {second (first cs)} {unpack case (tail cs)}} -}) \ No newline at end of file +}) + +; Currying +(fun {unpack f l} { + eval (join (list f) l) +}) +(fun {pack f & xs} {f xs}) +(def {curry} unpack) +(def {uncurry} pack) \ No newline at end of file diff --git a/src/stdlib/logs.connery b/src/stdlib/logs.connery new file mode 100644 index 0000000..9bc8c93 --- /dev/null +++ b/src/stdlib/logs.connery @@ -0,0 +1,58 @@ +(fun {__log_level_num__ i} + {case + {(== i 1) "ERROR"} + {(== i 2) "WARN"} + {(== i 3) "INFO"} + {(== i 4) "DEBUG"} + {(== i 5) "TRACE"} + {Otherwise "FATAL"}}) + +(fun {__log_level_connery_num__ i} + {case + {(== i 1) "Mishtake"} + {(== i 2) "Shtired"} + {(== i 3) "For Your Eyesh Only"} + {(== i 4) "Shocking"} + {(== i 5) "Without A Trashe"} + {Otherwise "Lishenshe To Kill"}}) + +(fun {__LEVELED_STANDARD_OUTPUT_LOG_HANDLER__ level msg} { +if (>= log_level level) + { + (if (!= connery_system_lang "Connery Classic") + {(print (join (join (__log_level_num__ level) ": ") msg))} + {(print (join (join (__log_level_connery_num__ level) ": ") msg))}) + } + {} +}) + +(fun {__NOOP_LOG_HANDLER__ level msg} {}) + +(def {__DEFAULT_LOGGER__} __LEVELED_STANDARD_OUTPUT_LOG_HANDLER__) +(def {interpreter_log_handler} __DEFAULT_LOGGER__) +(def {__LOGGER_INIT_COMPLETE__} False) + +(fun {__LOG__ level msg} { +if (__LOGGER_INIT_COMPLETE__) { +interpreter_log_handler level msg +} { +(def {log_level} __LOG_LEVEL__) +(interpreter_log_handler level msg) +(def {__LOGGER_INIT_COMPLETE__} True) +}}) + +(fun {go_loud loud_bool} { +(if (loud_bool) + {def {interpreter_log_handler} __DEFAULT_LOGGER__} + {def {interpreter_log_handler} __NOOP_LOG_HANDLER__}) +(if (loud_bool) + {if (< log_level 4) {(if (> __LOG_LEVEL__ 4) {(def {log_level} __LOG_LEVEL__)} {def {log_level} 4})} {}} + {if (> log_level 3) {(if (< __LOG_LEVEL__ 3) {(def {log_level} __LOG_LEVEL__)} {def {log_level} 3})} {}} +)}) + +(fun {log_fatal msg} {__LOG__ 0 msg}) +(fun {log_error msg} {__LOG__ 1 msg}) +(fun {log_warn msg} {__LOG__ 2 msg}) +(fun {log_info msg} {__LOG__ 3 msg}) +(fun {log_debug msg} {__LOG__ 4 msg}) +(fun {log_trace msg} {__LOG__ 5 msg}) \ No newline at end of file diff --git a/src/stdlib/main.connery b/src/stdlib/main.connery index b5737fd..fc55ad3 100644 --- a/src/stdlib/main.connery +++ b/src/stdlib/main.connery @@ -5,7 +5,18 @@ (load "stdlib/logic.connery") (load "stdlib/lists.connery") (load "stdlib/strings.connery") +(load "stdlib/logs.connery") +(load "stdlib/errors.connery") (load "stdlib/io.connery") (load "stdlib/http.connery") -(load "stdlib/csv.connery") -(load "stdlib/Q.connery") \ No newline at end of file + + +(load "stdlib/versions.connery") +(def {CONNERY_VERSION_INT} (sys "VERSION_INT")) +(def {CONNERY_VERSION} (sys "VERSION")) +(def {connery_version} (connery_version_num CONNERY_VERSION_INT)) +(def {CONNERY_SYSTEM_LANG_INT} (sys "SYSTEM_LANGUAGE_INT")) +(def {connery_system_lang} (system_lang_version_num CONNERY_SYSTEM_LANG_INT)) + + + diff --git a/src/stdlib/versions.connery b/src/stdlib/versions.connery new file mode 100644 index 0000000..2ac051f --- /dev/null +++ b/src/stdlib/versions.connery @@ -0,0 +1,15 @@ +(fun {connery_version_num i} { + case + {(== i 0) "Connery - Unspecified Version"} + {(== i 1) "Connery - 0.0.1 - The Legend Begins"} + {(== i 2) "Connery - 0.0.2"} + {(== i 9999) "Connery - Future Version"} + {Otherwise (error "Connery version is undefined.")} +}) + +(fun {system_lang_version_num i} { + case + {(== i 0) "Connery Classic"} + {(== i 1) "English"} + {Otherwise (error "Connery lang version is undefined.")} +}) \ No newline at end of file diff --git a/src/trace.c b/src/trace.c new file mode 100644 index 0000000..2c20ca6 --- /dev/null +++ b/src/trace.c @@ -0,0 +1,51 @@ +#include "cval.h" +#include "trace.h" + +trace* start_trace(char* s) { + + trace *tr = malloc(sizeof(trace) * 1); + trace_entry *te = malloc(sizeof(trace_entry) * 1); + + te->position=0; + te->data=cval_string("initialization of trace"); + + tr->current=te; + tr->first=te; + tr->source=cval_string(s); + + return tr; +} + +void record_trace(trace* t, cval* data) { + trace_entry *te = malloc(sizeof(trace_entry) * 1); + + te->position=t->current->position + 1; + te->prev=t->current; + te->data=cval_copy(data); + + t->current->next=te; + t->current=te; +} + +void record_str_trace(trace* t, char* data) { + record_trace(t, cval_string(data)); +} + +cval* fetch_traceback_data(trace* t, int x) { + trace_entry* cur_te = t->current; + cval* traceback = cval_q_expression(); + int y = 0; + + if (x > t->current->position) { + x = t->current->position; + } + + while (y <= x) { + cval_add(traceback, cur_te->data); + cur_te = t->current->prev; + y += 1; + } + + return traceback; +} + diff --git a/src/trace.h b/src/trace.h new file mode 100644 index 0000000..48af14b --- /dev/null +++ b/src/trace.h @@ -0,0 +1,26 @@ +#ifndef CONNERY_TRACE_H +#define CONNERY_TRACE_H +#include "cval.h" + +typedef struct cval cval; + +typedef struct trace_entry { + int position; + cval* data; + struct trace_entry* next; + struct trace_entry* prev; +} trace_entry; + +typedef struct trace { + cval* source; + struct trace_entry* first; + struct trace_entry* current; +} trace; + +trace* start_trace(char* s); +void record_trace(trace* t, cval* data); +void record_str_trace(trace* t, char* data); +cval* fetch_traceback_data(trace* t, int x); + +#endif //CONNERY_TRACE_H + diff --git a/src/util.c b/src/util.c index 66d6960..bb098d0 100644 --- a/src/util.c +++ b/src/util.c @@ -1,14 +1,11 @@ #include #include #include -#include -#include -#include #include "util.h" void init_http_response(struct http_response *s) { s->len = 0; - s->body = malloc(s->len + 1); + s->body = malloc(s->len+1); if (s->body == NULL) { fprintf(stderr, "malloc() failed\n"); exit(EXIT_FAILURE); @@ -16,24 +13,19 @@ void init_http_response(struct http_response *s) { s->body[0] = '\0'; } -size_t http_response_writer(void *ptr, size_t size, size_t nmemb, struct http_response *s) { - size_t new_len = s->len + size * nmemb; - s->body = realloc(s->body, new_len + 1); +size_t http_response_writer(void *ptr, size_t size, size_t nmemb, struct http_response *s) +{ + size_t new_len = s->len + size*nmemb; + s->body = realloc(s->body, new_len+1); if (s->body == NULL) { fprintf(stderr, "realloc() failed\n"); exit(EXIT_FAILURE); } - memcpy(s->body + s->len, ptr, size * nmemb); + memcpy(s->body+s->len, ptr, size*nmemb); s->body[new_len] = '\0'; s->len = new_len; - return size * nmemb; -} - -size_t http_download_writer(void *ptr, size_t size, size_t nmemb, void *stream) -{ - size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); - return written; + return size*nmemb; } typedef char *multi_tok_t; @@ -74,15 +66,17 @@ char *concatenateThree(const char *a, const char *b, const char *c) { return res; } -long long_power(long x, long exponent) { +long long_power(long x,long exponent) +{ int i; int number = 1; for (i = 0; i < exponent; ++i) number *= x; - return (number); + return(number); } -int count_digits(long n) { +int count_digits(long n) +{ if (n == 0) return 0; return 1 + count_digits(n / 10); @@ -132,31 +126,4 @@ long get_factor(int init_digits) { } } -int mkpath(const char *path, mode_t mode) { - char tmp[PATH_MAX]; - char *p = NULL; - size_t len; - - snprintf(tmp, sizeof(tmp), "%s", path); - len = strlen(tmp); - if (tmp[len - 1] == '/') - tmp[len - 1] = 0; - for (p = tmp + 1; *p; p++) - if (*p == '/') { - *p = 0; -#if defined(_WIN32) - if (_mkdir(tmp) < 0 && errno != EEXIST) -#else - if (mkdir(tmp, mode) < 0 && errno != EEXIST) -#endif - return -1; - *p = '/'; - } -#if defined(_WIN32) - if (_mkdir(tmp) < 0 && errno != EEXIST) -#else - if (mkdir(tmp, mode) < 0 && errno != EEXIST) -#endif - return -1; - return 1; -} \ No newline at end of file + diff --git a/src/util.h b/src/util.h index 4dbee17..6b1e7a6 100644 --- a/src/util.h +++ b/src/util.h @@ -1,7 +1,3 @@ -// -// Created by dev on 8/15/20. -// - #ifndef CONNERY_UTIL_H #define CONNERY_UTIL_H @@ -24,6 +20,7 @@ char *concatenateThree(const char *a, const char *b, const char *c); long long_power(long x,long exponent); int count_digits(long n); long get_factor(int init_digits); +char *replace_str(char *str, char *orig, char *rep); //mkpath int mkpath(const char *path, mode_t mode);