Пример #1
0
            /// <summary>
            /// string[] s;
            ///
            /// foreach(i;s)
            /// {
            ///		// i is of type 'string'
            ///		writeln(i);
            /// }
            /// </summary>
            public AbstractType GetForeachIteratorType(DVariable i)
            {
                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 = ExpressionTypeEvaluation.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);
            }
Пример #2
0
        private static List <AbstractType> DeduceOverloads(
            IEnumerable <AbstractType> rawOverloadList,
            IEnumerable <ISemantic> givenTemplateArguments,
            bool isMethodCall,
            ResolverContextStack ctxt)
        {
            bool hasTemplateArgsPassed = givenTemplateArguments != null;

            if (hasTemplateArgsPassed)
            {
                var enumm = givenTemplateArguments.GetEnumerator();
                hasTemplateArgsPassed = enumm.MoveNext();
                enumm.Dispose();
            }

            var filteredOverloads = new List <AbstractType>();

            if (rawOverloadList == null)
            {
                return(filteredOverloads);
            }

            foreach (var o in DResolver.StripAliasSymbols(rawOverloadList))
            {
                if (!(o is DSymbol))
                {
                    if (!hasTemplateArgsPassed)
                    {
                        filteredOverloads.Add(o);
                    }
                    continue;
                }

                var overload = (DSymbol)o;
                var tplNode  = overload.Definition;

                // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params
                if (tplNode == null)
                {
                    filteredOverloads.Add(overload);
                    continue;
                }

                // If the type or method has got no template parameters and if there were no args passed, keep it - it's legit.
                if (tplNode.TemplateParameters == null)
                {
                    if (!hasTemplateArgsPassed || isMethodCall)
                    {
                        filteredOverloads.Add(overload);
                    }
                    continue;
                }

                var deducedTypes = new DeducedTypeDictionary {
                    ParameterOwner = tplNode
                };
                foreach (var param in tplNode.TemplateParameters)
                {
                    deducedTypes[param.Name] = null;                     // Init all params to null to let deduction functions know what params there are
                }
                if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes))
                {
                    overload.DeducedTypes = deducedTypes.ToReadonly();                     // Assign calculated types to final result
                    filteredOverloads.Add(overload);
                }
                else
                {
                    overload.DeducedTypes = null;
                }
            }
            return(filteredOverloads);
        }
Пример #3
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 TemplateIntermediateType ResolveClassOrInterface(DClassLike dc, ResolutionContext ctxt, ISyntaxRegion instanceDeclaration, bool ResolveFirstBaseIdOnly = false, IEnumerable <TemplateParameterSymbol> extraDeducedTemplateParams = null)
        {
            if (parsedClassInstanceDecls == null)
            {
                parsedClassInstanceDecls = new List <ISyntaxRegion> ();
            }

            switch (dc.ClassType)
            {
            case DTokens.Class:
            case DTokens.Interface:
                break;

            default:
                if (dc.BaseClasses.Count != 0)
                {
                    ctxt.LogError(dc, "Only classes and interfaces may inherit from other classes/interfaces");
                }
                return(null);
            }

            bool isClass = dc.ClassType == DTokens.Class;

            if (bcStack > 6 || (instanceDeclaration != null && parsedClassInstanceDecls.Contains(instanceDeclaration)))
            {
                return(isClass ? new ClassType(dc, instanceDeclaration, null) as TemplateIntermediateType : new InterfaceType(dc, instanceDeclaration));
            }

            if (instanceDeclaration != null)
            {
                parsedClassInstanceDecls.Add(instanceDeclaration);
            }
            bcStack++;

            var deducedTypes = new DeducedTypeDictionary(dc);
            var tix          = instanceDeclaration as TemplateInstanceExpression;

            if (tix != null && (ctxt.Options & ResolutionOptions.NoTemplateParameterDeduction) == 0)
            {
                bool hasUndeterminedArgs;
                var  givenTemplateArguments = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasUndeterminedArgs);

                if (!TemplateInstanceHandler.DeduceParams(givenTemplateArguments, false, ctxt, null, dc, deducedTypes))
                {
                    parsedClassInstanceDecls.Remove(instanceDeclaration);
                    bcStack--;
                    return(null);
                }
            }

            if (extraDeducedTemplateParams != null)
            {
                foreach (var tps in extraDeducedTemplateParams)
                {
                    deducedTypes[tps.Parameter] = tps;
                }
            }


            if (dc.BaseClasses == null || dc.BaseClasses.Count < 1)
            {
                parsedClassInstanceDecls.Remove(instanceDeclaration);
                bcStack--;

                // The Object class has no further base class;
                // Normal class instances have the object as base class;
                // Interfaces must not have any default base class/interface
                return(isClass ? new ClassType(dc, instanceDeclaration, dc.NameHash != ObjectNameHash ? ctxt.ParseCache.ObjectClassResult : null, null, deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null) :
                       new InterfaceType(dc, instanceDeclaration, null, deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null) as TemplateIntermediateType);
            }


            #region Base class & interface resolution
            AbstractType[] res;
            var            pop = ctxt.ScopedBlock != dc.Parent;
            if (pop)
            {
                ctxt.PushNewScope(dc.Parent as IBlockNode);
            }

            foreach (var kv in deducedTypes)
            {
                ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value;
            }

            TemplateIntermediateType baseClass = null;
            var interfaces = new List <InterfaceType>();
            try
            {
                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 &&
                        (type as IdentifierDeclaration).IdHash == ObjectNameHash)
                    {
                        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 is IdentifierDeclaration && (type as IdentifierDeclaration).IdHash == dc.NameHash) || dc.NodeRoot == dc)
                    {
                        ctxt.LogError(new ResolutionError(dc, "A class cannot inherit from itself"));
                        continue;
                    }

                    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 (!isClass)
                            {
                                ctxt.LogError(new ResolutionError(type, "An interface cannot inherit from non-interfaces"));
                            }
                            else if (i == 0)
                            {
                                baseClass = r as TemplateIntermediateType;
                            }
                            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(r as InterfaceType);

                            if (isClass && dc.NameHash != ObjectNameHash && baseClass == null)
                            {
                                baseClass = ctxt.ParseCache.ObjectClassResult;
                            }
                        }
                        else
                        {
                            ctxt.LogError(new ResolutionError(type, "Resolved class is neither a class nor an interface"));
                            continue;
                        }
                    }
                }
            }
            finally
            {
                bcStack--;
                parsedClassInstanceDecls.Remove(instanceDeclaration);
            }

            if (pop)
            {
                ctxt.Pop();
            }
            else
            {
                foreach (var kv in deducedTypes)                 // May be backup old tps?
                {
                    ctxt.CurrentContext.DeducedTemplateParameters.Remove(kv.Key);
                }
            }

            #endregion

            if (isClass)
            {
                return(new ClassType(dc, instanceDeclaration, baseClass, interfaces.Count == 0 ? null : interfaces.ToArray(), deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null));
            }

            return(new InterfaceType(dc, instanceDeclaration, interfaces.Count == 0 ? null : interfaces.ToArray(), deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null));
        }
Пример #4
0
        /// <summary>
        /// Used for searching further identifier list parts.
        ///
        /// a.b -- nextIdentifier would be 'b' whereas <param name="resultBases">resultBases</param> contained the resolution result for 'a'
        /// </summary>
        public static AbstractType[] ResolveFurtherTypeIdentifier(string nextIdentifier,
                                                                  IEnumerable <AbstractType> resultBases,
                                                                  ResolverContextStack ctxt,
                                                                  object typeIdObject = null)
        {
            if ((resultBases = DResolver.StripAliasSymbols(resultBases)) == null)
            {
                return(null);
            }

            var r = new List <AbstractType>();

            var nextResults = new List <AbstractType>();

            foreach (var b in resultBases)
            {
                IEnumerable <AbstractType> scanResults = new[] { b };

                do
                {
                    foreach (var scanResult in scanResults)
                    {
                        // First filter out all alias and member results..so that there will be only (Static-)Type or Module results left..
                        if (scanResult is MemberSymbol)
                        {
                            var mr = (MemberSymbol)scanResult;

                            if (mr.Base != null)
                            {
                                nextResults.Add(mr.Base);
                            }
                        }

                        else if (scanResult is UserDefinedType)
                        {
                            var udt         = (UserDefinedType)scanResult;
                            var bn          = udt.Definition as IBlockNode;
                            var nodeMatches = NameScan.ScanNodeForIdentifier(bn, nextIdentifier, ctxt);

                            ctxt.PushNewScope(bn);
                            ctxt.CurrentContext.IntroduceTemplateParameterTypes(udt);

                            var results = HandleNodeMatches(nodeMatches, ctxt, b, typeIdObject);

                            if (results != null)
                            {
                                foreach (var res in results)
                                {
                                    r.Add(AbstractType.Get(res));
                                }
                            }

                            ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(udt);
                            ctxt.Pop();
                        }
                        else if (scanResult is PackageSymbol)
                        {
                            var pack = ((PackageSymbol)scanResult).Package;

                            IAbstractSyntaxTree accessedModule = null;
                            if (pack.Modules.TryGetValue(nextIdentifier, out accessedModule))
                            {
                                r.Add(new ModuleSymbol(accessedModule as DModule, typeIdObject as ISyntaxRegion, (PackageSymbol)scanResult));
                            }
                            else if (pack.Packages.TryGetValue(nextIdentifier, out pack))
                            {
                                r.Add(new PackageSymbol(pack, typeIdObject as ISyntaxRegion));
                            }
                        }
                        else if (scanResult is ModuleSymbol)
                        {
                            var modRes = (ModuleSymbol)scanResult;

                            var matches = NameScan.ScanNodeForIdentifier(modRes.Definition, nextIdentifier, ctxt);

                            var results = HandleNodeMatches(matches, ctxt, b, typeIdObject);

                            if (results != null)
                            {
                                foreach (var res in results)
                                {
                                    r.Add(AbstractType.Get(res));
                                }
                            }
                        }
                    }

                    scanResults = DResolver.FilterOutByResultPriority(ctxt, nextResults);
                    nextResults = new List <AbstractType>();
                }while (scanResults != null);
            }

            return(r.Count == 0 ? null : r.ToArray());
        }