hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-19 12:38:43 +0200
committerhachem <im@hachem.wtf>2026-09-19 12:38:43 +0200
commita79c97e04562b171780a24cba2cb1a71acfa4bbb (patch)
tree412642f948a30eb220512c304b34d60356f23b42
parent74a8a2b10a0513f5346ec47aa9b463e30f2b972e (diff)
types: array, extent, tuple_size, integral_constant
-rw-r--r--ast.h4
-rw-r--r--eval.c20
-rw-r--r--eval.h1
-rw-r--r--examples/xs.sfinae36
-rw-r--r--sfinae.l5
-rw-r--r--sfinae.y14
6 files changed, 80 insertions, 0 deletions
diff --git a/ast.h b/ast.h
index 52814d5..c25e118 100644
--- a/ast.h
+++ b/ast.h
@@ -8,11 +8,15 @@ enum NodeKind
TYPE_BYTE,
TYPE_SIZE,
TYPE_REMOVE_CV,
+ TYPE_ARRAY,
TYPE_DECLTYPE,
VALUE_DIFFERENCE,
VALUE_SUM,
VALUE_PRODUCT,
VALUE_QUOTIENT,
+ VALUE_EXTENT,
+ VALUE_TUPLE_SIZE,
+ VALUE_INTEGRAL_CONSTANT,
STMT_EMIT
};
diff --git a/eval.c b/eval.c
index 3c4ea34..8c92cd8 100644
--- a/eval.c
+++ b/eval.c
@@ -4,6 +4,7 @@
#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 complain(const struct Node* node, const char* message)
@@ -24,6 +25,7 @@ static int evaluate_value(const struct Node* node, int64_t* out)
{
int64_t left = 0;
int64_t right = 0;
+ struct Type type;
switch (node->kind)
{
case VALUE_DIFFERENCE:
@@ -50,6 +52,15 @@ static int evaluate_value(const struct Node* node, int64_t* out)
*out = left / right;
return 0;
+ case VALUE_EXTENT:
+ 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);
default: break;
}
@@ -61,6 +72,7 @@ static int evaluate_type(const struct Node* node, struct Type* out)
{
out->kind = KIND_VOID;
out->number = 0;
+ struct Type element;
switch (node->kind)
{
case TYPE_VOID: return 0;
@@ -68,6 +80,13 @@ static int evaluate_type(const struct Node* node, struct Type* out)
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_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_DECLTYPE:
if (evaluate_value(node->first, &out->number))
return 1;
@@ -92,6 +111,7 @@ static enum RunStatus emit(const struct Node* node)
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_VALUE: (void)printf("%" PRId64 "\n", type.number); break;
}
diff --git a/eval.h b/eval.h
index 3c5d947..649f5e9 100644
--- a/eval.h
+++ b/eval.h
@@ -10,6 +10,7 @@ enum TypeKind
KIND_INT32,
KIND_BYTE,
KIND_SIZE,
+ KIND_ARRAY,
KIND_VALUE
};
diff --git a/examples/xs.sfinae b/examples/xs.sfinae
new file mode 100644
index 0000000..faae464
--- /dev/null
+++ b/examples/xs.sfinae
@@ -0,0 +1,36 @@
+// the original sin: how wide is int xs[20][20]
+
+::emit<
+ ::decltype(
+ ::extent<
+ ::array<
+ ::array<
+ ::remove_cv_t<
+ ::int32_t
+ >,
+ ::integral_constant<
+ ::size_t,
+ ::tuple_size<
+ ::array<
+ ::byte,
+ ::difference<'Z', 'F'>
+ >
+ >::value
+ >::value
+ >,
+ ::integral_constant<
+ ::size_t,
+ ::difference<'Z', 'F'>
+ >::value
+ >
+ >::value
+ )
+>::commit;
+
+// an array type says its extent, a bare type says its name
+::emit<
+ ::array<
+ ::byte,
+ ::difference<'Z', 'F'>
+ >
+>::commit;
diff --git a/sfinae.l b/sfinae.l
index 37ddd1a..98da1cf 100644
--- a/sfinae.l
+++ b/sfinae.l
@@ -44,6 +44,11 @@ static int fail(const char* message)
"sum" return TOK_SUM;
"product" return TOK_PRODUCT;
"quotient" return TOK_QUOTIENT;
+"array" return TOK_ARRAY;
+"extent" return TOK_EXTENT;
+"tuple_size" return TOK_TUPLE_SIZE;
+"integral_constant" return TOK_INTEGRAL_CONSTANT;
+"value" return TOK_VALUE;
[<>(),;] return yytext[0];
'\\.' yylval.character = unescape(yytext[2]); return TOK_CHAR;
'.' yylval.character = yytext[1]; return TOK_CHAR;
diff --git a/sfinae.y b/sfinae.y
index 5a590a2..5b5d1be 100644
--- a/sfinae.y
+++ b/sfinae.y
@@ -28,6 +28,11 @@ void yyerror(const char* message);
%token TOK_SUM
%token TOK_PRODUCT
%token TOK_QUOTIENT
+%token TOK_ARRAY
+%token TOK_EXTENT
+%token TOK_TUPLE_SIZE
+%token TOK_INTEGRAL_CONSTANT
+%token TOK_VALUE
%token <character> TOK_CHAR
%type <node> statements statement type value
@@ -62,6 +67,8 @@ type
{ $$ = node_leaf(TYPE_SIZE); }
| TOK_COLONCOLON TOK_REMOVE_CV '<' type '>'
{ $$ = node_unary(TYPE_REMOVE_CV, $4); }
+ | TOK_COLONCOLON TOK_ARRAY '<' type ',' value '>'
+ { $$ = node_binary(TYPE_ARRAY, $4, $6); }
| TOK_COLONCOLON TOK_DECLTYPE '(' value ')'
{ $$ = node_unary(TYPE_DECLTYPE, $4); }
;
@@ -75,6 +82,13 @@ value
{ $$ = node_binary(VALUE_PRODUCT, $4, $6); }
| TOK_COLONCOLON TOK_QUOTIENT '<' value ',' value '>'
{ $$ = node_binary(VALUE_QUOTIENT, $4, $6); }
+ | TOK_COLONCOLON TOK_EXTENT '<' type '>' TOK_COLONCOLON TOK_VALUE
+ { $$ = node_unary(VALUE_EXTENT, $4); }
+ | TOK_COLONCOLON TOK_TUPLE_SIZE '<' type '>' TOK_COLONCOLON TOK_VALUE
+ { $$ = node_unary(VALUE_TUPLE_SIZE, $4); }
+ | TOK_COLONCOLON TOK_INTEGRAL_CONSTANT '<' TOK_COLONCOLON TOK_SIZE_T ',' value '>'
+ TOK_COLONCOLON TOK_VALUE
+ { $$ = node_unary(VALUE_INTEGRAL_CONSTANT, $7); }
;
%%