diff options
| author | hachem <im@hachem.wtf> | 2026-09-19 16:20:14 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-09-19 16:20:14 +0200 |
| commit | cd2a86435e5e413630e0ab0caa48d900e49ea275 (patch) | |
| tree | 559a1bfc52a853b61fe07e0b7aa17eca977f5fd2 | |
| parent | 0a9605b6b13f2e066a69662f5802b397f8b89424 (diff) | |
feat: tuples baby
| -rw-r--r-- | ast.h | 1 | ||||
| -rw-r--r-- | eval.c | 65 | ||||
| -rw-r--r-- | eval.h | 6 | ||||
| -rw-r--r-- | examples/hello.sfinae | 23 | ||||
| -rw-r--r-- | sfinae.l | 1 | ||||
| -rw-r--r-- | sfinae.y | 14 |
6 files changed, 94 insertions, 16 deletions
@@ -19,6 +19,7 @@ enum NodeKind TYPE_DECLTYPE, TYPE_CHAR, TYPE_CHAR_CONSTANT, + TYPE_TUPLE, VALUE_DIFFERENCE, VALUE_SUM, VALUE_PRODUCT, @@ -118,10 +118,53 @@ 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; + switch (type->kind) + { + case KIND_VOID: written = snprintf(buffer, size, "%s", ""); break; + case KIND_INT32: written = snprintf(buffer, size, "int32_t"); break; + case KIND_BYTE: written = snprintf(buffer, size, "byte"); break; + case KIND_SIZE: written = snprintf(buffer, size, "size_t"); break; + case KIND_ARRAY: + written = snprintf(buffer, size, "array[%" PRId64 "]", type->number); + break; + case KIND_CHAR: written = snprintf(buffer, size, "char"); break; + case KIND_CHAR_CONSTANT: written = snprintf(buffer, size, "%c", (char)type->number); break; + case KIND_VALUE: written = snprintf(buffer, size, "%" PRId64, type->number); break; + case KIND_TUPLE: written = snprintf(buffer, size, "%s", type->text); break; + } + + 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; + size_t used = 0; + for (const struct Node* element = node->first; element != NULL; element = element->next) + { + struct Type inner; + if (evaluate_type(machine, element, &inner)) + return 1; + + if (render(&inner, out->text + used, sizeof out->text - used)) + return complain(node, "that tuple is too much to say in one breath"); + + used = strlen(out->text); + } + + return 0; +} + static int evaluate_type(struct Machine* machine, const struct Node* node, struct Type* out) { out->kind = KIND_VOID; out->number = 0; + out->text[0] = '\0'; struct Type element; bool truth = false; switch (node->kind) @@ -131,6 +174,7 @@ static int evaluate_type(struct Machine* machine, const struct Node* node, struc case TYPE_BYTE: out->kind = KIND_BYTE; return 0; 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_CHAR_CONSTANT: if (evaluate_value(machine, node->first, &out->number)) return 1; @@ -162,7 +206,8 @@ static int evaluate_type(struct Machine* machine, const struct Node* node, struc static bool same_type(const struct Type* left, const struct Type* right) { - return left->kind == right->kind && left->number == right->number; + return left->kind == right->kind && left->number == right->number && + strcmp(left->text, right->text) == 0; } static int evaluate_condition(struct Machine* machine, const struct Node* node, bool* out) @@ -248,18 +293,18 @@ static enum RunStatus emit(struct Machine* machine, const struct Node* node) if (evaluate_type(machine, node->first, &type)) return RUN_FAILED; - switch (type.kind) + // void says nothing, not even a newline. everything else says its piece and ends the line + if (type.kind == KIND_VOID) + return RUN_DONE; + + char text[TEXT_LENGTH_MAX + 1]; + if (render(&type, text, sizeof text)) { - case KIND_VOID: break; - case KIND_INT32: (void)printf("int32_t\n"); break; - case KIND_BYTE: (void)printf("byte\n"); break; - case KIND_SIZE: (void)printf("size_t\n"); break; - case KIND_ARRAY: (void)printf("array[%" PRId64 "]\n", type.number); break; - case KIND_CHAR: (void)printf("char\n"); break; - case KIND_CHAR_CONSTANT: (void)printf("%c\n", (char)type.number); break; - case KIND_VALUE: (void)printf("%" PRId64 "\n", type.number); break; + (void)complain(node, "that is too much to say in one breath"); + return RUN_FAILED; } + (void)printf("%s\n", text); return RUN_DONE; } @@ -7,6 +7,9 @@ #define VARIABLES_MAX 64 +// the longest thing a single type can say when emitted +#define TEXT_LENGTH_MAX 255 + enum TypeKind { KIND_VOID, @@ -16,13 +19,16 @@ enum TypeKind KIND_ARRAY, KIND_CHAR, KIND_CHAR_CONSTANT, + KIND_TUPLE, KIND_VALUE }; +// a tuple keeps what it will say, already said, so nothing inside it can go out of scope struct Type { enum TypeKind kind; int64_t number; + char text[TEXT_LENGTH_MAX + 1]; }; struct Variable diff --git a/examples/hello.sfinae b/examples/hello.sfinae index 39f3a62..0154af8 100644 --- a/examples/hello.sfinae +++ b/examples/hello.sfinae @@ -1,8 +1,21 @@ -// prints 5 +// hello, world +// there are no strings. a ::tuple says what its elements say, glued together, +// and each element is a character type, its own distance from '\0' + ::emit< - ::conditional_t< - ::true_type::value, - ::decltype(::difference<'F', 'A'>), - ::void + ::tuple< + ::integral_constant<::char, ::difference<'H', '\0'>>, + ::integral_constant<::char, ::difference<'e', '\0'>>, + ::integral_constant<::char, ::difference<'l', '\0'>>, + ::integral_constant<::char, ::difference<'l', '\0'>>, + ::integral_constant<::char, ::difference<'o', '\0'>>, + ::integral_constant<::char, ::difference<',', '\0'>>, + ::integral_constant<::char, ::difference<' ', '\0'>>, + ::integral_constant<::char, ::difference<'w', '\0'>>, + ::integral_constant<::char, ::difference<'o', '\0'>>, + ::integral_constant<::char, ::difference<'r', '\0'>>, + ::integral_constant<::char, ::difference<'l', '\0'>>, + ::integral_constant<::char, ::difference<'d', '\0'>>, + ::integral_constant<::char, ::difference<'!', '\0'>> > >::commit; @@ -47,6 +47,7 @@ static int fail(const char* message) "byte" return TOK_BYTE; "size_t" return TOK_SIZE_T; "char" return TOK_CHAR_T; +"tuple" return TOK_TUPLE; "remove_cv_t" return TOK_REMOVE_CV; "decltype" return TOK_DECLTYPE; "difference" return TOK_DIFFERENCE; @@ -33,6 +33,7 @@ void yyerror(const char* message); %token TOK_BYTE %token TOK_SIZE_T %token TOK_CHAR_T +%token TOK_TUPLE %token TOK_REMOVE_CV %token TOK_DECLTYPE %token TOK_DIFFERENCE @@ -54,7 +55,7 @@ void yyerror(const char* message); %token <character> TOK_CHAR %type <name> name char_list -%type <node> statements statement sequence sequence_items type value condition +%type <node> statements statement sequence sequence_items type type_list value condition %% @@ -143,6 +144,17 @@ type { $$ = node_leaf(TYPE_CHAR); } | TOK_COLONCOLON TOK_INTEGRAL_CONSTANT '<' TOK_COLONCOLON TOK_CHAR_T ',' value '>' { $$ = node_unary(TYPE_CHAR_CONSTANT, $7); } + | TOK_COLONCOLON TOK_TUPLE '<' type_list '>' + { $$ = node_unary(TYPE_TUPLE, $4); } + ; + +type_list + : /* nothing */ + { $$ = NULL; } + | type + { $$ = $1; } + | type_list ',' type + { $$ = node_append($1, $3); } ; value |
