From 3481042259c1db4d9fb4e50d5e91e8c58e8cdac5 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 12 May 2024 15:56:24 -0400 Subject: Simplify interfaces by requiring all functions are pointer methods --- ast.c | 30 +----------------------------- ast.h | 2 -- compile.c | 2 -- interfaces.c | 13 ++++++++----- parse.c | 5 ++--- typecheck.c | 17 ++++++++++------- 6 files changed, 21 insertions(+), 48 deletions(-) diff --git a/ast.c b/ast.c index c13c562a..9199a567 100644 --- a/ast.c +++ b/ast.c @@ -136,7 +136,7 @@ CORD ast_to_xml(ast_t *ast) T(StructDef, "%r%r", data.name, arg_list_to_xml(data.fields), ast_to_xml(data.namespace)) T(EnumDef, "%r%r", data.name, tags_to_xml(data.tags), ast_to_xml(data.namespace)) T(LangDef, "%r", data.name, ast_to_xml(data.namespace)) - T(InterfaceDef, "%r%r", data.name, type_ast_to_xml(data.type_parameter), arg_list_to_xml(data.fields)) + T(InterfaceDef, "%r", data.name, arg_list_to_xml(data.fields)) T(Index, "%r%r", optional_tagged("indexed", data.indexed), optional_tagged("index", data.index)) T(FieldAccess, "%r", data.field, ast_to_xml(data.fielded)) T(Optional, "%r", ast_to_xml(data.value)) @@ -236,32 +236,4 @@ bool type_ast_eq(type_ast_t *x, type_ast_t *y) return true; } -type_ast_t *replace_type_ast(type_ast_t *t, type_ast_t *target, type_ast_t *replacement) -{ - if (!t) return t; - if (type_ast_eq(t, target)) - return replacement; - -#define REPLACED_MEMBER(t, tag, member) ({ t = memcpy(GC_MALLOC(sizeof(type_ast_t)), (t), sizeof(type_ast_t)); Match((struct type_ast_s*)(t), tag)->member = replace_type_ast(Match((t), tag)->member, target, replacement); t; }) - switch (t->tag) { - case UnknownTypeAST: - case VarTypeAST: return t; - case PointerTypeAST: return REPLACED_MEMBER(t, PointerTypeAST, pointed); - case ArrayTypeAST: return REPLACED_MEMBER(t, ArrayTypeAST, item); - case TableTypeAST: { - t = REPLACED_MEMBER(t, TableTypeAST, key); - return REPLACED_MEMBER(t, TableTypeAST, value); - } - case FunctionTypeAST: { - auto fn = Match(t, FunctionTypeAST); - t = REPLACED_MEMBER(t, FunctionTypeAST, ret); - arg_ast_t *args = LIST_MAP(fn->args, old_arg, .type=replace_type_ast(old_arg->type, target, replacement)); - Match((struct type_ast_s*)t, FunctionTypeAST)->args = args; - return t; - } - } - return t; -#undef REPLACED_MEMBER -} - // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/ast.h b/ast.h index 5c983a17..97bbd886 100644 --- a/ast.h +++ b/ast.h @@ -251,7 +251,6 @@ struct ast_s { } LangDef; struct { const char *name; - type_ast_t *type_parameter; arg_ast_t *fields; ast_t *namespace; } InterfaceDef; @@ -290,6 +289,5 @@ CORD type_ast_to_xml(type_ast_t *ast); int printf_ast(FILE *stream, const struct printf_info *info, const void *const args[]); ast_list_t *get_ast_children(ast_t *ast); bool is_idempotent(ast_t *ast); -type_ast_t *replace_type_ast(type_ast_t *t, type_ast_t *target, type_ast_t *replacement); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/compile.c b/compile.c index 7595a6ec..3f25f5f0 100644 --- a/compile.c +++ b/compile.c @@ -1662,8 +1662,6 @@ CORD compile(env_t *env, ast_t *ast) arg_t *type_args = Match(field_t, FunctionType)->args; CORD args = compile_arguments(env, ast, type_args->next, methodcall->args); - if (Match(field_t, FunctionType)->args->type->tag != PointerType) - code_err(ast, "Interface methods that take value types can't be called"); return CORD_all("({ ", compile_type(env, self_value_t), " $self = ", compile_to_pointer_depth(env, methodcall->self, 0, false), "; ", "$self.", methodcall->name, "($self.$obj", diff --git a/interfaces.c b/interfaces.c index db587cba..6406a9ce 100644 --- a/interfaces.c +++ b/interfaces.c @@ -63,14 +63,17 @@ void compile_interface_def(env_t *env, ast_t *ast) CORD_appendf(&env->code->typedefs, "#define %r(...) ((%r_t){__VA_ARGS__})\n", full_name, full_name); CORD_appendf(&env->code->typecode, "struct %r_s {\nvoid *$obj;\n", full_name); - type_ast_t *replacement_type_ast = NewTypeAST(ast->file, ast->start, ast->end, VarTypeAST, .name=def->name); for (arg_ast_t *field = def->fields; field; field = field->next) { - type_ast_t *field_type = replace_type_ast(field->type, def->type_parameter, replacement_type_ast); - type_t *field_t = parse_type_ast(env, field_type); - if (field_t->tag == ClosureType) + 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) + // Convert to method: + field_t = Type(FunctionType, .args=new(arg_t, .name="$obj", .type=Type(PointerType, .pointed=Type(MemoryType)), + .next=Match(field_t, FunctionType)->args), + .ret=Match(field_t, FunctionType)->ret); + } else { 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/parse.c b/parse.c index b657d353..7e9c246d 100644 --- a/parse.c +++ b/parse.c @@ -1825,10 +1825,9 @@ PARSER(parse_interface_def) { if (!match(&pos, "(")) parser_err(ctx, pos, pos, "I expected a '(' and a list of fields here"); - type_ast_t *type_param = expect(ctx, start, &pos, parse_type, "I couldn't parse the type parameter for this interface"); whitespace(&pos); - expect_str(ctx, start, &pos, ";", "I expected a ';' here"); arg_ast_t *fields = parse_args(ctx, &pos, false); + whitespace(&pos); expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this interface definition"); ast_t *namespace = NULL; @@ -1844,7 +1843,7 @@ PARSER(parse_interface_def) { if (!namespace) namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL); - return NewAST(ctx->file, start, pos, InterfaceDef, .name=name, .type_parameter=type_param, .fields=fields, .namespace=namespace); + return NewAST(ctx->file, start, pos, InterfaceDef, .name=name, .fields=fields, .namespace=namespace); } arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos, bool allow_unnamed) diff --git a/typecheck.c b/typecheck.c index fa8e3003..c4184579 100644 --- a/typecheck.c +++ b/typecheck.c @@ -272,20 +272,23 @@ void bind_statement(env_t *env, ast_t *statement) arg_t *fields = new(arg_t, .name="$obj", .type=Type(PointerType, .pointed=Type(MemoryType))); // interface implementor type_t *type = Type(InterfaceType, .name=def->name, .fields=fields, .opaque=true, .env=ns_env); // placeholder - type_ast_t *replacement_type_ast = NewTypeAST(statement->file, statement->start, statement->end, VarTypeAST, .name=def->name); Table$str_set(env->types, def->name, type); for (arg_ast_t *field_ast = def->fields; field_ast; field_ast = field_ast->next) { if (!field_ast->type) code_err(field_ast->value, "Interface fields must have defined types, not default values"); - type_ast_t *field_type = replace_type_ast(field_ast->type, def->type_parameter, replacement_type_ast); - type_t *field_t = parse_type_ast(env, field_type); - if (field_t->tag == ClosureType) + type_t *field_t = parse_type_ast(env, field_ast->type); + if (field_t->tag == ClosureType) { field_t = Match(field_t, ClosureType)->fn; - if ((field_t->tag == InterfaceType && Match(field_t, InterfaceType)->opaque) - || (field_t->tag == EnumType && Match(field_t, EnumType)->opaque)) + // Convert to method: + field_t = Type(FunctionType, .args=new(arg_t, .name="$obj", .type=Type(PointerType, .pointed=Type(MemoryType)), + .next=Match(field_t, FunctionType)->args), + .ret=Match(field_t, FunctionType)->ret); + } else 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) + } else { 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); -- cgit v1.2.3