mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add methodsof to type info (#1303)
Add `methodsof` to type info for struct, union and bitstruct
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
- Add `@const` attribute for macros, for better error messages with constant macros.
|
||||
- Add `wincrt` setting to libraries.
|
||||
- Add `+++` `&&&` `|||` as replacement for `$concat`, `$and` and `$or`.
|
||||
- Add `methodsof` to type info for struct, union and bitstruct
|
||||
|
||||
### Fixes
|
||||
|
||||
|
||||
@@ -1034,6 +1034,7 @@ typedef enum
|
||||
TYPE_PROPERTY_LEN,
|
||||
TYPE_PROPERTY_MAX,
|
||||
TYPE_PROPERTY_MEMBERSOF,
|
||||
TYPE_PROPERTY_METHODSOF,
|
||||
TYPE_PROPERTY_MIN,
|
||||
TYPE_PROPERTY_NAN,
|
||||
TYPE_PROPERTY_INNER,
|
||||
|
||||
@@ -178,6 +178,7 @@ static inline bool sema_create_const_max(SemaContext *context, Expr *expr, Type
|
||||
static inline bool sema_create_const_params(SemaContext *context, Expr *expr, Type *type);
|
||||
static inline void sema_create_const_membersof(SemaContext *context, Expr *expr, Type *type, AlignSize alignment,
|
||||
AlignSize offset);
|
||||
static inline void sema_create_const_methodsof(SemaContext *context, Expr *expr, Type *type);
|
||||
|
||||
static inline int64_t expr_get_index_max(Expr *expr);
|
||||
static inline bool expr_both_any_integer_or_integer_vector(Expr *left, Expr *right);
|
||||
@@ -3405,6 +3406,8 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e
|
||||
case TYPE_PROPERTY_MEMBERSOF:
|
||||
sema_create_const_membersof(context, expr, decl->type->canonical, parent->const_expr.member.align, parent->const_expr.member.offset);
|
||||
return true;
|
||||
case TYPE_PROPERTY_METHODSOF:
|
||||
sema_create_const_methodsof(context, expr, decl->type->canonical);
|
||||
case TYPE_PROPERTY_KINDOF:
|
||||
case TYPE_PROPERTY_SIZEOF:
|
||||
return sema_expr_rewrite_to_type_property(context, expr, decl->type->canonical, type_property, decl->type->canonical);
|
||||
@@ -3459,6 +3462,7 @@ MISSING_REF:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline void sema_expr_rewrite_typeid_kind(Expr *expr, Expr *parent)
|
||||
{
|
||||
Module *module = global_context_find_module(kw_std__core__types);
|
||||
@@ -3702,6 +3706,42 @@ static inline void sema_create_const_membersof(SemaContext *context, Expr *expr,
|
||||
expr_rewrite_const_untyped_list(expr, member_exprs);
|
||||
}
|
||||
|
||||
|
||||
static inline void sema_create_const_methodsof(SemaContext *context, Expr *expr, Type *type)
|
||||
{
|
||||
Decl **methods = type->decl->methods;
|
||||
unsigned method_count = vec_size(methods);
|
||||
|
||||
if (!method_count)
|
||||
{
|
||||
expr_rewrite_const_untyped_list(expr, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
Expr **method_exprs = method_count ? VECNEW(Expr*, method_count) : NULL;
|
||||
for (unsigned i = 0; i < method_count; i++)
|
||||
{
|
||||
Decl *method = methods[i];
|
||||
if (method->decl_kind == DECL_FUNC)
|
||||
{
|
||||
Decl *decl = methods[i];
|
||||
size_t namestr_len = strlen(decl->name);
|
||||
const char *namestr = str_copy(decl->name, namestr_len);
|
||||
Expr *expr_element = expr_new(EXPR_CONST, expr->span);
|
||||
expr_element->resolve_status = RESOLVE_DONE;
|
||||
expr_element->type = type_string;
|
||||
expr_element->const_expr = (ExprConst) {
|
||||
.const_kind = CONST_STRING,
|
||||
.bytes.ptr = namestr,
|
||||
.bytes.len = namestr_len,
|
||||
};
|
||||
vec_add(method_exprs, expr_element);
|
||||
}
|
||||
}
|
||||
expr_rewrite_const_untyped_list(expr, method_exprs);
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_create_const_max(SemaContext *context, Expr *expr, Type *type, Type *flat)
|
||||
{
|
||||
if (type_is_integer(flat))
|
||||
@@ -3827,6 +3867,7 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp
|
||||
case TYPE_PROPERTY_RETURNS:
|
||||
case TYPE_PROPERTY_PARAMS:
|
||||
case TYPE_PROPERTY_MEMBERSOF:
|
||||
case TYPE_PROPERTY_METHODSOF:
|
||||
case TYPE_PROPERTY_EXTNAMEOF:
|
||||
case TYPE_PROPERTY_NAMEOF:
|
||||
case TYPE_PROPERTY_QNAMEOF:
|
||||
@@ -4063,6 +4104,16 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case TYPE_PROPERTY_METHODSOF:
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_BITSTRUCT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case TYPE_PROPERTY_PARAMS:
|
||||
case TYPE_PROPERTY_RETURNS:
|
||||
return type_is_func_ptr(type);
|
||||
@@ -4137,6 +4188,11 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr,
|
||||
sema_create_const_membersof(context, expr, flat, align, 0);
|
||||
return true;
|
||||
}
|
||||
case TYPE_PROPERTY_METHODSOF:
|
||||
{
|
||||
sema_create_const_methodsof(context, expr, flat);
|
||||
return true;
|
||||
}
|
||||
case TYPE_PROPERTY_PARAMS:
|
||||
return sema_create_const_params(context, expr, flat);
|
||||
case TYPE_PROPERTY_RETURNS:
|
||||
|
||||
@@ -167,6 +167,7 @@ void symtab_init(uint32_t capacity)
|
||||
type_property_list[TYPE_PROPERTY_IS_SUBSTRUCT] = KW_DEF("is_substruct");
|
||||
type_property_list[TYPE_PROPERTY_KINDOF] = KW_DEF("kindof");
|
||||
type_property_list[TYPE_PROPERTY_MEMBERSOF] = KW_DEF("membersof");
|
||||
type_property_list[TYPE_PROPERTY_METHODSOF] = KW_DEF("methodsof");
|
||||
type_property_list[TYPE_PROPERTY_NAMEOF] = KW_DEF("nameof");
|
||||
type_property_list[TYPE_PROPERTY_NAMES] = KW_DEF("names");
|
||||
type_property_list[TYPE_PROPERTY_NAN] = KW_DEF("nan");
|
||||
|
||||
78
test/unit/regression/methodsof.c3
Normal file
78
test/unit/regression/methodsof.c3
Normal file
@@ -0,0 +1,78 @@
|
||||
module methodsof;
|
||||
|
||||
interface IBar
|
||||
{
|
||||
fn void fnA();
|
||||
fn void fnB();
|
||||
}
|
||||
struct Bar (IBar)
|
||||
{
|
||||
int a;
|
||||
}
|
||||
fn void Bar.fnB(&self) @dynamic {}
|
||||
fn void Bar.fnA(&self) @dynamic {}
|
||||
|
||||
struct Foo
|
||||
{
|
||||
int i;
|
||||
bool b;
|
||||
}
|
||||
|
||||
fn void Foo.foo(&self) {}
|
||||
fn int Foo.bar(&self, int x) { return x * self.i; }
|
||||
fn bool Foo.xyz(&self) { return self.b; }
|
||||
|
||||
struct NoMethods
|
||||
{
|
||||
int a;
|
||||
}
|
||||
|
||||
bitstruct BazBits : char
|
||||
{
|
||||
int a : 0..2;
|
||||
int b : 4..6;
|
||||
bool c : 7;
|
||||
}
|
||||
|
||||
fn void BazBits.fn1(&self) {}
|
||||
fn void BazBits.fn2(&self) {}
|
||||
|
||||
union AUnion {
|
||||
int y;
|
||||
double z;
|
||||
}
|
||||
|
||||
fn void AUnion.a(&self) {}
|
||||
fn void AUnion.b(&self) {}
|
||||
|
||||
|
||||
module methodsof @test;
|
||||
|
||||
import std::io;
|
||||
|
||||
fn void methodsof()
|
||||
{
|
||||
assert(Foo.methodsof.len == 3);
|
||||
assert(Bar.methodsof.len == 2);
|
||||
assert(NoMethods.methodsof.len == 0);
|
||||
|
||||
assert(Foo.methodsof[0] == "foo");
|
||||
assert(Foo.methodsof[1] == "bar");
|
||||
assert(Foo.methodsof[2] == "xyz");
|
||||
assert(Bar.methodsof[0] == "fnB");
|
||||
assert(Bar.methodsof[1] == "fnA");
|
||||
|
||||
assert(BazBits.methodsof[0] == "fn1");
|
||||
assert(BazBits.methodsof[1] == "fn2");
|
||||
|
||||
assert(AUnion.methodsof[0] == "a");
|
||||
assert(AUnion.methodsof[1] == "b");
|
||||
|
||||
Foo foo = { .i = 4, .b = true };
|
||||
assert(Foo.$eval(Foo.methodsof[2])(&foo) == true); // Foo.xyz
|
||||
assert(Foo.$eval(Foo.methodsof[1])(&foo, 2) == 8); // Foo.bar
|
||||
|
||||
Foo foo2 = { .i = 2, .b = false };
|
||||
assert(foo2.$eval(Foo.methodsof[2])() == false); // Foo.xyz
|
||||
assert(foo2.$eval(Foo.methodsof[1])(10) == 20); // Foo.bar
|
||||
}
|
||||
Reference in New Issue
Block a user