Add methodsof to type info (#1303)

Add `methodsof` to type info for struct, union and bitstruct
This commit is contained in:
Dodzey
2024-08-05 20:58:13 +01:00
committed by GitHub
parent e748f72447
commit 9daa173ab7
5 changed files with 137 additions and 0 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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:

View File

@@ -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");

View 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
}