initial addition and subtraction for bytes and ints

This commit is contained in:
llogiq 2015-08-13 14:22:05 +02:00
parent 5bdd3ed81f
commit 6aa36e9deb

View File

@ -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<Constant> {
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<Constant> {
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<F>(cx: &Context, left: &Expr, right: &Expr, op: F)
-> Option<Constant>
where F: FnMut(ConstantVariant, ConstantVariant) -> Option<ConstantVariant> {