Simplify interfaces by requiring all functions are pointer methods
This commit is contained in:
parent
f6f89265b7
commit
3481042259
30
ast.c
30
ast.c
@ -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
2
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
|
||||
|
@ -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",
|
||||
|
13
interfaces.c
13
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" : "");
|
||||
|
5
parse.c
5
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)
|
||||
|
17
typecheck.c
17
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);
|
||||
|
Loading…
Reference in New Issue
Block a user