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:
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;
};