From 345c4ce8412adde1cbb70ac63639f38c80f2839d Mon Sep 17 00:00:00 2001 From: William Bell <62452284+Ugric@users.noreply.github.com> Date: Sat, 9 Aug 2025 17:00:57 +0100 Subject: [PATCH] make objects initialisation through type.__call__ --- src/arobject.h | 16 ++++----- src/runtime/call/call.c | 70 +++++++++++++++++++++--------------- src/runtime/call/call.h | 6 +++- src/runtime/objects/object.c | 23 ++++++++---- src/runtime/objects/object.h | 6 ++-- src/runtime/runtime.c | 60 ++++++++++++++++++++++++------- testing.ar | 2 +- 7 files changed, 124 insertions(+), 59 deletions(-) diff --git a/src/arobject.h b/src/arobject.h index 4f81a29..cf78f54 100644 --- a/src/arobject.h +++ b/src/arobject.h @@ -12,11 +12,13 @@ #include "runtime/internals/hashmap/hashmap.h" #include -typedef struct ArErr ArErr; +typedef struct ArErr ArErr; +typedef struct RuntimeState RuntimeState; typedef struct ArgonObject ArgonObject; // forward declaration -typedef ArgonObject* (*native_fn)(size_t argc, ArgonObject**argv, ArErr*err); +typedef ArgonObject *(*native_fn)(size_t argc, ArgonObject **argv, ArErr *err, + RuntimeState *state); typedef enum ArgonType { TYPE_NULL, @@ -29,12 +31,11 @@ typedef enum ArgonType { TYPE_OBJECT, } ArgonType; - typedef struct { void *data; size_t capacity; size_t size; - struct hashmap_GC * hashmap; + struct hashmap_GC *hashmap; } ConstantArena; typedef struct { @@ -42,7 +43,7 @@ typedef struct { DArray *return_jumps; darray_armem bytecode; ConstantArena constants; - char* path; + char *path; } Translated; struct string_struct { @@ -57,7 +58,7 @@ typedef struct Stack { struct argon_function_struct { Translated translated; - uint8_t* bytecode; + uint8_t *bytecode; size_t bytecode_length; Stack *stack; size_t number_of_parameters; @@ -66,11 +67,10 @@ struct argon_function_struct { uint64_t column; }; - - // full definition of ArgonObject (no typedef again!) struct ArgonObject { ArgonType type; + ArgonType child_type; struct hashmap_GC *dict; union { mpq_t as_number; diff --git a/src/runtime/call/call.c b/src/runtime/call/call.c index ed56d10..fbf633b 100644 --- a/src/runtime/call/call.c +++ b/src/runtime/call/call.c @@ -70,41 +70,50 @@ double get_memory_usage_mb() { } #endif -ArErr run_call(Translated *translated, RuntimeState *state) { - ArgonObject *original_object = state->call_instance->to_call; +ArgonObject *argon_call(ArgonObject *original_object, size_t argc, + ArgonObject **argv, ArErr *err, RuntimeState *state) { + *err = run_call(original_object, argc, argv, state); + return state->registers[0]; +} + +ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, + RuntimeState *state) { ArgonObject *object = original_object; if (object->type != TYPE_FUNCTION && object->type != TYPE_NATIVE_FUNCTION && object->type != TYPE_METHOD) { - ArgonObject *call_method = get_field_for_class( - get_field(object, "__class__", false), "__call__", original_object); + ArgonObject *call_method = + get_field_for_class(get_field(object, "__class__", false, false), + "__call__", original_object); if (call_method) { object = call_method; } } + bool to_free_args = false; if (object->type == TYPE_METHOD) { - ArgonObject *binding_object = get_field(object, "__binding__", false); + ArgonObject *binding_object = + get_field(object, "__binding__", false, false); if (binding_object) { - ArgonObject **new_call_args = malloc( - sizeof(ArgonObject *) * (state->call_instance->args_length + 1)); + ArgonObject **new_call_args = malloc(sizeof(ArgonObject *) * (argc + 1)); new_call_args[0] = binding_object; - if (state->call_instance->args_length > 0) { - memcpy(new_call_args + 1, state->call_instance->args, - state->call_instance->args_length); + if (argc > 0) { + memcpy(new_call_args + 1, argv, argc * sizeof(ArgonObject *)); } - free(state->call_instance->args); - state->call_instance->args = new_call_args; - state->call_instance->args_length++; + argv = new_call_args; + argc++; + to_free_args = true; } - ArgonObject *function_object = get_field(object, "__function__", false); + ArgonObject *function_object = + get_field(object, "__function__", false, false); if (function_object) object = function_object; } if (object->type == TYPE_FUNCTION) { - if (state->call_instance->args_length != - object->value.argon_fn.number_of_parameters) { - ArgonObject *type_object_name = get_field_for_class( - get_field(object, "__class__", false), "__name__", original_object); - ArgonObject *object_name = get_field_for_class(object, "__name__", original_object); + if (argc != object->value.argon_fn.number_of_parameters) { + ArgonObject *type_object_name = + get_field_for_class(get_field(object, "__class__", false, false), + "__name__", original_object); + ArgonObject *object_name = + get_field_for_class(object, "__name__", original_object); return create_err( state->source_location.line, state->source_location.column, state->source_location.length, state->path, "Type Error", @@ -112,19 +121,20 @@ ArErr run_call(Translated *translated, RuntimeState *state) { (int)type_object_name->value.as_str.length, type_object_name->value.as_str.data, (int)object_name->value.as_str.length, object_name->value.as_str.data, - object->value.argon_fn.number_of_parameters, - state->call_instance->args_length); + object->value.argon_fn.number_of_parameters, argc); } Stack *scope = create_scope(object->value.argon_fn.stack); - for (size_t i = 0; i < state->call_instance->args_length; i++) { + for (size_t i = 0; i < argc; i++) { struct string_struct key = object->value.argon_fn.parameters[i]; - ArgonObject *value = (state->call_instance->args)[i]; + ArgonObject *value = argv[i]; uint64_t hash = siphash64_bytes(key.data, key.length, siphash_key); hashmap_insert_GC(scope->scope, hash, new_string_object(key.data, key.length), value, 0); } + if (to_free_args) + free(argv); StackFrame new_stackFrame = { - {translated->registerCount, + {object->value.argon_fn.translated.registerCount, NULL, {object->value.argon_fn.bytecode, sizeof(uint8_t), object->value.argon_fn.bytecode_length, @@ -169,8 +179,9 @@ ArErr run_call(Translated *translated, RuntimeState *state) { return no_err; } else if (object->type == TYPE_NATIVE_FUNCTION) { ArErr err = no_err; - state->registers[0] = object->value.native_fn( - state->call_instance->args_length, state->call_instance->args, &err); + state->registers[0] = object->value.native_fn(argc, argv, &err, state); + if (to_free_args) + free(argv); if (err.exists) { err.line = state->source_location.line; err.column = state->source_location.column; @@ -179,8 +190,11 @@ ArErr run_call(Translated *translated, RuntimeState *state) { } return err; } - ArgonObject *type_object_name = get_field_for_class( - get_field(original_object, "__class__", false), "__name__", original_object); + if (to_free_args) + free(argv); + ArgonObject *type_object_name = + get_field_for_class(get_field(original_object, "__class__", false, false), + "__name__", original_object); return create_err(state->source_location.line, state->source_location.column, state->source_location.length, state->path, "Type Error", "'%.*s' object is not callable", diff --git a/src/runtime/call/call.h b/src/runtime/call/call.h index 42df423..563596e 100644 --- a/src/runtime/call/call.h +++ b/src/runtime/call/call.h @@ -8,6 +8,10 @@ #define runtime_call_H #include "../runtime.h" -ArErr run_call(Translated *translated, RuntimeState *state); +ArgonObject *argon_call(ArgonObject *original_object, size_t argc, + ArgonObject **argv, ArErr *err, RuntimeState *state); + +ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, + RuntimeState *state); #endif // runtime_call_H \ No newline at end of file diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index c5fef57..d916654 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -34,21 +34,22 @@ ArgonObject *bind_object_to_function(ArgonObject *object, add_field(bound_method_wrapper, "__class__", ARGON_METHOD_TYPE); add_field(bound_method_wrapper, "__binding__", object); add_field(bound_method_wrapper, "__function__", function); - ArgonObject *function_name = get_field(function, "__name__", false); + ArgonObject *function_name = get_field(function, "__name__", false, false); if (function_name) add_field(bound_method_wrapper, "__name__", function_name); return bound_method_wrapper; } -ArgonObject *get_field_for_class(ArgonObject *target, char *name, ArgonObject *binding_object) { +ArgonObject *get_field_for_class(ArgonObject *target, char *name, + ArgonObject *binding_object) { char *field = "__base__"; while (target) { uint64_t hash = siphash64_bytes(name, strlen(name), siphash_key); ArgonObject *object = hashmap_lookup_GC(target->dict, hash); if (object) { - if (object->type == TYPE_FUNCTION || - object->type == TYPE_NATIVE_FUNCTION) { + if ((object->type == TYPE_FUNCTION || + object->type == TYPE_NATIVE_FUNCTION) && binding_object) { object = bind_object_to_function(binding_object, object); } return object; @@ -59,10 +60,18 @@ ArgonObject *get_field_for_class(ArgonObject *target, char *name, ArgonObject *b return NULL; } -ArgonObject *get_field(ArgonObject *target, char *name, bool recursive) { +ArgonObject *get_field(ArgonObject *target, char *name, bool recursive, + bool disable_method_wrapper) { char *field = "__class__"; - ArgonObject *object = hashmap_lookup_GC(target->dict, siphash64_bytes(name, strlen(name), siphash_key)); + ArgonObject *object = hashmap_lookup_GC( + target->dict, siphash64_bytes(name, strlen(name), siphash_key)); if (!recursive || object) return object; - return get_field_for_class(hashmap_lookup_GC(target->dict, siphash64_bytes(field, strlen(field), siphash_key)), name, target); + ArgonObject *binding = target; + if (disable_method_wrapper) + binding = NULL; + return get_field_for_class( + hashmap_lookup_GC(target->dict, + siphash64_bytes(field, strlen(field), siphash_key)), + name, binding); } \ No newline at end of file diff --git a/src/runtime/objects/object.h b/src/runtime/objects/object.h index de32911..7825a9e 100644 --- a/src/runtime/objects/object.h +++ b/src/runtime/objects/object.h @@ -17,8 +17,10 @@ ArgonObject *new_object(); void add_field(ArgonObject *target, char *name, ArgonObject *object); -ArgonObject *get_field_for_class(ArgonObject *target, char *name, ArgonObject *binding_object); +ArgonObject *get_field_for_class(ArgonObject *target, char *name, + ArgonObject *binding_object); -ArgonObject *get_field(ArgonObject *target, char *name, bool recursive); +ArgonObject *get_field(ArgonObject *target, char *name, 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 6f0aa96..bc16a56 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -29,16 +29,52 @@ ArgonObject *ARGON_METHOD_TYPE; Stack *Global_Scope = NULL; ArgonObject *ARGON_TYPE_TYPE___call__(size_t argc, ArgonObject **argv, - ArErr *err) { - if (argc<1) { - *err = create_err(0, 0, 0, "", "Runtime Error", "call missing self object."); + ArErr *err, RuntimeState *state) { + if (argc < 1) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__call__ expects at least 1 argument, got 0"); + return ARGON_NULL; + } + ArgonObject *cls = argv[0]; + if (cls == ARGON_TYPE_TYPE && argc == 2) { + ArgonObject *cls_class = get_field(argv[1], "__class__", true, false); + if (cls_class) + return cls_class; + return ARGON_NULL; + } + ArgonObject *cls___new__ = get_field_for_class(argv[0], "__new__", NULL); + if (!cls___new__) { + ArgonObject *cls___name__ = get_field(argv[0], "__name__", true, false); + *err = create_err( + 0, 0, 0, "", "Runtime Error", + "Object '%.*s' is missing __new__ method, so cannot be initialised", + (int)cls___name__->value.as_str.length, + cls___name__->value.as_str.data); return ARGON_NULL; } - ArgonObject *self = argv[0]; - ArgonObject *self_name = get_field(argv[0], "__name__", true); - printf("type: %.*s\n", (int)self_name->value.as_str.length, self_name->value.as_str.data); - return ARGON_NULL; + ArgonObject *new_object = argon_call(cls___new__, argc, argv, err, state); + if (err->exists) + return ARGON_NULL; + ArgonObject *args[] = {ARGON_TYPE_TYPE, new_object}; + ArgonObject *new_object_class = ARGON_TYPE_TYPE___call__(2, args, err, state); + if (new_object_class != ARGON_NULL && new_object_class == cls) { + ArgonObject *cls___init__ = + get_field_for_class(argv[0], "__init__", new_object); + if (!cls___init__) { + ArgonObject *cls___name__ = get_field(argv[0], "__name__", true, false); + *err = create_err( + 0, 0, 0, "", "Runtime Error", + "Object '%.*s' is missing __init__ method, so cannot be initialised", + (int)cls___name__->value.as_str.length, + cls___name__->value.as_str.data); + } + argon_call(cls___init__, argc - 1, argv + 1, err, state); + if (err->exists) + return ARGON_NULL; + } + + return new_object; } void bootstrap_types() { @@ -47,8 +83,7 @@ void bootstrap_types() { add_field(ARGON_TYPE_TYPE, "__base__", BASE_CLASS); add_field(ARGON_TYPE_TYPE, "__class__", ARGON_TYPE_TYPE); add_field(ARGON_TYPE_TYPE, "__call__", - create_argon_native_function( - "__call__", ARGON_TYPE_TYPE___call__)); + create_argon_native_function("__call__", ARGON_TYPE_TYPE___call__)); ARGON_NULL_TYPE = new_object(); add_field(ARGON_NULL_TYPE, "__base__", BASE_CLASS); @@ -91,8 +126,7 @@ void bootstrap_types() { void add_to_scope(Stack *stack, char *name, ArgonObject *value) { size_t length = strlen(name); - uint64_t hash = - siphash64_bytes(name, length, siphash_key); + uint64_t hash = siphash64_bytes(name, length, siphash_key); ArgonObject *key = new_string_object(name, length); hashmap_insert_GC(stack->scope, hash, key, value, 0); } @@ -249,7 +283,9 @@ ArErr run_instruction(Translated *translated, RuntimeState *state, (state->call_instance->args)[index] = state->registers[0]; break; case OP_CALL:; - ArErr err = run_call(translated, state); + ArErr err = run_call(state->call_instance->to_call, + state->call_instance->args_length, + state->call_instance->args, state); free(state->call_instance->args); call_instance = *state->call_instance; free(state->call_instance); diff --git a/testing.ar b/testing.ar index 9f081ae..18353e3 100644 --- a/testing.ar +++ b/testing.ar @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2025 William Bell # SPDX-License-Identifier: GPL-3.0-or-later -type() \ No newline at end of file +type.__call__() \ No newline at end of file