hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Acmd/harec/gen.ha | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acmd/harec/genutil.ha | 8++++++++
Mcmd/harec/main.ha | 1+
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); };