using System;
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
public class ConstantFold {
// (uint, uint)
// (int, int)
//
- static void DoConstantNumericPromotions (Binary.Operator oper,
+ static void DoConstantNumericPromotions (EmitContext ec, Binary.Operator oper,
ref Constant left, ref Constant right,
Location loc)
{
} else if (left is UIntConstant || right is UIntConstant){
//
// If either operand is of type uint, and the other
- // operand is of type sbyte, short or int, othe operands are
+ // operand is of type sbyte, short or int, the operands are
// converted to type long.
//
- if (!(left is UIntConstant))
- left = left.ToUInt (loc);
- else if (!(right is UIntConstant))
- right = right.ToUInt (loc);
+ Constant match, other;
+ if (left is UIntConstant){
+ other = right;
+ match = left;
+ } else {
+ other = left;
+ match = right;
+ }
+
+ // Nothing to do.
+ if (other is UIntConstant)
+ return;
+
+ if (other is SByteConstant || other is ShortConstant ||
+ other is IntConstant){
+ left = left.ToLong (loc);
+ right = right.ToLong (loc);
+ }
+
+ return;
+ } else if (left is EnumConstant || right is EnumConstant){
+ //
+ // If either operand is an enum constant, the other one must
+ // be implicitly convertable to that enum's underlying type.
+ //
+ EnumConstant match;
+ Constant other;
+ if (left is EnumConstant){
+ other = right;
+ match = (EnumConstant) left;
+ } else {
+ other = left;
+ match = (EnumConstant) right;
+ }
+
+ bool need_check = (other is EnumConstant) ||
+ ((oper != Binary.Operator.Addition) &&
+ (oper != Binary.Operator.Subtraction));
+
+ if (need_check &&
+ !Expression.ImplicitConversionExists (ec, match, other.Type)) {
+ Expression.Error_CannotConvertImplicit (loc, match.Type, other.Type);
+ left = null;
+ right = null;
+ return;
+ }
+
+ if (left is EnumConstant)
+ left = ((EnumConstant) left).Child;
+ if (right is EnumConstant)
+ right = ((EnumConstant) right).Child;
return;
+
} else {
//
// Force conversions to int32
if (right is EnumConstant)
right = ((EnumConstant) right).Child;
}
-
+
+ Type wrap_as;
+ Constant result = null;
switch (oper){
case Binary.Operator.BitwiseOr:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
break;
case Binary.Operator.BitwiseAnd:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
break;
case Binary.Operator.ExclusiveOr:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
break;
case Binary.Operator.Addition:
- Constant result;
bool left_is_string = left is StringConstant;
bool right_is_string = right is StringConstant;
// one is a string, and the other is not, then defer
// to runtime concatenation
//
+ wrap_as = null;
if (left_is_string || right_is_string){
if (left_is_string && right_is_string)
return new StringConstant (
//
// note that E operator + (E x, E y) is invalid
//
- Type wrap_as = null;
if (left is EnumConstant){
if (right is EnumConstant){
return null;
}
result = null;
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
return result;
case Binary.Operator.Subtraction:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ //
+ // handle "E operator - (E x, U y)"
+ // handle "E operator - (Y y, E x)"
+ // handle "U operator - (E x, E y)"
+ //
+ wrap_as = null;
+ if (left is EnumConstant){
+ if (right is EnumConstant){
+ if (left.Type == right.Type)
+ wrap_as = TypeManager.EnumToUnderlying (left.Type);
+ else
+ return null;
+ }
+ if (((EnumConstant) left).Child.Type != right.Type)
+ return null;
+
+ wrap_as = left.Type;
+ } else if (right is EnumConstant){
+ if (((EnumConstant) right).Child.Type != left.Type)
+ return null;
+ wrap_as = right.Type;
+ }
+
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
res = unchecked (((DoubleConstant) left).Value -
((DoubleConstant) right).Value);
- return new DoubleConstant (res);
+ result = new DoubleConstant (res);
} else if (left is FloatConstant){
float res;
res = unchecked (((FloatConstant) left).Value -
((FloatConstant) right).Value);
- return new FloatConstant (res);
+ result = new FloatConstant (res);
} else if (left is ULongConstant){
ulong res;
res = unchecked (((ULongConstant) left).Value -
((ULongConstant) right).Value);
- return new ULongConstant (res);
+ result = new ULongConstant (res);
} else if (left is LongConstant){
long res;
res = unchecked (((LongConstant) left).Value -
((LongConstant) right).Value);
- return new LongConstant (res);
+ result = new LongConstant (res);
} else if (left is UIntConstant){
uint res;
res = unchecked (((UIntConstant) left).Value -
((UIntConstant) right).Value);
- return new UIntConstant (res);
+ result = new UIntConstant (res);
} else if (left is IntConstant){
int res;
res = unchecked (((IntConstant) left).Value -
((IntConstant) right).Value);
- return new IntConstant (res);
+ result = new IntConstant (res);
} else {
throw new Exception ( "Unexepected input: " + left);
}
} catch (OverflowException){
Error_CompileTimeOverflow (loc);
}
- break;
+ if (wrap_as != null)
+ return new EnumConstant (result, wrap_as);
+ else
+ return result;
case Binary.Operator.Multiply:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
break;
case Binary.Operator.Division:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
break;
case Binary.Operator.Modulus:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
}
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
((StringConstant) right).Value);
}
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
return new BoolConstant (bool_res);
case Binary.Operator.LessThan:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
return new BoolConstant (bool_res);
case Binary.Operator.GreaterThan:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
return new BoolConstant (bool_res);
case Binary.Operator.GreaterThanOrEqual:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;
return new BoolConstant (bool_res);
case Binary.Operator.LessThanOrEqual:
- DoConstantNumericPromotions (oper, ref left, ref right, loc);
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
if (left == null || right == null)
return null;