diff options
| -rw-r--r-- | src/cffc.hff | 1 | ||||
| -rw-r--r-- | src/fmt.cff | 6 | ||||
| -rw-r--r-- | src/fold.cff | 68 | ||||
| -rw-r--r-- | src/main.cff | 1 | ||||
| -rw-r--r-- | src/parse.cff | 7 |
5 files changed, 80 insertions, 3 deletions
diff --git a/src/cffc.hff b/src/cffc.hff index 066c1f7..7dc9cfa 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -150,6 +150,7 @@ struct Parser { tokloc Loc, curloc Loc, eof bool, + error bool, is_header bool, peekchr Option<int>, peektok Option<Tok>, diff --git a/src/fmt.cff b/src/fmt.cff index 6707222..39b9e5b 100644 --- a/src/fmt.cff +++ b/src/fmt.cff @@ -387,6 +387,12 @@ extern fn warn(P *Parser, loc Loc, fmt *const u8, ...) void { } extern fn err(P *Parser, loc Loc, fmt *const u8, ...) void { + P.error = #t; + static nerr int = 0; + if nerr++ == 20 { + efmt("Aborting due to too many errors.\n"); + exit(1); + } let ap va_list #?; ap->start(fmt); vdiag(P, loc, "\e[31merror\e[0m", fmt, ap); diff --git a/src/fold.cff b/src/fold.cff index acfd613..2e7cae3 100644 --- a/src/fold.cff +++ b/src/fold.cff @@ -106,8 +106,8 @@ fn fbinary(ex *Expr) void { if ty->is(:Bool) { ty = typeof2(l.ty, r.ty); } - numcast(l, ty); - numcast(r, ty); + if isnumtype(l.ty) { numcast(l, ty); } + if isnumtype(r.ty) { numcast(r, ty); } if op == '/' and ty->is(:Int) and ri.i == 0 { // div/0 return; @@ -124,12 +124,35 @@ fn fbinary(ex *Expr) void { case op == '/' and ty->is(:Int); ei.i = li.i / ri.i; case op == '/' and ty->is(:Flo); *ef = *lf / *rf; case op == '%' and ty == ty_u64; ei.u = li.u % ri.u; + case op == '%' and ty->is(:Int); ei.i = li.i % ri.i; case op == '&' and ty->is(:Int); ei.i = li.i & ri.i; case op == '|' and ty->is(:Int); ei.i = li.i | ri.i; case op == '^' and ty->is(:Int); ei.i = li.i ^ ri.i; 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 op == '==' and ty->is(:Flo); *eb = *lf == *rf; + case op == '==' and ty->is(:Int); *eb = li.i == ri.i; + case op == '!=' and ty->is(:Flo); *eb = *lf != *rf; + case op == '!=' and ty->is(:Int); *eb = li.i != ri.i; + case op == '<' and ty->is(:Flo); *eb = *lf < *rf; + case op == '<' and ty == ty_u64; *eb = li.u < ri.u; + case op == '<' and ty->is(:Int); *eb = li.i < ri.i; + case op == '>' and ty->is(:Flo); *eb = *lf > *rf; + case op == '>' and ty == ty_u64; *eb = li.u > ri.u; + case op == '>' and ty->is(:Int); *eb = li.i > ri.i; + case op == '<=' and ty->is(:Flo); *eb = *lf <= *rf; + case op == '<=' and ty == ty_u64; *eb = li.u <= ri.u; + case op == '<=' and ty->is(:Int); *eb = li.i <= ri.i; + case op == '>=' and ty->is(:Flo); *eb = *lf >= *rf; + case op == '>=' and ty == ty_u64; *eb = li.u >= ri.u; + case op == '>=' and ty->is(:Int); *eb = li.i >= ri.i; + + case op == '+' and l.u.#tag == :StrLit and r.u.IntLit.u <= l.u.StrLit.#len; + assert(r.u.#tag == :IntLit, "str + ?"); + ex.u = :StrLit(l.u.StrLit[r.u.IntLit.u::l.u.StrLit.#len]); + return; + case else return; } @@ -140,6 +163,38 @@ fn fbinary(ex *Expr) void { } } +fn fcond(ex *Expr) void { + let test = ex.u.Cond.test, + t = ex.u.Cond.t, + f = ex.u.Cond.f; + let fo0 = fold(test); + if !fo0 { + return; + } + let ty = ex.ty; + *ex = test.u.BoolLit ? (do fold(t); *t;) : (do fold(f); *f;); + ex.ty = ty; +} + +fn findex(ex *Expr) void { + let l = ex.u.Index.lhs, + r = ex.u.Index.rhs; + let fl = fold(l), fr = fold(r); + if !fl or !fr { + return; + } + + if l.u.#tag == :StrLit { + if r.u.IntLit.u > l.u.StrLit.#len { + return; + } + ex.u = :IntLit{l.u.StrLit[r.u.IntLit.u]}; + } else { + assert(#f,"bad"); + } + +} + extern fn fold(ex *Expr) bool { switch ex.u.#tag { case :IntLit, :FloLit, :BoolLit; @@ -155,6 +210,12 @@ extern fn fold(ex *Expr) bool { case :BinOp; fbinary(ex); + case :Cond; + fcond(ex); + + case :Index; + findex(ex); + case else; return #f; } @@ -164,6 +225,9 @@ extern fn fold(ex *Expr) bool { numcast(ex, ex.ty); return #t; + case :StrLit, :NullLit, :EnumIni; + return #t; + case else; return #f; } diff --git a/src/main.cff b/src/main.cff index caebf9c..b8829a7 100644 --- a/src/main.cff +++ b/src/main.cff @@ -18,5 +18,6 @@ extern fn main(argc int, argv **u8) int { llvm_init(stdout); let decls = parse(&p); defer free(decls.#ptr); + if p.error { return 1; } } diff --git a/src/parse.cff b/src/parse.cff index a065739..5c3ac63 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -3060,6 +3060,8 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) case lexmatch(P, &tok, :kw_def); do { + let konst = lexmatch(P, #null, :kw_const); + let tok = lexexpect(P, :ident), name = tok.u.ident, ini Expr #?, @@ -3076,7 +3078,10 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) if !typematchestarg(ty, ini.ty) { err(P, ini.loc, "incompatible initializer (%t, expected %t)", ini.ty, ty); } - fold(&ini); + let f = fold(&ini); + if konst and !f { + err(P, ini.loc, "cannot evaluate expression at compile time"); + } decl = putdecl(P, tok.loc, { name, tok.loc, .u: :Def(ini) }); if yield { yield(decl, yarg); |