mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Complete missing functionality with $nameof / $extnameof / $qnameof
This commit is contained in:
committed by
Christoffer Lerno
parent
7c7ee58b6b
commit
fdcc189f41
@@ -2264,6 +2264,7 @@ static inline Type *type_flatten(Type *type)
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; }
|
||||
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind < TYPE_U8; }
|
||||
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind < TYPE_IXX; }
|
||||
|
||||
@@ -468,6 +468,7 @@ typedef enum
|
||||
TOKEN_CT_ELSE, // $else
|
||||
TOKEN_CT_ENDIF, // $endif
|
||||
TOKEN_CT_ENDSWITCH, // $endswitch
|
||||
TOKEN_CT_EXTNAMEOF, // $extnameof
|
||||
TOKEN_CT_IF, // $if
|
||||
TOKEN_CT_NAMEOF, // $nameof
|
||||
TOKEN_CT_OFFSETOF, // $offsetof
|
||||
|
||||
@@ -1417,6 +1417,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
|
||||
[TOKEN_CT_SIZEOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_ALIGNOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_EXTNAMEOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_OFFSETOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_NAMEOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_QNAMEOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
|
||||
@@ -1054,6 +1054,7 @@ Ast *parse_stmt(Context *context)
|
||||
case TOKEN_LBRAPIPE:
|
||||
case TOKEN_CT_OFFSETOF:
|
||||
case TOKEN_CT_ALIGNOF:
|
||||
case TOKEN_CT_EXTNAMEOF:
|
||||
case TOKEN_CT_SIZEOF:
|
||||
case TOKEN_CT_QNAMEOF:
|
||||
case TOKEN_CT_NAMEOF:
|
||||
|
||||
@@ -5903,14 +5903,49 @@ static inline bool sema_expr_analyse_ct_nameof(Context *context, Type *to, Expr
|
||||
Expr *first_expr = elements[0];
|
||||
if (!sema_analyse_expr_value(context, NULL, first_expr)) return false;
|
||||
|
||||
bool qualified = expr->ct_call_expr.token_type == TOKEN_CT_QNAMEOF;
|
||||
TokenType name_type = expr->ct_call_expr.token_type;
|
||||
|
||||
if (first_expr->expr_kind == EXPR_TYPEINFO)
|
||||
Decl *decl = NULL;
|
||||
Type *type = NULL;
|
||||
if (first_expr->expr_kind == EXPR_CONST && first_expr->const_expr.kind == TYPE_STRLIT)
|
||||
{
|
||||
ExprFlatElement *path_elements = NULL;
|
||||
if (!sema_analyse_identifier_path_string(context, first_expr, &decl, &type, &path_elements)) return false;
|
||||
if (path_elements)
|
||||
{
|
||||
SEMA_ERROR(first_expr, "You cannot take the name of sub elements by string name.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (first_expr->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
type = first_expr->type_expr->type->canonical;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first_expr->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(first_expr, "Expected an identifier or a string.");
|
||||
return false;
|
||||
}
|
||||
decl = first_expr->identifier_expr.decl;
|
||||
}
|
||||
if (type)
|
||||
{
|
||||
Type *type = first_expr->type_expr->type->canonical;
|
||||
if (!sema_resolve_type(context, type)) return false;
|
||||
|
||||
// TODO type_is_builtin is wrong also this does not cover virtual.
|
||||
if (!qualified || type_is_builtin(type->type_kind))
|
||||
if (name_type == TOKEN_CT_EXTNAMEOF)
|
||||
{
|
||||
if (!type_is_user_defined(type))
|
||||
{
|
||||
SEMA_ERROR(first_expr, "Only user defined types have an external name.");
|
||||
return false;
|
||||
}
|
||||
expr_rewrite_to_string(expr, type->decl->extname ?: type->decl->external_name);
|
||||
return true;
|
||||
}
|
||||
if (name_type == TOKEN_CT_NAMEOF || type_is_builtin(type->type_kind))
|
||||
{
|
||||
expr_rewrite_to_string(expr, type->name);
|
||||
return true;
|
||||
@@ -5922,14 +5957,22 @@ static inline bool sema_expr_analyse_ct_nameof(Context *context, Type *to, Expr
|
||||
expr_rewrite_to_string(expr, scratch_buffer_interned());
|
||||
return true;
|
||||
}
|
||||
if (first_expr->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(first_expr, "Expected an identifier.");
|
||||
return false;
|
||||
}
|
||||
Decl *decl = first_expr->identifier_expr.decl;
|
||||
|
||||
if (!decl->module || !qualified || decl_is_local(decl))
|
||||
assert(decl);
|
||||
|
||||
if (!sema_analyse_decl(context, decl)) return false;
|
||||
|
||||
if (name_type == TOKEN_CT_EXTNAMEOF)
|
||||
{
|
||||
if (!decl->external_name)
|
||||
{
|
||||
SEMA_ERROR(first_expr, "'%s' does not have an external name.", decl->name);
|
||||
return false;
|
||||
}
|
||||
expr_rewrite_to_string(expr, decl->extname ?: decl->external_name);
|
||||
return true;
|
||||
}
|
||||
if (!decl->module || name_type == TOKEN_CT_NAMEOF || decl_is_local(decl))
|
||||
{
|
||||
expr_rewrite_to_string(expr, decl->name);
|
||||
return true;
|
||||
@@ -6069,8 +6112,8 @@ static inline bool sema_expr_analyse_ct_call(Context *context, Type *to, Expr *e
|
||||
case TOKEN_CT_OFFSETOF:
|
||||
return sema_expr_analyse_ct_offsetof(context, to, expr);
|
||||
case TOKEN_CT_QNAMEOF:
|
||||
return sema_expr_analyse_ct_nameof(context, to, expr);
|
||||
case TOKEN_CT_NAMEOF:
|
||||
case TOKEN_CT_EXTNAMEOF:
|
||||
return sema_expr_analyse_ct_nameof(context, to, expr);
|
||||
default:
|
||||
UNREACHABLE
|
||||
|
||||
@@ -345,6 +345,8 @@ const char *token_type_to_string(TokenType type)
|
||||
return "$endif";
|
||||
case TOKEN_CT_ENDSWITCH:
|
||||
return "$endswitch";
|
||||
case TOKEN_CT_EXTNAMEOF:
|
||||
return "$extnameof";
|
||||
case TOKEN_CT_IF:
|
||||
return "$if";
|
||||
case TOKEN_CT_NAMEOF:
|
||||
|
||||
68
test/test_suite/compile_time_introspection/nameof.c3t
Normal file
68
test/test_suite/compile_time_introspection/nameof.c3t
Normal file
@@ -0,0 +1,68 @@
|
||||
// #target: x64-darwin
|
||||
module mymodule;
|
||||
|
||||
extern func void printf(char *, ...);
|
||||
|
||||
struct Foo { }
|
||||
|
||||
int b;
|
||||
|
||||
func void main()
|
||||
{
|
||||
printf("%s\n", $qnameof(Foo));
|
||||
printf("%s\n", $qnameof("Foo"));
|
||||
printf("%s\n", $nameof(Foo));
|
||||
printf("%s\n", $nameof("mymodule::Foo"));
|
||||
printf("%s\n", $extnameof(Foo));
|
||||
printf("%s\n", $extnameof("Foo"));
|
||||
|
||||
printf("%s\n", $qnameof(b));
|
||||
printf("%s\n", $qnameof("b"));
|
||||
printf("%s\n", $nameof(b));
|
||||
printf("%s\n", $nameof("mymodule::b"));
|
||||
printf("%s\n", $extnameof(b));
|
||||
printf("%s\n", $extnameof("b"));
|
||||
|
||||
int a;
|
||||
|
||||
printf("%s\n", $qnameof(a));
|
||||
printf("%s\n", $qnameof("a"));
|
||||
printf("%s\n", $nameof(a));
|
||||
printf("%s\n", $nameof("a"));
|
||||
|
||||
}
|
||||
|
||||
// #expect: mymodule.ll
|
||||
|
||||
@.str = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.1 = private constant [14 x i8] c"mymodule::Foo\00", align 1
|
||||
@.str.2 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.3 = private constant [14 x i8] c"mymodule::Foo\00", align 1
|
||||
@.str.4 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.5 = private constant [4 x i8] c"Foo\00", align 1
|
||||
@.str.6 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.7 = private constant [4 x i8] c"Foo\00", align 1
|
||||
@.str.8 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.9 = private constant [13 x i8] c"mymodule.Foo\00", align 1
|
||||
@.str.10 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.11 = private constant [13 x i8] c"mymodule.Foo\00", align 1
|
||||
@.str.12 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.13 = private constant [12 x i8] c"mymodule::b\00", align 1
|
||||
@.str.14 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.15 = private constant [12 x i8] c"mymodule::b\00", align 1
|
||||
@.str.16 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.17 = private constant [2 x i8] c"b\00", align 1
|
||||
@.str.18 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.19 = private constant [2 x i8] c"b\00", align 1
|
||||
@.str.20 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.21 = private constant [11 x i8] c"mymodule.b\00", align 1
|
||||
@.str.22 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.23 = private constant [11 x i8] c"mymodule.b\00", align 1
|
||||
@.str.24 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.25 = private constant [2 x i8] c"a\00", align 1
|
||||
@.str.26 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.27 = private constant [2 x i8] c"a\00", align 1
|
||||
@.str.28 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.29 = private constant [2 x i8] c"a\00", align 1
|
||||
@.str.30 = private constant [4 x i8] c"%s\0A\00", align 1
|
||||
@.str.31 = private constant [2 x i8] c"a\00", align 1
|
||||
15
test/test_suite/compile_time_introspection/nameof_err.c3
Normal file
15
test/test_suite/compile_time_introspection/nameof_err.c3
Normal file
@@ -0,0 +1,15 @@
|
||||
func void main()
|
||||
{
|
||||
int a;
|
||||
$extnameof(a); // #error: 'a' does not have an external name.
|
||||
}
|
||||
func void main2()
|
||||
{
|
||||
int a;
|
||||
$extnameof("a"); // #error: 'a' does not have an external name.
|
||||
}
|
||||
|
||||
func void main3()
|
||||
{
|
||||
$extnameof("int"); // #error: Only user defined types have an external name.
|
||||
}
|
||||
Reference in New Issue
Block a user