aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-05-12 15:18:46 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-05-12 15:18:46 -0400
commit4dbe046866a6280cf304c7e0ec6471d872bc8e27 (patch)
tree293b94a73769a8fd10cdc5135a3af8da82c4d334
parent8ada56c4248e9e09b8f151e9d516739dd86ad520 (diff)
Add interface fields
-rw-r--r--compile.c22
-rw-r--r--interfaces.c2
-rw-r--r--typecheck.c2
-rw-r--r--types.c7
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;
}