From fc7cfc7cfbcc2ee9e83844338a1b566bde0d33f4 Mon Sep 17 00:00:00 2001 From: William Bell <62452284+Ugric@users.noreply.github.com> Date: Tue, 9 Sep 2025 06:24:23 +0100 Subject: [PATCH] change how access is done and add built in array (need to optimise the size) --- perf.data | Bin 144208 -> 0 bytes perf.data.old | Bin 138728 -> 0 bytes src/arobject.h | 27 ++ src/err.h | 5 +- src/import.c | 468 ++++++++++++++++++++++ src/import.h | 15 + src/main.c | 433 +------------------- src/runtime/access/access.c | 44 -- src/runtime/access/access.h | 17 - src/runtime/call/call.c | 10 +- src/runtime/internals/hashmap/hashmap.c | 2 +- src/runtime/objects/functions/functions.c | 6 +- src/runtime/objects/number/number.c | 40 +- src/runtime/objects/object.c | 96 +++-- src/runtime/objects/object.h | 32 +- src/runtime/objects/string/string.c | 3 +- src/runtime/objects/term/term.c | 2 +- src/runtime/runtime.c | 146 +++++-- src/translator/access/access.c | 17 +- src/translator/bytecode_spec.md | 4 +- src/translator/translator.h | 2 +- tests/iteration-test.ar | 2 +- 22 files changed, 732 insertions(+), 639 deletions(-) delete mode 100644 perf.data delete mode 100644 perf.data.old create mode 100644 src/import.c create mode 100644 src/import.h delete mode 100644 src/runtime/access/access.c delete mode 100644 src/runtime/access/access.h diff --git a/perf.data b/perf.data deleted file mode 100644 index 4f3708648cfdccddadb16fe2f77684ecd59218f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144208 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 + +typedef enum { + __base__, + __class__, + __name__, + __add__, + __string__, + __subtract__, + __multiply__, + __division__, + __new__, + __init__, + __boolean__, + __get_attr__, + __binding__, + __function__, + field__address, + __call__, + __number__, + field_log, + field_length, + __getattribute__, + + BUILT_IN_FIELDS_COUNT, +} built_in_fields; + typedef struct ArErr ArErr; typedef struct RuntimeState RuntimeState; @@ -77,6 +103,7 @@ struct ArgonObject { ArgonType type; ArgonType child_type; struct hashmap_GC *dict; + ArgonObject* Builtin_slots[BUILT_IN_FIELDS_COUNT]; bool as_bool; union { struct as_number { diff --git a/src/err.h b/src/err.h index 4a9f623..dc0703c 100644 --- a/src/err.h +++ b/src/err.h @@ -4,10 +4,13 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +#ifndef RETURN_TYPE_H +#define RETURN_TYPE_H #include "returnTypes.h" extern const ArErr no_err; ArErr create_err(int64_t line, int64_t column, int length, char *path, const char *type, const char *fmt, ...); -void output_err(ArErr err); \ No newline at end of file +void output_err(ArErr err); +#endif // RETURN_TYPE_H \ No newline at end of file diff --git a/src/import.c b/src/import.c new file mode 100644 index 0000000..b399fb2 --- /dev/null +++ b/src/import.c @@ -0,0 +1,468 @@ +#include "../external/cwalk/include/cwalk.h" +#include "../external/xxhash/xxhash.h" +#include "arobject.h" +#include "err.h" +#include "hash_data/hash_data.h" +#include "hashmap/hashmap.h" +#include "lexer/lexer.h" +#include "lexer/token.h" +#include "runtime/internals/hashmap/hashmap.h" +#include "runtime/runtime.h" +#include "translator/translator.h" +#include +#include +#include +#include +#ifdef _WIN32 +#include // for _mkdir +#include // for _stat +#include +#else +#include +#include +#include +#endif +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include "err.h" +#include +#if defined(_WIN32) || defined(_WIN64) + +// Windows / MinGW usually uses little-endian, so these can be no-ops +// But define them explicitly to avoid implicit declaration warnings + +static inline uint32_t le32toh(uint32_t x) { return x; } +static inline uint64_t le64toh(uint64_t x) { return x; } +static inline uint32_t htole32(uint32_t x) { return x; } +static inline uint64_t htole64(uint64_t x) { return x; } + +#elif defined(__linux__) +#include +#include +#elif defined(__APPLE__) +#include +#define htole32(x) OSSwapHostToLittleInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) +// Add others as needed +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#include +#include +#endif + +int ensure_dir_exists(const char *path) { +#ifdef _WIN32 + struct _stat st; + if (_stat(path, &st) != 0) { + // Directory does not exist, create it + if (_mkdir(path) != 0) { + perror("_mkdir failed"); + return -1; + } + } else if (!(st.st_mode & _S_IFDIR)) { + fprintf(stderr, "Path exists but is not a directory\n"); + return -1; + } +#else + struct stat st; + if (stat(path, &st) != 0) { + // Directory does not exist, create it + if (mkdir(path, 0755) != 0) { + perror("mkdir failed"); + return -1; + } + } else if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "Path exists but is not a directory\n"); + return -1; + } +#endif + return 0; +} + +char *CWD; + +const char CACHE_FOLDER[] = "__arcache__"; +const char FILE_IDENTIFIER[5] = "ARBI"; +const char BYTECODE_EXTENTION[] = "arbin"; +const uint32_t version_number = 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 +} + +static inline void write_and_hash(FILE *file, XXH64_state_t *state, + const void *ptr, size_t size, size_t count) { + fwrite(ptr, size, count, file); + XXH64_update(state, ptr, size * count); +} + +static inline void update_hash_from_file(FILE *file, XXH64_state_t *state, + size_t size) { + char buffer[4096]; + size_t bytes_read; + size_t remaining = size; + + while (remaining > 0 && + (bytes_read = + fread(buffer, 1, + remaining > sizeof(buffer) ? sizeof(buffer) : remaining, + file)) > 0) { + XXH64_update(state, buffer, bytes_read); + remaining -= bytes_read; + } +} + +int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash, + char *source_path) { + FILE *bytecode_file = fopen(joined_paths, "rb"); + if (!bytecode_file) { + fprintf(stderr, "cache doesnt exist... compiling from source.\n"); + return 1; + } + + // Find file size + fseek(bytecode_file, 0, SEEK_END); + long file_size = ftell(bytecode_file); + if (file_size < (long)sizeof(uint64_t)) { + goto FAILED; + } + fseek(bytecode_file, 0, SEEK_SET); + + // Footer is the last 8 bytes + long data_size = file_size - sizeof(uint64_t); + + // Set up hash state + XXH64_state_t *state = XXH64_createState(); + XXH64_reset(state, 0); + + // Hash everything except last 8 bytes + update_hash_from_file(bytecode_file, state, data_size); + + // Read stored footer hash + uint64_t stored_hash_le; + if (fread(&stored_hash_le, 1, sizeof(stored_hash_le), bytecode_file) != + sizeof(stored_hash_le)) { + XXH64_freeState(state); + goto FAILED; + } + uint64_t stored_hash = le64toh(stored_hash_le); + + // Compare + uint64_t calc_hash = XXH64_digest(state); + XXH64_freeState(state); + + if (calc_hash != stored_hash) { + fprintf(stderr, "cache hash mismatch (corrupted?)\n"); + goto FAILED; + } + + // Now actually parse the file contents + fseek(bytecode_file, 0, SEEK_SET); // rewind to start + + char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0}; + if (fread(&file_identifier_from_cache, 1, + sizeof(file_identifier_from_cache) - 1, + bytecode_file) != sizeof(file_identifier_from_cache) - 1 || + memcmp(file_identifier_from_cache, FILE_IDENTIFIER, + sizeof(file_identifier_from_cache)) != 0) { + goto FAILED; + } + + uint32_t read_version; + if (fread(&read_version, 1, sizeof(read_version), bytecode_file) != + sizeof(read_version)) { + goto FAILED; + } + read_version = le32toh(read_version); + + if (read_version != version_number) { + goto FAILED; + } + + uint64_t read_hash; + if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) != + sizeof(read_hash)) { + goto FAILED; + } + read_hash = le64toh(read_hash); + + if (read_hash != hash) { + goto FAILED; + } + + uint8_t register_count; + if (fread(®ister_count, 1, sizeof(register_count), bytecode_file) != + sizeof(register_count)) { + goto FAILED; + } + + uint64_t constantsSize; + if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) != + sizeof(constantsSize)) { + goto FAILED; + } + constantsSize = le64toh(constantsSize); + + uint64_t bytecodeSize; + if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) != + sizeof(bytecodeSize)) { + goto FAILED; + } + bytecodeSize = le64toh(bytecodeSize); + + *translated_dest = init_translator(source_path); + + translated_dest->registerCount = register_count; + + arena_resize(&translated_dest->constants, constantsSize); + + if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) != + constantsSize) { + goto FAILED; + } + + translated_dest->constants.size = constantsSize; + + darray_resize(&translated_dest->bytecode, bytecodeSize); + + if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) != + bytecodeSize) { + goto FAILED; + } + + translated_dest->bytecode.size = bytecodeSize; + + fprintf(stderr, "cache exists and is valid, so will be used.\n"); + fclose(bytecode_file); + return 0; +FAILED: + fprintf(stderr, "cache is invalid... compiling from source.\n"); + fclose(bytecode_file); + return 1; +} + +Translated load_argon_file(char *path, ArErr *err) { + clock_t start, end; + clock_t beginning = clock(); + double time_spent, total_time_spent = 0; + + const char *basename_ptr; + size_t basename_length; + cwk_path_get_basename(path, &basename_ptr, &basename_length); + + if (!basename_ptr) { + *err = create_err(0, 0, 0, NULL, "Path Error", "path has no basename '%s'", + path); + return (Translated){}; + } + + char basename[FILENAME_MAX]; + memcpy(basename, basename_ptr, basename_length); + + size_t parent_directory_length; + cwk_path_get_dirname(path, &parent_directory_length); + + char parent_directory[FILENAME_MAX]; + memcpy(parent_directory, path, parent_directory_length); + parent_directory[parent_directory_length] = '\0'; + + char cache_folder_path[FILENAME_MAX]; + cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path, + sizeof(cache_folder_path)); + + char cache_file_path[FILENAME_MAX]; + cwk_path_join(cache_folder_path, basename, cache_file_path, + 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'", + path); + return (Translated){}; + } + + XXH3_state_t *hash_state = XXH3_createState(); + XXH3_64bits_reset(hash_state); + + char buffer[8192]; + size_t bytes; + while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) { + XXH3_64bits_update(hash_state, buffer, bytes); + } + rewind(file); + uint64_t hash = XXH3_64bits_digest(hash_state); + XXH3_freeState(hash_state); + + Translated translated; + + if (load_cache(&translated, cache_file_path, hash, path) != 0) { + + DArray tokens; + darray_init(&tokens, sizeof(Token)); + + LexerState state = {path, file, 0, 0, &tokens}; + start = clock(); + *err = lexer(state); + if (err->exists) { + darray_free(&tokens, free_token); + return (Translated){}; + } + end = clock(); + time_spent = (double)(end - start) / CLOCKS_PER_SEC; + fprintf(stderr, "Lexer time taken: %f seconds\n", time_spent); + fclose(state.file); + + DArray ast; + + darray_init(&ast, sizeof(ParsedValue)); + + start = clock(); + *err = parser(path, &ast, &tokens, false); + darray_free(&tokens, free_token); + if (err->exists) { + darray_free(&ast, free_parsed); + return (Translated){}; + } + end = clock(); + time_spent = (double)(end - start) / CLOCKS_PER_SEC; + fprintf(stderr, "Parser time taken: %f seconds\n", time_spent); + + start = clock(); + + translated = init_translator(path); + *err = translate(&translated, &ast); + darray_free(&ast, free_parsed); + if (err->exists) { + darray_free(&translated.bytecode, NULL); + free(translated.constants.data); + hashmap_free(translated.constants.hashmap, NULL); + return (Translated){}; + } + end = clock(); + time_spent = (double)(end - start) / CLOCKS_PER_SEC; + fprintf(stderr, "Translation time taken: %f seconds\n", time_spent); +#if defined(__linux__) + malloc_trim(0); +#endif + + ensure_dir_exists(cache_folder_path); + + file = fopen(cache_file_path, "wb"); + + uint64_t constantsSize = translated.constants.size; + uint64_t bytecodeSize = translated.bytecode.size; + + uint32_t version_number_htole32ed = htole32(version_number); + uint64_t net_hash = htole64(hash); + constantsSize = htole64(constantsSize); + bytecodeSize = htole64(bytecodeSize); + + XXH64_state_t *hash_state = XXH64_createState(); + XXH64_reset(hash_state, 0); + + write_and_hash(file, hash_state, &FILE_IDENTIFIER, sizeof(char), + strlen(FILE_IDENTIFIER)); + write_and_hash(file, hash_state, &version_number_htole32ed, + sizeof(uint32_t), 1); + write_and_hash(file, hash_state, &net_hash, sizeof(net_hash), 1); + write_and_hash(file, hash_state, &translated.registerCount, sizeof(uint8_t), + 1); + write_and_hash(file, hash_state, &constantsSize, sizeof(uint64_t), 1); + write_and_hash(file, hash_state, &bytecodeSize, sizeof(uint64_t), 1); + write_and_hash(file, hash_state, translated.constants.data, 1, + translated.constants.size); + write_and_hash(file, hash_state, translated.bytecode.data, + translated.bytecode.element_size, translated.bytecode.size); + + // Finalize the hash + uint64_t file_hash = XXH64_digest(hash_state); + XXH64_freeState(hash_state); + + // Convert to little-endian before writing if needed + uint64_t file_hash_le = htole64(file_hash); + fwrite(&file_hash_le, sizeof(file_hash_le), 1, file); + + fclose(file); + } + hashmap_free(translated.constants.hashmap, NULL); + Translated gc_translated = { + translated.registerCount, translated.registerAssignment, NULL, {}, {}, + translated.path}; + gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity); + memcpy(gc_translated.bytecode.data, translated.bytecode.data, + translated.bytecode.capacity); + gc_translated.bytecode.element_size = translated.bytecode.element_size; + gc_translated.bytecode.size = translated.bytecode.size; + gc_translated.bytecode.resizable = false; + gc_translated.bytecode.capacity = + translated.bytecode.size * translated.bytecode.element_size; + gc_translated.constants.data = ar_alloc_atomic(translated.constants.capacity); + memcpy(gc_translated.constants.data, translated.constants.data, + translated.constants.capacity); + gc_translated.constants.size = translated.constants.size; + gc_translated.constants.capacity = translated.constants.capacity; + free(translated.bytecode.data); + free(translated.constants.data); + total_time_spent = (double)(clock() - beginning) / CLOCKS_PER_SEC; + fprintf(stderr, "total time taken loading file (%s): %f seconds\n", path, + total_time_spent); + return gc_translated; +} + +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"}; + +struct hashmap *importing_hash_table = NULL; +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)); + 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)) { + found = true; + break; + } + } + if (!found) { + *err = create_err(0, 0, 0, NULL, "File Error", "Unable to find file '%s'", + path_relative); + return NULL; + } + 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); + Translated translated = load_argon_file(path, err); + if (err->exists) { + return NULL; + } + clock_t start = clock(), end; + RuntimeState state = init_runtime_state(translated, path); + Stack *main_scope = create_scope(Global_Scope, true); + runtime(translated, state, main_scope, err); + if (err->exists) { + return NULL; + } + 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_GC(imported_hash_table, hash, path, main_scope, 0); + return main_scope; +} \ No newline at end of file diff --git a/src/import.h b/src/import.h new file mode 100644 index 0000000..a969326 --- /dev/null +++ b/src/import.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef IMPORT_H +#define IMPORT_H +#include "err.h" + +extern char*CWD; + +Stack *ar_import(char *current_directory, char *path_relative, ArErr *err); + +#endif // IMPORT_H \ No newline at end of file diff --git a/src/main.c b/src/main.c index 1f83d95..66186f2 100644 --- a/src/main.c +++ b/src/main.c @@ -4,75 +4,20 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -#include "arobject.h" -#include "dynamic_array/darray.h" +#include "err.h" #include "hashmap/hashmap.h" -#include "lexer/lexer.h" -#include "lexer/token.h" +#include "import.h" #include "memory.h" -#include "parser/parser.h" -#include "returnTypes.h" #include "runtime/objects/object.h" -#include "runtime/runtime.h" #include "shell.h" -#include "translator/translator.h" -#include "../external/xxhash/xxhash.h" #include "hash_data/hash_data.h" #include #include #include #include -#include #include -#include -#include #include -#ifdef _WIN32 -#include // for _mkdir -#include // for _stat -#include -#else -#include -#include -#include -#endif -#include "../external/cwalk/include/cwalk.h" -#include - -#ifdef _WIN32 -#include -#else -#include -#include -#endif -#include "err.h" -#include - -#if defined(_WIN32) || defined(_WIN64) - -// Windows / MinGW usually uses little-endian, so these can be no-ops -// But define them explicitly to avoid implicit declaration warnings - -static inline uint32_t le32toh(uint32_t x) { return x; } -static inline uint64_t le64toh(uint64_t x) { return x; } -static inline uint32_t htole32(uint32_t x) { return x; } -static inline uint64_t htole64(uint64_t x) { return x; } - -#elif defined(__linux__) -#include -#include -#elif defined(__APPLE__) -#include -#define htole32(x) OSSwapHostToLittleInt32(x) -#define le32toh(x) OSSwapLittleToHostInt32(x) -#define htole64(x) OSSwapHostToLittleInt64(x) -#define le64toh(x) OSSwapLittleToHostInt64(x) -// Add others as needed -#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) -#include -#include -#endif char *get_current_directory() { char *buffer = NULL; @@ -102,392 +47,24 @@ char *get_current_directory() { return buffer; } -int ensure_dir_exists(const char *path) { -#ifdef _WIN32 - struct _stat st; - if (_stat(path, &st) != 0) { - // Directory does not exist, create it - if (_mkdir(path) != 0) { - perror("_mkdir failed"); - return -1; - } - } else if (!(st.st_mode & _S_IFDIR)) { - fprintf(stderr, "Path exists but is not a directory\n"); - return -1; - } -#else - struct stat st; - if (stat(path, &st) != 0) { - // Directory does not exist, create it - if (mkdir(path, 0755) != 0) { - perror("mkdir failed"); - return -1; - } - } else if (!S_ISDIR(st.st_mode)) { - fprintf(stderr, "Path exists but is not a directory\n"); - return -1; - } -#endif - return 0; -} - -static inline void write_and_hash(FILE *file, XXH64_state_t *state, - const void *ptr, size_t size, size_t count) { - fwrite(ptr, size, count, file); - XXH64_update(state, ptr, size * count); -} - -static inline void update_hash_from_file(FILE *file, XXH64_state_t *state, - size_t size) { - char buffer[4096]; - size_t bytes_read; - size_t remaining = size; - - while (remaining > 0 && - (bytes_read = - fread(buffer, 1, - remaining > sizeof(buffer) ? sizeof(buffer) : remaining, - file)) > 0) { - XXH64_update(state, buffer, bytes_read); - remaining -= bytes_read; - } -} - -const char CACHE_FOLDER[] = "__arcache__"; -const char FILE_IDENTIFIER[5] = "ARBI"; -const char BYTECODE_EXTENTION[] = "arbin"; -const uint32_t version_number = 0; - -int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash, - char *source_path) { - FILE *bytecode_file = fopen(joined_paths, "rb"); - if (!bytecode_file) { - fprintf(stderr, "cache doesnt exist... compiling from source.\n"); - return 1; - } - - // Find file size - fseek(bytecode_file, 0, SEEK_END); - long file_size = ftell(bytecode_file); - if (file_size < (long)sizeof(uint64_t)) { - goto FAILED; - } - fseek(bytecode_file, 0, SEEK_SET); - - // Footer is the last 8 bytes - long data_size = file_size - sizeof(uint64_t); - - // Set up hash state - XXH64_state_t *state = XXH64_createState(); - XXH64_reset(state, 0); - - // Hash everything except last 8 bytes - update_hash_from_file(bytecode_file, state, data_size); - - // Read stored footer hash - uint64_t stored_hash_le; - if (fread(&stored_hash_le, 1, sizeof(stored_hash_le), bytecode_file) != - sizeof(stored_hash_le)) { - XXH64_freeState(state); - goto FAILED; - } - uint64_t stored_hash = le64toh(stored_hash_le); - - // Compare - uint64_t calc_hash = XXH64_digest(state); - XXH64_freeState(state); - - if (calc_hash != stored_hash) { - fprintf(stderr, "cache hash mismatch (corrupted?)\n"); - goto FAILED; - } - - // Now actually parse the file contents - fseek(bytecode_file, 0, SEEK_SET); // rewind to start - - char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0}; - if (fread(&file_identifier_from_cache, 1, - sizeof(file_identifier_from_cache) - 1, - bytecode_file) != sizeof(file_identifier_from_cache) - 1 || - memcmp(file_identifier_from_cache, FILE_IDENTIFIER, - sizeof(file_identifier_from_cache)) != 0) { - goto FAILED; - } - - uint32_t read_version; - if (fread(&read_version, 1, sizeof(read_version), bytecode_file) != - sizeof(read_version)) { - goto FAILED; - } - read_version = le32toh(read_version); - - if (read_version != version_number) { - goto FAILED; - } - - uint64_t read_hash; - if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) != - sizeof(read_hash)) { - goto FAILED; - } - read_hash = le64toh(read_hash); - - if (read_hash != hash) { - goto FAILED; - } - - uint8_t register_count; - if (fread(®ister_count, 1, sizeof(register_count), bytecode_file) != - sizeof(register_count)) { - goto FAILED; - } - - uint64_t constantsSize; - if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) != - sizeof(constantsSize)) { - goto FAILED; - } - constantsSize = le64toh(constantsSize); - - uint64_t bytecodeSize; - if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) != - sizeof(bytecodeSize)) { - goto FAILED; - } - bytecodeSize = le64toh(bytecodeSize); - - *translated_dest = init_translator(source_path); - - - translated_dest->registerCount = register_count; - - arena_resize(&translated_dest->constants, constantsSize); - - if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) != - constantsSize) { - goto FAILED; - } - - translated_dest->constants.size = constantsSize; - - darray_resize(&translated_dest->bytecode, bytecodeSize); - - if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) != - bytecodeSize) { - goto FAILED; - } - - translated_dest->bytecode.size = bytecodeSize; - - fprintf(stderr, "cache exists and is valid, so will be used.\n"); - fclose(bytecode_file); - return 0; -FAILED: - fprintf(stderr, "cache is invalid... compiling from source.\n"); - fclose(bytecode_file); - return 1; -} - -Translated load_argon_file(char *path, ArErr *err) { - clock_t start, end; - clock_t beginning = clock(); - double time_spent, total_time_spent = 0; - - const char *basename_ptr; - size_t basename_length; - cwk_path_get_basename(path, &basename_ptr, &basename_length); - - if (!basename_ptr) { - *err = create_err(0, 0, 0, NULL, "Path Error", "path has no basename '%s'", - path); - return (Translated){}; - } - - char basename[FILENAME_MAX]; - memcpy(basename, basename_ptr, basename_length); - - size_t parent_directory_length; - cwk_path_get_dirname(path, &parent_directory_length); - - char parent_directory[FILENAME_MAX]; - memcpy(parent_directory, path, parent_directory_length); - parent_directory[parent_directory_length] = '\0'; - - char cache_folder_path[FILENAME_MAX]; - cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path, - sizeof(cache_folder_path)); - - char cache_file_path[FILENAME_MAX]; - cwk_path_join(cache_folder_path, basename, cache_file_path, - 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'", - path); - return (Translated){}; - } - - XXH3_state_t *hash_state = XXH3_createState(); - XXH3_64bits_reset(hash_state); - - char buffer[8192]; - size_t bytes; - while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) { - XXH3_64bits_update(hash_state, buffer, bytes); - } - rewind(file); - uint64_t hash = XXH3_64bits_digest(hash_state); - XXH3_freeState(hash_state); - - Translated translated; - - if (load_cache(&translated, cache_file_path, hash, path) != 0) { - - DArray tokens; - darray_init(&tokens, sizeof(Token)); - - LexerState state = {path, file, 0, 0, &tokens}; - start = clock(); - *err = lexer(state); - if (err->exists) { - darray_free(&tokens, free_token); - return (Translated){}; - } - end = clock(); - time_spent = (double)(end - start) / CLOCKS_PER_SEC; - fprintf(stderr, "Lexer time taken: %f seconds\n", time_spent); - fclose(state.file); - - DArray ast; - - darray_init(&ast, sizeof(ParsedValue)); - - start = clock(); - *err = parser(path, &ast, &tokens, false); - darray_free(&tokens, free_token); - if (err->exists) { - darray_free(&ast, free_parsed); - return (Translated){}; - } - end = clock(); - time_spent = (double)(end - start) / CLOCKS_PER_SEC; - fprintf(stderr, "Parser time taken: %f seconds\n", time_spent); - - start = clock(); - - translated = init_translator(path); - *err = translate(&translated, &ast); - darray_free(&ast, free_parsed); - if (err->exists) { - darray_free(&translated.bytecode, NULL); - free(translated.constants.data); - hashmap_free(translated.constants.hashmap, NULL); - return (Translated){}; - } - end = clock(); - time_spent = (double)(end - start) / CLOCKS_PER_SEC; - fprintf(stderr, "Translation time taken: %f seconds\n", time_spent); -#if defined(__linux__) - malloc_trim(0); -#endif - - ensure_dir_exists(cache_folder_path); - - file = fopen(cache_file_path, "wb"); - - uint64_t constantsSize = translated.constants.size; - uint64_t bytecodeSize = translated.bytecode.size; - - uint32_t version_number_htole32ed = htole32(version_number); - uint64_t net_hash = htole64(hash); - constantsSize = htole64(constantsSize); - bytecodeSize = htole64(bytecodeSize); - - XXH64_state_t *hash_state = XXH64_createState(); - XXH64_reset(hash_state, 0); - - write_and_hash(file, hash_state, &FILE_IDENTIFIER, sizeof(char), - strlen(FILE_IDENTIFIER)); - write_and_hash(file, hash_state, &version_number_htole32ed, - sizeof(uint32_t), 1); - write_and_hash(file, hash_state, &net_hash, sizeof(net_hash), 1); - write_and_hash(file, hash_state, &translated.registerCount, sizeof(uint8_t), - 1); - write_and_hash(file, hash_state, &constantsSize, sizeof(uint64_t), 1); - write_and_hash(file, hash_state, &bytecodeSize, sizeof(uint64_t), 1); - write_and_hash(file, hash_state, translated.constants.data, 1, - translated.constants.size); - write_and_hash(file, hash_state, translated.bytecode.data, - translated.bytecode.element_size, translated.bytecode.size); - - // Finalize the hash - uint64_t file_hash = XXH64_digest(hash_state); - XXH64_freeState(hash_state); - - // Convert to little-endian before writing if needed - uint64_t file_hash_le = htole64(file_hash); - fwrite(&file_hash_le, sizeof(file_hash_le), 1, file); - - fclose(file); - } - hashmap_free(translated.constants.hashmap, NULL); - Translated gc_translated = { - translated.registerCount, translated.registerAssignment, NULL, {}, {}, - translated.path}; - gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity); - memcpy(gc_translated.bytecode.data, translated.bytecode.data, - translated.bytecode.capacity); - gc_translated.bytecode.element_size = translated.bytecode.element_size; - gc_translated.bytecode.size = translated.bytecode.size; - gc_translated.bytecode.resizable = false; - gc_translated.bytecode.capacity = - translated.bytecode.size * translated.bytecode.element_size; - gc_translated.constants.data = ar_alloc_atomic(translated.constants.capacity); - memcpy(gc_translated.constants.data, translated.constants.data, - translated.constants.capacity); - gc_translated.constants.size = translated.constants.size; - gc_translated.constants.capacity =translated.constants.capacity; - free(translated.bytecode.data); - free(translated.constants.data); - total_time_spent = (double)(clock() - beginning) / CLOCKS_PER_SEC; - fprintf(stderr, "total time taken loading file (%s): %f seconds\n", path, - total_time_spent); - return gc_translated; -} - int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); ar_memory_init(); generate_siphash_key(siphash_key); - init_built_in_field_hashes(); bootstrap_types(); bootstrap_globals(); if (argc <= 1) return shell(); - char *CWD = get_current_directory(); + CWD = get_current_directory(); char *path_non_absolute = argv[1]; - char path[FILENAME_MAX]; - cwk_path_get_absolute(CWD, path_non_absolute, path, sizeof(path)); - free(CWD); ArErr err = no_err; - Translated translated = load_argon_file(path, &err); + ar_import(CWD, path_non_absolute, &err); if (err.exists) { output_err(err); return 1; } - clock_t start = clock(), end; - RuntimeState state = init_runtime_state(translated, path); - Stack *main_scope = create_scope(Global_Scope, true); - runtime(translated, state, main_scope, &err); - - end = clock(); - double time_spent = (double)(end - start) / CLOCKS_PER_SEC; - fprintf(stderr, "Execution time taken: %f seconds\n", time_spent); - + free(CWD); if (runtime_hash_table) hashmap_free(runtime_hash_table, NULL); if (err.exists) { diff --git a/src/runtime/access/access.c b/src/runtime/access/access.c deleted file mode 100644 index 3e72a37..0000000 --- a/src/runtime/access/access.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 William Bell - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ -#include "access.h" -#include - -ArgonObject *ARGON_TYPE_TYPE___get_attr__(size_t argc, ArgonObject **argv, - ArErr *err, RuntimeState *state) { - (void)state; - if (argc != 3) { - *err = create_err(0, 0, 0, "", "Runtime Error", - "__get_attr__ expects 3 arguments, got %" PRIu64); - return ARGON_NULL; - } - ArgonObject *to_access = argv[0]; - bool check_field = argv[1] == ARGON_TRUE; - if (check_field) { - ArgonObject *access = argv[2]; - uint64_t hash; - if (access->value.as_str.hash_computed) { - hash = access->value.as_str.hash; - } else { - hash = - runtime_hash(access->value.as_str.data, access->value.as_str.length, - access->value.as_str.prehash); - access->value.as_str.hash = hash; - access->value.as_str.hash_computed = true; - } - ArgonObject *value = get_field_l(to_access, access->value.as_str.data, hash, - access->value.as_str.length, true, false); - if (value) - return value; - ArgonObject *name = get_builtin_field_for_class( - get_builtin_field(to_access, __class__, false, false), __name__, - to_access); - *err = create_err( - 0, 0, 0, "", "Runtime Error", "'%.*s' object has no attribute '%.*s'", - (int)name->value.as_str.length, name->value.as_str.data, - (int)access->value.as_str.length, access->value.as_str.data); - } - return ARGON_NULL; -} \ No newline at end of file diff --git a/src/runtime/access/access.h b/src/runtime/access/access.h deleted file mode 100644 index 959ed53..0000000 --- a/src/runtime/access/access.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 William Bell - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#ifndef runtime_access_H -#define runtime_access_H -#include "../objects/literals/literals.h" -#include "../objects/object.h" -#include "../runtime.h" -#include - -ArgonObject *ARGON_TYPE_TYPE___get_attr__(size_t argc, ArgonObject **argv, - ArErr *err, RuntimeState *state); - -#endif // runtime_access_H \ No newline at end of file diff --git a/src/runtime/call/call.c b/src/runtime/call/call.c index 5a028ed..bf3ea4f 100644 --- a/src/runtime/call/call.c +++ b/src/runtime/call/call.c @@ -85,7 +85,7 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, if (object->type != TYPE_FUNCTION && object->type != TYPE_NATIVE_FUNCTION && object->type != TYPE_METHOD) { ArgonObject *call_method = get_builtin_field_for_class( - get_builtin_field(object, __class__, false, false), __call__, + get_builtin_field(object, __class__), __call__, original_object); if (call_method) { object = call_method; @@ -93,7 +93,7 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, } if (object->type == TYPE_METHOD) { ArgonObject *binding_object = - get_builtin_field(object, __binding__, false, false); + get_builtin_field(object, __binding__); if (binding_object) { ArgonObject **new_call_args = ar_alloc(sizeof(ArgonObject *) * (argc + 1)); @@ -105,14 +105,14 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, argc++; } ArgonObject *function_object = - get_builtin_field(object, __function__, false, false); + get_builtin_field(object, __function__); if (function_object) object = function_object; } if (object->type == TYPE_FUNCTION) { if (argc != object->value.argon_fn.number_of_parameters) { ArgonObject *type_object_name = get_builtin_field_for_class( - get_builtin_field(object, __class__, false, false), __name__, + get_builtin_field(object, __class__), __name__, original_object); ArgonObject *object_name = get_builtin_field_for_class(object, __name__, original_object); @@ -196,7 +196,7 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, return; } ArgonObject *type_object_name = get_builtin_field_for_class( - get_builtin_field(original_object, __class__, false, false), __name__, + get_builtin_field(original_object, __class__), __name__, original_object); *err = create_err(state->source_location.line, state->source_location.column, state->source_location.length, state->path, "Type Error", diff --git a/src/runtime/internals/hashmap/hashmap.c b/src/runtime/internals/hashmap/hashmap.c index 8312bcb..b637c82 100644 --- a/src/runtime/internals/hashmap/hashmap.c +++ b/src/runtime/internals/hashmap/hashmap.c @@ -27,7 +27,7 @@ struct hashmap_GC *createHashmap_GC() { } void clear_hashmap_GC(struct hashmap_GC *t) { - if (!t->hashmap_count) + if (!t->count) return; t->order = 1; t->count = 0; diff --git a/src/runtime/objects/functions/functions.c b/src/runtime/objects/functions/functions.c index 365b48e..f5bc757 100644 --- a/src/runtime/objects/functions/functions.c +++ b/src/runtime/objects/functions/functions.c @@ -15,8 +15,7 @@ ArgonObject *ARGON_FUNCTION_TYPE = NULL; ArgonObject *create_argon_native_function(char *name, native_fn native_fn) { - ArgonObject *object = new_object(); - add_builtin_field(object, __class__, ARGON_FUNCTION_TYPE); + ArgonObject *object = new_instance(ARGON_FUNCTION_TYPE); object->type = TYPE_NATIVE_FUNCTION; add_builtin_field(object, __name__, new_string_object(name, strlen(name), 0, 0)); @@ -26,8 +25,7 @@ ArgonObject *create_argon_native_function(char *name, native_fn native_fn) { void load_argon_function(Translated *translated, RuntimeState *state, struct Stack *stack) { - ArgonObject *object = new_object(); - add_builtin_field(object, __class__, ARGON_FUNCTION_TYPE); + ArgonObject *object = new_instance(ARGON_FUNCTION_TYPE); object->type = TYPE_FUNCTION; uint64_t offset = pop_bytecode(translated, state); uint64_t length = pop_bytecode(translated, state); diff --git a/src/runtime/objects/number/number.c b/src/runtime/objects/number/number.c index 7a87f75..2d6c687 100644 --- a/src/runtime/objects/number/number.c +++ b/src/runtime/objects/number/number.c @@ -37,7 +37,7 @@ ArgonObject *ARGON_NUMBER_TYPE___new__(size_t argc, ArgonObject **argv, self->type = TYPE_STRING; ArgonObject *boolean_convert_method = get_builtin_field_for_class( - get_builtin_field(object, __class__, false, false), __number__, object); + get_builtin_field(object, __class__), __number__, object); if (boolean_convert_method) { ArgonObject *boolean_object = argon_call(boolean_convert_method, 0, NULL, err, state); @@ -46,7 +46,7 @@ ArgonObject *ARGON_NUMBER_TYPE___new__(size_t argc, ArgonObject **argv, return boolean_object; } ArgonObject *type_name = get_builtin_field_for_class( - get_builtin_field(object, __class__, false, false), __name__, object); + get_builtin_field(object, __class__), __name__, object); *err = create_err( 0, 0, 0, "", "Runtime Error", "cannot convert type '%.*s' to number", type_name->value.as_str.length, type_name->value.as_str.data); @@ -85,7 +85,7 @@ ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv, } if (argv[1]->type != TYPE_NUMBER) { ArgonObject *type_name = get_builtin_field_for_class( - get_builtin_field(argv[1], __class__, false, false), __name__, argv[1]); + get_builtin_field(argv[1], __class__), __name__, argv[1]); *err = create_err( 0, 0, 0, "", "Runtime Error", "__add__ cannot perform addition between a number and %.*s", @@ -148,7 +148,7 @@ ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv, } if (argv[1]->type != TYPE_NUMBER) { ArgonObject *type_name = get_builtin_field_for_class( - get_builtin_field(argv[1], __class__, false, false), __name__, argv[1]); + get_builtin_field(argv[1], __class__), __name__, argv[1]); *err = create_err( 0, 0, 0, "", "Runtime Error", "__subtract__ cannot perform subtraction between number and %.*s", @@ -213,7 +213,7 @@ ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv, } if (argv[1]->type != TYPE_NUMBER) { ArgonObject *type_name = get_builtin_field_for_class( - get_builtin_field(argv[1], __class__, false, false), __name__, argv[1]); + get_builtin_field(argv[1], __class__), __name__, argv[1]); *err = create_err( 0, 0, 0, "", "Runtime Error", "__multiply__ cannot perform multiplication between number and %.*s", @@ -278,7 +278,7 @@ ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv, } if (argv[1]->type != TYPE_NUMBER) { ArgonObject *type_name = get_builtin_field_for_class( - get_builtin_field(argv[1], __class__, false, false), __name__, argv[1]); + get_builtin_field(argv[1], __class__), __name__, argv[1]); *err = create_err( 0, 0, 0, "", "Runtime Error", "__division__ cannot perform division between number and %.*s", @@ -288,6 +288,13 @@ ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv, if (argv[0]->value.as_number.is_int64 && argv[1]->value.as_number.is_int64) { int64_t a = argv[0]->value.as_number.n.i64; int64_t b = argv[1]->value.as_number.n.i64; + if (!b) { + *err = + create_err(state->source_location.line, state->source_location.column, + state->source_location.length, state->path, + "Zero Division Error", "division by zero"); + return NULL; + } return new_number_object_from_num_and_den(a, b); } else if (!argv[0]->value.as_number.is_int64 && !argv[1]->value.as_number.is_int64) { @@ -307,6 +314,13 @@ ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv, mpq_set(b_GMP, *argv[1]->value.as_number.n.mpq); } else { mpq_set(a_GMP, *argv[0]->value.as_number.n.mpq); + if (!argv[1]->value.as_number.n.i64) { + *err = create_err(state->source_location.line, + state->source_location.column, + state->source_location.length, state->path, + "Zero Division Error", "division by zero"); + return NULL; + } mpq_set_si(b_GMP, argv[1]->value.as_number.n.i64, 1); } mpq_div(a_GMP, a_GMP, b_GMP); @@ -492,7 +506,7 @@ void init_small_ints() { } void create_ARGON_NUMBER_TYPE() { - ARGON_NUMBER_TYPE = new_object(); + ARGON_NUMBER_TYPE = new_class(); add_builtin_field(ARGON_NUMBER_TYPE, __name__, new_string_object_null_terminated("number")); add_builtin_field( @@ -600,8 +614,7 @@ ArgonObject *new_number_object(mpq_t number) { if (is_int64 && i64 >= small_ints_min && i64 <= small_ints_max) { return &small_ints[i64 - small_ints_min]; } - ArgonObject *object = new_object(); - add_builtin_field(object, __class__, ARGON_NUMBER_TYPE); + ArgonObject *object = new_instance(ARGON_NUMBER_TYPE); object->type = TYPE_NUMBER; object->value.as_number.n.i64 = i64; object->value.as_number.is_int64 = is_int64; @@ -618,8 +631,7 @@ ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d) { if (d == 1 && n >= small_ints_min && n <= small_ints_max) { return &small_ints[n - small_ints_min]; } - ArgonObject *object = new_object(); - add_builtin_field(object, __class__, ARGON_NUMBER_TYPE); + ArgonObject *object = new_instance(ARGON_NUMBER_TYPE); object->type = TYPE_NUMBER; if (d == 1) { object->value.as_number.is_int64 = true; @@ -641,8 +653,7 @@ ArgonObject *new_number_object_from_int64(int64_t i64) { if (i64 >= small_ints_min && i64 <= small_ints_max) { return &small_ints[i64 - small_ints_min]; } - ArgonObject *object = new_object(); - add_builtin_field(object, __class__, ARGON_NUMBER_TYPE); + ArgonObject *object = new_instance(ARGON_NUMBER_TYPE); object->type = TYPE_NUMBER; object->value.as_number.is_int64 = true; object->value.as_number.n.i64 = i64; @@ -656,8 +667,7 @@ ArgonObject *new_number_object_from_double(double d) { if (is_int64 && i64 >= small_ints_min && i64 <= small_ints_max) { return &small_ints[i64 - small_ints_min]; } - ArgonObject *object = new_object(); - add_builtin_field(object, __class__, ARGON_NUMBER_TYPE); + ArgonObject *object = new_instance(ARGON_NUMBER_TYPE); object->type = TYPE_NUMBER; object->value.as_number.n.i64 = i64; object->value.as_number.is_int64 = is_int64; diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index b0bd36b..0e2df97 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -5,7 +5,6 @@ */ #include "object.h" -#include "../../hash_data/hash_data.h" #include "../../memory.h" #include "type/type.h" #include @@ -20,35 +19,48 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = { "__string__", "__subtract__", "__multiply__", "__division__", "__new__", "__init__", "__boolean__", "__get_attr__", "__binding__", "__function__", "address", "__call__", - "__number__", "log", "length"}; + "__number__", "log", "length", "__getattribute__"}; -uint64_t built_in_field_hashes[BUILT_IN_FIELDS_COUNT]; ArgonObject *new_object() { ArgonObject *object = ar_alloc(sizeof(ArgonObject)); + memset(object->Builtin_slots, 0, sizeof(object->Builtin_slots)); object->type = TYPE_OBJECT; - object->dict = createHashmap_GC(); - add_builtin_field(object, __class__, ARGON_TYPE_TYPE); - add_builtin_field(object, __base__, BASE_CLASS); + object->dict = NULL; object->as_bool = true; return object; } -void init_built_in_field_hashes() { - for (int i = 0; i < BUILT_IN_FIELDS_COUNT; i++) { - built_in_field_hashes[i] = siphash64_bytes( - built_in_field_names[i], strlen(built_in_field_names[i]), siphash_key); - } +ArgonObject *new_class() { + ArgonObject *object = new_object(); + add_builtin_field(object, __class__, ARGON_TYPE_TYPE); + add_builtin_field(object, __base__, BASE_CLASS); + return object; } -void add_builtin_field(ArgonObject *target, built_in_fields field, - ArgonObject *object) { - hashmap_insert_GC(target->dict, built_in_field_hashes[field], - (char *)built_in_field_names[field], object, 0); +ArgonObject *new_instance(ArgonObject *of) { + ArgonObject *object = new_object(); + add_builtin_field(object, __class__, of); + return object; +} + +inline void add_builtin_field(ArgonObject *target, built_in_fields field, + ArgonObject *object) { + target->Builtin_slots[field] = object; + // hashmap_insert_GC(target->dict, built_in_field_hashes[field], + // (char *)built_in_field_names[field], object, 0); } void add_field(ArgonObject *target, char *name, uint64_t hash, ArgonObject *object) { + for (size_t i = 0; i < BUILT_IN_FIELDS_COUNT; i++) { + if (strcmp(name, built_in_field_names[i])) { + target->Builtin_slots[i] = object; + return; + } + } + if (!object->dict) + object->dict = createHashmap_GC(); hashmap_insert_GC(target->dict, hash, name, object, 0); } @@ -60,7 +72,7 @@ ArgonObject *bind_object_to_function(ArgonObject *object, add_builtin_field(bound_method_wrapper, __binding__, object); add_builtin_field(bound_method_wrapper, __function__, function); ArgonObject *function_name = - get_builtin_field(function, __name__, false, false); + get_builtin_field(function, __name__); if (function_name) add_builtin_field(bound_method_wrapper, __name__, function_name); return bound_method_wrapper; @@ -79,7 +91,7 @@ ArgonObject *get_field_for_class_l(ArgonObject *target, char *name, } return object; } - target = get_builtin_field(target, __base__, false, false); + target = get_builtin_field(target, __base__); } return NULL; } @@ -87,6 +99,13 @@ ArgonObject *get_field_for_class_l(ArgonObject *target, char *name, ArgonObject *get_field_l(ArgonObject *target, char *name, uint64_t hash, size_t length, bool recursive, bool disable_method_wrapper) { + for (size_t i = 0; i < BUILT_IN_FIELDS_COUNT; i++) { + if (strcmp(name, built_in_field_names[i])) { + return target->Builtin_slots[i]; + } + } + if (!target->dict) + return NULL; ArgonObject *object = hashmap_lookup_GC(target->dict, hash); if (!recursive || object) return object; @@ -94,38 +113,35 @@ ArgonObject *get_field_l(ArgonObject *target, char *name, uint64_t hash, if (disable_method_wrapper) binding = NULL; return get_field_for_class_l( - hashmap_lookup_GC(target->dict, built_in_field_hashes[__class__]), name, + get_builtin_field(target, __class__), name, hash, length, binding); } ArgonObject *get_builtin_field_for_class(ArgonObject *target, built_in_fields field, ArgonObject *binding_object) { - while (target) { - ArgonObject *object = get_builtin_field(target, field, false, false); - if (object) { - if ((object->type == TYPE_FUNCTION || - object->type == TYPE_NATIVE_FUNCTION) && - binding_object) { - object = bind_object_to_function(binding_object, object); - } - return object; + ArgonObject *object = get_builtin_field(target, field); + if (object) { + if ((object->type == TYPE_FUNCTION || + object->type == TYPE_NATIVE_FUNCTION) && + binding_object) { + object = bind_object_to_function(binding_object, object); } - target = get_builtin_field(target, __base__, false, false); + return object; } return NULL; } -ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field, - bool recursive, bool disable_method_wrapper) { - ArgonObject *object = - hashmap_lookup_GC(target->dict, built_in_field_hashes[field]); - if (!recursive || object) - return object; - ArgonObject *binding = target; - if (disable_method_wrapper) - binding = NULL; - return get_builtin_field_for_class( - hashmap_lookup_GC(target->dict, built_in_field_hashes[__class__]), field, - binding); +ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field) { + return target->Builtin_slots[field]; + // ArgonObject *object = + // hashmap_lookup_GC(target->dict, built_in_field_hashes[field]); + // if (!recursive || object) + // return object; + // ArgonObject *binding = target; + // if (disable_method_wrapper) + // binding = NULL; + // return get_builtin_field_for_class( + // hashmap_lookup_GC(target->dict, built_in_field_hashes[__class__]), + // field, binding); } \ No newline at end of file diff --git a/src/runtime/objects/object.h b/src/runtime/objects/object.h index 1e6e1cc..2dfe02b 100644 --- a/src/runtime/objects/object.h +++ b/src/runtime/objects/object.h @@ -11,35 +11,12 @@ #include #include -typedef enum { - __base__, - __class__, - __name__, - __add__, - __string__, - __subtract__, - __multiply__, - __division__, - __new__, - __init__, - __boolean__, - __get_attr__, - __binding__, - __function__, - field__address, - __call__, - __number__, - field_log, - field_length, - BUILT_IN_FIELDS_COUNT -} built_in_fields; - -void init_built_in_field_hashes(); - extern ArgonObject *BASE_CLASS; typedef struct ArgonObject ArgonObject; -ArgonObject *new_object(); + +ArgonObject *new_class(); +ArgonObject *new_instance(ArgonObject * of); void add_builtin_field(ArgonObject *target, built_in_fields field, ArgonObject *object); @@ -62,7 +39,6 @@ ArgonObject *get_builtin_field_for_class(ArgonObject *target, built_in_fields field, ArgonObject *binding_object); -ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field, - bool recursive, bool disable_method_wrapper); +ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field); #endif // OBJECT_H \ No newline at end of file diff --git a/src/runtime/objects/string/string.c b/src/runtime/objects/string/string.c index e56edbd..5b1b889 100644 --- a/src/runtime/objects/string/string.c +++ b/src/runtime/objects/string/string.c @@ -15,8 +15,7 @@ ArgonObject *ARGON_STRING_TYPE = NULL; ArgonObject *new_string_object_without_memcpy(char *data, size_t length, uint64_t prehash, uint64_t hash) { - ArgonObject *object = new_object(); - add_builtin_field(object, __class__, ARGON_STRING_TYPE); + ArgonObject *object = new_instance(ARGON_STRING_TYPE); add_builtin_field(object, field_length, new_number_object_from_int64(length)); object->type = TYPE_STRING; diff --git a/src/runtime/objects/term/term.c b/src/runtime/objects/term/term.c index 8666b2c..75fd6e5 100644 --- a/src/runtime/objects/term/term.c +++ b/src/runtime/objects/term/term.c @@ -14,7 +14,7 @@ ArgonObject *term_log(size_t argc, ArgonObject **argv, ArErr *err, if (i != 0) printf(" "); ArgonObject *string_convert_method = get_builtin_field_for_class( - get_builtin_field(argv[i], __class__, false, false), __string__, argv[i]); + get_builtin_field(argv[i], __class__), __string__, argv[i]); if (string_convert_method) { ArgonObject *string_object = diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index b80bb87..e985f1e 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -9,7 +9,6 @@ #include "../hash_data/hash_data.h" #include "../parser/number/number.h" #include "../translator/translator.h" -#include "access/access.h" #include "assignment/assignment.h" #include "call/call.h" #include "declaration/declaration.h" @@ -34,7 +33,7 @@ ArgonObject *ARGON_METHOD_TYPE; Stack *Global_Scope = NULL; -ArgonObject *ACCESS_FUNCTION; +ArgonObject *GETATTRIBUTE_FUNCTION; ArgonObject *ADDITION_FUNCTION; ArgonObject *SUBTRACTION_FUNCTION; ArgonObject *MULTIPLY_FUNCTION; @@ -43,6 +42,53 @@ ArgonObject *POWER_FUNCTION; ArgonObject *MODULO_FUNCTION; ArgonObject *FLOORDIVISION_FUNCTION; +ArgonObject *BASE_CLASS___getattribute__(size_t argc, ArgonObject **argv, + ArErr *err, RuntimeState *state) { + (void)state; + if (argc != 3) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__getattribute__ expects 3 arguments, got %" PRIu64); + return ARGON_NULL; + } + ArgonObject *to_access = argv[0]; + bool check_field = argv[1] == ARGON_TRUE; + if (check_field) { + ArgonObject *access = argv[2]; + uint64_t hash; + if (access->value.as_str.hash_computed) { + hash = access->value.as_str.hash; + } else { + hash = + runtime_hash(access->value.as_str.data, access->value.as_str.length, + access->value.as_str.prehash); + access->value.as_str.hash = hash; + access->value.as_str.hash_computed = true; + } + ArgonObject *value = get_field_l(to_access, access->value.as_str.data, hash, + 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__) { + value = argon_call(cls__get_attr__, 1, (ArgonObject *[]){access}, err, state); + if (err->exists) { + return ARGON_NULL; + } + return value; + } + ArgonObject *name = get_builtin_field_for_class( + get_builtin_field(to_access, __class__), __name__, + to_access); + *err = create_err( + 0, 0, 0, "", "Runtime Error", "'%.*s' object has no attribute '%.*s'", + (int)name->value.as_str.length, name->value.as_str.data, + (int)access->value.as_str.length, access->value.as_str.data); + } + return ARGON_NULL; +} + ArgonObject *ARGON_ADDITION_FUNCTION(size_t argc, ArgonObject **argv, ArErr *err, RuntimeState *state) { if (argc < 1) { @@ -53,10 +99,10 @@ ArgonObject *ARGON_ADDITION_FUNCTION(size_t argc, ArgonObject **argv, ArgonObject *output = argv[0]; for (size_t i = 1; i < argc; i++) { ArgonObject *object__add__ = get_builtin_field_for_class( - get_builtin_field(output, __class__, false, false), __add__, output); + get_builtin_field(output, __class__), __add__, output); if (!object__add__) { ArgonObject *cls___name__ = - get_builtin_field(output, __name__, true, false); + get_builtin_field(output, __name__); *err = create_err(0, 0, 0, "", "Runtime Error", "Object '%.*s' is missing __add__ method", (int)cls___name__->value.as_str.length, @@ -80,11 +126,11 @@ ArgonObject *ARGON_SUBTRACTION_FUNCTION(size_t argc, ArgonObject **argv, ArgonObject *output = argv[0]; for (size_t i = 1; i < argc; i++) { ArgonObject *function__subtract__ = get_builtin_field_for_class( - get_builtin_field(output, __class__, false, false), __subtract__, + get_builtin_field(output, __class__), __subtract__, output); if (!function__subtract__) { ArgonObject *cls___name__ = - get_builtin_field(output, __name__, true, false); + get_builtin_field(output, __name__); *err = create_err(0, 0, 0, "", "Runtime Error", "Object '%.*s' is missing __subtract__ method", (int)cls___name__->value.as_str.length, @@ -108,11 +154,11 @@ ArgonObject *ARGON_MULTIPLY_FUNCTION(size_t argc, ArgonObject **argv, ArgonObject *output = argv[0]; for (size_t i = 1; i < argc; i++) { ArgonObject *function__multiply__ = get_builtin_field_for_class( - get_builtin_field(output, __class__, false, false), __multiply__, + get_builtin_field(output, __class__), __multiply__, output); if (!function__multiply__) { ArgonObject *cls___name__ = - get_builtin_field(output, __name__, true, false); + get_builtin_field(output, __name__); *err = create_err(0, 0, 0, "", "Runtime Error", "Object '%.*s' is missing __multiply__ method", (int)cls___name__->value.as_str.length, @@ -136,11 +182,11 @@ ArgonObject *ARGON_DIVISION_FUNCTION(size_t argc, ArgonObject **argv, ArgonObject *output = argv[0]; for (size_t i = 1; i < argc; i++) { ArgonObject *function__division__ = get_builtin_field_for_class( - get_builtin_field(output, __class__, false, false), __division__, + get_builtin_field(output, __class__), __division__, output); if (!function__division__) { ArgonObject *cls___name__ = - get_builtin_field(output, __name__, true, false); + get_builtin_field(output, __name__); *err = create_err(0, 0, 0, "", "Runtime Error", "Object '%.*s' is missing __division__ method", (int)cls___name__->value.as_str.length, @@ -164,7 +210,7 @@ ArgonObject *ARGON_TYPE_TYPE___call__(size_t argc, ArgonObject **argv, } ArgonObject *cls = argv[0]; if (cls == ARGON_TYPE_TYPE && argc == 2) { - ArgonObject *cls_class = get_builtin_field(argv[1], __class__, true, false); + ArgonObject *cls_class = get_builtin_field(argv[1], __class__); if (cls_class) return cls_class; return ARGON_NULL; @@ -173,7 +219,7 @@ ArgonObject *ARGON_TYPE_TYPE___call__(size_t argc, ArgonObject **argv, get_builtin_field_for_class(argv[0], __new__, NULL); if (!cls___new__) { ArgonObject *cls___name__ = - get_builtin_field(argv[0], __name__, true, false); + get_builtin_field(argv[0], __name__); *err = create_err( 0, 0, 0, "", "Runtime Error", "Object '%.*s' is missing __new__ method, so cannot be initialised", @@ -194,7 +240,7 @@ ArgonObject *ARGON_TYPE_TYPE___call__(size_t argc, ArgonObject **argv, get_builtin_field_for_class(argv[0], __init__, new_object); if (!cls___init__) { ArgonObject *cls___name__ = - get_builtin_field(argv[0], __name__, true, false); + get_builtin_field(argv[0], __name__); *err = create_err( 0, 0, 0, "", "Runtime Error", "Object '%.*s' is missing __init__ method, so cannot be initialised", @@ -232,8 +278,7 @@ ArgonObject *BASE_CLASS___new__(size_t argc, ArgonObject **argv, ArErr *err, "__new__ expects at least 1 argument, got %" PRIu64, argc); return ARGON_NULL; } - ArgonObject *new_obj = new_object(); - add_builtin_field(new_obj, __class__, argv[0]); + ArgonObject *new_obj = new_instance(argv[0]); return new_obj; } @@ -259,7 +304,7 @@ ArgonObject *BASE_CLASS___string__(size_t argc, ArgonObject **argv, ArErr *err, ArgonObject *object_name = get_builtin_field_for_class(argv[0], __name__, NULL); ArgonObject *class_name = get_builtin_field_for_class( - get_builtin_field(argv[0], __class__, false, false), __name__, NULL); + get_builtin_field(argv[0], __class__), __name__, NULL); char buffer[100]; if (class_name && object_name) @@ -298,7 +343,7 @@ ArgonObject *ARGON_STRING_TYPE___init__(size_t argc, ArgonObject **argv, self->value.as_str.length = 0; self->type = TYPE_STRING; ArgonObject *string_convert_method = get_builtin_field_for_class( - get_builtin_field(object, __class__, false, false), __string__, object); + get_builtin_field(object, __class__), __string__, object); if (string_convert_method) { ArgonObject *string_object = argon_call(string_convert_method, 0, NULL, err, state); @@ -325,7 +370,7 @@ ArgonObject *ARGON_BOOL_TYPE___new__(size_t argc, ArgonObject **argv, self->type = TYPE_STRING; ArgonObject *boolean_convert_method = get_builtin_field_for_class( - get_builtin_field(object, __class__, false, false), __boolean__, object); + get_builtin_field(object, __class__), __boolean__, object); if (boolean_convert_method) { ArgonObject *boolean_object = argon_call(boolean_convert_method, 0, NULL, err, state); @@ -334,7 +379,7 @@ ArgonObject *ARGON_BOOL_TYPE___new__(size_t argc, ArgonObject **argv, return boolean_object; } ArgonObject *type_name = get_builtin_field_for_class( - get_builtin_field(object, __class__, false, false), __name__, object); + get_builtin_field(object, __class__), __name__, object); *err = create_err( 0, 0, 0, "", "Runtime Error", "cannot convert type '%.*s' to bool", type_name->value.as_str.length, type_name->value.as_str.data); @@ -351,7 +396,7 @@ ArgonObject *ARGON_STRING_TYPE___add__(size_t argc, ArgonObject **argv, } if (argv[1]->type != TYPE_STRING) { ArgonObject *type_name = get_builtin_field_for_class( - get_builtin_field(argv[1], __class__, false, false), __name__, argv[1]); + get_builtin_field(argv[1], __class__), __name__, argv[1]); *err = create_err( 0, 0, 0, "", "Runtime Error", "__add__ cannot perform concatenation between a string and %.*s", @@ -476,32 +521,29 @@ ArgonObject *ARGON_NULL_TYPE___string__(size_t argc, ArgonObject **argv, } void bootstrap_types() { - BASE_CLASS = new_object(); - ARGON_TYPE_TYPE = new_object(); + BASE_CLASS = new_class(); + ARGON_TYPE_TYPE = new_class(); add_builtin_field(ARGON_TYPE_TYPE, __base__, BASE_CLASS); add_builtin_field(ARGON_TYPE_TYPE, __class__, ARGON_TYPE_TYPE); - ARGON_NULL_TYPE = new_object(); + ARGON_NULL_TYPE = new_class(); add_builtin_field(ARGON_NULL_TYPE, __base__, BASE_CLASS); - ARGON_NULL = new_object(); + ARGON_NULL = new_instance(ARGON_NULL_TYPE); ARGON_NULL->type = TYPE_NULL; - add_builtin_field(ARGON_NULL, __class__, ARGON_NULL_TYPE); ARGON_NULL->as_bool = false; - add_builtin_field(BASE_CLASS, __base__, NULL); + add_builtin_field(BASE_CLASS, __base__, ARGON_NULL); add_builtin_field(BASE_CLASS, __class__, ARGON_TYPE_TYPE); - ARGON_BOOL_TYPE = new_object(); + ARGON_BOOL_TYPE = new_class(); add_builtin_field(ARGON_BOOL_TYPE, __base__, BASE_CLASS); - ARGON_TRUE = new_object(); + ARGON_TRUE = new_instance(ARGON_BOOL_TYPE); ARGON_TRUE->type = TYPE_BOOL; - add_builtin_field(ARGON_TRUE, __class__, ARGON_BOOL_TYPE); - ARGON_FALSE = new_object(); + ARGON_FALSE = new_instance(ARGON_BOOL_TYPE); ARGON_FALSE->type = TYPE_BOOL; - add_builtin_field(ARGON_FALSE, __class__, ARGON_BOOL_TYPE); ARGON_NULL->as_bool = false; - ARGON_STRING_TYPE = new_object(); + ARGON_STRING_TYPE = new_class(); add_builtin_field(ARGON_STRING_TYPE, __base__, BASE_CLASS); add_builtin_field(ARGON_STRING_TYPE, __name__, @@ -515,12 +557,12 @@ void bootstrap_types() { add_builtin_field(ARGON_BOOL_TYPE, __name__, new_string_object_null_terminated("boolean")); - ARGON_FUNCTION_TYPE = new_object(); + ARGON_FUNCTION_TYPE = new_class(); add_builtin_field(ARGON_FUNCTION_TYPE, __base__, BASE_CLASS); add_builtin_field(ARGON_FUNCTION_TYPE, __name__, new_string_object_null_terminated("function")); - ARGON_METHOD_TYPE = new_object(); + ARGON_METHOD_TYPE = new_class(); add_builtin_field(ARGON_METHOD_TYPE, __base__, BASE_CLASS); add_builtin_field(ARGON_METHOD_TYPE, __name__, new_string_object_null_terminated("method")); @@ -580,8 +622,8 @@ void bootstrap_types() { add_builtin_field( ARGON_BOOL_TYPE, __number__, create_argon_native_function("__number__", ARGON_BOOL_TYPE___number__)); - ACCESS_FUNCTION = create_argon_native_function("__get_attr__", - ARGON_TYPE_TYPE___get_attr__); + GETATTRIBUTE_FUNCTION = create_argon_native_function("__get_attr__", + BASE_CLASS___getattribute__); ADDITION_FUNCTION = create_argon_native_function("add", ARGON_ADDITION_FUNCTION); SUBTRACTION_FUNCTION = @@ -590,7 +632,7 @@ void bootstrap_types() { create_argon_native_function("multiply", ARGON_MULTIPLY_FUNCTION); DIVISION_FUNCTION = create_argon_native_function("division", ARGON_DIVISION_FUNCTION); - add_builtin_field(BASE_CLASS, __get_attr__, ACCESS_FUNCTION); + add_builtin_field(BASE_CLASS, __getattribute__, GETATTRIBUTE_FUNCTION); } void add_to_scope(Stack *stack, char *name, ArgonObject *value) { @@ -611,7 +653,7 @@ void bootstrap_globals() { add_to_scope(Global_Scope, "multiply", MULTIPLY_FUNCTION); add_to_scope(Global_Scope, "division", DIVISION_FUNCTION); - ArgonObject *argon_term = new_object(); + ArgonObject *argon_term = new_class(); add_builtin_field(argon_term, __init__, ARGON_NULL); add_builtin_field(argon_term, field_log, create_argon_native_function("log", term_log)); @@ -723,7 +765,7 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, [OP_COPY_TO_REGISTER] = &&DO_COPY_TO_REGISTER, [OP_ADDITION] = &&DO_ADDITION, [OP_SUBTRACTION] = &&DO_SUBTRACTION, - [OP_LOAD_ACCESS_FUNCTION] = &&DO_LOAD_ACCESS_FUNCTION, + [OP_LOAD_GETATTRIBUTE_FUNCTION] = &&DO_LOAD_GETATTRIBUTE_FUNCTION, [OP_MULTIPLICATION] = &&DO_MULTIPLICATION, [OP_DIVISION] = &&DO_DIVISION, [OP_NOT] = &&DO_NOT}; @@ -830,8 +872,16 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, state->registers[0] = pop_byte(translated, state) ? ARGON_TRUE : ARGON_FALSE; continue; - DO_LOAD_ACCESS_FUNCTION: - state->registers[0] = ACCESS_FUNCTION; + DO_LOAD_GETATTRIBUTE_FUNCTION: + state->registers[0] = get_builtin_field_for_class( + get_builtin_field(state->registers[0], __class__), + __getattribute__, 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 __getattribute__ from objects class"); + } continue; DO_COPY_TO_REGISTER: { uint8_t from_register = pop_byte(translated, state); @@ -1034,6 +1084,13 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, valueB->value.as_number.is_int64)) { int64_t a = valueA->value.as_number.n.i64; int64_t b = valueB->value.as_number.n.i64; + if (!b) { + *err = create_err(state->source_location.line, + state->source_location.column, + state->source_location.length, state->path, + "Zero Division Error", "division by zero"); + continue; + } state->registers[registerC] = new_number_object_from_num_and_den(a, b); } else if (!valueA->value.as_number.is_int64 && @@ -1053,6 +1110,13 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, mpq_set(b_GMP, *valueB->value.as_number.n.mpq); } else { mpq_set(a_GMP, *valueA->value.as_number.n.mpq); + if (!valueB->value.as_number.n.i64) { + *err = create_err(state->source_location.line, + state->source_location.column, + state->source_location.length, state->path, + "Zero Division Error", "division by zero"); + continue; + } mpq_set_si(b_GMP, valueB->value.as_number.n.i64, 1); } mpq_div(a_GMP, a_GMP, b_GMP); diff --git a/src/translator/access/access.c b/src/translator/access/access.c index 400b404..ddf7ed6 100644 --- a/src/translator/access/access.c +++ b/src/translator/access/access.c @@ -8,22 +8,23 @@ size_t translate_access(Translated *translated, ParsedAccess *access, ArErr *err) { set_registers(translated, 1); - uint64_t first = push_instruction_byte(translated, OP_LOAD_ACCESS_FUNCTION); + uint64_t first = translate_parsed(translated, &access->to_access, err); + if (err->exists) + return 0; + push_instruction_byte(translated, OP_LOAD_GETATTRIBUTE_FUNCTION); push_instruction_byte(translated, OP_INIT_CALL); - push_instruction_code(translated, access->access.size + 2); - - translate_parsed(translated, &access->to_access, err); - push_instruction_byte(translated, OP_INSERT_ARG); - push_instruction_code(translated, 0); + push_instruction_code(translated, access->access.size+1); push_instruction_byte(translated, OP_LOAD_BOOL); push_instruction_byte(translated, access->access_fields); push_instruction_byte(translated, OP_INSERT_ARG); - push_instruction_code(translated, 1); + push_instruction_code(translated, 0); for (size_t i = 0; i < access->access.size; i++) { translate_parsed(translated, darray_get(&access->access, i), err); + if (err->exists) + return 0; push_instruction_byte(translated, OP_INSERT_ARG); - push_instruction_code(translated, 2+i); + push_instruction_code(translated, 1 + i); } push_instruction_byte(translated, OP_SOURCE_LOCATION); diff --git a/src/translator/bytecode_spec.md b/src/translator/bytecode_spec.md index f1d5788..f0b9b91 100644 --- a/src/translator/bytecode_spec.md +++ b/src/translator/bytecode_spec.md @@ -120,9 +120,9 @@ sets the source location onto the runtime 1. the column 1. the length -## OP_LOAD_ACCESS_FUNCTION +## OP_LOAD_GETATTRIBUTE_FUNCTION -loads the access function into register 1 +loads the \_\_getattribute\_\_ function from the objects class in register 1 and put it into register 1 ## OP_LOAD_BOOL diff --git a/src/translator/translator.h b/src/translator/translator.h index 370bbce..4062f90 100644 --- a/src/translator/translator.h +++ b/src/translator/translator.h @@ -36,7 +36,7 @@ typedef enum { OP_COPY_TO_REGISTER, OP_ADDITION, OP_SUBTRACTION, - OP_LOAD_ACCESS_FUNCTION, + OP_LOAD_GETATTRIBUTE_FUNCTION, OP_MULTIPLICATION, OP_DIVISION, OP_NOT diff --git a/tests/iteration-test.ar b/tests/iteration-test.ar index 2c929db..0f7853b 100644 --- a/tests/iteration-test.ar +++ b/tests/iteration-test.ar @@ -1,3 +1,3 @@ -let i = 1e7 +let i = 1e6 while (i) do i=i-1 \ No newline at end of file