aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-05-12 15:56:24 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-05-12 15:56:24 -0400
commit3481042259c1db4d9fb4e50d5e91e8c58e8cdac5 (patch)
treefa3a470a0ac5cce72bb9380c64495c00fa4da179
parentf6f89265b7eb73bd9a036133033e4fd654196b50 (diff)
Simplify interfaces by requiring all functions are pointer methods
-rw-r--r--ast.c30
-rw-r--r--ast.h2
-rw-r--r--compile.c2
-rw-r--r--interfaces.c13
-rw-r--r--parse.c5
-rw-r--r--typecheck.c17
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, "<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
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);