Context of TypeRefMask and ITypeRef instances. Contains additional information for routine context like current namespace, current type context etc.
コード例 #1
0
ファイル: TypeRefFactory.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Converts CLR type symbol to TypeRef used by flow analysis.
        /// </summary>
        public static ITypeRef CreateTypeRef(TypeRefContext ctx, TypeSymbol t)
        {
            Contract.ThrowIfNull(t);

            switch (t.SpecialType)
            {
                case SpecialType.System_Void: throw new ArgumentException();
                case SpecialType.System_Int32:
                case SpecialType.System_Int64: return LongTypeRef;
                case SpecialType.System_String: return StringTypeRef;
                case SpecialType.System_Double: return DoubleTypeRef;
                case SpecialType.System_Boolean: return BoolTypeRef;
                case SpecialType.System_Object: return new ClassTypeRef(NameUtils.SpecialNames.System_Object);
                case SpecialType.System_DateTime: return new ClassTypeRef(new QualifiedName(new Name("DateTime"), new[] { new Name("System") }));
                default:
                    if (t is NamedTypeSymbol)
                    {
                        return new ClassTypeRef(((NamedTypeSymbol)t).MakeQualifiedName());
                    }
                    else if (t is ArrayTypeSymbol)
                    {
                        var arr = (ArrayTypeSymbol)t;
                        if (!arr.IsSZArray)
                        {
                            throw new NotImplementedException();
                        }

                        return new ArrayTypeRef(null, CreateMask(ctx, arr.ElementType));
                    }
                    else
                    {
                        throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(t);
                    }
            }
        }
コード例 #2
0
ファイル: BoundExpression.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Gets type mask of the literal within given type context.
        /// </summary>
        internal TypeRefMask ResolveTypeMask(TypeRefContext typeCtx)
        {
            Debug.Assert(this.ConstantValue.HasValue);
            var value = this.ConstantValue.Value;

            if (value == null)
            {
                return typeCtx.GetNullTypeMask();
            }
            else
            {
                if (value is long || value is int)
                {
                    return typeCtx.GetLongTypeMask();
                }
                else if (value is string)
                {
                    return typeCtx.GetStringTypeMask();
                }
                else if (value is bool)
                {
                    return typeCtx.GetBooleanTypeMask();
                }
                else if (value is double)
                {
                    return typeCtx.GetDoubleTypeMask();
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Resolves list of input arguments.
        /// Implicit parameters passed by compiler are ignored.
        /// </summary>
        /// <param name="routine">Routine.</param>
        /// <param name="ctx">TYpe context to transmer type masks into.</param>
        /// <returns>List of input PHP arguments.</returns>
        public static PhpParam[] GetExpectedArguments(this IPhpRoutineSymbol routine, TypeRefContext ctx)
        {
            Contract.ThrowIfNull(routine);

            var ps = routine.Parameters;
            var table = (routine as SourceRoutineSymbol)?.LocalsTable;
            var result = new List<PhpParam>(ps.Length);

            foreach (ParameterSymbol p in ps)
            {
                if (result.Count == 0 && p.IsImplicitlyDeclared)
                {
                    continue;
                }

                // default value (bound expression)
                ConstantValue cvalue;
                var psrc = p as SourceParameterSymbol;
                var defaultexpr = psrc != null
                    ? psrc.Initializer
                    : ((cvalue = p.ExplicitDefaultConstantValue) != null ? new BoundLiteral(cvalue.Value) : null);

                //
                var phpparam = new PhpParam(
                    TypeRefFactory.CreateMask(ctx, p.Type),
                    p.RefKind != RefKind.None,
                    p.IsParams,
                    defaultexpr);

                result.Add(phpparam);
            }

            //
            return result.ToArray();
        }
コード例 #4
0
ファイル: TypeRefFactory.cs プロジェクト: iolevel/peachpie
        public static TypeRefMask CreateMask(TypeRefContext ctx, TypeSymbol t)
        {
            Contract.ThrowIfNull(t);

            switch (t.SpecialType)
            {
                case SpecialType.System_Void: return 0;
                case SpecialType.System_Int64: return ctx.GetLongTypeMask();
                case SpecialType.System_String: return ctx.GetStringTypeMask();
                case SpecialType.System_Double: return ctx.GetDoubleTypeMask();
                case SpecialType.System_Boolean: return ctx.GetBooleanTypeMask();
                case SpecialType.None:
                    var containing = t.ContainingAssembly;
                    if (containing != null && containing.IsPchpCorLibrary)
                    {
                        if (t.Name == "PhpValue") return TypeRefMask.AnyType;
                        if (t.Name == "PhpAlias") return TypeRefMask.AnyType.WithRefFlag;
                        if (t.Name == "PhpNumber") return ctx.GetNumberTypeMask();
                        if (t.Name == "PhpString") return ctx.GetWritableStringTypeMask();
                        if (t.Name == "PhpArray") return ctx.GetArrayTypeMask();
                        if (t.Name == "IPhpCallable") return ctx.GetCallableTypeMask();
                    }

                    break;
            }

            return CreateMask(ctx, CreateTypeRef(ctx, t));
        }
コード例 #5
0
ファイル: FlowContext.cs プロジェクト: iolevel/peachpie
        internal FlowContext(TypeRefContext/*!*/typeCtx, SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(typeCtx);
            
            _typeCtx = typeCtx;
            _routine = routine;

            //
            _varsIndex = new Dictionary<VariableName, int>();
        }
コード例 #6
0
ファイル: PHPDoc.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Gets type mask representing given type name.
        /// </summary>
        public static TypeRefMask GetTypeMask(TypeRefContext/*!*/typeCtx, string tname, NamingContext naming, bool fullyQualified = false)
        {
            if (!string.IsNullOrEmpty(tname))
            {
                // handle various array conventions
                if (tname.LastCharacter() == ']')
                {
                    // "TName[]"
                    if (tname.EndsWith("[]", StringComparison.Ordinal))
                    {
                        var elementType = GetTypeMask(typeCtx, tname.Remove(tname.Length - 2), naming, fullyQualified);
                        return typeCtx.GetArrayTypeMask(elementType);
                    }

                    // "array[TName]"
                    var arrayTypeName = QualifiedName.Array.Name.Value;
                    if (tname.Length > arrayTypeName.Length && tname[arrayTypeName.Length] == '[' &&
                        tname.StartsWith(arrayTypeName, StringComparison.OrdinalIgnoreCase))
                    {
                        var elementTypeName = tname.Substring(arrayTypeName.Length + 1, tname.Length - arrayTypeName.Length - 2);
                        var elementType = GetTypeMask(typeCtx, elementTypeName, naming, fullyQualified);
                        return typeCtx.GetArrayTypeMask(elementType);
                    }

                    // unknown something // ...                    
                }
                else
                {
                    var result = GetKnownTypeMask(typeCtx, tname);
                    if (result.IsUninitialized)
                    {
                        var qname = NameUtils.MakeQualifiedName(tname, false);
                        if (!fullyQualified && naming != null && !qname.IsReservedClassName)
                            qname = QualifiedName.TranslateAlias(qname, AliasKind.Type, naming.Aliases, naming.CurrentNamespace);

                        if (qname.IsPrimitiveTypeName)
                        {
                            result = GetKnownTypeMask(typeCtx, qname.Name.Value);
                            if (!result.IsUninitialized)
                                return result;
                        }

                        result = typeCtx.GetTypeMask(qname, true);
                    }

                    //Contract.Assert(!result.IsUninitialized);
                    return result;
                }
            }

            return 0;
        }
コード例 #7
0
ファイル: PHPDoc.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Gets type mask of known PHPDoc type name or <c>0</c> if such type is now known.
        /// </summary>
        public static TypeRefMask GetKnownTypeMask(TypeRefContext/*!*/typeCtx, string tname)
        {
            Contract.ThrowIfNull(typeCtx);
            if (!string.IsNullOrEmpty(tname))
            {
                TypeMaskGetter getter;
                if (_knownTypes.TryGetValue(tname, out getter))
                {
                    return getter(typeCtx);
                }
            }

            return 0;   // void
        }
コード例 #8
0
        /// <summary>
        /// Gets expected return type mask of given symbol (field, function, method or property).
        /// </summary>
        /// <remarks>Returned type mask corresponds to types that can be returned by invoking given symbol.</remarks>
        public static TypeRefMask GetResultType(this IPhpValue symbol, TypeRefContext ctx)
        {
            Contract.ThrowIfNull(symbol);
            Contract.ThrowIfNull(ctx);

            TypeSymbol t;

            if (symbol is FieldSymbol)
            {
                t = ((FieldSymbol)symbol).Type;
            }
            else if (symbol is MethodSymbol)
            {
                var m = (MethodSymbol)symbol;
                var r = symbol as SourceRoutineSymbol;
                if (r != null && r.IsStatic)
                {
                    // In case of a static function, we can return expected return type mask exactly.
                    // Such function cannot be overriden and we know exactly what the return type will be even the CLR type covers more possibilities.
                    return ctx.AddToContext(r.TypeRefContext, r.ResultTypeMask);
                }

                t = m.ReturnType;
            }
            else if (symbol is PropertySymbol)
            {
                t = ((PropertySymbol)symbol).Type;
            }
            else if (symbol is ParameterSymbol)
            {
                t = ((ParameterSymbol)symbol).Type;
            }
            else
            {
                throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(symbol);
            }

            // create the type mask from the CLR type symbol
            var mask = TypeRefFactory.CreateMask(ctx, t);

            // [CastToFalse]
            if (symbol is IPhpRoutineSymbol && ((IPhpRoutineSymbol)symbol).CastToFalse)
            {
                mask |= ctx.GetBooleanTypeMask();    // the function may return FALSE
            }

            //
            return mask;
        }
コード例 #9
0
ファイル: OverloadsList.cs プロジェクト: iolevel/peachpie
        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;
        }
コード例 #10
0
ファイル: PHPDoc.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Gets type mask at target type context representing given type names from given routine.
        /// </summary>
        public static TypeRefMask GetTypeMask(TypeRefContext/*!*/targetCtx, TypeRefContext/*!*/ctx, string[] tnames, NamingContext naming, bool fullyQualified = false)
        {
            Contract.ThrowIfNull(targetCtx);
            Contract.ThrowIfNull(ctx);

            var mask = GetTypeMask(ctx, tnames, naming, fullyQualified);
            return targetCtx.AddToContext(ctx, mask);
        }
コード例 #11
0
ファイル: CallInfo.cs プロジェクト: ruo2012/peachpie
 /// <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)
 {
 }
コード例 #12
0
ファイル: CallInfo.cs プロジェクト: iolevel/peachpie
 /// <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)
 {
 }
コード例 #13
0
ファイル: CallInfo.cs プロジェクト: iolevel/peachpie
 /// <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>
 public CallInfo(TypeRefContext ctx, int paramsCount)
     : this(ctx, paramsCount, 0)
 {
 }
コード例 #14
0
ファイル: CallInfo.cs プロジェクト: ruo2012/peachpie
 /// <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);
 }
コード例 #15
0
 public virtual ITypeRef /*!*/ Transfer(TypeRefContext /*!*/ source, TypeRefContext /*!*/ target)
 {
     return(this);
 }                                                                                                             // there is nothing depending on the context
コード例 #16
0
 public ITypeRef /*!*/ Transfer(TypeRefContext /*!*/ source, TypeRefContext /*!*/ target)
 {
     return(this);
 }
コード例 #17
0
ファイル: SourceCompiler.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Enqueues the standalone expression for analysis.
        /// </summary>
        void EnqueueExpression(BoundExpression expression, TypeRefContext/*!*/ctx, NamingContext naming)
        {
            Contract.ThrowIfNull(expression);
            Contract.ThrowIfNull(ctx);

            var dummy = new BoundBlock()
            {
                FlowState = new FlowState(new FlowContext(ctx, null)),
                Naming = naming
            };

            dummy.Add(new BoundExpressionStatement(expression));

            _worklist.Enqueue(dummy);
        }
コード例 #18
0
ファイル: TypeRefFactory.cs プロジェクト: iolevel/peachpie
        public static TypeRefMask CreateMask(TypeRefContext ctx, ITypeRef tref)
        {
            Contract.ThrowIfNull(tref);

            TypeRefMask result = 0;

            result.AddType(ctx.AddToContext(tref));

            if (!tref.IsPrimitiveType && !tref.IsArray)
            {
                result.IncludesSubclasses = true;
            }

            return result;
        }
コード例 #19
0
ファイル: CallInfo.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Gets actual parameter type if provided. Otherwise <c>void</c>.
        /// </summary>
        /// <param name="ctx">Target type context.</param>
        /// <param name="index">Index of parameter.</param>
        /// <returns>Type mask of the parameter or <c>void</c>.</returns>
        public TypeRefMask GetParamType(TypeRefContext/*!*/ctx, int index)
        {
            if (ctx == null) throw new ArgumentNullException("ctx");

            if (_typeCtx != null && index >= 0 && index < _paramsType.Length)
                return ctx.AddToContext(_typeCtx, _paramsType[index]);

            return 0;
        }
コード例 #20
0
ファイル: CallInfo.cs プロジェクト: ruo2012/peachpie
 /// <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)
 {
 }
コード例 #21
0
ファイル: TypeRefContext.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Adds properly types from another context.
        /// </summary>
        /// <param name="other">Another type context which types will be added to this one.</param>
        internal void AddToContext(TypeRefContext/*!*/other)
        {
            Contract.ThrowIfNull(other);

            foreach (var typeref in other.Types)
            {
                AddToContext(typeref.Transfer(other, this));
            }
        }
コード例 #22
0
ファイル: TypeRefContext.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Adds properly types from another context matching given mask.
        /// </summary>
        /// <param name="context">Context of <paramref name="mask"/>.</param>
        /// <param name="mask">Type mask representing types in <paramref name="context"/>.</param>
        /// <returns>Returns type mask in this context representing <paramref name="mask"/> as <paramref name="context"/>.</returns>
        public TypeRefMask AddToContext(TypeRefContext/*!*/context, TypeRefMask mask)
        {
            Contract.ThrowIfNull(context);

            if (mask.IsAnyType || mask.IsVoid || object.ReferenceEquals(this, context))
                return mask;

            var result = default(TypeRefMask);

            var types = context.Types;
            var count = Math.Min(types.Count, TypeRefMask.IndicesCount);
            for (int i = 0; i < count; i++)
            {
                if (mask.HasType(i))
                {
                    var index = AddToContext(types[i].Transfer(context, this));
                    result.AddType(index);
                }
            }

            //
            result.IsRef = mask.IsRef;
            result.IncludesSubclasses = mask.IncludesSubclasses;

            //
            return result;
        }
コード例 #23
0
ファイル: CallInfo.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Gets actual lates static bind type (type of <c>static</c>) if provided.
        /// Otherwise <c>void</c>.
        /// </summary>
        /// <param name="ctx">Target type context.</param>
        /// <returns>TYpe mask of <c>static</c> in given context or <c>void</c>.</returns>
        public TypeRefMask GetLateStaticBindType(TypeRefContext/*!*/ctx)
        {
            if (ctx == null) throw new ArgumentNullException("ctx");

            if (_typeCtx != null && !_lateStaticBindType.IsUninitialized)
                return ctx.AddToContext(_typeCtx, _lateStaticBindType);

            return 0;
        }
コード例 #24
0
ファイル: PHPDoc.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Gets type mask representing given type name.
        /// </summary>
        public static TypeRefMask GetTypeMask(TypeRefContext/*!*/typeCtx, string[] tnames, NamingContext naming, bool fullyQualified = false)
        {
            TypeRefMask result = 0;

            foreach (var tname in tnames)
                result |= GetTypeMask(typeCtx, tname, naming, fullyQualified);

            return result;
        }
コード例 #25
0
ファイル: CallInfo.cs プロジェクト: iolevel/peachpie
 /// <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)
 {
 }
コード例 #26
0
ファイル: PHPDoc.cs プロジェクト: iolevel/peachpie
        /// <summary>
        /// Gets type mask at target ctype context representing given type names from given routine.
        /// </summary>
        public static TypeRefMask GetTypeMask(TypeRefContext/*!*/targetCtx, Symbols.SourceRoutineSymbol/*!*/routine, string[] tnames, bool fullyQualified = false)
        {
            Contract.ThrowIfNull(targetCtx);
            Contract.ThrowIfNull(routine);

            return GetTypeMask(targetCtx, routine.TypeRefContext, tnames, routine.GetNamingContext(), fullyQualified);
        }
コード例 #27
0
ファイル: CallInfo.cs プロジェクト: iolevel/peachpie
 /// <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);
 }
コード例 #28
0
ファイル: CallInfo.cs プロジェクト: ruo2012/peachpie
 /// <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>
 public CallInfo(TypeRefContext ctx, int paramsCount)
     : this(ctx, paramsCount, 0)
 {
 }