hare

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

commit d50c9aa0b362b20ff49647bd0adfe7f7b0a780f8
parent d6819ca19bed2b349a3356efbaa5bac943ee020b
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu,  2 Sep 2021 15:41:22 +0200

cmd/harec: bindings, part one

Part two will store the initializer

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Acmd/harec/context.ha | 20++++++++++++++++++++
Mcmd/harec/gen.ha | 69+++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mcmd/harec/genutil.ha | 8++++++++
Mcmd/harec/qbe.ha | 48+++++++++++++++++++++++++++++++-----------------
Mhare/unit/expr.ha | 13++++++++++++-
Mhare/unit/process.ha | 35++++++++++++++++++++++++++++++++++-
Mhare/unit/scan.ha | 1+
Mhare/unit/scope.ha | 3++-
8 files changed, 159 insertions(+), 38 deletions(-)

diff --git a/cmd/harec/context.ha b/cmd/harec/context.ha @@ -0,0 +1,20 @@ +use io; +use hare::types; +use hare::unit; + +type context = struct { + out: *io::stream, + store: *types::typestore, + unit: *unit::unit, + arch: struct { + ptr: *qtype, + sz: *qtype, + }, + serial: uint, + bindings: []binding, +}; + +type binding = struct { + object: *unit::object, + name: temporary, +}; diff --git a/cmd/harec/gen.ha b/cmd/harec/gen.ha @@ -7,20 +7,20 @@ use hare::types; use hare::unit; use io; use os; - -type context = struct { - out: *io::stream, - store: *types::typestore, - unit: *unit::unit, - serial: uint, -}; +use strings; fn gen(store: *types::typestore, unit: *unit::unit) void = { + // TODO: context_init let ctx = context { out = bufio::dynamic(io::mode::WRITE), store = store, unit = unit, - serial = 0, + arch = struct { + // TODO: Initialize these properly + ptr: *qtype = &qlong, + sz: *qtype = &qlong, + }, + ... }; defer io::close(ctx.out); for (let i = 0z; i < len(unit.decls); i += 1) match (unit.decls[i].decl) { @@ -69,9 +69,9 @@ fn gen_func(ctx: *context, decl: *unit::decl) void = { const rval = gen_expr(ctx, body); if (!body.terminates) { if (has_rval) { - emit(ctx, void, qinstr::RET, rval); + emit(ctx.out, void, qinstr::RET, rval); } else { - emit(ctx, void, qinstr::RET); + emit(ctx.out, void, qinstr::RET); }; }; @@ -81,13 +81,46 @@ fn gen_func(ctx: *context, decl: *unit::decl) void = { fn gen_expr(ctx: *context, expr: *unit::expr) value = { return match (expr.expr) { - unit::compound_expr => gen_expr_compound(ctx, expr), - unit::constant_expr => gen_expr_const(ctx, expr), - unit::return_expr => gen_expr_return(ctx, expr), + unit::binding_expr => gen_binding(ctx, expr), + unit::compound_expr => gen_compound(ctx, expr), + unit::constant_expr => gen_const(ctx, expr), + unit::return_expr => gen_return(ctx, expr), + }; +}; + +fn gen_expr_at(ctx: *context, expr: *unit::expr, at: value) void = { + match (expr.expr) { + // TODO: Some functions will prefer _at + * => void, }; + const value = gen_expr(ctx, expr); + // TODO: Store +}; + +fn gen_binding(ctx: *context, expr: *unit::expr) value = { + const bindings = expr.expr as unit::binding_expr; + for (let i = 0z; i < len(bindings); i += 1) { + const item = bindings[i]; + const temp = mktemp(ctx); + append(ctx.bindings, binding { + object = item.object, + name = temp, + }); + const value = value { + value = temp, + _type = item.object._type, + }; + // TODO: tuple unpacking + // const lval, instr = allocval(value); + const instr = qinstr_alloc(value._type); + const lval = mklval(ctx, value); + emit(ctx.out, lval, instr, value._type.sz); + gen_expr_at(ctx, item.init, value); + }; + return vvoid; }; -fn gen_expr_compound(ctx: *context, expr: *unit::expr) value = { +fn gen_compound(ctx: *context, expr: *unit::expr) value = { const compound = expr.expr as unit::compound_expr; for (let i = 0z; i < len(compound); i += 1) { gen_expr(ctx, compound[i]); @@ -95,7 +128,7 @@ fn gen_expr_compound(ctx: *context, expr: *unit::expr) value = { return vvoid; // TODO }; -fn gen_expr_const(ctx: *context, expr: *unit::expr) value = { +fn gen_const(ctx: *context, expr: *unit::expr) value = { const constexpr = expr.expr as unit::constant_expr; const val: qval = match (constexpr) { void => return vvoid, @@ -113,12 +146,12 @@ fn gen_expr_const(ctx: *context, expr: *unit::expr) value = { }; }; -fn gen_expr_return(ctx: *context, expr: *unit::expr) value = { +fn gen_return(ctx: *context, expr: *unit::expr) value = { const rexpr = expr.expr as unit::return_expr; match (rexpr) { - null => emit(ctx, void, qinstr::RET), + null => emit(ctx.out, void, qinstr::RET), expr: *unit::expr => { - emit(ctx, void, qinstr::RET, gen_expr(ctx, expr)); + emit(ctx.out, void, qinstr::RET, gen_expr(ctx, expr)); }, }; return vvoid; diff --git a/cmd/harec/genutil.ha b/cmd/harec/genutil.ha @@ -6,3 +6,11 @@ fn mklabel(ctx: *context, name: str) str = { ctx.serial += 1; return fmt::bsprintf(buf, "@{}.{}", name, serial); }; + +fn mktemp(ctx: *context) temporary = { + let serial = ctx.serial; + ctx.serial += 1; + return fmt::asprintf(".{}", serial); +}; + +fn mklval(ctx: *context, val: value) qtypeval = (ctx.arch.ptr, val.value); diff --git a/cmd/harec/qbe.ha b/cmd/harec/qbe.ha @@ -1,4 +1,5 @@ use fmt; +use io; use hare::types; type global = str; @@ -7,6 +8,7 @@ type label = str; type qvoid = void; type constant = (u32 | u64 | f32 | f64 | str | qvoid); type qval = (global | temporary | label | constant); +type qtypeval = (const *qtype, qval); type value = struct { value: qval, @@ -19,19 +21,23 @@ const vvoid: value = value { }; fn emit( - ctx: *context, - out: (value | void), + to: *io::stream, + out: (qtypeval | void), instr: qinstr, args: (value | qval | qtype)... ) void = { - fmt::fprintf(ctx.out, "\t")!; + fmt::fprintf(to, "\t")!; match (out) { - val: value => abort(), // TODO + val: qtypeval => { + const ty = val.0, val = val.1; + qval_emit(to, val); + fmt::fprintf(to, " ={} ", qtype_repr(ty))!; + }, void => void, }; // TODO: The langauge should provide a means of converting enums to // strings without this - fmt::fprint(ctx.out, switch (instr) { + fmt::fprint(to, switch (instr) { qinstr::ADD => "add", qinstr::ALLOC16 => "alloc16", qinstr::ALLOC4 => "alloc4", @@ -125,23 +131,31 @@ fn emit( }; match (arg) { v: value => abort(), // Invariant - qv: qval => match (qv) { - g: global => fmt::fprintf(ctx.out, " ${}", g)!, - t: temporary => fmt::fprintf(ctx.out, " %{}", t)!, - l: label => fmt::fprintf(ctx.out, " @{}", l)!, - c: constant => match (c) { - qvoid => abort(), - v: (u32 | u64 | f32 | f64 | str) => - fmt::fprintf(ctx.out, " {}", v)!, - }, - }, + qv: qval => qval_emit(to, qv), qt: qtype => abort(), // TODO }; if (i + 1 < len(args)) { - fmt::fprint(ctx.out, ",")!; + fmt::fprint(to, ",")!; }; }; - fmt::fprintln(ctx.out)!; + fmt::fprintln(to)!; +}; + +fn qval_emit(to: *io::stream, qv: qval) void = match (qv) { + g: global => fmt::fprintf(to, " ${}", g)!, + t: temporary => fmt::fprintf(to, " %{}", t)!, + l: label => fmt::fprintf(to, " @{}", l)!, + c: constant => match (c) { + qvoid => abort(), + v: (u32 | u64 | f32 | f64 | str) => fmt::fprintf(to, " {}", v)!, + }, +}; + +fn qinstr_alloc(ty: *types::_type) qinstr = switch (ty.align) { + 4 => qinstr::ALLOC4, + 8 => qinstr::ALLOC8, + 16 => qinstr::ALLOC16, + * => abort(), }; type qinstr = enum { diff --git a/hare/unit/expr.ha b/hare/unit/expr.ha @@ -8,9 +8,20 @@ export type expr = struct { end: lex::location, result: const *types::_type, terminates: bool, - expr: (compound_expr | constant_expr | return_expr), + expr: (binding_expr | compound_expr | constant_expr | return_expr), }; +// A single variable biding. +// +// foo: int = bar +export type binding = struct { + object: *object, + init: *expr, +}; + +// A list of variable bindings. +export type binding_expr = []binding; + // A compound expression, i.e. { ... } export type compound_expr = []*expr; diff --git a/hare/unit/process.ha b/hare/unit/process.ha @@ -79,7 +79,7 @@ fn process_expr( ast::assert_expr => abort(), // TODO ast::assign_expr => abort(), // TODO ast::binarithm_expr => abort(), // TODO - ast::binding_expr => abort(), // TODO + ast::binding_expr => process_binding(ctx, expr), ast::break_expr => abort(), // TODO ast::call_expr => abort(), // TODO ast::cast_expr => abort(), // TODO @@ -102,6 +102,39 @@ fn process_expr( ast::unarithm_expr => abort(), // TODO }; +fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = { + const bind = aexpr.expr as ast::binding_expr; + assert(!bind.is_static && !bind.is_const); // TODO + + let bindings: binding_expr = []; + for (let i = 0z; i < len(bind.bindings); i += 1) { + const item = bind.bindings[i]; + const init = process_expr(ctx, item.init)?; + const _type = match (item._type) { + null => abort(), // TODO + ty: *ast::_type => types::lookup(ctx.store, ty)!, + }; + const object = scope_insert(ctx, object { + kind = object_kind::BIND, + ident = ast::ident_dup([item.name]), + name = ast::ident_dup([item.name]), + _type = _type, + ... + }); + append(bindings, binding { + object = object, + init = init, + }); + }; + return alloc(expr { + start = aexpr.start, + end = aexpr.end, + result = &types::builtin_void, + expr = bindings, + ... + }); +}; + fn process_compound(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const compound = aexpr.expr as ast::compound_expr; const scope = scope_push(ctx, scope_class::COMPOUND); diff --git a/hare/unit/scan.ha b/hare/unit/scan.ha @@ -52,4 +52,5 @@ fn scan_func( name = ast::ident_dup(func.ident), _type = fntype, }); + return; }; diff --git a/hare/unit/scope.ha b/hare/unit/scope.ha @@ -59,7 +59,7 @@ fn scope_pop(ctx: *context) *scope = { return scope; }; -fn scope_insert(ctx: *context, obj: object) void = { +fn scope_insert(ctx: *context, obj: object) *object = { const scope = ctx.scope; append(scope.objects, obj); let obj = &scope.objects[len(scope.objects) - 1]; @@ -73,4 +73,5 @@ fn scope_insert(ctx: *context, obj: object) void = { let hash = fnv::sum64(hash); obj.hash = hash; append(scope.hashmap[hash: size % SCOPE_BUCKETS], obj); + return obj; };