From b05408ebec2a75f483d33a2343e2d34ed34bb31f Mon Sep 17 00:00:00 2001 From: William Bell Date: Thu, 12 Jun 2025 04:37:07 +0100 Subject: [PATCH] add dictionaries and add accessing with a value --- final_test.ar | 41 +++++++------ src/lexer/token.h | 1 - src/parser/assignable/access/access.c | 51 ++++++++++++---- src/parser/assignable/access/access.h | 4 +- src/parser/dictionary/dictionary.c | 88 +++++++++++++++++++++++++++ src/parser/dictionary/dictionary.h | 16 +++++ src/parser/list/list.c | 2 + src/parser/parser.c | 18 +++++- src/parser/parser.h | 3 +- test.ar | 4 +- 10 files changed, 190 insertions(+), 38 deletions(-) create mode 100644 src/parser/dictionary/dictionary.c create mode 100644 src/parser/dictionary/dictionary.h diff --git a/final_test.ar b/final_test.ar index 581d83f..3da555a 100644 --- a/final_test.ar +++ b/final_test.ar @@ -1,39 +1,42 @@ + let __makeFile(name, type, data) = do + let File = {name: name, type: type, data: data} let save(path) = do let file = file.write(path) file.buffer(data) file.close() File.save = save + return File let __multipart(req, res) = do - let boundary = buffer().from(req.headers.splitN("boundary=", 2)) + let boundary = buffer().from(req.headers["content-type"].splitN("boundary=", 2)[1]) let newLineSplit = buffer().from("\r\n\r\n") let parts = req.buffer.body.split(boundary) - if (true) do - let str = parts.to("string") - if (str == "" || str=="--" || str=="--\r\n") do + for (i from 0 to parts.length) do + let str = parts[i].to("string") + if (str == "" || str=="--" || str=="--\r\n") continue str = null - let headers = [] - let lines = parts.splitN(newLineSplit, 2) - let headerLines = lines.to("string").split("\r\n") - if (true) do - let header = headerLines.splitN(": ", 2) - if (header.length != 2) do - headers = header - if (lines.length != 2) do - let body = lines + let headers = {} + let lines = parts[i].splitN(newLineSplit, 2) + let headerLines = lines[0].to("string").split("\r\n") + for (j from 0 to headerLines.length) do + let header = headerLines[j].splitN(": ", 2) + if (header.length != 2) continue + headers[header[0].lower()] = header[1] + if (lines.length != 2) continue + let body = lines[1] if (i != parts.length-1) do body = body.slice(0, body.length-4) if ("content-disposition" in headers) do - let disposition = headers.split("; ") - if (disposition == "form-data") do - let name = json.parse(disposition.splitN("=", 2)) + let disposition = headers["content-disposition"].split("; ") + if (disposition[0] == "form-data") do + let name = json.parse(disposition[1].splitN("=", 2)[1]) if (disposition.length >= 3) do - let filename = json.parse(disposition.splitN("=", 2)) - req.files = __makeFile(filename, headers, body) + let filename = json.parse(disposition[2].splitN("=", 2)[1]) + req.files[name] = __makeFile(filename, headers["content-type"], body) else do - req.formdata = body.to("string") + req.formdata[name] = body.to("string") res.next() diff --git a/src/lexer/token.h b/src/lexer/token.h index eaab0a2..fc4ea8a 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -5,7 +5,6 @@ typedef enum { TOKEN_STRING = 256, TOKEN_NUMBER, - TOKEN_FRACTION, TOKEN_IDENTIFIER, TOKEN_KEYWORD, TOKEN_NEW_LINE, diff --git a/src/parser/assignable/access/access.c b/src/parser/assignable/access/access.c index 068e64d..c07a4ae 100644 --- a/src/parser/assignable/access/access.c +++ b/src/parser/assignable/access/access.c @@ -1,18 +1,48 @@ #include "access.h" #include "../../../lexer/token.h" -#include "../../parser.h" -#include -#include #include "../../../memory.h" +#include "../../parser.h" +#include +#include +#include -ParsedValue *parse_access(char*file,DArray *tokens, size_t * index, ParsedValue * to_access) { +ParsedValue *parse_access(char *file, DArray *tokens, size_t *index, + ParsedValue *to_access) { + Token *first_token = darray_get(tokens, *index); (*index)++; - error_if_finished(file, tokens, index); - Token * token = darray_get(tokens, *index); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess)); - parsedAccess->to_access = to_access; - parsedAccess->access = strcpy(checked_malloc(strlen(token->value) + 1), token->value); + parsedAccess->to_access = *to_access; + free(to_access); + darray_init(&parsedAccess->access, sizeof(ParsedValue)); + if (first_token->type == TOKEN_DOT) { + error_if_finished(file, tokens, index); + Token *token = darray_get(tokens, *index); + ParsedValue parsedString; + parsedString.type = AST_STRING; + parsedString.data = + strcpy(checked_malloc(strlen(token->value) + 1), token->value); + darray_push(&parsedAccess->access, &parsedString); + } else { + while (true) { + skip_newlines_and_indents(tokens, index); + error_if_finished(file, tokens, index); + ParsedValue *parsedValue = parse_token(file, tokens, index, true); + darray_push(&parsedAccess->access, parsedValue); + free(parsedValue); + skip_newlines_and_indents(tokens, index); + error_if_finished(file, tokens, index); + Token *token = darray_get(tokens, *index); + if (token->type == TOKEN_RBRACKET) { + break; + } else if (token->type != TOKEN_COLON) { + fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, + token->line, token->column); + exit(EXIT_FAILURE); + } + (*index)++; + } + } parsedValue->type = AST_ACCESS; parsedValue->data = parsedAccess; (*index)++; @@ -22,8 +52,7 @@ ParsedValue *parse_access(char*file,DArray *tokens, size_t * index, ParsedValue void free_parse_access(void *ptr) { ParsedValue *parsedValue = ptr; ParsedAccess *parsedAccess = parsedValue->data; - free_parsed(parsedAccess->to_access); - free(parsedAccess->access); - free(parsedAccess->to_access); + free_parsed(&parsedAccess->to_access); + darray_free(&parsedAccess->access, free_parsed); free(parsedAccess); } \ No newline at end of file diff --git a/src/parser/assignable/access/access.h b/src/parser/assignable/access/access.h index 36a9b42..a05ee86 100644 --- a/src/parser/assignable/access/access.h +++ b/src/parser/assignable/access/access.h @@ -4,8 +4,8 @@ #include "../../../lexer/token.h" // for Token typedef struct { - ParsedValue * to_access; - char * access; + ParsedValue to_access; + DArray access; } ParsedAccess; // Function declaration for parsing an identifier diff --git a/src/parser/dictionary/dictionary.c b/src/parser/dictionary/dictionary.c new file mode 100644 index 0000000..91a2976 --- /dev/null +++ b/src/parser/dictionary/dictionary.c @@ -0,0 +1,88 @@ +#include "dictionary.h" +#include "../../lexer/token.h" +#include "../../memory.h" +#include "../parser.h" +#include +#include +#include + +ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) { + ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); + parsedValue->type = AST_DICTIONARY; + DArray *dictionary = checked_malloc(sizeof(DArray)); + parsedValue->data = dictionary; + darray_init(dictionary, sizeof(ParsedValue)); + (*index)++; + skip_newlines_and_indents(tokens, index); + error_if_finished(file, tokens, index); + Token *token = darray_get(tokens, *index); + if (token->type != TOKEN_RBRACE) { + while (true) { + skip_newlines_and_indents(tokens, index); + error_if_finished(file, tokens, index); + size_t keyIndex = *index; + Token *keyToken = darray_get(tokens, *index); + ParsedValue *key = parse_token(file, tokens, index, true); + if (keyToken->type == TOKEN_IDENTIFIER) { + key->type = AST_STRING; + } + skip_newlines_and_indents(tokens, index); + error_if_finished(file, tokens, index); + token = darray_get(tokens, *index); + ParsedValue *value; + bool tobreak = false; + switch (token->type) { + case TOKEN_COLON: + (*index)++; + skip_newlines_and_indents(tokens, index); + error_if_finished(file, tokens, index); + value = parse_token(file, tokens, index, true); + skip_newlines_and_indents(tokens, index); + error_if_finished(file, tokens, index); + token = darray_get(tokens, *index); + if (token->type == TOKEN_RBRACE) { + tobreak = true; + } else if (token->type != TOKEN_COMMA) { + fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, + token->column); + exit(EXIT_FAILURE); + } + break; + case TOKEN_RBRACE: + tobreak = true; + /* fall through */ + case TOKEN_COMMA: + value = parse_token(file, tokens, &keyIndex, true); + break; + default: + fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, + token->column); + exit(EXIT_FAILURE); + } + ParsedDictionaryEntry entry = {key, value}; + darray_push(dictionary, &entry); + if (tobreak) { + break; + } + (*index)++; + error_if_finished(file, tokens, index); + } + } + (*index)++; + return parsedValue; +} + +void free_dictionary_entry(void *ptr) { + ParsedDictionaryEntry *entry = ptr; + free_parsed(entry->key); + free(entry->key); + free_parsed(entry->value); + free(entry->value); +} + +void free_parsed_dictionary(void *ptr) { + ParsedValue *parsedValue = ptr; + DArray *parsed_dictionary = parsedValue->data; + darray_free(parsed_dictionary, free_dictionary_entry); + free(parsedValue->data); +} \ No newline at end of file diff --git a/src/parser/dictionary/dictionary.h b/src/parser/dictionary/dictionary.h new file mode 100644 index 0000000..9fe3a07 --- /dev/null +++ b/src/parser/dictionary/dictionary.h @@ -0,0 +1,16 @@ +#ifndef DICTIONARY_H +#define DICTIONARY_H +#include "../../lexer/token.h" // for Token +#include "../parser.h" + +typedef struct { + ParsedValue * key; + ParsedValue * value; +} ParsedDictionaryEntry; + +ParsedValue *parse_dictionary(char *file, DArray *tokens, + size_t *index); + +void free_parsed_dictionary(void *ptr); + +#endif // DICTIONARY_H \ No newline at end of file diff --git a/src/parser/list/list.c b/src/parser/list/list.c index 99fedac..d025c99 100644 --- a/src/parser/list/list.c +++ b/src/parser/list/list.c @@ -1,3 +1,4 @@ +#include "list.h" #include "../../lexer/token.h" #include "../../memory.h" #include "../parser.h" @@ -12,6 +13,7 @@ ParsedValue *parse_list(char *file, DArray *tokens, size_t *index) { parsedValue->data = list; darray_init(list, sizeof(ParsedValue)); (*index)++; + skip_newlines_and_indents(tokens, index); error_if_finished(file, tokens, index); Token *token = darray_get(tokens, *index); if (token->type != TOKEN_RBRACKET) { diff --git a/src/parser/parser.c b/src/parser/parser.c index d47a6d9..46825c1 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -6,6 +6,7 @@ #include "assignable/call/call.h" #include "assignable/identifier/identifier.h" #include "declaration/declaration.h" +#include "dictionary/dictionary.h" #include "dowrap/dowrap.h" #include "if/if.h" #include "list/list.h" @@ -21,9 +22,9 @@ #include const char *ValueTypeNames[] = { - "string", "assign", "identifier", "number", "if statement", - "access", "call", "declaration", "null", "boolean", - "do wrap", "operations", "list"}; + "string", "assign", "identifier", "number", "if statement", + "access", "call", "declaration", "null", "boolean", + "do wrap", "operations", "list", "dictionary"}; void error_if_finished(char *file, DArray *tokens, size_t *index) { if ((*index) >= tokens->size) { @@ -114,6 +115,9 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index, case TOKEN_LBRACKET: output = parse_list(file, tokens, index); break; + case TOKEN_LBRACE: + output = parse_dictionary(file, tokens, index); + break; default: fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, token->column); @@ -139,6 +143,7 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index, output = parse_call(file, tokens, index, output); break; case TOKEN_DOT: + case TOKEN_LBRACKET: output = parse_access(file, tokens, index, output); break; SWITCH_OPERATIONS @@ -183,6 +188,10 @@ void parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) { } void free_parsed(void *ptr) { + if (!ptr) { + fprintf(stderr, "panic: freeing NULL pointer\n"); + exit(EXIT_FAILURE); + } ParsedValue *parsed = ptr; switch (parsed->type) { case AST_IDENTIFIER: @@ -219,5 +228,8 @@ void free_parsed(void *ptr) { case AST_LIST: free_parsed_list(parsed); break; + case AST_DICTIONARY: + free_parsed_dictionary(parsed); + break; } } \ No newline at end of file diff --git a/src/parser/parser.h b/src/parser/parser.h index b91160d..2685a73 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -38,7 +38,8 @@ typedef enum { AST_BOOLEAN, AST_DOWRAP, AST_OPERATION, - AST_LIST + AST_LIST, + AST_DICTIONARY } ValueType; extern const char* ValueTypeNames[]; diff --git a/test.ar b/test.ar index ce738b2..12f7e9f 100644 --- a/test.ar +++ b/test.ar @@ -47,4 +47,6 @@ x = [ 'hello world', 'wow', 10 -] \ No newline at end of file +] + +term.log(x[0:1:1]) \ No newline at end of file