aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-22 17:47:02 +0200
committerlemon <lsof@mailbox.org>2022-08-22 17:47:02 +0200
commitd74ed7fb65bf7ac245d2548ac13f3f3fdabadd16 (patch)
tree7d98ba2472073d5414d51651742911993b5fbf81 /src
parente0686f7953bbc74ff03a7a6b22c0b82995ab494e (diff)
llvm hello worlding
Diffstat (limited to 'src')
-rw-r--r--src/cffc.hff7
-rw-r--r--src/llvm.cff514
-rw-r--r--src/main.cff6
-rw-r--r--src/map.hff12
-rw-r--r--src/parse.cff20
-rw-r--r--src/set.hff12
-rw-r--r--src/type.cff11
7 files changed, 569 insertions, 13 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index 2504fba..f78c61c 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -286,6 +286,7 @@ struct Decl {
name *const u8,
loc Loc,
externp bool,
+ toplevel bool,
u enum union {
Let Var,
Static Var,
@@ -436,6 +437,7 @@ fn isnumtype(ty *const Type) bool {
return ty->is(:Int) or ty->is(:Flo) or (ty->is(:Enum) and ty.u.Enum.lax);
}
extern fn typeof2(a *const Type, b *const Type) *const Type;
+extern fn types_to_llvm() void;
// env.cff
extern fn mkenv(parent *Env, alloc *Allocator) *Env;
@@ -459,4 +461,7 @@ extern static g_asmbackend Backend;
// llvm.cff
extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void;
-extern fn llvm_init() void;
+extern fn llvm_addfn(*Decl) void;
+extern fn llvm_addtype(*const Type) void;
+extern fn llvm_init(*FILE) void;
+extern fn llvm_fini() void;
diff --git a/src/llvm.cff b/src/llvm.cff
new file mode 100644
index 0000000..b839f09
--- /dev/null
+++ b/src/llvm.cff
@@ -0,0 +1,514 @@
+import "cffc.hff";
+import "common.hff";
+import "vec.hff";
+import "map.hff";
+
+static outfp *FILE = {};
+
+struct Value {
+ ty *const Type,
+ u enum union {
+ IImm i64,
+ FImm f64,
+ BImm bool,
+ Null,
+ ZeroIni,
+ StrLit [#]const u8,
+ StrConstRef int,
+ Tmp int,
+ LocalRef *Var,
+ GlobalRef *Var,
+ Fn *Fn,
+ }
+}
+
+static ty_i1 *Type = as(*void)&outfp; // dummy
+
+fn gen(fmt *const u8, ...) void;
+fn gen(fmt *const u8, ...) void {
+ let ap va_list #?;
+ ap->start(fmt);
+
+ fn pritype(ty *const Type) void {
+ if ty == ty_i1 {
+ gen("i1");
+ return;
+ }
+ switch ty.u {
+ case Void; gen("void");
+ case Bool; gen("i%z", ty.size*8);
+ case Int; gen("i%z", ty.size*8);
+ case Flo; gen(ty.size == 4 ? "float" : "double");
+ case Ptr p; gen("%t*", p->is(:Void) ? ty_i8 : p);
+ case Slice p; gen("{ %t*, %t }", p, ty_usize);
+ case Arr arr; gen("[%z x %t]", arr.length, arr.child);
+ case Agg agg; gen("%%%s.%d", agg.name ?? as(*const u8)"_", agg.id);
+ case Enum enu; pritype(enu.intty);
+ case Fn f;
+ gen("%t(", f.ret);
+ foreach(ty, i, f.params) {
+ gen("%t", ty);
+ if i < f.params.#len - 1 {
+ gen(", ");
+ } else if f.variadic {
+ gen(", ...");
+ }
+ }
+ gen(") ");
+ }
+ }
+
+ for let c = *fmt; c != 0; c = *++fmt {
+ if c != '%' {
+ fputc(c, outfp);
+ continue;
+ }
+ switch c = *++fmt {
+ case '%';
+ fprintf(outfp, "%%");
+ case 'c';
+ fprintf(outfp, "%c", ap->arg(int));
+ case 's';
+ fprintf(outfp, "%s", ap->arg(*const u8));
+ case 'S';
+ let str = ap->arg([#]const u8);
+ fputc('"', outfp);
+ foreach(c, _, str) {
+ extern fn isprint(int) int;
+ if isprint(c) == 0 {
+ fprintf(outfp, "\\%.2X", c);
+ } else {
+ fputc(c, outfp);
+ }
+ }
+ fprintf(outfp, "\\00\"");
+ case 'd';
+ fprintf(outfp, "%d", ap->arg(int));
+ case 'I';
+ fprintf(outfp, "%lld", as(c_llong)ap->arg(i64));
+ case 'f';
+ fprintf(outfp, "%.17f", ap->arg(f64));
+ case 'z';
+ fprintf(outfp, "%zu", ap->arg(usize));
+ case 'v';
+ switch ap->arg(Value).u {
+ case IImm i; gen("%I", i);
+ case FImm f; gen("%f", f);
+ case BImm b; gen("%s", b ? "true" : "false");
+ case Null; gen("null");
+ case ZeroIni; gen("zeroinitializer");
+ case Tmp t; fprintf(outfp, "%%t%d", t);
+ case LocalRef var; gen("%%%s.%d", container_of(var, Decl, u.Let).name, var.id);
+ case Fn f;
+ let decl = container_of(f, Decl, u.Fn);
+ if !decl.externp {
+ gen("@%s.%d", decl.name, f.id);
+ } else {
+ gen("@%s", decl.name);
+ }
+ case GlobalRef v;
+ let decl = container_of(v, Decl, u.Static);
+ if !decl.externp {
+ gen("@%s.%d", decl.name, v.id);
+ } else {
+ gen("@%s", decl.name);
+ }
+ case StrConstRef id;
+ gen("@.str.%d", id);
+
+ }
+ case 't';
+ pritype(ap->arg(*Type));
+
+ case else
+ assert(#f, "bad fmt '%c'", c);
+ }
+ }
+ ap->end();
+}
+
+static tmpid int = 1;
+
+fn genexpr(f *Fn, ex *Expr) Value;
+static arena Arena = {};
+static alloc Allocator = {};
+static strs Vec<[#]const u8> = {};
+
+fn genaddr(f *Fn, e *Expr) Value {
+ switch e.u {
+ case StrLit s;
+ let p *u8 = alloc->alloc(s.#len + 1, 1);
+ memcpy(p, s.#ptr, s.#len + 1);
+ let s = p[0::s.#len];
+ strs->push(s);
+ return {mkptrtype(e.ty), :StrConstRef(strs.len - 1)};
+ case else
+ assert(#f, "genaddr");
+ }
+}
+
+fn convert(f *Fn, to *const Type, ex *Expr) Value {
+ let from = ex.ty;
+
+ defmacro cvt(inst) [
+ (do let t = Value{to, :Tmp(tmpid++)},
+ val = genexpr(f, ex);
+ gen("\t%v = %s %t %v to %t\n", t, inst, from, val, to);
+ t;
+ )
+ ]
+
+ switch {
+ case from == to;
+ return genexpr(f, ex);
+
+ case to->is(:Int) and from->is(:Int) and to.size == from.size and to.u.Int.sgn != from.u.Int.sgn;
+ return genexpr(f, ex);
+
+ case to->is(:Int) and from->is(:Int) and to.size == from.size;
+ return cvt("bitcast");
+
+ case to->is(:Int) and from->is(:Int) and to.size < from.size;
+ return cvt("trunc");
+
+ case to->is(:Int) and from->is(:Int) and to.size > from.size;
+ return cvt(from.u.Int.sgn ? "sext" : "zext");
+
+ case to->is(:Int) and from->is(:Int) and to.size < from.size;
+ return cvt("trunc");
+
+ case to->is(:Int) and from->is(:Int) and to.size > from.size;
+ return cvt(from.u.Int.sgn ? "sext" : "zext");
+
+ case to->is(:Flo) and from->is(:Flo) and to.size == from.size;
+ return genexpr(f, ex);
+
+ case to->is(:Flo) and from->is(:Flo) and to.size > from.size;
+ return cvt("fpext");
+
+ case to->is(:Flo) and from->is(:Flo) and to.size < from.size;
+ return cvt("fptrunc");
+
+ case to->is(:Ptr) and from->is(:Arr);
+ let addr = genaddr(f, ex);
+ let t = Value{ex.ty, :Tmp(tmpid++)};
+ gen("\t%v = getelementptr %t, %t %v, %t 0, %t 0\n", t, addr.ty.u.Ptr, addr.ty, addr,
+ ty_usize, ty_usize);
+ return t;
+ case else
+ assert(#f, "convert");
+ }
+}
+
+fn genblock(f *Fn, block [#]Stmt) void;
+
+fn genexpr(f *Fn, ex *Expr) Value {
+ fold(ex);
+ switch ex.u {
+ case IntLit i; return {ex.ty, :IImm(i.i)};
+ case FloLit f; return {ex.ty, :FImm(f)};
+ case BoolLit b; return {ex.ty, :BImm(b)};
+ case NullLit; return {ex.ty, :Null};
+ case ZeroIni; return {ex.ty, :ZeroIni};
+ case StrLit s; return {ex.ty, :StrLit(s)};
+ case BinOp b;
+ defmacro genbinop(inst) [ {
+ let lhs = convert(f, ex.ty, b.lhs),
+ rhs = convert(f, ex.ty, b.rhs),
+ t = Value{ex.ty, :Tmp(tmpid++)};
+ gen("\t%v = %s %t %v, %v\n", t, inst, ex.ty, lhs, rhs);
+ return t;
+ } ]
+ let ty2 = typeof2(b.lhs.ty, b.rhs.ty);
+ defmacro gencmp(op) [ {
+ let lhs = convert(f, ty2, b.lhs),
+ rhs = convert(f, ty2, b.rhs),
+ t0 = Value{ex.ty, :Tmp(tmpid++)},
+ t1 = Value{ex.ty, :Tmp(tmpid++)};
+ gen("\t%v = %s %s %t %v, %v\n", t0, ty2->is(:Flo) ? "fcmp" : "icmp", op,
+ ty2, lhs, rhs);
+ gen("\t%v = zext i1 %v to %t\n", t1, t0, ex.ty);
+ return t1;
+ } ]
+ switch b.op {
+ case '+';
+ // TODO ptr arithmetic
+ genbinop(!ex.ty->is(:Flo) ? "add" : "fadd");
+ case '-';
+ genbinop(!ex.ty->is(:Flo) ? "sub" : "fsub");
+ case '*'; genbinop(!ex.ty->is(:Flo) ? "mul" : "fmul");
+ case '/'; genbinop(ex.ty->is(:Flo) ? "fdiv" : ex.ty.u.Int.sgn ? "sdiv" : "udiv");
+ case '%'; genbinop(ex.ty.u.Int.sgn ? "srem" : "urem");
+ case '&'; genbinop("and");
+ case '|'; genbinop("or");
+ case '^'; genbinop("or");
+ case '<<'; genbinop("shl");
+ case '>>'; genbinop(ex.ty.u.Int.sgn ? "ashr" : "lshr");
+ case '=='; gencmp("eq");
+ case '<'; gencmp(ty2->is(:Flo) ? "olt" : ty2.u.Int.sgn ? "slt" : "ult");
+ case '<='; gencmp(ty2->is(:Flo) ? "ole" : ty2.u.Int.sgn ? "sle" : "ule");
+ case '>'; gencmp(ty2->is(:Flo) ? "ogt" : ty2.u.Int.sgn ? "sgt" : "ugt");
+ case '>='; gencmp(ty2->is(:Flo) ? "oge" : ty2.u.Int.sgn ? "sge" : "uge");
+ case else
+ assert(#f, "binop? %d", b.op);
+ }
+ case UnOp op;
+
+ case Symbol decl;
+ switch decl.u {
+ case Let *var;
+ let t = Value{ex.ty, :Tmp(tmpid++)};
+ gen("\t%v = load %t, %t* %%%s.%d\n", t, ex.ty, ex.ty, decl.name, var.id);
+ return t;
+ case Static *var;
+ let t = Value{ex.ty, :Tmp(tmpid++)};
+ if decl.externp {
+ gen("\t%v = load %t, %t* @%s\n", t, ex.ty, ex.ty, decl.name);
+ } else {
+ gen("\t%v = load %t, %t* @%s.%d\n", t, ex.ty, ex.ty, decl.name, var.id);
+ }
+ return t;
+ case Fn *f;
+ return {ex.ty, :Fn(f)};
+ case else
+ assert(#f, "decl");
+ }
+ case Call call;
+ let lhs = genexpr(f, call.lhs);
+ let fnty = &(lhs.ty->is(:Ptr) ? lhs.ty.u.Ptr : lhs.ty).u.Fn;
+ let args *Value = xcalloc(call.args.#len, sizeof Value);
+ defer free(args);
+ foreach_ptr(arg, i, call.args) {
+ let ty = i < fnty.params.#len ? fnty.params[i] : typeof2(arg.ty, arg.ty);
+ args[i] = convert(f, ty, arg);
+ }
+ let t = Value{ex.ty, :Tmp(tmpid++)};
+ gen("\t%v = call %t %v(", t, call.lhs.ty, lhs);
+ foreach_ptr(arg, i, call.args) {
+ let ty = i < fnty.params.#len ? fnty.params[i] : typeof2(arg.ty, arg.ty);
+ gen("%t %v", ty, args[i]);
+ if i < call.args.#len - 1 {
+ gen(", ");
+ }
+ }
+ gen(")\n");
+ return t;
+
+ case else
+ assert(#f, "expr? %d", ex.u.#tag);
+ }
+}
+
+fn llvmbool(f *Fn, ex *Expr) Value {
+ let v = genexpr(f, ex);
+ let t = Value{ty_i1, :Tmp(tmpid++)};
+ if v.ty->is(:Bool) or v.ty->is(:Int) {
+ gen("\t%v = icmp ne %t %v, 0\n", t, v.ty, v);
+ } else {
+ gen("\t%v = icmp ne %t %v, null\n", t, v.ty, v);
+ }
+ return t;
+}
+
+fn nop() void {
+ gen("\t%%t%d = bitcast i8 0 to i8 ; NOP\n", tmpid++);
+}
+
+fn genstmt(f *Fn, st *Stmt) void {
+ switch st.u {
+ case Expr *e;
+ genexpr(f, e);
+
+ case Decl decl;
+ switch decl.u {
+ case Let var;
+ let nam = decl.name,
+ ty = var.ty;
+ gen("\t%%%s.%d = alloca %t\n", nam, var.id, ty);
+ if !var.ini->empty() {
+ gen("\tstore %t %v, %t* %%%s.%d\n",
+ ty, convert(f, ty, &var.ini.Some), ty, nam, var.id);
+ }
+ }
+ case If *cnd;
+ static ifid int = {};
+ let id = ifid++;
+ gen("\tbr i1 %v, label %%IfT%d, label %%IfF%d\n",
+ llvmbool(f, &cnd.test), id, id);
+ gen("IfT%d:", id);
+ nop();
+ genblock(f, cnd.t);
+ if cnd.f.#ptr {
+ gen("\tbr label %%IfSk%d\n", id);
+ }
+ gen("IfF%d:", id);
+ nop();
+ genblock(f, cnd.f);
+ if cnd.f.#ptr {
+ gen("IfSk%d:", id);
+ nop();
+ }
+ case While loop;
+ gen("Cont%d:", loop.id);
+ nop();
+ gen("\tbr i1 %v, label %%Next%d, label %%Brk%d\n",
+ llvmbool(f, &loop.test), loop.id, loop.id);
+ gen("Next%d:", loop.id);
+ nop();
+ genblock(f, loop.body);
+ gen("\tbr label %%Cont%d\n", loop.id);
+ gen("Brk%d:",loop.id);
+ nop();
+ case For loop;
+ genblock(f, loop.ini);
+ gen("\tbr label %%Cont%d\n", loop.id);
+ gen("Cont%d:", loop.id);
+ nop();
+ gen("\tbr i1 %v, label %%Next%d, label %%Brk%d\n",
+ llvmbool(f, &loop.test), loop.id, loop.id);
+ gen("Next%d:", loop.id);
+ nop();
+ genblock(f, loop.body);
+ if !loop.next->empty() {
+ genexpr(f, &loop.next.Some);
+ }
+ gen("\tbr label %%Cont%d\n", loop.id);
+ gen("Brk%d:",loop.id);
+ nop();
+ case Return *e;
+ switch *e {
+ case None;
+ gen("\tret void\n");
+ case Some *e;
+ let retty = f.ty.u.Fn.ret;
+ gen("\tret %t %v\n", retty, convert(f, retty, e));
+ }
+ case else
+ assert(#f, "stmt? %d", st.u.#tag);
+ }
+}
+
+fn genblock(f *Fn, block [#]Stmt) void {
+ foreach_ptr (st, _, block) {
+ genstmt(f, st);
+ }
+}
+
+struct FuncKey {
+ name *const u8,
+ externp bool,
+}
+struct FuncEntry {
+ t enum {
+ Idk, Def, Decl
+ },
+ ty *const Type,
+ id int,
+}
+static funcs Map<FuncKey, FuncEntry, struct {
+ fn hash(e FuncKey) u32 {
+ let h = fnv1a_s(FNV1A_INI, e.name);
+ h = fnv1a_i(h, as(int)e.externp);
+ return h;
+ }
+ fn eq(a FuncKey, b FuncKey) bool {
+ return a.name == b.name and a.externp == b.externp;
+ }
+}> = {};
+
+extern fn llvm_addfn(decl *Decl) void {
+ assert(decl.toplevel, "llvm-addfn");
+ let slot = funcs->get_slot({decl.name, decl.externp});
+ if slot.t != :Def {
+ slot.t = :Decl;
+ slot.ty = decl.u.Fn.ty;
+ slot.id = decl.u.Fn.id;
+ }
+}
+
+extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void {
+ if externp {
+ funcs->put({name, externp}, {:Def, f.ty, f.id});
+ }
+ tmpid = 0;
+ gen("define%s %t ", externp ? "" : " internal", f.ty.u.Fn.ret);
+ if !externp {
+ gen("@%s.%d(", name, f.id);
+ } else {
+ gen("@%s(", name);
+ }
+ foreach(ty, i, f.ty.u.Fn.params) {
+ gen("%t", ty);
+ if f.paramnames[i] {
+ gen(" %%%s", f.paramnames[i]);
+ }
+ if i < f.paramnames.#len - 1 {
+ gen(", ");
+ }
+ }
+ gen(") { \n");
+ let id = 0;
+ foreach(nam, i, f.paramnames) {
+ if nam {
+ let ty = f.ty.u.Fn.params[i];
+ gen("%%%s.%d = alloca %t ", nam, id, ty);
+ gen("store %t %%%s, %t* %%%s.%d\n", ty, nam, ty, nam, id);
+ ++id;
+ }
+ }
+ genblock(f, f.body.Some);
+ if f.ty.u.Fn.ret->is(:Void) {
+ gen("\tret void\n");
+ } else {
+ let retty = f.ty.u.Fn.ret;
+ gen("\tret %t undef\n", retty);
+ }
+ gen("}\n");
+}
+
+extern fn llvm_addtype(ty *const Type) void {
+ if ty.konst { return; }
+ switch ty.u {
+ case Agg agg;
+ assert(agg.kind == :Struct, "addtype");
+ if agg.fwd {
+ gen("%%%s.%d = type opaque\n", agg.name, agg.id);
+ } else {
+ }
+
+ }
+}
+
+extern fn llvm_fini() void {
+ vec_each(s, i, strs) {
+ gen("@.str.%z = internal constant [%z x i8] c%S;\n", i, s.#len + 1, s);
+ }
+ map_each(f, k, funcs) {
+ if f.t == :Decl {
+ let ty = f.ty;
+ gen("declare%s %t ", k.externp ? "" : " internal", ty.u.Fn.ret);
+ if !k.externp {
+ gen("@%s.%d(", k.name, f.id);
+ } else {
+ gen("@%s(", k.name);
+ }
+ foreach(tyy, i, ty.u.Fn.params) {
+ gen("%t", tyy);
+ if i < ty.u.Fn.params.#len - 1 {
+ gen(", ");
+ } else if ty.u.Fn.variadic {
+ gen(", ...");
+ }
+ }
+ gen(");\n");
+ }
+ }
+ strs->clear();
+ funcs->clear();
+ arena->destroy();
+}
+
+extern fn llvm_init(out *FILE) void {
+ alloc = {&arena, &Arena:allocf, #null};
+ outfp = out;
+}
diff --git a/src/main.cff b/src/main.cff
index 3327e48..d2330ed 100644
--- a/src/main.cff
+++ b/src/main.cff
@@ -8,8 +8,10 @@ extern fn main(argc int, argv **u8) int {
let p = Parser {};
parser_init(&p, argv[1]);
- llvm_init();
+ llvm_init(stdout);
let decls = parse(&p);
- free(decls.#ptr);
+ defer free(decls.#ptr);
+ types_to_llvm();
+ llvm_fini();
}
diff --git a/src/map.hff b/src/map.hff
index 700c553..c756d88 100644
--- a/src/map.hff
+++ b/src/map.hff
@@ -112,3 +112,15 @@ struct Map<K, V, KTraits> {
}
}
+
+defmacro map_each(v, k, map, &body) [
+ let $m = (map);
+ for let $i = 0; $i < $m.N; ++$i {
+ if $m->_iempty($i) {
+ continue;
+ }
+ let k = $m.keys[$i];
+ let v = $m.vals[$i];
+ body;
+ }
+]
diff --git a/src/parse.cff b/src/parse.cff
index 84ed1fe..699762c 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -966,7 +966,7 @@ fn xident2type(P *Parser, eloc Loc, name *const u8) *const Type {
fn parsefnparams(P *Parser, variadic *bool, paramnames *Vec<*const u8>, paramtys *Vec<*const Type>) void {
lexexpect(P, '(');
let tok Tok #?;
- *variadic = #t;
+ *variadic = #f;
while !lexmatch(P, &tok, ')') {
if lexmatch(P, #null, '...') {
*variadic = #t;
@@ -1513,7 +1513,7 @@ fn pexpostfix(P *Parser) Expr {
P.targty = args.len + 1 <= params.#len ? *param : #null;
let ex = parseexpr(P);
args->push(ex);
- if args.len >= params.#len and !Fn.variadic {
+ if args.len > params.#len and !Fn.variadic {
fatal(P, ex.loc, "too many args (%z, expected %z)", args.len, params.#len);
}
if args.len <= params.#len and !typematchestarg(*param, ex.ty) {
@@ -2397,7 +2397,8 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie
ty = constify(ty);
}
- let decl Decl = { name, tok.loc, externp, :Let { ty, ini, fwd, P.curfn ? P.curfn.id : 0, } };
+ let decl Decl = { name, tok.loc, externp, toplevel,
+ :Let { ty, ini, fwd, P.curfn ? P.curfn.id : 0, } };
if letp {
decl.u.Let.id = P.varid++;
} else {
@@ -2414,7 +2415,7 @@ fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, yield DeclYie
} while !lexmatch(P, &tok, ';');
}
-fn parsefn(P *Parser, loc Loc, externp bool, name *const u8) *Decl {
+fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Decl {
let decl Decl = {
name,
loc,
@@ -2435,9 +2436,13 @@ fn parsefn(P *Parser, loc Loc, externp bool, name *const u8) *Decl {
static id int = 0;
Fn.id = ++id;
let decl = putdecl(P, loc, decl);
-
+ decl.toplevel = toplevel;
+
if !lexmatch(P, #null, '{') {
lexexpects(P, ';', "';' or '{'");
+ if toplevel {
+ llvm_addfn(decl);
+ }
return decl;
}
@@ -2463,6 +2468,9 @@ fn parsefn(P *Parser, loc Loc, externp bool, name *const u8) *Decl {
(as(*Arena)P.alloc.a)->destroy();
}
}
+ if toplevel {
+ llvm_addfn(decl);
+ }
P.varid = varid;
P.loopid = loopid;
return decl;
@@ -2700,7 +2708,7 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool)
switch {
case lexmatch(P, &tok, :kw_fn);
let name = lexmatch(P, &tok, :ident) ? tok.u.ident : #null;
- decl = parsefn(P, tok.loc, externp, name);
+ decl = parsefn(P, tok.loc, toplevel, externp, name);
case lexmatch(P, &tok, :kw_import);
let path = (tok = lexexpects(P, :str, "import path")).u.str.#ptr;
diff --git a/src/set.hff b/src/set.hff
index 431ef93..6a03e52 100644
--- a/src/set.hff
+++ b/src/set.hff
@@ -11,7 +11,6 @@ struct Set<T, Traits> {
N int,
count int,
-
fn _nexthash(h *u32) u32 {
// return *h = (*h * 1664525) + 1013904223u; // double hashing
return ++*h; // linear probing
@@ -76,3 +75,14 @@ struct Set<T, Traits> {
self->intern(x);
}
}
+
+defmacro set_each(v, Set, &body) [
+ let $s = (Set);
+ for let $i = 0; $i < $s.N; ++$i {
+ let $idx = $s.set[$i];
+ if $idx > 0 {
+ let v = $s.buf.dat[$idx - 1];
+ body;
+ }
+ }
+]
diff --git a/src/type.cff b/src/type.cff
index ddb4cd8..194ff01 100644
--- a/src/type.cff
+++ b/src/type.cff
@@ -115,14 +115,13 @@ struct TypeTraits {
}
}
+static types_set Set<*const Type, TypeTraits> = {};
extern fn interntype(ty0 Type) *const Type {
- static set Set<*const Type, TypeTraits> = {};
-
if ty0.align == 0 {
ty0.align = ty0.size;
}
- return *set->intern(&ty0);
+ return *types_set->intern(&ty0);
}
extern fn completetype(ty *const Type) bool {
@@ -307,3 +306,9 @@ extern fn typeof2(a *const Type, b *const Type) *const Type {
}
return #null;
}
+
+extern fn types_to_llvm() void {
+ set_each(ty, types_set) {
+ llvm_addtype(ty);
+ }
+}