aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap/types.c1
-rw-r--r--src/cffc.hff7
-rw-r--r--src/parse.cff43
-rw-r--r--src/type.cff51
4 files changed, 98 insertions, 4 deletions
diff --git a/bootstrap/types.c b/bootstrap/types.c
index 788f001..fb5b50b 100644
--- a/bootstrap/types.c
+++ b/bootstrap/types.c
@@ -320,6 +320,7 @@ arraydecay(const struct type *ty) {
return ty;
ty2.t = TYptr;
+ ty2.align = ty2.size = g_targ.ptrsize;
return interntype(ty2);
}
diff --git a/src/cffc.hff b/src/cffc.hff
index 32683eb..2252373 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -109,6 +109,8 @@ struct Parser {
curfile *const u8,
curfn *Fn,
curenv *Env,
+ curloop int,
+ loopid int,
tokloc Loc,
curloc Loc,
eof bool,
@@ -157,13 +159,16 @@ struct Stmt {
u enum union {
Block [#]Stmt,
If struct { test Expr, t [#]Stmt, f [#]Stmt },
- While struct { test Expr, body [#]Stmt },
+ While struct { test Expr, body [#]Stmt, id int },
For struct {
ini [#]Stmt,
test Expr,
next Option<Expr>,
body [#]Stmt,
+ id int,
},
+ Break #{loopid} int,
+ Continue #{loopid} int,
Return Option<Expr>,
Expr Expr,
Decl *Decl,
diff --git a/src/parse.cff b/src/parse.cff
index 34e7943..c2c1817 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -724,6 +724,8 @@ fn islvalue(ex Expr) bool {
return decl.u.#tag == :Let or decl.u.#tag == :Static;
case UnOp u;
return u.op == :deref;
+ case Index;
+ return #t;
}
return #f;
}
@@ -735,15 +737,20 @@ fn pexprimary(P *Parser) Expr {
switch tok.t {
case :int, :chr;
return { tok.loc, tok.ty, .u: :IntLit { tok.u.int }};
+
case :flo;
return { tok.loc, tok.ty, .u: :FloLit(tok.u.flo) };
+
case :bool;
return { tok.loc, ty_bool, .u: :BoolLit(tok.u.bool) };
+
case :null;
return { tok.loc, ty_voidptr, .u: :NullLit };
+
case :str;
let ty = mkarrtype(tok.u.str.#len + 1, #t, ty_u8);
return { tok.loc, ty, .u: :StrLit(tok.u.str) };
+
case :ident;
let ident = tok.u.ident;
let decl = finddecl(P, ident);
@@ -758,10 +765,19 @@ fn pexprimary(P *Parser) Expr {
case Static var;
return { tok.loc, var.ty, .u: :Symbol(decl) };
}
+ case :kw_sizeof;
+ if lexmatch(P, &tok, '(') {
+ let ex = parseexpr(P);
+ lexexpect(P, ')');
+ return { ex.loc, ty_usize, :IntLit { ex.ty.size }};
+ }
+ return { tok.loc, ty_usize, :IntLit { parsetype(P).size }};
+
case '(';
let ex = parseexpr(P);
lexexpect(P, ')');
return ex;
+
case else;
fatal(P, tok.loc, "expected expression (near %qT)", tok);
}
@@ -1177,8 +1193,11 @@ fn pstwhile(P *Parser) Stmt {
err(P, test.loc, "while condition must be bool or pointer (%t)", test.ty);
}
lexexpect(P, '{');
- let t = parseblock(P);
- return { loc, :While { test, t }};
+ let t [#]Stmt #?;
+ with_tmpchange(P.curloop, ++P.loopid,
+ t = parseblock(P);
+ )
+ return { loc, :While { test, t, P.loopid }};
}
fn pstfor(P *Parser) Stmt {
@@ -1215,7 +1234,11 @@ fn pstfor(P *Parser) Stmt {
next = :Some(parseexpr(P));
lexexpect(P, '{');
}
- return { loc, :For { ini, test, next, parseblock(P) }};
+ let body [#]Stmt #?;
+ with_tmpchange(P.curloop, ++P.loopid,
+ body = parseblock(P);
+ )
+ return { loc, :For { ini, test, next, body, P.loopid }};
}
fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
@@ -1241,6 +1264,20 @@ fn parsestmts(P *Parser, yield StmtYielder, yarg *void) void {
case lexmatch(P, &tok, :kw_for);
return yield(pstfor(P), yarg);
+ case lexmatch(P, &tok, :kw_break);
+ if P.curloop == 0 {
+ err(P, tok.loc, "break outside loop");
+ }
+ lexexpect(P, ';');
+ return yield({ tok.loc, :Break(P.curloop) }, yarg);
+
+ case lexmatch(P, &tok, :kw_continue);
+ if P.curloop == 0 {
+ err(P, tok.loc, "continue outside loop");
+ }
+ lexexpect(P, ';');
+ return yield({ tok.loc, :Continue(P.curloop) }, yarg);
+
case else;
let ex = parseexpr(P);
lexexpect(P, ';');
diff --git a/src/type.cff b/src/type.cff
index 1d224cc..e3989c7 100644
--- a/src/type.cff
+++ b/src/type.cff
@@ -202,6 +202,31 @@ fn rank2numtype(r int) *const Type {
return *types[r];
}
+fn arraydecay(ty *const Type) *const Type {
+ switch ty.u {
+ case Arr arr; return mkptrtype(arr.child);
+ case else; return ty;
+ }
+}
+
+fn constifychild(ty *const Type) *const Type {
+ let ty2 = *ty;
+ switch ty.u {
+ case Ptr child;
+ let cchild = constify(child);
+ if child == cchild { return ty; }
+ ty2.u.Ptr = child;
+ return interntype(ty2);
+ case Slice child;
+ let cchild = constify(child);
+ if child == cchild { return ty; }
+ ty2.u.Slice = child;
+ return interntype(ty2);
+ case else;
+ assert(#f, "constifychild: not ptr or slice");
+ }
+}
+
extern fn typeof2(a *const Type, b *const Type) *const Type {
if a == b and !a->is(:Int) {
return a;
@@ -217,5 +242,31 @@ extern fn typeof2(a *const Type, b *const Type) *const Type {
if a == unconstify(b) {
return b;
}
+ if a->is(:Arr) and b->is(:Arr) {
+ a = arraydecay(a);
+ }
+ if a->is(:Ptr) and b->is(:Arr) {
+ b = arraydecay(b);
+ }
+ if a->is(:Arr) and b->is(:Ptr) {
+ a = arraydecay(a);
+ }
+ if a.u.#tag == b.u.#tag and (a->is(:Ptr) or a->is(:Slice)) {
+ let akonst = a.u.Ptr.konst,
+ bkonst = b.u.Ptr.konst,
+ uac = unconstify(a.u.Ptr),
+ ubc = unconstify(b.u.Ptr);
+ 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); }
+ return b;
+ }
+ }
return #null;
}