Files
Chloride/src/runtime/objects/dictionary/dictionary.c
2025-11-26 03:07:06 +00:00

253 lines
9.3 KiB
C

/*
* 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 <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
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;
size_t nodes_length;
struct node_GC ** nodes = hashmap_GC_to_array(object->value.as_hashmap, &nodes_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 < nodes_length; i++) {
struct node_GC *node = nodes[i];
ArgonObject *key = node->key;
ArgonObject *value = node->val;
if (!key) { fprintf(stderr, "NULL key at node %zu\n", i); continue; }
if (!value) { fprintf(stderr, "NULL value at node %zu\n", i); continue; }
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 = "<object>";
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 != nodes_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___getattr__(size_t argc,
ArgonObject **argv,
ArErr *err,
RuntimeState *state) {
(void)state;
if (argc != 2) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__getattr__ 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 '%.*s'", key->value.as_str->length, key->value.as_str->data);
return ARGON_NULL;
}
return result;
}
ArgonObject *create_ARGON_DICTIONARY_TYPE___setattr__(size_t argc,
ArgonObject **argv,
ArErr *err,
RuntimeState *state) {
(void)state;
if (argc != 3) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__setattr__ expects 2 argument, got %" PRIu64, argc);
return ARGON_NULL;
}
ArgonObject *object = argv[0];
ArgonObject *key = argv[1];
ArgonObject *value = argv[2];
int64_t hash = hash_object(key, err, state);
if (err->exists) {
return ARGON_NULL;
}
hashmap_insert_GC(object->value.as_hashmap, hash, key, value, 0);
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,
ArErr *err,
RuntimeState *state) {
(void)state;
if (argc != 3) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__setitem__ expects 2 argument, got %" PRIu64, argc);
return ARGON_NULL;
}
ArgonObject *object = argv[0];
ArgonObject *key = argv[1];
ArgonObject *value = argv[2];
int64_t hash = hash_object(key, err, state);
if (err->exists) {
return ARGON_NULL;
}
hashmap_insert_GC(object->value.as_hashmap, hash, key, value, 0);
return value;
}
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, __getattr__,
create_argon_native_function("__getattr__",
create_ARGON_DICTIONARY_TYPE___getattr__));
add_builtin_field(
ARGON_DICTIONARY_TYPE, __setattr__,
create_argon_native_function("__setattr__",
create_ARGON_DICTIONARY_TYPE___setattr__));
add_builtin_field(
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__));
}
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;
}