From 1024cb710eef497b00c739c8209078419f94b1c7 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Tue, 12 Oct 2021 21:38:31 -0400 Subject: [PATCH 01/43] Small improvements, began work on fast json parser, need dictionary type to proceed. --- src/CMakeLists.txt | 2 +- src/cval.c | 23 ++ src/cval.h | 2 +- src/jsmn.h | 471 ++++++++++++++++++++++++++++++++++++++ src/json.c | 126 ++++++++++ src/json.h | 7 + src/main.c | 44 +++- src/stdlib/errors.connery | 2 - src/stdlib/http.connery | 12 +- src/stdlib/main.connery | 5 +- src/trace.c | 27 +-- src/util.c | 13 -- src/util.h | 1 - 13 files changed, 671 insertions(+), 64 deletions(-) create mode 100644 src/jsmn.h create mode 100644 src/json.c create mode 100644 src/json.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07bb98d..a8e7afa 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 trace.c trace.h strings.c strings.h) +add_executable(Connery main.c mpc.c util.c util.h hashtable.c hashtable.h cval.h cval.c trace.c trace.h strings.c strings.h jsmn.h json.c json.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 73b0b59..b908baf 100644 --- a/src/cval.c +++ b/src/cval.c @@ -1,6 +1,7 @@ #include "cval.h" #include "util.h" #include "trace.h" +#include "hashtable.h" #include #include #include @@ -8,6 +9,7 @@ #include #define ENV_HASH_TABLE_SIZE 10000 +#define DICTIONARY_HASH_TABLE_SIZE 1000 #define SYSTEM_LANG 1 #define CASSERT(args, cond, fmt, ...) \ @@ -43,6 +45,7 @@ char* ctype_name(int t) { case CVAL_STRING: return "String"; case CVAL_FLOAT: return "Float"; case CVAL_BOOLEAN: return "Boolean"; + case CVAL_DICTIONARY: return "Dictionary"; default: return "Unknown Type"; } } @@ -121,6 +124,15 @@ cval* cval_q_expression(void) { return value; } +cval* cval_dictionary(void) { + cval* value = malloc(sizeof(cval)); + value->type = CVAL_DICTIONARY; + value->count = 0; + value->ht = hash_table_create(DICTIONARY_HASH_TABLE_SIZE); + value->cell = NULL; + return value; +} + cenv* cenv_new(void) { @@ -172,6 +184,10 @@ void cval_delete(cval* value) { free(value->str); break; + case CVAL_DICTIONARY: + hash_table_destroy(value->ht); + break; + } free(value); } @@ -261,6 +277,10 @@ cval* cval_copy(cval* v) { case CVAL_BOOLEAN: x->boolean = v->boolean; break; + + case CVAL_DICTIONARY: + v->ht = hash_table_copy(x->ht); + break; } return x; @@ -661,6 +681,9 @@ bool cval_print(cval* value) { case CVAL_STRING: cval_print_str(value); break; + + case CVAL_DICTIONARY: + hash_table_print(value->ht); } return true; diff --git a/src/cval.h b/src/cval.h index ec8fd69..7f38435 100644 --- a/src/cval.h +++ b/src/cval.h @@ -13,7 +13,7 @@ typedef cval *(*cbuiltin)(cenv *, cval *); enum { CVAL_NUMBER, CVAL_FAULT, CVAL_SYMBOL, CVAL_FUNCTION, CVAL_S_EXPRESSION, CVAL_Q_EXPRESSION, CVAL_STRING, CVAL_FLOAT, - CVAL_BOOLEAN + CVAL_BOOLEAN, CVAL_DICTIONARY }; struct cval { diff --git a/src/jsmn.h b/src/jsmn.h new file mode 100644 index 0000000..41219b7 --- /dev/null +++ b/src/jsmn.h @@ -0,0 +1,471 @@ +/* + * MIT License + * + * Copyright (c) 2010 Serge Zaitsev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef JSMN_H +#define JSMN_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef JSMN_STATIC +#define JSMN_API static +#else +#define JSMN_API extern +#endif + +/** + * JSON type identifier. Basic types are: + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null + */ +typedef enum { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1 << 0, + JSMN_ARRAY = 1 << 1, + JSMN_STRING = 1 << 2, + JSMN_PRIMITIVE = 1 << 3 +} jsmntype_t; + +enum jsmnerr { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +}; + +/** + * JSON token description. + * type type (object, array, string etc.) + * start start position in JSON data string + * end end position in JSON data string + */ +typedef struct jsmntok { + jsmntype_t type; + int start; + int end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif +} jsmntok_t; + +/** + * JSON parser. Contains an array of token blocks available. Also stores + * the string being parsed now and current position in that string. + */ +typedef struct jsmn_parser { + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g. parent object or array */ +} jsmn_parser; + +/** + * Create JSON parser over an array of tokens + */ +JSMN_API void jsmn_init(jsmn_parser *parser); + +/** + * Run JSON parser. It parses a JSON data string into and array of tokens, each + * describing + * a single JSON object. + */ +JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, + jsmntok_t *tokens, const unsigned int num_tokens); + +#ifndef JSMN_HEADER +/** + * Allocates a fresh unused token from the token pool. + */ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** + * Fills token type and boundaries. + */ +static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, + const int start, const int end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, + const size_t len, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *token; + int start; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t': + case '\r': + case '\n': + case ' ': + case ',': + case ']': + case '}': + goto found; + default: + /* to quiet a warning from gcc*/ + break; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Fills next token with JSON string. + */ +static int jsmn_parse_string(jsmn_parser *parser, const char *js, + const size_t len, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *token; + + int start = parser->pos; + + parser->pos++; + + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': + case '/': + case '\\': + case 'b': + case 'f': + case 'r': + case 'n': + case 't': + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; + i++) { + /* If it isn't a hex character we have an error */ + if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** + * Parse JSON string and fill tokens. + */ +JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, + jsmntok_t *tokens, const unsigned int num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': + case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + return JSMN_ERROR_NOMEM; + } + if (parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; +#ifdef JSMN_STRICT + /* In strict mode an object or array can't become a key */ + if (t->type == JSMN_OBJECT) { + return JSMN_ERROR_INVAL; + } +#endif + t->size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': + case ']': + if (tokens == NULL) { + break; + } + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + if (token->type != type || parser->toksuper == -1) { + return JSMN_ERROR_INVAL; + } + break; + } + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) { + return JSMN_ERROR_INVAL; + } + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) { + return r; + } + count++; + if (parser->toksuper != -1 && tokens != NULL) { + tokens[parser->toksuper].size++; + } + break; + case '\t': + case '\r': + case '\n': + case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 't': + case 'f': + case 'n': + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + const jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) { + return r; + } + count++; + if (parser->toksuper != -1 && tokens != NULL) { + tokens[parser->toksuper].size++; + } + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + } + + return count; +} + +/** + * Creates a new parser based over a given buffer with an array of tokens + * available. + */ +JSMN_API void jsmn_init(jsmn_parser *parser) { + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} + +#endif /* JSMN_HEADER */ + +#ifdef __cplusplus +} +#endif + +#endif /* JSMN_H */ diff --git a/src/json.c b/src/json.c new file mode 100644 index 0000000..073c632 --- /dev/null +++ b/src/json.c @@ -0,0 +1,126 @@ +#include "jsmn.h" +#include +#include +#include +#include +#include + +//ToDo: Json Parser +// Requires dictionary type + +static inline void *realloc_it(void *ptrmem, size_t size) { + void *p = realloc(ptrmem, size); + if (!p) { + free(ptrmem); + fprintf(stderr, "realloc(): errno=%d\n", errno); + } + return p; +} + +static int dump(const char *js, jsmntok_t *t, size_t count, int indent) { + int i, j, k; + jsmntok_t *key; + if (count == 0) { + return 0; + } + if (t->type == JSMN_PRIMITIVE) { + printf("%.*s", t->end - t->start, js + t->start); + return 1; + } else if (t->type == JSMN_STRING) { + printf("'%.*s'", t->end - t->start, js + t->start); + return 1; + } else if (t->type == JSMN_OBJECT) { + printf("\n"); + j = 0; + for (i = 0; i < t->size; i++) { + for (k = 0; k < indent; k++) { + printf(" "); + } + key = t + 1 + j; + j += dump(js, key, count - j, indent + 1); + if (key->size > 0) { + printf(": "); + j += dump(js, t + 1 + j, count - j, indent + 1); + } + printf("\n"); + } + return j + 1; + } else if (t->type == JSMN_ARRAY) { + j = 0; + printf("\n"); + for (i = 0; i < t->size; i++) { + for (k = 0; k < indent - 1; k++) { + printf(" "); + } + printf(" - "); + j += dump(js, t + 1 + j, count - j, indent + 1); + printf("\n"); + } + return j + 1; + } + return 0; +} + +int run() { + int r; + int eof_expected = 0; + char *js = NULL; + size_t jslen = 0; + char buf[BUFSIZ]; + + jsmn_parser p; + jsmntok_t *tok; + size_t tokcount = 2; + + /* Prepare parser */ + jsmn_init(&p); + + /* Allocate some tokens as a start */ + tok = malloc(sizeof(*tok) * tokcount); + if (tok == NULL) { + fprintf(stderr, "malloc(): errno=%d\n", errno); + return 3; + } + + for (;;) { + /* Read another chunk */ + r = fread(buf, 1, sizeof(buf), stdin); + if (r < 0) { + fprintf(stderr, "fread(): %d, errno=%d\n", r, errno); + return 1; + } + if (r == 0) { + if (eof_expected != 0) { + return 0; + } else { + fprintf(stderr, "fread(): unexpected EOF\n"); + return 2; + } + } + + js = realloc_it(js, jslen + r + 1); + if (js == NULL) { + return 3; + } + strncpy(js + jslen, buf, r); + jslen = jslen + r; + + again: + r = jsmn_parse(&p, js, jslen, tok, tokcount); + if (r < 0) { + if (r == JSMN_ERROR_NOMEM) { + tokcount = tokcount * 2; + tok = realloc_it(tok, sizeof(*tok) * tokcount); + if (tok == NULL) { + return 3; + } + goto again; + } + } else { + dump(js, tok, p.toknext, 0); + eof_expected = 1; + } + } + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/src/json.h b/src/json.h new file mode 100644 index 0000000..0fefcda --- /dev/null +++ b/src/json.h @@ -0,0 +1,7 @@ +#ifndef CONNERY_JSON_H +#define CONNERY_JSON_H + + + + +#endif //CONNERY_JSON_H diff --git a/src/main.c b/src/main.c index f6fbb30..3aaea19 100644 --- a/src/main.c +++ b/src/main.c @@ -6,13 +6,21 @@ #include "util.h" #include "cval.h" #include "hashtable.h" -#include "trace.h" + #include "strings.h" #define SYSTEM_LANG 0 #define CONNERY_VERSION "0.0.2" #define CONNERY_VER_INT 2 #define LOG_LEVEL 4 +#define TRACE_ENABLED 1 + +#if TRACE_ENABLED == 1 +#include "trace.h" +#else +typedef struct trace {} trace; +#endif + #ifdef _WIN32 #include @@ -38,6 +46,7 @@ mpc_parser_t *Number; mpc_parser_t *Float; mpc_parser_t *Symbol; mpc_parser_t *String; +mpc_parser_t *Dictionary; mpc_parser_t *Comment; mpc_parser_t *Sexpr; mpc_parser_t *Qexpr; @@ -280,6 +289,7 @@ cval *builtin_head(cenv *e, cval *a) { } +#if TRACE_ENABLED == 1 cval *set_trace_data(cenv *e, trace *t) { hash_table_set(e->ht, "__STATEMENT_NUMBER__", cval_number(t->current->position)); @@ -293,6 +303,7 @@ cval *set_trace_data(cenv *e, trace *t) { hash_table_set(e->ht, "__EXPRESSION__", t->current->data); } +#endif cval *builtin_tail(cenv *e, cval *a) { CASSERT_NUM("tail", a, 1) @@ -689,7 +700,9 @@ cval *builtin_load(cenv *e, cval *a) { CASSERT_NUM("load", a, 1) CASSERT_TYPE("load", a, 0, CVAL_STRING) +#if TRACE_ENABLED == 1 trace *t = start_trace(a->cell[0]->str); +#endif mpc_result_t r; if (mpc_parse_contents(a->cell[0]->str, Connery, &r)) { @@ -699,8 +712,10 @@ cval *builtin_load(cenv *e, cval *a) { while (expr->count) { cval *expression = cval_pop(expr, 0); +#if TRACE_ENABLED == 1 record_trace(t, expression); set_trace_data(e, t); +#endif cval *x = cval_evaluate(e, expression); @@ -745,8 +760,10 @@ cval *builtin_traced_load(cenv *e, cval *a, trace *t) { while (expr->count) { cval *expression = cval_pop(expr, 0); +#if TRACE_ENABLED == 1 record_trace(t, expression); set_trace_data(e, t); +#endif cval *x = cval_evaluate(e, expression); @@ -1127,10 +1144,11 @@ int main(int argc, char **argv) { Expr = mpc_new("expr"); Comment = mpc_new("comment"); String = mpc_new("string"); + Dictionary = mpc_new("dictionary"); Connery = mpc_new("connery"); mpca_lang(MPCA_LANG_DEFAULT, - " \ + " \ float : /-?[0-9]*\\.[0-9]+/ ; \ number : /-?[0-9]+/ ; \ symbol : /[a-zA-Z0-9_+\\-*\\/\\\\=<>!&]+/ \ @@ -1139,8 +1157,10 @@ int main(int argc, char **argv) { qexpr : '{' * '}' ; \ string : /\"(\\\\.|[^\"])*\"/; \ comment : /;[^\\r\\n]*/ ; \ - expr : | | \ - | | | | ;\ + dictionary: '<' ':' '>' ; \ + expr : | | \ + | | | | \ + | ; \ connery : /^/ * /$/ ; \ ", Float, Number, Symbol, Sexpr, Qexpr, Expr, String, Comment, Connery); @@ -1159,7 +1179,6 @@ int main(int argc, char **argv) { #if SYSTEM_LANG == 1 puts("_____________ English Mode _____________"); #endif - puts(" Version "CONNERY_VERSION); puts(" ConneryLang.org \n"); @@ -1167,21 +1186,22 @@ int main(int argc, char **argv) { if (argc == 1) { hash_table_set(e->ht, "__SOURCE__", cval_string("INTERACTIVE")); +#if TRACE_ENABLED == 1 trace *trace = start_trace("interactive"); +#endif while (1) { char *input = readline("connery> "); add_history(input); +#if TRACE_ENABLED == 1 record_trace(trace, cval_string(input)); set_trace_data(e, trace); - +#endif mpc_result_t result; if (mpc_parse("", input, Connery, &result)) { cval *output = cval_evaluate(e, cval_read(result.output)); cval_print_line(output); - - cval_delete(output); mpc_ast_delete(result.output); @@ -1195,13 +1215,17 @@ int main(int argc, char **argv) { if (argc >= 2) { hash_table_set(e->ht, "__SOURCE__", cval_string("FILE")); +#if TRACE_ENABLED == 1 trace *trace = start_trace("FILE"); +#endif for (int i = 1; i < argc; i++) { cval *args = cval_add(cval_s_expression(), cval_string(argv[i])); hash_table_set(e->ht, "__SOURCE_FILE__", cval_string(argv[i])); +#if TRACE_ENABLED == 1 cval *x = builtin_traced_load(e, args, trace); - - +#else + cval *x = builtin_load(e, args); +#endif if (x->type == CVAL_FAULT) { cval_print_line(x); } diff --git a/src/stdlib/errors.connery b/src/stdlib/errors.connery index 1cf2dce..63003fb 100644 --- a/src/stdlib/errors.connery +++ b/src/stdlib/errors.connery @@ -34,8 +34,6 @@ }{}) } {}) - (return (def {__last_fault__} (__FAULT__ msg))) - (if (== critical 1) {(log_fatal "critical error") (sys "HARD_EXIT")} {}) }) diff --git a/src/stdlib/http.connery b/src/stdlib/http.connery index 0bfca54..0dbdecc 100644 --- a/src/stdlib/http.connery +++ b/src/stdlib/http.connery @@ -1,6 +1,6 @@ -(def {GET} "GET") -(def {POST} "POST") -(def {DOWN} "DOWN") +(def {__HTTP_GET__} "GET") +(def {__HTTP_POST__} "POST") +(def {__HTTP_DOWN__} "DOWN") (fun {http_status_code_text response} { case @@ -22,13 +22,13 @@ }) (fun {http_get url} { - http GET url None + http __HTTP_GET__ url None }) (fun {http_post url post_body} { - http POST url None post_body + http __HTTP_POST__ url None post_body }) (fun {http_download url location} { - http DOWN url None location + http __HTTP_DOWN__ url None location }) \ No newline at end of file diff --git a/src/stdlib/main.connery b/src/stdlib/main.connery index ec1e43b..9585262 100644 --- a/src/stdlib/main.connery +++ b/src/stdlib/main.connery @@ -15,7 +15,4 @@ (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)) - - - +(def {connery_system_lang} (system_lang_version_num CONNERY_SYSTEM_LANG_INT)) \ No newline at end of file diff --git a/src/trace.c b/src/trace.c index 2c20ca6..154125f 100644 --- a/src/trace.c +++ b/src/trace.c @@ -2,17 +2,15 @@ #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"); + te->data=cval_string("-- initialization of trace --"); tr->current=te; tr->first=te; tr->source=cval_string(s); - return tr; } @@ -26,26 +24,3 @@ void record_trace(trace* t, cval* 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/util.c b/src/util.c index bb098d0..621dbf7 100644 --- a/src/util.c +++ b/src/util.c @@ -53,19 +53,6 @@ char *multi_tok(char *input, multi_tok_t *string, char *delimiter) { multi_tok_t multiTok_init() { return NULL; } -char *concatenateThree(const char *a, const char *b, const char *c) { - size_t alen = strlen(a); - size_t blen = strlen(b); - size_t clen = strlen(c); - char *res = malloc(alen + blen + clen + 1); - if (res) { - memcpy(res, a, alen); - memcpy(res + alen, b, blen); - memcpy(res + alen + blen, c, clen + 1); - } - return res; -} - long long_power(long x,long exponent) { int i; diff --git a/src/util.h b/src/util.h index 6b1e7a6..6ac9f0c 100644 --- a/src/util.h +++ b/src/util.h @@ -8,7 +8,6 @@ struct http_response { }; void init_http_response(struct http_response *s); size_t http_response_writer(void *ptr, size_t size, size_t nmemb, struct http_response *s); -size_t http_download_writer(void *ptr, size_t size, size_t nmemb, void *stream); //multitok typedef char *multi_tok_t; From cef43a07bb497b387d5f61f2f11f458fd4f67136 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Tue, 12 Oct 2021 23:00:45 -0400 Subject: [PATCH 02/43] Create dictionary grammar --- src/cval.c | 4 ++++ src/main.c | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/cval.c b/src/cval.c index b908baf..eb23a57 100644 --- a/src/cval.c +++ b/src/cval.c @@ -557,6 +557,10 @@ cval* cval_read(mpc_ast_t* t) { if (strstr(t->tag, "string")) { return cval_read_string(t); } + if (strstr(t->tag, "dictionary")) { + return cval_string("test"); + } + for (int i = 0; i < t->children_num; i++) { if (strcmp(t->children[i]->contents, "(") == 0){ diff --git a/src/main.c b/src/main.c index 3aaea19..39ae998 100644 --- a/src/main.c +++ b/src/main.c @@ -46,6 +46,7 @@ mpc_parser_t *Number; mpc_parser_t *Float; mpc_parser_t *Symbol; mpc_parser_t *String; +mpc_parser_t *DictionaryPair; mpc_parser_t *Dictionary; mpc_parser_t *Comment; mpc_parser_t *Sexpr; @@ -1144,6 +1145,7 @@ int main(int argc, char **argv) { Expr = mpc_new("expr"); Comment = mpc_new("comment"); String = mpc_new("string"); + DictionaryPair = mpc_new("dictionary_pair"); Dictionary = mpc_new("dictionary"); Connery = mpc_new("connery"); @@ -1155,15 +1157,17 @@ int main(int argc, char **argv) { |'+' | '-' | '*' | '/' ; \ sexpr : '(' * ')' ; \ qexpr : '{' * '}' ; \ + dictionary_pair : /[a-zA-Z0-9]*/ '&' /[,]?/ \ + | /[a-zA-Z0-9]*/ / & / /[,]?/ ; \ + dictionary : '#' * '#' ; \ string : /\"(\\\\.|[^\"])*\"/; \ comment : /;[^\\r\\n]*/ ; \ - dictionary: '<' ':' '>' ; \ expr : | | \ | | | | \ | ; \ connery : /^/ * /$/ ; \ ", - Float, Number, Symbol, Sexpr, Qexpr, Expr, String, Comment, Connery); + Float, Number, Symbol, Sexpr, Qexpr, DictionaryPair, Dictionary, Expr, String, Comment, Connery); cenv *e = cenv_new(); From 2194eec1cd661da1f6b3dad0f14a5c8cc02cfcb9 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 13 Oct 2021 20:21:22 -0400 Subject: [PATCH 03/43] Create dictionary grammar --- src/cval.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cval.c b/src/cval.c index eb23a57..cc68d9f 100644 --- a/src/cval.c +++ b/src/cval.c @@ -420,7 +420,6 @@ cval* cval_evaluate(cenv* env, cval* value) { if (value->type == CVAL_S_EXPRESSION) { return cval_evaluate_s_expression(env, value); - } return value; } @@ -491,6 +490,12 @@ cval *cval_read_boolean(mpc_ast_t *t) { return cval_boolean(false); } +cval *cval_read_dictionary(mpc_ast_t *t) { +// t->children[1]->children[0]->contents +// t->children[1]->children[1]->contents + return cval_string(t->children[2]->children[2]->contents); +} + cval* cval_read_num(mpc_ast_t* t) { errno = 0; long x = strtol(t->contents, NULL, 10); @@ -558,7 +563,7 @@ cval* cval_read(mpc_ast_t* t) { return cval_read_string(t); } if (strstr(t->tag, "dictionary")) { - return cval_string("test"); + return cval_read_dictionary(t); } From 4aefef7600e3e60eb105c72926af84c9d40b7788 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Thu, 14 Oct 2021 18:44:00 -0400 Subject: [PATCH 04/43] Basic dictionary init working #dictionary&"active"# --- src/cval.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/cval.c b/src/cval.c index cc68d9f..386eaca 100644 --- a/src/cval.c +++ b/src/cval.c @@ -9,7 +9,6 @@ #include #define ENV_HASH_TABLE_SIZE 10000 -#define DICTIONARY_HASH_TABLE_SIZE 1000 #define SYSTEM_LANG 1 #define CASSERT(args, cond, fmt, ...) \ @@ -124,11 +123,11 @@ cval* cval_q_expression(void) { return value; } -cval* cval_dictionary(void) { +cval* cval_dictionary(hash_table* ht) { cval* value = malloc(sizeof(cval)); value->type = CVAL_DICTIONARY; value->count = 0; - value->ht = hash_table_create(DICTIONARY_HASH_TABLE_SIZE); + value->ht = ht; value->cell = NULL; return value; } @@ -490,12 +489,6 @@ cval *cval_read_boolean(mpc_ast_t *t) { return cval_boolean(false); } -cval *cval_read_dictionary(mpc_ast_t *t) { -// t->children[1]->children[0]->contents -// t->children[1]->children[1]->contents - return cval_string(t->children[2]->children[2]->contents); -} - cval* cval_read_num(mpc_ast_t* t) { errno = 0; long x = strtol(t->contents, NULL, 10); @@ -531,6 +524,19 @@ cval *cval_read_symbol(char *symbol) { } } +cval *cval_read_dictionary(mpc_ast_t *t) { + int items = t->children_num - 2; + int iter = 1; + + hash_table* ht = hash_table_create(items * 10); + while (iter <= items) { + hash_table_set(ht, t->children[iter]->children[0]->contents, cval_read(t->children[iter]->children[2])); + iter += 1; + } + + return cval_dictionary(ht); +} + cval* cval_read(mpc_ast_t* t) { if (strstr(t->tag, "boolean")) { From 546bb0505f2c58bc41d5eb9ddfa4bd6c81a82c2e Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Thu, 14 Oct 2021 19:20:44 -0400 Subject: [PATCH 05/43] Float copy bug fix --- src/cval.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cval.c b/src/cval.c index 386eaca..0b1705a 100644 --- a/src/cval.c +++ b/src/cval.c @@ -247,6 +247,7 @@ cval* cval_copy(cval* v) { case CVAL_FLOAT: x->fnum = v->fnum; + break; case CVAL_FAULT: x->err = malloc(strlen(v->err) + 1); From 9937e793a122306e7dc78e364cf5e516c86ec024 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Thu, 14 Oct 2021 19:21:58 -0400 Subject: [PATCH 06/43] Make branch all about dictionary support --- src/CMakeLists.txt | 2 +- src/jsmn.h | 471 --------------------------------------------- src/json.c | 126 ------------ src/json.h | 7 - 4 files changed, 1 insertion(+), 605 deletions(-) delete mode 100644 src/jsmn.h delete mode 100644 src/json.c delete mode 100644 src/json.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a8e7afa..07bb98d 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 trace.c trace.h strings.c strings.h jsmn.h json.c json.h) +add_executable(Connery main.c mpc.c util.c util.h hashtable.c hashtable.h cval.h cval.c trace.c trace.h strings.c strings.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/jsmn.h b/src/jsmn.h deleted file mode 100644 index 41219b7..0000000 --- a/src/jsmn.h +++ /dev/null @@ -1,471 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2010 Serge Zaitsev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef JSMN_H -#define JSMN_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef JSMN_STATIC -#define JSMN_API static -#else -#define JSMN_API extern -#endif - -/** - * JSON type identifier. Basic types are: - * o Object - * o Array - * o String - * o Other primitive: number, boolean (true/false) or null - */ -typedef enum { - JSMN_UNDEFINED = 0, - JSMN_OBJECT = 1 << 0, - JSMN_ARRAY = 1 << 1, - JSMN_STRING = 1 << 2, - JSMN_PRIMITIVE = 1 << 3 -} jsmntype_t; - -enum jsmnerr { - /* Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /* Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /* The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3 -}; - -/** - * JSON token description. - * type type (object, array, string etc.) - * start start position in JSON data string - * end end position in JSON data string - */ -typedef struct jsmntok { - jsmntype_t type; - int start; - int end; - int size; -#ifdef JSMN_PARENT_LINKS - int parent; -#endif -} jsmntok_t; - -/** - * JSON parser. Contains an array of token blocks available. Also stores - * the string being parsed now and current position in that string. - */ -typedef struct jsmn_parser { - unsigned int pos; /* offset in the JSON string */ - unsigned int toknext; /* next token to allocate */ - int toksuper; /* superior token node, e.g. parent object or array */ -} jsmn_parser; - -/** - * Create JSON parser over an array of tokens - */ -JSMN_API void jsmn_init(jsmn_parser *parser); - -/** - * Run JSON parser. It parses a JSON data string into and array of tokens, each - * describing - * a single JSON object. - */ -JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, - jsmntok_t *tokens, const unsigned int num_tokens); - -#ifndef JSMN_HEADER -/** - * Allocates a fresh unused token from the token pool. - */ -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *tok; - if (parser->toknext >= num_tokens) { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; -#ifdef JSMN_PARENT_LINKS - tok->parent = -1; -#endif - return tok; -} - -/** - * Fills token type and boundaries. - */ -static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, - const int start, const int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; -} - -/** - * Fills next available token with JSON primitive. - */ -static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, - const size_t len, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *token; - int start; - - start = parser->pos; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - switch (js[parser->pos]) { -#ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': -#endif - case '\t': - case '\r': - case '\n': - case ' ': - case ',': - case ']': - case '}': - goto found; - default: - /* to quiet a warning from gcc*/ - break; - } - if (js[parser->pos] < 32 || js[parser->pos] >= 127) { - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } -#ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; -#endif - -found: - if (tokens == NULL) { - parser->pos--; - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - parser->pos--; - return 0; -} - -/** - * Fills next token with JSON string. - */ -static int jsmn_parse_string(jsmn_parser *parser, const char *js, - const size_t len, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *token; - - int start = parser->pos; - - parser->pos++; - - /* Skip starting quote */ - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c = js[parser->pos]; - - /* Quote: end of string */ - if (c == '\"') { - if (tokens == NULL) { - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - return 0; - } - - /* Backslash: Quoted symbol expected */ - if (c == '\\' && parser->pos + 1 < len) { - int i; - parser->pos++; - switch (js[parser->pos]) { - /* Allowed escaped symbols */ - case '\"': - case '/': - case '\\': - case 'b': - case 'f': - case 'r': - case 'n': - case 't': - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; - i++) { - /* If it isn't a hex character we have an error */ - if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; - } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } - } - parser->pos = start; - return JSMN_ERROR_PART; -} - -/** - * Parse JSON string and fill tokens. - */ -JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, - jsmntok_t *tokens, const unsigned int num_tokens) { - int r; - int i; - jsmntok_t *token; - int count = parser->toknext; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c; - jsmntype_t type; - - c = js[parser->pos]; - switch (c) { - case '{': - case '[': - count++; - if (tokens == NULL) { - break; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - return JSMN_ERROR_NOMEM; - } - if (parser->toksuper != -1) { - jsmntok_t *t = &tokens[parser->toksuper]; -#ifdef JSMN_STRICT - /* In strict mode an object or array can't become a key */ - if (t->type == JSMN_OBJECT) { - return JSMN_ERROR_INVAL; - } -#endif - t->size++; -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - break; - case '}': - case ']': - if (tokens == NULL) { - break; - } - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); -#ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) { - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) { - if (token->type != type || parser->toksuper == -1) { - return JSMN_ERROR_INVAL; - } - break; - } - token = &tokens[token->parent]; - } -#else - for (i = parser->toknext - 1; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) { - return JSMN_ERROR_INVAL; - } - for (; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - parser->toksuper = i; - break; - } - } -#endif - break; - case '\"': - r = jsmn_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) { - return r; - } - count++; - if (parser->toksuper != -1 && tokens != NULL) { - tokens[parser->toksuper].size++; - } - break; - case '\t': - case '\r': - case '\n': - case ' ': - break; - case ':': - parser->toksuper = parser->toknext - 1; - break; - case ',': - if (tokens != NULL && parser->toksuper != -1 && - tokens[parser->toksuper].type != JSMN_ARRAY && - tokens[parser->toksuper].type != JSMN_OBJECT) { -#ifdef JSMN_PARENT_LINKS - parser->toksuper = tokens[parser->toksuper].parent; -#else - for (i = parser->toknext - 1; i >= 0; i--) { - if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { - if (tokens[i].start != -1 && tokens[i].end == -1) { - parser->toksuper = i; - break; - } - } - } -#endif - } - break; -#ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 't': - case 'f': - case 'n': - /* And they must not be keys of the object */ - if (tokens != NULL && parser->toksuper != -1) { - const jsmntok_t *t = &tokens[parser->toksuper]; - if (t->type == JSMN_OBJECT || - (t->type == JSMN_STRING && t->size != 0)) { - return JSMN_ERROR_INVAL; - } - } -#else - /* In non-strict mode every unquoted value is a primitive */ - default: -#endif - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) { - return r; - } - count++; - if (parser->toksuper != -1 && tokens != NULL) { - tokens[parser->toksuper].size++; - } - break; - -#ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; -#endif - } - } - - if (tokens != NULL) { - for (i = parser->toknext - 1; i >= 0; i--) { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { - return JSMN_ERROR_PART; - } - } - } - - return count; -} - -/** - * Creates a new parser based over a given buffer with an array of tokens - * available. - */ -JSMN_API void jsmn_init(jsmn_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; -} - -#endif /* JSMN_HEADER */ - -#ifdef __cplusplus -} -#endif - -#endif /* JSMN_H */ diff --git a/src/json.c b/src/json.c deleted file mode 100644 index 073c632..0000000 --- a/src/json.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "jsmn.h" -#include -#include -#include -#include -#include - -//ToDo: Json Parser -// Requires dictionary type - -static inline void *realloc_it(void *ptrmem, size_t size) { - void *p = realloc(ptrmem, size); - if (!p) { - free(ptrmem); - fprintf(stderr, "realloc(): errno=%d\n", errno); - } - return p; -} - -static int dump(const char *js, jsmntok_t *t, size_t count, int indent) { - int i, j, k; - jsmntok_t *key; - if (count == 0) { - return 0; - } - if (t->type == JSMN_PRIMITIVE) { - printf("%.*s", t->end - t->start, js + t->start); - return 1; - } else if (t->type == JSMN_STRING) { - printf("'%.*s'", t->end - t->start, js + t->start); - return 1; - } else if (t->type == JSMN_OBJECT) { - printf("\n"); - j = 0; - for (i = 0; i < t->size; i++) { - for (k = 0; k < indent; k++) { - printf(" "); - } - key = t + 1 + j; - j += dump(js, key, count - j, indent + 1); - if (key->size > 0) { - printf(": "); - j += dump(js, t + 1 + j, count - j, indent + 1); - } - printf("\n"); - } - return j + 1; - } else if (t->type == JSMN_ARRAY) { - j = 0; - printf("\n"); - for (i = 0; i < t->size; i++) { - for (k = 0; k < indent - 1; k++) { - printf(" "); - } - printf(" - "); - j += dump(js, t + 1 + j, count - j, indent + 1); - printf("\n"); - } - return j + 1; - } - return 0; -} - -int run() { - int r; - int eof_expected = 0; - char *js = NULL; - size_t jslen = 0; - char buf[BUFSIZ]; - - jsmn_parser p; - jsmntok_t *tok; - size_t tokcount = 2; - - /* Prepare parser */ - jsmn_init(&p); - - /* Allocate some tokens as a start */ - tok = malloc(sizeof(*tok) * tokcount); - if (tok == NULL) { - fprintf(stderr, "malloc(): errno=%d\n", errno); - return 3; - } - - for (;;) { - /* Read another chunk */ - r = fread(buf, 1, sizeof(buf), stdin); - if (r < 0) { - fprintf(stderr, "fread(): %d, errno=%d\n", r, errno); - return 1; - } - if (r == 0) { - if (eof_expected != 0) { - return 0; - } else { - fprintf(stderr, "fread(): unexpected EOF\n"); - return 2; - } - } - - js = realloc_it(js, jslen + r + 1); - if (js == NULL) { - return 3; - } - strncpy(js + jslen, buf, r); - jslen = jslen + r; - - again: - r = jsmn_parse(&p, js, jslen, tok, tokcount); - if (r < 0) { - if (r == JSMN_ERROR_NOMEM) { - tokcount = tokcount * 2; - tok = realloc_it(tok, sizeof(*tok) * tokcount); - if (tok == NULL) { - return 3; - } - goto again; - } - } else { - dump(js, tok, p.toknext, 0); - eof_expected = 1; - } - } - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/src/json.h b/src/json.h deleted file mode 100644 index 0fefcda..0000000 --- a/src/json.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef CONNERY_JSON_H -#define CONNERY_JSON_H - - - - -#endif //CONNERY_JSON_H From 39b65f25a92505675c8f7424796f28b1cdb32d3e Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Thu, 14 Oct 2021 20:03:13 -0400 Subject: [PATCH 07/43] added stow --- src/cval.c | 2 +- src/hashtable.c | 13 ++++++++----- src/main.c | 10 ++++++++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/cval.c b/src/cval.c index 0b1705a..3073919 100644 --- a/src/cval.c +++ b/src/cval.c @@ -279,7 +279,7 @@ cval* cval_copy(cval* v) { break; case CVAL_DICTIONARY: - v->ht = hash_table_copy(x->ht); + x->ht = hash_table_copy(v->ht); break; } diff --git a/src/hashtable.c b/src/hashtable.c index 269349e..f57d4d5 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -159,18 +159,21 @@ void hash_table_destroy(hash_table *target_hash_table) { hash_table *hash_table_copy(hash_table *target_hash_table) { hash_table *new_hash_table = hash_table_create(target_hash_table->table_size); - for (long i = 0; i < target_hash_table->table_size; i++) { - new_hash_table->entries[i] = target_hash_table->entries[i]; + if (target_hash_table->items == 0) { + return new_hash_table; } - new_hash_table->items = target_hash_table->items; + for (long i = 0; i < target_hash_table->table_size; i++) { + if (target_hash_table->entries[i] != NULL) { + hash_table_set(new_hash_table, target_hash_table->entries[i]->key, target_hash_table->entries[i]->value); + }; + } return new_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++) { @@ -228,7 +231,7 @@ int hash_table_print(hash_table *target_hash_table) { } - printf("\ntotal items: "); + printf("\ntotal items: %li/%li", target_hash_table->items, target_hash_table->table_size); return target_hash_table -> items; } \ No newline at end of file diff --git a/src/main.c b/src/main.c index 39ae998..8508514 100644 --- a/src/main.c +++ b/src/main.c @@ -947,6 +947,15 @@ cval *builtin_type(cenv *e, cval *a) { } } +cval *builtin_stow(cenv *e, cval *a) { + CASSERT_TYPE("stow", a, 0, CVAL_DICTIONARY); + CASSERT_TYPE("stow", a, 1, CVAL_STRING); + CASSERT_NUM("stow", a, 3); + + hash_table_set(a->cell[0]->ht, a->cell[1]->str, a->cell[2]); + return a->cell[0]; +} + cval *builtin_http(cenv *e, cval *a) { CASSERT_TYPE("http", a, 0, CVAL_STRING); CASSERT_TYPE("http", a, 1, CVAL_STRING); @@ -1084,6 +1093,7 @@ void cenv_add_builtins(cenv *e) { cenv_add_builtin(e, "\\", builtin_lambda); cenv_add_builtin(e, "def", builtin_def); cenv_add_builtin(e, "=", builtin_put); + cenv_add_builtin(e, "stow", builtin_stow); cenv_add_builtin(e, "list", builtin_list); cenv_add_builtin(e, "head", builtin_head); From 9f8b8e823df306e7925a9712aac39a2cfb6812d8 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Thu, 14 Oct 2021 21:45:12 -0400 Subject: [PATCH 08/43] Improved stow --- src/main.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 8508514..a95b3e0 100644 --- a/src/main.c +++ b/src/main.c @@ -950,12 +950,32 @@ cval *builtin_type(cenv *e, cval *a) { cval *builtin_stow(cenv *e, cval *a) { CASSERT_TYPE("stow", a, 0, CVAL_DICTIONARY); CASSERT_TYPE("stow", a, 1, CVAL_STRING); - CASSERT_NUM("stow", a, 3); + + if (a->count < 3) { + return cval_fault("stow requiresh at leasht three argumentsh, lad." + "The dictionary, the key (ash a shtring of courshe) and the value to be shet."); + } hash_table_set(a->cell[0]->ht, a->cell[1]->str, a->cell[2]); + + if (a->count >= 5) { + int pos = 0; + while (a->count > (pos + 3)) { + hash_table_set(a->cell[0]->ht, a->cell[pos + 3]->str, a->cell[pos + 4]); + pos += 2; + } + } return a->cell[0]; } +cval *builtin_grab(cenv *e, cval *a) { + CASSERT_TYPE("stow", a, 0, CVAL_DICTIONARY); + CASSERT_TYPE("stow", a, 1, CVAL_STRING); + CASSERT_NUM("stow", a, 2); + + return hash_table_get(a->cell[0]->ht, a->cell[1]->str); +} + cval *builtin_http(cenv *e, cval *a) { CASSERT_TYPE("http", a, 0, CVAL_STRING); CASSERT_TYPE("http", a, 1, CVAL_STRING); @@ -1093,7 +1113,9 @@ void cenv_add_builtins(cenv *e) { cenv_add_builtin(e, "\\", builtin_lambda); cenv_add_builtin(e, "def", builtin_def); cenv_add_builtin(e, "=", builtin_put); + cenv_add_builtin(e, "stow", builtin_stow); + cenv_add_builtin(e, "grab", builtin_grab); cenv_add_builtin(e, "list", builtin_list); cenv_add_builtin(e, "head", builtin_head); From da2102e0dfc6a2b7c7c386d5c22e2241fb13a384 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Thu, 14 Oct 2021 21:50:45 -0400 Subject: [PATCH 09/43] Improved stow further --- src/main.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main.c b/src/main.c index a95b3e0..b36a80f 100644 --- a/src/main.c +++ b/src/main.c @@ -952,7 +952,7 @@ cval *builtin_stow(cenv *e, cval *a) { CASSERT_TYPE("stow", a, 1, CVAL_STRING); if (a->count < 3) { - return cval_fault("stow requiresh at leasht three argumentsh, lad." + return cval_fault("stow requiresh at leasht three argumentsh." "The dictionary, the key (ash a shtring of courshe) and the value to be shet."); } @@ -961,17 +961,22 @@ cval *builtin_stow(cenv *e, cval *a) { if (a->count >= 5) { int pos = 0; while (a->count > (pos + 3)) { + + if ((a->count - pos + 3) % 2 == 0) { hash_table_set(a->cell[0]->ht, a->cell[pos + 3]->str, a->cell[pos + 4]); - pos += 2; + pos += 2;} + else { + return cval_fault("shtow requiresh a even number of argumentsh, lad."); + } } } return a->cell[0]; } cval *builtin_grab(cenv *e, cval *a) { - CASSERT_TYPE("stow", a, 0, CVAL_DICTIONARY); - CASSERT_TYPE("stow", a, 1, CVAL_STRING); - CASSERT_NUM("stow", a, 2); + CASSERT_TYPE("grab", a, 0, CVAL_DICTIONARY); + CASSERT_TYPE("grab", a, 1, CVAL_STRING); + CASSERT_NUM("grab", a, 2); return hash_table_get(a->cell[0]->ht, a->cell[1]->str); } From f6805c2dc39acf18b4b723abcea49db7d0a6d6dd Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Fri, 15 Oct 2021 22:18:28 -0400 Subject: [PATCH 10/43] Add NULL type to support grab --- src/cval.c | 29 +++++++++++++++++++++++++++++ src/cval.h | 4 +++- src/main.c | 30 +++++++++++++++++++++++++----- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/cval.c b/src/cval.c index 3073919..07acd44 100644 --- a/src/cval.c +++ b/src/cval.c @@ -33,6 +33,8 @@ cval* cval_pop(cval* value, int i); cval* cval_evaluate(cenv* env,cval* value); cval* cval_take(cval* value, int i); +cval* NULL_CVAL_CONSTANT = NULL; + char* ctype_name(int t) { switch(t) { case CVAL_FUNCTION: return "Function"; @@ -45,6 +47,7 @@ char* ctype_name(int t) { case CVAL_FLOAT: return "Float"; case CVAL_BOOLEAN: return "Boolean"; case CVAL_DICTIONARY: return "Dictionary"; + case CVAL_NULL: return "Null"; default: return "Unknown Type"; } } @@ -132,6 +135,20 @@ cval* cval_dictionary(hash_table* ht) { return value; } +cval* cval_null() { + if (NULL_CVAL_CONSTANT == NULL) { + cval *value = malloc(sizeof(cval)); + value->type = CVAL_NULL; + value->count = -1; + value->str = "NULL"; + value->num = 0; + value->fnum = 0.0; + value->cell = NULL; + value->boolean = false; + NULL_CVAL_CONSTANT = value; + } + return NULL_CVAL_CONSTANT; +} cenv* cenv_new(void) { @@ -187,6 +204,9 @@ void cval_delete(cval* value) { hash_table_destroy(value->ht); break; + case CVAL_NULL: + break; + } free(value); } @@ -281,6 +301,10 @@ cval* cval_copy(cval* v) { case CVAL_DICTIONARY: x->ht = hash_table_copy(v->ht); break; + + case CVAL_NULL: + x = v; + break; } return x; @@ -700,6 +724,11 @@ bool cval_print(cval* value) { case CVAL_DICTIONARY: hash_table_print(value->ht); + break; + + case CVAL_NULL: + printf("NULL"); + break; } return true; diff --git a/src/cval.h b/src/cval.h index 7f38435..d7e887c 100644 --- a/src/cval.h +++ b/src/cval.h @@ -13,7 +13,7 @@ typedef cval *(*cbuiltin)(cenv *, cval *); enum { CVAL_NUMBER, CVAL_FAULT, CVAL_SYMBOL, CVAL_FUNCTION, CVAL_S_EXPRESSION, CVAL_Q_EXPRESSION, CVAL_STRING, CVAL_FLOAT, - CVAL_BOOLEAN, CVAL_DICTIONARY + CVAL_BOOLEAN, CVAL_DICTIONARY, CVAL_NULL }; struct cval { @@ -61,6 +61,8 @@ cval *cval_s_expression(void); cval *cval_q_expression(void); +cval *cval_null(void); + void cval_delete(cval *value); cval *cval_take(cval *value, int i); diff --git a/src/main.c b/src/main.c index b36a80f..3610d4b 100644 --- a/src/main.c +++ b/src/main.c @@ -974,11 +974,29 @@ cval *builtin_stow(cenv *e, cval *a) { } cval *builtin_grab(cenv *e, cval *a) { - CASSERT_TYPE("grab", a, 0, CVAL_DICTIONARY); - CASSERT_TYPE("grab", a, 1, CVAL_STRING); - CASSERT_NUM("grab", a, 2); + CASSERT_TYPE("grab", a, 0, CVAL_DICTIONARY) - return hash_table_get(a->cell[0]->ht, a->cell[1]->str); + if (a->count == 2) { + CASSERT_TYPE("grab", a, 1, CVAL_STRING) + cval* result = cval_copy(hash_table_get(a->cell[0]->ht, a->cell[1]->str)); + cval_delete(a); + return result; + } + + int idx = 1; + cval *list = cval_q_expression(); + while (idx < a->count) { + if (a->cell[idx]->type == CVAL_STRING) { + cval_add(list, cval_copy(hash_table_get(a->cell[0]->ht, a->cell[idx]->str))); + idx += 1; + } else { + free(list); + return cval_fault("I can only grab itemsh via namesh defined in shtringsh, lad. Try again."); + } + } + + cval_delete(a); + return list; } cval *builtin_http(cenv *e, cval *a) { @@ -1208,12 +1226,13 @@ int main(int argc, char **argv) { cenv *e = cenv_new(); + hash_table_set(e->ht, "NULL", cval_null()); cenv_add_builtins(e); load_standard_lib(e); puts(" ______ \n" " / ____/___ ____ ____ ___ _______ __\n" - " / / / __ \\/ __ \\/ __ \\/ _ \\/ ___/ / / /\n" + " / / / __ \\/ __ \\/ __ \\/ _ \\=/ ___/ / / /\n" "/ /___/ /_/ / / / / / / / __/ / / /_/ / \n" "\\____/\\____/_/ /_/_/ /_/\\___/_/ \\__, / \n" " /____/ "); @@ -1225,6 +1244,7 @@ int main(int argc, char **argv) { hash_table_set(e->ht, "__LOG_LEVEL__", cval_number(LOG_LEVEL)); + if (argc == 1) { hash_table_set(e->ht, "__SOURCE__", cval_string("INTERACTIVE")); #if TRACE_ENABLED == 1 From 5ef8b291a77523df98ce70cb3dd0a9deac7f4e28 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Fri, 15 Oct 2021 22:43:30 -0400 Subject: [PATCH 11/43] - Fixed bug with NULL type - Added immortal types - Completed grab --- src/cval.c | 7 +++++-- src/main.c | 12 +++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/cval.c b/src/cval.c index 07acd44..7bd3b1c 100644 --- a/src/cval.c +++ b/src/cval.c @@ -164,8 +164,8 @@ void cenv_delete(cenv* e) { } void cval_delete(cval* value) { + bool immortal = false; switch(value->type) { - case CVAL_NUMBER: break; @@ -205,10 +205,13 @@ void cval_delete(cval* value) { break; case CVAL_NULL: + immortal = true; break; } - free(value); + + if (!immortal) { + free(value); } } cval* cval_take(cval* value, int i) { diff --git a/src/main.c b/src/main.c index 3610d4b..181b56e 100644 --- a/src/main.c +++ b/src/main.c @@ -987,14 +987,20 @@ cval *builtin_grab(cenv *e, cval *a) { cval *list = cval_q_expression(); while (idx < a->count) { if (a->cell[idx]->type == CVAL_STRING) { - cval_add(list, cval_copy(hash_table_get(a->cell[0]->ht, a->cell[idx]->str))); + cval *item = hash_table_get(a->cell[0]->ht, a->cell[idx]->str); + + if (item == NULL) { + cval_add(list, cval_null()); + } else { + cval_add(list, cval_copy(item)); + } idx += 1; } else { - free(list); + cval_delete(list); + cval_delete(a); return cval_fault("I can only grab itemsh via namesh defined in shtringsh, lad. Try again."); } } - cval_delete(a); return list; } From 359de2469b42a94cec96f8cbaf7c94a1b68bea7a Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Sat, 16 Oct 2021 13:03:16 -0400 Subject: [PATCH 12/43] - functional stow and grab --- src/cval.c | 22 ++++++--- src/hashtable.c | 5 +- src/main.c | 102 ++++++++++++++++++++++++++-------------- src/stdlib/http.connery | 101 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+), 44 deletions(-) diff --git a/src/cval.c b/src/cval.c index 7bd3b1c..a4f7bc7 100644 --- a/src/cval.c +++ b/src/cval.c @@ -8,7 +8,8 @@ #include #include -#define ENV_HASH_TABLE_SIZE 10000 +#define ENV_HASH_TABLE_SIZE 1000 +#define DICTIONARY_LITERAL_INSTANTIATED_HASH_TABLE_MINIMUM 100 #define SYSTEM_LANG 1 #define CASSERT(args, cond, fmt, ...) \ @@ -248,6 +249,11 @@ cenv* cenv_copy(cenv* e) { } cval* cval_copy(cval* v) { + + if (v == NULL || v->type == CVAL_NULL) { + return cval_null(); + } + cval* x = malloc(sizeof(cval)); x->type = v->type; @@ -304,10 +310,6 @@ cval* cval_copy(cval* v) { case CVAL_DICTIONARY: x->ht = hash_table_copy(v->ht); break; - - case CVAL_NULL: - x = v; - break; } return x; @@ -556,9 +558,15 @@ cval *cval_read_dictionary(mpc_ast_t *t) { int items = t->children_num - 2; int iter = 1; - hash_table* ht = hash_table_create(items * 10); + hash_table* ht = hash_table_create(items + DICTIONARY_LITERAL_INSTANTIATED_HASH_TABLE_MINIMUM); + while (iter <= items) { - hash_table_set(ht, t->children[iter]->children[0]->contents, cval_read(t->children[iter]->children[2])); + t->children[iter]->children[0]->contents[strlen(t->children[iter]->children[0]->contents)-1] = '\0'; + char* unescaped = malloc(strlen(t->children[iter]->children[0]->contents+1)+1); + strcpy(unescaped, t->children[iter]->children[0]->contents+1); + unescaped = mpcf_unescape(unescaped); + hash_table_set(ht, unescaped, cval_read(t->children[iter]->children[2])); + free(unescaped); iter += 1; } diff --git a/src/hashtable.c b/src/hashtable.c index f57d4d5..1f300b2 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -61,7 +61,8 @@ void hash_table_set(hash_table *target_hash_table, const char *key, cval *value) } cval *hash_table_get(hash_table *target_hash_table, const char *key) { - if (target_hash_table->items == 0) { + + if (target_hash_table == NULL) { return NULL; } @@ -164,7 +165,7 @@ hash_table *hash_table_copy(hash_table *target_hash_table) { } for (long i = 0; i < target_hash_table->table_size; i++) { - if (target_hash_table->entries[i] != NULL) { + if (target_hash_table->entries[i] != NULL && target_hash_table->entries[i]->key != NULL && target_hash_table->entries[i]->value != NULL) { hash_table_set(new_hash_table, target_hash_table->entries[i]->key, target_hash_table->entries[i]->value); }; } diff --git a/src/main.c b/src/main.c index 181b56e..994afd0 100644 --- a/src/main.c +++ b/src/main.c @@ -16,7 +16,9 @@ #define TRACE_ENABLED 1 #if TRACE_ENABLED == 1 + #include "trace.h" + #else typedef struct trace {} trace; #endif @@ -291,6 +293,7 @@ cval *builtin_head(cenv *e, cval *a) { } #if TRACE_ENABLED == 1 + cval *set_trace_data(cenv *e, trace *t) { hash_table_set(e->ht, "__STATEMENT_NUMBER__", cval_number(t->current->position)); @@ -304,6 +307,7 @@ cval *set_trace_data(cenv *e, trace *t) { hash_table_set(e->ht, "__EXPRESSION__", t->current->data); } + #endif cval *builtin_tail(cenv *e, cval *a) { @@ -654,13 +658,14 @@ cval *builtin_for(cenv *e, cval *a) { cval *loop = cval_copy(loop_org); while (y <= q) { - x = cval_evaluate(e, loop); - y += 1; - if (y <= q) { - cval_delete(x); - loop = cval_copy(loop_org); + x = cval_evaluate(e, loop); + y += 1; + if (y <= q) { + cval_delete(x); + loop = cval_copy(loop_org); - }} + } + } cval_delete(loop_org); cval_delete(a); @@ -948,25 +953,40 @@ cval *builtin_type(cenv *e, cval *a) { } cval *builtin_stow(cenv *e, cval *a) { - CASSERT_TYPE("stow", a, 0, CVAL_DICTIONARY); CASSERT_TYPE("stow", a, 1, CVAL_STRING); if (a->count < 3) { - return cval_fault("stow requiresh at leasht three argumentsh." + return cval_fault("Stow requiresh at leasht three argumentsh." "The dictionary, the key (ash a shtring of courshe) and the value to be shet."); } - hash_table_set(a->cell[0]->ht, a->cell[1]->str, a->cell[2]); + hash_table* ht = NULL; + + if (a->cell[0]->type == CVAL_DICTIONARY) { + ht = a->cell[0]->ht; + } else { + if (a->cell[0]->type == CVAL_Q_EXPRESSION) { + if (a->cell[0]->cell[0]->type == CVAL_DICTIONARY) { + ht = a->cell[0]->cell[0]->ht; + } + } + } + + if (ht == NULL) { + return cval_fault("Stow requiresh a dictionary, shtring for the key, and a value for the value."); + } + + hash_table_set(ht, a->cell[1]->str, a->cell[2]); if (a->count >= 5) { int pos = 0; while (a->count > (pos + 3)) { if ((a->count - pos + 3) % 2 == 0) { - hash_table_set(a->cell[0]->ht, a->cell[pos + 3]->str, a->cell[pos + 4]); - pos += 2;} - else { - return cval_fault("shtow requiresh a even number of argumentsh, lad."); + hash_table_set(ht, a->cell[pos + 3]->str, a->cell[pos + 4]); + pos += 2; + } else { + return cval_fault("Stow requiresh a even number of argumentsh, lad."); } } } @@ -974,35 +994,48 @@ cval *builtin_stow(cenv *e, cval *a) { } cval *builtin_grab(cenv *e, cval *a) { - CASSERT_TYPE("grab", a, 0, CVAL_DICTIONARY) - if (a->count == 2) { - CASSERT_TYPE("grab", a, 1, CVAL_STRING) - cval* result = cval_copy(hash_table_get(a->cell[0]->ht, a->cell[1]->str)); - cval_delete(a); - return result; + hash_table* ht = NULL; + + if (a->cell[0]->type == CVAL_Q_EXPRESSION) { + if (a->cell[0]->cell[0]->type == CVAL_DICTIONARY) { + ht = a->cell[0]->cell[0]->ht; + } + } else { + if (a->cell[0]->type == CVAL_DICTIONARY) { + ht = a->cell[0]->ht; + } + } + + if (ht == NULL) { + return cval_fault("Grab requiresh at leasht two argumentsh, the dictionary to fetch from, and the key to fetch."); } int idx = 1; - cval *list = cval_q_expression(); + cval *list = cval_q_expression();; while (idx < a->count) { if (a->cell[idx]->type == CVAL_STRING) { - cval *item = hash_table_get(a->cell[0]->ht, a->cell[idx]->str); - if (item == NULL) { - cval_add(list, cval_null()); - } else { - cval_add(list, cval_copy(item)); - } - idx += 1; + cval *item = NULL; + + item = hash_table_get(ht, a->cell[idx]->str); + + if (item == NULL) { + cval_add(list, cval_null()); } else { - cval_delete(list); - cval_delete(a); - return cval_fault("I can only grab itemsh via namesh defined in shtringsh, lad. Try again."); + cval_add(list, cval_copy(item)); } + idx += 1; + } else { + cval_delete(list); + cval_delete(a); + return cval_fault("I can only grab itemsh via namesh defined in shtringsh, lad. Try again."); } - cval_delete(a); - return list; +} + +cval_delete(a); +return +list; } cval *builtin_http(cenv *e, cval *a) { @@ -1218,9 +1251,8 @@ int main(int argc, char **argv) { |'+' | '-' | '*' | '/' ; \ sexpr : '(' * ')' ; \ qexpr : '{' * '}' ; \ - dictionary_pair : /[a-zA-Z0-9]*/ '&' /[,]?/ \ - | /[a-zA-Z0-9]*/ / & / /[,]?/ ; \ - dictionary : '#' * '#' ; \ + dictionary_pair : '&' /[,]?/ ; \ + dictionary : '#' * '#' ; \ string : /\"(\\\\.|[^\"])*\"/; \ comment : /;[^\\r\\n]*/ ; \ expr : | | \ diff --git a/src/stdlib/http.connery b/src/stdlib/http.connery index 0dbdecc..226f3df 100644 --- a/src/stdlib/http.connery +++ b/src/stdlib/http.connery @@ -2,6 +2,107 @@ (def {__HTTP_POST__} "POST") (def {__HTTP_DOWN__} "DOWN") +(def {__http_status_codes__} { + # + "100"&"Continue", + "101"&"Switching Protocols", + "102"&"Processing", + "103"&"Early Hints", + "110"&"Response is Stale", + "111"&"Revalidation Failed", + "112"&"Disconnected Operation", + "113"&"Heuristic Expiration", + "199"&"Miscellaneous Warning", + "214"&"Transformation Applied", + "299"&"Miscellaneous Persistent Warning", + "200"&"OK", + "201"&"Created", + "202"&"Accepted", + "203"&"Non-Authoritative Information", + "204"&"No Content", + "205"&"Reset Content", + "206"&"Partial Content", + "207"&"Multi-Status", + "208"&"Already Reported", + "218"&"This is fine", + "226"&"IM Used", + "300"&"Multiple Choices", + "301"&"Moved Permanently", + "302"&"Found", + "303"&"See Other", + "304"&"Not Modified", + "305"&"Use Proxy", + "306"&"Switch Proxy", + "307"&"Temporary Redirect", + "308"&"Permanent Redirect", + "400"&"Bad Request", + "401"&"Unauthorized", + "402"&"Payment Required", + "403"&"Forbidden", + "404"&"Not Found", + "405"&"Method Not Allowed", + "406"&"Not Acceptable", + "407"&"Proxy Authentication Required", + "408"&"Request Timeout", + "409"&"Conflict", + "410"&"Gone", + "411"&"Length Required", + "412"&"Precondition Failed", + "413"&"Payload Too Large", + "414"&"URI Too Long", + "415"&"Unsupported Media Type", + "416"&"Range Not Satisfiable", + "417"&"Expectation Failed", + "418"&"I'm a teapot", + "419"&"Page Expired", + "420"&"Method Failure/Enhance Your Calm", + "421"&"Misdirected Request", + "422"&"Unprocessable Entity", + "423"&"Locked", + "424"&"Failed Dependency", + "425"&"Too Early", + "426"&"Upgrade Required", + "428"&"Precondition Required", + "429"&"Too Many Requests", + "430"&"Request Header Fields Too Large", + "431"&"Request Header Fields Too Large", + "444"&"No Response", + "450"&"Blocked by Windows Parental Controls", + "451"&"Unavailable For Legal Reasons", + "463"&"Client closed connection", + "463"&"Too many IP addresses within X-Forwarded-For", + "494"&"Request header too large", + "495"&"SSL Certificate Error", + "496"&"SSL Certificate Required", + "497"&"HTTP Request Sent to HTTPS Port", + "499"&"Client Closed Request", + "500"&"Internal Server Error", + "501"&"Not Not Implemented", + "502"&"Bad Gateway", + "503"&"Service Unavailable", + "504"&"Gateway Timeout", + "505"&"HTTP Version Not Supported", + "506"&"Variant Also Negotiates", + "507"&"Insufficient Storage", + "508"&"Loop Detected", + "509"&"Bandwidth Limit Exceeded", + "510"&"Not Extended", + "511"&"Network Authentication Required" + "520"&"Web Server Returned an Unknown Error", + "521"&"Web Server Is Down", + "522"&"Connection Timed Out", + "523"&"Origin Is Unreachable", + "524"&"A Timeout Occurred", + "525"&"SSL Handshake Failed", + "526"&"Invalid SSL Certificate", + "527"&"Railgun Error", + "529"&"Site is overloaded", + "530"&"Site is frozen/Cloudflare 1xxx Error", + "561"&"Unauthorized", + "598"&"Network read timeout error" + # +}) + (fun {http_status_code_text response} { case {(== (first response) 200) "OK"} From 38bfea76c0e2d156384697a966a7a8a7501815f5 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Sat, 16 Oct 2021 17:29:18 -0400 Subject: [PATCH 13/43] - functional stow and grab, for real this time --- src/cval.c | 2 +- src/hashtable.c | 29 +++++++++++++++++++++++++---- src/main.c | 11 +++++------ src/stdlib/http.connery | 20 ++------------------ src/strings.c | 8 ++++++++ src/strings.h | 1 + 6 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/cval.c b/src/cval.c index a4f7bc7..f451231 100644 --- a/src/cval.c +++ b/src/cval.c @@ -130,7 +130,7 @@ cval* cval_q_expression(void) { cval* cval_dictionary(hash_table* ht) { cval* value = malloc(sizeof(cval)); value->type = CVAL_DICTIONARY; - value->count = 0; + value->count = ht->items; value->ht = ht; value->cell = NULL; return value; diff --git a/src/hashtable.c b/src/hashtable.c index 1f300b2..eef27f5 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -60,6 +60,7 @@ void hash_table_set(hash_table *target_hash_table, const char *key, cval *value) target_hash_table->items += 1; } + cval *hash_table_get(hash_table *target_hash_table, const char *key) { if (target_hash_table == NULL) { @@ -157,22 +158,42 @@ void hash_table_destroy(hash_table *target_hash_table) { free(target_hash_table); } -hash_table *hash_table_copy(hash_table *target_hash_table) { - hash_table *new_hash_table = hash_table_create(target_hash_table->table_size); + +hash_table *hash_table_copy_and_resize(hash_table *target_hash_table, int newSize) { + + hash_table *new_hash_table = NULL; + + if (newSize == 0) { + new_hash_table = hash_table_create(target_hash_table->table_size); } + else { + new_hash_table = hash_table_create(newSize); + } + if (target_hash_table->items == 0) { return new_hash_table; } for (long i = 0; i < target_hash_table->table_size; i++) { - if (target_hash_table->entries[i] != NULL && target_hash_table->entries[i]->key != NULL && target_hash_table->entries[i]->value != NULL) { + if (target_hash_table->entries[i] != NULL) { hash_table_set(new_hash_table, target_hash_table->entries[i]->key, target_hash_table->entries[i]->value); - }; + + hash_table_entry* prev = target_hash_table->entries[i]->next; + + while (prev != NULL) { + hash_table_set(new_hash_table, prev->key, prev->value); + prev = prev->next; + } + } } return new_hash_table; } +hash_table *hash_table_copy(hash_table *target_hash_table) { + return hash_table_copy_and_resize(target_hash_table, 0); +} + int hash_table_print(hash_table *target_hash_table) { int first_row = 1; diff --git a/src/main.c b/src/main.c index 994afd0..085bb5d 100644 --- a/src/main.c +++ b/src/main.c @@ -13,7 +13,7 @@ #define CONNERY_VERSION "0.0.2" #define CONNERY_VER_INT 2 #define LOG_LEVEL 4 -#define TRACE_ENABLED 1 +#define TRACE_ENABLED 0 #if TRACE_ENABLED == 1 @@ -1122,14 +1122,13 @@ cval *builtin_input(cenv *e, cval *a) { } 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); + cval* new; - return cval_string(str); + if (a->cell[0]->type == CVAL_NUMBER) { + new = cval_string(int_to_string(a->cell[0]->num)); } + return new; } cval *builtin_sys(cenv *e, cval *a) { diff --git a/src/stdlib/http.connery b/src/stdlib/http.connery index 226f3df..45b8fd1 100644 --- a/src/stdlib/http.connery +++ b/src/stdlib/http.connery @@ -69,8 +69,7 @@ "444"&"No Response", "450"&"Blocked by Windows Parental Controls", "451"&"Unavailable For Legal Reasons", - "463"&"Client closed connection", - "463"&"Too many IP addresses within X-Forwarded-For", + "463"&"Client closed connection/Too many IP addresses within X-Forwarded-For", "494"&"Request header too large", "495"&"SSL Certificate Error", "496"&"SSL Certificate Required", @@ -104,22 +103,7 @@ }) (fun {http_status_code_text response} { - case - {(== (first response) 200) "OK"} - {(== (first response) 202) "Accepted"} - {(== (first response) 301) "Moved Permanently"} - {(== (first response) 400) "Bad Request"} - {(== (first response) 401) "Unauthorized"} - {(== (first response) 402) "Payment Required"} - {(== (first response) 403) "Forbidden"} - {(== (first response) 404) "Not Found"} - {(== (first response) 405) "Method Not Allowed"} - {(== (first response) 406) "Not Acceptable"} - {(== (first response) 408) "Request Timeout"} - {(== (first response) 500) "Internal Server Error"} - {(== (first response) 502) "Bad Gateway"} - {(== (first response) 504) "Gateway Timeout"} - {(Otherwise) "Unknown"} + grab __http_status_codes__ (convert_string response) }) (fun {http_get url} { diff --git a/src/strings.c b/src/strings.c index 55fd744..6601f3c 100644 --- a/src/strings.c +++ b/src/strings.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "cval.h" #define SYSTEM_LANG 0 @@ -40,6 +41,12 @@ CASSERT(args, args->count == num, \ #endif +char *int_to_string(long integer) { + char *str = malloc(11); + sprintf(str, "%ld", integer); + return str; +} + // https://creativeandcritical.net/str-replace-c char *repl_str(const char *str, const char *from, const char *to) { @@ -260,6 +267,7 @@ cval *builtin_split(cenv *e, cval *a) { } cval *builtin_concat(cenv *e, cval *a) { +// todo: rewrite this CASSERT_TYPE("concat", a, 0, CVAL_STRING); CASSERT_TYPE("concat", a, 1, CVAL_STRING); diff --git a/src/strings.h b/src/strings.h index b6d1006..ca3e631 100644 --- a/src/strings.h +++ b/src/strings.h @@ -7,5 +7,6 @@ cval *builtin_string_replace_first_char(cenv *e, cval *a); cval *builtin_find(cenv *e, cval *a); cval *builtin_split(cenv *e, cval *a); cval *builtin_concat(cenv *e, cval *a); +char *int_to_string(long integer); #endif //CONNERY_STRINGS_H From 8bf0605185597996ce84dec4e19e9e56234f870a Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Sat, 16 Oct 2021 17:53:42 -0400 Subject: [PATCH 14/43] - functional stow and grab, for real this time --- src/hashtable.c | 25 ++++++++++++++++++++++++- src/hashtable.h | 2 ++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/hashtable.c b/src/hashtable.c index eef27f5..a7bf152 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -4,6 +4,10 @@ #include "hashtable.h" +#define HASH_TABLE_RESIZE_DEPTH 2 +#define HASH_TABLE_RESIZE_BONUS 1000 + + unsigned int hash(const char *key, const long table_size) { unsigned long int value = 0; unsigned int key_len = strlen(key); @@ -21,6 +25,7 @@ hash_table_entry *hash_table_pair(const char *key, cval *value) { hash_table_entry *entry = malloc(sizeof(hash_table_entry) * 1); entry->key = malloc(strlen(key) + 1); + strcpy(entry->key, key); entry->value = malloc(sizeof(cval)); @@ -42,6 +47,7 @@ void hash_table_set(hash_table *target_hash_table, const char *key, cval *value) } hash_table_entry *prev; + int depth = 1; while (entry != NULL) { @@ -54,10 +60,22 @@ void hash_table_set(hash_table *target_hash_table, const char *key, cval *value) prev = entry; entry = prev->next; + depth += 1; } prev->next = hash_table_pair(key, value); target_hash_table->items += 1; + + if (depth > HASH_TABLE_RESIZE_DEPTH) { + hash_table *ht; + ht = hash_table_copy_and_resize(target_hash_table, target_hash_table->table_size + HASH_TABLE_RESIZE_BONUS); + target_hash_table->entries = ht->entries; + target_hash_table->table_size = ht->table_size; + target_hash_table->items = ht->items; + + ht->entries = NULL; + hash_table_destroy(ht); + } } @@ -149,6 +167,11 @@ void hash_table_entry_delete(hash_table *target_hash_table, const char *key) { void hash_table_destroy(hash_table *target_hash_table) { + if (target_hash_table->entries == NULL) { + free(target_hash_table); + return; + } + for (long i = 0; i < target_hash_table->table_size; i++) { if (target_hash_table->entries[i] != NULL) { hash_table_entry_delete(target_hash_table, target_hash_table->entries[i]->key); @@ -159,7 +182,7 @@ void hash_table_destroy(hash_table *target_hash_table) { } -hash_table *hash_table_copy_and_resize(hash_table *target_hash_table, int newSize) { +hash_table *hash_table_copy_and_resize(hash_table *target_hash_table, long newSize) { hash_table *new_hash_table = NULL; diff --git a/src/hashtable.h b/src/hashtable.h index 72e2455..423bbfd 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -25,6 +25,8 @@ void hash_table_destroy(hash_table *target_hash_table); hash_table *hash_table_copy(hash_table *target_hash_table); +hash_table *hash_table_copy_and_resize(hash_table *target_hash_table, long newSize); + void hash_table_entry_delete(hash_table *target_hash_table, const char *key); int hash_table_print(hash_table *target_hash_table); From 77b32a8c68ddca780b06c2735b975e164e603654 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Sun, 17 Oct 2021 10:57:10 -0400 Subject: [PATCH 15/43] - True and False improved --- src/cval.c | 7 ------- src/main.c | 2 ++ src/stdlib/constants.connery | 3 ++- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cval.c b/src/cval.c index f451231..532d788 100644 --- a/src/cval.c +++ b/src/cval.c @@ -544,14 +544,7 @@ cval* cval_read_string(mpc_ast_t* t) { } cval *cval_read_symbol(char *symbol) { - - if (strcmp(symbol, "True") == 0) { - return cval_boolean(true); - } else if (strcmp(symbol, "False") == 0) { - return cval_boolean(false); - } else { return cval_symbol(symbol); - } } cval *cval_read_dictionary(mpc_ast_t *t) { diff --git a/src/main.c b/src/main.c index 085bb5d..c0d5e2b 100644 --- a/src/main.c +++ b/src/main.c @@ -1264,6 +1264,8 @@ int main(int argc, char **argv) { cenv *e = cenv_new(); hash_table_set(e->ht, "NULL", cval_null()); + hash_table_set(e->ht, "True", cval_boolean(true)); + hash_table_set(e->ht, "False", cval_boolean(false)); cenv_add_builtins(e); load_standard_lib(e); diff --git a/src/stdlib/constants.connery b/src/stdlib/constants.connery index a601f3d..01f3e1b 100644 --- a/src/stdlib/constants.connery +++ b/src/stdlib/constants.connery @@ -6,4 +6,5 @@ ; Easter Egg -(def {best_kid} "Alice Imogen Cipriano") \ No newline at end of file +(def {best_kid} "Alice Imogen Cipriano") + From cdf1674ee81481dc619595bd3fbb540af5a68bf7 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Sun, 17 Oct 2021 11:12:36 -0400 Subject: [PATCH 16/43] - Turned booleans into singletons --- src/cval.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/cval.c b/src/cval.c index 532d788..7488540 100644 --- a/src/cval.c +++ b/src/cval.c @@ -35,6 +35,8 @@ cval* cval_evaluate(cenv* env,cval* value); cval* cval_take(cval* value, int i); cval* NULL_CVAL_CONSTANT = NULL; +cval* TRUE_CVAL_CONSTANT = NULL; +cval* FALSE_CVAL_CONSTANT = NULL; char* ctype_name(int t) { switch(t) { @@ -61,12 +63,31 @@ cval* cval_function(cbuiltin func) { } 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; + if (b) { + if (TRUE_CVAL_CONSTANT == NULL) { + cval *value = malloc(sizeof(cval)); + value->type = CVAL_BOOLEAN; + value->num = 1; + value->fnum = 1; + value->boolean = true; + value->count = 0; + value->cell = NULL; + TRUE_CVAL_CONSTANT = value; + } + return TRUE_CVAL_CONSTANT; + } else { + if (FALSE_CVAL_CONSTANT == NULL) { + cval *value = malloc(sizeof(cval)); + value->type = CVAL_BOOLEAN; + value->num = -1; + value->fnum = -1; + value->boolean = false; + value->count = 0; + value->cell = NULL; + FALSE_CVAL_CONSTANT = value; + } + return FALSE_CVAL_CONSTANT; + } } cval* cval_number(long x) { @@ -209,6 +230,10 @@ void cval_delete(cval* value) { immortal = true; break; + case CVAL_BOOLEAN: + immortal = true; + break; + } if (!immortal) { From 81298769cbd2a8ecd2c00c57d3bfc48cc1dfa1a8 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Sun, 17 Oct 2021 12:48:12 -0400 Subject: [PATCH 17/43] - Immortal types finalized - Boolean and Null improvements --- src/cval.c | 84 +++++++++++++++++++++++++++---------------------- src/cval.h | 1 + src/hashtable.c | 9 +++--- 3 files changed, 53 insertions(+), 41 deletions(-) diff --git a/src/cval.c b/src/cval.c index 7488540..dfefd78 100644 --- a/src/cval.c +++ b/src/cval.c @@ -9,7 +9,7 @@ #include #define ENV_HASH_TABLE_SIZE 1000 -#define DICTIONARY_LITERAL_INSTANTIATED_HASH_TABLE_MINIMUM 100 +#define DICTIONARY_LITERAL_INSTANTIATED_HASH_TABLE_MINIMUM 125 #define SYSTEM_LANG 1 #define CASSERT(args, cond, fmt, ...) \ @@ -37,6 +37,7 @@ cval* cval_take(cval* value, int i); cval* NULL_CVAL_CONSTANT = NULL; cval* TRUE_CVAL_CONSTANT = NULL; cval* FALSE_CVAL_CONSTANT = NULL; +bool IMMORTALS_CREATED = false; char* ctype_name(int t) { switch(t) { @@ -62,32 +63,50 @@ cval* cval_function(cbuiltin func) { return v; } +void create_immortals() { + if (!IMMORTALS_CREATED) { + cval *nullConst = malloc(sizeof(cval)); + nullConst->type = CVAL_NULL; + nullConst->count = -1; + nullConst->str = "NULL"; + nullConst->num = 0; + nullConst->fnum = 0.0; + nullConst->cell = NULL; + nullConst->boolean = false; + NULL_CVAL_CONSTANT = nullConst; + + cval *trueConst = malloc(sizeof(cval)); + trueConst->type = CVAL_BOOLEAN; + trueConst->num = 1; + trueConst->fnum = 1; + trueConst->boolean = true; + trueConst->count = 0; + trueConst->cell = NULL; + TRUE_CVAL_CONSTANT = trueConst; + + cval *falseConst = malloc(sizeof(cval)); + falseConst->type = CVAL_BOOLEAN; + falseConst->num = -1; + falseConst->fnum = -1.0; + falseConst->boolean = false; + falseConst->count = 0; + falseConst->cell = NULL; + FALSE_CVAL_CONSTANT = falseConst;} + + IMMORTALS_CREATED = true; +} + cval *cval_boolean(bool b) { + if (!IMMORTALS_CREATED) { + create_immortals(); + } + if (b) { - if (TRUE_CVAL_CONSTANT == NULL) { - cval *value = malloc(sizeof(cval)); - value->type = CVAL_BOOLEAN; - value->num = 1; - value->fnum = 1; - value->boolean = true; - value->count = 0; - value->cell = NULL; - TRUE_CVAL_CONSTANT = value; - } return TRUE_CVAL_CONSTANT; - } else { - if (FALSE_CVAL_CONSTANT == NULL) { - cval *value = malloc(sizeof(cval)); - value->type = CVAL_BOOLEAN; - value->num = -1; - value->fnum = -1; - value->boolean = false; - value->count = 0; - value->cell = NULL; - FALSE_CVAL_CONSTANT = value; - } - return FALSE_CVAL_CONSTANT; } + + return FALSE_CVAL_CONSTANT; + } cval* cval_number(long x) { @@ -158,21 +177,13 @@ cval* cval_dictionary(hash_table* ht) { } cval* cval_null() { - if (NULL_CVAL_CONSTANT == NULL) { - cval *value = malloc(sizeof(cval)); - value->type = CVAL_NULL; - value->count = -1; - value->str = "NULL"; - value->num = 0; - value->fnum = 0.0; - value->cell = NULL; - value->boolean = false; - NULL_CVAL_CONSTANT = value; + if (!IMMORTALS_CREATED) { + create_immortals(); } + return NULL_CVAL_CONSTANT; } - cenv* cenv_new(void) { cenv* e = malloc(sizeof(cenv)); e->par = NULL; @@ -226,10 +237,8 @@ void cval_delete(cval* value) { hash_table_destroy(value->ht); break; - case CVAL_NULL: - immortal = true; - break; + case CVAL_NULL: case CVAL_BOOLEAN: immortal = true; break; @@ -767,3 +776,4 @@ void cval_print_line(cval* value) { putchar('\n'); } } + diff --git a/src/cval.h b/src/cval.h index d7e887c..3592cd0 100644 --- a/src/cval.h +++ b/src/cval.h @@ -121,4 +121,5 @@ cval *builtin_eval(cenv *e, cval *a); cval *builtin_list(cenv *e, cval *a); + #endif //CONNERY_CVAL_H diff --git a/src/hashtable.c b/src/hashtable.c index a7bf152..86c627c 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -4,8 +4,9 @@ #include "hashtable.h" -#define HASH_TABLE_RESIZE_DEPTH 2 -#define HASH_TABLE_RESIZE_BONUS 1000 +#define HASH_TABLE_RESIZE_DEPTH 3 +#define HASH_TABLE_RESIZE_MULTIPLIER 2 +#define HASH_TABLE_RESIZE_BONUS 100 unsigned int hash(const char *key, const long table_size) { @@ -66,9 +67,9 @@ void hash_table_set(hash_table *target_hash_table, const char *key, cval *value) prev->next = hash_table_pair(key, value); target_hash_table->items += 1; - if (depth > HASH_TABLE_RESIZE_DEPTH) { + if (depth >= HASH_TABLE_RESIZE_DEPTH) { hash_table *ht; - ht = hash_table_copy_and_resize(target_hash_table, target_hash_table->table_size + HASH_TABLE_RESIZE_BONUS); + ht = hash_table_copy_and_resize(target_hash_table, (target_hash_table->table_size * HASH_TABLE_RESIZE_MULTIPLIER) + HASH_TABLE_RESIZE_BONUS); target_hash_table->entries = ht->entries; target_hash_table->table_size = ht->table_size; target_hash_table->items = ht->items; From 3d1b19c4c4fb1dbd741084aebc27b1900800919a Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 18 Oct 2021 20:24:51 -0400 Subject: [PATCH 18/43] - Got type working correctly --- src/cval.c | 14 ++------ src/hashtable.c | 2 +- src/main.c | 69 ++++++++++++++++++++++++++++-------- src/stdlib/constants.connery | 10 ------ src/stdlib/main.connery | 1 - src/stdlib/types.connery | 7 ++-- 6 files changed, 62 insertions(+), 41 deletions(-) delete mode 100644 src/stdlib/constants.connery diff --git a/src/cval.c b/src/cval.c index dfefd78..1534539 100644 --- a/src/cval.c +++ b/src/cval.c @@ -8,6 +8,8 @@ #include #include +// todo: add garbage collector for dictionaries + #define ENV_HASH_TABLE_SIZE 1000 #define DICTIONARY_LITERAL_INSTANTIATED_HASH_TABLE_MINIMUM 125 #define SYSTEM_LANG 1 @@ -30,10 +32,6 @@ if (!(cond)) {\ func, args->count, num) -cval* cval_pop(cval* value, int i); -cval* cval_evaluate(cenv* env,cval* value); -cval* cval_take(cval* value, int i); - cval* NULL_CVAL_CONSTANT = NULL; cval* TRUE_CVAL_CONSTANT = NULL; cval* FALSE_CVAL_CONSTANT = NULL; @@ -106,7 +104,6 @@ cval *cval_boolean(bool b) { } return FALSE_CVAL_CONSTANT; - } cval* cval_number(long x) { @@ -233,11 +230,6 @@ void cval_delete(cval* value) { free(value->str); break; - case CVAL_DICTIONARY: - hash_table_destroy(value->ht); - break; - - case CVAL_NULL: case CVAL_BOOLEAN: immortal = true; @@ -342,7 +334,7 @@ cval* cval_copy(cval* v) { break; case CVAL_DICTIONARY: - x->ht = hash_table_copy(v->ht); + x->ht = v->ht; break; } diff --git a/src/hashtable.c b/src/hashtable.c index 86c627c..9481400 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -3,7 +3,6 @@ #include "cval.h" #include "hashtable.h" - #define HASH_TABLE_RESIZE_DEPTH 3 #define HASH_TABLE_RESIZE_MULTIPLIER 2 #define HASH_TABLE_RESIZE_BONUS 100 @@ -43,6 +42,7 @@ void hash_table_set(hash_table *target_hash_table, const char *key, cval *value) if (entry == NULL) { target_hash_table->entries[slot] = hash_table_pair(key, value); + target_hash_table->items += 1; return; } diff --git a/src/main.c b/src/main.c index c0d5e2b..f33b3b7 100644 --- a/src/main.c +++ b/src/main.c @@ -14,6 +14,7 @@ #define CONNERY_VER_INT 2 #define LOG_LEVEL 4 #define TRACE_ENABLED 0 +#define STD_LIB_LOCATION "stdlib/main.connery" #if TRACE_ENABLED == 1 @@ -912,6 +913,12 @@ cval *builtin_length(cenv *e, cval *a) { return cval_number(length); } + if (a->cell[0]->type == CVAL_DICTIONARY) { + long length = a->cell[0]->ht->items; + cval_delete(a); + return cval_number(length); + } + cval_delete(a); #if SYSTEM_LANG == 0 return cval_fault("Function 'length' pashed unshupported type!"); @@ -923,33 +930,58 @@ cval *builtin_length(cenv *e, cval *a) { cval *builtin_type(cenv *e, cval *a) { int type = a->cell[0]->type; - cval_delete(a); + cval* returnVal = NULL; switch (type) { case CVAL_NUMBER: - return cval_number(0); + returnVal = cval_number(0); + break; case CVAL_STRING: - return cval_number(1); + returnVal = cval_number(1); + break; case CVAL_S_EXPRESSION: - return cval_number(2); + returnVal = cval_number(2); + break; case CVAL_Q_EXPRESSION: - return cval_number(3); + if (a->cell[0]->cell[0] != NULL && a->cell[0]->cell[0]->type == CVAL_DICTIONARY) { + returnVal = cval_number(8); + break; + } + returnVal = cval_number(3); + break; case CVAL_FUNCTION: - return cval_number(4); + returnVal = cval_number(4); + break; case CVAL_SYMBOL: - return cval_number(5); + returnVal = cval_number(5); + break; case CVAL_BOOLEAN: - return cval_number(6); + returnVal = cval_number(6); + break; + + case CVAL_FLOAT: + returnVal = cval_number(7); + break; + + case CVAL_DICTIONARY: + returnVal = cval_number(8); + break; + + case CVAL_NULL: + returnVal = cval_number(9); + break; + default: - return cval_fault("Type not defined!"); + returnVal = cval_fault("Type not defined!"); } + return returnVal; } cval *builtin_stow(cenv *e, cval *a) { @@ -959,19 +991,20 @@ cval *builtin_stow(cenv *e, cval *a) { return cval_fault("Stow requiresh at leasht three argumentsh." "The dictionary, the key (ash a shtring of courshe) and the value to be shet."); } - - hash_table* ht = NULL; + cval* activeCval = NULL; if (a->cell[0]->type == CVAL_DICTIONARY) { - ht = a->cell[0]->ht; + activeCval = a->cell[0]; } else { if (a->cell[0]->type == CVAL_Q_EXPRESSION) { if (a->cell[0]->cell[0]->type == CVAL_DICTIONARY) { - ht = a->cell[0]->cell[0]->ht; + activeCval = a->cell[0]->cell[0]; } } } + hash_table* ht = activeCval->ht; + if (ht == NULL) { return cval_fault("Stow requiresh a dictionary, shtring for the key, and a value for the value."); } @@ -990,7 +1023,7 @@ cval *builtin_stow(cenv *e, cval *a) { } } } - return a->cell[0]; + return activeCval; } cval *builtin_grab(cenv *e, cval *a) { @@ -1263,9 +1296,15 @@ int main(int argc, char **argv) { cenv *e = cenv_new(); - hash_table_set(e->ht, "NULL", cval_null()); + hash_table_set(e->ht, "Null", cval_null()); hash_table_set(e->ht, "True", cval_boolean(true)); hash_table_set(e->ht, "False", cval_boolean(false)); + hash_table_set(e->ht, "Empty", cval_string("")); + hash_table_set(e->ht, "None", cval_s_expression()); + hash_table_set(e->ht, "Otherwise", cval_boolean(true)); + hash_table_set(e->ht, "__std_lib_main_location__", cval_string(STD_LIB_LOCATION)); + hash_table_set(e->ht, "__BK_13__", cval_string("Nyvpr Vzbtra Pvcevnab")); + cenv_add_builtins(e); load_standard_lib(e); diff --git a/src/stdlib/constants.connery b/src/stdlib/constants.connery deleted file mode 100644 index 01f3e1b..0000000 --- a/src/stdlib/constants.connery +++ /dev/null @@ -1,10 +0,0 @@ -; Constants -(def {None} {}) -(def {Empty} "") -(def {Otherwise} True) -(def {std_lib_main_location} "stdlib/main.connery") - - -; Easter Egg -(def {best_kid} "Alice Imogen Cipriano") - diff --git a/src/stdlib/main.connery b/src/stdlib/main.connery index 9585262..5a98994 100644 --- a/src/stdlib/main.connery +++ b/src/stdlib/main.connery @@ -1,4 +1,3 @@ -(load "stdlib/constants.connery") (load "stdlib/functional.connery") (load "stdlib/types.connery") (load "stdlib/math.connery") diff --git a/src/stdlib/types.connery b/src/stdlib/types.connery index 91d798d..e29d21d 100644 --- a/src/stdlib/types.connery +++ b/src/stdlib/types.connery @@ -6,9 +6,10 @@ {(== i 3) "Q Expression"} {(== i 4) "Function"} {(== i 5) "Symbol"} - {(== i 6) "Float"} - {(== i 7) "Boolean"} - {(== i 8) "Null"} + {(== i 6) "Boolean"} + {(== i 7) "Float"} + {(== i 8) "Dictionary"} + {(== i 9) "Null Type"} {(Otherwise) "Unknown"} }) From 1e1ee2be7fbd2337921a4cb581fdf65b3b79b88e Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 18 Oct 2021 20:29:00 -0400 Subject: [PATCH 19/43] - Got type working correctly (for real) --- src/main.c | 4 ---- src/stdlib/http.connery | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index f33b3b7..ec1c487 100644 --- a/src/main.c +++ b/src/main.c @@ -946,10 +946,6 @@ cval *builtin_type(cenv *e, cval *a) { break; case CVAL_Q_EXPRESSION: - if (a->cell[0]->cell[0] != NULL && a->cell[0]->cell[0]->type == CVAL_DICTIONARY) { - returnVal = cval_number(8); - break; - } returnVal = cval_number(3); break; diff --git a/src/stdlib/http.connery b/src/stdlib/http.connery index 45b8fd1..d4ee404 100644 --- a/src/stdlib/http.connery +++ b/src/stdlib/http.connery @@ -2,7 +2,7 @@ (def {__HTTP_POST__} "POST") (def {__HTTP_DOWN__} "DOWN") -(def {__http_status_codes__} { +(def {__http_status_codes__} # "100"&"Continue", "101"&"Switching Protocols", @@ -100,7 +100,7 @@ "561"&"Unauthorized", "598"&"Network read timeout error" # -}) +) (fun {http_status_code_text response} { grab __http_status_codes__ (convert_string response) From 2d696d0d2a8d356189555f6341db1a8b87fc26e1 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 18 Oct 2021 22:19:05 -0400 Subject: [PATCH 20/43] - begin work on allocator - added object id's to cvals --- src/CMakeLists.txt | 2 +- src/allocator.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ src/allocator.h | 4 +++ src/cval.h | 3 +- src/main.c | 1 - 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/allocator.c create mode 100644 src/allocator.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07bb98d..ddcf298 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 trace.c trace.h strings.c strings.h) +add_executable(Connery main.c mpc.c util.c util.h hashtable.c hashtable.h cval.h cval.c trace.c trace.h strings.c strings.h allocator.c allocator.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/allocator.c b/src/allocator.c new file mode 100644 index 0000000..ac89b35 --- /dev/null +++ b/src/allocator.c @@ -0,0 +1,69 @@ +#include "allocator.h" +#include "cval.h" + +#define PREALLOCATE_SLOTS 255 +#define PREALLOCATE_ROWS 4 + +int CUR_OBJ_ID = 0; + +typedef struct cval_allocation_array { + cval** array; + int size; + int allocated; +} cval_allocation_array; + +typedef struct cval_allocation_index { + cval_allocation_array** rows; + int cur; + int size; +} cval_allocation_index; + +cval_allocation_index* INDEX = NULL; + +int createObjectId() { + CUR_OBJ_ID += 1; + return CUR_OBJ_ID; +} + +cval_allocation_array *preallocateArray(int slots) { + cval_allocation_array* array_struct = malloc(sizeof(cval_allocation_array)); + cval** array = malloc(sizeof(cval *) * slots); + array_struct->size = slots; + array_struct->allocated = 0; + + for (int i = 0; i < slots; ++i) { + cval *nullConst = malloc(sizeof(cval)); + nullConst->type = CVAL_UNALLOCATED; + nullConst->objId = createObjectId(); + array[i] = nullConst; + } + + array_struct->array = array; + return array_struct; +} + +cval_allocation_index *preallocateIndex(int rows, int slots) { + cval_allocation_index* index = malloc(sizeof(cval_allocation_index)); + index->cur = 0; + + for (int i = 0; i < rows; ++i) { + index->rows[i] = preallocateArray(slots); + } + + return index; +} + +void setup() { + INDEX = preallocateIndex(PREALLOCATE_ROWS, PREALLOCATE_SLOTS); +} + +cval** allocateMany(int total) { + cval** array = malloc(sizeof(cval *) * total); + + for (int i = 0; i < total; ++i) { + if (INDEX->rows[INDEX->cur]->allocated == INDEX->rows[INDEX->cur]->size) { + } + } + + +} \ No newline at end of file diff --git a/src/allocator.h b/src/allocator.h new file mode 100644 index 0000000..cf3328a --- /dev/null +++ b/src/allocator.h @@ -0,0 +1,4 @@ +#ifndef CONNERY_ALLOCATOR_H +#define CONNERY_ALLOCATOR_H + +#endif //CONNERY_ALLOCATOR_H diff --git a/src/cval.h b/src/cval.h index 3592cd0..52ccc5c 100644 --- a/src/cval.h +++ b/src/cval.h @@ -13,7 +13,7 @@ typedef cval *(*cbuiltin)(cenv *, cval *); enum { CVAL_NUMBER, CVAL_FAULT, CVAL_SYMBOL, CVAL_FUNCTION, CVAL_S_EXPRESSION, CVAL_Q_EXPRESSION, CVAL_STRING, CVAL_FLOAT, - CVAL_BOOLEAN, CVAL_DICTIONARY, CVAL_NULL + CVAL_BOOLEAN, CVAL_DICTIONARY, CVAL_NULL, CVAL_UNALLOCATED, CVAL_DELETED }; struct cval { @@ -33,6 +33,7 @@ struct cval { cval *body; int count; + int objId; cval **cell; }; diff --git a/src/main.c b/src/main.c index ec1c487..ed6ee09 100644 --- a/src/main.c +++ b/src/main.c @@ -973,7 +973,6 @@ cval *builtin_type(cenv *e, cval *a) { returnVal = cval_number(9); break; - default: returnVal = cval_fault("Type not defined!"); } From b8f74985ea1e9f5ea20b79e6db35094355156fb0 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Tue, 19 Oct 2021 17:35:58 -0400 Subject: [PATCH 21/43] Started work on allocator --- src/allocator.c | 105 ++++++++++++++++++++++++++++++++++++++---------- src/allocator.h | 3 ++ src/cval.c | 3 +- src/main.c | 3 ++ 4 files changed, 92 insertions(+), 22 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index ac89b35..84d7d3e 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -3,67 +3,130 @@ #define PREALLOCATE_SLOTS 255 #define PREALLOCATE_ROWS 4 - -int CUR_OBJ_ID = 0; +#define ROWS_MAX 32767 +#define MAX_OBJECT_ID 8355585 +#define PRE_CACHE_SIZE 16 typedef struct cval_allocation_array { - cval** array; + cval **array; int size; int allocated; } cval_allocation_array; typedef struct cval_allocation_index { - cval_allocation_array** rows; + cval_allocation_array **rows; int cur; int size; + bool oom; } cval_allocation_index; -cval_allocation_index* INDEX = NULL; +cval_allocation_index *INDEX = NULL; +int CUR_OBJ_ID = 0; +int CUR_PRE_CACHE_POS = NULL; +bool INIT_COMPLETE = false; + +cval *OUT_OF_MEMORY_FAULT = NULL; +cval **preCache = NULL; int createObjectId() { CUR_OBJ_ID += 1; - return CUR_OBJ_ID; + + if (CUR_OBJ_ID <= MAX_OBJECT_ID) { + return CUR_OBJ_ID; + } + + return -1; } cval_allocation_array *preallocateArray(int slots) { - cval_allocation_array* array_struct = malloc(sizeof(cval_allocation_array)); - cval** array = malloc(sizeof(cval *) * slots); + cval_allocation_array *array_struct = malloc(sizeof(cval_allocation_array)); + cval **array = malloc(sizeof(cval *) * slots); array_struct->size = slots; array_struct->allocated = 0; for (int i = 0; i < slots; ++i) { - cval *nullConst = malloc(sizeof(cval)); - nullConst->type = CVAL_UNALLOCATED; - nullConst->objId = createObjectId(); - array[i] = nullConst; + int objId = createObjectId(); + if (objId != -1) { + cval *nullConst = malloc(sizeof(cval)); + nullConst->type = CVAL_UNALLOCATED; + nullConst->objId = objId; + array[i] = nullConst; + } else { + return NULL; + } } - array_struct->array = array; return array_struct; } cval_allocation_index *preallocateIndex(int rows, int slots) { - cval_allocation_index* index = malloc(sizeof(cval_allocation_index)); + cval_allocation_index *index = malloc(sizeof(cval_allocation_index)); index->cur = 0; + index->rows = malloc(sizeof(cval_allocation_array*) * ROWS_MAX); + + if (OUT_OF_MEMORY_FAULT == NULL) { + OUT_OF_MEMORY_FAULT = cval_fault("You've run out of memory, and thush out of time my young friend."); + } for (int i = 0; i < rows; ++i) { - index->rows[i] = preallocateArray(slots); + cval_allocation_array *array = preallocateArray(slots); + if (array != NULL) { + index->rows[i] = array; + } + } + + for (int i = rows; i < ROWS_MAX; ++i) { + index->rows[i] = NULL; } return index; } -void setup() { - INDEX = preallocateIndex(PREALLOCATE_ROWS, PREALLOCATE_SLOTS); -} +void setup(); -cval** allocateMany(int total) { - cval** array = malloc(sizeof(cval *) * total); +cval **allocateMany(int total) { + + cval **array = malloc(sizeof(cval *) * total); for (int i = 0; i < total; ++i) { + // allocate more slots when out of memory, returning out of memory fault + // on failure. if (INDEX->rows[INDEX->cur]->allocated == INDEX->rows[INDEX->cur]->size) { + if (INDEX->cur == INDEX->size) { + if (INDEX->cur < ROWS_MAX) { + INDEX->cur += 1; + INDEX->size += 1; + INDEX->rows[INDEX->cur] = preallocateArray(PREALLOCATE_SLOTS); + } else { + array[i] = OUT_OF_MEMORY_FAULT; + return array; + } + } else { + INDEX->cur += 1; + } } + array[i] = INDEX->rows[INDEX->cur]->array[INDEX->rows[INDEX->cur]->allocated]; + } + + return array; +} + +void allocator_setup() { + INDEX = preallocateIndex(PREALLOCATE_ROWS, PREALLOCATE_SLOTS); + preCache = allocateMany(PRE_CACHE_SIZE); + CUR_PRE_CACHE_POS = 0; + INIT_COMPLETE = true; +} + +cval *allocate() { + cval* val = NULL; + if (CUR_PRE_CACHE_POS > PRE_CACHE_SIZE - 1) { + preCache = allocateMany(PRE_CACHE_SIZE); + CUR_PRE_CACHE_POS = 0; } + val = preCache[CUR_PRE_CACHE_POS]; + CUR_PRE_CACHE_POS += 1; + return val; +} -} \ No newline at end of file diff --git a/src/allocator.h b/src/allocator.h index cf3328a..44977c6 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -1,4 +1,7 @@ #ifndef CONNERY_ALLOCATOR_H #define CONNERY_ALLOCATOR_H +#include "cval.h" +cval *allocate(); +void allocator_setup(); #endif //CONNERY_ALLOCATOR_H diff --git a/src/cval.c b/src/cval.c index 1534539..caf0aa5 100644 --- a/src/cval.c +++ b/src/cval.c @@ -2,6 +2,7 @@ #include "util.h" #include "trace.h" #include "hashtable.h" +#include "allocator.h" #include #include #include @@ -107,7 +108,7 @@ cval *cval_boolean(bool b) { } cval* cval_number(long x) { - cval* value = malloc(sizeof(cval)); + cval* value = allocate(); value->type = CVAL_NUMBER; value->num = x; return value; diff --git a/src/main.c b/src/main.c index ed6ee09..8c14a30 100644 --- a/src/main.c +++ b/src/main.c @@ -6,6 +6,7 @@ #include "util.h" #include "cval.h" #include "hashtable.h" +#include "allocator.h" #include "strings.h" @@ -1258,6 +1259,8 @@ void load_standard_lib(cenv *e) { } int main(int argc, char **argv) { + allocator_setup(); + Number = mpc_new("number"); Float = mpc_new("float"); Symbol = mpc_new("symbol"); From abe1fe58e6e31f05390e30e46decb0589444a201 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Tue, 19 Oct 2021 18:47:33 -0400 Subject: [PATCH 22/43] - more allocator work --- src/allocator.c | 18 ++++++++++++++++-- src/allocator.h | 1 + src/cval.c | 15 +++++++++------ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 84d7d3e..2a40b4f 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -82,8 +82,6 @@ cval_allocation_index *preallocateIndex(int rows, int slots) { return index; } -void setup(); - cval **allocateMany(int total) { cval **array = malloc(sizeof(cval *) * total); @@ -106,16 +104,19 @@ cval **allocateMany(int total) { } } array[i] = INDEX->rows[INDEX->cur]->array[INDEX->rows[INDEX->cur]->allocated]; + INDEX->rows[INDEX->cur]->allocated += 1; } return array; } void allocator_setup() { + if (!INIT_COMPLETE) { INDEX = preallocateIndex(PREALLOCATE_ROWS, PREALLOCATE_SLOTS); preCache = allocateMany(PRE_CACHE_SIZE); CUR_PRE_CACHE_POS = 0; INIT_COMPLETE = true; + } } cval *allocate() { @@ -130,3 +131,16 @@ cval *allocate() { return val; } +void deallocate(cval* cval) { + switch (cval->type) { + case CVAL_NUMBER: + cval->num = 0; + break; + + case CVAL_FLOAT: + cval->fnum = 0; + break; + } + + cval->type = CVAL_DELETED; +} diff --git a/src/allocator.h b/src/allocator.h index 44977c6..c5bd0c5 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -3,5 +3,6 @@ #include "cval.h" cval *allocate(); +void deallocate(cval* cval); void allocator_setup(); #endif //CONNERY_ALLOCATOR_H diff --git a/src/cval.c b/src/cval.c index caf0aa5..96569c5 100644 --- a/src/cval.c +++ b/src/cval.c @@ -115,7 +115,7 @@ cval* cval_number(long x) { } cval* cval_float(long double x) { - cval* value = malloc(sizeof(cval)); + cval* value = allocate(); value->type = CVAL_FLOAT; value->fnum = x; return value; @@ -130,7 +130,9 @@ cval* cval_string (char* s) { } cval* cval_fault(char* fmt, ...) { - cval* value = malloc(sizeof(cval)); + // allows faults to be thrown during + // allocator problems + cval* value = malloc(sizeof(cenv)); value->type = CVAL_FAULT; va_list va; va_start(va, fmt); @@ -183,7 +185,7 @@ cval* cval_null() { } cenv* cenv_new(void) { - cenv* e = malloc(sizeof(cenv)); + cenv* e = malloc(sizeof(cenv*)); e->par = NULL; e->ht = hash_table_create(ENV_HASH_TABLE_SIZE); return e; @@ -197,10 +199,11 @@ void cenv_delete(cenv* e) { void cval_delete(cval* value) { bool immortal = false; switch(value->type) { - case CVAL_NUMBER: - break; + case CVAL_NUMBER: case CVAL_FLOAT: + immortal = true; + deallocate(value); break; case CVAL_FUNCTION: @@ -239,7 +242,7 @@ void cval_delete(cval* value) { } if (!immortal) { - free(value); } + free(value); } } cval* cval_take(cval* value, int i) { From 81d9d3bd1fcf9c1cf325c608f344a375504927b2 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Tue, 19 Oct 2021 19:52:41 -0400 Subject: [PATCH 23/43] - added: sys "ALLOCATOR_STATUS" to track allocator improvements - added: objId to determine object ids --- src/allocator.c | 47 ++++++++++++++++++++++++++++++++++++++--------- src/allocator.h | 2 ++ src/cval.c | 24 +++++++++++++----------- src/cval.h | 2 ++ src/hashtable.c | 3 --- src/main.c | 11 +++++++++++ 6 files changed, 66 insertions(+), 23 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 2a40b4f..a110d6d 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -1,10 +1,10 @@ #include "allocator.h" #include "cval.h" -#define PREALLOCATE_SLOTS 255 -#define PREALLOCATE_ROWS 4 -#define ROWS_MAX 32767 -#define MAX_OBJECT_ID 8355585 +#define PREALLOCATE_SLOTS 4096 +#define PREALLOCATE_ROWS 16 +#define ROWS_MAX 4194304 +#define MAX_OBJECT_ID 17179869184 #define PRE_CACHE_SIZE 16 typedef struct cval_allocation_array { @@ -22,7 +22,7 @@ typedef struct cval_allocation_index { cval_allocation_index *INDEX = NULL; int CUR_OBJ_ID = 0; -int CUR_PRE_CACHE_POS = NULL; +int CUR_PRE_CACHE_POS = 0; bool INIT_COMPLETE = false; cval *OUT_OF_MEMORY_FAULT = NULL; @@ -62,6 +62,7 @@ cval_allocation_array *preallocateArray(int slots) { cval_allocation_index *preallocateIndex(int rows, int slots) { cval_allocation_index *index = malloc(sizeof(cval_allocation_index)); index->cur = 0; + index->size = rows; index->rows = malloc(sizeof(cval_allocation_array*) * ROWS_MAX); if (OUT_OF_MEMORY_FAULT == NULL) { @@ -82,7 +83,7 @@ cval_allocation_index *preallocateIndex(int rows, int slots) { return index; } -cval **allocateMany(int total) { +cval **internalCacheFetch(int total) { cval **array = malloc(sizeof(cval *) * total); @@ -113,8 +114,7 @@ cval **allocateMany(int total) { void allocator_setup() { if (!INIT_COMPLETE) { INDEX = preallocateIndex(PREALLOCATE_ROWS, PREALLOCATE_SLOTS); - preCache = allocateMany(PRE_CACHE_SIZE); - CUR_PRE_CACHE_POS = 0; + preCache = internalCacheFetch(PRE_CACHE_SIZE); INIT_COMPLETE = true; } } @@ -122,7 +122,7 @@ void allocator_setup() { cval *allocate() { cval* val = NULL; if (CUR_PRE_CACHE_POS > PRE_CACHE_SIZE - 1) { - preCache = allocateMany(PRE_CACHE_SIZE); + preCache = internalCacheFetch(PRE_CACHE_SIZE); CUR_PRE_CACHE_POS = 0; } @@ -131,6 +131,18 @@ cval *allocate() { return val; } +cval **allocateMany(int total) { + cval** result = malloc(sizeof(cval*) * total); + int cur = 1; + + while (cur <= total) { + result[cur] = allocate(); + cur += 1; + } + + return result; +} + void deallocate(cval* cval) { switch (cval->type) { case CVAL_NUMBER: @@ -144,3 +156,20 @@ void deallocate(cval* cval) { cval->type = CVAL_DELETED; } + +cval *allocator_status() { + if (INIT_COMPLETE) { + hash_table* ht = hash_table_create(100); + hash_table_set(ht, "PREALLOCATE_SLOTS", cval_number(PREALLOCATE_SLOTS)); + hash_table_set(ht, "PREALLOCATE_ROWS", cval_number(PREALLOCATE_ROWS)); + hash_table_set(ht, "ROWS_MAX", cval_number(ROWS_MAX)); + hash_table_set(ht, "MAX_OBJECT_ID", cval_number(MAX_OBJECT_ID)); + hash_table_set(ht, "PRE_CACHE_SIZE", cval_number(PRE_CACHE_SIZE)); + hash_table_set(ht, "CURRENT_ROW_ALLOCATED", cval_number(INDEX->rows[INDEX->cur]->allocated)); + hash_table_set(ht, "CURRNET_ROWS_SIZE", cval_number(INDEX->rows[INDEX->cur]->size)); + hash_table_set(ht, "INDEX_CURSOR", cval_number(INDEX->cur)); + hash_table_set(ht, "INDEX_SIZE", cval_number(INDEX->size)); + hash_table_set(ht, "NEXT_OBJECT_ID", cval_number(CUR_OBJ_ID)); + return cval_dictionary(ht); } + return OUT_OF_MEMORY_FAULT; +} diff --git a/src/allocator.h b/src/allocator.h index c5bd0c5..34bbb41 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -3,6 +3,8 @@ #include "cval.h" cval *allocate(); +cval **allocateMany(int total); void deallocate(cval* cval); void allocator_setup(); +cval *allocator_status(); #endif //CONNERY_ALLOCATOR_H diff --git a/src/cval.c b/src/cval.c index 96569c5..64a7eb3 100644 --- a/src/cval.c +++ b/src/cval.c @@ -56,7 +56,7 @@ char* ctype_name(int t) { } cval* cval_function(cbuiltin func) { - cval* v = malloc(sizeof(cval)); + cval* v = allocate(); v->type = CVAL_FUNCTION; v->builtin = func; return v; @@ -64,7 +64,7 @@ cval* cval_function(cbuiltin func) { void create_immortals() { if (!IMMORTALS_CREATED) { - cval *nullConst = malloc(sizeof(cval)); + cval *nullConst = allocate(); nullConst->type = CVAL_NULL; nullConst->count = -1; nullConst->str = "NULL"; @@ -74,7 +74,7 @@ void create_immortals() { nullConst->boolean = false; NULL_CVAL_CONSTANT = nullConst; - cval *trueConst = malloc(sizeof(cval)); + cval *trueConst = allocate(); trueConst->type = CVAL_BOOLEAN; trueConst->num = 1; trueConst->fnum = 1; @@ -83,7 +83,7 @@ void create_immortals() { trueConst->cell = NULL; TRUE_CVAL_CONSTANT = trueConst; - cval *falseConst = malloc(sizeof(cval)); + cval *falseConst = allocate(); falseConst->type = CVAL_BOOLEAN; falseConst->num = -1; falseConst->fnum = -1.0; @@ -122,7 +122,7 @@ cval* cval_float(long double x) { } cval* cval_string (char* s) { - cval* v = malloc(sizeof(cval)); + cval* v = allocate(); v->type = CVAL_STRING; v->str = malloc(strlen(s) + 1); strcpy(v->str, s); @@ -144,7 +144,7 @@ cval* cval_fault(char* fmt, ...) { } cval* cval_symbol(char* s) { - cval* value = malloc(sizeof(cval)); + cval* value = allocate(); value->type = CVAL_SYMBOL; value->sym = malloc(strlen(s) + 1); strcpy(value->sym, s); @@ -152,7 +152,7 @@ cval* cval_symbol(char* s) { } cval* cval_s_expression(void) { - cval* value = malloc(sizeof(cval)); + cval* value = allocate(); value->type = CVAL_S_EXPRESSION; value->count = 0; value->cell = NULL; @@ -160,7 +160,7 @@ cval* cval_s_expression(void) { } cval* cval_q_expression(void) { - cval* value = malloc(sizeof(cval)); + cval* value = allocate(); value->type = CVAL_Q_EXPRESSION; value->count = 0; value->cell = NULL; @@ -168,7 +168,7 @@ cval* cval_q_expression(void) { } cval* cval_dictionary(hash_table* ht) { - cval* value = malloc(sizeof(cval)); + cval* value = allocate(); value->type = CVAL_DICTIONARY; value->count = ht->items; value->ht = ht; @@ -231,7 +231,9 @@ void cval_delete(cval* value) { break; case CVAL_STRING: + immortal = true; free(value->str); + deallocate(value); break; case CVAL_NULL: @@ -242,7 +244,7 @@ void cval_delete(cval* value) { } if (!immortal) { - free(value); } + deallocate(value); } } cval* cval_take(cval* value, int i) { @@ -284,7 +286,7 @@ cval* cval_copy(cval* v) { return cval_null(); } - cval* x = malloc(sizeof(cval)); + cval* x = allocate(); x->type = v->type; switch (v->type) { diff --git a/src/cval.h b/src/cval.h index 52ccc5c..722ab6b 100644 --- a/src/cval.h +++ b/src/cval.h @@ -64,6 +64,8 @@ cval *cval_q_expression(void); cval *cval_null(void); +cval* cval_dictionary(hash_table* ht); + void cval_delete(cval *value); cval *cval_take(cval *value, int i); diff --git a/src/hashtable.c b/src/hashtable.c index 9481400..f6836ba 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -277,7 +277,4 @@ int hash_table_print(hash_table *target_hash_table) { } - printf("\ntotal items: %li/%li", target_hash_table->items, target_hash_table->table_size); - return target_hash_table -> items; - } \ No newline at end of file diff --git a/src/main.c b/src/main.c index 8c14a30..5e82e7c 100644 --- a/src/main.c +++ b/src/main.c @@ -1160,6 +1160,12 @@ cval *builtin_convert_string(cenv *e, cval *a) { return new; } +cval *builtin_object_id(cenv *e, cval *a) { + CASSERT_NUM("object_id", a, 1); + + return cval_number(a->cell[0]->objId); +} + cval *builtin_sys(cenv *e, cval *a) { CASSERT_TYPE("stats", a, 0, CVAL_STRING); CASSERT_NUM("stats", a, 1); @@ -1190,6 +1196,10 @@ cval *builtin_sys(cenv *e, cval *a) { return cval_number(SYSTEM_LANG); } + if (strcmp(cmd, "ALLOCATOR_STATUS") == 0) { + return allocator_status(); + } + return cval_fault("invalid input to stats"); } @@ -1217,6 +1227,7 @@ void cenv_add_builtins(cenv *e) { 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, "objId", builtin_object_id); cenv_add_builtin(e, "+", builtin_add); cenv_add_builtin(e, "-", builtin_sub); From 1967491b3c11ae8877714ba53c813733868665ec Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 20 Oct 2021 18:27:22 -0400 Subject: [PATCH 24/43] - adding cval sweeping --- src/allocator.c | 116 +++++++++++++++++++++++++++++++++++++++--------- src/allocator.h | 1 + src/main.c | 4 ++ 3 files changed, 101 insertions(+), 20 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index a110d6d..d724e11 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -16,8 +16,9 @@ typedef struct cval_allocation_array { typedef struct cval_allocation_index { cval_allocation_array **rows; int cur; + int scur; int size; - bool oom; + bool smode; } cval_allocation_index; cval_allocation_index *INDEX = NULL; @@ -65,10 +66,6 @@ cval_allocation_index *preallocateIndex(int rows, int slots) { index->size = rows; index->rows = malloc(sizeof(cval_allocation_array*) * ROWS_MAX); - if (OUT_OF_MEMORY_FAULT == NULL) { - OUT_OF_MEMORY_FAULT = cval_fault("You've run out of memory, and thush out of time my young friend."); - } - for (int i = 0; i < rows; ++i) { cval_allocation_array *array = preallocateArray(slots); if (array != NULL) { @@ -83,13 +80,40 @@ cval_allocation_index *preallocateIndex(int rows, int slots) { return index; } +cval *fetchSmode() { + if (INDEX->smode) { + int cur = 1; + + while (INDEX->scur < INDEX->cur) { + while (cur <= PREALLOCATE_SLOTS) { + cval* target = INDEX->rows[INDEX->scur]->array[cur]; + if (target->type == CVAL_UNALLOCATED) { + return target; + } + cur += 1; + } + + } + INDEX->scur += 1; + } + return NULL; +} + + cval **internalCacheFetch(int total) { cval **array = malloc(sizeof(cval *) * total); for (int i = 0; i < total; ++i) { - // allocate more slots when out of memory, returning out of memory fault - // on failure. + + cval* sModeResult = fetchSmode(); + + if (sModeResult != NULL) { + array[i] = sModeResult; + continue; + } + + if (sModeResult == NULL) { if (INDEX->rows[INDEX->cur]->allocated == INDEX->rows[INDEX->cur]->size) { if (INDEX->cur == INDEX->size) { if (INDEX->cur < ROWS_MAX) { @@ -107,15 +131,17 @@ cval **internalCacheFetch(int total) { array[i] = INDEX->rows[INDEX->cur]->array[INDEX->rows[INDEX->cur]->allocated]; INDEX->rows[INDEX->cur]->allocated += 1; } + } return array; } void allocator_setup() { if (!INIT_COMPLETE) { - INDEX = preallocateIndex(PREALLOCATE_ROWS, PREALLOCATE_SLOTS); - preCache = internalCacheFetch(PRE_CACHE_SIZE); - INIT_COMPLETE = true; + OUT_OF_MEMORY_FAULT = cval_fault("You've run out of memory, and thush out of time my young friend."); + INDEX = preallocateIndex(PREALLOCATE_ROWS, PREALLOCATE_SLOTS); + preCache = internalCacheFetch(PRE_CACHE_SIZE); + INIT_COMPLETE = true; } } @@ -144,19 +170,67 @@ cval **allocateMany(int total) { } void deallocate(cval* cval) { - switch (cval->type) { - case CVAL_NUMBER: - cval->num = 0; - break; - - case CVAL_FLOAT: - cval->fnum = 0; - break; + cval->type = CVAL_DELETED; +} + +int sweep() { + int curRow = 1; + int sweptObj = 0; + bool rowSet = false; + + while (curRow <= INDEX->size) { + cval_allocation_array* row = INDEX->rows[curRow - 1]; + + int curObject = 1; + while (curObject <= row->size) { + cval* object = row->array[curObject - 1]; + + if (object->type == CVAL_DELETED) { + object->num = 0; + object->fnum = 0; + object->boolean = false; + object->type = CVAL_UNALLOCATED; + row->allocated -= 1; + sweptObj += 1; + + if (!rowSet) { + INDEX->scur = curRow; + rowSet = true; + } + } + + curObject += 1; + } + curRow += 1; } - cval->type = CVAL_DELETED; + INDEX->smode = true; + return sweptObj; +} + +cval* mark_and_sweep() { + int sweptObj = sweep(); + + hash_table* ht = hash_table_create(100); + hash_table_set(ht, "PREALLOCATE_SLOTS", cval_number(PREALLOCATE_SLOTS)); + hash_table_set(ht, "PREALLOCATE_ROWS", cval_number(PREALLOCATE_ROWS)); + hash_table_set(ht, "ROWS_MAX", cval_number(ROWS_MAX)); + hash_table_set(ht, "MAX_OBJECT_ID", cval_number(MAX_OBJECT_ID)); + hash_table_set(ht, "PRE_CACHE_SIZE", cval_number(PRE_CACHE_SIZE)); + hash_table_set(ht, "CURRENT_ROW_ALLOCATED", cval_number(INDEX->rows[INDEX->cur]->allocated)); + hash_table_set(ht, "CURRNET_ROWS_SIZE", cval_number(INDEX->rows[INDEX->cur]->size)); + hash_table_set(ht, "INDEX_CURSOR", cval_number(INDEX->cur)); + hash_table_set(ht, "INDEX_SIZE", cval_number(INDEX->size)); + hash_table_set(ht, "NEXT_OBJECT_ID", cval_number(CUR_OBJ_ID)); + hash_table_set(ht, "SWEPT_OBJECTS", cval_number(sweptObj)); + hash_table_set(ht, "S_MODE", cval_boolean(INDEX->smode)); + hash_table_set(ht, "S_MODE_CURSOR", cval_number(INDEX->scur)); + + return cval_dictionary(ht); } + + cval *allocator_status() { if (INIT_COMPLETE) { hash_table* ht = hash_table_create(100); @@ -170,6 +244,8 @@ cval *allocator_status() { hash_table_set(ht, "INDEX_CURSOR", cval_number(INDEX->cur)); hash_table_set(ht, "INDEX_SIZE", cval_number(INDEX->size)); hash_table_set(ht, "NEXT_OBJECT_ID", cval_number(CUR_OBJ_ID)); + hash_table_set(ht, "S_MODE", cval_boolean(INDEX->smode)); + hash_table_set(ht, "S_MODE_CURSOR", cval_number(INDEX->scur)); return cval_dictionary(ht); } - return OUT_OF_MEMORY_FAULT; + return cval_fault("The allocator takesh a wee bit of time to warm up laddy."); } diff --git a/src/allocator.h b/src/allocator.h index 34bbb41..dbf2602 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -7,4 +7,5 @@ cval **allocateMany(int total); void deallocate(cval* cval); void allocator_setup(); cval *allocator_status(); +cval *mark_and_sweep(); #endif //CONNERY_ALLOCATOR_H diff --git a/src/main.c b/src/main.c index 5e82e7c..58ad7f7 100644 --- a/src/main.c +++ b/src/main.c @@ -1200,6 +1200,10 @@ cval *builtin_sys(cenv *e, cval *a) { return allocator_status(); } + if (strcmp(cmd, "TAKE_OUT_THE_TRASH") == 0) { + return mark_and_sweep(); + } + return cval_fault("invalid input to stats"); } From 9a369647adc032291626f5aa6e9aa92302f7a9ec Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 20 Oct 2021 18:41:46 -0400 Subject: [PATCH 25/43] - can recover blocks allocated and then deleted --- src/allocator.c | 10 ++++------ src/cval.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index d724e11..42601d2 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -88,13 +88,13 @@ cval *fetchSmode() { while (cur <= PREALLOCATE_SLOTS) { cval* target = INDEX->rows[INDEX->scur]->array[cur]; if (target->type == CVAL_UNALLOCATED) { + target->type = CVAL_REALLOCATED; return target; } cur += 1; } - - } INDEX->scur += 1; + } } return NULL; } @@ -107,13 +107,11 @@ cval **internalCacheFetch(int total) { for (int i = 0; i < total; ++i) { cval* sModeResult = fetchSmode(); - if (sModeResult != NULL) { array[i] = sModeResult; continue; } - if (sModeResult == NULL) { if (INDEX->rows[INDEX->cur]->allocated == INDEX->rows[INDEX->cur]->size) { if (INDEX->cur == INDEX->size) { if (INDEX->cur < ROWS_MAX) { @@ -129,8 +127,8 @@ cval **internalCacheFetch(int total) { } } array[i] = INDEX->rows[INDEX->cur]->array[INDEX->rows[INDEX->cur]->allocated]; - INDEX->rows[INDEX->cur]->allocated += 1; - } + array[i]->type = CVAL_REALLOCATED; + INDEX->rows[INDEX->cur]->allocated += 1; } return array; diff --git a/src/cval.h b/src/cval.h index 722ab6b..43a5492 100644 --- a/src/cval.h +++ b/src/cval.h @@ -13,7 +13,7 @@ typedef cval *(*cbuiltin)(cenv *, cval *); enum { CVAL_NUMBER, CVAL_FAULT, CVAL_SYMBOL, CVAL_FUNCTION, CVAL_S_EXPRESSION, CVAL_Q_EXPRESSION, CVAL_STRING, CVAL_FLOAT, - CVAL_BOOLEAN, CVAL_DICTIONARY, CVAL_NULL, CVAL_UNALLOCATED, CVAL_DELETED + CVAL_BOOLEAN, CVAL_DICTIONARY, CVAL_NULL, CVAL_UNALLOCATED, CVAL_DELETED, CVAL_REALLOCATED }; struct cval { From 705ab984eba43e91a1ded9478f9e7fb7a8da3eeb Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 20 Oct 2021 18:45:26 -0400 Subject: [PATCH 26/43] - added deleted cval recovery to end of standard library init sequence. Started with objId 24760 and now have 4148. Saved 20612 cvals for reuse. --- src/stdlib/main.connery | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stdlib/main.connery b/src/stdlib/main.connery index 5a98994..3e9e3be 100644 --- a/src/stdlib/main.connery +++ b/src/stdlib/main.connery @@ -14,4 +14,5 @@ (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)) \ No newline at end of file +(def {connery_system_lang} (system_lang_version_num CONNERY_SYSTEM_LANG_INT)) +(sys "TAKE_OUT_THE_TRASH") \ No newline at end of file From 3c1edafd92574a316206fd542fee181bee888dbf Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 20 Oct 2021 20:30:09 -0400 Subject: [PATCH 27/43] - cval allocator is working as expected. --- src/allocator.c | 70 ++++++++++++++++++++----------------------------- src/cval.h | 1 + 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 42601d2..b64d715 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -87,8 +87,8 @@ cval *fetchSmode() { while (INDEX->scur < INDEX->cur) { while (cur <= PREALLOCATE_SLOTS) { cval* target = INDEX->rows[INDEX->scur]->array[cur]; - if (target->type == CVAL_UNALLOCATED) { - target->type = CVAL_REALLOCATED; + if (target->type == CVAL_REALLOCATED) { + target->type = CVAL_UNALLOCATED; return target; } cur += 1; @@ -127,7 +127,7 @@ cval **internalCacheFetch(int total) { } } array[i] = INDEX->rows[INDEX->cur]->array[INDEX->rows[INDEX->cur]->allocated]; - array[i]->type = CVAL_REALLOCATED; + array[i]->type = CVAL_UNALLOCATED; INDEX->rows[INDEX->cur]->allocated += 1; } @@ -155,18 +155,6 @@ cval *allocate() { return val; } -cval **allocateMany(int total) { - cval** result = malloc(sizeof(cval*) * total); - int cur = 1; - - while (cur <= total) { - result[cur] = allocate(); - cur += 1; - } - - return result; -} - void deallocate(cval* cval) { cval->type = CVAL_DELETED; } @@ -187,7 +175,7 @@ int sweep() { object->num = 0; object->fnum = 0; object->boolean = false; - object->type = CVAL_UNALLOCATED; + object->type = CVAL_REALLOCATED; row->allocated -= 1; sweptObj += 1; @@ -206,44 +194,44 @@ int sweep() { return sweptObj; } -cval* mark_and_sweep() { - int sweptObj = sweep(); - +cval *allocatorStatus(int sweptObj){ hash_table* ht = hash_table_create(100); hash_table_set(ht, "PREALLOCATE_SLOTS", cval_number(PREALLOCATE_SLOTS)); hash_table_set(ht, "PREALLOCATE_ROWS", cval_number(PREALLOCATE_ROWS)); - hash_table_set(ht, "ROWS_MAX", cval_number(ROWS_MAX)); - hash_table_set(ht, "MAX_OBJECT_ID", cval_number(MAX_OBJECT_ID)); - hash_table_set(ht, "PRE_CACHE_SIZE", cval_number(PRE_CACHE_SIZE)); - hash_table_set(ht, "CURRENT_ROW_ALLOCATED", cval_number(INDEX->rows[INDEX->cur]->allocated)); - hash_table_set(ht, "CURRNET_ROWS_SIZE", cval_number(INDEX->rows[INDEX->cur]->size)); + hash_table_set(ht, "INDEX_ROWS_MAX", cval_number(ROWS_MAX)); + hash_table_set(ht, "INDEX_MAX_OBJECT_ID", cval_number(MAX_OBJECT_ID)); + hash_table_set(ht, "INDEX_PRE_CACHE_SIZE", cval_number(PRE_CACHE_SIZE)); + hash_table_set(ht, "ROW_ALLOCATED", cval_number(INDEX->rows[INDEX->cur]->allocated)); + hash_table_set(ht, "ROW_SIZE", cval_number(INDEX->rows[INDEX->cur]->size)); hash_table_set(ht, "INDEX_CURSOR", cval_number(INDEX->cur)); hash_table_set(ht, "INDEX_SIZE", cval_number(INDEX->size)); - hash_table_set(ht, "NEXT_OBJECT_ID", cval_number(CUR_OBJ_ID)); - hash_table_set(ht, "SWEPT_OBJECTS", cval_number(sweptObj)); + hash_table_set(ht, "INDEX_NEXT_OBJECT_ID", cval_number(CUR_OBJ_ID)); + + if (sweptObj != 0) { + hash_table_set(ht, "SWEPT_OBJECTS", cval_number(sweptObj)); } + hash_table_set(ht, "S_MODE", cval_boolean(INDEX->smode)); hash_table_set(ht, "S_MODE_CURSOR", cval_number(INDEX->scur)); - return cval_dictionary(ht); } +cval* mark_and_sweep() { + int sweptObj = 0; + + if (INIT_COMPLETE) { + sweptObj = sweep(); + } + + return allocatorStatus(sweptObj); +} + + cval *allocator_status() { if (INIT_COMPLETE) { - hash_table* ht = hash_table_create(100); - hash_table_set(ht, "PREALLOCATE_SLOTS", cval_number(PREALLOCATE_SLOTS)); - hash_table_set(ht, "PREALLOCATE_ROWS", cval_number(PREALLOCATE_ROWS)); - hash_table_set(ht, "ROWS_MAX", cval_number(ROWS_MAX)); - hash_table_set(ht, "MAX_OBJECT_ID", cval_number(MAX_OBJECT_ID)); - hash_table_set(ht, "PRE_CACHE_SIZE", cval_number(PRE_CACHE_SIZE)); - hash_table_set(ht, "CURRENT_ROW_ALLOCATED", cval_number(INDEX->rows[INDEX->cur]->allocated)); - hash_table_set(ht, "CURRNET_ROWS_SIZE", cval_number(INDEX->rows[INDEX->cur]->size)); - hash_table_set(ht, "INDEX_CURSOR", cval_number(INDEX->cur)); - hash_table_set(ht, "INDEX_SIZE", cval_number(INDEX->size)); - hash_table_set(ht, "NEXT_OBJECT_ID", cval_number(CUR_OBJ_ID)); - hash_table_set(ht, "S_MODE", cval_boolean(INDEX->smode)); - hash_table_set(ht, "S_MODE_CURSOR", cval_number(INDEX->scur)); - return cval_dictionary(ht); } + return allocatorStatus(0); + } return cval_fault("The allocator takesh a wee bit of time to warm up laddy."); } + diff --git a/src/cval.h b/src/cval.h index 43a5492..aff069f 100644 --- a/src/cval.h +++ b/src/cval.h @@ -35,6 +35,7 @@ struct cval { int count; int objId; cval **cell; + bool mark; }; struct cenv { From 4d2caefd073ca683cdf1a5e237a8461d9cc507c4 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Thu, 21 Oct 2021 19:45:30 -0400 Subject: [PATCH 28/43] - Basics of mark working --- src/allocator.c | 61 +++++++++++++++++++++++++++++++++++++++++++++---- src/allocator.h | 2 +- src/hashtable.c | 41 ++++++++++++++++++++++++++++++++- src/hashtable.h | 2 ++ src/main.c | 2 +- 5 files changed, 100 insertions(+), 8 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index b64d715..1dcdc4e 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -159,6 +159,52 @@ void deallocate(cval* cval) { cval->type = CVAL_DELETED; } +int markValue(cval* val) { + if (val != NULL) { + val->mark = true; + } +} + +int markDictionary(cval* dictionary) { + cval** dictContent = hash_table_dump_values(dictionary->ht); + int items = dictionary->ht->items; + int totalMarked = items; + int cur = 0; + + while (items <= cur + 1) { + cval* curValue = dictContent[cur]; + curValue->mark = true; + + if (curValue->type == CVAL_DICTIONARY) { + totalMarked += markDictionary(curValue); + } + + cur += 1; + } + + return totalMarked; +} + +int mark(cenv* env) { + cval** envContents = hash_table_dump_values(env->ht); + int size = env->ht->items; + int totalMarked = size; + int cur = 0; + + while (cur < size - 1) { + cval* curValue = envContents[cur]; + markValue(curValue); + + if (curValue->type == CVAL_DICTIONARY) { + totalMarked += markDictionary(curValue); + } + + cur += 1; + } + return totalMarked; +} + + int sweep() { int curRow = 1; int sweptObj = 0; @@ -194,7 +240,7 @@ int sweep() { return sweptObj; } -cval *allocatorStatus(int sweptObj){ +cval *allocatorStatus(int sweptObj, int markedObj){ hash_table* ht = hash_table_create(100); hash_table_set(ht, "PREALLOCATE_SLOTS", cval_number(PREALLOCATE_SLOTS)); hash_table_set(ht, "PREALLOCATE_ROWS", cval_number(PREALLOCATE_ROWS)); @@ -207,30 +253,35 @@ cval *allocatorStatus(int sweptObj){ hash_table_set(ht, "INDEX_SIZE", cval_number(INDEX->size)); hash_table_set(ht, "INDEX_NEXT_OBJECT_ID", cval_number(CUR_OBJ_ID)); - if (sweptObj != 0) { + if (sweptObj != -1) { hash_table_set(ht, "SWEPT_OBJECTS", cval_number(sweptObj)); } + if (markedObj != -1) { + hash_table_set(ht, "MARKED_OBJECTS", cval_number(markedObj)); } + hash_table_set(ht, "S_MODE", cval_boolean(INDEX->smode)); hash_table_set(ht, "S_MODE_CURSOR", cval_number(INDEX->scur)); return cval_dictionary(ht); } -cval* mark_and_sweep() { +cval* mark_and_sweep(cenv* env) { int sweptObj = 0; + int markedObj = 0; if (INIT_COMPLETE) { sweptObj = sweep(); + markedObj = mark(env); } - return allocatorStatus(sweptObj); + return allocatorStatus(sweptObj, markedObj); } cval *allocator_status() { if (INIT_COMPLETE) { - return allocatorStatus(0); + return allocatorStatus(-1, -1); } return cval_fault("The allocator takesh a wee bit of time to warm up laddy."); } diff --git a/src/allocator.h b/src/allocator.h index dbf2602..82cf4b0 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -7,5 +7,5 @@ cval **allocateMany(int total); void deallocate(cval* cval); void allocator_setup(); cval *allocator_status(); -cval *mark_and_sweep(); +cval* mark_and_sweep(cenv* env); #endif //CONNERY_ALLOCATOR_H diff --git a/src/hashtable.c b/src/hashtable.c index f6836ba..dda2fc1 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -35,6 +35,8 @@ hash_table_entry *hash_table_pair(const char *key, cval *value) { return entry; } + + void hash_table_set(hash_table *target_hash_table, const char *key, cval *value) { unsigned int slot = hash(key, target_hash_table->table_size); @@ -114,7 +116,7 @@ hash_table *hash_table_create(const long table_size) { ht->items = 0; for (int i = 0; i < table_size; ++i) { - ht->entries[i] = NULL; + ht->entries[i] = NULL; } return ht; @@ -218,6 +220,43 @@ hash_table *hash_table_copy(hash_table *target_hash_table) { return hash_table_copy_and_resize(target_hash_table, 0); } +cval **hash_table_dump_values(hash_table *target_hash_table) { + cval** array = malloc(sizeof(cval*) * target_hash_table->items); + int itemsFound = 0; + + for (long i = 0; i < target_hash_table->table_size; i++) { + + if (target_hash_table->entries[i] != NULL) { + itemsFound += 1; + array[itemsFound - 1] = target_hash_table->entries[i]->value; + + if (target_hash_table->entries[i]->next != NULL) { + hash_table_entry *entry = target_hash_table->entries[i]->next; + while (entry != NULL) { + itemsFound += 1; + array[itemsFound - 1] = entry->value; + entry = entry->next; + } + } + } + } + + return array; +} + +cval **hash_table_dump_keys(hash_table *target_hash_table) { + cval** array = malloc(sizeof(cval*) * target_hash_table->items); + int itemsFound = 0; + + for (long i = 0; i < target_hash_table->table_size; i++) { + + while (target_hash_table->entries[i] != NULL) { + itemsFound += 1; + array[itemsFound - 1] = cval_string(target_hash_table->entries[i]->key); + } + } +} + int hash_table_print(hash_table *target_hash_table) { int first_row = 1; diff --git a/src/hashtable.h b/src/hashtable.h index 423bbfd..52bd1cf 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -31,4 +31,6 @@ void hash_table_entry_delete(hash_table *target_hash_table, const char *key); int hash_table_print(hash_table *target_hash_table); +cval **hash_table_dump_values(hash_table *target_hash_table); + #endif //CONNERY_HASHTABLE_H diff --git a/src/main.c b/src/main.c index 58ad7f7..61f1073 100644 --- a/src/main.c +++ b/src/main.c @@ -1201,7 +1201,7 @@ cval *builtin_sys(cenv *e, cval *a) { } if (strcmp(cmd, "TAKE_OUT_THE_TRASH") == 0) { - return mark_and_sweep(); + return mark_and_sweep(e); } return cval_fault("invalid input to stats"); From da90d860655ac12bc2f289e601b79b93deabed52 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Fri, 22 Oct 2021 18:02:28 -0400 Subject: [PATCH 29/43] - Further work into mark --- src/allocator.c | 50 +++++++++++++++++++++++++++++-------------------- src/cval.c | 3 +++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 1dcdc4e..e39eb55 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -51,6 +51,7 @@ cval_allocation_array *preallocateArray(int slots) { cval *nullConst = malloc(sizeof(cval)); nullConst->type = CVAL_UNALLOCATED; nullConst->objId = objId; + nullConst->cell = NULL; array[i] = nullConst; } else { return NULL; @@ -101,7 +102,6 @@ cval *fetchSmode() { cval **internalCacheFetch(int total) { - cval **array = malloc(sizeof(cval *) * total); for (int i = 0; i < total; ++i) { @@ -159,11 +159,7 @@ void deallocate(cval* cval) { cval->type = CVAL_DELETED; } -int markValue(cval* val) { - if (val != NULL) { - val->mark = true; - } -} +long markValue(cval* val); int markDictionary(cval* dictionary) { cval** dictContent = hash_table_dump_values(dictionary->ht); @@ -171,9 +167,9 @@ int markDictionary(cval* dictionary) { int totalMarked = items; int cur = 0; - while (items <= cur + 1) { + while (cur + 1 <= items) { cval* curValue = dictContent[cur]; - curValue->mark = true; + markValue(curValue); if (curValue->type == CVAL_DICTIONARY) { totalMarked += markDictionary(curValue); @@ -184,21 +180,33 @@ int markDictionary(cval* dictionary) { return totalMarked; } +long markValue(cval* val) { + long marked = 0; + if (val != NULL) { + for (int i = 0; i < val->count; i++) { + marked = markValue(val->cell[i]); + } + + if (val->type == CVAL_DICTIONARY) { + marked = markDictionary(val); + } + + marked += 1; + val->mark = true; + } + + return marked; +} -int mark(cenv* env) { +long mark(cenv* env) { cval** envContents = hash_table_dump_values(env->ht); - int size = env->ht->items; - int totalMarked = size; + long size = env->ht->items; + long totalMarked = 0; int cur = 0; while (cur < size - 1) { cval* curValue = envContents[cur]; - markValue(curValue); - - if (curValue->type == CVAL_DICTIONARY) { - totalMarked += markDictionary(curValue); - } - + totalMarked += markValue(curValue); cur += 1; } return totalMarked; @@ -217,11 +225,13 @@ int sweep() { while (curObject <= row->size) { cval* object = row->array[curObject - 1]; - if (object->type == CVAL_DELETED) { + if (object->type == CVAL_DELETED || !object->mark) { object->num = 0; object->fnum = 0; object->boolean = false; object->type = CVAL_REALLOCATED; + object->cell = NULL; + object->count = 0; row->allocated -= 1; sweptObj += 1; @@ -230,7 +240,7 @@ int sweep() { rowSet = true; } } - + object->mark = false; curObject += 1; } curRow += 1; @@ -270,8 +280,8 @@ cval* mark_and_sweep(cenv* env) { int markedObj = 0; if (INIT_COMPLETE) { - sweptObj = sweep(); markedObj = mark(env); + sweptObj = sweep(); } return allocatorStatus(sweptObj, markedObj); diff --git a/src/cval.c b/src/cval.c index 64a7eb3..0c5824e 100644 --- a/src/cval.c +++ b/src/cval.c @@ -51,6 +51,9 @@ char* ctype_name(int t) { case CVAL_BOOLEAN: return "Boolean"; case CVAL_DICTIONARY: return "Dictionary"; case CVAL_NULL: return "Null"; + case CVAL_UNALLOCATED: return "UNALLOCATED"; + case CVAL_REALLOCATED: return "REALLOCATED"; + case CVAL_DELETED: return "DELETED"; default: return "Unknown Type"; } } From 3c6efa699caed32ef9aec2cd6a2f255cbc15a2e7 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Fri, 22 Oct 2021 18:09:08 -0400 Subject: [PATCH 30/43] - A little closer --- src/allocator.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/allocator.c b/src/allocator.c index e39eb55..a97ec78 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -187,6 +187,14 @@ long markValue(cval* val) { marked = markValue(val->cell[i]); } + if (val->formals != NULL) { + markValue(val->formals); + } + + if (val->body != NULL) { + markValue(val->body); + } + if (val->type == CVAL_DICTIONARY) { marked = markDictionary(val); } @@ -212,7 +220,6 @@ long mark(cenv* env) { return totalMarked; } - int sweep() { int curRow = 1; int sweptObj = 0; @@ -232,6 +239,8 @@ int sweep() { object->type = CVAL_REALLOCATED; object->cell = NULL; object->count = 0; + object->formals = NULL; + object->body = NULL; row->allocated -= 1; sweptObj += 1; From 3f7f5d1833aa0661ba89c1d8955fabf0156c0a5a Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 25 Oct 2021 17:45:22 -0400 Subject: [PATCH 31/43] - Attempting to locate fault with garbage collector, missing something... --- dev-notes.txt | 2 ++ src/allocator.c | 59 ++++++++++++++++++++++++++----------------------- src/cval.c | 2 +- 3 files changed, 34 insertions(+), 29 deletions(-) create mode 100644 dev-notes.txt diff --git a/dev-notes.txt b/dev-notes.txt new file mode 100644 index 0000000..eb89934 --- /dev/null +++ b/dev-notes.txt @@ -0,0 +1,2 @@ +Connery to replicate garbage collector fault: +if (== 1 (type "test")) {True} {False} \ No newline at end of file diff --git a/src/allocator.c b/src/allocator.c index a97ec78..faf5ad5 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -52,6 +52,8 @@ cval_allocation_array *preallocateArray(int slots) { nullConst->type = CVAL_UNALLOCATED; nullConst->objId = objId; nullConst->cell = NULL; + nullConst->formals = NULL; + nullConst->body = NULL; array[i] = nullConst; } else { return NULL; @@ -170,53 +172,52 @@ int markDictionary(cval* dictionary) { while (cur + 1 <= items) { cval* curValue = dictContent[cur]; markValue(curValue); - - if (curValue->type == CVAL_DICTIONARY) { - totalMarked += markDictionary(curValue); - } - cur += 1; } return totalMarked; } + +long markEnv(cenv* env); + long markValue(cval* val) { long marked = 0; if (val != NULL) { - for (int i = 0; i < val->count; i++) { - marked = markValue(val->cell[i]); - } + val->mark = true; + marked += 1; - if (val->formals != NULL) { - markValue(val->formals); + for (int i = 0; i < val->count; i++) { + marked += markValue(val->cell[i]); } - if (val->body != NULL) { - markValue(val->body); - } + marked += markValue(val->formals); + marked += markValue(val->body); if (val->type == CVAL_DICTIONARY) { - marked = markDictionary(val); + marked += markDictionary(val); } - - marked += 1; - val->mark = true; } return marked; } -long mark(cenv* env) { - cval** envContents = hash_table_dump_values(env->ht); - long size = env->ht->items; +long markEnv(cenv* env) { + cenv* curEnv = env; long totalMarked = 0; - int cur = 0; + + while (curEnv != NULL) { + cval** envContents = hash_table_dump_values(curEnv->ht); + long size = curEnv->ht->items; + int cur = 0; while (cur < size - 1) { - cval* curValue = envContents[cur]; - totalMarked += markValue(curValue); + totalMarked += markValue(envContents[cur]); cur += 1; } + + curEnv = curEnv->par; + } + return totalMarked; } @@ -232,7 +233,7 @@ int sweep() { while (curObject <= row->size) { cval* object = row->array[curObject - 1]; - if (object->type == CVAL_DELETED || !object->mark) { + if (object->type == CVAL_DELETED || (!object->mark && object->type != CVAL_UNALLOCATED && object->type != CVAL_REALLOCATED)) { object->num = 0; object->fnum = 0; object->boolean = false; @@ -241,6 +242,7 @@ int sweep() { object->count = 0; object->formals = NULL; object->body = NULL; + object->sym = NULL; row->allocated -= 1; sweptObj += 1; @@ -259,7 +261,7 @@ int sweep() { return sweptObj; } -cval *allocatorStatus(int sweptObj, int markedObj){ +cval *allocatorStatus(long sweptObj, long markedObj){ hash_table* ht = hash_table_create(100); hash_table_set(ht, "PREALLOCATE_SLOTS", cval_number(PREALLOCATE_SLOTS)); hash_table_set(ht, "PREALLOCATE_ROWS", cval_number(PREALLOCATE_ROWS)); @@ -285,14 +287,15 @@ cval *allocatorStatus(int sweptObj, int markedObj){ cval* mark_and_sweep(cenv* env) { - int sweptObj = 0; - int markedObj = 0; + long sweptObj = 0; + long markedObj = 0; if (INIT_COMPLETE) { - markedObj = mark(env); + markedObj = markEnv(env); sweptObj = sweep(); } + preCache = internalCacheFetch(PRE_CACHE_SIZE); return allocatorStatus(sweptObj, markedObj); } diff --git a/src/cval.c b/src/cval.c index 0c5824e..073a499 100644 --- a/src/cval.c +++ b/src/cval.c @@ -11,7 +11,7 @@ // todo: add garbage collector for dictionaries -#define ENV_HASH_TABLE_SIZE 1000 +#define ENV_HASH_TABLE_SIZE 100 #define DICTIONARY_LITERAL_INSTANTIATED_HASH_TABLE_MINIMUM 125 #define SYSTEM_LANG 1 From 634d3c6f855cf632ccfd6cfe133ccc31797c2715 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 25 Oct 2021 21:48:09 -0400 Subject: [PATCH 32/43] - Allocator and garbage collector improvements, weird behavior around immortal objects, hardcoded them into the mark sequence for now --- dev-notes.txt | 2 -- src/allocator.c | 8 +++++++- src/cval.c | 4 +--- src/cval.h | 4 ++++ src/hashtable.c | 4 ++-- 5 files changed, 14 insertions(+), 8 deletions(-) delete mode 100644 dev-notes.txt diff --git a/dev-notes.txt b/dev-notes.txt deleted file mode 100644 index eb89934..0000000 --- a/dev-notes.txt +++ /dev/null @@ -1,2 +0,0 @@ -Connery to replicate garbage collector fault: -if (== 1 (type "test")) {True} {False} \ No newline at end of file diff --git a/src/allocator.c b/src/allocator.c index faf5ad5..f58b71d 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -90,10 +90,11 @@ cval *fetchSmode() { while (INDEX->scur < INDEX->cur) { while (cur <= PREALLOCATE_SLOTS) { cval* target = INDEX->rows[INDEX->scur]->array[cur]; + if (target != NULL) { if (target->type == CVAL_REALLOCATED) { target->type = CVAL_UNALLOCATED; return target; - } + }} cur += 1; } INDEX->scur += 1; @@ -292,6 +293,11 @@ cval* mark_and_sweep(cenv* env) { if (INIT_COMPLETE) { markedObj = markEnv(env); + + NULL_CVAL_CONSTANT->mark = true; + TRUE_CVAL_CONSTANT->mark = true; + FALSE_CVAL_CONSTANT->mark = true; + sweptObj = sweep(); } diff --git a/src/cval.c b/src/cval.c index 073a499..49fd286 100644 --- a/src/cval.c +++ b/src/cval.c @@ -9,8 +9,6 @@ #include #include -// todo: add garbage collector for dictionaries - #define ENV_HASH_TABLE_SIZE 100 #define DICTIONARY_LITERAL_INSTANTIATED_HASH_TABLE_MINIMUM 125 #define SYSTEM_LANG 1 @@ -135,7 +133,7 @@ cval* cval_string (char* s) { cval* cval_fault(char* fmt, ...) { // allows faults to be thrown during // allocator problems - cval* value = malloc(sizeof(cenv)); + cval* value = malloc(sizeof(cval*)); value->type = CVAL_FAULT; va_list va; va_start(va, fmt); diff --git a/src/cval.h b/src/cval.h index aff069f..06902bc 100644 --- a/src/cval.h +++ b/src/cval.h @@ -125,5 +125,9 @@ cval *builtin_eval(cenv *e, cval *a); cval *builtin_list(cenv *e, cval *a); +cval* NULL_CVAL_CONSTANT; +cval* TRUE_CVAL_CONSTANT; +cval* FALSE_CVAL_CONSTANT; + #endif //CONNERY_CVAL_H diff --git a/src/hashtable.c b/src/hashtable.c index dda2fc1..d0d7771 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -202,12 +202,12 @@ hash_table *hash_table_copy_and_resize(hash_table *target_hash_table, long newSi for (long i = 0; i < target_hash_table->table_size; i++) { if (target_hash_table->entries[i] != NULL) { - hash_table_set(new_hash_table, target_hash_table->entries[i]->key, target_hash_table->entries[i]->value); + hash_table_set(new_hash_table, target_hash_table->entries[i]->key, cval_copy(target_hash_table->entries[i]->value)); hash_table_entry* prev = target_hash_table->entries[i]->next; while (prev != NULL) { - hash_table_set(new_hash_table, prev->key, prev->value); + hash_table_set(new_hash_table, prev->key, cval_copy(prev->value)); prev = prev->next; } } From f7325f4a0eb250c4d1ccb402424d84364cd3c460 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 25 Oct 2021 22:00:32 -0400 Subject: [PATCH 33/43] - remove travis.yml --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8884bbb..0000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: c - -services: - - docker - -script: - - docker build --tag connerylang . \ No newline at end of file From 7863cf48c45b2c8d424968027e7f588a637e5fb0 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 25 Oct 2021 22:16:30 -0400 Subject: [PATCH 34/43] - prepare for release --- src/allocator.c | 2 +- src/main.c | 5 +++-- src/stdlib/main.connery | 3 +-- src/stdlib/versions.connery | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index f58b71d..2c02f58 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -289,7 +289,7 @@ cval *allocatorStatus(long sweptObj, long markedObj){ cval* mark_and_sweep(cenv* env) { long sweptObj = 0; - long markedObj = 0; + long markedObj = 3; if (INIT_COMPLETE) { markedObj = markEnv(env); diff --git a/src/main.c b/src/main.c index 61f1073..e743851 100644 --- a/src/main.c +++ b/src/main.c @@ -11,8 +11,8 @@ #include "strings.h" #define SYSTEM_LANG 0 -#define CONNERY_VERSION "0.0.2" -#define CONNERY_VER_INT 2 +#define CONNERY_VERSION "0.0.3" +#define CONNERY_VER_INT 3 #define LOG_LEVEL 4 #define TRACE_ENABLED 0 #define STD_LIB_LOCATION "stdlib/main.connery" @@ -1320,6 +1320,7 @@ int main(int argc, char **argv) { cenv_add_builtins(e); load_standard_lib(e); + mark_and_sweep(e); puts(" ______ \n" " / ____/___ ____ ____ ___ _______ __\n" diff --git a/src/stdlib/main.connery b/src/stdlib/main.connery index 3e9e3be..5a98994 100644 --- a/src/stdlib/main.connery +++ b/src/stdlib/main.connery @@ -14,5 +14,4 @@ (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)) -(sys "TAKE_OUT_THE_TRASH") \ No newline at end of file +(def {connery_system_lang} (system_lang_version_num CONNERY_SYSTEM_LANG_INT)) \ No newline at end of file diff --git a/src/stdlib/versions.connery b/src/stdlib/versions.connery index 2ac051f..052ef31 100644 --- a/src/stdlib/versions.connery +++ b/src/stdlib/versions.connery @@ -3,6 +3,7 @@ {(== i 0) "Connery - Unspecified Version"} {(== i 1) "Connery - 0.0.1 - The Legend Begins"} {(== i 2) "Connery - 0.0.2"} + {(== i 3) "Connery - 0.0.3 - From America with Love"} {(== i 9999) "Connery - Future Version"} {Otherwise (error "Connery version is undefined.")} }) From bdff70878f9f8e716f92961e390b00e8a88b291d Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 25 Oct 2021 22:54:07 -0400 Subject: [PATCH 35/43] - added softer delete --- src/allocator.c | 5 +++-- src/cval.c | 1 - src/cval.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 2c02f58..2129d07 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -159,7 +159,7 @@ cval *allocate() { } void deallocate(cval* cval) { - cval->type = CVAL_DELETED; + cval->deleted = true; } long markValue(cval* val); @@ -234,7 +234,7 @@ int sweep() { while (curObject <= row->size) { cval* object = row->array[curObject - 1]; - if (object->type == CVAL_DELETED || (!object->mark && object->type != CVAL_UNALLOCATED && object->type != CVAL_REALLOCATED)) { + if (object->deleted || (!object->mark && object->type != CVAL_UNALLOCATED && object->type != CVAL_REALLOCATED)) { object->num = 0; object->fnum = 0; object->boolean = false; @@ -244,6 +244,7 @@ int sweep() { object->formals = NULL; object->body = NULL; object->sym = NULL; + object->deleted = false; row->allocated -= 1; sweptObj += 1; diff --git a/src/cval.c b/src/cval.c index 49fd286..86ff554 100644 --- a/src/cval.c +++ b/src/cval.c @@ -51,7 +51,6 @@ char* ctype_name(int t) { case CVAL_NULL: return "Null"; case CVAL_UNALLOCATED: return "UNALLOCATED"; case CVAL_REALLOCATED: return "REALLOCATED"; - case CVAL_DELETED: return "DELETED"; default: return "Unknown Type"; } } diff --git a/src/cval.h b/src/cval.h index 06902bc..43a9e1f 100644 --- a/src/cval.h +++ b/src/cval.h @@ -13,7 +13,7 @@ typedef cval *(*cbuiltin)(cenv *, cval *); enum { CVAL_NUMBER, CVAL_FAULT, CVAL_SYMBOL, CVAL_FUNCTION, CVAL_S_EXPRESSION, CVAL_Q_EXPRESSION, CVAL_STRING, CVAL_FLOAT, - CVAL_BOOLEAN, CVAL_DICTIONARY, CVAL_NULL, CVAL_UNALLOCATED, CVAL_DELETED, CVAL_REALLOCATED + CVAL_BOOLEAN, CVAL_DICTIONARY, CVAL_NULL, CVAL_UNALLOCATED, CVAL_REALLOCATED }; struct cval { @@ -36,6 +36,7 @@ struct cval { int objId; cval **cell; bool mark; + bool deleted; }; struct cenv { From 1ffa8040b1f25b5459d1a1ec7fda34d921c51205 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 25 Oct 2021 23:16:27 -0400 Subject: [PATCH 36/43] - delete improvements, bugfixes --- src/allocator.c | 38 +++++++++++++++++++++++++++++--------- src/cval.c | 31 ++++--------------------------- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 2129d07..1526ceb 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -139,7 +139,9 @@ cval **internalCacheFetch(int total) { void allocator_setup() { if (!INIT_COMPLETE) { - OUT_OF_MEMORY_FAULT = cval_fault("You've run out of memory, and thush out of time my young friend."); + OUT_OF_MEMORY_FAULT = malloc(sizeof(cval)); + OUT_OF_MEMORY_FAULT->type = CVAL_FAULT; + OUT_OF_MEMORY_FAULT->err = "You've run out of memory, and thush out of time my young friend."; INDEX = preallocateIndex(PREALLOCATE_ROWS, PREALLOCATE_SLOTS); preCache = internalCacheFetch(PRE_CACHE_SIZE); INIT_COMPLETE = true; @@ -235,15 +237,33 @@ int sweep() { cval* object = row->array[curObject - 1]; if (object->deleted || (!object->mark && object->type != CVAL_UNALLOCATED && object->type != CVAL_REALLOCATED)) { - object->num = 0; - object->fnum = 0; - object->boolean = false; + + switch (object->type) { + case CVAL_NUMBER: + object->num = 0; + break; + + case CVAL_BOOLEAN: + object->boolean = false; + break; + + case CVAL_FLOAT: + object->fnum = 0.0; + break; + + case CVAL_SYMBOL: + free(object->sym); + break; + + case CVAL_FAULT: + free(object->err); + break; + + case CVAL_STRING: + free(object->str); + break; + } object->type = CVAL_REALLOCATED; - object->cell = NULL; - object->count = 0; - object->formals = NULL; - object->body = NULL; - object->sym = NULL; object->deleted = false; row->allocated -= 1; sweptObj += 1; diff --git a/src/cval.c b/src/cval.c index 86ff554..8a33e7d 100644 --- a/src/cval.c +++ b/src/cval.c @@ -130,9 +130,7 @@ cval* cval_string (char* s) { } cval* cval_fault(char* fmt, ...) { - // allows faults to be thrown during - // allocator problems - cval* value = malloc(sizeof(cval*)); + cval* value = allocate(); value->type = CVAL_FAULT; va_list va; va_start(va, fmt); @@ -200,10 +198,9 @@ void cval_delete(cval* value) { bool immortal = false; switch(value->type) { - case CVAL_NUMBER: - case CVAL_FLOAT: + case CVAL_NULL: + case CVAL_BOOLEAN: immortal = true; - deallocate(value); break; case CVAL_FUNCTION: @@ -214,14 +211,6 @@ void cval_delete(cval* value) { } break; - case CVAL_FAULT: - free(value->err); - break; - - case CVAL_SYMBOL: - free(value->sym); - break; - case CVAL_Q_EXPRESSION: case CVAL_S_EXPRESSION: for (int i = 0; i < value->count; i++) { @@ -229,18 +218,6 @@ void cval_delete(cval* value) { } free(value->cell); break; - - case CVAL_STRING: - immortal = true; - free(value->str); - deallocate(value); - break; - - case CVAL_NULL: - case CVAL_BOOLEAN: - immortal = true; - break; - } if (!immortal) { @@ -373,7 +350,7 @@ cval* cval_call(cenv* e, cval* f, cval* a) { if(f->formals->count == 0) { cval_delete(a); - return cval_fault("Function pashed too many argumentsh. Got %i, Expected %s", given, total); + return cval_fault("Function pashed too many argumentsh. Got %i, Expected %i", given, total); } cval* sym = cval_pop(f->formals, 0); From c16545e4d5b1e3f9e60d22328441932aea2e8947 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Mon, 25 Oct 2021 23:34:09 -0400 Subject: [PATCH 37/43] - more bugfixes --- src/allocator.c | 2 ++ src/allocator.h | 1 + src/hashtable.c | 8 ++++---- src/main.c | 7 ++++++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 1526ceb..8f111f0 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -25,6 +25,7 @@ cval_allocation_index *INDEX = NULL; int CUR_OBJ_ID = 0; int CUR_PRE_CACHE_POS = 0; bool INIT_COMPLETE = false; +bool ALLOCATOR_MEMORY_PRESSURE = false; cval *OUT_OF_MEMORY_FAULT = NULL; cval **preCache = NULL; @@ -121,6 +122,7 @@ cval **internalCacheFetch(int total) { INDEX->cur += 1; INDEX->size += 1; INDEX->rows[INDEX->cur] = preallocateArray(PREALLOCATE_SLOTS); + ALLOCATOR_MEMORY_PRESSURE = true; } else { array[i] = OUT_OF_MEMORY_FAULT; return array; diff --git a/src/allocator.h b/src/allocator.h index 82cf4b0..7919508 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -8,4 +8,5 @@ void deallocate(cval* cval); void allocator_setup(); cval *allocator_status(); cval* mark_and_sweep(cenv* env); +bool ALLOCATOR_MEMORY_PRESSURE; #endif //CONNERY_ALLOCATOR_H diff --git a/src/hashtable.c b/src/hashtable.c index d0d7771..7f49758 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -2,6 +2,7 @@ #include #include "cval.h" #include "hashtable.h" +#include "allocator.h" #define HASH_TABLE_RESIZE_DEPTH 3 #define HASH_TABLE_RESIZE_MULTIPLIER 2 @@ -28,7 +29,7 @@ hash_table_entry *hash_table_pair(const char *key, cval *value) { strcpy(entry->key, key); - entry->value = malloc(sizeof(cval)); + entry->value = allocate(); entry->value = cval_copy(value); entry->next = NULL; @@ -55,8 +56,8 @@ void hash_table_set(hash_table *target_hash_table, const char *key, cval *value) while (entry != NULL) { if (strcmp(entry->key, key) == 0) { - free(entry->value); - entry->value = malloc(sizeof(cval)); + (entry->value); + entry->value = allocate(); entry->value = cval_copy(value); return; } @@ -155,7 +156,6 @@ void hash_table_entry_delete(hash_table *target_hash_table, const char *key) { free(entry->key); cval_delete(entry->value); - free(entry); target_hash_table->items -= 1; return; diff --git a/src/main.c b/src/main.c index e743851..669e933 100644 --- a/src/main.c +++ b/src/main.c @@ -675,7 +675,7 @@ cval *builtin_for(cenv *e, cval *a) { } cval *cval_lambda(cval *formals, cval *body) { - cval *v = malloc(sizeof(cval)); + cval *v = allocate(); v->type = CVAL_FUNCTION; v->builtin = NULL; @@ -1363,6 +1363,11 @@ int main(int argc, char **argv) { mpc_err_delete(result.error); } free(input); + + if (ALLOCATOR_MEMORY_PRESSURE) { + mark_and_sweep(e); + ALLOCATOR_MEMORY_PRESSURE = false; + } } } From 8f3f325d537521f726556cbac3190fd62f1d6d4c Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Tue, 26 Oct 2021 19:14:04 -0400 Subject: [PATCH 38/43] - Valgrind fixes --- src/allocator.c | 4 ++-- src/cval.c | 9 ++++++--- src/cval.h | 2 +- src/hashtable.c | 1 - src/main.c | 5 ----- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 8f111f0..77e34c0 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -42,7 +42,7 @@ int createObjectId() { cval_allocation_array *preallocateArray(int slots) { cval_allocation_array *array_struct = malloc(sizeof(cval_allocation_array)); - cval **array = malloc(sizeof(cval *) * slots); + cval **array = malloc(sizeof(cval*) * slots); array_struct->size = slots; array_struct->allocated = 0; @@ -106,7 +106,7 @@ cval *fetchSmode() { cval **internalCacheFetch(int total) { - cval **array = malloc(sizeof(cval *) * total); + cval **array = malloc(sizeof(cval) * total); for (int i = 0; i < total; ++i) { diff --git a/src/cval.c b/src/cval.c index 8a33e7d..e69c64f 100644 --- a/src/cval.c +++ b/src/cval.c @@ -183,7 +183,7 @@ cval* cval_null() { } cenv* cenv_new(void) { - cenv* e = malloc(sizeof(cenv*)); + cenv* e = malloc(sizeof(cenv)); e->par = NULL; e->ht = hash_table_create(ENV_HASH_TABLE_SIZE); return e; @@ -516,8 +516,11 @@ cval* cval_join(cval* x, cval* y) { x = cval_add(x, y->cell[i]); } - free(y->cell); - free(y); + for (int i = 0; i < y->count; i++) { + deallocate(y->cell[i]); + } + + deallocate(y); return x; } diff --git a/src/cval.h b/src/cval.h index 43a9e1f..5b87b11 100644 --- a/src/cval.h +++ b/src/cval.h @@ -33,7 +33,7 @@ struct cval { cval *body; int count; - int objId; + long objId; cval **cell; bool mark; bool deleted; diff --git a/src/hashtable.c b/src/hashtable.c index 7f49758..6ea61ed 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -29,7 +29,6 @@ hash_table_entry *hash_table_pair(const char *key, cval *value) { strcpy(entry->key, key); - entry->value = allocate(); entry->value = cval_copy(value); entry->next = NULL; diff --git a/src/main.c b/src/main.c index 669e933..99d177b 100644 --- a/src/main.c +++ b/src/main.c @@ -1363,11 +1363,6 @@ int main(int argc, char **argv) { mpc_err_delete(result.error); } free(input); - - if (ALLOCATOR_MEMORY_PRESSURE) { - mark_and_sweep(e); - ALLOCATOR_MEMORY_PRESSURE = false; - } } } From f00906b9c75caf046d9e86e10d55b53ec0dec98d Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 27 Oct 2021 19:05:37 -0400 Subject: [PATCH 39/43] - added inspect builtin to allow for easier debugging --- src/allocator.c | 33 ++++++++++++++++++++----- src/allocator.h | 3 +++ src/hashtable.c | 5 ++-- src/main.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 94 insertions(+), 13 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 77e34c0..58f0126 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -21,6 +21,20 @@ typedef struct cval_allocation_index { bool smode; } cval_allocation_index; +long get_row_by_id(long id) { + long row = 1; + + while ((row * PREALLOCATE_SLOTS) < id) { + row += 1; + } + + return row; +} + +long get_index_by_row_and_id(long id, long row) { + return (id - ((row - 1) * PREALLOCATE_SLOTS)); +} + cval_allocation_index *INDEX = NULL; int CUR_OBJ_ID = 0; int CUR_PRE_CACHE_POS = 0; @@ -42,7 +56,7 @@ int createObjectId() { cval_allocation_array *preallocateArray(int slots) { cval_allocation_array *array_struct = malloc(sizeof(cval_allocation_array)); - cval **array = malloc(sizeof(cval*) * slots); + cval **array = calloc(sizeof(cval*), slots); array_struct->size = slots; array_struct->allocated = 0; @@ -65,10 +79,10 @@ cval_allocation_array *preallocateArray(int slots) { } cval_allocation_index *preallocateIndex(int rows, int slots) { - cval_allocation_index *index = malloc(sizeof(cval_allocation_index)); + cval_allocation_index *index = malloc(sizeof(cval_allocation_index*)); index->cur = 0; index->size = rows; - index->rows = malloc(sizeof(cval_allocation_array*) * ROWS_MAX); + index->rows = calloc(sizeof(cval_allocation_array*), ROWS_MAX); for (int i = 0; i < rows; ++i) { cval_allocation_array *array = preallocateArray(slots); @@ -106,7 +120,7 @@ cval *fetchSmode() { cval **internalCacheFetch(int total) { - cval **array = malloc(sizeof(cval) * total); + cval **array = calloc(sizeof(cval*), total); for (int i = 0; i < total; ++i) { @@ -195,8 +209,10 @@ long markValue(cval* val) { marked += markValue(val->cell[i]); } - marked += markValue(val->formals); - marked += markValue(val->body); + if (val->type == CVAL_S_EXPRESSION || val->type == CVAL_Q_EXPRESSION) { + marked += markValue(val->formals); + marked += markValue(val->body); + } if (val->type == CVAL_DICTIONARY) { marked += markDictionary(val); @@ -337,3 +353,8 @@ cval *allocator_status() { return cval_fault("The allocator takesh a wee bit of time to warm up laddy."); } +cval *object_by_id(long id) { + long row = get_row_by_id(id); + return INDEX->rows[row]->array[get_index_by_row_and_id(id, row)]; +} + diff --git a/src/allocator.h b/src/allocator.h index 7919508..ffadd8b 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -8,5 +8,8 @@ void deallocate(cval* cval); void allocator_setup(); cval *allocator_status(); cval* mark_and_sweep(cenv* env); +long get_row_by_id(long id); +long get_index_by_row_and_id(long id, long row); +cval *object_by_id(long id); bool ALLOCATOR_MEMORY_PRESSURE; #endif //CONNERY_ALLOCATOR_H diff --git a/src/hashtable.c b/src/hashtable.c index 6ea61ed..a67ff42 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -8,7 +8,6 @@ #define HASH_TABLE_RESIZE_MULTIPLIER 2 #define HASH_TABLE_RESIZE_BONUS 100 - unsigned int hash(const char *key, const long table_size) { unsigned long int value = 0; unsigned int key_len = strlen(key); @@ -112,7 +111,7 @@ hash_table *hash_table_create(const long table_size) { hash_table *ht = malloc(sizeof(hash_table) * 1); ht->table_size = table_size; - ht->entries = malloc(sizeof(hash_table_entry *) * table_size); + ht->entries = calloc(sizeof(hash_table_entry *), table_size); ht->items = 0; for (int i = 0; i < table_size; ++i) { @@ -220,7 +219,7 @@ hash_table *hash_table_copy(hash_table *target_hash_table) { } cval **hash_table_dump_values(hash_table *target_hash_table) { - cval** array = malloc(sizeof(cval*) * target_hash_table->items); + cval** array = calloc(sizeof(cval*),target_hash_table->items); int itemsFound = 0; for (long i = 0; i < target_hash_table->table_size; i++) { diff --git a/src/main.c b/src/main.c index 99d177b..f425732 100644 --- a/src/main.c +++ b/src/main.c @@ -1160,10 +1160,68 @@ cval *builtin_convert_string(cenv *e, cval *a) { return new; } -cval *builtin_object_id(cenv *e, cval *a) { - CASSERT_NUM("object_id", a, 1); +cval *builtin_inspect(cenv *e, cval *a) { + CASSERT_NUM("inspect", a, 1); + cval * value = a; + cval* container_data = NULL; + cval* env_data = NULL; + cval* allocator_data = NULL; + hash_table* ht = hash_table_create(15); + hash_table* env_ht = hash_table_create(10); + hash_table* allocator_ht = hash_table_create(2); + + if (a->type == CVAL_S_EXPRESSION) { + if (a->count > 0) { + hash_table* c_ht = hash_table_create(2); + hash_table_set(c_ht, "container_id", cval_number(value->objId)); + hash_table_set(c_ht, "container_pointer", cval_number((long) value)); + container_data = cval_dictionary(c_ht); + value = a->cell[0]; + } + } + + if (container_data != NULL) { + hash_table_set(ht, "container", container_data); + } + + hash_table_set(ht, "id", cval_number(value->objId)); + hash_table_set(ht, "type", cval_string(ctype_name(value->type))); + hash_table_set(ht, "count", cval_number(value->count)); + hash_table_set(ht, "is_deleted", cval_boolean(value->deleted)); + hash_table_set(ht, "is_marked", cval_boolean(value->mark)); + hash_table_set(ht, "has_children", cval_boolean(value->count > 0)); + hash_table_set(ht, "pointer", cval_number((long) value)); + + + + hash_table_set(env_ht, "env_pointer", cval_number((long) e)); + hash_table_set(env_ht, "env_size", cval_number((long) e->ht->table_size)); + hash_table_set(env_ht, "env_items", cval_number((long) e->ht->items)); + if (e->par != NULL) { + hash_table_set(env_ht, "env_parent_pointer", cval_number((long) e->par)); + } + + env_data = cval_dictionary(env_ht); + hash_table_set(ht, "env", env_data); + + long row = get_row_by_id(a->objId); + hash_table_set(allocator_ht, "row", cval_number(row)); + hash_table_set(allocator_ht, "index", cval_number(get_index_by_row_and_id(a->objId, row))); + allocator_data = cval_dictionary(ht); + + hash_table_set(ht, "allocator", allocator_data); + + if (value->type == CVAL_DICTIONARY) { + hash_table_set(ht, "size", cval_number(value->ht->table_size)); + hash_table_set(ht, "items", cval_number(value->ht->items)); + hash_table_set(ht, "ht_pointer", cval_number((long) value->ht)); + } + + if (value->type == CVAL_STRING) { + hash_table_set(ht, "string_pointer", cval_number((long) value->str)); + } - return cval_number(a->cell[0]->objId); + return cval_dictionary(ht); } cval *builtin_sys(cenv *e, cval *a) { @@ -1231,7 +1289,7 @@ void cenv_add_builtins(cenv *e) { 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, "objId", builtin_object_id); + cenv_add_builtin(e, "inspect", builtin_inspect); cenv_add_builtin(e, "+", builtin_add); cenv_add_builtin(e, "-", builtin_sub); From 1caad2401ac1e4c28d2afcb4322c0e5e9d710f9d Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 27 Oct 2021 19:55:17 -0400 Subject: [PATCH 40/43] - fix allocator bug --- src/allocator.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 58f0126..2b42842 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -84,7 +84,7 @@ cval_allocation_index *preallocateIndex(int rows, int slots) { index->size = rows; index->rows = calloc(sizeof(cval_allocation_array*), ROWS_MAX); - for (int i = 0; i < rows; ++i) { + for (int i = 0; i <= rows; ++i) { cval_allocation_array *array = preallocateArray(slots); if (array != NULL) { index->rows[i] = array; @@ -131,12 +131,11 @@ cval **internalCacheFetch(int total) { } if (INDEX->rows[INDEX->cur]->allocated == INDEX->rows[INDEX->cur]->size) { - if (INDEX->cur == INDEX->size) { + if (INDEX->cur == INDEX->size - 1) { if (INDEX->cur < ROWS_MAX) { INDEX->cur += 1; INDEX->size += 1; INDEX->rows[INDEX->cur] = preallocateArray(PREALLOCATE_SLOTS); - ALLOCATOR_MEMORY_PRESSURE = true; } else { array[i] = OUT_OF_MEMORY_FAULT; return array; @@ -146,8 +145,8 @@ cval **internalCacheFetch(int total) { } } array[i] = INDEX->rows[INDEX->cur]->array[INDEX->rows[INDEX->cur]->allocated]; - array[i]->type = CVAL_UNALLOCATED; - INDEX->rows[INDEX->cur]->allocated += 1; + array[i]->type = CVAL_UNALLOCATED; + INDEX->rows[INDEX->cur]->allocated += 1; } return array; @@ -209,10 +208,8 @@ long markValue(cval* val) { marked += markValue(val->cell[i]); } - if (val->type == CVAL_S_EXPRESSION || val->type == CVAL_Q_EXPRESSION) { - marked += markValue(val->formals); - marked += markValue(val->body); - } + marked += markValue(val->formals); + marked += markValue(val->body); if (val->type == CVAL_DICTIONARY) { marked += markDictionary(val); @@ -287,7 +284,7 @@ int sweep() { sweptObj += 1; if (!rowSet) { - INDEX->scur = curRow; + INDEX->scur = curRow - 1; rowSet = true; } } From addb4095f27c7a5b830bff43dd6c54a0714b21b6 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 27 Oct 2021 21:49:33 -0400 Subject: [PATCH 41/43] - improve allocator memory efficiency --- src/allocator.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/allocator.c b/src/allocator.c index 2b42842..73d5246 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -165,7 +165,11 @@ void allocator_setup() { cval *allocate() { cval* val = NULL; + if (CUR_PRE_CACHE_POS > PRE_CACHE_SIZE - 1) { + if (preCache != NULL) { + free(preCache); + } preCache = internalCacheFetch(PRE_CACHE_SIZE); CUR_PRE_CACHE_POS = 0; } @@ -188,11 +192,11 @@ int markDictionary(cval* dictionary) { int cur = 0; while (cur + 1 <= items) { - cval* curValue = dictContent[cur]; - markValue(curValue); + markValue(dictContent[cur]); cur += 1; } + free(dictContent); return totalMarked; } @@ -234,6 +238,7 @@ long markEnv(cenv* env) { } curEnv = curEnv->par; + free(envContents); } return totalMarked; From a2f29fca0e0db3eaeb5fc624d7691ff9d98757e9 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 27 Oct 2021 22:50:12 -0400 Subject: [PATCH 42/43] - overall memory improvements --- src/allocator.c | 18 +++++++++++++++++- src/allocator.h | 1 + src/cval.c | 3 +-- .../perf/create_range 1 - 9999 flamegraph.png | Bin 0 -> 73136 bytes src/hashtable.c | 10 ++++++---- src/main.c | 8 ++++++-- 6 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 src/errata/perf/create_range 1 - 9999 flamegraph.png diff --git a/src/allocator.c b/src/allocator.c index 73d5246..4f2511e 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -79,10 +79,11 @@ cval_allocation_array *preallocateArray(int slots) { } cval_allocation_index *preallocateIndex(int rows, int slots) { - cval_allocation_index *index = malloc(sizeof(cval_allocation_index*)); + cval_allocation_index *index = malloc(sizeof(cval_allocation_index)); index->cur = 0; index->size = rows; index->rows = calloc(sizeof(cval_allocation_array*), ROWS_MAX); + index->smode = false; for (int i = 0; i <= rows; ++i) { cval_allocation_array *array = preallocateArray(slots); @@ -360,3 +361,18 @@ cval *object_by_id(long id) { return INDEX->rows[row]->array[get_index_by_row_and_id(id, row)]; } +void index_shutdown() { + int curRow = 1; + + while (curRow <= INDEX->size) { + cval_allocation_array *row = INDEX->rows[curRow - 1]; + + int curObject = 1; + while (curObject <= row->size) { + free(row->array[curObject - 1]); + curObject += 1; + } + curRow += 1; + } +} + diff --git a/src/allocator.h b/src/allocator.h index ffadd8b..5941348 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -11,5 +11,6 @@ cval* mark_and_sweep(cenv* env); long get_row_by_id(long id); long get_index_by_row_and_id(long id, long row); cval *object_by_id(long id); +void index_shutdown(); bool ALLOCATOR_MEMORY_PRESSURE; #endif //CONNERY_ALLOCATOR_H diff --git a/src/cval.c b/src/cval.c index e69c64f..6f61de1 100644 --- a/src/cval.c +++ b/src/cval.c @@ -300,7 +300,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 = calloc(sizeof(cval*), x->count); for (int i = 0; i < x->count; i++) { x->cell[i] = cval_copy(v->cell[i]); } @@ -311,7 +311,6 @@ cval* cval_copy(cval* v) { strcpy(x->str, v->str); break; - case CVAL_BOOLEAN: x->boolean = v->boolean; break; diff --git a/src/errata/perf/create_range 1 - 9999 flamegraph.png b/src/errata/perf/create_range 1 - 9999 flamegraph.png new file mode 100644 index 0000000000000000000000000000000000000000..776bd96a7c5668bf9b16badd79a0cbbf490c4747 GIT binary patch literal 73136 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 = malloc(strlen(key) + 1); @@ -109,9 +109,9 @@ cval *hash_table_get(hash_table *target_hash_table, const char *key) { hash_table *hash_table_create(const long table_size) { - hash_table *ht = malloc(sizeof(hash_table) * 1); + hash_table *ht = malloc(sizeof(hash_table)); ht->table_size = table_size; - ht->entries = calloc(sizeof(hash_table_entry *), table_size); + ht->entries = calloc(sizeof(hash_table_entry*), table_size); ht->items = 0; for (int i = 0; i < table_size; ++i) { @@ -169,6 +169,7 @@ void hash_table_entry_delete(hash_table *target_hash_table, const char *key) { void hash_table_destroy(hash_table *target_hash_table) { if (target_hash_table->entries == NULL) { + free(target_hash_table->entries); free(target_hash_table); return; } @@ -179,6 +180,7 @@ void hash_table_destroy(hash_table *target_hash_table) { } } + free(target_hash_table->entries); free(target_hash_table); } @@ -243,7 +245,7 @@ cval **hash_table_dump_values(hash_table *target_hash_table) { } cval **hash_table_dump_keys(hash_table *target_hash_table) { - cval** array = malloc(sizeof(cval*) * target_hash_table->items); + cval** array = calloc(sizeof(cval*), target_hash_table->items); int itemsFound = 0; for (long i = 0; i < target_hash_table->table_size; i++) { diff --git a/src/main.c b/src/main.c index f425732..6c54086 100644 --- a/src/main.c +++ b/src/main.c @@ -1247,6 +1247,9 @@ cval *builtin_sys(cenv *e, cval *a) { } if (strcmp(cmd, "SOFT_EXIT") == 0) { + mpc_cleanup(8, Number, Float, Symbol, Sexpr, Qexpr, Expr, Comment, String, DictionaryPair, Dictionary, Connery); + index_shutdown(); + cenv_delete(e); exit(0); } @@ -1444,7 +1447,8 @@ int main(int argc, char **argv) { } } - mpc_cleanup(8, Number, Float, Symbol, String, Comment, Sexpr, Qexpr, Expr, Connery); + mpc_cleanup(8, Number, Float, Symbol, Sexpr, Qexpr, Expr, Comment, String, DictionaryPair, Dictionary, Connery); + index_shutdown(); cenv_delete(e); - return 0; + exit(0); } \ No newline at end of file From 2abb785591df7402d33cfd5e80bf049afd332654 Mon Sep 17 00:00:00 2001 From: Will Cipriano Date: Wed, 27 Oct 2021 22:51:41 -0400 Subject: [PATCH 43/43] - better cleanup for shutdown --- src/allocator.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/allocator.c b/src/allocator.c index 4f2511e..5569899 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -374,5 +374,8 @@ void index_shutdown() { } curRow += 1; } + + free(INDEX->rows); + free(INDEX); }