diff --git a/lang/main.c b/lang/main.c index a82a01b..7dd85d3 100644 --- a/lang/main.c +++ b/lang/main.c @@ -1,100 +1,24 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2023 John Watts and the LuminaSensum contributors -#include +#include "number.h" #include -#include -#include - -#include "error.h" -#include "symbol.h" - -struct object; - -#define ARGS_MAX 8 - -typedef struct { - struct object *args[ARGS_MAX]; -} argstack; - -typedef struct object *(object_call)(struct object *, int, argstack *); - -typedef struct { - symbol symbol; - object_call *call; -} call_mapping; - -#define CALLS_MAX 32 - -typedef struct object { - int value; - atomic_int refcount; - call_mapping calls[CALLS_MAX]; - int calls_count; -} object; - -object *create_object(int value); - -object *add_objects(object *objA, int args, argstack *stack) { - abort_if(args != 1, "wrong arg count"); - object *objB = stack->args[0]; - abort_if(objB == NULL, "objB is null"); - int new_value = objA->value + objB->value; - return create_object(new_value); -} - -object *create_object(int value) { - object *obj = malloc(sizeof(object)); - abort_if(!obj, "obj malloc failed"); - obj->value = value; - obj->refcount = 1; - call_mapping *add_call = &obj->calls[0]; - add_call->symbol = find_symbol("Add"); - add_call->call = add_objects; - obj->calls_count = 1; - return obj; -} - -void drop_object(object **objptr) { - if (*objptr) { - object *obj = *objptr; - atomic_int count = atomic_fetch_sub_explicit( - &obj->refcount, 1, memory_order_relaxed); - if (count == 1) { - printf("freeing %p\n", (void *)obj); - free(obj); - } - } - *objptr = NULL; -} - -object *dispatch_call(object *obj, int sym, int args, argstack *stack) { - for (int i = 0; i < obj->calls_count; ++i) { - call_mapping *curr_call = &obj->calls[i]; - int symbol = curr_call->symbol; - if (symbol == sym) { - return curr_call->call(obj, args, stack); - } - } - abort_msg("no call found to dispatch"); -} int lang_main(void) { printf("Hello world!\n"); printf("symb %i\n", find_symbol("a")); printf("symb %i\n", find_symbol("b")); - object *numA = create_object(5); - object *numB = create_object(3); - argstack stack; - stack.args[0] = numB; - object *numC = dispatch_call(numA, find_symbol("Add"), 1, &stack); - printf("numC value is %i\n", numC->value); + struct object *numA = number_create(5); + struct object *numB = number_create(3); + struct object *args[] = {numB}; + struct object *numC = dispatch_call(numA, "Add", 1, &args[0]); + printf("numC value is %i\n", number_value(numC)); printf("numA is %p\n", (void *)numA); printf("numB is %p\n", (void *)numB); printf("numC is %p\n", (void *)numC); - drop_object(&numA); - drop_object(&numB); - drop_object(&numC); + object_drop(&numA); + object_drop(&numB); + object_drop(&numC); printf("numA is %p\n", (void *)numA); printf("numB is %p\n", (void *)numB); printf("numC is %p\n", (void *)numC); diff --git a/lang/number.c b/lang/number.c new file mode 100644 index 0000000..3f2dc8f --- /dev/null +++ b/lang/number.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2023 John Watts and the LuminaSensum contributors + +#include "error.h" +#include "object.h" +#include "stdio.h" +#include + +struct object_class num_class; + +struct number { + struct object obj; + int value; +}; + +struct object *number_create(int value) { + struct number *num = malloc(sizeof(struct number)); + abort_if(!num, "unable to allocate number"); + num->obj.class_data = &num_class; + num->obj.ref_count = 1; + num->value = value; + return (struct object *)num; +} + +void number_cleanup(struct object *obj) { + abort_if(obj->class_data != &num_class, + "number_cleanup obj is not a number"); + struct number *num = (struct number *)obj; + free(num); +} + +int number_value(struct object *obj) { + abort_if(obj->class_data != &num_class, + "number_value obj is not a number"); + struct number *num = (struct number *)obj; + return num->value; +} + +struct object *number_add( + struct object *obj, int arg_count, struct object **args) { + abort_if(arg_count != 1, "number_add called with more than 1 argument"); + abort_if(!args[0], "number_add arg is NULL"); + abort_if(obj->class_data != &num_class, + "number_add obj is not a number"); + abort_if(args[0]->class_data != &num_class, + "number_add arg is not a number"); + struct number *numA = (struct number *)obj; + struct number *numB = (struct number *)args[0]; + int added = numA->value + numB->value; + return number_create(added); +} + +struct object_call calls[] = { + {.name = "Add", .handler = number_add}, {.name = NULL, /* end */}}; + +struct object_class num_class = { + .cleanup = number_cleanup, + .calls = &calls[0], +}; diff --git a/lang/number.h b/lang/number.h new file mode 100644 index 0000000..4f3a5d7 --- /dev/null +++ b/lang/number.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2023 John Watts and the LuminaSensum contributors + +#ifndef NUMBER_H +#define NUMBER_H + +#include "object.h" + +// Creates a number +struct object *number_create(int value); + +// Gets a number's value +int number_value(struct object *); + +// Adds two numbers together +struct object *number_add(struct object *, struct object *); + +#endif diff --git a/lang/object.c b/lang/object.c new file mode 100644 index 0000000..62907ad --- /dev/null +++ b/lang/object.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2023 John Watts and the LuminaSensum contributors + +#include "object.h" +#include "error.h" +#include +#include + +void object_drop(struct object **objptr) { + if (*objptr == NULL) { + return; + } + struct object *obj = *objptr; + atomic_int count = atomic_fetch_sub_explicit( + &obj->ref_count, 1, memory_order_relaxed); + if (count == 1) { + // We were the last user of the object, clean it up + obj->class_data->cleanup(obj); + } + *objptr = NULL; +} + +struct object *dispatch_call(struct object *obj, const char *name, + int arg_count, struct object **args) { + struct object_call *call = obj->class_data->calls; + while (call->name != NULL) { + if (strcmp(call->name, name) == 0) { + return call->handler(obj, arg_count, args); + } + ++call; + } + abort_msg("no call found to dispatch"); +} diff --git a/lang/object.h b/lang/object.h new file mode 100644 index 0000000..c22728a --- /dev/null +++ b/lang/object.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2023 John Watts and the LuminaSensum contributors + +#ifndef OBJECT_H +#define OBJECT_H + +#include "symbol.h" +#include + +// Forward declare the class as we need it in object +struct object_class; + +// Object structure used by all classes +// Place this at the start of your private structure and cast accordingly +// Make sure to compile with -fno-strict-aliasing +struct object { + struct object_class *class_data; + atomic_int ref_count; +}; + +// Dispatchable object call +struct object_call { + const char *name; + struct object *(*handler)( + struct object *obj, int arg_count, struct object **args); +}; + +// Object class shared between objects +struct object_class { + void (*cleanup)(struct object *obj); + struct object_call + *calls; // Points to array terminated by call with NULL name +}; + +// Drops a reference to an object, possibly cleaning up the object +// Sets objptr to NULL +void object_drop(struct object **objptr); + +// Calls a method on an object +struct object *dispatch_call(struct object *obj, const char *name, + int arg_count, struct object **args); + +#endif