public EmitConvertToPhpValue ( TypeSymbol from, TypeRefMask fromHint ) : TypeSymbol | ||
from | TypeSymbol | |
fromHint | TypeRefMask | |
return | TypeSymbol |
internal static TypeSymbol EmitStrictEquality(CodeGenerator cg, TypeSymbol xtype, BoundExpression right) { TypeSymbol ytype; switch (xtype.SpecialType) { case SpecialType.System_Boolean: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Boolean) { // bool == bool cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if ( ytype.SpecialType == SpecialType.System_Double || ytype.SpecialType == SpecialType.System_Int32 || ytype.SpecialType == SpecialType.System_Int64 || ytype.SpecialType == SpecialType.System_String || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.PhpString || ytype == cg.CoreTypes.Object) { // bool == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // bool == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_bool_PhpValue) .Expect(SpecialType.System_Boolean); } case SpecialType.System_Int32: cg.Builder.EmitOpCode(ILOpCode.Conv_i8); // i4 -> 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_Boolean || ytype.SpecialType == SpecialType.System_String || ytype.SpecialType == SpecialType.System_Double || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.Object || ytype == cg.CoreTypes.PhpString) { // i8 == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // i8 == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_long_PhpValue) .Expect(SpecialType.System_Boolean); } case SpecialType.System_Double: ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Double) { // r8 == r8 cg.Builder.EmitOpCode(ILOpCode.Ceq); return cg.CoreTypes.Boolean; } else if ( ytype.SpecialType == SpecialType.System_Boolean || ytype.SpecialType == SpecialType.System_String || ytype.SpecialType == SpecialType.System_Int64 || ytype.SpecialType == SpecialType.System_Int32 || ytype.IsOfType(cg.CoreTypes.IPhpArray) || ytype == cg.CoreTypes.Object || ytype == cg.CoreTypes.PhpString) { // r8 == something else => false cg.EmitPop(ytype); cg.EmitPop(xtype); cg.Builder.EmitBoolConstant(false); return cg.CoreTypes.Boolean; } else { // r8 == PhpValue cg.EmitConvertToPhpValue(ytype, 0); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_double_PhpValue) .Expect(SpecialType.System_Boolean); } default: // TODO: PhpArray, Object === ... xtype = cg.EmitConvertToPhpValue(xtype, 0); ytype = cg.Emit(right); if (ytype.SpecialType == SpecialType.System_Boolean) { // PhpValue == bool return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_PhpValue_bool) .Expect(SpecialType.System_Boolean); } else { ytype = cg.EmitConvertToPhpValue(ytype, 0); // PhpValue == PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.StrictCeq_PhpValue_PhpValue) .Expect(SpecialType.System_Boolean); } } }
/// <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); } } }
internal override TypeSymbol Emit(CodeGenerator cg) { MethodSymbol ctorsymbol; if (_arguments.Length == 0) { // <ctx>.Exit(); ctorsymbol = cg.CoreMethods.Ctors.ScriptDiedException; } else { // LOAD <status> var t = cg.Emit(_arguments[0].Value); switch (t.SpecialType) { case SpecialType.System_Int32: cg.Builder.EmitOpCode(ILOpCode.Conv_i8); // i4 -> i8 goto case SpecialType.System_Int64; case SpecialType.System_Int64: ctorsymbol = cg.CoreMethods.Ctors.ScriptDiedException_Long; break; default: cg.EmitConvertToPhpValue(t, 0); ctorsymbol = cg.CoreMethods.Ctors.ScriptDiedException_PhpValue; break; } } // cg.EmitCall(ILOpCode.Newobj, ctorsymbol); cg.Builder.EmitThrow(false); // return cg.CoreTypes.Void; }
void IBoundReference.EmitStore(CodeGenerator cg, TypeSymbol valueType) { // Template: array[index] var isphparr = (this.Array.ResultType == cg.CoreTypes.PhpArray); // whether the target is instance of PhpArray, otherwise it is an IPhpArray and we have to use .callvirt if (Access.IsWriteRef) { // PhpAlias if (valueType != cg.CoreTypes.PhpAlias) { cg.EmitConvertToPhpValue(valueType, 0); cg.Emit_PhpValue_MakeAlias(); } // .SetItemAlias(key, alias) or .AddValue(PhpValue.Create(alias)) if (this.Index != null) { if (isphparr) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemAlias_IntStringKey_PhpAlias); else cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.IPhpArray.SetItemAlias_IntStringKey_PhpAlias); } else { cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Create_PhpAlias); if (isphparr) cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.IPhpArray.AddValue_PhpValue); else cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.AddValue_PhpValue); } } else if (Access.IsUnset) { if (this.Index == null) throw new InvalidOperationException(); // .RemoveKey(key) if (isphparr) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.RemoveKey_IntStringKey); else cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.IPhpArray.RemoveKey_IntStringKey); } else { Debug.Assert(Access.IsWrite); cg.EmitConvertToPhpValue(valueType, 0); // .SetItemValue(key, value) or .AddValue(value) if (this.Index != null) { if (isphparr) cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.IPhpArray.SetItemValue_IntStringKey_PhpValue); else cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemValue_IntStringKey_PhpValue); } else { if (isphparr) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.AddValue_PhpValue); else cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.IPhpArray.AddValue_PhpValue); } } }
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 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 override void Generate(CodeGenerator cg) { Debug.Assert(this.Enumeree != null); // get the enumerator, // bind actual MoveNext() and CurrentValue and CurrentKey // Template: using( // a) enumerator = enumeree.GetEnumerator() // b) enumerator = Operators.GetEnumerator(enumeree) // ) ... cg.EmitSequencePoint(this.Enumeree.PhpSyntax); var enumereeType = cg.Emit(this.Enumeree); Debug.Assert(enumereeType.SpecialType != SpecialType.System_Void); var getEnumeratorMethod = enumereeType.LookupMember<MethodSymbol>(WellKnownMemberNames.GetEnumeratorMethodName); TypeSymbol enumeratorType; if (enumereeType.IsOfType(cg.CoreTypes.PhpArray)) { cg.Builder.EmitBoolConstant(_aliasedValues); // PhpArray.GetForeachtEnumerator(bool) enumeratorType = cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpArray.GetForeachEnumerator_Boolean); // TODO: IPhpArray } // TODO: IPhpEnumerable // TODO: IPhpArray // TODO: Iterator else if (getEnumeratorMethod != null && getEnumeratorMethod.ParameterCount == 0 && enumereeType.IsReferenceType) { // enumeree.GetEnumerator() enumeratorType = cg.EmitCall(getEnumeratorMethod.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call, getEnumeratorMethod); } else { cg.EmitConvertToPhpValue(enumereeType, 0); cg.Builder.EmitBoolConstant(_aliasedValues); cg.EmitCallerRuntimeTypeHandle(); // Operators.GetForeachEnumerator(PhpValue, bool, RuntimeTypeHandle) enumeratorType = cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.GetForeachEnumerator_PhpValue_Bool_RuntimeTypeHandle); } // _current = enumeratorType.LookupMember<PropertySymbol>(WellKnownMemberNames.CurrentPropertyName); // TODO: Err if no Current _currentValue = enumeratorType.LookupMember<PropertySymbol>(_aliasedValues ? "CurrentValueAliased" : "CurrentValue"); _currentKey = enumeratorType.LookupMember<PropertySymbol>("CurrentKey"); _disposeMethod = enumeratorType.LookupMember<MethodSymbol>("Dispose", m => m.ParameterCount == 0 && !m.IsStatic); // _enumeratorLoc = cg.GetTemporaryLocal(enumeratorType); cg.Builder.EmitLocalStore(_enumeratorLoc); // bind methods _moveNextMethod = enumeratorType.LookupMember<MethodSymbol>(WellKnownMemberNames.MoveNextMethodName); // TODO: Err if there is no MoveNext() Debug.Assert(_moveNextMethod.ReturnType.SpecialType == SpecialType.System_Boolean); Debug.Assert(_moveNextMethod.IsStatic == false); if (_disposeMethod != null) { /* Template: try { body } finally { enumerator.Dispose } */ // try { cg.Builder.AssertStackEmpty(); cg.Builder.OpenLocalScope(ScopeType.TryCatchFinally); cg.Builder.OpenLocalScope(ScopeType.Try); // EmitBody(cg); // } cg.Builder.CloseLocalScope(); // /Try // finally { cg.Builder.OpenLocalScope(ScopeType.Finally); // enumerator.Dispose() & cleanup EmitDisposeAndClean(cg); // } cg.Builder.CloseLocalScope(); // /Finally cg.Builder.CloseLocalScope(); // /TryCatchFinally } else { EmitBody(cg); EmitDisposeAndClean(cg); } }
/// <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; } } }
public virtual void EmitStore(CodeGenerator cg, TypeSymbol valueType) { // STACK: <PhpArray> <key> if (_access.IsWriteRef) { // PhpAlias if (valueType != cg.CoreTypes.PhpAlias) { cg.EmitConvertToPhpValue(valueType, 0); cg.Emit_PhpValue_MakeAlias(); } // .SetItemAlias(key, alias) cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpArray.SetItemAlias_IntStringKey_PhpAlias); } else if (_access.IsUnset) { Debug.Assert(valueType == null); // .RemoveKey(key) cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpArray.RemoveKey_IntStringKey); } else { Debug.Assert(_access.IsWrite); cg.EmitConvertToPhpValue(valueType, 0); // .SetItemValue(key, value) cg.EmitCall(ILOpCode.Callvirt, cg.CoreMethods.PhpArray.SetItemValue_IntStringKey_PhpValue); } }
public void EmitStore(CodeGenerator cg, TypeSymbol valueType) { var type = _place.TypeOpt; // Write Ref if (_access.IsWriteRef) { if (valueType != cg.CoreTypes.PhpAlias) { Debug.Assert(false, "caller should get aliased value"); cg.EmitConvertToPhpValue(valueType, 0); valueType = cg.Emit_PhpValue_MakeAlias(); } // if (type == cg.CoreTypes.PhpAlias) { // <place> = <alias> _place.EmitStore(cg.Builder); } else if (type == cg.CoreTypes.PhpValue) { // <place> = PhpValue.Create(<alias>) cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.Create_PhpAlias); _place.EmitStore(cg.Builder); } else { Debug.Assert(false, "Assigning alias to non-aliasable variable."); cg.EmitConvert(valueType, 0, type); _place.EmitStore(cg.Builder); } } else if (_access.IsUnset) { Debug.Assert(valueType == null); // <place> = if (type == cg.CoreTypes.PhpAlias) { // new PhpAlias(void) cg.Emit_PhpValue_Void(); cg.Emit_PhpValue_MakeAlias(); } else if (type.IsReferenceType) { // null cg.Builder.EmitNullConstant(); } else { // default(T) cg.EmitLoadDefaultOfValueType(type); } _place.EmitStore(cg.Builder); } else { // if (type == cg.CoreTypes.PhpAlias) { // <place>.Value = <value> cg.EmitConvertToPhpValue(valueType, 0); cg.Emit_PhpAlias_SetValue(); } else if (type == cg.CoreTypes.PhpValue) { if (_thint.IsRef) { // Operators.SetValue(ref <place>, (PhpValue)<value>); cg.EmitConvertToPhpValue(valueType, 0); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.SetValue_PhpValueRef_PhpValue); } else { // <place> = <value> cg.EmitConvertToPhpValue(valueType, 0); _place.EmitStore(cg.Builder); } } else { cg.EmitConvert(valueType, 0, type); _place.EmitStore(cg.Builder); } } }
public TypeSymbol EmitLoad(CodeGenerator cg) { Debug.Assert(_access.IsRead); var type = _place.TypeOpt; // Ensure Object ($x->.. =) if (_access.EnsureObject) { if (type == cg.CoreTypes.PhpAlias) { _place.EmitLoad(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureObject) .Expect(SpecialType.System_Object); } else if (type == cg.CoreTypes.PhpValue) { _place.EmitLoadAddress(cg.Builder); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureObject) .Expect(SpecialType.System_Object); if (_thint.IsSingleType && cg.IsClassOnly(_thint)) { var tref = cg.Routine.TypeRefContext.GetTypes(_thint)[0]; var clrtype = (TypeSymbol)cg.DeclaringCompilation.GetTypeByMetadataName(tref.QualifiedName.ClrName()); if (clrtype != null && !clrtype.IsErrorType() && clrtype != cg.CoreTypes.Object) { cg.EmitCastClass(clrtype); return clrtype; } } return cg.CoreTypes.Object; } else if (type.IsOfType(cg.CoreTypes.IPhpArray)) { // PhpArray -> stdClass // PhpString -> stdClass (?) // otherwise keep the instance on stack throw new NotImplementedException(); } else { if (type.IsReferenceType) { if (type == cg.CoreTypes.Object) { // Operators.EnsureObject(ref <place>) _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureObject_ObjectRef) .Expect(SpecialType.System_Object); } else { // <place> return _place.EmitLoad(cg.Builder); } } else { // return new stdClass(ctx) throw new NotImplementedException(); } } } // Ensure Array ($x[] =) else if (_access.EnsureArray) { if (type == cg.CoreTypes.PhpAlias) { // <place>.EnsureArray() _place.EmitLoad(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } else if (type == cg.CoreTypes.PhpValue) { if (cg.IsArrayOnly(_thint)) { // uses typehint and accesses .Array directly if possible // <place>.Array _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.get_Array) .Expect(cg.CoreTypes.PhpArray); } else { // <place>.EnsureArray() _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } } else if (type.IsOfType(cg.CoreTypes.IPhpArray)) { // Operators.EnsureArray(ref <place>) _place.EmitLoadAddress(cg.Builder); if (type == cg.CoreTypes.PhpArray) { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureArray_PhpArrayRef) .Expect(cg.CoreTypes.PhpArray); } else { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureArray_IPhpArrayRef) .Expect(cg.CoreTypes.IPhpArray); } } throw new NotImplementedException("EnsureArray(" + type.Name + ")"); } // Ensure Alias (&$x) else if (_access.IsReadRef) { if (type == cg.CoreTypes.PhpAlias) { // TODO: <place>.AddRef() return _place.EmitLoad(cg.Builder); } else if (type == cg.CoreTypes.PhpValue) { // return <place>.EnsureAlias() _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureAlias) .Expect(cg.CoreTypes.PhpAlias); } else if (type == cg.CoreTypes.PhpNumber) { throw new NotImplementedException(); } else { Debug.Assert(false, "value cannot be aliased"); // new PhpAlias((PhpValue)<place>, 1) cg.EmitConvertToPhpValue(_place.EmitLoad(cg.Builder), 0); return cg.Emit_PhpValue_MakeAlias(); } } // Read Value & Dereference eventually else { if (type == cg.CoreTypes.PhpAlias) { _place.EmitLoad(cg.Builder); if (_access.TargetType == cg.CoreTypes.PhpArray) { // <place>.Value.ToArray() cg.Builder.EmitOpCode(ILOpCode.Ldflda); cg.EmitSymbolToken(cg.CoreMethods.PhpAlias.Value, null); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray) .Expect(cg.CoreTypes.PhpArray); } return cg.Emit_PhpAlias_GetValue(); } else if (type == cg.CoreTypes.PhpValue) { if (_access.TargetType == cg.CoreTypes.PhpArray) { // <place>.ToArray() _place.EmitLoadAddress(cg.Builder); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray) .Expect(cg.CoreTypes.PhpArray); } // TODO: dereference if applicable (=> PhpValue.Alias.Value) return _place.EmitLoad(cg.Builder); } else { return _place.EmitLoad(cg.Builder); } } }
public TypeSymbol EmitLoad(CodeGenerator cg) { Debug.Assert(Access.IsRead); var type = Field.Type; // Ensure Object (..->Field->.. =) if (Access.EnsureObject) { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); // PhpAlias return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureObject) .Expect(SpecialType.System_Object); } else if (type == cg.CoreTypes.PhpValue) { EmitOpCode_LoadAddress(cg); // &PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureObject) .Expect(SpecialType.System_Object); } else { if (type.IsReferenceType) { // TODO: ensure it is not null EmitOpCode_Load(cg); return type; } else { // return new stdClass(ctx) throw new NotImplementedException(); } } } // Ensure Array (xxx->Field[] =) else if (Access.EnsureArray) { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpAlias.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } else if (type == cg.CoreTypes.PhpValue) { EmitOpCode_LoadAddress(cg); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureArray) .Expect(cg.CoreTypes.IPhpArray); } else if (type.IsOfType(cg.CoreTypes.IPhpArray)) { EmitOpCode_LoadAddress(cg); // ensure value is not null if (type == cg.CoreTypes.PhpArray) { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureArray_PhpArrayRef) .Expect(cg.CoreTypes.PhpArray); } else { return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.Operators.EnsureArray_IPhpArrayRef) .Expect(cg.CoreTypes.IPhpArray); } } throw new NotImplementedException(); } // Ensure Alias (&...->Field) else if (Access.IsReadRef) { if (type == cg.CoreTypes.PhpAlias) { // TODO: <place>.AddRef() EmitOpCode_Load(cg); return type; } else if (type == cg.CoreTypes.PhpValue) { // return <place>.EnsureAlias() EmitOpCode_LoadAddress(cg); // &PhpValue return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureAlias) .Expect(cg.CoreTypes.PhpAlias); } else { Debug.Assert(false, "value cannot be aliased"); // new PhpAlias((PhpValue)<place>, 1) EmitOpCode_Load(cg); cg.EmitConvertToPhpValue(type, 0); return cg.Emit_PhpValue_MakeAlias(); } } // Read (...->Field) & Dereference eventually else { if (type == cg.CoreTypes.PhpAlias) { EmitOpCode_Load(cg); if (Access.TargetType != null) { // convert PhpValue to target type without loading whole value and storing to temporary variable switch (Access.TargetType.SpecialType) { default: if (Access.TargetType == cg.CoreTypes.PhpArray) { // <PhpAlias>.Value.ToArray() cg.Builder.EmitOpCode(ILOpCode.Ldflda); cg.EmitSymbolToken(cg.CoreMethods.PhpAlias.Value, null); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray); } break; } } return cg.Emit_PhpAlias_GetValue(); } else if (type == cg.CoreTypes.PhpValue) { if (Access.TargetType != null) { // convert PhpValue to target type without loading whole value and storing to temporary variable switch (Access.TargetType.SpecialType) { case SpecialType.System_Double: EmitOpCode_LoadAddress(cg); // &PhpValue.ToDouble() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToDouble); case SpecialType.System_Int64: EmitOpCode_LoadAddress(cg); // &PhpValue.ToLong() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToLong); case SpecialType.System_Boolean: EmitOpCode_LoadAddress(cg); // &PhpValue.ToBoolean() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToBoolean); case SpecialType.System_String: EmitOpCode_LoadAddress(cg); // &PhpValue.ToString(ctx) cg.EmitLoadContext(); return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToString_Context); case SpecialType.System_Object: EmitOpCode_LoadAddress(cg); // &PhpValue.ToClass() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToClass); default: if (Access.TargetType == cg.CoreTypes.PhpArray) { EmitOpCode_LoadAddress(cg); // &PhpValue.ToArray() return cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.ToArray); } break; } } // TODO: dereference if applicable (=> PhpValue.Alias.Value) EmitOpCode_Load(cg); return type; } else { EmitOpCode_Load(cg); return type; } } }
internal override void EmitInit(CodeGenerator cg) { // TODO: check callable, iterable // TODO: ? if (cg.HasUnoptimizedLocals && $this) <locals>["this"] = ... var srcparam = _symbol as SourceParameterSymbol; if (srcparam != null) { var srcplace = new ParamPlace(_symbol); var routine = srcparam.Routine; if (cg.HasUnoptimizedLocals) { Debug.Assert(cg.LocalsPlaceOpt != null); // copy parameter to <locals>[Name] // <locals>[name] = value cg.LocalsPlaceOpt.EmitLoad(cg.Builder); // <locals> cg.EmitIntStringKey(new BoundLiteral(this.Name)); // [key] cg.EmitConvertToPhpValue(srcplace.EmitLoad(cg.Builder), 0); // value cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpArray.SetItemValue_IntStringKey_PhpValue); // _isUnoptimized = true; } else { // TODO: copy parameter by value in case of PhpValue, Array, PhpString // create local variable in case of parameter type is not enough for its use within routine if (_symbol.Type != cg.CoreTypes.PhpValue && _symbol.Type != cg.CoreTypes.PhpAlias) { var tmask = routine.ControlFlowGraph.GetLocalTypeMask(srcparam.Name); var clrtype = cg.DeclaringCompilation.GetTypeFromTypeRef(routine, tmask); if (clrtype != _symbol.Type) // Assert: only if clrtype is not covered by _symbol.Type { // TODO: performance warning _lazyLocal = new BoundLocal(new SynthesizedLocalSymbol(routine, srcparam.Name, clrtype)); _lazyLocal.EmitInit(cg); var localplace = _lazyLocal.Place(cg.Builder); // <local> = <param> localplace.EmitStorePrepare(cg.Builder); cg.EmitConvert(srcplace.EmitLoad(cg.Builder), 0, clrtype); localplace.EmitStore(cg.Builder); } } } } }