hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-19 14:38:55 +0200
committerhachem <im@hachem.wtf>2026-09-19 14:38:55 +0200
commitb79902cd36b2c5b54bbf0f07078fc528754977b2 (patch)
tree0f3baa55b58831c46c7631619f76eef5cb371f71
parent7160bdb390ef1c9bdcfb0c075b33be39d62860f3 (diff)
feat: variables and shi
-rw-r--r--ast.c24
-rw-r--r--ast.h19
-rw-r--r--eval.c140
-rw-r--r--eval.h18
-rw-r--r--examples/xs.sfinae54
-rw-r--r--main.c6
-rw-r--r--sfinae.l3
-rw-r--r--sfinae.y35
8 files changed, 237 insertions, 62 deletions
diff --git a/ast.c b/ast.c
index e420ba3..ed694f9 100644
--- a/ast.c
+++ b/ast.c
@@ -5,6 +5,22 @@
#include <stdlib.h>
#include <string.h>
+void name_init(struct Name* name)
+{
+ name->length = 0;
+ name->text[0] = '\0';
+}
+
+bool name_push(struct Name* name, char character)
+{
+ if (name->length == NAME_LENGTH_MAX)
+ return false;
+
+ name->text[name->length++] = character;
+ name->text[name->length] = '\0';
+ return true;
+}
+
static struct Node* node_new(enum NodeKind kind)
{
struct Node* node = calloc(1, sizeof *node);
@@ -55,6 +71,14 @@ struct Node* node_ternary(enum NodeKind kind, struct Node* first, struct Node* s
return node;
}
+struct Node* node_named(enum NodeKind kind, const struct Name* name, struct Node* first)
+{
+ struct Node* node = node_new(kind);
+ (void)snprintf(node->name, sizeof node->name, "%s", name->text);
+ node->first = first;
+ return node;
+}
+
struct Node* node_append(struct Node* list, struct Node* node)
{
struct Node* last = list;
diff --git a/ast.h b/ast.h
index 39924b6..d17eaef 100644
--- a/ast.h
+++ b/ast.h
@@ -1,5 +1,11 @@
#pragma once
+#include <stdbool.h>
+#include <stddef.h>
+
+// names longer than this are refused, nobody needs a longer name
+#define NAME_LENGTH_MAX 15
+
enum NodeKind
{
NODE_CHAR,
@@ -19,32 +25,45 @@ enum NodeKind
VALUE_TUPLE_SIZE,
VALUE_INTEGRAL_CONSTANT,
VALUE_CONDITIONAL,
+ VALUE_VARIABLE,
COND_TRUE,
COND_FALSE,
COND_IS_SAME,
COND_EQUAL,
COND_LESS,
+ STMT_DECLARE,
STMT_EMIT,
STMT_STATIC_ASSERT
};
+struct Name
+{
+ char text[NAME_LENGTH_MAX + 1];
+ size_t length;
+};
+
struct Node
{
enum NodeKind kind;
int line;
char character;
+ char name[NAME_LENGTH_MAX + 1];
struct Node* first;
struct Node* second;
struct Node* third;
struct Node* next;
};
+void name_init(struct Name* name);
+bool name_push(struct Name* name, char character);
+
struct Node* node_leaf(enum NodeKind kind);
struct Node* node_char(char character);
struct Node* node_unary(enum NodeKind kind, struct Node* first);
struct Node* node_binary(enum NodeKind kind, struct Node* first, struct Node* second);
struct Node* node_ternary(enum NodeKind kind, struct Node* first, struct Node* second,
struct Node* third);
+struct Node* node_named(enum NodeKind kind, const struct Name* name, struct Node* first);
struct Node* node_append(struct Node* list, struct Node* node);
void node_free(struct Node* node);
diff --git a/eval.c b/eval.c
index b0ad454..fc6e6d7 100644
--- a/eval.c
+++ b/eval.c
@@ -2,12 +2,47 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
+#include <string.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 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);
+
+void machine_init(struct Machine* machine)
+{
+ memset(machine, 0, sizeof *machine);
+}
+
+static struct Variable* find_variable(struct Machine* machine, const char* name)
+{
+ for (size_t index = 0; index < VARIABLES_MAX; index++)
+ {
+ struct Variable* variable = &machine->variables[index];
+ if (variable->declared && strcmp(variable->name, name) == 0)
+ return variable;
+ }
+
+ return NULL;
+}
+
+static bool bind_variable(struct Machine* machine, const char* name, int64_t value)
+{
+ for (size_t index = 0; index < VARIABLES_MAX; index++)
+ {
+ struct Variable* variable = &machine->variables[index];
+ if (variable->declared)
+ continue;
+
+ (void)snprintf(variable->name, sizeof variable->name, "%s", name);
+ variable->value = value;
+ variable->declared = true;
+ return true;
+ }
+
+ return false;
+}
static int complain(const struct Node* node, const char* message)
{
@@ -15,19 +50,21 @@ static int complain(const struct Node* node, const char* message)
return 1;
}
-static int evaluate_operands(const struct Node* node, int64_t* left, int64_t* right)
+static int evaluate_operands(struct Machine* machine, const struct Node* node, int64_t* left,
+ int64_t* right)
{
- if (evaluate_value(node->first, left))
+ if (evaluate_value(machine, node->first, left))
return 1;
- return evaluate_value(node->second, right);
+ return evaluate_value(machine, node->second, right);
}
-static int evaluate_value(const struct Node* node, int64_t* out)
+static int evaluate_value(struct Machine* machine, const struct Node* node, int64_t* out)
{
int64_t left = 0;
int64_t right = 0;
struct Type type;
+ struct Variable* variable = NULL;
bool truth = false;
switch (node->kind)
{
@@ -35,19 +72,19 @@ static int evaluate_value(const struct Node* node, int64_t* out)
*out = (int64_t)node->first->character - (int64_t)node->second->character;
return 0;
case VALUE_SUM:
- if (evaluate_operands(node, &left, &right))
+ if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left + right;
return 0;
case VALUE_PRODUCT:
- if (evaluate_operands(node, &left, &right))
+ if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left * right;
return 0;
case VALUE_QUOTIENT:
- if (evaluate_operands(node, &left, &right))
+ if (evaluate_operands(machine, node, &left, &right))
return 1;
if (right == 0)
@@ -57,16 +94,23 @@ static int evaluate_value(const struct Node* node, int64_t* out)
return 0;
case VALUE_EXTENT:
case VALUE_TUPLE_SIZE:
- if (evaluate_type(node->first, &type))
+ if (evaluate_type(machine, node->first, &type))
return 1;
*out = type.kind == KIND_ARRAY ? type.number : 0;
return 0;
- case VALUE_INTEGRAL_CONSTANT: return evaluate_value(node->first, out);
+ case VALUE_INTEGRAL_CONSTANT: return evaluate_value(machine, node->first, out);
+ case VALUE_VARIABLE:
+ variable = find_variable(machine, node->name);
+ if (variable == NULL)
+ return complain(node, "that name was never declared");
+
+ *out = variable->value;
+ return 0;
case VALUE_CONDITIONAL:
- if (evaluate_condition(node->first, &truth))
+ if (evaluate_condition(machine, node->first, &truth))
return 1;
- return evaluate_value(truth ? node->second : node->third, out);
+ return evaluate_value(machine, truth ? node->second : node->third, out);
default: break;
}
@@ -74,7 +118,7 @@ static int evaluate_value(const struct Node* node, int64_t* out)
return 1;
}
-static int evaluate_type(const struct Node* node, struct Type* out)
+static int evaluate_type(struct Machine* machine, const struct Node* node, struct Type* out)
{
out->kind = KIND_VOID;
out->number = 0;
@@ -86,18 +130,19 @@ static int evaluate_type(const struct Node* node, struct Type* out)
case TYPE_INT32: out->kind = KIND_INT32; return 0;
case TYPE_BYTE: out->kind = KIND_BYTE; return 0;
case TYPE_SIZE: out->kind = KIND_SIZE; return 0;
- case TYPE_REMOVE_CV: return evaluate_type(node->first, out);
+ case TYPE_REMOVE_CV: return evaluate_type(machine, node->first, out);
case TYPE_ARRAY:
- if (evaluate_type(node->first, &element) || evaluate_value(node->second, &out->number))
+ if (evaluate_type(machine, node->first, &element) ||
+ evaluate_value(machine, node->second, &out->number))
return 1;
out->kind = KIND_ARRAY;
return 0;
case TYPE_CONDITIONAL:
- if (evaluate_condition(node->first, &truth))
+ if (evaluate_condition(machine, node->first, &truth))
return 1;
- return evaluate_type(truth ? node->second : node->third, out);
+ return evaluate_type(machine, truth ? node->second : node->third, out);
case TYPE_DECLTYPE:
- if (evaluate_value(node->first, &out->number))
+ if (evaluate_value(machine, node->first, &out->number))
return 1;
out->kind = KIND_VALUE;
return 0;
@@ -113,7 +158,7 @@ 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)
+static int evaluate_condition(struct Machine* machine, const struct Node* node, bool* out)
{
int64_t left = 0;
int64_t right = 0;
@@ -125,19 +170,20 @@ static int evaluate_condition(const struct Node* node, bool* out)
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))
+ if (evaluate_type(machine, node->first, &left_type) ||
+ evaluate_type(machine, node->second, &right_type))
return 1;
*out = same_type(&left_type, &right_type);
return 0;
case COND_EQUAL:
- if (evaluate_operands(node, &left, &right))
+ if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left == right;
return 0;
case COND_LESS:
- if (evaluate_operands(node, &left, &right))
+ if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left < right;
@@ -149,10 +195,37 @@ static int evaluate_condition(const struct Node* node, bool* out)
return 1;
}
-static enum RunStatus emit(const struct Node* node)
+static enum RunStatus declare(struct Machine* machine, const struct Node* node)
+{
+ if (find_variable(machine, node->name) != NULL)
+ {
+ (void)complain(node, "already declared, and there is no changing that");
+ return RUN_FAILED;
+ }
+
+ struct Type type;
+ if (evaluate_type(machine, node->first, &type))
+ return RUN_FAILED;
+
+ if (type.kind != KIND_VALUE)
+ {
+ (void)complain(node, "that type carries no value, decltype something");
+ return RUN_FAILED;
+ }
+
+ if (!bind_variable(machine, node->name, type.number))
+ {
+ (void)complain(node, "too many variables, this was never meant to scale");
+ return RUN_FAILED;
+ }
+
+ return RUN_DONE;
+}
+
+static enum RunStatus emit(struct Machine* machine, const struct Node* node)
{
struct Type type;
- if (evaluate_type(node->first, &type))
+ if (evaluate_type(machine, node->first, &type))
return RUN_FAILED;
switch (type.kind)
@@ -168,10 +241,10 @@ static enum RunStatus emit(const struct Node* node)
return RUN_DONE;
}
-static enum RunStatus static_assert_statement(const struct Node* node)
+static enum RunStatus static_assert_statement(struct Machine* machine, const struct Node* node)
{
bool truth = false;
- if (evaluate_condition(node->first, &truth))
+ if (evaluate_condition(machine, node->first, &truth))
return RUN_FAILED;
if (!truth)
@@ -183,12 +256,13 @@ static enum RunStatus static_assert_statement(const struct Node* node)
return RUN_DONE;
}
-static enum RunStatus execute_one(const struct Node* node)
+static enum RunStatus execute_one(struct Machine* machine, const struct Node* node)
{
switch (node->kind)
{
- case STMT_EMIT: return emit(node);
- case STMT_STATIC_ASSERT: return static_assert_statement(node);
+ case STMT_DECLARE: return declare(machine, node);
+ case STMT_EMIT: return emit(machine, node);
+ case STMT_STATIC_ASSERT: return static_assert_statement(machine, node);
default: break;
}
@@ -196,11 +270,11 @@ static enum RunStatus execute_one(const struct Node* node)
return RUN_FAILED;
}
-enum RunStatus execute(const struct Node* statement)
+enum RunStatus execute(struct Machine* machine, const struct Node* statement)
{
while (statement != NULL)
{
- enum RunStatus status = execute_one(statement);
+ enum RunStatus status = execute_one(machine, statement);
if (status != RUN_DONE)
return status;
diff --git a/eval.h b/eval.h
index 649f5e9..eba8244 100644
--- a/eval.h
+++ b/eval.h
@@ -2,8 +2,11 @@
#include "ast.h"
+#include <stdbool.h>
#include <stdint.h>
+#define VARIABLES_MAX 64
+
enum TypeKind
{
KIND_VOID,
@@ -20,10 +23,23 @@ struct Type
int64_t number;
};
+struct Variable
+{
+ char name[NAME_LENGTH_MAX + 1];
+ int64_t value;
+ bool declared;
+};
+
+struct Machine
+{
+ struct Variable variables[VARIABLES_MAX];
+};
+
enum RunStatus
{
RUN_DONE,
RUN_FAILED
};
-enum RunStatus execute(const struct Node* statement);
+void machine_init(struct Machine* machine);
+enum RunStatus execute(struct Machine* machine, const struct Node* statement);
diff --git a/examples/xs.sfinae b/examples/xs.sfinae
index 7cb7dd9..e140252 100644
--- a/examples/xs.sfinae
+++ b/examples/xs.sfinae
@@ -1,34 +1,36 @@
-::emit<
- ::decltype(
- ::extent<
- ::array<
+::declare<
+ ::name<'x', 's'>,
+ ::conditional_t<
+ ::true_type::value,
+ ::decltype(
+ ::extent<
::array<
- ::remove_cv_t<
- ::int32_t
+ ::array<
+ ::remove_cv_t<
+ ::int32_t
+ >,
+ ::integral_constant<
+ ::size_t,
+ ::tuple_size<
+ ::array<
+ ::byte,
+ ::difference<'Z', 'F'>
+ >
+ >::value
+ >::value
>,
::integral_constant<
::size_t,
- ::tuple_size<
- ::array<
- ::byte,
- ::difference<'Z', 'F'>
- >
- >::value
+ ::difference<'Z', 'F'>
>::value
- >,
- ::integral_constant<
- ::size_t,
- ::difference<'Z', 'F'>
- >::value
- >
- >::value
- )
+ >
+ >::value
+ ),
+ ::void
+ >
>::commit;
+::emit<::decltype(::value_of<::name<'x', 's'>>)>::commit;
+
// an array type says its extent, a bare type says its name
-::emit<
- ::array<
- ::byte,
- ::difference<'Z', 'F'>
- >
->::commit;
+::emit<::array<::byte, ::value_of<::name<'x', 's'>>>>::commit;
diff --git a/main.c b/main.c
index 682b9db..db2c879 100644
--- a/main.c
+++ b/main.c
@@ -13,7 +13,11 @@ static int run_program(void)
if (status != 0 || lexer_failed())
status = 1;
else
- status = execute(program_root) == RUN_FAILED;
+ {
+ struct Machine machine;
+ machine_init(&machine);
+ status = execute(&machine, program_root) == RUN_FAILED;
+ }
node_free(program_root);
program_root = NULL;
diff --git a/sfinae.l b/sfinae.l
index 2ee7a3d..7c745ef 100644
--- a/sfinae.l
+++ b/sfinae.l
@@ -35,6 +35,9 @@ static int fail(const char* message)
"emit" return TOK_EMIT;
"static_assert" return TOK_STATIC_ASSERT;
"commit" return TOK_COMMIT;
+"declare" return TOK_DECLARE;
+"name" return TOK_NAME;
+"value_of" return TOK_VALUE_OF;
"void" return TOK_VOID;
"int32_t" return TOK_INT32;
"byte" return TOK_BYTE;
diff --git a/sfinae.y b/sfinae.y
index 0d7f0ee..e142aaa 100644
--- a/sfinae.y
+++ b/sfinae.y
@@ -3,6 +3,7 @@
#include "lexer.h"
#include <stdio.h>
+#include <string.h>
struct Node* program_root = NULL;
@@ -12,6 +13,7 @@ void yyerror(const char* message);
%union
{
char character;
+ struct Name name;
struct Node* node;
}
@@ -19,6 +21,9 @@ void yyerror(const char* message);
%token TOK_EMIT
%token TOK_STATIC_ASSERT
%token TOK_COMMIT
+%token TOK_DECLARE
+%token TOK_NAME
+%token TOK_VALUE_OF
%token TOK_VOID
%token TOK_INT32
%token TOK_BYTE
@@ -43,6 +48,7 @@ void yyerror(const char* message);
%token TOK_LESS
%token <character> TOK_CHAR
+%type <name> name char_list
%type <node> statements statement type value condition
%%
@@ -64,6 +70,30 @@ statement
{ $$ = node_unary(STMT_EMIT, $4); }
| TOK_COLONCOLON TOK_STATIC_ASSERT '<' condition '>' TOK_COLONCOLON TOK_COMMIT
{ $$ = node_unary(STMT_STATIC_ASSERT, $4); }
+ | TOK_COLONCOLON TOK_DECLARE '<' name ',' type '>' TOK_COLONCOLON TOK_COMMIT
+ { $$ = node_named(STMT_DECLARE, &$4, $6); }
+ ;
+
+name
+ : TOK_COLONCOLON TOK_NAME '<' char_list '>'
+ { $$ = $4; }
+ ;
+
+char_list
+ : TOK_CHAR
+ {
+ name_init(&$$);
+ (void)name_push(&$$, $1);
+ }
+ | char_list ',' TOK_CHAR
+ {
+ $$ = $1;
+ if (!name_push(&$$, $3))
+ {
+ yyerror("that name is too long, who are you");
+ YYERROR;
+ }
+ }
;
type
@@ -94,6 +124,8 @@ value
{ $$ = node_binary(VALUE_PRODUCT, $4, $6); }
| TOK_COLONCOLON TOK_QUOTIENT '<' value ',' value '>'
{ $$ = node_binary(VALUE_QUOTIENT, $4, $6); }
+ | TOK_COLONCOLON TOK_VALUE_OF '<' name '>'
+ { $$ = node_named(VALUE_VARIABLE, &$4, NULL); }
| TOK_COLONCOLON TOK_EXTENT '<' type '>' TOK_COLONCOLON TOK_VALUE
{ $$ = node_unary(VALUE_EXTENT, $4); }
| TOK_COLONCOLON TOK_TUPLE_SIZE '<' type '>' TOK_COLONCOLON TOK_VALUE
@@ -124,6 +156,7 @@ void yyerror(const char* message)
{
if (!lexer_failed())
{
- (void)fprintf(stderr, "line %d: %s, did you forget to commit\n", yylineno, message);
+ (void)fprintf(stderr, "line %d: %s%s\n", yylineno, message,
+ strcmp(message, "syntax error") == 0 ? ", did you forget to commit" : "");
}
}