private EmitConvertIntToLong ( TypeSymbol stack ) : TypeSymbol | ||
stack | TypeSymbol | New type on top of stack. |
return | TypeSymbol |
/// <summary> /// Emits subtraction operator. /// </summary> internal static TypeSymbol EmitSub(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> int64 TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // i8 - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 - r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_double) .Expect(cg.CoreTypes.Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_number) .Expect(cg.CoreTypes.PhpNumber); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // i8 - value : value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_long_value) .Expect(cg.CoreTypes.PhpNumber); } case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 - r8 : r8 il.EmitOpCode(ILOpCode.Sub); return cg.CoreTypes.Double; } throw new NotImplementedException($"Sub(double, {ytype.Name})"); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // number - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // number - r8 : double return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // number - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_number_number) .Expect(cg.CoreTypes.PhpNumber); } throw new NotImplementedException($"Sub(PhpNumber, {ytype.Name})"); } else if (xtype == cg.CoreTypes.PhpValue) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // value - i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // value - r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // value - number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // value - value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Subtract_value_value) .Expect(cg.CoreTypes.PhpNumber); } throw new NotImplementedException($"Sub(PhpValue, {ytype.Name})"); } throw new NotImplementedException($"Sub({xtype.Name},...)"); } }
/// <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); } } }
/// <summary> /// Emits <c>+</c> operator suitable for actual operands. /// </summary> internal static TypeSymbol EmitAdd(CodeGenerator cg, TypeSymbol xtype, BoundExpression Right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> long // if (xtype == cg.CoreTypes.PhpNumber) { var ytype = cg.EmitConvertIntToLong(cg.Emit(Right)); // int|bool -> long if (ytype == cg.CoreTypes.PhpNumber) { // number + number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_number_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // number + r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_number_double) .Expect(SpecialType.System_Double); } else if (ytype.SpecialType == SpecialType.System_Int64) { // number + long : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_number_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // number + value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_number_value) .Expect(cg.CoreTypes.PhpNumber); } // throw new NotImplementedException($"Add(number, {ytype.Name})"); } else if (xtype.SpecialType == SpecialType.System_Double) { var ytype = cg.EmitConvertNumberToDouble(Right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 + r8 : r8 il.EmitOpCode(ILOpCode.Add); return cg.CoreTypes.Double; } else if (ytype == cg.CoreTypes.PhpValue) { // r8 + value : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_double_value) .Expect(SpecialType.System_Double); } // throw new NotImplementedException($"Add(double, {ytype.Name})"); } else if (xtype.SpecialType == SpecialType.System_Int64) { var ytype = cg.EmitConvertIntToLong(cg.Emit(Right)); // int|bool -> long if (ytype.SpecialType == SpecialType.System_Int64) { if (resultTypeOpt != null) { if (resultTypeOpt.SpecialType == SpecialType.System_Int64) { // (long)(i8 + i8 : number) il.EmitOpCode(ILOpCode.Add); return cg.CoreTypes.Long; } } // i8 + i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_long_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 + r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_long_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 + number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_long_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // i8 + value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_long_value) .Expect(cg.CoreTypes.PhpNumber); } // throw new NotImplementedException($"Add(int64, {ytype.Name})"); } else if (xtype == cg.CoreTypes.PhpValue) { var ytype = cg.EmitConvertIntToLong(cg.Emit(Right)); // int|bool -> long // PhpString -> String if (ytype == cg.CoreTypes.PhpString) { cg.EmitConvertToString(ytype, 0); // continue ... } if (ytype.SpecialType == SpecialType.System_Int64) { // value + i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // value + r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.String) { // value + string : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_string) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpNumber) { // value + number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // value + value : value return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Add_value_value) .Expect(cg.CoreTypes.PhpValue); } // throw new NotImplementedException($"Add(PhpValue, {ytype.Name})"); } // throw new NotImplementedException($"Add({xtype.Name}, ...)"); }
internal static TypeSymbol EmitPow(CodeGenerator cg, TypeSymbol xtype, FlowAnalysis.TypeRefMask xtype_hint, BoundExpression right) { var il = cg.Builder; TypeSymbol ytype; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> long switch (xtype.SpecialType) { case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // int|bool -> long if (ytype.SpecialType == SpecialType.System_Int64) { // i8 ** i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_long); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 ** number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_number); } // y -> PhpValue cg.EmitConvert(ytype, right.TypeRefMask, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // i8 ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_long_value); case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // int|bool|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_double_double); } // y -> PhpValue cg.EmitConvert(ytype, right.TypeRefMask, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // r8 ** value : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_double_value); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // int|bool -> long if (ytype == cg.CoreTypes.Double) { // number ** r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_double); } if (ytype.SpecialType == SpecialType.System_Int64) { // y -> number ytype = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Create_Long); } if (ytype == cg.CoreTypes.PhpNumber) { // number ** number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_number); } // y -> PhpValue ytype = cg.EmitConvertToPhpValue(ytype, right.TypeRefMask); // number ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_number_value); } // x -> PhpValue xtype = cg.EmitConvertToPhpValue(xtype, xtype_hint); cg.EmitConvert(right, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // value ** value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Pow_value_value); } }
internal static TypeSymbol EmitDiv(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> int64 TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { il.EmitOpCode(ILOpCode.Div); return xtype; // r8 } // double / value : double cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_double_PhpValue); case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype == cg.CoreTypes.PhpNumber) { // long / number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Division_long_number) .Expect(cg.CoreTypes.PhpNumber); } // long / value : number cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_long_PhpValue); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype == cg.CoreTypes.PhpNumber) { // nmumber / number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Division_number_number) .Expect(cg.CoreTypes.PhpNumber); } } // x -> PhpValue xtype = cg.EmitConvertToPhpValue(xtype, 0); cg.EmitConvert(right, cg.CoreTypes.PhpValue); ytype = cg.CoreTypes.PhpValue; // value / value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Div_PhpValue_PhpValue); } }
internal static TypeSymbol EmitMul(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, TypeSymbol resultTypeOpt = null) { var il = cg.Builder; xtype = cg.EmitConvertIntToLong(xtype); // int|bool -> int64 TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 * r8 : r8 il.EmitOpCode(ILOpCode.Mul); return xtype; // r8 } else if (ytype == cg.CoreTypes.PhpValue) { // r8 * value : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_double_value) .Expect(SpecialType.System_Double); } // throw new NotImplementedException($"Mul(double, {ytype.Name})"); case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { // i8 * i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_long_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 * r8 : r8 return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_long_double) .Expect(SpecialType.System_Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // i8 * number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_long_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // i8 * value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_long_value) .Expect(cg.CoreTypes.PhpNumber); } // throw new NotImplementedException($"Mul(int64, {ytype.Name})"); default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); if (ytype.SpecialType == SpecialType.System_Int64) { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype.SpecialType == SpecialType.System_Double) { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_double) .Expect(cg.CoreTypes.Double); } else if (ytype == cg.CoreTypes.PhpNumber) { // number * number : number cg.EmitConvertToPhpNumber(ytype, right.TypeRefMask); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpValue) { // number * value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_value) .Expect(cg.CoreTypes.PhpNumber); } else { // TODO: unconvertible // number * number : number cg.EmitConvertToPhpNumber(ytype, right.TypeRefMask); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_number_number) .Expect(cg.CoreTypes.PhpNumber); } // throw new NotImplementedException($"Mul(PhpNumber, {ytype.Name})"); } else if (xtype == cg.CoreTypes.PhpValue) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype == cg.CoreTypes.PhpValue) { // value * value : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_value_value) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.PhpNumber) { // value * number : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_value_number) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.Long) { // value * i8 : number return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_value_long) .Expect(cg.CoreTypes.PhpNumber); } else if (ytype == cg.CoreTypes.Double) { // value * r8 : double return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpNumber.Mul_value_double) .Expect(SpecialType.System_Double); } // throw new NotImplementedException($"Mul(PhpValue, {ytype.Name})"); } // throw new NotImplementedException($"Mul({xtype.Name}, ...)"); } }
/// <summary> /// Emits comparison operator pushing <c>bool</c> (<c>i4</c> of value <c>0</c> or <c>1</c>) onto the evaluation stack. /// </summary> /// <returns>Resulting type code pushed onto the top of evaliuation stack.</returns> internal static TypeSymbol EmitLtGt(CodeGenerator cg, TypeSymbol xtype, BoundExpression right, bool lt) { TypeSymbol ytype; var il = cg.Builder; switch (xtype.SpecialType) { case SpecialType.System_Void: // Operators.CompareNull(value) throw new NotImplementedException(); case SpecialType.System_Int32: // i4 -> i8 il.EmitOpCode(ILOpCode.Conv_i8); goto case SpecialType.System_Int64; case SpecialType.System_Int64: ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype.SpecialType == SpecialType.System_Int64) { il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } else if (ytype.SpecialType == SpecialType.System_Double) { // i8 <> r8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.Operators.Clt_long_double : cg.CoreMethods.Operators.Cgt_long_double); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(i8, value) <> 0 cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_long_value); il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } return cg.CoreTypes.Boolean; case SpecialType.System_Double: ytype = cg.EmitConvertNumberToDouble(right); // bool|int|long|number -> double if (ytype.SpecialType == SpecialType.System_Double) { // r8 <> r8 il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } else { // compare(r8, value) ytype = cg.EmitConvertToPhpValue(ytype, 0); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_double_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); } return cg.CoreTypes.Boolean; case SpecialType.System_String: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_String) { // compare(string, string) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_string); } else if (ytype.SpecialType == SpecialType.System_Int64) { // compare(string, long) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_long); } else if (ytype.SpecialType == SpecialType.System_Double) { // compare(string, double) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_double); } else { // compare(string, value) ytype = cg.EmitConvertToPhpValue(ytype, 0); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_string_value); } // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; case SpecialType.System_Boolean: cg.EmitConvert(right, cg.CoreTypes.Boolean); ytype = cg.CoreTypes.Boolean; // compare(bool, bool) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_bool_bool); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; default: if (xtype == cg.CoreTypes.PhpNumber) { ytype = cg.EmitConvertIntToLong(cg.Emit(right)); // bool|int -> long if (ytype.SpecialType == SpecialType.System_Int64) { // number <> i8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_long : cg.CoreMethods.PhpNumber.gt_number_long) .Expect(SpecialType.System_Boolean); } else if (ytype.SpecialType == SpecialType.System_Double) { // number <> r8 return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_double : cg.CoreMethods.PhpNumber.gt_number_double) .Expect(SpecialType.System_Boolean); } else if (ytype == cg.CoreTypes.PhpNumber) { // number <> number return cg.EmitCall(ILOpCode.Call, lt ? cg.CoreMethods.PhpNumber.lt_number_number : cg.CoreMethods.PhpNumber.gt_number_number) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // compare(number, value) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_number_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); // +1 on stack il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; } } else { xtype = cg.EmitConvertToPhpValue(xtype, 0); ytype = cg.Emit(right); // TODO: if (ytype.SpecialType == SpecialType.System_Boolean) ... // TODO: if (ytype.SpecialType == SpecialType.System_Int64) ... // TODO: if (ytype.SpecialType == SpecialType.System_String) ... // TODO: if (ytype.SpecialType == SpecialType.System_Double) ... // compare(value, value) ytype = cg.EmitConvertToPhpValue(ytype, right.TypeRefMask); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.Compare_value_value); // <> 0 il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); il.EmitOpCode(lt ? ILOpCode.Clt : ILOpCode.Cgt); return cg.CoreTypes.Boolean; } } }