From c6aab10e74d58fbcad723c5f074a0bb51e9f2283 Mon Sep 17 00:00:00 2001 From: hachem Date: Sat, 19 Sep 2026 18:53:06 +0200 Subject: feat: add functions with defines params and return --- eval.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 4 deletions(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index d19d029..c872c90 100644 --- a/eval.c +++ b/eval.c @@ -6,6 +6,9 @@ #include "eval.h" +#define DEPTH_MAX 32 +#define PARAMETERS_MAX 8 + static int evaluate_type(struct Machine* machine, const struct Node* node, struct Type* out); static int evaluate_value(struct Machine* machine, const struct Node* node, int64_t* out); static int evaluate_condition(struct Machine* machine, const struct Node* node, bool* out); @@ -44,6 +47,18 @@ static bool bind_variable(struct Machine* machine, const char* name, int64_t val return false; } +static struct Function* find_function(struct Machine* machine, const char* name) +{ + for (size_t index = 0; index < FUNCTIONS_MAX; index++) + { + struct Function* function = &machine->functions[index]; + if (function->defined && strcmp(function->name, name) == 0) + return function; + } + + return NULL; +} + static int complain(const struct Node* node, const char* message) { (void)fprintf(stderr, "line %d: %s\n", node->line, message); @@ -118,7 +133,6 @@ static int evaluate_value(struct Machine* machine, const struct Node* node, int6 return 1; } -// writes what a type looks like when emitted. true when it does not fit static bool render(const struct Type* type, char* buffer, size_t size) { int written = 0; @@ -140,7 +154,6 @@ static bool render(const struct Type* type, char* buffer, size_t size) return written < 0 || (size_t)written >= size; } -// a tuple says everything its elements say, in order static int evaluate_tuple(struct Machine* machine, const struct Node* node, struct Type* out) { out->kind = KIND_TUPLE; @@ -160,6 +173,67 @@ static int evaluate_tuple(struct Machine* machine, const struct Node* node, stru return 0; } +static int invoke(struct Machine* machine, const struct Node* node, struct Type* out) +{ + struct Function* function = find_function(machine, node->name); + if (function == NULL) + return complain(node, "no such function, define it first, like everything else"); + + if (machine->depth >= DEPTH_MAX) + return complain(node, "too deep, this was never meant to scale"); + + struct Type arguments[PARAMETERS_MAX]; + size_t count = 0; + const struct Node* parameter = function->node->first; + const struct Node* argument = node->first; + while (parameter != NULL && argument != NULL) + { + if (count == PARAMETERS_MAX) + return complain(node, "too many arguments, nobody needs that many"); + + if (evaluate_type(machine, argument, &arguments[count])) + return 1; + + if (arguments[count].kind != KIND_VALUE) + return complain(argument, "an argument carries a value, decltype it"); + + count++; + parameter = parameter->next; + argument = argument->next; + } + + if (parameter != NULL || argument != NULL) + return complain(node, "wrong number of arguments, count them again"); + + struct Variable saved[VARIABLES_MAX]; + memcpy(saved, machine->variables, sizeof saved); + memset(machine->variables, 0, sizeof machine->variables); + parameter = function->node->first; + for (size_t index = 0; index < count; index++) + { + (void)bind_variable(machine, parameter->name, arguments[index].number); + parameter = parameter->next; + } + + machine->depth++; + enum RunStatus status = execute(machine, function->node->body); + machine->depth--; + memcpy(machine->variables, saved, sizeof saved); + if (status == RUN_FAILED) + return 1; + + if (status == RUN_RETURNED) + *out = machine->returned; + else + { + out->kind = KIND_VOID; + out->number = 0; + out->text[0] = '\0'; + } + + return 0; +} + static int evaluate_type(struct Machine* machine, const struct Node* node, struct Type* out) { out->kind = KIND_VOID; @@ -175,6 +249,7 @@ static int evaluate_type(struct Machine* machine, const struct Node* node, struc case TYPE_SIZE: out->kind = KIND_SIZE; return 0; case TYPE_CHAR: out->kind = KIND_CHAR; return 0; case TYPE_TUPLE: return evaluate_tuple(machine, node, out); + case TYPE_INVOKE: return invoke(machine, node, out); case TYPE_CHAR_CONSTANT: if (evaluate_value(machine, node->first, &out->number)) return 1; @@ -293,7 +368,6 @@ static enum RunStatus emit(struct Machine* machine, const struct Node* node) if (evaluate_type(machine, node->first, &type)) return RUN_FAILED; - // void says nothing, not even a newline. everything else says its piece and ends the line if (type.kind == KIND_VOID) return RUN_DONE; @@ -320,7 +394,6 @@ static enum RunStatus enable_if(struct Machine* machine, const struct Node* node return execute(machine, node->body); } -// runs the body count times. no index, no condition, no break. you wanted a loop static enum RunStatus repeat(struct Machine* machine, const struct Node* node) { int64_t count = 0; @@ -352,6 +425,44 @@ static enum RunStatus static_assert_statement(struct Machine* machine, const str return RUN_DONE; } +static enum RunStatus define(struct Machine* machine, const struct Node* node) +{ + if (find_function(machine, node->name) != NULL) + { + (void)complain(node, "already defined, functions are forever"); + return RUN_FAILED; + } + + for (size_t index = 0; index < FUNCTIONS_MAX; index++) + { + struct Function* function = &machine->functions[index]; + if (function->defined) + continue; + + (void)snprintf(function->name, sizeof function->name, "%s", node->name); + function->node = node; + function->defined = true; + return RUN_DONE; + } + + (void)complain(node, "too many functions, this was never meant to scale"); + return RUN_FAILED; +} + +static enum RunStatus return_statement(struct Machine* machine, const struct Node* node) +{ + if (machine->depth == 0) + { + (void)complain(node, "return from what, exactly"); + return RUN_FAILED; + } + + if (evaluate_type(machine, node->first, &machine->returned)) + return RUN_FAILED; + + return RUN_RETURNED; +} + static enum RunStatus execute_one(struct Machine* machine, const struct Node* node) { switch (node->kind) @@ -362,6 +473,8 @@ static enum RunStatus execute_one(struct Machine* machine, const struct Node* no case STMT_REPEAT: return repeat(machine, node); case STMT_EMIT: return emit(machine, node); case STMT_STATIC_ASSERT: return static_assert_statement(machine, node); + case STMT_DEFINE: return define(machine, node); + case STMT_RETURN: return return_statement(machine, node); default: break; } -- cgit v1.3