aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cffc.hff1
-rw-r--r--src/fmt.cff6
-rw-r--r--src/fold.cff68
-rw-r--r--src/main.cff1
-rw-r--r--src/parse.cff7
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);