aboutsummaryrefslogtreecommitdiff
path: root/src/fold.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/fold.cff')
-rw-r--r--src/fold.cff68
1 files changed, 66 insertions, 2 deletions
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;
}