public PhpParam(TypeRefMask tmask, bool isByRef, bool isVariadic, BoundExpression defaultValue) { this.Type = tmask; this.IsVariadic = isVariadic; this.DefaultValue = defaultValue; this.IsByRef = isByRef; }
/// <summary> /// Sets type of local variable in current state. /// </summary> protected virtual TypeRefMask SetVar(string name, TypeRefMask typemask) { AssertState(); _state.SetVar(name, typemask); return typemask; }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { if (_place == null) { // unoptimized locals return new BoundIndirectVariablePlace(new BoundLiteral(this.Name), access); } else { return new BoundLocalPlace(_place, access, thint); } }
/// <summary> /// Gets value indicating the given type is long or double or both but nothing else. /// </summary> /// <param name="tmask"></param> /// <returns></returns> bool IsNumberOnly(TypeRefMask tmask) { if (TypeCtx.IsLong(tmask) || TypeCtx.IsDouble(tmask)) { if (tmask.IsSingleType) return true; return !tmask.IsAnyType && TypeCtx.GetTypes(tmask) .All(t => t.TypeCode == Core.PhpTypeCode.Long || t.TypeCode == Core.PhpTypeCode.Double); } return false; }
private static TypeRefMask[] GetParamsTypeArr(int count, TypeRefMask value) { if (count < 0) return null; if (count == 0) return EmptyArray<TypeRefMask>.Instance; // var arr = new TypeRefMask[count]; for (int i = 0; i < arr.Length; i++) arr[i] = value; return arr; }
public MethodSymbol Resolve(TypeRefContext typeCtx, TypeRefMask[] args, TypeSymbol classCtx) { // see Pchp.Core.Dynamic.OverloadBinder var result = new List<MethodSymbol>(_methods); // RemoveInaccessible(result, classCtx); if (result.Count == 1) return result[0]; // TODO: cost of args convert operation // by params count var result2 = new List<MethodSymbol>(); foreach (var m in result) { var nmandatory = 0; var hasoptional = false; var hasparams = false; var expectedparams = m.GetExpectedArguments(typeCtx); foreach (var p in expectedparams) { hasoptional |= p.DefaultValue != null; hasparams |= p.IsVariadic; if (!hasoptional && !hasparams) nmandatory++; // TODO: check args[i] is convertible to p.Type } if (args.Length >= nmandatory && (hasparams || args.Length <= expectedparams.Length)) { result2.Add(m); } } // return (result2.Count == 1) ? result2[0] : null; }
/// <summary> /// Emits conversion to a class object. /// </summary> /// <param name="from">Type of value on top of the evaluation stack.</param> /// <param name="fromHint">Hint in case of multitype value.</param> /// <param name="to">Target type.</param> private void EmitConvertToClass(TypeSymbol from, TypeRefMask fromHint, TypeSymbol to) { Contract.ThrowIfNull(from); Contract.ThrowIfNull(to); Debug.Assert(to.IsReferenceType); // TODO: structs other than primitive types Debug.Assert(to != CoreTypes.PhpAlias); // dereference if (from == CoreTypes.PhpAlias) { Emit_PhpAlias_GetValue(); from = CoreTypes.PhpValue; } if (from == to) { return; } Debug.Assert(to != CoreTypes.PhpArray && to != CoreTypes.PhpString && to != CoreTypes.PhpAlias); if (to == CoreTypes.IPhpCallable) { // (IPhpCallable) if (!from.IsEqualToOrDerivedFrom(CoreTypes.IPhpCallable)) { if (from.SpecialType == SpecialType.System_String) { EmitCall(ILOpCode.Call, CoreMethods.Operators.AsCallable_String); } else if ( from.SpecialType == SpecialType.System_Int64 || from.SpecialType == SpecialType.System_Boolean || from.SpecialType == SpecialType.System_Double) { throw new ArgumentException($"{from.Name} cannot be converted to a class of type {to.Name}!"); // TODO: ErrCode } else { EmitConvertToPhpValue(from, fromHint); EmitCall(ILOpCode.Call, CoreMethods.Operators.AsCallable_PhpValue); } } return; } if (to.IsArray()) { var arrt = (ArrayTypeSymbol)to; if (arrt.IsSZArray) { if (arrt.ElementType.SpecialType == SpecialType.System_Byte) { // byte[] // Template: (PhpString).ToBytes(Context) EmitConvertToPhpString(from, fromHint); // PhpString this.EmitLoadContext(); // Context EmitCall(ILOpCode.Call, CoreMethods.PhpString.ToBytes_Context) .Expect(to); // ToBytes() return; } } throw new NotImplementedException($"Conversion from {from.Name} to {to.Name} is not implemented."); } switch (from.SpecialType) { case SpecialType.System_Void: case SpecialType.System_Int32: case SpecialType.System_Int64: case SpecialType.System_Boolean: case SpecialType.System_Double: case SpecialType.System_String: if (to == CoreTypes.Object) { from = EmitConvertToPhpValue(from, fromHint); goto default; } else { throw new ArgumentException($"{from.Name} cannot be converted to a class of type {to.Name}!"); // TODO: ErrCode } default: if (from == CoreTypes.PhpValue) { if (!fromHint.IsRef && IsClassOnly(fromHint)) { // <value>.Object EmitPhpValueAddr(); from = EmitCall(ILOpCode.Call, CoreMethods.PhpValue.Object.Getter) .Expect(SpecialType.System_Object); } else { // Convert.ToClass( value ) from = EmitCall(ILOpCode.Call, CoreMethods.Operators.ToClass_PhpValue) .Expect(SpecialType.System_Object); } // (T) EmitCastClass(from, to); return; } if (from == CoreTypes.PhpNumber) { // Object EmitPhpNumberAddr(); EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToClass) .Expect(SpecialType.System_Object); // (T) EmitCastClass(to); return; } else if (from.IsOfType(CoreTypes.PhpArray)) { // (T)PhpArray.ToClass(); EmitCastClass(EmitCall(ILOpCode.Call, CoreMethods.PhpArray.ToClass), to); return; } else if (from.IsOfType(CoreTypes.IPhpArray)) { // (T)Convert.ToClass(IPhpArray) EmitCastClass(EmitCall(ILOpCode.Call, CoreMethods.Operators.ToClass_IPhpArray), to); return; } else if (from.IsReferenceType) { Debug.Assert(from != CoreTypes.PhpAlias); // (T)obj // let .NET deal with eventual cast error for now EmitCastClass(from, to); return; } throw new NotImplementedException(); } }
/// <summary> /// Gets value indicating whether given type mask represents a boolean. /// </summary> public bool IsBoolean(TypeRefMask mask) { return (mask.Mask & _isBoolMask) != 0; }
/// <summary> /// Emits conversion from one CLR type to another using PHP conventions. /// </summary> /// <param name="from">Type of value on top of evaluation stack.</param> /// <param name="fromHint">Type hint in case of a multityple type choices (like PhpValue or PhpNumber or PhpAlias).</param> /// <param name="to">Target CLR type.</param> public void EmitConvert(TypeSymbol from, TypeRefMask fromHint, TypeSymbol to) { Contract.ThrowIfNull(from); Contract.ThrowIfNull(to); Debug.Assert(!to.IsErrorType(), "Conversion to an error type."); // conversion is not needed: if (from.SpecialType == to.SpecialType && (from == to || (to.SpecialType != SpecialType.System_Object && from.IsOfType(to)))) { return; } // from = EmitSpecialize(from, fromHint); // specialized conversions: switch (to.SpecialType) { case SpecialType.System_Void: EmitPop(from); return; case SpecialType.System_Boolean: EmitConvertToBool(from, fromHint); return; case SpecialType.System_Int32: EmitConvertToInt(from, fromHint); return; case SpecialType.System_Int64: EmitConvertToLong(from, fromHint); return; case SpecialType.System_Single: EmitConvertToDouble(from, fromHint); _il.EmitOpCode(ILOpCode.Conv_r4); return; case SpecialType.System_Double: EmitConvertToDouble(from, fromHint); return; case SpecialType.System_String: EmitConvertToString(from, fromHint); return; case SpecialType.System_Object: EmitConvertToClass(from, fromHint, to); return; default: if (to == CoreTypes.PhpValue) { EmitConvertToPhpValue(from, fromHint); } else if (to == CoreTypes.PhpAlias) { EmitConvertToPhpValue(from, fromHint); Emit_PhpValue_MakeAlias(); } else if (to == CoreTypes.PhpNumber) { EmitConvertToPhpNumber(from, fromHint); } else if (CoreTypes.PhpArray.Symbol.IsOfType(to)) { EmitConvertToPhpArray(from, fromHint); } else if (to == CoreTypes.PhpString) { EmitConvertToPhpString(from, fromHint); } else if (to.IsReferenceType) { EmitConvertToClass(from, fromHint, to); } else if (to.IsEnumType()) { EmitConvertToEnum(from, (NamedTypeSymbol)to); } else if (to == CoreTypes.IntStringKey) { EmitConvertToIntStringKey(from, fromHint); } else { break; } return; } // throw new NotImplementedException($"{to}"); }
public TypeSymbol EmitConvertToPhpValue(TypeSymbol from, TypeRefMask fromHint) { return(EmitConvertToPhpValue(from, fromHint, _il, _moduleBuilder, _diagnostics)); }
/// <summary> /// Gets value indicating the given type represents a double and nothing else. /// </summary> internal bool IsDoubleOnly(TypeRefMask tmask) { return tmask.IsSingleType && _routine.TypeRefContext.IsDouble(tmask); }
/// <summary> /// Initializes <see cref="CallInfo"/>. /// </summary> /// <param name="ctx">Type context of the caller.</param> /// <param name="paramsCount">Amount of parameters used for the call.</param> /// <param name="lateStaticBindType">Type of the <c>self</c> in the caller context.</param> public CallInfo(TypeRefContext ctx, int paramsCount, TypeRefMask lateStaticBindType) : this(ctx, GetParamsTypeArr(paramsCount, TypeRefMask.AnyType), lateStaticBindType) { }
public void EmitConvertToBool(TypeSymbol from, TypeRefMask fromHint, bool negation = false) { // TODO: use {fromHint} to emit casting in compile time // dereference if (from == CoreTypes.PhpAlias) { // <PhpAlias>.Value.ToBoolean() Emit_PhpAlias_GetValueAddr(); EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToBoolean); // ! if (negation) { EmitLogicNegation(); } // return; } // from = EmitSpecialize(from, fromHint); // switch (from.SpecialType) { case SpecialType.System_Void: _il.EmitBoolConstant(negation ? true : false); // (bool)void == false return; case SpecialType.System_Boolean: case SpecialType.System_Int32: break; // nop case SpecialType.System_Int64: _il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); _il.EmitOpCode(ILOpCode.Conv_i8, 0); _il.EmitOpCode(negation ? ILOpCode.Ceq : ILOpCode.Cgt_un); return; case SpecialType.System_Double: // r8 == 0.0 _il.EmitDoubleConstant(0.0); _il.EmitOpCode(ILOpCode.Ceq); if (!negation) { // !<i4> EmitLogicNegation(); } return; case SpecialType.System_String: // Convert.ToBoolean(string) EmitCall(ILOpCode.Call, CoreMethods.Operators.ToBoolean_String); break; case SpecialType.System_Object: EmitCall(ILOpCode.Call, CoreMethods.Operators.ToBoolean_Object); break; case SpecialType.None: if (from == CoreTypes.PhpValue) { // (bool)value EmitCall(ILOpCode.Call, CoreMethods.Operators.ToBoolean_PhpValue); break; } else if (from == CoreTypes.PhpNumber) { EmitPhpNumberAddr(); EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToBoolean); break; } else if (from.IsOfType(CoreTypes.IPhpConvertible)) { // (IPhpConvertible).ToBoolean() if (CanBeNull(fromHint)) { // Template: <value> != null && <value>.ToBoolean() EmitCall(ILOpCode.Call, CoreMethods.Operators.ToBoolean_IPhpConvertible); } else { // Template: <value>.ToBoolean() EmitCall(ILOpCode.Callvirt, CoreMethods.IPhpConvertible.ToBoolean) .Expect(SpecialType.System_Boolean); } break; } //else if (from == CoreTypes.PhpString) //{ // EmitCall(ILOpCode.Call, CoreMethods.PhpString.ToBoolean); // break; //} //else if (from.IsOfType(CoreTypes.IPhpArray)) //{ // // TODO: != null && .Count != 0 // // IPhpArray.Count != 0 // EmitCall(ILOpCode.Callvirt, CoreMethods.IPhpArray.get_Count); // _il.EmitOpCode(ILOpCode.Ldc_i4_0, 1); // _il.EmitOpCode(negation ? ILOpCode.Ceq : ILOpCode.Cgt_un); // return; // negation handled //} else if (from.IsReferenceType) { goto case SpecialType.System_Object; } goto default; default: throw new NotImplementedException($"(bool){from.Name}"); } // !<i4> if (negation) { EmitLogicNegation(); } }
///// <summary> ///// Gets value indicating whether given type mask represents a resource. ///// </summary> //public bool IsResource(TypeRefMask mask) { return GetObjectTypes(mask).Any(InheritesFromPhpResource); } /// <summary> /// Gets value indicating whether given type mask represents a primitive type. /// </summary> public bool IsPrimitiveType(TypeRefMask mask) { return (mask.Mask & _isPrimitiveMask) != 0; }
/// <summary> /// Gets value indicating the given type represents only PHP Array. /// </summary> internal bool IsArrayOnly(TypeRefMask tmask) { return(!tmask.IsVoid && !tmask.IsAnyType && !tmask.IsRef && this.TypeRefContext.GetTypes(tmask).AllIsArray()); }
/// <summary> /// Gets value indicating the type can be <c>null</c>. /// </summary> internal bool CanBeNull(TypeRefMask tmask) { return(tmask.IsAnyType || tmask.IsRef || tmask.IsUninitialized || this.TypeRefContext.IsNull(tmask) || this.TypeRefContext.IsBoolean(tmask)); // TODO: other scalar types (string, number) }
/// <summary> /// Gets value indicating the given type represents only class types. /// </summary> internal bool IsClassOnly(TypeRefMask tmask) { return(!tmask.IsVoid && !tmask.IsRef && this.TypeRefContext.IsObjectOnly(tmask)); // .GetTypes(tmask).AllIsObject(); }
/// <summary> /// Gets value indicating the given type represents UTF16 readonly string and nothing else. /// </summary> internal bool IsReadonlyStringOnly(TypeRefMask tmask) { return(tmask.IsSingleType && !tmask.IsRef && this.TypeRefContext.IsReadonlyString(tmask)); }
/// <summary> /// Gets value indicating the given type represents a long and nothing else. /// </summary> internal bool IsBooleanOnly(TypeRefMask tmask) { return(tmask.IsSingleType && !tmask.IsRef && this.TypeRefContext.IsBoolean(tmask)); }
/// <summary> /// Gets value indicating whether given type mask represents a double type. /// </summary> public bool IsDouble(TypeRefMask mask) { return (mask.Mask & _isDoubleMask) != 0; }
/// <summary> /// Resolves <see cref="INamedTypeSymbol"/> best fitting given type mask. /// </summary> internal NamedTypeSymbol GetTypeFromTypeRef(SourceRoutineSymbol /*!*/ routine, TypeRefMask typeMask) { Debug.Assert(routine != null); return(this.GetTypeFromTypeRef(routine.TypeRefContext, typeMask)); }
/// <summary> /// Gets value indicating whether given type mask represents an array. /// </summary> public bool IsArray(TypeRefMask mask) { return (mask.Mask & _isArrayMask) != 0; }
public void EmitConvertToLong(TypeSymbol from, TypeRefMask fromHint) { Contract.ThrowIfNull(from); // dereference if (from == CoreTypes.PhpAlias) { Emit_PhpAlias_GetValue(); from = CoreTypes.PhpValue; } // from = EmitSpecialize(from, fromHint); switch (from.SpecialType) { case SpecialType.System_Boolean: _il.EmitOpCode(ILOpCode.Conv_i8); // bool -> Int64 return; case SpecialType.System_Int32: _il.EmitOpCode(ILOpCode.Conv_i8); // Int32 -> Int64 return; case SpecialType.System_Int64: // nop return; case SpecialType.System_Double: _il.EmitOpCode(ILOpCode.Conv_i8); // double -> int64 break; case SpecialType.System_String: EmitCall(ILOpCode.Call, CoreMethods.Operators.ToLong_String) .Expect(SpecialType.System_Int64); break; default: if (from == CoreTypes.PhpNumber) { EmitPhpNumberAddr(); EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToLong); return; } else if (from.IsOfType(CoreTypes.IPhpArray)) { // (long)IPhpArray.Count EmitCall(ILOpCode.Callvirt, CoreMethods.IPhpArray.get_Count); _il.EmitOpCode(ILOpCode.Conv_i8); // Int32 -> Int64 return; } else if (from == CoreTypes.PhpValue) { EmitCall(ILOpCode.Call, CoreMethods.Operators.ToLong_PhpValue); return; } else { throw new NotImplementedException(); } } }
//public bool IsArrayKey(TypeRefMask mask) { return (mask.Mask & IsArrayKeyMask) != 0; } // TODO: type can be of type object with method __toString() ? /// <summary> /// In case of array type, gets its possible element types. /// </summary> public TypeRefMask GetElementType(TypeRefMask mask) { TypeRefMask result; if (IsArray(mask) && !mask.IsAnyType) { result = default(TypeRefMask); // uninitalized var arrtypes = GetTypes(mask, _isArrayMask); foreach (var t in arrtypes) { Debug.Assert(t.IsArray); result |= t.ElementType; } if (result.IsVoid) { // empty array //result = TypeRefMask.AnyType; } } else { result = TypeRefMask.AnyType; } return result; }
public static TypeSymbol EmitConvertToPhpValue(TypeSymbol from, TypeRefMask fromHint, ILBuilder il, Emit.PEModuleBuilder module, DiagnosticBag diagnostic) { Contract.ThrowIfNull(from); var compilation = module.Compilation; switch (from.SpecialType) { case SpecialType.System_Boolean: il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_Boolean); break; case SpecialType.System_Int32: il.EmitOpCode(ILOpCode.Conv_i8); // Int32 -> Int64 goto case SpecialType.System_Int64; // PhpValue.Create((long)<stack>) case SpecialType.System_Int64: il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_Long); break; case SpecialType.System_Double: il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_Double); break; case SpecialType.System_Void: Emit_PhpValue_Void(il, module, diagnostic); break; case SpecialType.System_String: il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_String) .Expect(compilation.CoreTypes.PhpValue); break; default: if (from == compilation.CoreTypes.PhpAlias) { il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_PhpAlias) .Expect(compilation.CoreTypes.PhpValue); break; } else if (from == compilation.CoreTypes.PhpValue) { // nop break; } else if (from == compilation.CoreTypes.PhpString) { il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_PhpString) .Expect(compilation.CoreTypes.PhpValue); break; } else if (from == compilation.CoreTypes.PhpNumber) { il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_PhpNumber) .Expect(compilation.CoreTypes.PhpValue); break; } else if (from.IsOfType(compilation.CoreTypes.PhpArray)) { il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_PhpArray) .Expect(compilation.CoreTypes.PhpValue); break; } else if (from == compilation.CoreTypes.IntStringKey) { il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.Create_IntStringKey) .Expect(compilation.CoreTypes.PhpValue); break; } else if (from.IsReferenceType) { il.EmitCall(module, diagnostic, ILOpCode.Call, compilation.CoreMethods.PhpValue.FromClass_Object) .Expect(compilation.CoreTypes.PhpValue); break; } else { throw new NotImplementedException($"{from.Name}"); } } // return(compilation.CoreTypes.PhpValue); }
/// <summary> /// Gets value indicating the given type represents UTF16 readonly string and nothing else. /// </summary> internal bool IsReadonlyStringOnly(TypeRefMask tmask) { return tmask.IsSingleType && _routine.TypeRefContext.IsReadonlyString(tmask); }
/// <summary> /// Gets types of type <c>object</c> (classes, interfaces, traits) referenced by given type mask. /// </summary> public IList<ITypeRef>/*!*/GetObjectTypes(TypeRefMask mask) { if (mask.IsAnyType) return EmptyArray<ITypeRef>.Instance; return GetTypes(mask, _isObjectMask); }
/// <summary> /// Initializes <see cref="CallInfo"/>. /// </summary> /// <param name="ctx">Type context of the caller.</param> /// <param name="paramsType">Type of parameters used for the call. Length of the array corresponds to the parameters count.</param> /// <param name="lateStaticBindType">Type of the <c>self</c> in the caller context.</param> public CallInfo(TypeRefContext ctx, TypeRefMask[] paramsType, TypeRefMask lateStaticBindType) { _typeCtx = ctx; _paramsType = paramsType; _lateStaticBindType = (lateStaticBindType.IsSingleType ? lateStaticBindType : 0); }
/// <summary> /// Gets value indicating whether given type mask represents a number. /// </summary> public bool IsNumber(TypeRefMask mask) { return (mask.Mask & IsNumberMask) != 0; }
/// <summary>The given type represents only an integer, long or double.</summary> internal bool IsNumberOnly(TypeRefMask tmask) { return(!tmask.IsVoid && !tmask.IsAnyType && this.TypeRefContext.GetTypes(tmask).All(TypeHelpers.IsNumber) && !tmask.IsRef); }
/// <summary> /// Gets value indicating whether given type mask represents UTF16 readonly string. /// </summary> public bool IsReadonlyString(TypeRefMask mask) { return (mask.Mask & _isStringMask) != 0; }
public void EmitConvertToBool(TypeSymbol from, TypeRefMask fromHint) { this.EmitImplicitConversion(from, CoreTypes.Boolean); }
/// <summary> /// Emits conversion to <see cref="System.String"/>. /// </summary> public void EmitConvertToString(TypeSymbol from, TypeRefMask fromHint) { Contract.ThrowIfNull(from); // dereference if (from == CoreTypes.PhpAlias) { Emit_PhpAlias_GetValue(); from = CoreTypes.PhpValue; } from = EmitSpecialize(from, fromHint); // switch (from.SpecialType) { case SpecialType.System_String: // nop break; case SpecialType.System_Void: Builder.EmitStringConstant(string.Empty); break; case SpecialType.System_Boolean: EmitCall(ILOpCode.Call, CoreMethods.Operators.ToString_Bool); break; case SpecialType.System_Int32: EmitCall(ILOpCode.Call, CoreMethods.Operators.ToString_Int32); break; case SpecialType.System_Int64: EmitCall(ILOpCode.Call, CoreMethods.Operators.ToString_Long); break; case SpecialType.System_Double: EmitLoadContext(); EmitCall(ILOpCode.Call, CoreMethods.Operators.ToString_Double_Context); break; case SpecialType.System_Object: // PhpValue.Create(object) from = EmitCall(ILOpCode.Call, CoreMethods.PhpValue.FromClass_Object); goto default; default: if (from == CoreTypes.PhpNumber) { EmitPhpNumberAddr(); // PhpNumber -> PhpNumber addr EmitLoadContext(); // Context EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToString_Context) .Expect(SpecialType.System_String); break; } else if (from == CoreTypes.PhpString) { EmitLoadContext(); // Context EmitCall(ILOpCode.Call, CoreMethods.PhpString.ToString_Context) .Expect(SpecialType.System_String); break; } else if (from == CoreTypes.PhpValue) { EmitPhpValueAddr(); // PhpValue -> PhpValue addr EmitLoadContext(); // Context EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToString_Context) .Expect(SpecialType.System_String); break; } throw new NotImplementedException($"(string){from}"); } }
/// <summary> /// Gets types referenced by given type mask. /// </summary> public IList<ITypeRef>/*!*/GetTypes(TypeRefMask mask) { return GetTypes(mask, TypeRefMask.AnyTypeMask); }
/// <summary> /// Emits conversion to an object of given type. /// </summary> /// <param name="from">Type of value on top of the evaluation stack.</param> /// <param name="fromHint">Hint in case of multitype value.</param> /// <param name="to">Target type.</param> private void EmitConvertToClass(TypeSymbol from, TypeRefMask fromHint, TypeSymbol to) { Contract.ThrowIfNull(from); Contract.ThrowIfNull(to); Debug.Assert(to.IsReferenceType); Debug.Assert(to != CoreTypes.PhpAlias); Debug.Assert(!to.IsErrorType(), "Trying to convert to an ErrorType"); // -> IPhpCallable if (to == CoreTypes.IPhpCallable) { EmitConvertToIPhpCallable(from, fromHint); return; } // -> System.Array if (to.IsArray()) { var arrt = (ArrayTypeSymbol)to; if (arrt.IsSZArray) { // byte[] if (arrt.ElementType.SpecialType == SpecialType.System_Byte) { // Template: (PhpString).ToBytes(Context) EmitConvertToPhpString(from, fromHint); // PhpString EmitPhpStringAddr(); this.EmitLoadContext(); // Context EmitCall(ILOpCode.Call, CoreMethods.PhpString.ToBytes_Context) .Expect(to); // ToBytes() return; } throw this.NotImplementedException($"Conversion from {from.Name} to {arrt.ElementType.Name}[] is not implemented."); } throw this.NotImplementedException($"Conversion from {from.Name} to array {to.Name} is not implemented."); } // dereference if (from == CoreTypes.PhpAlias) { // <alias>.Value : PhpValue from = Emit_PhpAlias_GetValue(); } if (from.IsReferenceType && from.IsOfType(to)) { return; } Debug.Assert(to != CoreTypes.PhpArray && to != CoreTypes.PhpString && to != CoreTypes.PhpAlias); switch (from.SpecialType) { case SpecialType.System_Void: case SpecialType.System_Int32: case SpecialType.System_Int64: case SpecialType.System_Boolean: case SpecialType.System_Double: case SpecialType.System_String: // Template: null EmitPop(from); _il.EmitNullConstant(); return; default: Debug.Assert(from != CoreTypes.PhpAlias); if (from.IsValueType) { if (from == CoreTypes.PhpValue) { if (IsClassOnly(fromHint)) { // <STACK>.Object EmitPhpValueAddr(); from = EmitCall(ILOpCode.Call, CoreMethods.PhpValue.Object.Getter) .Expect(SpecialType.System_Object); } else { // Convert.AsObject( <STACK> ) from = EmitCall(ILOpCode.Call, CoreMethods.Operators.AsObject_PhpValue) .Expect(SpecialType.System_Object); } } else { // null EmitPop(from); _il.EmitNullConstant(); return; } } // break; } // Template: (T)object EmitCastClass(from, to); }
/// <summary> /// Gets string representation of types contained in given type mask. /// </summary> public string ToString(TypeRefMask mask) { if (!mask.IsVoid) { if (mask.IsAnyType) return TypeRefMask.MixedTypeName; // var types = new List<string>(1); // handle arrays separately var arrmask = mask & _isArrayMask; if (arrmask != 0) { mask &= ~_isArrayMask; ITypeRef elementtype = null; var elementmask = GetElementType(arrmask); if (elementmask.IsSingleType) elementtype = GetTypes(elementmask).FirstOrDefault(); if (elementtype != null) types.Add(elementtype.QualifiedName.ToString() + "[]"); else types.Add(TypeRefFactory.ArrayTypeRef.QualifiedName.ToString()); } //// int|double => number //var isNumber = (_isIntMask != 0 && _isDoubleMask != 0 && (mask & IsNumberMask) == IsNumberMask); //if (isNumber) // mask &= ~IsNumberMask; // types.AddRange(GetTypes(mask).Select(t => t.QualifiedName.ToString())); //if (isNumber) // types.Add("number"); // if (types.Count != 0) { types.Sort(); return string.Join(PHPDocBlock.TypeVarDescTag.TypeNamesSeparator.ToString(), types.Distinct()); } } return TypeRefMask.VoidTypeName; }
/// <summary> /// Emits conversion from one CLR type to another using PHP conventions. /// </summary> /// <param name="from">Type of value on top of evaluation stack.</param> /// <param name="fromHint">Type hint in case of a multityple type choices (like PhpValue or PhpNumber or PhpAlias).</param> /// <param name="to">Target CLR type.</param> /// <param name="conversion">Conversion semantic.</param> public void EmitConvert(TypeSymbol from, TypeRefMask fromHint, TypeSymbol to, ConversionKind conversion = ConversionKind.Implicit) { Contract.ThrowIfNull(from); Contract.ThrowIfNull(to); Debug.Assert(!from.IsUnreachable); Debug.Assert(!to.IsUnreachable); Debug.Assert(!to.IsErrorType(), "Conversion to an error type."); // conversion is not needed: if (from.SpecialType == to.SpecialType && (from == to || (to.SpecialType != SpecialType.System_Object && from.IsOfType(to)))) { return; } if (from.SpecialType == SpecialType.System_Void) { // void -> T EmitLoadDefault(to); return; } // from = EmitSpecialize(from, fromHint); if (from != to) { var conv = DeclaringCompilation.Conversions.ClassifyConversion(from, to, conversion); if (conv.Exists) { ConversionsExtensions.EmitConversion(this, conv, from, to, @checked: false); } else { // specialized conversions: if (to == CoreTypes.PhpValue) { EmitConvertToPhpValue(from, fromHint); } else if (to == CoreTypes.PhpString) { // -> PhpString EmitConvertToPhpString(from, fromHint); } else if (to == CoreTypes.PhpAlias) { EmitConvertToPhpValue(from, fromHint); Emit_PhpValue_MakeAlias(); } else if (to.IsReferenceType) { if (to == CoreTypes.PhpArray || to == CoreTypes.IPhpArray || to == CoreTypes.IPhpEnumerable || to == CoreTypes.PhpHashtable) { // -> PhpArray // TODO: try unwrap "value.Object as T" EmitConvertToPhpArray(from, fromHint); } else { // -> Object, PhpResource EmitConvertToClass(from, fromHint, to); } } else if (to.IsNullableType(out var ttype)) { EmitConvertToNullable_T(from, fromHint, to, ttype, conversion); } else if (to.SpecialType == SpecialType.System_DateTime) { EmitConvertToDateTime(from); } else { throw this.NotImplementedException($"Conversion from '{from}' to '{to}'"); } } } }
/// <summary> /// Gets value indicating whether given type mask represents a string type (readonly or writable). /// </summary> public bool IsAString(TypeRefMask mask) { return (mask.Mask & IsAStringMask) != 0; }
public BoundArrayTypeRef(TypeRefMask elementType) { _elementType = elementType; }
/// <summary> /// Gets value indicating whether given type mask represents a writablke string (string builder). /// </summary> public bool IsWritableString(TypeRefMask mask) { return (mask.Mask & _isWritableStringMask) != 0; }
// TODO: signature public BoundLambdaTypeRef(TypeRefMask returnType) { _returnType = returnType; }
/// <summary> /// Gets value indicating whether given type mask represents an integer type. /// </summary> public bool IsLong(TypeRefMask mask) { return (mask.Mask & _isLongMask) != 0; }
protected virtual TypeSymbol BuildReturnType(Signature signature, TypeRef tref, PHPDocBlock phpdocOpt, TypeRefMask rtype) { if (signature.AliasReturn) { return(DeclaringCompilation.CoreTypes.PhpAlias); } // PHP7 return type if (tref != null) { return(DeclaringCompilation.GetTypeFromTypeRef(tref)); } // var typeCtx = this.TypeRefContext; // if (phpdocOpt != null) { var returnTag = phpdocOpt.Returns; if (returnTag != null && returnTag.TypeNames.Length != 0) { var tmask = PHPDoc.GetTypeMask(typeCtx, returnTag.TypeNamesArray, this.GetNamingContext()); if (!tmask.IsVoid && !tmask.IsAnyType) { return(DeclaringCompilation.GetTypeFromTypeRef(typeCtx, tmask)); } } } // return(DeclaringCompilation.GetTypeFromTypeRef(typeCtx, rtype)); }
/// <summary> /// Gets value indicating whether given type mask represents an object. /// </summary> public bool IsObject(TypeRefMask mask) { return (mask.Mask & _isObjectMask) != 0; }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { return(new BoundLocalPlace(_place, access, thint)); }
/// <summary> /// Gets value indicating whether given type mask represents a lambda function or <c>callable</c> primitive type. /// </summary> public bool IsLambda(TypeRefMask mask) { return (mask.Mask & _isLambdaMask) != 0; }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { if (_isUnoptimized) { return(new BoundIndirectVariablePlace(new BoundLiteral(this.Name), access)); } else { // return((_lazyLocal != null) ? _lazyLocal.BindPlace(il, access, thint) : new BoundLocalPlace(Place(il), access, thint)); } }
/// <summary> /// Gets value indicating whether given type can be <c>null</c>. /// </summary> public bool IsNullable(TypeRefMask mask) { return (mask.Mask & IsNullableMask) != 0; }
/// <summary> /// Gets <see cref="IBoundReference"/> providing load and store operations. /// </summary> internal abstract IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint);
/// <summary> /// Explicitly defines late static bind type (type of <c>static</c>). /// </summary> /// <param name="staticTypeMask">Type mask of <c>static</c> or <c>void</c> if this information is unknown.</param> internal void SetLateStaticBindType(TypeRefMask staticTypeMask) { _staticTypeMask = staticTypeMask; }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { return(new BoundLocalPlace(Place(il), access, _routine.TypeRefContext.GetThisTypeMask())); }
/// <summary> /// Gets value indicating the given type represents a long and nothing else. /// </summary> internal bool IsBooleanOnly(TypeRefMask tmask) { return tmask.IsSingleType && _routine.TypeRefContext.IsBoolean(tmask); }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { // IBoundReference of $_GLOBALS[<name>] if (_name.IsAutoGlobal) { return(new BoundSuperglobalPlace(_name, access)); } else { // <variables>[<name>] return(new BoundGlobalPlace(new BoundLiteral(_name.Value), access)); } }
/// <summary> /// Gets value indicating the given type represents only PHP Array. /// </summary> internal bool IsArrayOnly(TypeRefMask tmask) { return !tmask.IsVoid && !tmask.IsAnyType && _routine.TypeRefContext.GetTypes(tmask).All(x => x.IsArray); }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { if (_place == null) { // unoptimized locals return(new BoundIndirectVariablePlace(new BoundLiteral(this.Name), access)); } else { return(new BoundLocalPlace(_place, access, thint)); } }
/// <summary> /// Initializes <see cref="CallInfo"/>. /// </summary> /// <param name="ctx">Type context of the caller.</param> /// <param name="paramsType">Type of parameters used for the call. Length of the array corresponds to the parameters count.</param> public CallInfo(TypeRefContext ctx, TypeRefMask[] paramsType) : this(ctx, paramsType, 0) { }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { return(new BoundIndirectVariablePlace(_nameExpr, access)); }
/// <summary> /// Gets value indicating the given type represents a long and nothing else. /// </summary> internal bool IsLongOnly(TypeRefMask tmask) { return(tmask.IsSingleType && this.TypeRefContext.IsLong(tmask) && !tmask.IsRef); }
internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint) { Debug.Assert(_name.IsAutoGlobal); return(new BoundSuperglobalPlace(_name, access)); }