Esempio n. 1
0
 public PhpParam(TypeRefMask tmask, bool isByRef, bool isVariadic, BoundExpression defaultValue)
 {
     this.Type = tmask;
     this.IsVariadic = isVariadic;
     this.DefaultValue = defaultValue;
     this.IsByRef = isByRef;
 }
Esempio n. 2
0
        /// <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;
        }
Esempio n. 3
0
 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);
     }
 }
Esempio n. 4
0
        /// <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;
        }
Esempio n. 5
0
        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;
        }
Esempio n. 6
0
        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;
        }
Esempio n. 7
0
        /// <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();
            }
        }
Esempio n. 8
0
 /// <summary>
 /// Gets value indicating whether given type mask represents a boolean.
 /// </summary>
 public bool IsBoolean(TypeRefMask mask) { return (mask.Mask & _isBoolMask) != 0; }
Esempio n. 9
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}");
        }
Esempio n. 10
0
 public TypeSymbol EmitConvertToPhpValue(TypeSymbol from, TypeRefMask fromHint)
 {
     return(EmitConvertToPhpValue(from, fromHint, _il, _moduleBuilder, _diagnostics));
 }
Esempio n. 11
0
 /// <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);
 }
Esempio n. 12
0
 /// <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)
 {
 }
Esempio n. 13
0
        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();
            }
        }
Esempio n. 14
0
        ///// <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));
 }
Esempio n. 20
0
 /// <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));
 }
Esempio n. 22
0
 /// <summary>
 /// Gets value indicating whether given type mask represents an array.
 /// </summary>
 public bool IsArray(TypeRefMask mask) { return (mask.Mask & _isArrayMask) != 0; }
Esempio n. 23
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();
                }
            }
        }
Esempio n. 24
0
        //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;
        }
Esempio n. 25
0
        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);
        }
Esempio n. 26
0
 /// <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);
 }
Esempio n. 27
0
        /// <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);
        }
Esempio n. 28
0
 /// <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);
 }
Esempio n. 29
0
 /// <summary>
 /// Gets value indicating whether given type mask represents a number.
 /// </summary>
 public bool IsNumber(TypeRefMask mask) { return (mask.Mask & IsNumberMask) != 0; }
Esempio n. 30
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);
 }
Esempio n. 31
0
 /// <summary>
 /// Gets value indicating whether given type mask represents UTF16 readonly string.
 /// </summary>
 public bool IsReadonlyString(TypeRefMask mask) { return (mask.Mask & _isStringMask) != 0; }
Esempio n. 32
0
 public void EmitConvertToBool(TypeSymbol from, TypeRefMask fromHint)
 {
     this.EmitImplicitConversion(from, CoreTypes.Boolean);
 }
Esempio n. 33
0
        /// <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}");
            }
        }
Esempio n. 34
0
 /// <summary>
 /// Gets types referenced by given type mask.
 /// </summary>
 public IList<ITypeRef>/*!*/GetTypes(TypeRefMask mask)
 {
     return GetTypes(mask, TypeRefMask.AnyTypeMask);
 }
Esempio n. 35
0
        /// <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);
        }
Esempio n. 36
0
        /// <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;
        }
Esempio n. 37
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>
        /// <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}'");
                    }
                }
            }
        }
Esempio n. 38
0
 /// <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; }
Esempio n. 39
0
 public BoundArrayTypeRef(TypeRefMask elementType)
 {
     _elementType = elementType;
 }
Esempio n. 40
0
 /// <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; }
Esempio n. 41
0
        // TODO: signature

        public BoundLambdaTypeRef(TypeRefMask returnType)
        {
            _returnType = returnType;
        }
Esempio n. 42
0
 /// <summary>
 /// Gets value indicating whether given type mask represents an integer type.
 /// </summary>
 public bool IsLong(TypeRefMask mask) { return (mask.Mask & _isLongMask) != 0; }
Esempio n. 43
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));
        }
Esempio n. 44
0
 /// <summary>
 /// Gets value indicating whether given type mask represents an object.
 /// </summary>
 public bool IsObject(TypeRefMask mask) { return (mask.Mask & _isObjectMask) != 0; }
Esempio n. 45
0
 internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint)
 {
     return(new BoundLocalPlace(_place, access, thint));
 }
Esempio n. 46
0
 /// <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; }
Esempio n. 47
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));
     }
 }
Esempio n. 48
0
 /// <summary>
 /// Gets value indicating whether given type can be <c>null</c>.
 /// </summary>
 public bool IsNullable(TypeRefMask mask) { return (mask.Mask & IsNullableMask) != 0; }
Esempio n. 49
0
 /// <summary>
 /// Gets <see cref="IBoundReference"/> providing load and store operations.
 /// </summary>
 internal abstract IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint);
Esempio n. 50
0
 /// <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;
 }
Esempio n. 51
0
 internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint)
 {
     return(new BoundLocalPlace(Place(il), access, _routine.TypeRefContext.GetThisTypeMask()));
 }
Esempio n. 52
0
 /// <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);
 }
Esempio n. 53
0
        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));
            }
        }
Esempio n. 54
0
 /// <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);
 }
Esempio n. 55
0
 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));
     }
 }
Esempio n. 56
0
 /// <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)
 {
 }
Esempio n. 57
0
 internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint)
 {
     return(new BoundIndirectVariablePlace(_nameExpr, access));
 }
Esempio n. 58
0
 /// <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);
 }
Esempio n. 59
0
        internal override IBoundReference BindPlace(ILBuilder il, BoundAccess access, TypeRefMask thint)
        {
            Debug.Assert(_name.IsAutoGlobal);

            return(new BoundSuperglobalPlace(_name, access));
        }