diff options
| author | 2022-08-18 17:39:25 +0200 | |
|---|---|---|
| committer | 2022-08-18 17:39:25 +0200 | |
| commit | 9c485da5e1d955031fa2a3654bfc2ef814898167 (patch) | |
| tree | 44e841ced0479d5ec82cca28733413784eedf52c /src/fold.cff | |
| parent | f0214ff61b5a94b9629db6f43d7a5b010bd4ffbc (diff) | |
lots of goodnes
Diffstat (limited to 'src/fold.cff')
| -rw-r--r-- | src/fold.cff | 71 |
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; + } } |