aboutsummaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-05-12 13:50:06 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-05-12 13:50:06 -0400
commitd143c72b2267883c229a09cc27bbeafcf2c3fd70 (patch)
tree90312f0e4ee553e0588dc3c45f955b5184bf3778 /compile.c
parenta20f522fd61698282d3e01931260c588dd7f40b1 (diff)
WIP, but functional interfaces
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c85
1 files changed, 79 insertions, 6 deletions
diff --git a/compile.c b/compile.c
index 59ee0b03..88c5a0ba 100644
--- a/compile.c
+++ b/compile.c
@@ -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));