From 4dbe046866a6280cf304c7e0ec6471d872bc8e27 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 12 May 2024 15:18:46 -0400 Subject: Add interface fields --- compile.c | 22 +++++++++++++++------- interfaces.c | 2 ++ typecheck.c | 2 ++ types.c | 7 ++++++- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/compile.c b/compile.c index 88c5a0ba..782fc3fe 100644 --- a/compile.c +++ b/compile.c @@ -1702,16 +1702,24 @@ CORD compile(env_t *env, ast_t *ast) auto interface = Match(t, InterfaceType); ast_t *impl = call->args->value; type_t *impl_t = get_type(env, impl); - if (impl_t->tag != PointerType) + if (impl_t->tag != PointerType) { impl = WrapAST(impl, HeapAllocate, impl); - CORD c = CORD_all("(", compile_type(env, t), "){", compile(env, impl)); + impl_t = Type(PointerType, .pointed=impl_t); + } + CORD c = CORD_all("({ ", compile_type(env, impl_t), " $impl = ", compile(env, impl), "; (", compile_type(env, t), "){$impl"); for (arg_t *field = interface->fields->next; field; field = field->next) { binding_t *b = get_namespace_binding(env, impl, field->name); - if (!b) code_err(ast, "The type %T doesn't have '%s' for the interface %T", impl_t, field->name, t); - // TODO: typecheck implementation! - c = CORD_all(c, ", (void*)", b->code); + if (b) { + // TODO: typecheck implementation! + c = CORD_all(c, ", (void*)", b->code); + } else { + type_t *member_t = get_field_type(impl_t, field->name); + if (!member_t) + code_err(ast, "The type %T doesn't have '%s' for the interface %T", impl_t, field->name, t); + c = CORD_all(c, ", &$impl->", field->name); + } } - return CORD_cat(c, "}"); + return CORD_cat(c, "};})"); } else if (t->tag == IntType || t->tag == NumType) { // Int/Num constructor: if (!call->args || call->args->next) @@ -1883,7 +1891,7 @@ CORD compile(env_t *env, ast_t *ast) code_err(ast, "There is no '%s' field on tables", f->field); } case InterfaceType: { - code_err(ast, "Interface field access is not yet implemented"); + return CORD_all("(*(", compile_to_pointer_depth(env, f->fielded, 0, false), ").", f->field, ")"); } case ModuleType: { const char *name = Match(value_t, ModuleType)->name; diff --git a/interfaces.c b/interfaces.c index a1f1e73f..db587cba 100644 --- a/interfaces.c +++ b/interfaces.c @@ -69,6 +69,8 @@ void compile_interface_def(env_t *env, ast_t *ast) type_t *field_t = parse_type_ast(env, field_type); if (field_t->tag == ClosureType) field_t = Match(field_t, ClosureType)->fn; + if (field_t->tag != FunctionType) + field_t = Type(PointerType, .pointed=field_t); CORD decl = compile_declaration(env, field_t, field->name); CORD_appendf(&env->code->typecode, "%r%s;\n", decl, field_t->tag == BoolType ? ":1" : ""); diff --git a/typecheck.c b/typecheck.c index 5e3d005f..fa8e3003 100644 --- a/typecheck.c +++ b/typecheck.c @@ -284,6 +284,8 @@ void bind_statement(env_t *env, ast_t *statement) if ((field_t->tag == InterfaceType && Match(field_t, InterfaceType)->opaque) || (field_t->tag == EnumType && Match(field_t, EnumType)->opaque)) code_err(field_ast->type, "This type is recursive and would create an infinitely sized interface. Try using a pointer."); + if (field_t->tag != FunctionType) + field_t = Type(PointerType, .pointed=field_t); fields = new(arg_t, .name=field_ast->name, .type=field_t, .default_val=field_ast->value, .next=fields); } REVERSE_LIST(fields); diff --git a/types.c b/types.c index fd41bbcc..85060b4c 100644 --- a/types.c +++ b/types.c @@ -479,6 +479,8 @@ type_t *get_field_type(type_t *t, const char *field_name) { t = value_type(t); switch (t->tag) { + case PointerType: + return get_field_type(Match(t, PointerType)->pointed, field_name); case StructType: { auto struct_t = Match(t, StructType); for (arg_t *field = struct_t->fields; field; field = field->next) { @@ -490,8 +492,11 @@ type_t *get_field_type(type_t *t, const char *field_name) case InterfaceType: { auto interface = Match(t, InterfaceType); for (arg_t *field = interface->fields; field; field = field->next) { - if (streq(field->name, field_name)) + if (streq(field->name, field_name)) { + if (field->type->tag == PointerType) + return Match(field->type, PointerType)->pointed; return field->type; + } } return NULL; } -- cgit v1.2.3