From 4b6d15336ae0282927b8312a3fc6d5cfaee053f5 Mon Sep 17 00:00:00 2001 From: William Bell <62452284+Ugric@users.noreply.github.com> Date: Wed, 6 Aug 2025 22:31:31 +0100 Subject: [PATCH] make native function support and start working on support for error catching --- src/arobject.h | 6 +- src/runtime/call/call.c | 69 ++++++++++++++--------- src/runtime/call/call.h | 2 +- src/runtime/objects/functions/functions.c | 1 + src/runtime/objects/object.c | 28 ++++++++- src/runtime/objects/object.h | 4 +- src/runtime/runtime.c | 13 ++--- src/runtime/runtime.h | 8 ++- testing.ar | 4 +- 9 files changed, 91 insertions(+), 44 deletions(-) diff --git a/src/arobject.h b/src/arobject.h index b8c2ca2..367db70 100644 --- a/src/arobject.h +++ b/src/arobject.h @@ -7,10 +7,13 @@ #ifndef AROBJECT_H #define AROBJECT_H +#include "dynamic_array/darray.h" #include "runtime/internals/dynamic_array_armem/darray_armem.h" #include "runtime/internals/hashmap/hashmap.h" #include +typedef struct ArErr ArErr; + typedef struct ArgonObject ArgonObject; // forward declaration typedef enum ArgonType { @@ -40,6 +43,7 @@ struct argon_function_struct { size_t number_of_parameters; struct string_struct *parameters; char* path; + DArray source_locations; uint64_t line; uint64_t column; }; @@ -54,7 +58,7 @@ struct ArgonObject { mpq_t as_number; bool as_bool; struct string_struct as_str; - void *native_fn; + ArgonObject* (*native_fn)(size_t argc, ArgonObject**argv, ArErr*err); struct argon_function_struct argon_fn; } value; }; diff --git a/src/runtime/call/call.c b/src/runtime/call/call.c index 871373d..1ac148b 100644 --- a/src/runtime/call/call.c +++ b/src/runtime/call/call.c @@ -11,9 +11,8 @@ #include #include #include -#include #include - +#include #if defined(_WIN32) #include @@ -70,26 +69,29 @@ double get_memory_usage_mb() { } #endif -void run_call(Translated *translated, RuntimeState *state) { +ArErr run_call(Translated *translated, RuntimeState *state) { uint8_t from_register = pop_byte(translated, state); uint8_t source_location_index = pop_bytecode(translated, state); - ArgonObject *object = state->registers[from_register]; - if (object->type != TYPE_FUNCTION) { - ArgonObject *to_call = get_field(object,"__class__"); - while (to_call) { - ArgonObject *call_object = get_field(to_call,"__call__"); - if (call_object) { - ArgonObject** new_call_args = malloc(sizeof(ArgonObject*)*(*state->call_args_length+1)); - memcpy(new_call_args+1, *state->call_args, *state->call_args_length); - free(*state->call_args); - new_call_args[0] = object; - *state->call_args = new_call_args; - (*state->call_args_length)++; - object = call_object; - break; + ArgonObject *original_object = state->registers[from_register]; + ArgonObject *object = original_object; + if (object->type != TYPE_FUNCTION && object->type != TYPE_NATIVE_FUNCTION) { + ArgonObject *call_method = + get_field_for_class(get_field(object, "__class__", false), "__call__"); + if (call_method) { + // Prepend the original object as first argument (self) + ArgonObject **new_call_args = + malloc(sizeof(ArgonObject *) * (*state->call_args_length + 1)); + new_call_args[0] = object; + if (*state->call_args_length > 0) { + memcpy(new_call_args + 1, *state->call_args, *state->call_args_length); } - to_call = get_field(to_call,"__base__"); - }; + if (*state->call_args) { + free(*state->call_args); + } + *state->call_args = new_call_args; + (*state->call_args_length)++; + object = call_method; + } } if (object->type == TYPE_FUNCTION) { Stack *scope = create_scope(object->value.argon_fn.stack); @@ -104,22 +106,23 @@ void run_call(Translated *translated, RuntimeState *state) { object->value.argon_fn.bytecode_length, object->value.argon_fn.bytecode_length, false}; StackFrame new_stackFrame = { - (Translated){translated->registerCount, NULL, bytecode_darray, - translated->source_locations, translated->constants, + {translated->registerCount, NULL, bytecode_darray, + object->value.argon_fn.source_locations, translated->constants, object->value.argon_fn.path}, - (RuntimeState){state->registers, 0, state->path, + {state->registers, 0, state->path, state->currentStackFramePointer, state->call_args, - state->call_args_length}, + state->call_args_length, {}}, scope, *state->currentStackFramePointer, - no_err, (*state->currentStackFramePointer)->depth + 1}; - if (((*state->currentStackFramePointer)->depth+1) % STACKFRAME_CHUNKS == 0) { - *state->currentStackFramePointer = checked_malloc(sizeof(StackFrame) * STACKFRAME_CHUNKS); + if (((*state->currentStackFramePointer)->depth + 1) % STACKFRAME_CHUNKS == + 0) { + *state->currentStackFramePointer = + checked_malloc(sizeof(StackFrame) * STACKFRAME_CHUNKS); } else { *state->currentStackFramePointer = *state->currentStackFramePointer + 1; } - **state->currentStackFramePointer = new_stackFrame; + **state->currentStackFramePointer = new_stackFrame; if ((*state->currentStackFramePointer)->depth >= 10000) { double logval = log10((double)(*state->currentStackFramePointer)->depth); if (floor(logval) == logval) { @@ -133,11 +136,21 @@ void run_call(Translated *translated, RuntimeState *state) { (*state->currentStackFramePointer)->depth); if (memoryUsage) { fprintf(stderr, ", memory usage at %f MB\n", memoryUsage); - } else { fprintf(stderr, "\n"); } } }; + return no_err; + } else if (object->type == TYPE_NATIVE_FUNCTION) { + ArErr err = no_err; + state->registers[0] = + object->value.native_fn(*state->call_args_length, *state->call_args, + &err); + return err; } + SourceLocation *source_location = + darray_get(&translated->source_locations, source_location_index); + ArgonObject *type_object_name = get_field_for_class(get_field(object, "__class__", false), "__name__"); + return create_err(source_location->line, source_location->column, source_location->length, state->path, "Type Error", "'%.*s' object is not callable", (int)type_object_name->value.as_str.length, type_object_name->value.as_str.data); } \ No newline at end of file diff --git a/src/runtime/call/call.h b/src/runtime/call/call.h index 28d7d92..42df423 100644 --- a/src/runtime/call/call.h +++ b/src/runtime/call/call.h @@ -8,6 +8,6 @@ #define runtime_call_H #include "../runtime.h" -void run_call(Translated *translated, RuntimeState *state); +ArErr run_call(Translated *translated, RuntimeState *state); #endif // runtime_call_H \ No newline at end of file diff --git a/src/runtime/objects/functions/functions.c b/src/runtime/objects/functions/functions.c index fdae740..166ec7e 100644 --- a/src/runtime/objects/functions/functions.c +++ b/src/runtime/objects/functions/functions.c @@ -23,6 +23,7 @@ void load_argon_function(Translated *translated, RuntimeState *state, uint64_t length = pop_bytecode(translated, state); add_field(object, "__name__", new_string_object(arena_get(&translated->constants, offset), length)); object->value.argon_fn.path = translated->path; + object->value.argon_fn.source_locations = translated->source_locations; object->value.argon_fn.number_of_parameters = pop_bytecode(translated, state); object->value.argon_fn.parameters = ar_alloc(object->value.argon_fn.number_of_parameters * sizeof(struct string_struct)); diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index c93a35c..f4f89f0 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -26,7 +26,29 @@ void add_field(ArgonObject *target, char *name, ArgonObject *object) { object, 0); } -ArgonObject *get_field(ArgonObject *target, char *name) { - uint64_t hash = siphash64_bytes(name, strlen(name), siphash_key); - return hashmap_lookup_GC(target->dict, hash); +ArgonObject *get_field_for_class(ArgonObject *target, char *name) { + 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) + return object; + hash = siphash64_bytes(field, strlen(field), siphash_key); + target = hashmap_lookup_GC(target->dict, hash); + } + return NULL; +} + +ArgonObject *get_field(ArgonObject *target, char *name, bool recursive) { + char *field = "__class__"; + while (target) { + uint64_t hash = siphash64_bytes(name, strlen(name), siphash_key); + ArgonObject *object = hashmap_lookup_GC(target->dict, hash); + if (!recursive || object) + return object; + hash = siphash64_bytes(field, strlen(field), siphash_key); + target = hashmap_lookup_GC(target->dict, hash); + field = "__base__"; + } + return NULL; } \ No newline at end of file diff --git a/src/runtime/objects/object.h b/src/runtime/objects/object.h index 614d568..a297fcc 100644 --- a/src/runtime/objects/object.h +++ b/src/runtime/objects/object.h @@ -17,6 +17,8 @@ ArgonObject *new_object(); void add_field(ArgonObject *target, char *name, ArgonObject *object); -ArgonObject *get_field(ArgonObject *target, char *name); +ArgonObject *get_field_for_class(ArgonObject *target, char *name); + +ArgonObject *get_field(ArgonObject *target, char *name, bool recursive); #endif // OBJECT_H \ No newline at end of file diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 38623e8..efb0bf4 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -214,7 +214,7 @@ ArErr run_instruction(Translated *translated, RuntimeState *state, state->registers[to_register]; break; case OP_CALL: - run_call(translated, state); + return run_call(translated, state); // ArgonObject *object = state->registers[from_register]; // char *field = "__class__"; // uint64_t hash = siphash64_bytes(field, strlen(field), siphash_key); @@ -234,7 +234,6 @@ ArErr run_instruction(Translated *translated, RuntimeState *state, // (int)class_name->value.as_str.length, class_name->value.as_str.data, // object); // } - break; default: return create_err(0, 0, 0, NULL, "Runtime Error", "Invalid Opcode %#x", opcode); @@ -249,7 +248,8 @@ RuntimeState init_runtime_state(Translated translated, char *path) { path, NULL, NULL, - NULL}; + 0, + {}}; return runtime; } @@ -275,19 +275,18 @@ ArErr runtime(Translated translated, RuntimeState state, Stack *stack) { StackFrame *currentStackFrame = checked_malloc(sizeof(StackFrame) * STACKFRAME_CHUNKS); - *currentStackFrame = (StackFrame){translated, state, stack, NULL, no_err, 0}; + *currentStackFrame = (StackFrame){translated, state, stack, NULL, 0}; currentStackFrame->state.currentStackFramePointer = ¤tStackFrame; ArErr err = no_err; while (currentStackFrame) { while (currentStackFrame->state.head < currentStackFrame->translated.bytecode.size && - !currentStackFrame->err.exists) { - currentStackFrame->err = + !err.exists) { + err = run_instruction(¤tStackFrame->translated, ¤tStackFrame->state, ¤tStackFrame->stack); } StackFrame *tempStackFrame = currentStackFrame; - err = currentStackFrame->err; currentStackFrame = currentStackFrame->previousStackFrame; if (tempStackFrame->depth % STACKFRAME_CHUNKS == 0) { free(tempStackFrame); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index e2bcaf9..3d0ced9 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -14,6 +14,12 @@ typedef struct StackFrame StackFrame; typedef struct RuntimeState RuntimeState; +typedef struct ErrorCatch { + size_t jump_to; + Stack *stack; + StackFrame *stackFrame; +} ErrorCatch; + typedef struct RuntimeState { ArgonObject **registers; size_t head; @@ -21,6 +27,7 @@ typedef struct RuntimeState { StackFrame **currentStackFramePointer; ArgonObject*** call_args; size_t* call_args_length; + DArray catch_errors; // ErrorCatch[] } RuntimeState; typedef struct StackFrame { @@ -28,7 +35,6 @@ typedef struct StackFrame { RuntimeState state; Stack *stack; StackFrame *previousStackFrame; - ArErr err; uint64_t depth; } StackFrame; diff --git a/testing.ar b/testing.ar index c76956b..7c12052 100644 --- a/testing.ar +++ b/testing.ar @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: 2025 William Bell # SPDX-License-Identifier: GPL-3.0-or-later -let f()=f() -f() +let f(name)="" +f("bruh")() \ No newline at end of file