Deprecate interfaces (RIP)
This commit is contained in:
parent
934fd8a173
commit
02fe49a764
2
Makefile
2
Makefile
@ -29,7 +29,7 @@ BUILTIN_OBJS=builtins/array.o builtins/bool.o builtins/nums.o builtins/functions
|
||||
|
||||
all: libtomo.so tomo
|
||||
|
||||
tomo: tomo.c SipHash/halfsiphash.o ast.o parse.o environment.o types.o typecheck.o structs.o enums.o interfaces.o compile.o repl.o
|
||||
tomo: tomo.c SipHash/halfsiphash.o ast.o parse.o environment.o types.o typecheck.o structs.o enums.o compile.o repl.o
|
||||
|
||||
libtomo.so: $(BUILTIN_OBJS) SipHash/halfsiphash.o
|
||||
$(CC) $^ $(CFLAGS) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) -lgc -lcord -lm -lunistring -ldl -Wl,-soname,libtomo.so -shared -o $@
|
||||
|
1
ast.c
1
ast.c
@ -136,7 +136,6 @@ 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</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))
|
||||
|
7
ast.h
7
ast.h
@ -111,7 +111,7 @@ typedef enum {
|
||||
Skip, Stop, Pass,
|
||||
Return,
|
||||
Extern,
|
||||
StructDef, EnumDef, LangDef, InterfaceDef,
|
||||
StructDef, EnumDef, LangDef,
|
||||
Index, FieldAccess, Optional,
|
||||
DocTest,
|
||||
Use,
|
||||
@ -249,11 +249,6 @@ struct ast_s {
|
||||
const char *name;
|
||||
ast_t *namespace;
|
||||
} LangDef;
|
||||
struct {
|
||||
const char *name;
|
||||
arg_ast_t *fields;
|
||||
ast_t *namespace;
|
||||
} InterfaceDef;
|
||||
struct {
|
||||
ast_t *indexed, *index;
|
||||
bool unchecked;
|
||||
|
77
compile.c
77
compile.c
@ -10,7 +10,6 @@
|
||||
#include "compile.h"
|
||||
#include "enums.h"
|
||||
#include "structs.h"
|
||||
#include "interfaces.h"
|
||||
#include "environment.h"
|
||||
#include "typecheck.h"
|
||||
#include "builtins/util.h"
|
||||
@ -116,10 +115,6 @@ CORD compile_type(env_t *env, type_t *t)
|
||||
auto e = Match(t, EnumType);
|
||||
return CORD_all(e->env->file_prefix, e->name, "_t");
|
||||
}
|
||||
case InterfaceType: {
|
||||
auto s = Match(t, InterfaceType);
|
||||
return CORD_all(s->env->file_prefix, s->name, "_t");
|
||||
}
|
||||
case TypeInfoType: return "TypeInfo";
|
||||
default: compiler_err(NULL, NULL, NULL, "Not implemented");
|
||||
}
|
||||
@ -446,10 +441,6 @@ CORD compile_statement(env_t *env, ast_t *ast)
|
||||
compile_namespace(env, def->name, def->namespace);
|
||||
return CORD_EMPTY;
|
||||
}
|
||||
case InterfaceDef: {
|
||||
compile_interface_def(env, ast);
|
||||
return CORD_EMPTY;
|
||||
}
|
||||
case FunctionDef: {
|
||||
auto fndef = Match(ast, FunctionDef);
|
||||
bool is_private = Match(fndef->name, Var)->name[0] == '_';
|
||||
@ -862,7 +853,7 @@ CORD expr_as_text(env_t *env, CORD expr, type_t *t, CORD color)
|
||||
case TableType: return CORD_asprintf("Table$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
|
||||
case FunctionType: case ClosureType: return CORD_asprintf("Func$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
|
||||
case PointerType: return CORD_asprintf("Pointer$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
|
||||
case StructType: case EnumType: case InterfaceType:
|
||||
case StructType: case EnumType:
|
||||
return CORD_asprintf("(%r)->CustomInfo.as_text(stack(%r), %r, %r)",
|
||||
compile_type_info(env, t), expr, color, compile_type_info(env, t));
|
||||
default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for %T", t);
|
||||
@ -1651,35 +1642,6 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
return CORD_all("Table$clear(", self, ")");
|
||||
} else code_err(ast, "There is no '%s' method for tables", call->name);
|
||||
}
|
||||
case InterfaceType: {
|
||||
auto methodcall = Match(ast, MethodCall);
|
||||
binding_t *b = get_namespace_binding(env, methodcall->self, methodcall->name);
|
||||
if (b) {
|
||||
type_t *fn_t = get_method_type(env, methodcall->self, methodcall->name);
|
||||
arg_ast_t *args = new(arg_ast_t, .value=methodcall->self, .next=methodcall->args);
|
||||
return CORD_all(b->code, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, args), ")");
|
||||
} else {
|
||||
auto interface = Match(self_value_t, InterfaceType);
|
||||
for (arg_t *field = interface->fields; field; field = field->next) {
|
||||
if (streq(field->name, methodcall->name)) {
|
||||
env_t tmp_env = *env;
|
||||
tmp_env.types = new(table_t, .fallback=tmp_env.types);
|
||||
Table$str_set(tmp_env.types, interface->type_parameter, self_value_t);
|
||||
type_t *field_t = field->type;
|
||||
if (field_t->tag == ClosureType)
|
||||
field_t = Match(field_t, ClosureType)->fn;
|
||||
|
||||
arg_t *type_args = Match(field_t, FunctionType)->args;
|
||||
CORD args = compile_arguments(env, ast, type_args->next, methodcall->args);
|
||||
return CORD_all("({ ", compile_type(env, self_value_t), " $self = ",
|
||||
compile_to_pointer_depth(env, methodcall->self, 0, false), "; ",
|
||||
"$self.", methodcall->name, "($self.$obj",
|
||||
args == CORD_EMPTY ? CORD_EMPTY : ", ", args, "); })");
|
||||
}
|
||||
}
|
||||
code_err(ast, "There is no method called '%s' on the interface type %s", methodcall->name, interface->name);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
auto methodcall = Match(ast, MethodCall);
|
||||
type_t *fn_t = get_method_type(env, methodcall->self, methodcall->name);
|
||||
@ -1703,34 +1665,6 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
fn_t = Type(FunctionType, .args=Match(t, StructType)->fields, .ret=t);
|
||||
CORD fn = compile(env, call->fn);
|
||||
return CORD_all(fn, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, call->args), ")");
|
||||
} else if (t->tag == InterfaceType) {
|
||||
// Interface constructor:
|
||||
if (!call->args) code_err(ast, "You need to provide an argument to this interface constructor");
|
||||
if (call->args->next) code_err(ast, "This interface constructor only takes one argument");
|
||||
auto interface = Match(t, InterfaceType);
|
||||
ast_t *impl = call->args->value;
|
||||
type_t *impl_t = get_type(env, impl);
|
||||
if (impl_t->tag != PointerType) {
|
||||
impl = WrapAST(impl, HeapAllocate, 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) {
|
||||
// TODO: typecheck implementation!
|
||||
CORD field_code = b->code;
|
||||
if (!promote(env, &field_code, b->type, field->type))
|
||||
code_err(ast, "I can't promote the method '%s' from %T to %T", field->name, b->type, field->type);
|
||||
c = CORD_all(c, ", ", field_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, "};})");
|
||||
} else if (t->tag == IntType || t->tag == NumType) {
|
||||
// Int/Num constructor:
|
||||
if (!call->args || call->args->next)
|
||||
@ -1901,9 +1835,6 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
}
|
||||
code_err(ast, "There is no '%s' field on tables", f->field);
|
||||
}
|
||||
case InterfaceType: {
|
||||
return CORD_all("(*(", compile_to_pointer_depth(env, f->fielded, 0, false), ").", f->field, ")");
|
||||
}
|
||||
case ModuleType: {
|
||||
const char *name = Match(value_t, ModuleType)->name;
|
||||
env_t *module_env = Table$str_get(*env->imports, name);
|
||||
@ -1969,7 +1900,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
case Extern: code_err(ast, "Externs are not supported yet");
|
||||
case TableEntry: code_err(ast, "Table entries should not be compiled directly");
|
||||
case Declare: case Assign: case UpdateAssign: case For: case While: case StructDef: case LangDef:
|
||||
case EnumDef: case FunctionDef: case InterfaceDef: case Skip: case Stop: case Pass: case Return: case DocTest:
|
||||
case EnumDef: case FunctionDef: case Skip: case Stop: case Pass: case Return: case DocTest:
|
||||
code_err(ast, "This is not a valid expression");
|
||||
case Unknown: code_err(ast, "Unknown AST");
|
||||
}
|
||||
@ -2025,10 +1956,6 @@ CORD compile_type_info(env_t *env, type_t *t)
|
||||
auto e = Match(t, EnumType);
|
||||
return CORD_all("(&", e->env->file_prefix, e->name, ")");
|
||||
}
|
||||
case InterfaceType: {
|
||||
auto i = Match(t, InterfaceType);
|
||||
return CORD_all("(&", i->env->file_prefix, i->name, ")");
|
||||
}
|
||||
case ArrayType: {
|
||||
type_t *item_t = Match(t, ArrayType)->item_type;
|
||||
return CORD_asprintf("$ArrayInfo(%r)", compile_type_info(env, item_t));
|
||||
|
@ -324,10 +324,6 @@ binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name)
|
||||
auto enum_ = Match(cls_type, EnumType);
|
||||
return enum_->env ? get_binding(enum_->env, name) : NULL;
|
||||
}
|
||||
case InterfaceType: {
|
||||
auto interface = Match(cls_type, InterfaceType);
|
||||
return interface->env ? get_binding(interface->env, name) : NULL;
|
||||
}
|
||||
case TypeInfoType: {
|
||||
auto info = Match(cls_type, TypeInfoType);
|
||||
return info->env ? get_binding(info->env, name) : NULL;
|
||||
|
125
interfaces.c
125
interfaces.c
@ -1,125 +0,0 @@
|
||||
// Logic for compiling interfaces
|
||||
#include <ctype.h>
|
||||
#include <gc/cord.h>
|
||||
#include <gc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ast.h"
|
||||
#include "builtins/text.h"
|
||||
#include "compile.h"
|
||||
#include "interfaces.h"
|
||||
#include "environment.h"
|
||||
#include "typecheck.h"
|
||||
#include "builtins/util.h"
|
||||
|
||||
static CORD compile_str_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, InterfaceDef);
|
||||
CORD full_name = CORD_cat(env->file_prefix, def->name);
|
||||
const char *name = def->name;
|
||||
const char *dollar = strrchr(name, '$');
|
||||
if (dollar) name = dollar + 1;
|
||||
CORD str_func = CORD_asprintf("static CORD %r$as_text(%r_t *interface, bool use_color) {\n"
|
||||
"\tif (!interface) return \"%s\";\n", full_name, full_name, name);
|
||||
return CORD_all(str_func, "\treturn CORD_asprintf(use_color ? \"\\x1b[0;1m", name, "\\x1b[m<\\x1b[36m%p\\x1b[m>\" : \"", name, "<%p>\", interface->$obj);\n}");
|
||||
}
|
||||
|
||||
static CORD compile_compare_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, InterfaceDef);
|
||||
CORD full_name = CORD_cat(env->file_prefix, def->name);
|
||||
return CORD_all("static int ", full_name, "$compare(const ", full_name, "_t *x, const ", full_name,
|
||||
"_t *y, const TypeInfo *info) {\n"
|
||||
"(void)info;\n",
|
||||
"return (x->$obj > y->$obj) - (x->$obj < y->$obj);\n}");
|
||||
}
|
||||
|
||||
static CORD compile_equals_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, InterfaceDef);
|
||||
CORD full_name = CORD_cat(env->file_prefix, def->name);
|
||||
return CORD_all("static bool ", full_name, "$equal(const ", full_name, "_t *x, const ", full_name,
|
||||
"_t *y, const TypeInfo *info) {\n"
|
||||
"(void)info;\n",
|
||||
"return (x->$obj == y->$obj);\n}");
|
||||
}
|
||||
|
||||
static CORD compile_hash_method(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, InterfaceDef);
|
||||
CORD full_name = CORD_cat(env->file_prefix, def->name);
|
||||
return CORD_all("static uint32_t ", full_name, "$hash(const ", full_name, "_t *interface, const TypeInfo *info) {\n"
|
||||
"(void)info;\n"
|
||||
"uint32_t hash;\n"
|
||||
"halfsiphash(&interface->$obj, sizeof(void*), TOMO_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));\n"
|
||||
"return hash;\n}\n");
|
||||
}
|
||||
|
||||
void compile_interface_def(env_t *env, ast_t *ast)
|
||||
{
|
||||
auto def = Match(ast, InterfaceDef);
|
||||
CORD full_name = CORD_cat(env->file_prefix, def->name);
|
||||
CORD_appendf(&env->code->typedefs, "typedef struct %r_s %r_t;\n", full_name, full_name);
|
||||
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);
|
||||
for (arg_ast_t *field = def->fields; field; field = field->next) {
|
||||
type_t *field_t = parse_type_ast(env, field->type);
|
||||
if (field_t->tag == ClosureType) {
|
||||
field_t = Match(field_t, ClosureType)->fn;
|
||||
// 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" : "");
|
||||
}
|
||||
CORD_appendf(&env->code->typecode, "};\n");
|
||||
|
||||
// Typeinfo:
|
||||
CORD_appendf(&env->code->typedefs, "extern const TypeInfo %r;\n", full_name);
|
||||
|
||||
type_t *t = Table$str_get(*env->types, def->name);
|
||||
assert(t && t->tag == InterfaceType);
|
||||
auto interface = Match(t, InterfaceType);
|
||||
CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=CustomInfo, .CustomInfo={",
|
||||
full_name, type_size(t), type_align(t));
|
||||
|
||||
typeinfo = CORD_all(typeinfo, ".as_text=(void*)", full_name, "$as_text, ");
|
||||
env->code->funcs = CORD_all(env->code->funcs, compile_str_method(env, ast));
|
||||
|
||||
if (interface->fields && !interface->fields->next) { // Single member, can just use its methods
|
||||
type_t *member_t = interface->fields->type;
|
||||
switch (member_t->tag) {
|
||||
case TextType:
|
||||
typeinfo = CORD_all(typeinfo, ".hash=(void*)", type_to_cord(member_t), "$hash", ", ");
|
||||
// fallthrough
|
||||
case IntType: case NumType:
|
||||
typeinfo = CORD_all(typeinfo, ".compare=(void*)", type_to_cord(member_t), "$compare, "
|
||||
".equal=(void*)", type_to_cord(member_t), "$equal, ");
|
||||
// fallthrough
|
||||
case BoolType: goto got_methods;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (interface->fields) {
|
||||
env->code->funcs = CORD_all(env->code->funcs, compile_compare_method(env, ast),
|
||||
compile_equals_method(env, ast), compile_hash_method(env, ast));
|
||||
typeinfo = CORD_all(
|
||||
typeinfo,
|
||||
".compare=(void*)", full_name, "$compare, "
|
||||
".equal=(void*)", full_name, "$equal, "
|
||||
".hash=(void*)", full_name, "$hash");
|
||||
}
|
||||
got_methods:;
|
||||
typeinfo = CORD_cat(typeinfo, "}}};\n");
|
||||
env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo);
|
||||
|
||||
compile_namespace(env, def->name, def->namespace);
|
||||
}
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
10
interfaces.h
10
interfaces.h
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Compilation of user-defined interfaces
|
||||
|
||||
#include "ast.h"
|
||||
#include "environment.h"
|
||||
|
||||
void compile_interface_def(env_t *env, ast_t *ast);
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
37
parse.c
37
parse.c
@ -91,7 +91,6 @@ static PARSER(parse_var);
|
||||
static PARSER(parse_enum_def);
|
||||
static PARSER(parse_struct_def);
|
||||
static PARSER(parse_lang_def);
|
||||
static PARSER(parse_interface_def);
|
||||
static PARSER(parse_text);
|
||||
static PARSER(parse_func_def);
|
||||
static PARSER(parse_extern);
|
||||
@ -1598,7 +1597,6 @@ PARSER(parse_namespace) {
|
||||
if ((stmt=optional(ctx, &pos, parse_struct_def))
|
||||
||(stmt=optional(ctx, &pos, parse_enum_def))
|
||||
||(stmt=optional(ctx, &pos, parse_lang_def))
|
||||
||(stmt=optional(ctx, &pos, parse_interface_def))
|
||||
||(stmt=optional(ctx, &pos, parse_func_def))
|
||||
||(stmt=optional(ctx, &pos, parse_use))
|
||||
||(stmt=optional(ctx, &pos, parse_linker))
|
||||
@ -1634,7 +1632,6 @@ PARSER(parse_file_body) {
|
||||
if ((stmt=optional(ctx, &pos, parse_struct_def))
|
||||
||(stmt=optional(ctx, &pos, parse_enum_def))
|
||||
||(stmt=optional(ctx, &pos, parse_lang_def))
|
||||
||(stmt=optional(ctx, &pos, parse_interface_def))
|
||||
||(stmt=optional(ctx, &pos, parse_func_def))
|
||||
||(stmt=optional(ctx, &pos, parse_use))
|
||||
||(stmt=optional(ctx, &pos, parse_linker))
|
||||
@ -1812,40 +1809,6 @@ PARSER(parse_lang_def) {
|
||||
return NewAST(ctx->file, start, pos, LangDef, .name=name, .namespace=namespace);
|
||||
}
|
||||
|
||||
PARSER(parse_interface_def) {
|
||||
// interface Name(T; field:type, ...): namespace...
|
||||
const char *start = pos;
|
||||
if (!match_word(&pos, "interface")) return NULL;
|
||||
int64_t starting_indent = get_indent(ctx, pos);
|
||||
spaces(&pos);
|
||||
const char *name = get_id(&pos);
|
||||
if (!name)
|
||||
parser_err(ctx, start, pos, "I expected a name for this interface");
|
||||
spaces(&pos);
|
||||
|
||||
if (!match(&pos, "("))
|
||||
parser_err(ctx, pos, pos, "I expected a '(' and a list of fields here");
|
||||
whitespace(&pos);
|
||||
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;
|
||||
if (match(&pos, ":")) {
|
||||
const char *ns_pos = pos;
|
||||
whitespace(&ns_pos);
|
||||
int64_t ns_indent = get_indent(ctx, ns_pos);
|
||||
if (ns_indent > starting_indent) {
|
||||
pos = ns_pos;
|
||||
namespace = optional(ctx, &pos, parse_namespace);
|
||||
}
|
||||
}
|
||||
if (!namespace)
|
||||
namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
|
||||
|
||||
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)
|
||||
{
|
||||
arg_ast_t *args = NULL;
|
||||
|
73
typecheck.c
73
typecheck.c
@ -263,46 +263,6 @@ void bind_statement(env_t *env, ast_t *statement)
|
||||
bind_statement(ns_env, stmt->ast);
|
||||
break;
|
||||
}
|
||||
case InterfaceDef: {
|
||||
auto def = Match(statement, InterfaceDef);
|
||||
if (get_binding(env, def->name))
|
||||
code_err(statement, "A %T called '%s' has already been defined", get_binding(env, def->name)->type, def->name);
|
||||
|
||||
env_t *ns_env = namespace_env(env, def->name);
|
||||
|
||||
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
|
||||
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_t *field_t = parse_type_ast(env, field_ast->type);
|
||||
if (field_t->tag == ClosureType) {
|
||||
field_t = Match(field_t, ClosureType)->fn;
|
||||
// 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.");
|
||||
} 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);
|
||||
type->__data.InterfaceType.fields = fields; // populate placeholder
|
||||
type->__data.InterfaceType.opaque = false;
|
||||
|
||||
type_t *typeinfo_type = Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env);
|
||||
Table$str_set(env->locals, def->name, new(binding_t, .type=typeinfo_type, .code=CORD_all(env->file_prefix, def->name)));
|
||||
|
||||
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
|
||||
bind_statement(ns_env, stmt->ast);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Use: {
|
||||
env_t *module_env = load_module(env, statement);
|
||||
for (table_t *bindings = module_env->locals; bindings != module_env->globals; bindings = bindings->fallback) {
|
||||
@ -593,7 +553,7 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
|
||||
if (fn_type_t->tag == TypeInfoType) {
|
||||
type_t *t = Match(fn_type_t, TypeInfoType)->type;
|
||||
if (t->tag == StructType || t->tag == InterfaceType || t->tag == IntType || t->tag == NumType)
|
||||
if (t->tag == StructType || t->tag == IntType || t->tag == NumType)
|
||||
return t; // Constructor
|
||||
code_err(call->fn, "This is not a type that has a constructor");
|
||||
}
|
||||
@ -634,31 +594,6 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
else if (streq(call->name, "clear")) return Type(VoidType);
|
||||
else code_err(ast, "There is no '%s' method for tables", call->name);
|
||||
}
|
||||
case InterfaceType: {
|
||||
auto methodcall = Match(ast, MethodCall);
|
||||
binding_t *b = get_namespace_binding(env, methodcall->self, methodcall->name);
|
||||
if (b) {
|
||||
if (b->type->tag != FunctionType)
|
||||
code_err(ast, "'%s' is not a function, it's a %T", methodcall->name, b->type);
|
||||
return Match(b->type, FunctionType)->ret;
|
||||
} else {
|
||||
auto interface = Match(self_value_t, InterfaceType);
|
||||
for (arg_t *field = interface->fields; field; field = field->next) {
|
||||
if (streq(field->name, methodcall->name)) {
|
||||
env_t tmp_env = *env;
|
||||
tmp_env.types = new(table_t, .fallback=tmp_env.types);
|
||||
Table$str_set(tmp_env.types, interface->type_parameter, self_value_t);
|
||||
type_t *field_t = field->type;
|
||||
if (field_t->tag == ClosureType)
|
||||
field_t = Match(field_t, ClosureType)->fn;
|
||||
if (field_t->tag != FunctionType)
|
||||
code_err(ast, "'%s' is not a function, it's a %T", methodcall->name, b->type);
|
||||
return Match(field_t, FunctionType)->ret;
|
||||
}
|
||||
}
|
||||
code_err(ast, "There is no method called '%s' on the interface type %s", methodcall->name, interface->name);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
type_t *fn_type_t = get_method_type(env, call->self, call->name);
|
||||
if (!fn_type_t)
|
||||
@ -680,7 +615,7 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
|
||||
// Early out if the type is knowable without any context from the block:
|
||||
switch (last->ast->tag) {
|
||||
case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: case LangDef: case InterfaceDef:
|
||||
case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: case LangDef:
|
||||
return Type(VoidType);
|
||||
default: break;
|
||||
}
|
||||
@ -857,7 +792,7 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
return Type(ClosureType, Type(FunctionType, .args=args, .ret=ret));
|
||||
}
|
||||
|
||||
case FunctionDef: case StructDef: case EnumDef: case LangDef: case InterfaceDef: {
|
||||
case FunctionDef: case StructDef: case EnumDef: case LangDef: {
|
||||
return Type(VoidType);
|
||||
}
|
||||
|
||||
@ -996,7 +931,7 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
bool is_discardable(env_t *env, ast_t *ast)
|
||||
{
|
||||
switch (ast->tag) {
|
||||
case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: case LangDef: case InterfaceDef: case Use:
|
||||
case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: case LangDef: case Use:
|
||||
return true;
|
||||
default: break;
|
||||
}
|
||||
|
38
types.c
38
types.c
@ -45,9 +45,6 @@ CORD type_to_cord(type_t *t) {
|
||||
auto struct_ = Match(t, StructType);
|
||||
return struct_->name;
|
||||
}
|
||||
case InterfaceType: {
|
||||
return Match(t, InterfaceType)->name;
|
||||
}
|
||||
case PointerType: {
|
||||
auto ptr = Match(t, PointerType);
|
||||
CORD sigil = ptr->is_stack ? "&" : "@";
|
||||
@ -216,7 +213,6 @@ bool has_heap_memory(type_t *t)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case InterfaceType: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@ -309,7 +305,6 @@ bool can_leave_uninitialized(type_t *t)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case InterfaceType: return false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@ -337,13 +332,6 @@ static bool _can_have_cycles(type_t *t, table_t *seen)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case InterfaceType: {
|
||||
for (arg_t *field = Match(t, InterfaceType)->fields; field; field = field->next) {
|
||||
if (_can_have_cycles(field->type, seen))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@ -390,13 +378,6 @@ type_t *replace_type(type_t *t, type_t *target, type_t *replacement)
|
||||
Match((struct type_s*)t, EnumType)->tags = tags;
|
||||
return t;
|
||||
}
|
||||
case InterfaceType: {
|
||||
auto interface = Match(t, InterfaceType);
|
||||
arg_t *fields = LIST_MAP(interface->fields, field, .type=replace_type(field->type, target, replacement));
|
||||
t = COPY(t);
|
||||
Match((struct type_s*)t, InterfaceType)->fields = fields;
|
||||
return t;
|
||||
}
|
||||
default: return t;
|
||||
}
|
||||
#undef COPY
|
||||
@ -417,8 +398,8 @@ size_t type_size(type_t *t)
|
||||
case FunctionType: return sizeof(void*);
|
||||
case ClosureType: return sizeof(struct {void *fn, *userdata;});
|
||||
case PointerType: return sizeof(void*);
|
||||
case StructType: case InterfaceType: {
|
||||
arg_t *fields = t->tag == StructType ? Match(t, StructType)->fields : Match(t, InterfaceType)->fields;
|
||||
case StructType: {
|
||||
arg_t *fields = Match(t, StructType)->fields;
|
||||
size_t size = t->tag == StructType ? 0 : sizeof(void*);
|
||||
for (arg_t *field = fields; field; field = field->next) {
|
||||
type_t *field_type = field->type;
|
||||
@ -468,8 +449,8 @@ size_t type_align(type_t *t)
|
||||
case FunctionType: return __alignof__(void*);
|
||||
case ClosureType: return __alignof__(struct {void *fn, *userdata;});
|
||||
case PointerType: return __alignof__(void*);
|
||||
case StructType: case InterfaceType: {
|
||||
arg_t *fields = t->tag == StructType ? Match(t, StructType)->fields : Match(t, InterfaceType)->fields;
|
||||
case StructType: {
|
||||
arg_t *fields = Match(t, StructType)->fields;
|
||||
size_t align = t->tag == StructType ? 0 : sizeof(void*);
|
||||
for (arg_t *field = fields; field; field = field->next) {
|
||||
size_t field_align = type_align(field->type);
|
||||
@ -505,17 +486,6 @@ type_t *get_field_type(type_t *t, const char *field_name)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
case InterfaceType: {
|
||||
auto interface = Match(t, InterfaceType);
|
||||
for (arg_t *field = interface->fields; field; field = field->next) {
|
||||
if (streq(field->name, field_name)) {
|
||||
if (field->type->tag == PointerType)
|
||||
return Match(field->type, PointerType)->pointed;
|
||||
return field->type;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
case EnumType: {
|
||||
auto e = Match(t, EnumType);
|
||||
for (tag_t *tag = e->tags; tag; tag = tag->next) {
|
||||
|
7
types.h
7
types.h
@ -52,7 +52,6 @@ struct type_s {
|
||||
PointerType,
|
||||
StructType,
|
||||
EnumType,
|
||||
InterfaceType,
|
||||
TypeInfoType,
|
||||
ModuleType,
|
||||
} tag;
|
||||
@ -99,12 +98,6 @@ struct type_s {
|
||||
bool opaque;
|
||||
struct env_s *env;
|
||||
} EnumType;
|
||||
struct {
|
||||
const char *name, *type_parameter;
|
||||
arg_t *fields;
|
||||
bool opaque;
|
||||
struct env_s *env;
|
||||
} InterfaceType;
|
||||
struct {
|
||||
const char *name;
|
||||
type_t *type;
|
||||
|
Loading…
Reference in New Issue
Block a user