about summary refs log tree commit diff
path: root/src/rustc/middle/const_eval.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/rustc/middle/const_eval.rs')
-rw-r--r--src/rustc/middle/const_eval.rs167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/rustc/middle/const_eval.rs b/src/rustc/middle/const_eval.rs
new file mode 100644
index 00000000000..ca066b127bc
--- /dev/null
+++ b/src/rustc/middle/const_eval.rs
@@ -0,0 +1,167 @@
+import syntax::ast::*;
+
+// FIXME this doesn't handle big integer/float literals correctly (nor does
+// the rest of our literal handling)
+enum const_val {
+    const_float(float),
+    const_int(i64),
+    const_uint(u64),
+    const_str(str),
+}
+
+// FIXME: issue #1417
+fn eval_const_expr(tcx: middle::ty::ctxt, e: @expr) -> const_val {
+    import middle::ty;
+    fn fromb(b: bool) -> const_val { const_int(b as i64) }
+    alt check e.node {
+      expr_unary(neg, inner) {
+        alt check eval_const_expr(tcx, inner) {
+          const_float(f) { const_float(-f) }
+          const_int(i) { const_int(-i) }
+          const_uint(i) { const_uint(-i) }
+        }
+      }
+      expr_unary(not, inner) {
+        alt check eval_const_expr(tcx, inner) {
+          const_int(i) { const_int(!i) }
+          const_uint(i) { const_uint(!i) }
+        }
+      }
+      expr_binary(op, a, b) {
+        alt check (eval_const_expr(tcx, a), eval_const_expr(tcx, b)) {
+          (const_float(a), const_float(b)) {
+            alt check op {
+              add { const_float(a + b) } subtract { const_float(a - b) }
+              mul { const_float(a * b) } div { const_float(a / b) }
+              rem { const_float(a % b) } eq { fromb(a == b) }
+              lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) }
+              ge { fromb(a >= b) } gt { fromb(a > b) }
+            }
+          }
+          (const_int(a), const_int(b)) {
+            alt check op {
+              add { const_int(a + b) } subtract { const_int(a - b) }
+              mul { const_int(a * b) } div { const_int(a / b) }
+              rem { const_int(a % b) } and | bitand { const_int(a & b) }
+              or | bitor { const_int(a | b) } bitxor { const_int(a ^ b) }
+              lsl { const_int(a << b) } lsr { const_int(a >> b) }
+              asr { const_int(a >>> b) }
+              eq { fromb(a == b) } lt { fromb(a < b) }
+              le { fromb(a <= b) } ne { fromb(a != b) }
+              ge { fromb(a >= b) } gt { fromb(a > b) }
+            }
+
+          }
+          (const_uint(a), const_uint(b)) {
+            alt check op {
+              add { const_uint(a + b) } subtract { const_uint(a - b) }
+              mul { const_uint(a * b) } div { const_uint(a / b) }
+              rem { const_uint(a % b) } and | bitand { const_uint(a & b) }
+              or | bitor { const_uint(a | b) } bitxor { const_uint(a ^ b) }
+              lsl { const_int((a << b) as i64) }
+              lsr { const_int((a >> b) as i64) }
+              asr { const_int((a >>> b) as i64) }
+              eq { fromb(a == b) } lt { fromb(a < b) }
+              le { fromb(a <= b) } ne { fromb(a != b) }
+              ge { fromb(a >= b) } gt { fromb(a > b) }
+            }
+          }
+        }
+      }
+      expr_cast(base, _) {
+        let ety = ty::expr_ty(tcx, e);
+        let base = eval_const_expr(tcx, base);
+        alt check ty::get(ety).struct {
+          ty::ty_float(_) {
+            alt check base {
+              const_uint(u) { const_float(u as f64) }
+              const_int(i) { const_float(i as f64) }
+              const_float(_) { base }
+            }
+          }
+          ty::ty_uint(_) {
+            alt check base {
+              const_uint(_) { base }
+              const_int(i) { const_uint(i as u64) }
+              const_float(f) { const_uint(f as u64) }
+            }
+          }
+          ty::ty_int(_) | ty::ty_bool {
+            alt check base {
+              const_uint(u) { const_int(u as i64) }
+              const_int(_) { base }
+              const_float(f) { const_int(f as i64) }
+            }
+          }
+        }
+      }
+      expr_lit(lit) { lit_to_const(lit) }
+    }
+}
+
+fn lit_to_const(lit: @lit) -> const_val {
+    alt lit.node {
+      lit_str(s) { const_str(s) }
+      lit_int(n, _) { const_int(n) }
+      lit_uint(n, _) { const_uint(n) }
+      lit_float(n, _) { const_float(option::get(float::from_str(n))) }
+      lit_nil { const_int(0i64) }
+      lit_bool(b) { const_int(b as i64) }
+    }
+}
+
+fn compare_const_vals(a: const_val, b: const_val) -> int {
+  alt (a, b) {
+    (const_int(a), const_int(b)) {
+        if a == b {
+            0
+        } else if a < b {
+            -1
+        } else {
+            1
+        }
+    }
+    (const_uint(a), const_uint(b)) {
+        if a == b {
+            0
+        } else if a < b {
+            -1
+        } else {
+            1
+        }
+    }
+    (const_float(a), const_float(b)) {
+        if a == b {
+            0
+        } else if a < b {
+            -1
+        } else {
+            1
+        }
+    }
+    (const_str(a), const_str(b)) {
+        if a == b {
+            0
+        } else if a < b {
+            -1
+        } else {
+            1
+        }
+    }
+    _ {
+        fail "compare_const_vals: ill-typed comparison";
+    }
+  }
+}
+
+fn compare_lit_exprs(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> int {
+  compare_const_vals(eval_const_expr(tcx, a), eval_const_expr(tcx, b))
+}
+
+fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> bool {
+    compare_lit_exprs(tcx, a, b) == 0
+}
+
+fn lit_eq(a: @lit, b: @lit) -> bool {
+    compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0
+}