Simplify interfaces by requiring all functions are pointer methods

This commit is contained in:
Bruce Hill 2024-05-12 15:56:24 -04:00
parent f6f89265b7
commit 3481042259
6 changed files with 21 additions and 48 deletions

30
ast.c
View File

@ -136,7 +136,7 @@ CORD ast_to_xml(ast_t *ast)
T(StructDef, "<StructDef name=\"%s\">%r<namespace>%r</namespace></StructDef>", data.name, arg_list_to_xml(data.fields), ast_to_xml(data.namespace))
T(EnumDef, "<EnumDef name=\"%s\"><tags>%r</tags><namespace>%r</namespace></EnumDef>", data.name, tags_to_xml(data.tags), ast_to_xml(data.namespace))
T(LangDef, "<LangDef name=\"%s\">%r</LangDef>", data.name, ast_to_xml(data.namespace))
T(InterfaceDef, "<InterfaceDef name=\"%s\">%r%r</InterfaceDef>", data.name, type_ast_to_xml(data.type_parameter), arg_list_to_xml(data.fields))
T(InterfaceDef, "<InterfaceDef name=\"%s\">%r</InterfaceDef>", data.name, arg_list_to_xml(data.fields))
T(Index, "<Index>%r%r</Index>", optional_tagged("indexed", data.indexed), optional_tagged("index", data.index))
T(FieldAccess, "<FieldAccess field=\"%s\">%r</FieldAccess>", data.field, ast_to_xml(data.fielded))
T(Optional, "<Optional>%r</Optional>", 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

2
ast.h
View File

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

View File

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

View File

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

View File

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

View File

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