public override ABT.Expr GetExpr(ABT.Env env) {
// 1. semant operands
var left = SemantExpr(this.Left, ref env);
var right = SemantExpr(this.Right, ref env);
// 2. perform usual arithmetic conversion
Tuple<ABT.Expr, ABT.Expr, ABT.ExprTypeKind> castReturn = ABT.TypeCast.UsualArithmeticConversion(left, right);
left = castReturn.Item1;
right = castReturn.Item2;
var typeKind = castReturn.Item3;
var isConst = left.Type.IsConst || right.Type.IsConst;
var isVolatile = left.Type.IsVolatile || right.Type.IsVolatile;
// 3. if both operands are constants
if (left.IsConstExpr && right.IsConstExpr) {
switch (typeKind) {
case ABT.ExprTypeKind.ULONG:
return new ABT.ConstULong(OperateULong(((ABT.ConstULong)left).Value, ((ABT.ConstULong)right).Value), env);
case ABT.ExprTypeKind.LONG:
return new ABT.ConstLong(OperateLong(((ABT.ConstLong)left).Value, ((ABT.ConstLong)right).Value), env);
default:
throw new InvalidOperationException("Expected long or unsigned long.");
}
}
// 4. if not both operands are constants
switch (typeKind) {
case ABT.ExprTypeKind.ULONG:
return ConstructExpr(left, right, new ABT.ULongType(isConst, isVolatile));
case ABT.ExprTypeKind.LONG:
return ConstructExpr(left, right, new ABT.ULongType(isConst, isVolatile));
default:
throw new InvalidOperationException("Expected long or unsigned long.");
}
}
}