diff options
Diffstat (limited to 'compile.c')
| -rw-r--r-- | compile.c | 85 |
1 files changed, 79 insertions, 6 deletions
@@ -10,6 +10,7 @@ #include "compile.h" #include "enums.h" #include "structs.h" +#include "interfaces.h" #include "environment.h" #include "typecheck.h" #include "builtins/util.h" @@ -107,6 +108,10 @@ 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"); } @@ -424,7 +429,6 @@ CORD compile_statement(env_t *env, ast_t *ast) return CORD_EMPTY; } case LangDef: { - // TODO: implement auto def = Match(ast, LangDef); CORD_appendf(&env->code->typedefs, "typedef CORD %r%s_t;\n", env->file_prefix, def->name); CORD_appendf(&env->code->typedefs, "extern const TypeInfo %r%s;\n", env->file_prefix, def->name); @@ -434,6 +438,10 @@ 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] == '_'; @@ -810,6 +818,8 @@ CORD compile_statement(env_t *env, ast_t *ast) return CORD_EMPTY; } default: + if (!is_discardable(env, ast)) + code_err(ast, "The result of this statement cannot be discarded"); return CORD_asprintf("(void)%r;", compile(env, ast)); } } @@ -843,8 +853,9 @@ 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: return CORD_asprintf("(%r)->CustomInfo.as_text(stack(%r), %r, %r)", - compile_type_info(env, t), expr, color, compile_type_info(env, t)); + case StructType: case EnumType: case InterfaceType: + 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); } } @@ -1468,8 +1479,14 @@ CORD compile(env_t *env, ast_t *ast) code = CORD_all(code, compile_type(env, arg_type), " $", arg->name, ", "); } - for (ast_list_t *stmt = Match(lambda->body, Block)->statements; stmt; stmt = stmt->next) - (void)compile_statement(body_scope, stmt->ast); + // Find which variables are captured in the closure: + env_t *tmp_scope = fresh_scope(body_scope); + for (ast_list_t *stmt = Match(lambda->body, Block)->statements; stmt; stmt = stmt->next) { + if (stmt->next) + (void)compile_statement(tmp_scope, stmt->ast); + else + (void)compile(tmp_scope, stmt->ast); + } CORD userdata; if (Table$length(*fn_ctx.closed_vars) == 0) { @@ -1625,6 +1642,36 @@ 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); + bool is_ptr = Match(field_t, FunctionType)->args->type->tag == PointerType; + return CORD_all("({ ", compile_type(env, self_value_t), " $self = ", + compile_to_pointer_depth(env, methodcall->self, 0, false), "; ", + "$self.", methodcall->name, "(", is_ptr ? CORD_EMPTY : "*", "(", compile_type(env, self_value_t), "*)$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); @@ -1644,10 +1691,29 @@ CORD compile(env_t *env, ast_t *ast) } else if (fn_t->tag == TypeInfoType) { type_t *t = Match(fn_t, TypeInfoType)->type; if (t->tag == StructType) { + // Struct constructor: 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); + CORD c = CORD_all("(", compile_type(env, t), "){", compile(env, impl)); + for (arg_t *field = interface->fields->next; field; field = field->next) { + binding_t *b = get_namespace_binding(env, impl, field->name); + if (!b) code_err(ast, "The type %T doesn't have '%s' for the interface %T", impl_t, field->name, t); + // TODO: typecheck implementation! + c = CORD_all(c, ", (void*)", b->code); + } + return CORD_cat(c, "}"); } else if (t->tag == IntType || t->tag == NumType) { + // Int/Num constructor: if (!call->args || call->args->next) code_err(call->fn, "This constructor takes exactly 1 argument"); type_t *actual = get_type(env, call->args->value); @@ -1816,6 +1882,9 @@ CORD compile(env_t *env, ast_t *ast) } code_err(ast, "There is no '%s' field on tables", f->field); } + case InterfaceType: { + code_err(ast, "Interface field access is not yet implemented"); + } case ModuleType: { const char *name = Match(value_t, ModuleType)->name; env_t *module_env = Table$str_get(*env->imports, name); @@ -1881,7 +1950,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 Skip: case Stop: case Pass: case Return: case DocTest: + case EnumDef: case FunctionDef: case InterfaceDef: 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"); } @@ -1937,6 +2006,10 @@ 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)); |
