commit 2e83970d123e177196e7ea3571f7bcab399a18e8
parent d95cf82bd4fa655b52a5ba526faafd87edbfdfb6
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 22 Aug 2021 11:12:00 +0200
cmd/harec: add bare-bones gen skeleton
We won't have a separate "emit" step for this design.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
3 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/cmd/harec/gen.ha b/cmd/harec/gen.ha
@@ -0,0 +1,70 @@
+use bufio;
+use fmt;
+use hare::module;
+use hare::types;
+use hare::unit;
+use io;
+use os;
+
+type context = struct {
+ out: *io::stream,
+ store: *types::typestore,
+ unit: *unit::unit,
+ serial: uint,
+};
+
+fn gen(store: *types::typestore, unit: *unit::unit) void = {
+ let ctx = context {
+ out = bufio::dynamic(io::mode::WRITE),
+ store = store,
+ unit = unit,
+ serial = 0,
+ };
+ defer io::close(ctx.out);
+ for (let i = 0z; i < len(unit.decls); i += 1) match (unit.decls[i].decl) {
+ func: unit::decl_func => gen_func(&ctx, &unit.decls[i]),
+ * => abort(), // TODO
+ };
+};
+
+fn gen_func(ctx: *context, decl: *unit::decl) void = {
+ // TODO: const fndecl = &decl.decl as *unit::decl_func;
+ const fndecl = decl.decl as unit::decl_func;
+ if (fndecl.body == null) {
+ return; // Prototype
+ };
+ const fntype = fndecl.prototype._type as types::func;
+ assert(fntype.flags == 0);
+ ctx.serial = 0;
+
+ const ident = module::identuscore(fndecl.ident);
+ defer free(ident);
+ fmt::printf("{}function section \".text.{}\" \"ax\"",
+ if (decl.exported) "export " else "", ident)!;
+ const rtype = fntype.result;
+ if (!(rtype._type is types::builtin) ||
+ rtype._type as types::builtin != types::builtin::VOID) {
+ abort(); // TODO: Return type
+ };
+ fmt::printf(" ${}(", ident)!;
+ assert(len(fntype.params) == 0); // TODO
+ fmt::println(") {")!;
+ fmt::println(mklabel(ctx, "start"))!;
+
+ // We use a dynamic buffer here so that we can emit alloc instructions
+ // on-demand at the start of the function, rather than spread out
+ // through the body. This is more reliable on qbe's ARM backend, and
+ // generates better IL besides.
+ bufio::reset(ctx.out);
+
+ fmt::fprintln(ctx.out, mklabel(ctx, "body"))!;
+ gen_expr(ctx, fndecl.body: *unit::expr);
+
+ io::write(os::stdout, bufio::buffer(ctx.out))!;
+ fmt::println("}\n")!;
+};
+
+fn gen_expr(ctx: *context, expr: *unit::expr) void = {
+ // TODO
+ fmt::fprintfln(ctx.out, "\tret")!;
+};
diff --git a/cmd/harec/genutil.ha b/cmd/harec/genutil.ha
@@ -0,0 +1,8 @@
+use fmt;
+
+fn mklabel(ctx: *context, name: str) str = {
+ static let buf: [1024]u8 = [0...];
+ let serial = ctx.serial;
+ ctx.serial += 1;
+ return fmt::bsprintf(buf, "@{}.{}", name, serial);
+};
diff --git a/cmd/harec/main.ha b/cmd/harec/main.ha
@@ -76,4 +76,5 @@ export fn main() void = {
u: unit::unit => u,
};
defer unit::unit_free(unit);
+ gen(store, &unit);
};