aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ast.h2
-rw-r--r--compile.c34
-rw-r--r--enums.c40
-rw-r--r--environment.c23
-rw-r--r--environment.h2
-rw-r--r--parse.c6
-rw-r--r--structs.c40
-rw-r--r--typecheck.c30
8 files changed, 122 insertions, 55 deletions
diff --git a/ast.h b/ast.h
index b80aeb61..93d279d7 100644
--- a/ast.h
+++ b/ast.h
@@ -179,7 +179,7 @@ struct ast_s {
type_ast_t *ret_type;
ast_t *body;
ast_t *cache;
- bool is_inline;
+ bool is_inline, is_private;
} FunctionDef;
struct {
arg_ast_t *args;
diff --git a/compile.c b/compile.c
index 115ac701..67aa8d71 100644
--- a/compile.c
+++ b/compile.c
@@ -578,40 +578,38 @@ CORD compile(env_t *env, ast_t *ast)
return CORD_cat(code, ")");
}
- // Table, TableEntry,
case FunctionDef: {
auto fndef = Match(ast, FunctionDef);
CORD name = compile(env, fndef->name);
- CORD_appendf(&env->code->staticdefs, "static %r %r_(", fndef->ret_type ? compile_type_ast(fndef->ret_type) : "void", name);
+ CORD signature = CORD_all(fndef->ret_type ? compile_type_ast(fndef->ret_type) : "void", " ", name, "(");
for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) {
type_t *arg_type = get_arg_ast_type(env, arg);
- CORD_appendf(&env->code->staticdefs, "%r %s", compile_type(arg_type), arg->name);
- if (arg->next) env->code->staticdefs = CORD_cat(env->code->staticdefs, ", ");
+ CORD_appendf(&signature, "%r %s", compile_type(arg_type), arg->name);
+ if (arg->next) signature = CORD_cat(signature, ", ");
}
- env->code->staticdefs = CORD_cat(env->code->staticdefs, ");\n");
+ signature = CORD_cat(signature, ")");
+ if (fndef->is_private)
+ env->code->staticdefs = CORD_all(env->code->staticdefs, "static ", signature, ";\n");
+ else
+ env->code->fndefs = CORD_all(env->code->fndefs, signature, ";\n");
+
+ CORD code = signature;
+ if (fndef->is_inline)
+ code = CORD_cat("inline ", code);
+ if (!fndef->is_private)
+ code = CORD_cat("public ", code);
- CORD kwargs = CORD_asprintf("#define %r(...) ({ struct {", name);
- CORD passed_args = CORD_EMPTY;
- CORD_appendf(&env->code->funcs, "%r %r_(", fndef->ret_type ? compile_type_ast(fndef->ret_type) : "void", name);
env_t *body_scope = fresh_scope(env);
body_scope->locals->fallback = env->globals;
for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) {
type_t *arg_type = get_arg_ast_type(env, arg);
- CORD arg_typecode = compile_type(arg_type);
- CORD_appendf(&env->code->funcs, "%r %s", arg_typecode, arg->name);
- if (arg->next) env->code->funcs = CORD_cat(env->code->funcs, ", ");
- CORD_appendf(&kwargs, "%r %s; ", arg_typecode, arg->name);
- CORD_appendf(&passed_args, "$args.%s", arg->name);
- if (arg->next) passed_args = CORD_cat(passed_args, ", ");
- set_binding(body_scope, arg->name, new(binding_t, .type=arg_type));
+ set_binding(body_scope, arg->name, new(binding_t, .type=arg_type, .code=arg->name));
}
- CORD_appendf(&kwargs, "} $args = {__VA_ARGS__}; %r_(%r); })\n", name, passed_args);
- CORD_appendf(&env->code->staticdefs, "%r", kwargs);
CORD body = compile(body_scope, fndef->body);
if (CORD_fetch(body, 0) != '{')
body = CORD_asprintf("{\n%r\n}", body);
- CORD_appendf(&env->code->funcs, ") %r", body);
+ env->code->funcs = CORD_all(env->code->funcs, code, " ", body);
return CORD_EMPTY;
}
case FunctionCall: case MethodCall: {
diff --git a/enums.c b/enums.c
index caa64018..684eb7f7 100644
--- a/enums.c
+++ b/enums.c
@@ -15,7 +15,7 @@
static CORD compile_str_method(env_t *env, ast_t *ast)
{
auto def = Match(ast, EnumDef);
- CORD str_func = CORD_all("static CORD ", def->name, "__as_text(", def->name, "_t *obj, bool use_color) {\n"
+ CORD str_func = CORD_all("static CORD ", def->name, "$as_text(", def->name, "_t *obj, bool use_color) {\n"
"\tif (!obj) return \"", def->name, "\";\n"
"switch (obj->$tag) {\n");
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
@@ -42,7 +42,7 @@ static CORD compile_str_method(env_t *env, ast_t *ast)
static CORD compile_compare_method(env_t *env, ast_t *ast)
{
auto def = Match(ast, EnumDef);
- CORD cmp_func = CORD_all("static int ", def->name, "__compare(const ", def->name, "_t *x, const ", def->name,
+ CORD cmp_func = CORD_all("static int ", def->name, "$compare(const ", def->name, "_t *x, const ", def->name,
"_t *y, const TypeInfo *info) {\n"
"(void)info;\n"
"int diff = x->$tag - y->$tag;\n"
@@ -60,7 +60,7 @@ static CORD compile_compare_method(env_t *env, ast_t *ast)
static CORD compile_equals_method(env_t *env, ast_t *ast)
{
auto def = Match(ast, EnumDef);
- CORD eq_func = CORD_all("static bool ", def->name, "__equal(const ", def->name, "_t *x, const ", def->name,
+ CORD eq_func = CORD_all("static bool ", def->name, "$equal(const ", def->name, "_t *x, const ", def->name,
"_t *y, const TypeInfo *info) {\n"
"(void)info;\n"
"if (x->$tag != y->$tag) return no;\n"
@@ -77,7 +77,7 @@ static CORD compile_equals_method(env_t *env, ast_t *ast)
static CORD compile_hash_method(env_t *env, ast_t *ast)
{
auto def = Match(ast, EnumDef);
- CORD hash_func = CORD_all("static uint32_t ", def->name, "__hash(const ", def->name, "_t *obj, const TypeInfo *info) {\n"
+ CORD hash_func = CORD_all("static uint32_t ", def->name, "$hash(const ", def->name, "_t *obj, const TypeInfo *info) {\n"
"(void)info;\n"
"uint32_t hashes[2] = {(uint32_t)obj->$tag};\n"
"switch (obj->$tag) {\n");
@@ -143,12 +143,36 @@ void compile_enum_def(env_t *env, ast_t *ast)
compile_hash_method(env, ast));
typeinfo = CORD_all(
typeinfo,
- ".as_text=(void*)", def->name, "__as_text, "
- ".equal=(void*)", def->name, "__equal, "
- ".hash=(void*)", def->name, "__hash, "
- ".compare=(void*)", def->name, "__compare");
+ ".as_text=(void*)", def->name, "$as_text, "
+ ".equal=(void*)", def->name, "$equal, "
+ ".hash=(void*)", def->name, "$hash, "
+ ".compare=(void*)", def->name, "$compare");
typeinfo = CORD_cat(typeinfo, "}}};\n");
env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo);
+
+ env_t *ns_env = namespace_env(env, def->name);
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
+ ast_t *ast = stmt->ast;
+ switch (ast->tag) {
+ case FunctionDef:
+ CORD code = compile_statement(ns_env, ast);
+ env->code->funcs = CORD_cat(env->code->funcs, code);
+ break;
+ case Declare: {
+ CORD code = compile_statement(ns_env, ast);
+ env->code->staticdefs = CORD_cat(env->code->staticdefs, code);
+ auto decl = Match(ast, Declare);
+ type_t *t = get_type(ns_env, decl->value);
+ env->code->fndefs = CORD_all(env->code->fndefs, "extern ", compile_type(t), " ", compile(ns_env, decl->var), ";\n");
+ break;
+ }
+ default: {
+ CORD code = compile_statement(ns_env, ast);
+ env->code->main = CORD_cat(env->code->main, code);
+ break;
+ }
+ }
+ }
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/environment.c b/environment.c
index 483f123f..be04f0a6 100644
--- a/environment.c
+++ b/environment.c
@@ -197,6 +197,19 @@ env_t *fresh_scope(env_t *env)
return scope;
}
+env_t *namespace_env(env_t *env, const char *namespace_name)
+{
+ env_t *ns_env = new(env_t);
+ *ns_env = *env;
+ ns_env->locals = Table_str_get(env->type_namespaces, namespace_name);
+ if (!ns_env->locals) {
+ ns_env->locals = new(table_t, .fallback=env->globals);
+ Table_str_set(env->type_namespaces, namespace_name, ns_env->locals);
+ }
+ ns_env->scope_prefix = CORD_cat(namespace_name, "$");
+ return ns_env;
+}
+
binding_t *get_binding(env_t *env, const char *name)
{
return Table_str_get(env->locals, name);
@@ -223,15 +236,15 @@ binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name)
return Table_str_get(ns, name);
}
case TypeInfoType: case StructType: case EnumType: {
- const char *name;
+ const char *type_name;
switch (cls_type->tag) {
- case TypeInfoType: name = Match(cls_type, TypeInfoType)->name; break;
- case StructType: name = Match(cls_type, StructType)->name; break;
- case EnumType: name = Match(cls_type, EnumType)->name; break;
+ case TypeInfoType: type_name = Match(cls_type, TypeInfoType)->name; break;
+ case StructType: type_name = Match(cls_type, StructType)->name; break;
+ case EnumType: type_name = Match(cls_type, EnumType)->name; break;
default: errx(1, "Unreachable");
}
- table_t *namespace = Table_str_get(env->type_namespaces, name);
+ table_t *namespace = Table_str_get(env->type_namespaces, type_name);
if (!namespace) return NULL;
return Table_str_get(namespace, name);
}
diff --git a/environment.h b/environment.h
index 47d1dea2..8660fe68 100644
--- a/environment.h
+++ b/environment.h
@@ -20,6 +20,7 @@ typedef struct {
table_t *types, *globals, *locals;
table_t *type_namespaces; // Map of type name -> namespace table
compilation_unit_t *code;
+ CORD scope_prefix;
} env_t;
typedef struct {
@@ -29,6 +30,7 @@ typedef struct {
env_t *new_compilation_unit(void);
env_t *fresh_scope(env_t *env);
+env_t *namespace_env(env_t *env, const char *namespace_name);
__attribute__((noreturn))
void compiler_err(file_t *f, const char *start, const char *end, const char *fmt, ...);
binding_t *get_binding(env_t *env, const char *name);
diff --git a/parse.c b/parse.c
index 0b1ebd6d..5d1bcb20 100644
--- a/parse.c
+++ b/parse.c
@@ -1708,7 +1708,7 @@ PARSER(parse_func_def) {
arg_ast_t *args = parse_args(ctx, &pos, false);
whitespace(&pos);
- bool is_inline = false;
+ bool is_inline = false, is_private = false;
ast_t *cache_ast = NULL;
for (bool specials = match(&pos, ";"); specials; specials = match_separator(&pos)) {
const char *flag_start = pos;
@@ -1721,6 +1721,8 @@ PARSER(parse_func_def) {
parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'");
whitespace(&pos);
cache_ast = expect(ctx, start, &pos, parse_expr, "I expected a maximum size for the cache");
+ } else if (match_word(&pos, "private")) {
+ is_private = true;
}
}
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function definition");
@@ -1734,7 +1736,7 @@ PARSER(parse_func_def) {
"This function needs a body block");
return NewAST(ctx->file, start, pos, FunctionDef,
.name=name, .args=args, .ret_type=ret_type, .body=body, .cache=cache_ast,
- .is_inline=is_inline);
+ .is_inline=is_inline, .is_private=is_private);
}
PARSER(parse_extern) {
diff --git a/structs.c b/structs.c
index de2cf806..970fc8ca 100644
--- a/structs.c
+++ b/structs.c
@@ -38,7 +38,7 @@ static bool is_plain_data(env_t *env, type_t *t)
static CORD compile_str_method(env_t *env, ast_t *ast)
{
auto def = Match(ast, StructDef);
- CORD str_func = CORD_asprintf("static CORD %s__as_text(%s_t *obj, bool use_color) {\n"
+ CORD str_func = CORD_asprintf("static CORD %s$as_text(%s_t *obj, bool use_color) {\n"
"\tif (!obj) return \"%s\";\n", def->name, def->name, def->name);
if (def->secret) {
CORD_appendf(&str_func, "\treturn use_color ? \"\\x1b[0;1m%s\\x1b[m(\\x1b[2m...\\x1b[m)\" : \"%s(...)\";\n}",
@@ -59,7 +59,7 @@ static CORD compile_str_method(env_t *env, ast_t *ast)
static CORD compile_compare_method(env_t *env, ast_t *ast)
{
auto def = Match(ast, StructDef);
- CORD cmp_func = CORD_all("static int ", def->name, "__compare(const ", def->name, "_t *x, const ", def->name,
+ CORD cmp_func = CORD_all("static int ", def->name, "$compare(const ", def->name, "_t *x, const ", def->name,
"_t *y, const TypeInfo *info) {\n"
"(void)info;\n",
"int diff;\n");
@@ -86,7 +86,7 @@ static CORD compile_compare_method(env_t *env, ast_t *ast)
static CORD compile_equals_method(env_t *env, ast_t *ast)
{
auto def = Match(ast, StructDef);
- CORD eq_func = CORD_all("static bool ", def->name, "__equal(const ", def->name, "_t *x, const ", def->name,
+ CORD eq_func = CORD_all("static bool ", def->name, "$equal(const ", def->name, "_t *x, const ", def->name,
"_t *y, const TypeInfo *info) {\n"
"(void)info;\n");
for (arg_ast_t *field = def->fields; field; field = field->next) {
@@ -111,7 +111,7 @@ static CORD compile_equals_method(env_t *env, ast_t *ast)
static CORD compile_hash_method(env_t *env, ast_t *ast)
{
auto def = Match(ast, StructDef);
- CORD hash_func = CORD_all("static uint32_t ", def->name, "__hash(const ", def->name, "_t *obj, const TypeInfo *info) {\n"
+ CORD hash_func = CORD_all("static uint32_t ", def->name, "$hash(const ", def->name, "_t *obj, const TypeInfo *info) {\n"
"(void)info;\n"
"uint32_t field_hashes[] = {");
for (arg_ast_t *field = def->fields; field; field = field->next) {
@@ -146,7 +146,7 @@ void compile_struct_def(env_t *env, ast_t *ast)
CORD typeinfo = CORD_asprintf("public const TypeInfo %s = {%zu, %zu, {.tag=CustomInfo, .CustomInfo={",
def->name, type_size(t), type_align(t));
- typeinfo = CORD_all(typeinfo, ".as_text=(void*)", def->name, "__as_text, ");
+ typeinfo = CORD_all(typeinfo, ".as_text=(void*)", def->name, "$as_text, ");
env->code->funcs = CORD_all(env->code->funcs, compile_str_method(env, ast));
if (!t || !is_plain_data(env, t)) {
env->code->funcs = CORD_all(
@@ -154,12 +154,36 @@ void compile_struct_def(env_t *env, ast_t *ast)
compile_hash_method(env, ast));
typeinfo = CORD_all(
typeinfo,
- ".equal=(void*)", def->name, "__equal, "
- ".hash=(void*)", def->name, "__hash, "
- ".compare=(void*)", def->name, "__compare");
+ ".equal=(void*)", def->name, "$equal, "
+ ".hash=(void*)", def->name, "$hash, "
+ ".compare=(void*)", def->name, "$compare");
}
typeinfo = CORD_cat(typeinfo, "}}};\n");
env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo);
+
+ env_t *ns_env = namespace_env(env, def->name);
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
+ ast_t *ast = stmt->ast;
+ switch (ast->tag) {
+ case FunctionDef:
+ CORD code = compile_statement(ns_env, ast);
+ env->code->funcs = CORD_cat(env->code->funcs, code);
+ break;
+ case Declare: {
+ CORD code = compile_statement(ns_env, ast);
+ env->code->staticdefs = CORD_cat(env->code->staticdefs, code);
+ auto decl = Match(ast, Declare);
+ type_t *t = get_type(ns_env, decl->value);
+ env->code->fndefs = CORD_all(env->code->fndefs, "extern ", compile_type(t), " ", compile(ns_env, decl->var), ";\n");
+ break;
+ }
+ default: {
+ CORD code = compile_statement(ns_env, ast);
+ env->code->main = CORD_cat(env->code->main, code);
+ break;
+ }
+ }
+ }
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/typecheck.c b/typecheck.c
index 75417e63..eb510264 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -99,20 +99,23 @@ void bind_statement(env_t *env, ast_t *statement)
case Declare: {
auto decl = Match(statement, Declare);
type_t *type = get_type(env, decl->value);
- set_binding(env, Match(decl->var, Var)->name, new(binding_t, .type=type));
+ const char *name = Match(decl->var, Var)->name;
+ CORD code = CORD_cat(env->scope_prefix, name);
+ set_binding(env, name, new(binding_t, .type=type, .code=code));
break;
}
case FunctionDef: {
auto def = Match(statement, FunctionDef);
type_t *type = get_function_def_type(env, statement);
- set_binding(env, Match(def->name, Var)->name, new(binding_t, .type=type));
+ const char *name = Match(def->name, Var)->name;
+ CORD code = CORD_all(env->scope_prefix, name);
+ set_binding(env, name, new(binding_t, .type=type, .code=code));
break;
}
case StructDef: {
auto def = Match(statement, StructDef);
- table_t *namespace = new(table_t);
- Table_str_set(env->type_namespaces, def->name, namespace);
+ env_t *ns_env = namespace_env(env, def->name);
arg_t *fields = NULL;
type_t *type = Type(StructType, .name=def->name, .fields=fields); // placeholder
@@ -124,7 +127,9 @@ void bind_statement(env_t *env, ast_t *statement)
type->__data.StructType.fields = fields; // populate placeholder
Table_str_set(env->types, def->name, type);
- // TODO: bind body members
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
+ bind_statement(ns_env, stmt->ast);
+ }
type_t *typeinfo_type = Type(TypeInfoType, .name=def->name, .type=type);
Table_str_set(env->globals, def->name, new(binding_t, .type=typeinfo_type));
@@ -133,8 +138,7 @@ void bind_statement(env_t *env, ast_t *statement)
case EnumDef: {
auto def = Match(statement, EnumDef);
- table_t *namespace = new(table_t);
- Table_str_set(env->type_namespaces, def->name, namespace);
+ env_t *ns_env = namespace_env(env, def->name);
tag_t *tags = NULL;
type_t *type = Type(EnumType, .name=def->name, .tags=tags); // placeholder
@@ -153,7 +157,7 @@ void bind_statement(env_t *env, ast_t *statement)
for (tag_t *tag = tags; tag; tag = tag->next) {
type_t *constructor_t = Type(FunctionType, .args=Match(tag->type, StructType)->fields, .ret=type);
- Table_str_set(namespace, tag->name, new(binding_t, .type=constructor_t, .code=CORD_all(def->name, "$tagged$", tag->name)));
+ set_binding(ns_env, tag->name, new(binding_t, .type=constructor_t, .code=CORD_all(def->name, "$tagged$", tag->name)));
Table_str_set(env->types, heap_strf("%s$%s", def->name, tag->name), tag->type);
}
Table_str_set(env->types, def->name, type);
@@ -161,7 +165,10 @@ void bind_statement(env_t *env, ast_t *statement)
type_t *typeinfo_type = Type(TypeInfoType, .name=def->name, .type=type);
Table_str_set(env->globals, def->name, new(binding_t, .type=typeinfo_type));
- // TODO: bind body members
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
+ bind_statement(ns_env, stmt->ast);
+ }
+
break;
}
default: break;
@@ -188,9 +195,6 @@ type_t *get_function_def_type(env_t *env, ast_t *ast)
type_t *get_method_type(env_t *env, ast_t *self, const char *name)
{
- type_t *self_type = get_type(env, self);
- if (!self_type)
- code_err(self, "I couldn't get this type");
binding_t *b = get_namespace_binding(env, self, name);
if (!b || !b->type)
code_err(self, "No such method: %s", name);
@@ -395,7 +399,7 @@ type_t *get_type(env_t *env, ast_t *ast)
if (!fn_type_t)
code_err(ast, "No such method!");
if (fn_type_t->tag != FunctionType)
- code_err(ast, "This isn't a function, it's a %T", fn_type_t);
+ code_err(ast, "This isn't a method, it's a %T", fn_type_t);
auto fn_type = Match(fn_type_t, FunctionType);
return fn_type->ret;
}