diff options
| -rw-r--r-- | bootstrap/types.c | 1 | ||||
| -rw-r--r-- | src/cffc.hff | 7 | ||||
| -rw-r--r-- | src/parse.cff | 43 | ||||
| -rw-r--r-- | src/type.cff | 51 |
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; } |