hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-19 13:47:08 +0200
committerhachem <im@hachem.wtf>2026-09-19 13:47:08 +0200
commitd0ca03c84bcad3dc42fd173b0baf3a15e9b52f9b (patch)
tree89fa494129849e23b1d760466e87ef6046cbfcb4 /eval.c
parenta79c97e04562b171780a24cba2cb1a71acfa4bbb (diff)
feat: add conditionals
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c58
1 files changed, 54 insertions, 4 deletions
diff --git a/eval.c b/eval.c
index 8c92cd8..eddeb6b 100644
--- a/eval.c
+++ b/eval.c
@@ -1,11 +1,13 @@
#include <assert.h>
#include <inttypes.h>
+#include <stdbool.h>
#include <stdio.h>
#include "eval.h"
static int evaluate_type(const struct Node* node, struct Type* out);
static int evaluate_value(const struct Node* node, int64_t* out);
+static int evaluate_condition(const struct Node* node, bool* out);
static int complain(const struct Node* node, const char* message)
{
@@ -26,6 +28,7 @@ static int evaluate_value(const struct Node* node, int64_t* out)
int64_t left = 0;
int64_t right = 0;
struct Type type;
+ bool truth = false;
switch (node->kind)
{
case VALUE_DIFFERENCE:
@@ -56,11 +59,14 @@ static int evaluate_value(const struct Node* node, int64_t* out)
case VALUE_TUPLE_SIZE:
if (evaluate_type(node->first, &type))
return 1;
-
- // a non-array has no extent, so it gets zero, exactly like the real thing
*out = type.kind == KIND_ARRAY ? type.number : 0;
return 0;
case VALUE_INTEGRAL_CONSTANT: return evaluate_value(node->first, out);
+ case VALUE_CONDITIONAL:
+ if (evaluate_condition(node->first, &truth))
+ return 1;
+
+ return evaluate_value(truth ? node->second : node->third, out);
default: break;
}
@@ -73,6 +79,7 @@ static int evaluate_type(const struct Node* node, struct Type* out)
out->kind = KIND_VOID;
out->number = 0;
struct Type element;
+ bool truth = false;
switch (node->kind)
{
case TYPE_VOID: return 0;
@@ -81,12 +88,14 @@ static int evaluate_type(const struct Node* node, struct Type* out)
case TYPE_SIZE: out->kind = KIND_SIZE; return 0;
case TYPE_REMOVE_CV: return evaluate_type(node->first, out);
case TYPE_ARRAY:
- // the element type is evaluated for its side of the bargain, then forgotten
if (evaluate_type(node->first, &element) || evaluate_value(node->second, &out->number))
return 1;
-
out->kind = KIND_ARRAY;
return 0;
+ case TYPE_CONDITIONAL:
+ if (evaluate_condition(node->first, &truth))
+ return 1;
+ return evaluate_type(truth ? node->second : node->third, out);
case TYPE_DECLTYPE:
if (evaluate_value(node->first, &out->number))
return 1;
@@ -99,6 +108,47 @@ static int evaluate_type(const struct Node* node, struct Type* out)
return 1;
}
+static bool same_type(const struct Type* left, const struct Type* right)
+{
+ return left->kind == right->kind && left->number == right->number;
+}
+
+static int evaluate_condition(const struct Node* node, bool* out)
+{
+ int64_t left = 0;
+ int64_t right = 0;
+ struct Type left_type;
+ struct Type right_type;
+ *out = false;
+ switch (node->kind)
+ {
+ case COND_TRUE: *out = true; return 0;
+ case COND_FALSE: return 0;
+ case COND_IS_SAME:
+ if (evaluate_type(node->first, &left_type) || evaluate_type(node->second, &right_type))
+ return 1;
+
+ *out = same_type(&left_type, &right_type);
+ return 0;
+ case COND_EQUAL:
+ if (evaluate_operands(node, &left, &right))
+ return 1;
+
+ *out = left == right;
+ return 0;
+ case COND_LESS:
+ if (evaluate_operands(node, &left, &right))
+ return 1;
+
+ *out = left < right;
+ return 0;
+ default: break;
+ }
+
+ assert(!"the parser handed a non-condition where a condition goes");
+ return 1;
+}
+
static enum RunStatus emit(const struct Node* node)
{
struct Type type;