From 6aa36e9deb9191ae8414b433d49c71ac37475cea Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 13 Aug 2015 14:22:05 +0200 Subject: [PATCH] initial addition and subtraction for bytes and ints --- src/const.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/src/const.rs b/src/const.rs index cef2cd7f9fc..bc53c1062dc 100644 --- a/src/const.rs +++ b/src/const.rs @@ -222,11 +222,75 @@ fn neg_float_str(s: &InternedString) -> Cow<'static, str> { } } +fn is_negative(ty: LitIntType) -> bool { + match ty { + SignedIntLit(_, sign) | UnsuffixedIntLit(sign) => sign == Minus, + UnsignedIntLit(_) => false, + } +} + +fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option(LitIntType) { + match (l, r) { + (SignedIntLit(lty, _), SignedIntLit(rty, _)) => if lty == rty { + Some(SignedIntLit(lty, s)) } else { None }, + (UnsignedIntLit(lty), UnsignedIntLit(rty)) => + if Sign == Plus && lty == rty { + Some(UnsignedIntLit(lty)) + } else { None }, + (UnsuffixedIntLit(_), UnsuffixedIntLit(_)) => UnsuffixedIntLit(s), + (SignedIntLit(lty, _), UnsuffixedIntLit(_)) => SignedIntLit(lty, s), + (UnsignedIntLit(lty), UnsuffixedIntLit(rs)) => if rs == Plus { + Some(UnsignedIntLit(lty)) } else { None }, + (UnsuffixedIntLit(_), SignedIntLit(rty, _)) => SignedIntLit(rty, s), + (UnsuffixedIntLit(ls), UnsignedIntLit(rty)) => if ls == Plus { + Some(UnsignedIntLit(rty)) } else { None }, + _ => None, + } +} + fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) -> Option { match op.node { - //BiAdd, - //BiSub, + BiAdd => constant_binop_apply(cx, left, right, |l, r| + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => + l8.checked_add(r8).map(|v| ConstantByte(v)), + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + if ln == rn { + unify_int_type(lty, rty, if ln { Minus } else { Plus }) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))) + } else { + if ln { + add_neg_int(r64, rty, l64, lty) + } else { + add_neg_int(l64, lty, r64, rty) + } + } + }, + // TODO: float + _ => None + }), + BiSub => constant_binop_apply(cx, left, right, |l, r| + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => if r8 > l8 { + None } else { Some(ConstantByte(l8 - r8)) }, + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + match (ln, rn) { + (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), + (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), + (true, false) => unify_int_type(lty, rty, Minus) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))), + (false, true) => unify_int_type(lty, rty, Plus) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))), + } + }, + _ => None, + }), //BiMul, //BiDiv, //BiRem, @@ -247,6 +311,21 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) } } +fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> + Some(Constant) { + if neg > pos { + unify_int_type(nty, pty, Minus).map(|ty| ConstantInt(neg - pos, ty)) + } else { + unify_int_type(nty, pty, Plus).map(|ty| ConstantInt(pos - neg, ty)) + } +} + +fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: Bool) -> + Option { + unify_int_type(lty, rty, if neg { Minus } else { Plus }).and_then( + |ty| l64.checked_sub(r64).map(|v| ConstantInt(v, ty))) +} + fn constant_binop_apply(cx: &Context, left: &Expr, right: &Expr, op: F) -> Option where F: FnMut(ConstantVariant, ConstantVariant) -> Option {