diff --git a/Makefile b/Makefile index fbeafe7..05f63e2 100644 --- a/Makefile +++ b/Makefile @@ -2,52 +2,46 @@ # # SPDX-License-Identifier: GPL-3.0-or-later +# Default FLEX tool BINARY = bin/argon FLEX_TOOL = flex -SRC_DIRS = src external/xxhash external/cwalk/src external/libdye/src external/linenoise -CFILES = $(shell find $(SRC_DIRS) -name '*.c' \ - ! -path "*/tests/*" \ - ! -path "*/fuzz/*" \ - ! -path "*/cli/*" \ - ! -path "*/example*") \ - $(LEXER_C) -OBJDIR = build -OBJS = $(CFILES:%.c=$(OBJDIR)/%.o) +CFILES = external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c external/linenoise/linenoise.c $(shell find src -name '*.c') -CFLAGS = $(ARCHFLAGS) -Wall -Wextra -Wno-unused-function -Werror=unused-result \ - -Iexternal/cwalk/include -Iexternal/libdye/include +LEXER_SRC = src/lexer/lex.l +LEXER_C = src/lexer/lex.yy.c +LEXER_H = src/lexer/lex.yy.h +CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function -Werror=unused-result -Iexternal/cwalk/include -Iexternal/libdye/include LDFLAGS = -lgc -lgmp -lm all: $(BINARY) -# Rule to build lexer + $(LEXER_C) $(LEXER_H): $(LEXER_SRC) $(FLEX_TOOL) --header-file=$(LEXER_H) -o $(LEXER_C) $(LEXER_SRC) -# Pattern rule for compiling .c -> .o -$(OBJDIR)/%.o: %.c $(LEXER_C) $(LEXER_H) - @mkdir -p $(dir $@) - gcc -O3 -c $< -o $@ $(CFLAGS) +$(BINARY): $(CFILES) $(LEXER_C) $(LEXER_H) + mkdir -p bin + gcc -O3 -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS} -s -# Link final binary -$(BINARY): $(OBJS) - @mkdir -p bin - gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) -s +native: $(CFILES) $(LEXER_C) $(LEXER_H) + mkdir -p bin + gcc -O3 -march=native -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS} -native: CFLAGS += -march=native -native: $(BINARY) +debug: $(CFILES) $(LEXER_C) $(LEXER_H) + mkdir -p bin + gcc -g -O3 -o $(BINARY) $(CFILES) $(CFLAGS) -debug: CFLAGS += -g -debug: $(BINARY) +full-debug: $(CFILES) $(LEXER_C) $(LEXER_H) + mkdir -p bin + gcc -g -O3 -fsanitize=address -fno-omit-frame-pointer -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS} -full-debug: CFLAGS += -g -fsanitize=address -fno-omit-frame-pointer -full-debug: $(BINARY) - -optimised: CFLAGS += -fprofile-generate -optimised: $(BINARY) +optimised: $(CFILES) $(LEXER_C) $(LEXER_H) + mkdir -p bin + gcc -O3 -fprofile-generate -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS} ${BINARY} rand_test.ar - $(MAKE) CFLAGS="$(CFLAGS:-fprofile-generate=-fprofile-use)" $(BINARY) + gcc -O3 -fprofile-use -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS} + clean: rm -rf build bin diff --git a/src/arobject.h b/src/arobject.h index 48c6ea2..59b4f67 100644 --- a/src/arobject.h +++ b/src/arobject.h @@ -16,6 +16,7 @@ typedef enum { __base__, __class__, __name__, + BUILT_IN_ARRAY_COUNT, __add__, __string__, __subtract__, @@ -33,6 +34,8 @@ typedef enum { field_log, field_length, __getattribute__, + __hash__, + __repr__, BUILT_IN_FIELDS_COUNT, } built_in_fields; @@ -53,6 +56,7 @@ typedef enum ArgonType { TYPE_FUNCTION, TYPE_NATIVE_FUNCTION, TYPE_METHOD, + TYPE_DICTIONARY, TYPE_OBJECT, } ArgonType; @@ -113,11 +117,11 @@ struct as_number { // full definition of ArgonObject (no typedef again!) struct ArgonObject { struct hashmap_GC *dict; - size_t built_in_slot_size; size_t built_in_slot_length; - struct built_in_slot *built_in_slot; + struct built_in_slot built_in_slot[BUILT_IN_ARRAY_COUNT]; union { struct as_number *as_number; + struct hashmap_GC* as_hashmap; struct string_struct* as_str; native_fn native_fn; struct argon_function_struct *argon_fn; diff --git a/src/main.c b/src/main.c index 855ca1a..ab0f7e3 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,7 @@ #include "hashmap/hashmap.h" #include "import.h" #include "memory.h" +#include "runtime/objects/object.h" #include "runtime/runtime.h" #include "shell.h" @@ -50,8 +51,8 @@ char *get_current_directory() { 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) diff --git a/src/runtime/internals/hashmap/hashmap.c b/src/runtime/internals/hashmap/hashmap.c index b637c82..1a7ad56 100644 --- a/src/runtime/internals/hashmap/hashmap.c +++ b/src/runtime/internals/hashmap/hashmap.c @@ -25,6 +25,27 @@ struct hashmap_GC *createHashmap_GC() { t->inline_count = 0; return t; } +void hashmap_GC_to_array(struct hashmap_GC *t, struct node_GC**array, + size_t *array_length) { + size_t array_size = 8; + *array_length = 0; + *array = ar_alloc(array_size * sizeof(struct node_GC)); + for (size_t i = 0; i < t->inline_count; i++) { + if (*array_length >=array_size) { + array_size*=2; + *array=ar_realloc(*array, array_size * sizeof(struct node_GC)); + } + (*array)[(*array_length)++] = t->inline_values[i]; + } + for (size_t i = 0; i < t->size; i++) { + if (!t->list[i]) continue; + if (*array_length >=array_size) { + array_size*=2; + *array=ar_realloc(*array, array_size * sizeof(struct node_GC)); + } + (*array)[(*array_length)++] = *t->list[i]; + } +} void clear_hashmap_GC(struct hashmap_GC *t) { if (!t->count) @@ -68,6 +89,17 @@ int hashCode_GC(struct hashmap_GC *t, uint64_t hash) { } int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) { + for (size_t i = 0; i < t->inline_count; i++) { + if (t->inline_values[i].hash == hash) { + size_t length = t->inline_count - i; + if (length > 1) { + memmove(&t->inline_values[i], &t->inline_values[i + 1], + (length - 1) * sizeof(struct node_GC)); + } + t->inline_count--; + return 1; + } + } int pos = hashCode_GC(t, hash); struct node_GC *list = t->list[pos]; struct node_GC *temp = list; @@ -91,18 +123,17 @@ void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key, if (!order) { order = t->order++; } - size_t stop = t->inline_count; - for (size_t i = 0; i < stop; i++) { + for (size_t i = 0; i < t->inline_count; i++) { if (t->inline_values[i].hash == hash) { t->inline_values[i].val = val; return; } } - if (!t->list && stop < INLINE_HASHMAP_ARRAY_SIZE) { - t->inline_values[stop].hash = hash; - t->inline_values[stop].key = key; - t->inline_values[stop].val = val; - t->inline_values[stop].order = order; + if (!t->list && t->inline_count < INLINE_HASHMAP_ARRAY_SIZE) { + t->inline_values[t->inline_count].hash = hash; + t->inline_values[t->inline_count].key = key; + t->inline_values[t->inline_count].val = val; + t->inline_values[t->inline_count].order = order; t->inline_count++; t->count++; return; diff --git a/src/runtime/internals/hashmap/hashmap.h b/src/runtime/internals/hashmap/hashmap.h index 10b0688..a9b8400 100644 --- a/src/runtime/internals/hashmap/hashmap.h +++ b/src/runtime/internals/hashmap/hashmap.h @@ -33,12 +33,15 @@ struct hashmap_GC *createHashmap_GC(); void clear_hashmap_GC(struct hashmap_GC *t); +void hashmap_GC_to_array(struct hashmap_GC *t, struct node_GC**array, + size_t *array_length); + int hashCode_GC(struct hashmap_GC *t, uint64_t hash); int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash); void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key, - void *val, size_t order); + void *val, size_t order); void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash); diff --git a/src/runtime/objects/dictionary/dictionary.c b/src/runtime/objects/dictionary/dictionary.c index e69de29..c19688e 100644 --- a/src/runtime/objects/dictionary/dictionary.c +++ b/src/runtime/objects/dictionary/dictionary.c @@ -0,0 +1,169 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +#include "dictionary.h" +#include "../../call/call.h" +#include "../functions/functions.h" +#include "../literals/literals.h" +#include "../string/string.h" +#include +#include +#include +#include +#include + +ArgonObject *ARGON_DICTIONARY_TYPE = NULL; + +ArgonObject *create_ARGON_DICTIONARY_TYPE___init__(size_t argc, + ArgonObject **argv, + ArErr *err, + RuntimeState *state) { + (void)state; + if (argc != 1) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__init__ expects 1 argument, got %" PRIu64, argc); + return ARGON_NULL; + } + ArgonObject *object = argv[0]; + object->type = TYPE_DICTIONARY; + object->value.as_hashmap = createHashmap_GC(); + return object; +} + +ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc, + ArgonObject **argv, + ArErr *err, + RuntimeState *state) { + (void)state; + if (argc != 1) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__init__ expects 1 argument, got %" PRIu64, argc); + return ARGON_NULL; + } + ArgonObject *object = argv[0]; + size_t string_length = 0; + char *string = NULL; + struct node_GC *keys; + size_t keys_length; + hashmap_GC_to_array(object->value.as_hashmap, &keys, &keys_length); + char *string_obj = "{"; + size_t length = strlen(string_obj); + string = realloc(string, string_length + length); + memcpy(string + string_length, string_obj, length); + string_length += length; + for (size_t i = 0; i < keys_length; i++) { + struct node_GC node = keys[i]; + ArgonObject *key = node.key; + ArgonObject *value = node.val; + + ArgonObject *string_convert_method = get_builtin_field_for_class( + get_builtin_field(key, __class__), __repr__, key); + + if (string_convert_method) { + ArgonObject *string_object = + argon_call(string_convert_method, 0, NULL, err, state); + string = + realloc(string, string_length + string_object->value.as_str->length); + memcpy(string + string_length, string_object->value.as_str->data, + string_object->value.as_str->length); + string_length += string_object->value.as_str->length; + } else { + char *string_obj = ""; + size_t length = strlen(string_obj); + string = realloc(string, string_length + length); + memcpy(string + string_length, string_obj, length); + string_length += length; + } + + char *string_obj = ": "; + size_t length = strlen(string_obj); + string = realloc(string, string_length + length); + memcpy(string + string_length, string_obj, length); + string_length += length; + + string_convert_method = get_builtin_field_for_class( + get_builtin_field(value, __class__), __repr__, value); + + if (string_convert_method && value != object) { + ArgonObject *string_object = + argon_call(string_convert_method, 0, NULL, err, state); + string = + realloc(string, string_length + string_object->value.as_str->length); + memcpy(string + string_length, string_object->value.as_str->data, + string_object->value.as_str->length); + string_length += string_object->value.as_str->length; + } else { + char *string_obj = ""; + size_t length = strlen(string_obj); + string = realloc(string, string_length + length); + memcpy(string + string_length, string_obj, length); + string_length += length; + } + + if (i != keys_length - 1) { + char *string_obj = ", "; + size_t length = strlen(string_obj); + string = realloc(string, string_length + length); + memcpy(string + string_length, string_obj, length); + string_length += length; + } + } + string_obj = "}"; + length = strlen(string_obj); + string = realloc(string, string_length + length); + memcpy(string + string_length, string_obj, length); + string_length += length; + ArgonObject* result = new_string_object(string, string_length, 0, 0); + free(string); + return result; +} + +ArgonObject *create_ARGON_DICTIONARY_TYPE___get_attr__(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); + 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) { + *err = create_err(0, 0, 0, NULL, "Attribute Error", + "Dictionary has no attribute ''"); + return ARGON_NULL; + } + return result; +} + +void create_ARGON_DICTIONARY_TYPE() { + ARGON_DICTIONARY_TYPE = new_class(); + add_builtin_field(ARGON_DICTIONARY_TYPE, __name__, + new_string_object_null_terminated("dictionary")); + add_builtin_field(ARGON_DICTIONARY_TYPE, __init__, + 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__)); + add_builtin_field(ARGON_DICTIONARY_TYPE, __string__, + create_argon_native_function( + "__string__", create_ARGON_DICTIONARY_TYPE___string__)); +} + +ArgonObject *create_dictionary(struct hashmap_GC *hashmap) { + ArgonObject *object = new_instance(ARGON_DICTIONARY_TYPE); + object->type = TYPE_DICTIONARY; + object->value.as_hashmap = hashmap; + return object; +} \ No newline at end of file diff --git a/src/runtime/objects/dictionary/dictionary.h b/src/runtime/objects/dictionary/dictionary.h index e69de29..75b377e 100644 --- a/src/runtime/objects/dictionary/dictionary.h +++ b/src/runtime/objects/dictionary/dictionary.h @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef DICTIONARY_H +#define DICTIONARY_H +#include "../object.h" + +extern ArgonObject *ARGON_DICTIONARY_TYPE; + +void create_ARGON_DICTIONARY_TYPE(); + +ArgonObject* create_dictionary(struct hashmap_GC*hashmap); + +#endif // DICTIONARY_H \ No newline at end of file diff --git a/src/runtime/objects/number/number.c b/src/runtime/objects/number/number.c index 99bcd0b..fee2990 100644 --- a/src/runtime/objects/number/number.c +++ b/src/runtime/objects/number/number.c @@ -497,9 +497,7 @@ void init_small_ints() { for (int64_t i = 0; i <= small_ints_max - small_ints_min; i++) { int64_t n = i + small_ints_min; small_ints[i].type = TYPE_NUMBER; - small_ints[i].built_in_slot = NULL; small_ints[i].built_in_slot_length = 0; - small_ints[i].built_in_slot_size = 0; small_ints[i].dict = NULL; small_ints[i].value.as_number = &small_ints_as_number[i]; add_builtin_field(&small_ints[i], __class__, ARGON_NUMBER_TYPE); diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index e86aac0..341ec45 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -5,7 +5,9 @@ */ #include "object.h" +#include "../../hash_data/hash_data.h" #include "../../memory.h" +#include "../call/call.h" #include "type/type.h" #include #include @@ -29,16 +31,34 @@ int strcmp_len(const char *s1, size_t len, const char *s2) { ArgonObject *BASE_CLASS = NULL; const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = { - "__base__", "__class__", "__name__", "__add__", - "__string__", "__subtract__", "__multiply__", "__division__", - "__new__", "__init__", "__boolean__", "__get_attr__", - "__binding__", "__function__", "address", "__call__", - "__number__", "log", "length", "__getattribute__"}; + "__base__", + "__class__", + "__name__", + "", // above is anything that gets stored in built in slots + "__add__", + "__string__", + "__subtract__", + "__multiply__", + "__division__", + "__new__", + "__init__", + "__boolean__", + "__get_attr__", + "__binding__", + "__function__", + "address", + "__call__", + "__number__", + "log", + "length", + "__getattribute__", + "__hash__", + "__repr__"}; + +uint64_t built_in_field_hashes[BUILT_IN_FIELDS_COUNT]; ArgonObject *new_object() { ArgonObject *object = ar_alloc(sizeof(ArgonObject)); - object->built_in_slot = NULL; - object->built_in_slot_size = 0; object->built_in_slot_length = 0; object->type = TYPE_OBJECT; object->dict = NULL; @@ -46,6 +66,32 @@ ArgonObject *new_object() { 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); + } +} + +int64_t hash_object(ArgonObject *object, ArErr *err, RuntimeState *state) { + ArgonObject *hash_function = get_builtin_field_for_class( + get_builtin_field(object, __class__), __hash__, object); + if (!hash_function) { + *err = create_err(err->line, err->column, err->length, err->path, + "Hash Error", "objects class has no __hash__ method"); + return 0; + } + ArgonObject *hash_result = argon_call(hash_function, 0, NULL, err, state); + if (hash_result->type != TYPE_NUMBER || + !hash_result->value.as_number->is_int64) { + *err = + create_err(err->line, err->column, err->length, err->path, "Hash Error", + "hash result needs to be a 64 bit integer."); + return 0; + } + return hash_result->value.as_number->n.i64; +} + ArgonObject *new_class() { ArgonObject *object = new_object(); add_builtin_field(object, __class__, ARGON_TYPE_TYPE); @@ -67,30 +113,33 @@ inline void add_builtin_field(ArgonObject *target, built_in_fields field, return; } } - if (target->built_in_slot_length >= target->built_in_slot_size) { - target->built_in_slot_size *= 2; - if (target->built_in_slot_size == 0) target->built_in_slot_size = 2; - else if (target->built_in_slot_size>BUILT_IN_FIELDS_COUNT) target->built_in_slot_size = BUILT_IN_FIELDS_COUNT; - target->built_in_slot = - ar_realloc(target->built_in_slot, target->built_in_slot_size * - sizeof(struct built_in_slot)); + if (field > BUILT_IN_ARRAY_COUNT) { + if (!target->dict) + target->dict = createHashmap_GC(); + hashmap_insert_GC(target->dict, built_in_field_hashes[field], + (char *)built_in_field_names[field], object, 0); + return; } - target->built_in_slot[target->built_in_slot_length++] = (struct built_in_slot){field, object}; + target->built_in_slot[target->built_in_slot_length++] = + (struct built_in_slot){field, object}; // hashmap_insert_GC(target->dict, built_in_field_hashes[field], // (char *)built_in_field_names[field], object, 0); } void add_field_l(ArgonObject *target, char *name, uint64_t hash, size_t length, ArgonObject *object) { - for (size_t i = 0; i < BUILT_IN_FIELDS_COUNT; i++) { + for (size_t i = 0; i < BUILT_IN_ARRAY_COUNT; i++) { if (strcmp_len(name, length, built_in_field_names[i]) == 0) { add_builtin_field(target, i, object); return; } } - if (!object->dict) - object->dict = createHashmap_GC(); - hashmap_insert_GC(target->dict, hash, name, object, 0); + if (!target->dict) + target->dict = createHashmap_GC(); + char *name_copy = ar_alloc(length); + memcpy(name_copy, name, length); + name_copy[length] = '\0'; + hashmap_insert_GC(target->dict, hash, name_copy, object, 0); } ArgonObject *bind_object_to_function(ArgonObject *object, @@ -127,9 +176,9 @@ 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++) { + for (size_t i = 0; i < target->built_in_slot_length; i++) { if (strcmp_len(name, length, built_in_field_names[i]) == 0) { - return get_builtin_field(target, i); + return target->built_in_slot[i].value; } } if (!target->dict) @@ -161,22 +210,32 @@ ArgonObject *get_builtin_field_for_class(ArgonObject *target, } return NULL; } +inline ArgonObject *get_builtin_field(ArgonObject *target, + built_in_fields field) { + return get_builtin_field_with_recursion_support(target, field, false, false); +} -ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field) { +ArgonObject * +get_builtin_field_with_recursion_support(ArgonObject *target, + built_in_fields field, bool recursive, + bool disable_method_wrapper) { + if (!target) + return NULL; for (size_t i = 0; i < target->built_in_slot_length; i++) { if (target->built_in_slot[i].field == field) { return target->built_in_slot[i].value; } } - return NULL; - // 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); + if (!target->dict) + return NULL; + 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 ffd13c9..ccc8670 100644 --- a/src/runtime/objects/object.h +++ b/src/runtime/objects/object.h @@ -18,6 +18,10 @@ typedef struct ArgonObject ArgonObject; ArgonObject *new_class(); ArgonObject *new_instance(ArgonObject * of); +void init_built_in_field_hashes(); + +int64_t hash_object(ArgonObject *object, ArErr *err, RuntimeState *state); + void add_builtin_field(ArgonObject *target, built_in_fields field, ArgonObject *object); @@ -41,4 +45,6 @@ ArgonObject *get_builtin_field_for_class(ArgonObject *target, ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field); +ArgonObject *get_builtin_field_with_recursion_support(ArgonObject *target, built_in_fields field, bool recursive, bool disable_method_wrapper); + #endif // OBJECT_H \ No newline at end of file diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 85add2e..425e468 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -13,6 +13,7 @@ #include "call/call.h" #include "declaration/declaration.h" #include "internals/hashmap/hashmap.h" +#include "objects/dictionary/dictionary.h" #include "objects/functions/functions.h" #include "objects/literals/literals.h" #include "objects/number/number.h" @@ -433,6 +434,25 @@ ArgonObject *ARGON_STRING_TYPE___string__(size_t argc, ArgonObject **argv, } return argv[0]; } +ArgonObject *ARGON_STRING_TYPE___hash__(size_t argc, ArgonObject **argv, + ArErr *err, RuntimeState *state) { + (void)state; + if (argc != 1) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__hash__ expects 1 arguments, got %" PRIu64, argc); + } + uint64_t hash; + if (argv[0]->value.as_str->hash_computed) { + hash = argv[0]->value.as_str->hash; + } else { + hash = + runtime_hash(argv[0]->value.as_str->data, argv[0]->value.as_str->length, + argv[0]->value.as_str->prehash); + argv[0]->value.as_str->hash = hash; + argv[0]->value.as_str->hash_computed = true; + } + return new_number_object_from_int64(hash); +} ArgonObject *ARGON_STRING_TYPE___number__(size_t argc, ArgonObject **argv, ArErr *err, RuntimeState *state) { @@ -569,12 +589,18 @@ void bootstrap_types() { add_builtin_field( BASE_CLASS, __string__, create_argon_native_function("__string__", BASE_CLASS___string__)); + add_builtin_field( + BASE_CLASS, __repr__, + create_argon_native_function("__repr__", BASE_CLASS___string__)); add_builtin_field( ARGON_TYPE_TYPE, __call__, create_argon_native_function("__call__", ARGON_TYPE_TYPE___call__)); add_builtin_field( ARGON_STRING_TYPE, __init__, create_argon_native_function("__init__", ARGON_STRING_TYPE___init__)); + add_builtin_field( + ARGON_STRING_TYPE, __hash__, + create_argon_native_function("__hash__", ARGON_STRING_TYPE___hash__)); add_builtin_field( ARGON_STRING_TYPE, __add__, create_argon_native_function("__add__", ARGON_STRING_TYPE___add__)); @@ -622,17 +648,19 @@ void bootstrap_types() { DIVISION_FUNCTION = create_argon_native_function("division", ARGON_DIVISION_FUNCTION); add_builtin_field(BASE_CLASS, __getattribute__, GETATTRIBUTE_FUNCTION); + create_ARGON_DICTIONARY_TYPE(); } void add_to_scope(Stack *stack, char *name, ArgonObject *value) { size_t length = strlen(name); uint64_t hash = siphash64_bytes(name, length, siphash_key); - ArgonObject *key = new_string_object(name, length, 0, 0); + ArgonObject *key = new_string_object(name, length, 0, hash); hashmap_insert_GC(stack->scope, hash, key, value, 0); } void bootstrap_globals() { Global_Scope = create_scope(NULL, true); + add_to_scope(Global_Scope, "global", create_dictionary(Global_Scope->scope)); add_to_scope(Global_Scope, "string", ARGON_STRING_TYPE); add_to_scope(Global_Scope, "type", ARGON_TYPE_TYPE); add_to_scope(Global_Scope, "boolean", ARGON_BOOL_TYPE); @@ -641,6 +669,7 @@ void bootstrap_globals() { add_to_scope(Global_Scope, "subtract", SUBTRACTION_FUNCTION); add_to_scope(Global_Scope, "multiply", MULTIPLY_FUNCTION); add_to_scope(Global_Scope, "division", DIVISION_FUNCTION); + add_to_scope(Global_Scope, "dictionary", ARGON_DICTIONARY_TYPE); ArgonObject *argon_term = new_class(); add_builtin_field(argon_term, __init__, ARGON_NULL);