public static void EmitNumericConversion(this CodeGenerator cg, TypeSymbol from, TypeSymbol to, bool @checked = false) { if (to.IsEnumType()) { to = to.GetEnumUnderlyingType(); } if (from.IsEnumType()) { from = from.GetEnumUnderlyingType(); } var fromcode = from.PrimitiveTypeCode; var tocode = to.PrimitiveTypeCode; if (tocode == Microsoft.Cci.PrimitiveTypeCode.Boolean) { switch (fromcode) { case Microsoft.Cci.PrimitiveTypeCode.Float32: // Template: !(STACK == 0.0f) cg.Builder.EmitSingleConstant(0.0f); cg.Builder.EmitOpCode(ILOpCode.Ceq); cg.EmitLogicNegation(); return; case Microsoft.Cci.PrimitiveTypeCode.Float64: // Template: !(STACK == 0.0) cg.Builder.EmitDoubleConstant(0.0); cg.Builder.EmitOpCode(ILOpCode.Ceq); cg.EmitLogicNegation(); return; } // otherwise, // treat boolean as to int32 conversion tocode = Microsoft.Cci.PrimitiveTypeCode.Int32; } if (fromcode == Microsoft.Cci.PrimitiveTypeCode.Boolean) { fromcode = Microsoft.Cci.PrimitiveTypeCode.Int32; } // cg.Builder.EmitNumericConversion(fromcode, tocode, @checked); }
/// <summary> /// Emits check for values equality. /// Lefts <c>bool</c> on top of evaluation stack. /// </summary> internal static TypeSymbol EmitEquality(CodeGenerator cg, TypeSymbol xtype, BoundExpression right) { TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Boolean: // bool == y.ToBoolean() cg.EmitConvert(right, cg.CoreTypes.Boolean); cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; case SpecialType.System_Int32: // i4 -> i8 cg.Builder.EmitOpCode(ILOpCode.Conv_i8); goto case SpecialType.System_Int64; case SpecialType.System_Int64: ytype = cg.Emit(right); // if (ytype.SpecialType == SpecialType.System_Int32) { cg.Builder.EmitOpCode(ILOpCode.Conv_i8); // i4 -> i8 ytype = cg.CoreTypes.Long; } // if (ytype.SpecialType == SpecialType.System_Int64) { // i8 == i8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_double) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Boolean) { // i8 == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_bool) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_String) { // i8 == string return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_long_string) .Expect(SpecialType.System_Boolean); } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(i8, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_long_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|long|int -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 == r8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if (ytype.SpecialType == SpecialType.System_String) { // r8 == string return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_double_string) .Expect(SpecialType.System_Boolean); } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(double, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_double_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; case SpecialType.System_String: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Int32) { // i4 -> i8 cg.Builder.EmitOpCode(ILOpCode.Conv_i8); ytype = cg.CoreTypes.Long; } if (ytype.SpecialType == SpecialType.System_Int64) { // string == i8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Boolean) { // string == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_bool) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // string == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Ceq_string_double) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_String) { // compare(string, string) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_string).Expect(SpecialType.System_Int32); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; } // value ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(string, value) == 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_value); cg.EmitLogicNegation(); return cg.CoreTypes.Boolean; //case SpecialType.System_Object: // goto default; default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // number == i8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // number == r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_double) .Expect(SpecialType.System_Boolean); } else if (ytype == cg.CoreTypes.PhpNumber) { // number == number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_number) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // number == value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Eq_number_PhpValue) .Expect(SpecialType.System_Boolean); } } else { // TODO: xtype: PhpArray, ... xtype = cg.EmitConvertToPhpValue(xtype, 0); // TODO: overloads for type of <right> ytype = cg.EmitConvertToPhpValue(cg.Emit(right), right.TypeRefMask); // value == value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Eq_PhpValue_PhpValue) .Expect(SpecialType.System_Boolean); } } }
internal override TypeSymbol Emit(CodeGenerator cg) { Debug.Assert(this.Access.IsRead || this.Access.IsNone); // TypeSymbol returned_type; if (UsesOperatorMethod) { throw new NotImplementedException(); // call this.Operator(Left, Right) } switch (this.Operation) { #region Arithmetic Operations case Operations.Add: returned_type = (cg.IsLongOnly(this.TypeRefMask)) ? cg.CoreTypes.Long.Symbol : this.Access.TargetType; returned_type = EmitAdd(cg, Left, Right, returned_type); break; case Operations.Sub: //Template: "x - y" Operators.Subtract(x,y) [overloads] returned_type = EmitSub(cg, Left, Right, this.Access.TargetType); break; case Operations.Div: //Template: "x / y" returned_type = EmitDivision(cg); break; case Operations.Mul: //Template: "x * y" returned_type = EmitMultiply(cg); break; case Operations.Pow: //Template: "x ** y" returned_type = EmitPow(cg); break; case Operations.Mod: //Template: "x % y" Operators.Remainder(x,y) //codeGenerator.EmitBoxing(node.LeftExpr.Emit(codeGenerator)); //ro_typecode = node.RightExpr.Emit(codeGenerator); //switch (ro_typecode) //{ // case PhpTypeCode.Integer: // returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Int32); // break; // default: // codeGenerator.EmitBoxing(ro_typecode); // returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Object); // break; //} //break; throw new NotImplementedException(); case Operations.ShiftLeft: //// LOAD Operators.ShiftLeft(box left, box right); //codeGenerator.EmitBoxing(node.LeftExpr.Emit(codeGenerator)); //codeGenerator.EmitBoxing(node.RightExpr.Emit(codeGenerator)); //returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftLeft); //break; throw new NotImplementedException(); case Operations.ShiftRight: //// LOAD Operators.ShiftRight(box left, box right); //codeGenerator.EmitBoxing(node.LeftExpr.Emit(codeGenerator)); //codeGenerator.EmitBoxing(node.RightExpr.Emit(codeGenerator)); //returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftRight); //break; throw new NotImplementedException(); #endregion #region Boolean and Bitwise Operations case Operations.And: returned_type = EmitBinaryBooleanOperation(cg, true); break; case Operations.Or: returned_type = EmitBinaryBooleanOperation(cg, false); break; case Operations.Xor: returned_type = EmitBinaryXor(cg); break; case Operations.BitAnd: returned_type = EmitBitAnd(cg, Left, Right); break; case Operations.BitOr: returned_type = EmitBitOr(cg, Left, Right); break; case Operations.BitXor: //returned_typecode = EmitBitOperation(node, codeGenerator, Operators.BitOp.Xor); //break; throw new NotImplementedException(); #endregion #region Comparing Operations case Operations.Equal: returned_type = EmitEquality(cg); break; case Operations.NotEqual: EmitEquality(cg); cg.EmitLogicNegation(); returned_type = cg.CoreTypes.Boolean; break; case Operations.GreaterThan: returned_type = EmitLtGt(cg, false); break; case Operations.LessThan: returned_type = EmitLtGt(cg, true); break; case Operations.GreaterThanOrEqual: // template: !(LessThan) returned_type = EmitLtGt(cg, true); cg.EmitLogicNegation(); break; case Operations.LessThanOrEqual: // template: !(GreaterThan) returned_type = EmitLtGt(cg, false); cg.EmitLogicNegation(); break; case Operations.Identical: // Left === Right returned_type = EmitStrictEquality(cg); break; case Operations.NotIdentical: // ! (Left === Right) returned_type = EmitStrictEquality(cg); cg.EmitLogicNegation(); break; #endregion default: throw ExceptionUtilities.Unreachable; } // switch (Access.Flags) { case AccessMask.Read: // Result is read, do nothing. Debug.Assert(returned_type.SpecialType != SpecialType.System_Void); break; case AccessMask.None: // Result is not read, pop the result cg.EmitPop(returned_type); returned_type = cg.CoreTypes.Void; break; } // return returned_type; }
public static void EmitNumericConversion(this CodeGenerator cg, TypeSymbol from, TypeSymbol to, bool @checked = false) { if (to.IsEnumType()) { to = to.GetEnumUnderlyingType(); } if (from.IsEnumType()) { from = from.GetEnumUnderlyingType(); } if (from.SpecialType == SpecialType.System_Decimal) { // explicit numeric conversion, treating decimal as double // (double)System.Decimal cg.EmitCall( ILOpCode.Call, (MethodSymbol)cg.DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_Decimal__op_Explicit_ToDouble)); cg.Builder.EmitOpCode(ILOpCode.Conv_r8); // from = cg.CoreTypes.Double; } if (to.SpecialType == SpecialType.System_Decimal) { EmitNumericConversionToDecimal(cg, from, @checked); return; } var fromcode = from.PrimitiveTypeCode; var tocode = to.PrimitiveTypeCode; if (fromcode == tocode) { return; } if (tocode == Microsoft.Cci.PrimitiveTypeCode.Boolean) { switch (fromcode) { case Microsoft.Cci.PrimitiveTypeCode.Float32: // Template: !(STACK == 0.0f) cg.Builder.EmitSingleConstant(0.0f); cg.Builder.EmitOpCode(ILOpCode.Ceq); cg.EmitLogicNegation(); return; case Microsoft.Cci.PrimitiveTypeCode.Float64: // Template: !(STACK == 0.0) cg.Builder.EmitDoubleConstant(0.0); cg.Builder.EmitOpCode(ILOpCode.Ceq); cg.EmitLogicNegation(); return; } // otherwise, // treat boolean as to int32 conversion tocode = Microsoft.Cci.PrimitiveTypeCode.Int32; } if (fromcode == Microsoft.Cci.PrimitiveTypeCode.Boolean) { fromcode = Microsoft.Cci.PrimitiveTypeCode.Int32; } // cg.Builder.EmitNumericConversion(fromcode, tocode, @checked); }