aboutsummaryrefslogtreecommitdiff
path: root/src/fold.cff
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-18 17:39:25 +0200
committerlemon <lsof@mailbox.org>2022-08-18 17:39:25 +0200
commit9c485da5e1d955031fa2a3654bfc2ef814898167 (patch)
tree44e841ced0479d5ec82cca28733413784eedf52c /src/fold.cff
parentf0214ff61b5a94b9629db6f43d7a5b010bd4ffbc (diff)
lots of goodnes
Diffstat (limited to 'src/fold.cff')
-rw-r--r--src/fold.cff71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/fold.cff b/src/fold.cff
index 7b393e5..476e860 100644
--- a/src/fold.cff
+++ b/src/fold.cff
@@ -52,15 +52,86 @@ fn numcast(ex *Expr, to *const Type) void {
: :BoolLit;
}
+fn funary(ex *Expr) void {
+}
+
+fn fbinary(ex *Expr) void {
+ let l = ex.u.BinOp.lhs,
+ r = ex.u.BinOp.rhs;
+ let li = l.u.IntLit,
+ lf = l.u.FloLit,
+ ri = r.u.IntLit,
+ rf = r.u.FloLit,
+ ei = &ex.u.IntLit,
+ ef = &ex.u.FloLit,
+ eb = &ex.u.BoolLit;
+ let ty = unconstify(ex.ty);
+ let op = ex.u.BinOp.op;
+
+ if !fold(l) or !fold(r) {
+ return;
+ }
+ if ty->is(:Bool) {
+ ty = typeof2(l.ty, r.ty);
+ }
+ numcast(l, ty);
+ numcast(r, ty);
+
+ if op == '/' and ty->is(:Int) and ri.i == 0 { // div/0
+ return;
+ }
+ switch {
+ 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->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(: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(: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) and !ty.u.Int.sgn; ei.u = li.u >> ri.u;
+ case op == '>>' and ty->is(:Int); ei.i = li.i >> ri.i;
+ }
+
+ if !ex.ty->is(:Bool) {
+ numcast(ex, ty);
+ } else {
+ ex.u.#tag = :BoolLit;
+ }
+}
+
extern fn fold(ex *Expr) bool {
switch ex.u.#tag {
case :IntLit, :FloLit, :BoolLit;
numcast(ex, ex.ty);
return #t;
+
case :StrLit, :NullLit;
return #t;
+
+ case :UnOp;
+ funary(ex);
+
+ case :BinOp;
+ fbinary(ex);
+
case else;
return #f;
}
+ switch ex.u.#tag {
+ case :IntLit, :FloLit, :BoolLit;
+ numcast(ex, ex.ty);
+ return #t;
+
+ case else;
+ return #f;
+ }
}