hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c121
1 files changed, 117 insertions, 4 deletions
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;
}