From 0a9605b6b13f2e066a69662f5802b397f8b89424 Mon Sep 17 00:00:00 2001 From: hachem Date: Sat, 19 Sep 2026 16:15:50 +0200 Subject: feat: char and integral_constant types --- ast.h | 2 ++ eval.c | 9 +++++++++ eval.h | 2 ++ examples/chars.sfinae | 16 ++++++++++++++++ sfinae.l | 1 + sfinae.y | 5 +++++ 6 files changed, 35 insertions(+) create mode 100644 examples/chars.sfinae diff --git a/ast.h b/ast.h index e18b5d9..da409be 100644 --- a/ast.h +++ b/ast.h @@ -17,6 +17,8 @@ enum NodeKind TYPE_ARRAY, TYPE_CONDITIONAL, TYPE_DECLTYPE, + TYPE_CHAR, + TYPE_CHAR_CONSTANT, VALUE_DIFFERENCE, VALUE_SUM, VALUE_PRODUCT, diff --git a/eval.c b/eval.c index 2f79a5d..170b122 100644 --- a/eval.c +++ b/eval.c @@ -130,6 +130,13 @@ static int evaluate_type(struct Machine* machine, const struct Node* node, struc 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_CHAR: out->kind = KIND_CHAR; return 0; + case TYPE_CHAR_CONSTANT: + if (evaluate_value(machine, node->first, &out->number)) + return 1; + + out->kind = KIND_CHAR_CONSTANT; + return 0; case TYPE_REMOVE_CV: return evaluate_type(machine, node->first, out); case TYPE_ARRAY: if (evaluate_type(machine, node->first, &element) || @@ -248,6 +255,8 @@ static enum RunStatus emit(struct Machine* machine, const struct Node* node) 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; } diff --git a/eval.h b/eval.h index eba8244..eb3fe1d 100644 --- a/eval.h +++ b/eval.h @@ -14,6 +14,8 @@ enum TypeKind KIND_BYTE, KIND_SIZE, KIND_ARRAY, + KIND_CHAR, + KIND_CHAR_CONSTANT, KIND_VALUE }; diff --git a/examples/chars.sfinae b/examples/chars.sfinae new file mode 100644 index 0000000..b38118b --- /dev/null +++ b/examples/chars.sfinae @@ -0,0 +1,16 @@ +// ::integral_constant<::char, V> is a type that says one character +// there are no character values, so it says its own distance from '\0' + +::emit<::integral_constant<::char, ::difference<'h', '\0'>>>::commit; +::emit<::integral_constant<::char, ::difference<'i', '\0'>>>::commit; + +// ::char on its own is a type like any other, and says its name +::emit<::remove_cv_t<::char>>::commit; + +// two character types are the same type when they say the same thing +::static_assert< + ::is_same< + ::integral_constant<::char, ::difference<'a', '\0'>>, + ::integral_constant<::char, ::sum<::difference<'a', 'b'>, ::difference<'b', '\0'>>> + >::value +>::commit; diff --git a/sfinae.l b/sfinae.l index c8099c9..f5b9cf1 100644 --- a/sfinae.l +++ b/sfinae.l @@ -46,6 +46,7 @@ static int fail(const char* message) "int32_t" return TOK_INT32; "byte" return TOK_BYTE; "size_t" return TOK_SIZE_T; +"char" return TOK_CHAR_T; "remove_cv_t" return TOK_REMOVE_CV; "decltype" return TOK_DECLTYPE; "difference" return TOK_DIFFERENCE; diff --git a/sfinae.y b/sfinae.y index 341be36..aa7650b 100644 --- a/sfinae.y +++ b/sfinae.y @@ -32,6 +32,7 @@ void yyerror(const char* message); %token TOK_INT32 %token TOK_BYTE %token TOK_SIZE_T +%token TOK_CHAR_T %token TOK_REMOVE_CV %token TOK_DECLTYPE %token TOK_DIFFERENCE @@ -138,6 +139,10 @@ type { $$ = node_ternary(TYPE_CONDITIONAL, $4, $6, $8); } | TOK_COLONCOLON TOK_DECLTYPE '(' value ')' { $$ = node_unary(TYPE_DECLTYPE, $4); } + | TOK_COLONCOLON TOK_CHAR_T + { $$ = node_leaf(TYPE_CHAR); } + | TOK_COLONCOLON TOK_INTEGRAL_CONSTANT '<' TOK_COLONCOLON TOK_CHAR_T ',' value '>' + { $$ = node_unary(TYPE_CHAR_CONSTANT, $7); } ; value -- cgit v1.3