diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-03-04 13:51:47 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-03-04 13:51:47 -0500 |
| commit | e29aa52460df6a5d3e78f7e466947bcdd7a3bbb0 (patch) | |
| tree | c0225e0db0d0e49e9ffe7e0e94e19ec067d98a8a | |
| parent | 0b7ca098ae1dc5e31485bc505a441d3796f0702b (diff) | |
Struct and enum methods and static members
| -rw-r--r-- | ast.h | 2 | ||||
| -rw-r--r-- | compile.c | 34 | ||||
| -rw-r--r-- | enums.c | 40 | ||||
| -rw-r--r-- | environment.c | 23 | ||||
| -rw-r--r-- | environment.h | 2 | ||||
| -rw-r--r-- | parse.c | 6 | ||||
| -rw-r--r-- | structs.c | 40 | ||||
| -rw-r--r-- | typecheck.c | 30 |
8 files changed, 122 insertions, 55 deletions
@@ -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; @@ -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: { @@ -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); @@ -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) { @@ -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; } |
