From 4c52777ca9e52edd0bff76168d886de9757ea457 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 30 Dec 2021 16:53:37 +0100 Subject: [PATCH] Add :ref module and refactor type handling --- Makefile | 2 +- api/bool.c | 6 ++--- api/bool.h | 5 ++-- api/int.c | 11 +++++--- api/int.h | 4 +-- api/nil.c | 8 +++--- api/nil.h | 3 +-- api/ref.c | 17 ++++++++----- api/ref.h | 4 +-- api/str.c | 8 +++--- api/str.h | 5 ++-- api/util.c | 15 +++++++++++ api/util.h | 8 ++++++ api/vm.c | 74 +++++++++++++++++++++++++++++++----------------------- api/vm.h | 14 +++++------ doc/std.md | 32 +++++++++-------------- src/vm.c | 6 ++--- std/bool.c | 13 +++------- std/int.c | 16 ++++-------- std/nil.c | 6 +++++ std/ref.c | 21 ++++++++++++++++ std/str.c | 6 +++++ 22 files changed, 170 insertions(+), 114 deletions(-) create mode 100644 api/util.c create mode 100644 api/util.h create mode 100644 std/ref.c diff --git a/Makefile b/Makefile index 8dbf5d8..17c6922 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ uwu: src/*.c src/*.h .PHONY: std api -std: std/bool.so std/int.so std/str.so std/nil.so +std: std/bool.so std/int.so std/str.so std/nil.so std/ref.so api: api/api.so std/%.so: std/%.c diff --git a/api/bool.c b/api/bool.c index 4cbc3f3..768ae2f 100644 --- a/api/bool.c +++ b/api/bool.c @@ -25,7 +25,7 @@ bool uwubool_get(UwUVMValue vm_value) return true; } -static void *uwubool_copy(void *data) +static void *uwubool_clone(void *data) { bool *copy = malloc(sizeof(*copy)); *copy = *(bool *) data; @@ -38,7 +38,7 @@ static char *uwubool_print(void *data) } UwUVMType uwubool_type = { - .copy = &uwubool_copy, - .delete = &free, + .clone = &uwubool_clone, + .delet = &free, .print = &uwubool_print, }; diff --git a/api/bool.h b/api/bool.h index 70dfd60..2e43f78 100644 --- a/api/bool.h +++ b/api/bool.h @@ -5,8 +5,7 @@ #include "vm.h" extern UwUVMType uwubool_type; - -UwUVMValue uwubool_create(bool value); -bool uwubool_get(UwUVMValue vm_value); +UwUVMValue uwubool_create(bool value); +bool uwubool_get(UwUVMValue vm_value); #endif diff --git a/api/int.c b/api/int.c index 0b9329d..8446d1d 100644 --- a/api/int.c +++ b/api/int.c @@ -13,7 +13,12 @@ UwUVMValue uwuint_create(int value) return vm_value; } -void *uwuint_copy(void *data) +int uwuint_get(UwUVMValue vm_value) +{ + return *(int *) vm_value.data; +} + +void *uwuint_clone(void *data) { int *copy = malloc(sizeof(*copy)); *copy = *(int *) data; @@ -26,7 +31,7 @@ char *uwuint_print(void *data) } UwUVMType uwuint_type = { - .copy = &uwuint_copy, - .delete = &free, + .clone = &uwuint_clone, + .delet = &free, .print = &uwuint_print, }; diff --git a/api/int.h b/api/int.h index e9c5798..6b5361d 100644 --- a/api/int.h +++ b/api/int.h @@ -4,7 +4,7 @@ #include "vm.h" extern UwUVMType uwuint_type; - -UwUVMValue uwuint_create(int value); +UwUVMValue uwuint_create(int value); +int uwuint_get(UwUVMValue vm_value); #endif diff --git a/api/nil.c b/api/nil.c index b6304e0..2c47cb6 100644 --- a/api/nil.c +++ b/api/nil.c @@ -9,12 +9,12 @@ UwUVMValue uwunil_create() }; } -static void *uwunil_copy(void *data) +static void *uwunil_clone(void *data) { return data; } -static void uwunil_delete(void *data) +static void uwunil_delet(void *data) { (void) data; } @@ -26,7 +26,7 @@ static char *uwunil_print(void *data) } UwUVMType uwunil_type = { - .copy = &uwunil_copy, - .delete = &uwunil_delete, + .clone = &uwunil_clone, + .delet = &uwunil_delet, .print = &uwunil_print, }; diff --git a/api/nil.h b/api/nil.h index 014be45..7b2a5cf 100644 --- a/api/nil.h +++ b/api/nil.h @@ -4,7 +4,6 @@ #include "vm.h" extern UwUVMType uwunil_type; - -UwUVMValue uwunil_create(); +UwUVMValue uwunil_create(); #endif diff --git a/api/ref.c b/api/ref.c index f66ae19..43eb68e 100644 --- a/api/ref.c +++ b/api/ref.c @@ -1,20 +1,25 @@ #include "../src/util.h" #include "ref.h" -UwUVMValue uwuref_create(UwUVMFunction *function) +UwUVMValue uwuref_create(UwUVMFunction *value) { return (UwUVMValue) { .type = &uwuref_type, - .data = function, + .data = value, }; } -static void *uwuref_copy(void *data) +UwUVMFunction *uwuref_get(UwUVMValue value) +{ + return value.data; +} + +static void *uwuref_clone(void *data) { return data; } -static void uwuref_delete(void *data) +static void uwuref_delet(void *data) { (void) data; } @@ -25,7 +30,7 @@ static char *uwuref_print(void *data) } UwUVMType uwuref_type = { - .copy = &uwuref_copy, - .delete = &uwuref_delete, + .clone = &uwuref_clone, + .delet = &uwuref_delet, .print = &uwuref_print, }; diff --git a/api/ref.h b/api/ref.h index 6a2fead..4bbe017 100644 --- a/api/ref.h +++ b/api/ref.h @@ -4,7 +4,7 @@ #include "vm.h" extern UwUVMType uwuref_type; - -UwUVMValue uwuref_create(UwUVMFunction *function); +UwUVMValue uwuref_create(UwUVMFunction *value); +UwUVMFunction *uwuref_get(UwUVMValue vm_value); #endif diff --git a/api/str.c b/api/str.c index 84d2b10..eefd0d7 100644 --- a/api/str.c +++ b/api/str.c @@ -12,10 +12,10 @@ UwUVMValue uwustr_create(const char *value) char *uwustr_get(UwUVMValue vm_value) { - vm_value.type->print(vm_value.data); + return uwuvm_print_value(vm_value); } -static void *uwustr_copy(void *data) +static void *uwustr_clone(void *data) { return strdup(data); } @@ -26,7 +26,7 @@ static char *uwustr_print(void *data) } UwUVMType uwustr_type = { - .copy = &uwustr_copy, - .delete = &free, + .clone = &uwustr_clone, + .delet = &free, .print = &uwustr_print, }; diff --git a/api/str.h b/api/str.h index 609328e..d7596fc 100644 --- a/api/str.h +++ b/api/str.h @@ -4,8 +4,7 @@ #include "vm.h" extern UwUVMType uwustr_type; - -UwUVMValue uwustr_create(const char *value); -char *uwustr_get(UwUVMValue vm_value); +UwUVMValue uwustr_create(const char *value); +char *uwustr_get(UwUVMValue vm_value); #endif diff --git a/api/util.c b/api/util.c new file mode 100644 index 0000000..c3e8a38 --- /dev/null +++ b/api/util.c @@ -0,0 +1,15 @@ +#include "../src/err.h" +#include "util.h" +#include "bool.h" + +UwUVMValue uwuutil_is_type(const char *fnname, UwUVMArgs *args, UwUVMType *type) +{ + if (args->num < 1) + error("error: %s requires at least one argument\n", fnname); + + for (size_t i = 0; i < args->num; i++) + if (uwuvm_get_arg(args, i).type != type) + return uwubool_create(false); + + return uwubool_create(true); +} diff --git a/api/util.h b/api/util.h new file mode 100644 index 0000000..259f53a --- /dev/null +++ b/api/util.h @@ -0,0 +1,8 @@ +#ifndef _API_UTIL_H_ +#define _API_UTIL_H_ + +#include "vm.h" + +UwUVMValue uwuutil_is_type(const char *fnname, UwUVMArgs *args, UwUVMType *type); + +#endif diff --git a/api/vm.c b/api/vm.c index 73ec87e..5cab6c0 100644 --- a/api/vm.c +++ b/api/vm.c @@ -6,33 +6,22 @@ #include "ref.h" #include "int.h" -void uwuvm_free_value(UwUVMValue value) +UwUVMValue uwuvm_clone_value(UwUVMValue value) { - value.type->delete(value.data); + return (UwUVMValue) { + .type = value.type, + .data = value.type->clone(value.data), + }; } -void uwuvm_free_args(UwUVMArgs *args) +void uwuvm_delet_value(UwUVMValue value) { - if (args->evaluated) { - for (size_t i = 0; i < args->num; i++) { - UwUVMValue *value = args->evaluated[i]; - - if (value) { - uwuvm_free_value(*value); - free(value); - } - } - - free(args->evaluated); - } + value.type->delet(value.data); } -UwUVMValue uwuvm_copy_value(UwUVMValue value) +char *uwuvm_print_value(UwUVMValue value) { - return (UwUVMValue) { - .type = value.type, - .data = value.type->copy(value.data), - }; + return value.type->print(value.data); } UwUVMValue uwuvm_get_arg(UwUVMArgs *args, size_t i) @@ -58,30 +47,53 @@ UwUVMValue uwuvm_evaluate_expression(UwUVMExpression *expression, UwUVMArgs *arg if ((size_t) expression->value.int_value >= args->num) error("error: not enough arguments (accessed argument $%d, but only %lu arguments were passed)\n", expression->value.int_value, args->num); - return uwuvm_copy_value(uwuvm_get_arg(args, expression->value.int_value)); + return uwuvm_clone_value(uwuvm_get_arg(args, expression->value.int_value)); case EX_FNNAME: return uwuref_create(expression->value.ref_value); case EX_FNCALL: - return uwuvm_run_function(expression->value.cll_value.function, (UwUVMArgs) { - .num = expression->value.cll_value.num_args, - .evaluated = expression->value.cll_value.num_args == 0 ? NULL : calloc(expression->value.cll_value.num_args, sizeof(UwUVMValue *)), - .unevaluated = expression->value.cll_value.args, - .super = args, - }); + return uwuvm_call_function( + expression->value.cll_value.function, + expression->value.cll_value.num_args, + expression->value.cll_value.args, + args + ); default: return (UwUVMValue) {}; } } -UwUVMValue uwuvm_run_function(UwUVMFunction *function, UwUVMArgs args) +UwUVMValue uwuvm_call_function(UwUVMFunction *function, size_t num_args, UwUVMExpression *unevaluated_args, UwUVMArgs *super_args) { - UwUVMValue value = function->type == MODULE_PLAIN + UwUVMValue *evaluated_args[num_args]; + + for (size_t i = 0; i < num_args; i++) + evaluated_args[i] = NULL; + + UwUVMArgs args = { + .num = num_args, + .evaluated = evaluated_args, + .unevaluated = unevaluated_args, + .super = super_args, + }; + + UwUVMValue return_value = function->type == MODULE_PLAIN ? uwuvm_evaluate_expression(function->value.plain, &args) : function->value.native(&args); - uwuvm_free_args(&args); - return value; + if (num_args > 0) { + for (size_t i = 0; i < num_args; i++) { + UwUVMValue *value = evaluated_args[i]; + + if (value) { + uwuvm_delet_value(*value); + free(value); + } + } + + } + + return return_value; } diff --git a/api/vm.h b/api/vm.h index 7286f63..81465f8 100644 --- a/api/vm.h +++ b/api/vm.h @@ -13,9 +13,9 @@ typedef enum typedef struct { - void *(*copy )(void *data); - void (*delete)(void *data); - char *(*print )(void *data); + void *(*clone)(void *data); + void (*delet)(void *data); + char *(*print)(void *data); } UwUVMType; typedef struct @@ -71,11 +71,11 @@ typedef struct size_t num_libraries; } UwUVMProgram; -void uwuvm_free_value(UwUVMValue value); -void uwuvm_free_args(UwUVMArgs *args); -UwUVMValue uwuvm_copy_value(UwUVMValue value); +UwUVMValue uwuvm_clone_value(UwUVMValue value); +void uwuvm_delet_value(UwUVMValue value); +char *uwuvm_print_value(UwUVMValue value); UwUVMValue uwuvm_get_arg(UwUVMArgs *args, size_t i); UwUVMValue uwuvm_evaluate_expression(UwUVMExpression *expression, UwUVMArgs *args); -UwUVMValue uwuvm_run_function(UwUVMFunction *function, UwUVMArgs args); +UwUVMValue uwuvm_call_function(UwUVMFunction *function, size_t num_args, UwUVMExpression *unevaluated_args, UwUVMArgs *super_args); #endif diff --git a/doc/std.md b/doc/std.md index debf460..2e7720b 100644 --- a/doc/std.md +++ b/doc/std.md @@ -1,50 +1,42 @@ # Standard library -## The `:nil` module - -- `:nil:nil`: The nil constant - ## The `:bool` module -- `:bool:if`: Requires exactly 3 arguments of arbitrary type. If $0 is a truthy value, evaluate and return $1. If $0 is a falsy value, evaluate and return $2. Values considered as falsy are: `:bool:false` and `:nil:nil`. Everything else is considered truey. - +- `:bool:if`: Requires exactly 3 arguments of arbitrary type. If $0 is a truthy value, evaluate and return $1. If $0 is a falsy value, evaluate and return $2. Values considered as falsy are: `:bool:false` and `:nil:nil`. Everything else is considered truthy. - `:bool:and`: Accepts an arbitrary number of arguments of arbitrary type, but at least one. Returns `:bool:true` if all of the arguments are considered truthy. - - `:bool:or`: Accepts an arbitrary number of arguments of arbitrary type, but at least one. Returns `:bool:true` if at least one of the arguments is considered truthy. - - `:bool:equal`: Accepts an arbitrary number of arguments of arbitrary type, but at least 2. Returns `bool:true` if either all of the arguments are considered truthy or all of the arguments are considered falsy. - - `:bool:not`: Accepts exactly one argument of arbitrary type. Returns `:bool:true` if the $0 is considered falsy, returns `:bool:false` if $0 is considered truthy. - - `:bool:true`: The true constant - - `:bool:false`: The false constant - - `:bool:is`: Accepts an arbitrary number of arguments of arbitrary type, but at least one. Returns `:bool:true` if all arguments are booleans (`:nil:nil` is NOT considered a boolean). ## The `:int` module - `:int:add`: Accepts an arbitrary number of integer arguments (or none at all) and returns the sum of all arguments, or `0` if none were given. - - `:int:sub`: Accepts exactly 2 integer arguments and returns their difference. - - `:int:mul`: Accepts an arbitrary number of integer arguments (or none at all) and returns the product of all arguments, or `1` if none were given. - - `:int:div`: Accepts exactly 2 integer arguments and returns their quotient (rounded towards 0). - - `:int:mod`: Accepts exactly 2 integer arguments and returns the reminder of their division. - - `:int:smaller`: Accepts exactly 2 integer arguments and returns `:bool:true` if $0 is smaller than $1, `:boool:false` else. - - `:int:greater`: Accepts exactly 2 integer arguments and returns `:bool:true` if $0 is greater than $1, `:bool:false` else. - - `:int:equal`: Accepts an arbitrary number of integer arguments, but at least 2. Returns `bool:true` if all the arguments are equal. - - `:int:is`: Accepts an arbitrary number of arguments of arbitrary type, but at least one. Returns `:bool:true` if all arguments are integers. +## The `:nil` module + +- `:nil:nil`: The nil constant +- `:nil:is`: Accepts an arbitrary number of arguments of arbitrary type, but at least one. Returns `:bool:true` if all arguments are strings. + +## The `:ref` module + +- `:ref:call`: Accepts a function reference as $0 and after that and arbitrary number of arguments of arbitrary type. Calls the function $0 with the arguments that follow and returns it's return value. +- `:ref:is`: Accepts an arbitrary number of arguments of arbitrary type, but at least one. Returns `:bool:true` if all arguments are function references. + ## The `:str` module - `:str:cat`: Accepts an arbitrary number of arguments of arbitrary type and returns the concatenation of their string representations. +- `:str:is`: Accepts an arbitrary number of arguments of arbitrary type, but at least one. Returns `:bool:true` if all arguments are strings. ### String representations diff --git a/src/vm.c b/src/vm.c index 335eb48..8b1b13a 100644 --- a/src/vm.c +++ b/src/vm.c @@ -20,14 +20,14 @@ static void free_expression(UwUVMExpression *expr) void vm_run_file(const char *progname, const char *modname) { UwUVMProgram program = create_program(progname, modname); - UwUVMValue result = ((UwUVMValue (*)(UwUVMFunction *, UwUVMArgs args)) dlsym(program.api_library, "uwuvm_run_function"))(program.main_function, (UwUVMArgs) {.num = 0, .evaluated = NULL, .unevaluated = NULL, .super = NULL}); + UwUVMValue result = ((UwUVMValue (*)(UwUVMFunction *, size_t, UwUVMExpression *, UwUVMArgs *)) dlsym(program.api_library, "uwuvm_call_function"))(program.main_function, 0, NULL, NULL); - char *str = ((char *(*)(UwUVMValue)) dlsym(program.api_library, "uwustr_get"))(result); + char *str = ((char *(*)(UwUVMValue)) dlsym(program.api_library, "uwuvm_print_value"))(result); printf("%s\n", str); free(str); - ((void (*)(UwUVMValue)) dlsym(program.api_library, "uwuvm_free_value"))(result); + ((void (*)(UwUVMValue)) dlsym(program.api_library, "uwuvm_delet_value"))(result); for (size_t i = 0; i < program.num_functions; i++) { UwUVMFunction *function = program.functions[i]; diff --git a/std/bool.c b/std/bool.c index 02aa887..4386dc3 100644 --- a/std/bool.c +++ b/std/bool.c @@ -2,8 +2,10 @@ #include #include "../src/err.h" #include "../api/vm.h" +#include "../api/util.h" #include "../api/bool.h" + static inline bool get_bool_arg(UwUVMArgs *args, size_t i) { return uwubool_get(uwuvm_get_arg(args, i)); @@ -14,7 +16,7 @@ UwUVMValue uwu_if(UwUVMArgs *args) if (args->num != 3) error("error: :bool:if requires exactly 3 arguments\n"); - return uwuvm_copy_value(get_bool_arg(args, 0) + return uwuvm_clone_value(get_bool_arg(args, 0) ? uwuvm_get_arg(args, 1) : uwuvm_get_arg(args, 2) ); @@ -84,12 +86,5 @@ UwUVMValue uwu_false(UwUVMArgs *args) UwUVMValue uwu_is(UwUVMArgs *args) { - if (args->num < 1) - error("error: :bool:is requires at least 1 argument\n"); - - for (size_t i = 0; i < args->num; i++) - if (uwuvm_get_arg(args, i).type != &uwubool_type) - return uwubool_create(false); - - return uwubool_create(true); + return uwuutil_is_type(":bool:is", args, &uwubool_type); } diff --git a/std/int.c b/std/int.c index c6c8ab7..6857f26 100644 --- a/std/int.c +++ b/std/int.c @@ -4,6 +4,7 @@ #include "../api/vm.h" #include "../api/int.h" #include "../api/bool.h" +#include "../api/util.h" typedef enum { @@ -30,8 +31,8 @@ static int binary(const char *fnname, UwUVMArgs *args, BinaryOP op) if (value1.type != &uwuint_type) error("error: %s requires an integer as $1\n", fnname); - int a = *(int *) value0.data; - int b = *(int *) value1.data; + int a = uwuint_get(value0); + int b = uwuint_get(value1); switch (op) { case BOP_SUB: return a - b; @@ -60,7 +61,7 @@ static int reduce(const char *fnname, UwUVMArgs *args, ReduceOP op, int result) if (value.type != &uwuint_type) error("error: %s only accepts integers as arguments (invalid argument: $%lu)\n", fnname, i); - int this = *(int *) value.data; + int this = uwuint_get(value); switch (op) { case ROP_ADD: result += this; break; @@ -123,12 +124,5 @@ UwUVMValue uwu_equal(UwUVMArgs *args) UwUVMValue uwu_is(UwUVMArgs *args) { - if (args->num < 1) - error("error: :int:is requires at least 1 argument\n"); - - for (size_t i = 0; i < args->num; i++) - if (uwuvm_get_arg(args, i).type != &uwuint_type) - return uwubool_create(false); - - return uwubool_create(true); + return uwuutil_is_type(":int:is", args, &uwuint_type); } diff --git a/std/nil.c b/std/nil.c index 33230fb..599e3d4 100644 --- a/std/nil.c +++ b/std/nil.c @@ -1,5 +1,6 @@ #include "../src/err.h" #include "../api/nil.h" +#include "../api/util.h" UwUVMValue uwu_nil(UwUVMArgs *args) { @@ -8,3 +9,8 @@ UwUVMValue uwu_nil(UwUVMArgs *args) return uwunil_create(); } + +UwUVMValue uwu_is(UwUVMArgs *args) +{ + return uwuutil_is_type(":nil:is", args, &uwunil_type); +} diff --git a/std/ref.c b/std/ref.c new file mode 100644 index 0000000..f82bb50 --- /dev/null +++ b/std/ref.c @@ -0,0 +1,21 @@ +#include "../src/err.h" +#include "../api/ref.h" +#include "../api/util.h" + +UwUVMValue uwu_call(UwUVMArgs *args) +{ + if (args->num < 1) + error(":ref:call requires at least one argument\n"); + + UwUVMValue value = uwuvm_get_arg(args, 0); + + if (value.type != &uwuref_type) + error(":ref:call requires a function reference as $0\n"); + + return uwuvm_call_function(value.data, args->num - 1, &args->unevaluated[1], args->super); +} + +UwUVMValue uwu_is(UwUVMArgs *args) +{ + return uwuutil_is_type(":ref:is", args, &uwuref_type); +} diff --git a/std/str.c b/std/str.c index 16f756b..953e8c0 100644 --- a/std/str.c +++ b/std/str.c @@ -2,6 +2,7 @@ #include #include "../api/vm.h" #include "../api/str.h" +#include "../api/util.h" UwUVMValue uwu_cat(UwUVMArgs *args) { @@ -28,3 +29,8 @@ UwUVMValue uwu_cat(UwUVMArgs *args) return uwustr_create(result); } + +UwUVMValue uwu_is(UwUVMArgs *args) +{ + return uwuutil_is_type(":str:is", args, &uwustr_type); +} -- 2.44.0