aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-24 06:46:23 +0200
committerlemon <lsof@mailbox.org>2022-08-24 06:46:23 +0200
commite5ed3b20351a2715fe88d9a5dbcc8e6757fe96aa (patch)
tree7333f357bc38ed389e8845d59196594377dc46d6 /src
parent039ab20bbf6b68c423f420be2481b447d85c606b (diff)
llvm defer and more
Diffstat (limited to 'src')
-rw-r--r--src/cffc.hff48
-rw-r--r--src/env.cff8
-rw-r--r--src/fold.cff1
-rw-r--r--src/irgen.cff14
-rw-r--r--src/llvm.cff119
-rw-r--r--src/parse.cff226
-rw-r--r--src/targ.cff1
-rw-r--r--src/type.cff12
8 files changed, 304 insertions, 125 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index 1c80b3a..d327766 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -119,6 +119,7 @@ struct Type {
struct Fn;
struct Expan;
struct IRCtx;
+struct Block;
struct Parser {
fp *FILE,
irctx *IRCtx,
@@ -128,6 +129,7 @@ struct Parser {
curfn *Fn,
curenv *Env,
curloop int,
+ curblock *Block,
curexpan *Expan,
expanno int,
loopid int,
@@ -154,6 +156,13 @@ enum UnOp {
}
struct Stmt;
+struct Defers;
+struct Block {
+ sts [#]Stmt,
+ defers *Defers,
+ id int,
+}
+
struct Expr {
loc Loc,
ty *const Type,
@@ -180,13 +189,21 @@ struct Expr {
EUnionIni struct { var *const AggField, ex *Expr },
AggIni struct { flds [#]*const AggField, exs [#]Expr },
ArrIni struct { idxs [#]u32, exs [#]Expr, maxn i64 },
- Stmt [#]Stmt,
+ Stmt Block,
}
}
+
+struct Defers {
+ next *Defers,
+ blockid int,
+ age int,
+ ex Expr
+}
+
struct ISwitchCase {
es [#]Expr,
- t [#]Stmt
+ t Block
}
struct EUSwitchCase {
@@ -196,35 +213,36 @@ struct EUSwitchCase {
variant int,
captty *const Type,
fld *AggField,
- t [#]Stmt
+ t Block
}
struct CSwitchCase {
test Expr,
- t [#]Stmt,
+ t Block,
}
struct Stmt {
loc Loc,
u enum union {
- Block [#]Stmt,
- If struct { test Expr, t [#]Stmt, f [#]Stmt },
- While struct { test Expr, body [#]Stmt, id int },
+ Block Block,
+ If struct { test Expr, t Block, f Block },
+ While struct { test Expr, body Block, id int },
+ DoWhile struct { test Expr, body Block, id int },
For struct {
- ini [#]Stmt,
+ ini Block,
test Expr,
next Option<Expr>,
- body [#]Stmt,
+ body Block,
id int,
},
Break #{loopid} int,
Continue #{loopid} int,
- Return Option<Expr>,
+ Return struct { ex Option<Expr>, deferage int },
Expr Expr,
Decl *Decl,
- ISwitch struct { ex Expr, cs [#]ISwitchCase, f [#]Stmt },
- EUSwitch struct { ex Expr, cs [#]EUSwitchCase, f [#]Stmt },
- CSwitch struct { cs [#]CSwitchCase, f [#]Stmt }
+ ISwitch struct { ex Expr, cs [#]ISwitchCase, f Block },
+ EUSwitch struct { ex Expr, cs [#]EUSwitchCase, f Block },
+ CSwitch struct { cs [#]CSwitchCase, f Block }
}
}
@@ -233,7 +251,7 @@ struct Fn {
paramnames [#]*const u8,
variadic bool,
id int,
- body Option<[#]Stmt>
+ body Option<Block>
}
struct Var {
@@ -340,6 +358,7 @@ struct Targ {
sizesize u8,
f64align u8,
valistsize u8, valistalign u8,
+ valistllvmty *const u8,
charsigned bool,
shortenum bool,
@@ -443,6 +462,7 @@ extern fn types_to_llvm() void;
extern fn mkenv(parent *Env, alloc *Allocator) *Env;
extern fn envparent(*Env) *Env;
extern fn envput(*Env, Decl, **const Decl) *Decl;
+extern fn envput_alloc(*Env, *Allocator, Decl, **const Decl) *Decl;
extern fn envfind(*Env, *const u8) *Decl;
extern fn envfind_noparent(*Env, *const u8) *Decl;
extern fn envfree(*Env) void;
diff --git a/src/env.cff b/src/env.cff
index 816053e..6bc24fe 100644
--- a/src/env.cff
+++ b/src/env.cff
@@ -24,9 +24,9 @@ extern fn envparent(env *Env) *Env {
return env.parent;
}
-extern fn envput(env *Env, decl Decl, old **const Decl) *Decl {
+extern fn envput_alloc(env *Env, alloc *Allocator, decl Decl, old **const Decl) *Decl {
let l **DeclList = env.decls->get_slot(decl.name);
- let n *DeclList = anew(env.alloc, DeclList);
+ let n *DeclList = anew(alloc, DeclList);
if *l { // decl with this name exists
let old = (*old = &(*l).decl);
switch {
@@ -51,6 +51,10 @@ extern fn envput(env *Env, decl Decl, old **const Decl) *Decl {
return &n.decl;
}
+extern fn envput(env *Env, decl Decl, old **const Decl) *Decl {
+ return envput_alloc(env, env.alloc, decl, old);
+}
+
extern fn envfind(env *Env, name *const u8) *Decl {
let l **DeclList = env.decls->get(name);
if l == #null {
diff --git a/src/fold.cff b/src/fold.cff
index c9991b7..00e4702 100644
--- a/src/fold.cff
+++ b/src/fold.cff
@@ -129,6 +129,7 @@ fn fbinary(ex *Expr) void {
case op == '<<' and ty->is(:Int); ei.i = li.i << ri.i;
case op == '>>' and ty->is(:Int) and !ty.u.Int.sgn; ei.u = li.u >> ri.u;
case op == '>>' and ty->is(:Int); ei.i = li.i >> ri.i;
+ case else return;
}
if !ex.ty->is(:Bool) {
diff --git a/src/irgen.cff b/src/irgen.cff
index e157406..c0ea1e1 100644
--- a/src/irgen.cff
+++ b/src/irgen.cff
@@ -70,7 +70,7 @@ struct InstStream {
}
-fn genblock(S *InstStream, block [#]Stmt) void;
+fn genblock(S *InstStream, block Block) void;
fn genexpr(S *InstStream, ex *Expr) IRValue {
static tmpid int = 0;
@@ -343,7 +343,7 @@ fn genstmt(S *InstStream, stmt *Stmt) void {
let beqz = S->mkinst1({:beqz}, :Val(t));
S->push(beqz);
genblock(S, If.t);
- if If.f.#ptr {
+ if If.f.sts.#ptr {
let b = S->mkinst({:b}, 0);
S->push(b);
beqz.branch = S->pushnop();
@@ -407,11 +407,11 @@ fn genstmt(S *InstStream, stmt *Stmt) void {
assert(jumpto != #null, "no cont label %d", id);
S->push(S->mkinst({:b, .branch: *jumpto},0));
- case Return retex;
- if retex->empty() {
+ case Return *ret;
+ if ret.ex->empty() {
S->push(S->mkinst({:ret0}, 0));
} else {
- let inst = S->mkinst1({:ret}, :Val(genexpr(S, &retex.Some)));
+ let inst = S->mkinst1({:ret}, :Val(genexpr(S, &ret.ex.Some)));
S->push(inst);
}
@@ -420,8 +420,8 @@ fn genstmt(S *InstStream, stmt *Stmt) void {
}
}
-fn genblock(S *InstStream, block [#]Stmt) void {
- foreach_ptr(st, _, block) {
+fn genblock(S *InstStream, block Block) void {
+ foreach_ptr(st, _, block.sts) {
genstmt(S, st);
}
}
diff --git a/src/llvm.cff b/src/llvm.cff
index 4ea469d..053d44d 100644
--- a/src/llvm.cff
+++ b/src/llvm.cff
@@ -55,6 +55,7 @@ fn gen(fmt *const u8, ...) void {
}
}
gen(") ");
+ case VaList; gen("%s", g_targ.valistllvmty);
}
}
@@ -94,7 +95,7 @@ fn gen(fmt *const u8, ...) void {
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 BImm b; gen("%d", as(int)b);
case Null; gen("null");
case ZeroIni; gen("zeroinitializer");
case Tmp t; fprintf(outfp, "%%t%d", t);
@@ -235,7 +236,7 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value {
}
}
-fn genblock(f *Fn, block [#]Stmt) void;
+fn genblock(f *Fn, block Block) Option<Value>;
fn genexpr(f *Fn, ex *Expr) Value {
fold(ex);
@@ -333,8 +334,8 @@ fn genexpr(f *Fn, ex *Expr) Value {
rhs = b.rhs.ty->is(:Ptr) ? genexpr(f, b.rhs) : convert(f, ty2 ?? b.rhs.ty, b.rhs);
return gensub(ex.ty, lhs, rhs);
case '*'; return genbinop(b.lhs, b.rhs, !ex.ty->is(:Flo) ? "mul" : "fmul");
- case '/'; return genbinop(b.lhs, b.rhs, ex.ty->is(:Flo) ? "fdiv"
- : ex.ty.u.Int.sgn ? "sdiv" : "udiv");
+ case '/'; return genbinop(b.lhs, b.rhs,
+ ex.ty->is(:Flo) ? "fdiv" : ex.ty.u.Int.sgn ? "sdiv" : "udiv");
case '%'; return genbinop(b.lhs, b.rhs, ex.ty.u.Int.sgn ? "srem" : "urem");
case '&'; return genbinop(b.lhs, b.rhs, "and");
case '|'; return genbinop(b.lhs, b.rhs, "or");
@@ -376,12 +377,12 @@ fn genexpr(f *Fn, ex *Expr) Value {
ex.ty, b.lhs, b.rhs);
case '%=';
return genassignop(ex.ty.u.Int.sgn ? "srem" : "urem", ex.ty, b.lhs, b.rhs);
- case '&='; return genassignop("and", ex.ty, b.lhs, b.rhs);
- case '|='; return genassignop("or", ex.ty, b.lhs, b.rhs);
- case '^='; return genassignop("xor", ex.ty, b.lhs, b.rhs);
- case '<<='; return genassignop("shl", ex.ty, b.lhs, b.rhs);
- case '>>='; return genassignop(ex.ty.u.Int.sgn ? "ashr" : "lshr", ex.ty, b.lhs, b.rhs);
-
+ case '&='; return genassignop("and", ex.ty, b.lhs, b.rhs);
+ case '|='; return genassignop("or", ex.ty, b.lhs, b.rhs);
+ case '^='; return genassignop("xor", ex.ty, b.lhs, b.rhs);
+ case'<<='; return genassignop("shl", ex.ty, b.lhs, b.rhs);
+ case'>>='; return genassignop(ex.ty.u.Int.sgn ? "ashr" : "lshr", ex.ty, b.lhs, b.rhs);
+
case else
assert(#f, "binop? %c", b.op);
}
@@ -393,7 +394,11 @@ fn genexpr(f *Fn, ex *Expr) Value {
let var = mktmp(ex.ty);
let val = mktmp(ex.ty);
gen("\t%v = load %t, %t* %v\n", var, ex.ty, ex.ty, addr);
- gen("\t%v = add %t %v, %v\n", val, ex.ty, var, one);
+ if ex.ty->is(:Ptr) {
+ gen("\t%v = getelementptr %t, %t %v, i32 %v\n", val, ex.ty.u.Ptr, ex.ty, var, one);
+ } else {
+ gen("\t%v = add %t %v, %v\n", val, ex.ty, var, one);
+ }
gen("\tstore %t %v, %t* %v\n", ex.ty, val, ex.ty, addr);
return val;
@@ -403,7 +408,11 @@ fn genexpr(f *Fn, ex *Expr) Value {
let var = mktmp(ex.ty);
let val = mktmp(ex.ty);
gen("\t%v = load %t, %t* %v\n", var, ex.ty, ex.ty, addr);
- gen("\t%v = add %t %v, %v\n", val, ex.ty, var, one);
+ if ex.ty->is(:Ptr) {
+ gen("\t%v = getelementptr %t, %t %v, i32 %v\n", val, ex.ty.u.Ptr, ex.ty, var, one);
+ } else {
+ gen("\t%v = add %t %v, %v\n", val, ex.ty, var, one);
+ }
gen("\tstore %t %v, %t* %v\n", ex.ty, val, ex.ty, addr);
return var;
@@ -466,7 +475,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
let t Value #?;
if fnty.ret->is(:Void) {
t = {ty_void};
- gen("call %t %v(", call.lhs.ty, lhs);
+ gen("\tcall %t %v(", call.lhs.ty, lhs);
} else {
t = mktmp(ex.ty);
gen("\t%v = call %t %v(", t, call.lhs.ty, lhs);
@@ -480,6 +489,12 @@ fn genexpr(f *Fn, ex *Expr) Value {
}
gen(")\n");
return t;
+
+ case Stmt block;
+ switch genblock(f, block) {
+ case Some val; return val;
+ case None; return {ty_void};
+ }
case else
assert(#f, "expr? %d", ex.u.#tag);
@@ -501,8 +516,11 @@ fn nop() void {
gen("\t%%t%d = bitcast i8 0 to i8 ; NOP\n", tmpid++);
}
-fn genstmt(f *Fn, st *Stmt) void {
+fn genstmt(f *Fn, block *Block, st *Stmt) void {
switch st.u {
+ case Block block;
+ genblock(f, block);
+
case Expr *e;
genexpr(f, e);
@@ -525,14 +543,14 @@ fn genstmt(f *Fn, st *Stmt) void {
gen("IfT%d:", id);
nop();
genblock(f, cnd.t);
- if cnd.f.#ptr {
+ if cnd.f.sts.#ptr {
gen("\tbr label %%IfSk%d\n", id);
}
gen("\tbr label %%IfF%d\n", id);
gen("IfF%d:", id);
nop();
genblock(f, cnd.f);
- if cnd.f.#ptr {
+ if cnd.f.sts.#ptr {
gen("\tbr label %%IfSk%d\n", id);
gen("IfSk%d:", id);
nop();
@@ -573,8 +591,14 @@ fn genstmt(f *Fn, st *Stmt) void {
case Continue loopid;
gen("\tbr label %%Cont%d\n", loopid);
- case Return *e;
- switch *e {
+ case Return *ret;
+ for let defers = block.defers; defers; defers = defers.next {
+ if defers.age < ret.deferage {
+ genexpr(f, &defers.ex);
+ }
+
+ }
+ switch ret.ex {
case None;
gen("\tret void\n");
case Some *e;
@@ -586,10 +610,19 @@ fn genstmt(f *Fn, st *Stmt) void {
}
}
-fn genblock(f *Fn, block [#]Stmt) void {
- foreach_ptr (st, _, block) {
- genstmt(f, st);
+fn genblock(f *Fn, block Block) Option<Value> {
+ foreach_ptr (st, _, block.sts) {
+ genstmt(f, &block, st);
}
+ for let defers = block.defers; defers; defers = defers.next {
+ if defers.blockid == block.id {
+ let ex = genexpr(f, &defers.ex);
+ if defers.next == #null {
+ return :Some(ex);
+ }
+ }
+ }
+ return :None;
}
struct FuncKey {
@@ -666,10 +699,48 @@ extern fn llvm_addtype(ty *const Type) void {
if ty.konst { return; }
switch ty.u {
case Agg agg;
- assert(agg.kind == :Struct, "addtype");
+ gen("%%%s.%d = type ", agg.name ?? as(*const u8)"_", agg.id);
if agg.fwd {
- gen("%%%s.%d = type opaque\n", agg.name, agg.id);
- } else {
+ gen("opaque\n");
+ } else if agg.flds.#len == 0 {
+ gen("{ i8 }");
+ } else if agg.kind == :Struct {
+ gen("{ ");
+ foreach (fld, i, agg.flds) {
+ gen("%t", fld.ty);
+ if i < agg.flds.#len - 1 {
+ gen(", ");
+ }
+ }
+ gen(" }\n");
+ } else if agg.kind == :Union {
+ let size = ty.size;
+ let ty *const Type = #null;
+ foreach (fld, i, agg.flds) {
+ if ty == #null or fld.ty.align > ty.align {
+ ty = fld.ty;
+ }
+ }
+ gen("{ %t ", ty);
+ if ty.size < size {
+ gen(", [%z x i8] ", size - ty.size);
+ }
+ gen("}\n");
+ } else if agg.kind == :EUnion {
+ gen("{ %t, ", agg.enumty);
+ let size = ty.size;
+ let ty *const Type = #null;
+ foreach (fld, i, agg.flds) {
+ if ty == #null or (fld.ty != #null and fld.ty.align > ty.align) {
+ ty = fld.ty;
+ }
+ }
+ ty = ty ?? ty_void;
+ gen(" %t ", ty);
+ if ty.size < size {
+ gen(", [%z x i8] ", size - ty.size);
+ }
+ gen("}\n");
}
}
diff --git a/src/parse.cff b/src/parse.cff
index 760c0f9..e731d47 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -81,7 +81,7 @@ fn issep(c u8) bool {
case '(', ')', '[', ']', '{', '}', '.', ',',
';', '?', '+', '-', '*', '/', '&', '|',
'^', '~', '=', '\'', '"', '<', '>', ':',
- '@', '#', '\\', '`';
+ '@', '#', '\\', '`', '%', '!';
return #t;
}
return #f;
@@ -100,7 +100,7 @@ fn ishsep(c u8) bool {
}
fn readtilsep(P *Parser, buf [#]u8, dot bool) int {
- let i = 0,
+ let i = 0z,
c u8 #?;
while (!issep(c = chrpeek(P))) or (dot and c == '.') {
chr(P);
@@ -114,7 +114,7 @@ fn readtilsep(P *Parser, buf [#]u8, dot bool) int {
}
fn readtilhsep(P *Parser, buf [#]u8, dot bool) int {
- let i = 0,
+ let i = 0z,
c u8 #?,
pred = &ishsep;
while (!pred(c = chrpeek(P))) or (dot and c == '.') {
@@ -151,8 +151,8 @@ extern static keyword2str [NUM_KEYWORDS]*const u8 = {
};
fn str2keyword(s *const u8) int {
- let i = 0zs,
- j = keyword2str.#len - 1;
+ let i isize = 0,
+ j isize = keyword2str.#len - 1;
while i <= j {
let k = (j + i) / 2;
let cmp = strcmp(keyword2str[k], s);
@@ -452,7 +452,9 @@ fn lex(P *Parser) Tok {
if delim == '"' {
tok.t = :str;
+ str->push('\0');
tok.u.str = str->move(P.alloc);
+ tok.u.str = tok.u.str[0::tok.u.str.#len - 1];
} else {
tok.t = :chr;
if str.len == 0 {
@@ -627,6 +629,18 @@ fn putdecl(P *Parser, eloc Loc, decl Decl) *Decl {
return d;
}
+fn putdecl_alloc(P *Parser, alloc *Allocator, eloc Loc, decl Decl) *Decl {
+ if envfind(primenv, decl.name) {
+ fatal(P, eloc, "cannot shadow primitive `%s'", decl.name);
+ }
+ let d0 *const Decl;
+ let d = envput_alloc(P.curenv, alloc, decl, &d0);
+ if d == #null {
+ fatal(P, eloc, "attempt to redefine `%s' (previously defined at %l)", decl.name, d0.loc);
+ }
+ return d;
+}
+
///////////////////
// Types Parsing //
///////////////////
@@ -669,8 +683,8 @@ fn parseenum(P *Parser, name *const u8, lax bool) *const Type {
}
}
let intty *const Type = intty ?? (
- max < 1u64 << ((g_targ.intsize * 8) - 1) ? ty_int
- : max < 1u64 << 31 ? ty_i32
+ max < 1i64 << ((g_targ.intsize * 8) - 1) ? ty_int
+ : max < 1i64 << 31 ? ty_i32
: ty_i64);
static id int = 0;
return interntype({ .u: :Enum { intty, name, lax, id++, vals->move(P.alloc) }});
@@ -716,10 +730,10 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c
if !lexmatch(P, &tok, ';') {
agg.fwd = #f;
lexexpect(P, '{');
- let size = 0, align = 1;
+ let size = 0z, align = 1z;
let flds Vec<AggField> = {};
let havedecls = #f;
- let f0align = -1i64;
+ let f0align = -1zs;
while !lexmatch(P, &tok, '}') {
if isdecltokt(lexpeek(P).t) {
havedecls = #t;
@@ -895,7 +909,7 @@ fn parseexpandtepl(P *Parser, tepl *Tepl) *const Type {
#'search
for cache = tepl.cache; cache; cache = cache.next {
- for let i = 0; i < nparam; ++i {
+ for let i = 0z; i < nparam; ++i {
let arg = &tpargs[i];
switch cache.args[i] {
case Ty ty;
@@ -1102,7 +1116,7 @@ fn parseaggini(P *Parser, loc Loc, ty *const Type) Expr {
let tok Tok #?;
let flds Vec<*const AggField> = {};
let exs Vec<Expr> = {};
- let iota = 0;
+ let iota = 0u64;
while !lexmatch(P, &tok, '}') {
let fld *AggField #?;
let ex Expr #?;
@@ -1299,49 +1313,32 @@ fn parseexpandmacro(P *Parser, loc Loc, mac *Macro) void {
}
-fn parseblock0(P *Parser) [#]Stmt;
+fn parseblock0(P *Parser) Block;
fn pexprimary(P *Parser) Expr {
let tok Tok = lex(P);
let ex Expr #?;
- switch tok.t {
- case :int, :chr;
- ex = { tok.loc, tok.ty, .u: :IntLit { tok.u.int }};
-
- case :flo;
- ex = { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) };
- case :bool;
- ex = { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) };
-
- case :null;
- ex = { tok.loc, ty_voidptr, .u: :NullLit };
-
- case :str;
- let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8);
- ex = { tok.loc, ty, .u: :StrLit(tok.u.str) };
-
- case :ident;
- let ident = tok.u.ident;
- let decl = finddecl(P, ident);
- let fakedecl Decl = {};
+ let fakedecl Decl #?;
+ fn resolvedecl(P *Parser, tok Tok, decl *Decl, ex *Expr) void {
+ let fakedecl Decl #?;
if decl == #null {
fatal(P, tok.loc, "%qT is not defined", tok);
}
while #t {
switch decl.u {
case Fn f;
- ex = { tok.loc, f.ty, .u: :Symbol(decl) };
+ *ex = { tok.loc, f.ty, .u: :Symbol(decl) };
case Let var;
- ex = { tok.loc, var.ty, .u: :Symbol(decl) };
+ *ex = { tok.loc, var.ty, .u: :Symbol(decl) };
case Static var;
- ex = { tok.loc, var.ty, .u: :Symbol(decl) };
+ *ex = { tok.loc, var.ty, .u: :Symbol(decl) };
case Def dex;
dex.loc = tok.loc;
- ex = dex;
+ *ex = dex;
case Macro *mac;
parseexpandmacro(P, tok.loc, mac);
- ex = parseexpr(P);
+ *ex = parseexpr(P);
case Ty ty;
if (tok = lexpeek(P)).t != ':' and tok.t != '{' {
lexexpects(P, ':', "`:' or `{' after type name");
@@ -1356,9 +1353,10 @@ fn pexprimary(P *Parser) Expr {
continue;
} else if !ty->is(:Agg) and !ty->is(:Enum) {
fatal(P, tok.loc, "type is not aggregate or enum");
- } else {
+ } else {;
P.targty = ty;
- return parseexpr(P);
+ *ex = parseexpr(P);
+ return;
}
case Tepl *tepl;
fakedecl = { .u: :Ty(parseexpandtepl(P, tepl)) };
@@ -1367,6 +1365,34 @@ fn pexprimary(P *Parser) Expr {
}
break;
}
+ }
+
+ switch tok.t {
+ case :int, :chr;
+ ex = { tok.loc, tok.ty, .u: :IntLit { tok.u.int }};
+
+ case :flo;
+ ex = { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) };
+
+ case :bool;
+ ex = { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) };
+
+ case :null;
+ ex = { tok.loc, ty_voidptr, .u: :NullLit };
+
+ case :str;
+ let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8);
+ ex = { tok.loc, ty, .u: :StrLit(tok.u.str) };
+
+ case :ident;
+ let ident = tok.u.ident;
+ let decl = finddecl(P, ident);
+ resolvedecl(P, tok, decl, &ex);
+
+ case :typearg;
+ fakedecl = { .u: :Ty(tok.ty) };
+ resolvedecl(P, tok, &fakedecl, &ex);
+
case :kw_sizeof;
let ty *const Type #?;
if lexmatch(P, &tok, '(') {
@@ -1418,7 +1444,8 @@ fn pexprimary(P *Parser) Expr {
case '(';
if lexmatch(P, &tok, :kw_do) {
- let st = parseblock0(P);
+ let block = parseblock0(P);
+ let st = block.sts;
lexexpect(P, ')');
if st.#len == 0 or st[st.#len - 1].u.#tag != :Expr {
ex = { tok.loc, ty_void, :Stmt(st) };
@@ -1840,7 +1867,11 @@ fn pexcmp(P *Parser) Expr {
fatal(P, tok.loc, "invalid non-numeric operands %t and %t to relational operator %qT",
ex.ty, rhs.ty, tok);
}
- if ty->is(:Int) and ty != ty_int and ex.ty.u.Int.sgn != rhs.ty.u.Int.sgn {
+ fn ispositiveintlit(ex Expr) bool {
+ return ex.u.#tag == :IntLit and ex.u.IntLit.i >- 0;
+ }
+ if ty->is(:Int) and ty != ty_int and ex.ty.u.Int.sgn != rhs.ty.u.Int.sgn
+ and !(ispositiveintlit(ex) or ispositiveintlit(rhs)) {
warn(P, tok.loc, "comparing integers of different signedness (%t and %t)", ex.ty, rhs.ty);
}
}
@@ -1889,13 +1920,16 @@ fn pexlog(P *Parser) Expr {
fn pexcond(P *Parser) Expr {
let tok Tok = {};
+ let targty = P.targty;
let ex = pexlog(P);
if (lexmatch(P, &tok, '?')) {
+ P.targty = targty;
let ex2 = parseexpr(P);
if !ex.ty->is(:Bool) and !ex.ty->is(:Ptr) {
fatal(P, ex.loc, "invalid test operand to conditional operator (%t)", ex.ty);
}
lexexpect(P, ':');
+ P.targty = targty;
let ex3 = pexcond(P);
let ty = typeof2(ex2.ty, ex3.ty);
if ty == #null {
@@ -1971,7 +2005,7 @@ fn stmtdup(alloc *Allocator, st Stmt) *Stmt {
}
typedef StmtYielder *fn(Stmt, *void) void;
-fn parseblock(P *Parser) [#]Stmt;
+fn parseblock(P *Parser) Block;
fn parsevardecl(P *Parser, toplevel bool, externp bool, letp bool, DeclYielder, *void) void;
fn pstlet(P *Parser, yield StmtYielder, yarg *void) void {
@@ -1998,7 +2032,7 @@ fn pstif(P *Parser, loc Loc) Stmt {
if lexmatch(P, &tok, :kw_else) {
if lexmatch(P, &tok, :kw_if) {
let f = stmtdup(P.alloc, pstif(P, tok.loc));
- return { loc, :If { test, t, f[0::1] }};
+ return { loc, :If { test, t, { f[0::1] } }};
} else {
lexexpect(P, '{');
let f = parseblock(P);
@@ -2008,7 +2042,7 @@ fn pstif(P *Parser, loc Loc) Stmt {
return { loc, :If { test, t }};
}
-fn pstreturn(P *Parser, loc Loc) Stmt {
+fn pstreturn(P *Parser, loc Loc, deferage int) Stmt {
if P.curfn == #null {
fatal(P, loc, "return outside function");
}
@@ -2017,7 +2051,7 @@ fn pstreturn(P *Parser, loc Loc) Stmt {
if retty != ty_void {
err(P, loc, "return with no value in function returning %t", retty);
}
- return { loc, :Return{} };
+ return { loc, :Return{ :None, deferage} };
} else {
P.targty = retty;
let ex = parseexpr(P);
@@ -2026,7 +2060,7 @@ fn pstreturn(P *Parser, loc Loc) Stmt {
err(P, ex.loc, "incompatible type in return statement (%t, expected %t)",
ex.ty, retty);
}
- return { loc, :Return(:Some(ex)) };
+ return { loc, :Return{:Some(ex), deferage} };
}
}
@@ -2036,7 +2070,7 @@ fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt {
err(P, test.loc, "while condition must be bool or pointer (%t)", test.ty);
}
lexexpect(P, '{');
- let body [#]Stmt #?;
+ let body Block #?;
with_tmpchange(P.curloop, ++P.loopid) {
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
@@ -2050,8 +2084,29 @@ fn pstwhile(P *Parser, loc Loc, label *const u8) Stmt {
return { loc, :While { test, body, P.loopid }};
}
+fn pstdowhile(P *Parser, loc Loc, label *const u8) Stmt {
+ lexexpect(P, '{');
+ let body Block #?;
+ with_tmpchange(P.curloop, ++P.loopid) {
+ let env = mkenv(P.curenv, P.alloc);
+ defer envfree(env);
+ pushenv(P, env);
+ if label {
+ putdecl(P, loc, { label, loc, .u: :Label(P.loopid) });
+ }
+ body = parseblock(P);
+ popenv(P);
+ }
+ lexexpect(P, :kw_while);
+ let test = parseexpr(P);
+ if !test.ty->is(:Bool) and !test.ty->is(:Ptr) {
+ err(P, test.loc, "do-while condition must be bool or pointer (%t)", test.ty);
+ }
+ return { loc, :DoWhile { test, body, P.loopid }};
+}
+
fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
- let ini [#]Stmt = {};
+ let ini Block = {};
let test Expr #?;
let next = Option<Expr>:None;
let tok Tok #?;
@@ -2062,12 +2117,12 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
sts->push(st);
}
pstlet(P, &yieldlet, &sts);
- ini = sts->move(P.alloc);
+ ini = { sts->move(P.alloc) };
} else if lexmatch(P, #null, ';') {
// pass
} else {
let ex = parseexpr(P);
- ini = stmtdup(P.alloc, { ex.loc, :Expr(ex) })[0::1];
+ ini = { stmtdup(P.alloc, { ex.loc, :Expr(ex) })[0::1] };
lexexpect(P, ';');
}
@@ -2085,7 +2140,7 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
next = :Some(parseexpr(P));
lexexpect(P, '{');
}
- let body [#]Stmt #?;
+ let body Block #?;
let id = ++P.loopid;
with_tmpchange(P.curloop, id) {
let env = mkenv(P.curenv, P.alloc);
@@ -2103,7 +2158,7 @@ fn pstfor(P *Parser, loc Loc, label *const u8) Stmt {
fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt {
let tok Tok #?;
let cs Vec<ISwitchCase> = {};
- let f [#]Stmt = {};
+ let f Block = {};
let elsep = #f;
while !lexmatch(P, &tok, '}') {
lexexpect(P, :kw_case);
@@ -2140,7 +2195,7 @@ fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt {
fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt {
let cs Vec<EUSwitchCase> = {};
let tok Tok #?;
- let f [#]Stmt = {};
+ let f Block = {};
let elsep = #f;
while !lexmatch(P, &tok, '}') {
@@ -2196,7 +2251,7 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt {
fn pstcswitch(P *Parser, loc Loc) Stmt {
let cs Vec<CSwitchCase> = {};
let tok Tok #?;
- let f [#]Stmt = {};
+ let f Block = {};
let elsep = #f;
while !lexmatch(P, &tok, '}') {
@@ -2237,6 +2292,7 @@ fn pstswitch(P *Parser, loc Loc) Stmt {
}
fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
+ static deferage int = {};
let tok Tok = {};
switch {
case lexmatch(P, &tok, '{');
@@ -2251,7 +2307,7 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
return yield(pstif(P, tok.loc), yarg);
case lexmatch(P, &tok, :kw_return);
- return yield(pstreturn(P, tok.loc), yarg);
+ return yield(pstreturn(P, tok.loc, deferage), yarg);
case lexmatch(P, &tok, :label);
let label = tok.u.ident;
@@ -2260,6 +2316,8 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
return yield(pstwhile(P, tok.loc, label), yarg);
case lexmatch(P, &tok, :kw_for);
return yield(pstfor(P, tok.loc, label), yarg);
+ case lexmatch(P, &tok, :kw_do);
+ return yield(pstdowhile(P, tok.loc, label), yarg);
case else
fatal(P, tok.loc, "label can only precede looping statement");
}
@@ -2270,6 +2328,10 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
case lexmatch(P, &tok, :kw_for);
return yield(pstfor(P, tok.loc, #null), yarg);
+ case lexmatch(P, &tok, :kw_do);
+ return yield(pstdowhile(P, tok.loc, #null), yarg);
+
+
case lexmatch(P, &tok, :kw_break) or lexmatch(P, &tok, :kw_continue);
if P.curloop == 0 {
err(P, tok.loc, "%s outside loop", tok.t == :kw_break ? "break" : "continue");
@@ -2287,6 +2349,20 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
lexexpect(P, ';');
return yield({ tok.loc, tok.t == :kw_break ? :Break(loop) : :Continue(loop) }, yarg);
+ case lexmatch(P, &tok, :kw_defer);
+ if P.curblock == #null {
+ fatal(P, tok.loc, "defer outside function");
+ }
+ let ex = parseexpr(P);
+ lexexpect(P, ';');
+ let defr *Defers = anew(P.alloc, Defers);
+ defr.age = deferage++;
+ defr.ex = ex;
+ defr.blockid = P.curblock.id;
+ defr.next = P.curblock.defers;
+ P.curblock.defers = defr;
+ return;
+
case lexmatch(P, &tok, :kw_switch);
return yield(pstswitch(P, tok.loc), yarg);
@@ -2317,25 +2393,30 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
}
}
-fn parseblock0(P *Parser) [#]Stmt {
+fn parseblock0(P *Parser) Block {
+ static id int = 1;
+ let block Block = { .id: id++, .defers: P.curblock ? P.curblock.defers : #null };
let sts Vec<Stmt> = {};
let tok Tok = {};
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
pushenv(P, env);
- while (tok = lexpeek(P)).t != '}' and tok.t != :kw_case and tok.t != ')' {
- if lexmatch(P, #null, ';') { continue; }
- fn pushstmt(st Stmt, arg *void) void {
- let sts *Vec<Stmt> = arg;
- sts->push(st);
+ with_tmpchange(P.curblock, &block) {
+ while (tok = lexpeek(P)).t != '}' and tok.t != :kw_case and tok.t != ')' {
+ if lexmatch(P, #null, ';') { continue; }
+ fn pushstmt(st Stmt, arg *void) void {
+ let sts *Vec<Stmt> = arg;
+ sts->push(st);
+ }
+ parsestmts(P, &pushstmt, &sts);
}
- parsestmts(P, &pushstmt, &sts);
}
popenv(P);
- return sts->move(P.alloc);
+ block.sts = sts->move(P.alloc);
+ return block;
}
-fn parseblock(P *Parser) [#]Stmt {
+fn parseblock(P *Parser) Block {
let b = parseblock0(P);
lexexpect(P, '}');
return b;
@@ -2429,7 +2510,8 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
}});
static id int = 0;
Fn.id = ++id;
- let decl = putdecl(P, loc, decl);
+ // TODO tlalloc necessary for templates. but it leaks some memory
+ let decl = putdecl_alloc(P, P.tlalloc, loc, decl);
decl.toplevel = toplevel;
if !lexmatch(P, #null, '{') {
@@ -2443,7 +2525,6 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
let varid = P.varid, loopid = P.loopid;
P.varid = 0;
P.loopid = 0;
- with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }) {
with_tmpchange(P.curfn, Fn) {
let env = mkenv(P.curenv, P.alloc);
defer envfree(env);
@@ -2455,12 +2536,13 @@ fn parsefn(P *Parser, loc Loc, toplevel bool, externp bool, name *const u8) *Dec
}});
}
}
- Fn.body = :Some(parseblock(P));
- popenv(P);
- // ir_genfn(P.irctx, Fn);
- llvm_genfn(externp, name, Fn);
- (as(*Arena)P.alloc.a)->destroy();
- }
+ with_tmpchange(P.alloc, &Allocator { &Arena {}, &Arena:allocf }) {
+ Fn.body = :Some(parseblock(P));
+ popenv(P);
+ // ir_genfn(P.irctx, Fn);
+ llvm_genfn(externp, name, Fn);
+ (as(*Arena)P.alloc.a)->destroy();
+ }
}
if toplevel {
llvm_addfn(decl);
diff --git a/src/targ.cff b/src/targ.cff
index 38fcb48..c5fc093 100644
--- a/src/targ.cff
+++ b/src/targ.cff
@@ -12,6 +12,7 @@ static const targs []const Targ = {
.sizesize: 8,
.f64align: 8,
.valistsize: 24, .valistalign: 8,
+ .valistllvmty: "{ i32, i32, i8*, i8* }",
.charsigned: #t,
.shortenum: #f,
}
diff --git a/src/type.cff b/src/type.cff
index 194ff01..3feb14c 100644
--- a/src/type.cff
+++ b/src/type.cff
@@ -295,14 +295,14 @@ extern fn typeof2(a *const Type, b *const Type) *const Type {
if uac == ubc {
return akonst ? a : b;
}
- if uac == ty_void {
- if bkonst and !akonst { return constifychild(a); }
- return a;
- }
- if ubc == ty_void {
- if akonst and !bkonst { return constifychild(b); }
+ if uac->is(:Void) {
+ if !bkonst and akonst { return constifychild(b); }
return b;
}
+ if ubc->is(:Void) {
+ if !akonst and bkonst { return constifychild(a); }
+ return a;
+ }
}
return #null;
}