Esempio n. 1
0
        /// <summary>
        /// Takes the class passed via the tr, and resolves its base class and/or implemented interfaces.
        /// Also usable for enums.
        ///
        /// Never returns null. Instead, the original 'tr' object will be returned if no base class was resolved.
        /// Will clone 'tr', whereas the new object will contain the base class.
        /// </summary>
        public static UserDefinedType ResolveBaseClasses(UserDefinedType tr, ResolutionContext ctxt, bool ResolveFirstBaseIdOnly = false)
        {
            if (bcStack > 8)
            {
                bcStack--;
                return(tr);
            }

            if (tr is EnumType)
            {
                var et = tr as EnumType;

                AbstractType bt = null;

                if (et.Definition.Type == null)
                {
                    bt = new PrimitiveType(DTokens.Int);
                }
                else
                {
                    if (tr.Definition.Parent is IBlockNode)
                    {
                        ctxt.PushNewScope((IBlockNode)tr.Definition.Parent);
                    }

                    var bts = TypeDeclarationResolver.Resolve(et.Definition.Type, ctxt);

                    if (tr.Definition.Parent is IBlockNode)
                    {
                        ctxt.Pop();
                    }

                    ctxt.CheckForSingleResult(bts, et.Definition.Type);

                    if (bts != null && bts.Length != 0)
                    {
                        bt = bts[0];
                    }
                }

                return(new EnumType(et.Definition, bt, et.DeclarationOrExpressionBase));
            }

            var dc = tr.Definition as DClassLike;

            // Return immediately if searching base classes of the Object class
            if (dc == null || ((dc.BaseClasses == null || dc.BaseClasses.Count < 1) && dc.Name == "Object"))
            {
                return(tr);
            }

            // If no base class(es) specified, and if it's no interface that is handled, return the global Object reference
            // -- and do not throw any error message, it's ok
            if (dc.BaseClasses == null || dc.BaseClasses.Count < 1)
            {
                if (tr is ClassType)                // Only Classes can inherit from non-interfaces
                {
                    return(new ClassType(dc, tr.DeclarationOrExpressionBase, ctxt.ParseCache.ObjectClassResult));
                }
                return(tr);
            }

            #region Base class & interface resolution
            TemplateIntermediateType baseClass = null;
            var interfaces = new List <InterfaceType>();

            if (!(tr is ClassType || tr is InterfaceType))
            {
                if (dc.BaseClasses.Count != 0)
                {
                    ctxt.LogError(dc, "Only classes and interfaces may inherit from other classes/interfaces");
                }
                return(tr);
            }

            for (int i = 0; i < (ResolveFirstBaseIdOnly ? 1 : dc.BaseClasses.Count); i++)
            {
                var type = dc.BaseClasses[i];

                // If there's an explicit 'Object' inheritance, also return the pre-resolved object class
                if (type is IdentifierDeclaration && ((IdentifierDeclaration)type).Id == "Object")
                {
                    if (baseClass != null)
                    {
                        ctxt.LogError(new ResolutionError(dc, "Class must not have two base classes"));
                        continue;
                    }
                    else if (i != 0)
                    {
                        ctxt.LogError(new ResolutionError(dc, "The base class name must preceed base interfaces"));
                        continue;
                    }

                    baseClass = ctxt.ParseCache.ObjectClassResult;
                    continue;
                }

                if (type == null || type.ToString(false) == dc.Name || dc.NodeRoot == dc)
                {
                    ctxt.LogError(new ResolutionError(dc, "A class cannot inherit from itself"));
                    continue;
                }

                ctxt.PushNewScope(dc.Parent as IBlockNode);

                bcStack++;

                var res = DResolver.StripAliasSymbols(TypeDeclarationResolver.Resolve(type, ctxt));

                ctxt.CheckForSingleResult(res, type);

                if (res != null && res.Length != 0)
                {
                    var r = res[0];
                    if (r is ClassType || r is TemplateType)
                    {
                        if (tr is InterfaceType)
                        {
                            ctxt.LogError(new ResolutionError(type, "An interface cannot inherit from non-interfaces"));
                        }
                        else if (i == 0)
                        {
                            baseClass = (TemplateIntermediateType)r;
                        }
                        else
                        {
                            ctxt.LogError(new ResolutionError(dc, "The base " + (r is ClassType ?  "class" : "template") + " name must preceed base interfaces"));
                        }
                    }
                    else if (r is InterfaceType)
                    {
                        interfaces.Add((InterfaceType)r);
                    }
                    else
                    {
                        ctxt.LogError(new ResolutionError(type, "Resolved class is neither a class nor an interface"));
                        continue;
                    }
                }

                bcStack--;

                ctxt.Pop();
            }
            #endregion

            if (baseClass == null && interfaces.Count == 0)
            {
                return(tr);
            }

            if (tr is ClassType)
            {
                return(new ClassType(dc, tr.DeclarationOrExpressionBase, baseClass, interfaces.Count == 0 ? null : interfaces.ToArray(), tr.DeducedTypes));
            }
            else if (tr is InterfaceType)
            {
                return(new InterfaceType(dc, tr.DeclarationOrExpressionBase, interfaces.Count == 0 ? null : interfaces.ToArray(), tr.DeducedTypes));
            }

            // Method should end here
            return(tr);
        }
Esempio n. 2
0
        /// <summary>
        /// string[] s;
        ///
        /// foreach(i;s)
        /// {
        ///		// i is of type 'string'
        ///		writeln(i);
        /// }
        /// </summary>
        public static AbstractType GetForeachIteratorType(DVariable i, ResolutionContext ctxt)
        {
            var r       = new List <AbstractType>();
            var curStmt = ctxt.ScopedStatement;

            bool init = true;

            // Walk up statement hierarchy -- note that foreach loops can be nested
            while (curStmt != null)
            {
                if (init)
                {
                    init = false;
                }
                else
                {
                    curStmt = curStmt.Parent;
                }

                if (curStmt is ForeachStatement)
                {
                    var fe = (ForeachStatement)curStmt;

                    if (fe.ForeachTypeList == null)
                    {
                        continue;
                    }

                    // If the searched variable is declared in the header
                    int iteratorIndex = -1;

                    for (int j = 0; j < fe.ForeachTypeList.Length; j++)
                    {
                        if (fe.ForeachTypeList[j] == i)
                        {
                            iteratorIndex = j;
                            break;
                        }
                    }

                    if (iteratorIndex == -1)
                    {
                        continue;
                    }

                    bool keyIsSearched = iteratorIndex == 0 && fe.ForeachTypeList.Length > 1;


                    // foreach(var k, var v; 0 .. 9)
                    if (keyIsSearched && fe.IsRangeStatement)
                    {
                        // -- it's static type int, of course(?)
                        return(new PrimitiveType(DTokens.Int));
                    }

                    var aggregateType = Evaluation.EvaluateType(fe.Aggregate, ctxt);

                    aggregateType = DResolver.StripMemberSymbols(aggregateType);

                    if (aggregateType == null)
                    {
                        return(null);
                    }

                    // The most common way to do a foreach
                    if (aggregateType is AssocArrayType)
                    {
                        var ar = (AssocArrayType)aggregateType;

                        return(keyIsSearched ? ar.KeyType : ar.ValueType);
                    }
                    else if (aggregateType is UserDefinedType)
                    {
                        var tr = (UserDefinedType)aggregateType;

                        if (keyIsSearched || !(tr.Definition is IBlockNode))
                        {
                            continue;
                        }

                        bool foundIterPropertyMatch = false;
                        #region Foreach over Structs and Classes with Ranges

                        // Enlist all 'back'/'front' members
                        var t_l = new List <AbstractType>();

                        foreach (var n in (IBlockNode)tr.Definition)
                        {
                            if (fe.IsReverse ? n.Name == "back" : n.Name == "front")
                            {
                                t_l.Add(HandleNodeMatch(n, ctxt));
                            }
                        }

                        // Remove aliases
                        var iterPropertyTypes = DResolver.StripAliasSymbols(t_l);

                        foreach (var iterPropType in iterPropertyTypes)
                        {
                            if (iterPropType is MemberSymbol)
                            {
                                foundIterPropertyMatch = true;

                                var itp = (MemberSymbol)iterPropType;

                                // Only take non-parameterized methods
                                if (itp.Definition is DMethod && ((DMethod)itp.Definition).Parameters.Count != 0)
                                {
                                    continue;
                                }

                                // Handle its base type [return type] as iterator type
                                if (itp.Base != null)
                                {
                                    r.Add(itp.Base);
                                }

                                foundIterPropertyMatch = true;
                            }
                        }

                        if (foundIterPropertyMatch)
                        {
                            continue;
                        }
                        #endregion

                        #region Foreach over Structs and Classes with opApply
                        t_l.Clear();
                        r.Clear();

                        foreach (var n in (IBlockNode)tr.Definition)
                        {
                            if (n is DMethod &&
                                (fe.IsReverse ? n.Name == "opApplyReverse" : n.Name == "opApply"))
                            {
                                t_l.Add(HandleNodeMatch(n, ctxt));
                            }
                        }

                        iterPropertyTypes = DResolver.StripAliasSymbols(t_l);

                        foreach (var iterPropertyType in iterPropertyTypes)
                        {
                            if (iterPropertyType is MemberSymbol)
                            {
                                var mr = (MemberSymbol)iterPropertyType;
                                var dm = mr.Definition as DMethod;

                                if (dm == null || dm.Parameters.Count != 1)
                                {
                                    continue;
                                }

                                var dg = dm.Parameters[0].Type as DelegateDeclaration;

                                if (dg == null || dg.Parameters.Count != fe.ForeachTypeList.Length)
                                {
                                    continue;
                                }

                                var paramType = Resolve(dg.Parameters[iteratorIndex].Type, ctxt);

                                if (paramType != null && paramType.Length > 0)
                                {
                                    r.Add(paramType[0]);
                                }
                            }
                        }
                        #endregion
                    }

                    if (r.Count > 1)
                    {
                        ctxt.LogError(new ResolutionError(curStmt, "Ambigous iterator type"));
                    }

                    return(r.Count != 0 ? r[0] : null);
                }
            }

            return(null);
        }