From f3912ae49f632d077eada7c89b82ecaff2a556c6 Mon Sep 17 00:00:00 2001 From: William Bell Date: Wed, 26 Nov 2025 03:07:06 +0000 Subject: [PATCH] add item access --- src/arobject.h | 3 +- src/import.c | 45 ++++--- src/memory.c | 10 +- src/memory.h | 3 +- src/parser/assignable/access/access.c | 63 +++++----- src/parser/assignable/item/item.c | 80 ++++++++++++ src/parser/assignable/item/item.h | 25 ++++ src/parser/parser.c | 8 +- src/parser/parser.h | 1 + .../dynamic_array_armem/darray_armem.c | 2 +- src/runtime/internals/hashmap/hashmap.c | 2 +- src/runtime/objects/dictionary/dictionary.c | 40 +++++- src/runtime/objects/object.c | 3 +- src/runtime/objects/string/string.c | 114 +++++++++++------- src/runtime/objects/string/string.h | 18 +-- src/runtime/runtime.c | 25 +++- src/translator/bytecode_spec.md | 4 + src/translator/item_access/item_access.c | 33 +++++ src/translator/item_access/item_access.h | 15 +++ src/translator/translator.c | 4 + src/translator/translator.h | 1 + tests/iteration-test.ar | 3 - 22 files changed, 383 insertions(+), 119 deletions(-) create mode 100644 src/parser/assignable/item/item.c create mode 100644 src/parser/assignable/item/item.h create mode 100644 src/translator/item_access/item_access.c create mode 100644 src/translator/item_access/item_access.h delete mode 100644 tests/iteration-test.ar diff --git a/src/arobject.h b/src/arobject.h index 069fd0d..cef8190 100644 --- a/src/arobject.h +++ b/src/arobject.h @@ -29,13 +29,14 @@ typedef enum { __new__, __init__, __boolean__, - __get_attr__, + __getattr__, field__address, __call__, __number__, field_length, __getattribute__, __setattr__, + __getitem__, __setitem__, __hash__, __repr__, diff --git a/src/import.c b/src/import.c index fc10a08..4954b3b 100644 --- a/src/import.c +++ b/src/import.c @@ -43,6 +43,15 @@ static inline uint64_t htole64(uint64_t x) { return x; } #elif defined(__linux__) #include #include +#include +#include +#include + +int is_regular_file(const char *path) { + struct stat path_stat; + stat(path, &path_stat); + return S_ISREG(path_stat.st_mode); +} #elif defined(__APPLE__) #include #define htole32(x) OSSwapHostToLittleInt32(x) @@ -93,11 +102,11 @@ const uint32_t version_number = 0; const char version_string[] = "4.0.0"; bool file_exists(const char *path) { - struct stat st; - if (stat(path, &st) == 0) { - return S_ISREG(st.st_mode); // true only if it's a regular file - } - return false; // doesn't exist, or stat failed + struct stat st; + if (stat(path, &st) == 0) { + return S_ISREG(st.st_mode); // true only if it's a regular file + } + return false; // doesn't exist, or stat failed } static inline void write_and_hash(FILE *file, XXH64_state_t *state, @@ -285,7 +294,6 @@ Translated load_argon_file(char *path, ArErr *err) { sizeof(cache_file_path)); cwk_path_change_extension(cache_file_path, BYTECODE_EXTENTION, cache_file_path, sizeof(cache_file_path)); - FILE *file = fopen(path, "r"); if (!file) { *err = create_err(0, 0, 0, NULL, "File Error", "Unable to open file '%s'", @@ -400,7 +408,8 @@ Translated load_argon_file(char *path, ArErr *err) { Translated gc_translated = { translated.registerCount, translated.registerAssignment, NULL, {}, {}, translated.path}; - gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity+translated.constants.capacity); + gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity + + translated.constants.capacity); memcpy(gc_translated.bytecode.data, translated.bytecode.data, translated.bytecode.capacity); gc_translated.bytecode.element_size = translated.bytecode.element_size; @@ -408,7 +417,8 @@ Translated load_argon_file(char *path, ArErr *err) { gc_translated.bytecode.resizable = false; gc_translated.bytecode.capacity = translated.bytecode.size * translated.bytecode.element_size; - gc_translated.constants.data = gc_translated.bytecode.data+translated.bytecode.capacity; + gc_translated.constants.data = + gc_translated.bytecode.data + translated.bytecode.capacity; memcpy(gc_translated.constants.data, translated.constants.data, translated.constants.capacity); gc_translated.constants.size = translated.constants.size; @@ -422,8 +432,8 @@ Translated load_argon_file(char *path, ArErr *err) { } const char *PRE_PATHS_TO_TEST[] = {"", "", "argon_modules", "argon_modules"}; -const char *POST_PATHS_TO_TEST[sizeof(PRE_PATHS_TO_TEST)/sizeof(char *)] = {"", "init.ar", "", - "init.ar"}; +const char *POST_PATHS_TO_TEST[sizeof(PRE_PATHS_TO_TEST) / sizeof(char *)] = { + "", "init.ar", "", "init.ar"}; struct hashmap *importing_hash_table = NULL; struct hashmap_GC *imported_hash_table = NULL; @@ -431,8 +441,9 @@ struct hashmap_GC *imported_hash_table = NULL; Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) { char path[FILENAME_MAX]; bool found = false; - for (size_t i = 0; i < sizeof(PRE_PATHS_TO_TEST)/sizeof(char *); i++) { - cwk_path_get_absolute(current_directory, PRE_PATHS_TO_TEST[i], path, sizeof(path)); + for (size_t i = 0; i < sizeof(PRE_PATHS_TO_TEST) / sizeof(char *); i++) { + cwk_path_get_absolute(current_directory, PRE_PATHS_TO_TEST[i], path, + sizeof(path)); cwk_path_get_absolute(path, path_relative, path, sizeof(path)); cwk_path_get_absolute(path, POST_PATHS_TO_TEST[i], path, sizeof(path)); if (file_exists(path)) { @@ -445,9 +456,10 @@ Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) { path_relative); return NULL; } - if (!importing_hash_table) importing_hash_table = createHashmap(); + if (!importing_hash_table) + importing_hash_table = createHashmap(); uint64_t hash = siphash64_bytes(path, strlen(path), siphash_key); - hashmap_insert(importing_hash_table, hash, path, (void*)true, 0); + hashmap_insert(importing_hash_table, hash, path, (void *)true, 0); Translated translated = load_argon_file(path, err); if (err->exists) { return NULL; @@ -462,8 +474,9 @@ Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) { end = clock(); double time_spent = (double)(end - start) / CLOCKS_PER_SEC; fprintf(stderr, "Execution time taken: %f seconds\n", time_spent); - hashmap_insert(importing_hash_table, hash, path, (void*)false, 0); - if (!imported_hash_table) imported_hash_table = createHashmap_GC(); + hashmap_insert(importing_hash_table, hash, path, (void *)false, 0); + if (!imported_hash_table) + imported_hash_table = createHashmap_GC(); hashmap_insert_GC(imported_hash_table, hash, path, main_scope, 0); return main_scope; } \ No newline at end of file diff --git a/src/memory.c b/src/memory.c index 81a1c51..59e4a8d 100644 --- a/src/memory.c +++ b/src/memory.c @@ -6,7 +6,6 @@ #include "memory.h" #include -#include #include #include #include @@ -22,6 +21,15 @@ void *checked_malloc(size_t size) { return ptr; } +void *checked_realloc(void *ptr, size_t size) { + void *new_ptr = realloc(ptr, size); + if (!new_ptr) { + fprintf(stderr, "fatal error: failed to allocate %zu bytes\n", size); + exit(EXIT_FAILURE); + } + return new_ptr; +} + struct allocation *memory_allocations = NULL; size_t memory_allocations_size = 0; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; diff --git a/src/memory.h b/src/memory.h index e99453f..8b0894b 100644 --- a/src/memory.h +++ b/src/memory.h @@ -9,7 +9,7 @@ #include // for size_t #include -#include +#include // GC-managed allocations @@ -37,5 +37,6 @@ void ar_memory_init(); void ar_memory_shutdown(); void *checked_malloc(size_t size); +void *checked_realloc(void *ptr, size_t size); #endif // ARGON_MEMORY_H \ No newline at end of file diff --git a/src/parser/assignable/access/access.c b/src/parser/assignable/access/access.c index 3850d2a..c8f1796 100644 --- a/src/parser/assignable/access/access.c +++ b/src/parser/assignable/access/access.c @@ -15,41 +15,38 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index, ParsedValue *to_access) { - Token *first_token = darray_get(tokens, *index); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); - if (first_token->type == TOKEN_DOT) { - ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess)); - parsedAccess->to_access = to_access; - parsedAccess->access = NULL; - parsedValue->type = AST_ACCESS; - parsedValue->data = parsedAccess; - (*index)++; - ArErr err = error_if_finished(file, tokens, index); - if (err.exists) { - free_parsed(parsedValue); - free(parsedValue); - return (ParsedValueReturn){err, NULL}; - } - Token *token = darray_get(tokens, *index); - if (token->type != TOKEN_IDENTIFIER) { - free_parsed(parsedValue); - free(parsedValue); - return (ParsedValueReturn){create_err(token->line, token->column, - token->length, file, "Syntax Error", - "expected identifier after dot"), - NULL}; - } - parsedAccess->line = token->line; - parsedAccess->column = token->column; - parsedAccess->length = token->length; - ParsedValueReturn parsedString = parse_string(token, false); - if (parsedString.err.exists) { - free_parsed(parsedValue); - free(parsedValue); - return parsedString; - } - parsedAccess->access = parsedString.value; + ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess)); + parsedAccess->to_access = to_access; + parsedAccess->access = NULL; + parsedValue->type = AST_ACCESS; + parsedValue->data = parsedAccess; + (*index)++; + ArErr err = error_if_finished(file, tokens, index); + if (err.exists) { + free_parsed(parsedValue); + free(parsedValue); + return (ParsedValueReturn){err, NULL}; } + Token *token = darray_get(tokens, *index); + if (token->type != TOKEN_IDENTIFIER) { + free_parsed(parsedValue); + free(parsedValue); + return (ParsedValueReturn){create_err(token->line, token->column, + token->length, file, "Syntax Error", + "expected identifier after dot"), + NULL}; + } + parsedAccess->line = token->line; + parsedAccess->column = token->column; + parsedAccess->length = token->length; + ParsedValueReturn parsedString = parse_string(token, false); + if (parsedString.err.exists) { + free_parsed(parsedValue); + free(parsedValue); + return parsedString; + } + parsedAccess->access = parsedString.value; (*index)++; return (ParsedValueReturn){no_err, parsedValue}; } diff --git a/src/parser/assignable/item/item.c b/src/parser/assignable/item/item.c new file mode 100644 index 0000000..a8261a9 --- /dev/null +++ b/src/parser/assignable/item/item.c @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "item.h" +#include "../../../lexer/token.h" +#include "../../../memory.h" +#include "../../parser.h" +#include +#include +#include +#include + +ParsedValueReturn parse_item_access(char *file, DArray *tokens, size_t *index, + ParsedValue *to_access) { + ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); + ParsedItemAccess *parsedItemAccess = checked_malloc(sizeof(ParsedItemAccess)); + parsedItemAccess->to_access = to_access; + size_t capacity = 4; + parsedItemAccess->items = checked_malloc(capacity * sizeof(ParsedValue *)); + parsedItemAccess->itemc = 0; + parsedValue->type = AST_ITEM_ACCESS; + parsedValue->data = parsedItemAccess; + Token *token = darray_get(tokens, *index); + parsedItemAccess->line = token->line; + parsedItemAccess->column = token->column; + parsedItemAccess->length = token->length; + (*index)++; + while (true) { + ArErr err = error_if_finished(file, tokens, index); + if (err.exists) { + free_parsed(parsedValue); + free(parsedValue); + return (ParsedValueReturn){err, NULL}; + } + ParsedValueReturn parsedKey = parse_token(file, tokens, index, true); + if (parsedKey.err.exists) { + free_parsed(parsedValue); + free(parsedValue); + return parsedKey; + } + parsedItemAccess->items[parsedItemAccess->itemc++] = parsedKey.value; + if (parsedItemAccess->itemc > capacity) { + capacity *= 2; + parsedItemAccess->items = checked_realloc( + parsedItemAccess->items, capacity * sizeof(ParsedValue *)); + } + Token *token = darray_get(tokens, *index); + (*index)++; + if (token->type == TOKEN_COMMA) { + continue; + } else if (token->type == TOKEN_RBRACKET) { + break; + } else { + free_parsed(parsedValue); + free(parsedValue); + return (ParsedValueReturn){ + create_err(token->line, token->column, token->length, file, + "Syntax Error", + "expected either a comma or a closing bracket"), + NULL}; + } + } + return (ParsedValueReturn){no_err, parsedValue}; +} + +void free_parse_item_access(void *ptr) { + ParsedValue *parsedValue = ptr; + ParsedItemAccess *parsedItemAccess = parsedValue->data; + free_parsed(parsedItemAccess->to_access); + free(parsedItemAccess->to_access); + for (size_t i = 0; i < parsedItemAccess->itemc; i++) { + free_parsed(parsedItemAccess->items[i]); + free(parsedItemAccess->items[i]); + } + free(parsedItemAccess->items); + free(parsedItemAccess); +} \ No newline at end of file diff --git a/src/parser/assignable/item/item.h b/src/parser/assignable/item/item.h new file mode 100644 index 0000000..baf5a7d --- /dev/null +++ b/src/parser/assignable/item/item.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef ITEM_ACCESS_H +#define ITEM_ACCESS_H +#include "../../parser.h" +#include "../../../lexer/token.h" // for Token +typedef struct { + ParsedValue *to_access; + ParsedValue **items; + size_t itemc; + size_t line; + size_t column; + size_t length; +} ParsedItemAccess; + +ParsedValueReturn parse_item_access(char *file, DArray *tokens, size_t *index, + ParsedValue *to_access); + +void free_parse_item_access(void *ptr); + +#endif // ACCESS_H \ No newline at end of file diff --git a/src/parser/parser.c b/src/parser/parser.c index b110c35..3faa1e9 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -11,6 +11,7 @@ #include "assignable/assign/assign.h" #include "assignable/call/call.h" #include "assignable/identifier/identifier.h" +#include "assignable/item/item.h" #include "declaration/declaration.h" #include "dictionary/dictionary.h" #include "dowrap/dowrap.h" @@ -164,9 +165,11 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index, output = parse_call(file, tokens, index, output.value); break; case TOKEN_DOT: - case TOKEN_LBRACKET: output = parse_access(file, tokens, index, output.value); break; + case TOKEN_LBRACKET: + output = parse_item_access(file, tokens, index, output.value); + break; SWITCH_OPERATIONS if (process_operations) { output = parse_operations(file, tokens, index, output.value); @@ -241,6 +244,9 @@ void free_parsed(void *ptr) { case AST_ACCESS: free_parse_access(parsed); break; + case AST_ITEM_ACCESS: + free_parse_item_access(parsed); + break; case AST_NULL: case AST_BOOLEAN: break; diff --git a/src/parser/parser.h b/src/parser/parser.h index c188f9b..4f011a9 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -40,6 +40,7 @@ typedef enum { AST_NUMBER, AST_IF, AST_ACCESS, + AST_ITEM_ACCESS, AST_CALL, AST_DECLARATION, AST_NULL, diff --git a/src/runtime/internals/dynamic_array_armem/darray_armem.c b/src/runtime/internals/dynamic_array_armem/darray_armem.c index cf1842e..3429078 100644 --- a/src/runtime/internals/dynamic_array_armem/darray_armem.c +++ b/src/runtime/internals/dynamic_array_armem/darray_armem.c @@ -6,7 +6,7 @@ #include "darray_armem.h" #include "../../../memory.h" -#include +#include #include #include #include diff --git a/src/runtime/internals/hashmap/hashmap.c b/src/runtime/internals/hashmap/hashmap.c index f699cb4..bfaa494 100644 --- a/src/runtime/internals/hashmap/hashmap.c +++ b/src/runtime/internals/hashmap/hashmap.c @@ -7,7 +7,7 @@ #include "hashmap.h" #include "../../../memory.h" -#include +#include #include #include #include diff --git a/src/runtime/objects/dictionary/dictionary.c b/src/runtime/objects/dictionary/dictionary.c index b703a52..fbce636 100644 --- a/src/runtime/objects/dictionary/dictionary.c +++ b/src/runtime/objects/dictionary/dictionary.c @@ -122,14 +122,14 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc, return result; } -ArgonObject *create_ARGON_DICTIONARY_TYPE___get_attr__(size_t argc, +ArgonObject *create_ARGON_DICTIONARY_TYPE___getattr__(size_t argc, ArgonObject **argv, ArErr *err, RuntimeState *state) { (void)state; if (argc != 2) { *err = create_err(0, 0, 0, "", "Runtime Error", - "__get_attr__ expects 2 argument, got %" PRIu64, argc); + "__getattr__ expects 2 argument, got %" PRIu64, argc); return ARGON_NULL; } ArgonObject *object = argv[0]; @@ -169,6 +169,32 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___setattr__(size_t argc, return value; } +ArgonObject *create_ARGON_DICTIONARY_TYPE___getitem__(size_t argc, + ArgonObject **argv, + ArErr *err, + RuntimeState *state) { + (void)state; + if (argc != 2) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__getitem__ expects 2 argument, got %" PRIu64, argc); + return ARGON_NULL; + } + ArgonObject *object = argv[0]; + ArgonObject *key = argv[1]; + int64_t hash = hash_object(key, err, state); + if (err->exists) { + return ARGON_NULL; + } + ArgonObject *result = hashmap_lookup_GC(object->value.as_hashmap, hash); + if (!result) { + char *object_str = argon_object_to_null_terminated_string(key, err, state); + + *err = create_err(0, 0, 0, NULL, "Attribute Error", + "Dictionary has no item '%s'", object_str); + return ARGON_NULL; + } + return result; +} ArgonObject *create_ARGON_DICTIONARY_TYPE___setitem__(size_t argc, ArgonObject **argv, @@ -199,9 +225,9 @@ void create_ARGON_DICTIONARY_TYPE() { create_argon_native_function( "__init__", create_ARGON_DICTIONARY_TYPE___init__)); add_builtin_field( - ARGON_DICTIONARY_TYPE, __get_attr__, - create_argon_native_function("__get_attr__", - create_ARGON_DICTIONARY_TYPE___get_attr__)); + ARGON_DICTIONARY_TYPE, __getattr__, + create_argon_native_function("__getattr__", + create_ARGON_DICTIONARY_TYPE___getattr__)); add_builtin_field( ARGON_DICTIONARY_TYPE, __setattr__, create_argon_native_function("__setattr__", @@ -210,6 +236,10 @@ void create_ARGON_DICTIONARY_TYPE() { ARGON_DICTIONARY_TYPE, __setitem__, create_argon_native_function("__setitem__", create_ARGON_DICTIONARY_TYPE___setitem__)); + add_builtin_field( + ARGON_DICTIONARY_TYPE, __getitem__, + create_argon_native_function("__getitem__", + create_ARGON_DICTIONARY_TYPE___getitem__)); add_builtin_field(ARGON_DICTIONARY_TYPE, __string__, create_argon_native_function( "__string__", create_ARGON_DICTIONARY_TYPE___string__)); diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index c2666af..03eae83 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -45,7 +45,8 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = { "__new__", "__init__", "__boolean__", - "__get_attr__", + "__getattr__", + "__getitem__", "address", "__call__", "__number__", diff --git a/src/runtime/objects/string/string.c b/src/runtime/objects/string/string.c index 4ce5d46..c39b66d 100644 --- a/src/runtime/objects/string/string.c +++ b/src/runtime/objects/string/string.c @@ -5,6 +5,7 @@ */ #include "string.h" +#include "../../call/call.h" #include "../number/number.h" #include "../object.h" #include @@ -14,51 +15,58 @@ ArgonObject *ARGON_STRING_TYPE = NULL; - - - char *c_quote_string(const char *input, size_t len) { - // Worst case: every byte becomes "\uXXXX" (6 chars) + quotes + NUL - size_t max_out = 2 + (len * 6) + 1; - char *out = malloc(max_out); - if (!out) return NULL; + // Worst case: every byte becomes "\uXXXX" (6 chars) + quotes + NUL + size_t max_out = 2 + (len * 6) + 1; + char *out = malloc(max_out); + if (!out) + return NULL; - size_t j = 0; - out[j++] = '"'; + size_t j = 0; + out[j++] = '"'; - for (size_t i = 0; i < len; i++) { - unsigned char c = (unsigned char)input[i]; + for (size_t i = 0; i < len; i++) { + unsigned char c = (unsigned char)input[i]; - switch (c) { - case '\n': - out[j++] = '\\'; out[j++] = 'n'; break; - case '\t': - out[j++] = '\\'; out[j++] = 't'; break; - case '\r': - out[j++] = '\\'; out[j++] = 'r'; break; - case '\\': - out[j++] = '\\'; out[j++] = '\\'; break; - case '\"': - out[j++] = '\\'; out[j++] = '\"'; break; - default: - if (isprint(c)) { - out[j++] = c; - } else { - // write \uXXXX - j += sprintf(&out[j], "\\u%04X", c); - } - } + switch (c) { + case '\n': + out[j++] = '\\'; + out[j++] = 'n'; + break; + case '\t': + out[j++] = '\\'; + out[j++] = 't'; + break; + case '\r': + out[j++] = '\\'; + out[j++] = 'r'; + break; + case '\\': + out[j++] = '\\'; + out[j++] = '\\'; + break; + case '\"': + out[j++] = '\\'; + out[j++] = '\"'; + break; + default: + if (isprint(c)) { + out[j++] = c; + } else { + // write \uXXXX + j += sprintf(&out[j], "\\u%04X", c); + } } + } - out[j++] = '"'; - out[j] = '\0'; - return out; + out[j++] = '"'; + out[j] = '\0'; + return out; } -void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash, - uint64_t hash) { - add_builtin_field(object, field_length, - new_number_object_from_int64(length)); +void init_string(ArgonObject *object, char *data, size_t length, + uint64_t prehash, uint64_t hash) { + add_builtin_field(object, field_length, new_number_object_from_int64(length)); object->type = TYPE_STRING; object->value.as_str = ar_alloc(sizeof(struct string_struct)); object->value.as_str->data = data; @@ -69,18 +77,40 @@ void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash, object->as_bool = length; } -ArgonObject *new_string_object_without_memcpy(char *data, size_t length, uint64_t prehash, - uint64_t hash) { +ArgonObject *new_string_object_without_memcpy(char *data, size_t length, + uint64_t prehash, uint64_t hash) { ArgonObject *object = new_instance(ARGON_STRING_TYPE); - init_string(object,data,length,prehash,hash); + init_string(object, data, length, prehash, hash); return object; } ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash, uint64_t hash) { - char*data_copy = ar_alloc_atomic(length); + char *data_copy = ar_alloc_atomic(length); memcpy(data_copy, data, length); - return new_string_object_without_memcpy(data_copy,length, prehash, hash); + return new_string_object_without_memcpy(data_copy, length, prehash, hash); +} + +char *argon_object_to_null_terminated_string(ArgonObject *object, ArErr *err, + RuntimeState *state) { + ArgonObject *string_convert_method = get_builtin_field_for_class( + get_builtin_field(object, __class__), __repr__, object); + + if (!string_convert_method) + return ""; + + ArgonObject *string_object = + argon_call(string_convert_method, 0, NULL, err, state); + if (err->exists) + return NULL; + + + if (string_object->type != TYPE_STRING) return ""; + + char *string = ar_alloc(string_object->value.as_str->length+1); + string[string_object->value.as_str->length] = '\0'; + memcpy(string, string_object->value.as_str->data, string_object->value.as_str->length); + return string; } ArgonObject *new_string_object_null_terminated(char *data) { diff --git a/src/runtime/objects/string/string.h b/src/runtime/objects/string/string.h index 15edc65..018b787 100644 --- a/src/runtime/objects/string/string.h +++ b/src/runtime/objects/string/string.h @@ -12,13 +12,17 @@ extern ArgonObject *ARGON_STRING_TYPE; char *c_quote_string(const char *input, size_t len); -void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash, +void init_string(ArgonObject *object, char *data, size_t length, + uint64_t prehash, uint64_t hash); + +char *argon_object_to_null_terminated_string(ArgonObject *object, ArErr *err, + RuntimeState *state); + +ArgonObject *new_string_object_without_memcpy(char *data, size_t length, + uint64_t prehash, uint64_t hash); + +ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash, uint64_t hash); -ArgonObject *new_string_object_without_memcpy(char *data, size_t length, uint64_t prehash, - uint64_t hash); - -ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash, uint64_t hash); - -ArgonObject *new_string_object_null_terminated(char*data); +ArgonObject *new_string_object_null_terminated(char *data); #endif // STRING_OBJ_H \ No newline at end of file diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 6b5382f..4489cb3 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -22,7 +22,7 @@ #include "objects/term/term.h" #include "objects/type/type.h" #include -#include +#include #include #include #include @@ -72,11 +72,11 @@ ArgonObject *BASE_CLASS___getattribute__(size_t argc, ArgonObject **argv, access->value.as_str->length, true, false); if (value) return value; - ArgonObject *cls__get_attr__ = get_builtin_field_for_class( - get_builtin_field(to_access, __class__), __get_attr__, to_access); - if (cls__get_attr__) { + ArgonObject *cls__getattr__ = get_builtin_field_for_class( + get_builtin_field(to_access, __class__), __getattr__, to_access); + if (cls__getattr__) { value = - argon_call(cls__get_attr__, 1, (ArgonObject *[]){access}, err, state); + argon_call(cls__getattr__, 1, (ArgonObject *[]){access}, err, state); if (err->exists) { return ARGON_NULL; } @@ -890,7 +890,8 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, [OP_NOT] = &&DO_NOT, [OP_LOAD_SETATTR_METHOD] = &&DO_LOAD_SETATTR_METHOD, [OP_CREATE_DICTIONARY] = &&DO_CREATE_DICTIONARY, - [OP_LOAD_SETITEM_METHOD] = &&DO_LOAD_SETITEM_METHOD}; + [OP_LOAD_SETITEM_METHOD] = &&DO_LOAD_SETITEM_METHOD, + [OP_LOAD_GETITEM_METHOD] = &&DO_LOAD_GETITEM_METHOD}; _state.head = 0; StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame)); @@ -1288,6 +1289,18 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, } continue; } + DO_LOAD_GETITEM_METHOD: { + state->registers[0] = get_builtin_field_for_class( + get_builtin_field(state->registers[0], __class__), __getitem__, + state->registers[0]); + if (!state->registers[0]) { + *err = create_err( + state->source_location.line, state->source_location.column, + state->source_location.length, state->path, "Runtime Error", + "unable to get __getitem__ from objects class"); + } + continue; + } } ArgonObject *result = currentStackFrame->state.registers[0]; diff --git a/src/translator/bytecode_spec.md b/src/translator/bytecode_spec.md index 3169678..a336377 100644 --- a/src/translator/bytecode_spec.md +++ b/src/translator/bytecode_spec.md @@ -193,6 +193,10 @@ loads the \_\_setattr\_\_ method from the objects class in register 0 and put it create a dictionary object into register 0. +## OP_LOAD_GETITEM_METHOD + +loads the \_\_getitem\_\_ method from the objects class in register 0 and put it into register 0 + ## OP_LOAD_SETITEM_METHOD loads the \_\_setitem\_\_ method from the objects class in register 0 and put it into register 0 \ No newline at end of file diff --git a/src/translator/item_access/item_access.c b/src/translator/item_access/item_access.c new file mode 100644 index 0000000..f75b955 --- /dev/null +++ b/src/translator/item_access/item_access.c @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +#include "item_access.h" +#include + +size_t translate_item_access(Translated *translated, ParsedItemAccess *access, + ArErr *err) { + set_registers(translated, 1); + uint64_t first = translate_parsed(translated, access->to_access, err); + if (err->exists) + return 0; + push_instruction_byte(translated, OP_LOAD_GETITEM_METHOD); + push_instruction_byte(translated, OP_INIT_CALL); + push_instruction_code(translated, access->itemc); + + for (size_t i = 0; i < access->itemc; i++) { + translate_parsed(translated, access->items[i], err); + if (err->exists) + return 0; + push_instruction_byte(translated, OP_INSERT_ARG); + push_instruction_code(translated, i); + } + + push_instruction_byte(translated, OP_SOURCE_LOCATION); + push_instruction_code(translated, access->line); + push_instruction_code(translated, access->column); + push_instruction_code(translated, access->length); + push_instruction_byte(translated, OP_CALL); + return first; +} \ No newline at end of file diff --git a/src/translator/item_access/item_access.h b/src/translator/item_access/item_access.h new file mode 100644 index 0000000..bf266c1 --- /dev/null +++ b/src/translator/item_access/item_access.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef translator_item_access_H +#define translator_item_access_H +#include "../../parser/assignable/item/item.h" +#include "../translator.h" + +size_t translate_item_access(Translated *translated, ParsedItemAccess *access, + ArErr *err); + +#endif // translator_item_access_H \ No newline at end of file diff --git a/src/translator/translator.c b/src/translator/translator.c index 89aa852..52cc441 100644 --- a/src/translator/translator.c +++ b/src/translator/translator.c @@ -9,6 +9,8 @@ #include "../parser/dictionary/dictionary.h" #include "../parser/not/not.h" #include "access/access.h" +#include "../parser/assignable/item/item.h" +#include "item_access/item_access.h" #include "assignment/assignment.h" #include "call/call.h" #include "declaration/declaration.h" @@ -163,6 +165,8 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue, err); case AST_ACCESS: return translate_access(translated, (ParsedAccess *)parsedValue->data, err); + case AST_ITEM_ACCESS: + return translate_item_access(translated, (ParsedItemAccess *)parsedValue->data, err); case AST_OPERATION: return translate_operation(translated, (ParsedOperation *)parsedValue->data, err); diff --git a/src/translator/translator.h b/src/translator/translator.h index e734008..3f91b6e 100644 --- a/src/translator/translator.h +++ b/src/translator/translator.h @@ -42,6 +42,7 @@ typedef enum { OP_NOT, OP_LOAD_SETATTR_METHOD, OP_CREATE_DICTIONARY, + OP_LOAD_GETITEM_METHOD, OP_LOAD_SETITEM_METHOD } OperationType; diff --git a/tests/iteration-test.ar b/tests/iteration-test.ar deleted file mode 100644 index 2c929db..0000000 --- a/tests/iteration-test.ar +++ /dev/null @@ -1,3 +0,0 @@ -let i = 1e7 -while (i) do - i=i-1 \ No newline at end of file