public static AbstractType[] ResolveIdentifier(string id, ResolverContextStack ctxt, object idObject, bool ModuleScope = false) { var loc = idObject is ISyntaxRegion ? ((ISyntaxRegion)idObject).Location:CodeLocation.Empty; if (ModuleScope) { ctxt.PushNewScope(ctxt.ScopedBlock.NodeRoot as IAbstractSyntaxTree); } // If there are symbols that must be preferred, take them instead of scanning the ast else { var tstk = new Stack <ResolverContext>(); D_Parser.Resolver.Templates.TemplateParameterSymbol dedTemplateParam = null; while (!ctxt.CurrentContext.DeducedTemplateParameters.TryGetValue(id, out dedTemplateParam)) { if (ctxt.PrevContextIsInSameHierarchy) { tstk.Push(ctxt.Pop()); } else { break; } } while (tstk.Count > 0) { ctxt.Push(tstk.Pop()); } if (dedTemplateParam != null) { return new[] { dedTemplateParam } } ; } var matches = NameScan.SearchMatchesAlongNodeHierarchy(ctxt, loc, id); var res = HandleNodeMatches(matches, ctxt, null, idObject); if (ModuleScope) { ctxt.Pop(); } return(res); }
bool IsMoreSpecialized(ITypeDeclaration Spec, ITemplateParameter t2, Dictionary <string, ISemantic> t1_DummyParamList) { // Make a type out of t1's specialization var frame = ctxt.PushNewScope(ctxt.ScopedBlock.Parent as IBlockNode); // Make the T in e.g. T[] a virtual type so T will be replaced by it // T** will be X** then - so a theoretically valid type instead of a template param var dummyType = new ClassType(new DClassLike { Name = "X" }, null, null); foreach (var kv in t1_DummyParamList) { frame.DeducedTemplateParameters[kv.Key] = new TemplateParameterSymbol(t2, dummyType); } var t1_TypeResults = Resolver.TypeResolution.TypeDeclarationResolver.Resolve(Spec, ctxt); if (t1_TypeResults == null || t1_TypeResults.Length == 0) { return(true); } ctxt.Pop(); // Now try to fit the virtual Type t2 into t1 - and return true if it's possible return(new TemplateParameterDeduction(new DeducedTypeDictionary(), ctxt).Handle(t2, t1_TypeResults[0])); }
public void CacheModuleMethods(IAbstractSyntaxTree ast, ResolverContextStack ctxt) { foreach (var m in ast) { if (m is DMethod) { var dm = (DMethod)m; if (dm.Parameters == null || dm.Parameters.Count == 0 || dm.Parameters[0].Type == null) { continue; } ctxt.PushNewScope(dm); var firstArg_result = TypeDeclarationResolver.Resolve(dm.Parameters[0].Type, ctxt); ctxt.Pop(); if (firstArg_result != null && firstArg_result.Length != 0) { lock (CachedMethods) CachedMethods[dm] = firstArg_result[0]; } } } }
public static bool TryGetImplicitProperty(TemplateType template, ResolverContextStack ctxt, out AbstractType[] matchingChild) { // Check if there are only children that are named as the parent template. // That's the requirement for the special treatment. matchingChild = null; if (!ContainsEquallyNamedChildrenOnly(template.Definition)) { return(false); } // Prepare a new context bool pop = !ctxt.NodeIsInCurrentScopeHierarchy(template.Definition); if (pop) { ctxt.PushNewScope(template.Definition); } // Introduce the deduced params to the current resolution context ctxt.CurrentContext.IntroduceTemplateParameterTypes(template); // Get actual overloads, var overloads = template.Definition[template.Name]; // resolve them var resolvedOverloads = TypeDeclarationResolver.HandleNodeMatches(overloads, ctxt, null, template.DeclarationOrExpressionBase); // and deduce their parameters whereas this time, the parent's parameter are given already, in the case it's e.g. // needed as return type or in a declaration condition: // Furthermore, pass all the arguments that have been passed to the super template, to the child, // so these arguments may be used again for some inner parameters. var args = new List <ISemantic>(template.DeducedTypes.Count); foreach (var kv in template.DeducedTypes) { args.Add((ISemantic)kv.Value.ParameterValue ?? kv.Value.Base); } matchingChild = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(resolvedOverloads, args, true, ctxt); // Undo context-related changes if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(template); } return(matchingChild != null && matchingChild.Length == 1 && matchingChild[0] != null); }
/// <summary> /// </summary> /// <param name="ast">The syntax tree to scan</param> /// <param name="symbol">Might not be a child symbol of ast</param> /// <param name="ctxt">The context required to search for symbols</param> /// <returns></returns> public static IEnumerable<ISyntaxRegion> Scan(IAbstractSyntaxTree ast, INode symbol, ResolverContextStack ctxt) { if (ast == null || symbol == null || ctxt == null) return null; ctxt.PushNewScope(ast); var f = new ReferencesFinder(symbol, ast, ctxt); f.S(ast); ctxt.Pop(); return f.l; }
/// <summary> /// </summary> /// <param name="ast">The syntax tree to scan</param> /// <param name="symbol">Might not be a child symbol of ast</param> /// <param name="ctxt">The context required to search for symbols</param> /// <returns></returns> public static IEnumerable <ISyntaxRegion> Scan(IAbstractSyntaxTree ast, INode symbol, ResolverContextStack ctxt) { if (ast == null || symbol == null || ctxt == null) { return(null); } ctxt.PushNewScope(ast); var f = new ReferencesFinder(symbol, ast, ctxt); f.S(ast); ctxt.Pop(); return(f.l); }
public void CacheModuleMethods(IAbstractSyntaxTree ast, ResolverContextStack ctxt) { foreach (var m in ast) if (m is DMethod) { var dm = (DMethod)m; if (dm.Parameters == null || dm.Parameters.Count == 0 || dm.Parameters[0].Type == null) continue; ctxt.PushNewScope(dm); var firstArg_result = TypeDeclarationResolver.Resolve(dm.Parameters[0].Type, ctxt); ctxt.Pop(); if (firstArg_result != null && firstArg_result.Length != 0) lock (CachedMethods) CachedMethods[dm] = firstArg_result[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, ResolverContextStack 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 = 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); }
public static AbstractType GetMethodReturnType(DMethod method, ResolverContextStack ctxt) { if (ctxt != null && ctxt.Options.HasFlag(ResolutionOptions.DontResolveBaseTypes)) { return(null); } /* * If a method's type equals null, assume that it's an 'auto' function.. * 1) Search for a return statement * 2) Resolve the returned expression * 3) Use that one as the method's type */ bool pushMethodScope = ctxt.ScopedBlock != method; if (method.Type != null) { if (pushMethodScope) { ctxt.PushNewScope(method); } //FIXME: Is it legal to explicitly return a nested type? var returnType = TypeDeclarationResolver.Resolve(method.Type, ctxt); if (pushMethodScope) { ctxt.Pop(); } if (ctxt.CheckForSingleResult(returnType, method.Type)) { return(returnType[0]); } } else if (method.Body != null) { ReturnStatement returnStmt = null; var list = new List <IStatement> { method.Body }; var list2 = new List <IStatement>(); bool foundMatch = false; while (!foundMatch && list.Count > 0) { foreach (var stmt in list) { if (stmt is ReturnStatement) { returnStmt = stmt as ReturnStatement; if (!(returnStmt.ReturnExpression is TokenExpression) || (returnStmt.ReturnExpression as TokenExpression).Token != DTokens.Null) { foundMatch = true; break; } } if (stmt is StatementContainingStatement) { list2.AddRange((stmt as StatementContainingStatement).SubStatements); } } list = list2; list2 = new List <IStatement>(); } if (returnStmt != null && returnStmt.ReturnExpression != null) { if (pushMethodScope) { var dedTypes = ctxt.CurrentContext.DeducedTemplateParameters; ctxt.PushNewScope(method); ctxt.CurrentContext.ScopedStatement = returnStmt; if (dedTypes.Count != 0) { foreach (var kv in dedTypes) { ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value; } } } var t = Evaluation.EvaluateType(returnStmt.ReturnExpression, ctxt); if (pushMethodScope) { ctxt.Pop(); } return(t); } } return(null); }
/// <summary> /// The variable's or method's base type will be resolved (if auto type, the intializer's type will be taken). /// A class' base class will be searched. /// etc.. /// </summary> public static AbstractType HandleNodeMatch( INode m, ResolverContextStack ctxt, AbstractType resultBase = null, object typeBase = null) { stackNum_HandleNodeMatch++; /* * Pushing a new scope is only required if current scope cannot be found in the handled node's hierarchy. */ bool popAfterwards = !ctxt.NodeIsInCurrentScopeHierarchy(m); if (popAfterwards) { ctxt.PushNewScope(m is IBlockNode ? (IBlockNode)m : m.Parent as IBlockNode); } //HACK: Really dirty stack overflow prevention via manually counting call depth var canResolveBaseGenerally = stackNum_HandleNodeMatch < 6; var DoResolveBaseType = canResolveBaseGenerally && !ctxt.Options.HasFlag(ResolutionOptions.DontResolveBaseClasses) && (m.Type == null || m.Type.ToString(false) != m.Name); AbstractType ret = null; // To support resolving type parameters to concrete types if the context allows this, introduce all deduced parameters to the current context if (canResolveBaseGenerally && resultBase is DSymbol) { ctxt.CurrentContext.IntroduceTemplateParameterTypes((DSymbol)resultBase); } // Only import symbol aliases are allowed to search in the parse cache if (m is ImportSymbolAlias) { var isa = (ImportSymbolAlias)m; if (isa.IsModuleAlias ? isa.Type != null : isa.Type.InnerDeclaration != null) { var mods = new List <DModule>(); var td = isa.IsModuleAlias ? isa.Type : isa.Type.InnerDeclaration; foreach (var mod in ctxt.ParseCache.LookupModuleName(td.ToString())) { mods.Add(mod as DModule); } if (mods.Count == 0) { ctxt.LogError(new NothingFoundError(isa.Type)); } else if (mods.Count > 1) { var m__ = new List <ISemantic>(); foreach (var mod in mods) { m__.Add(new ModuleSymbol(mod, isa.Type)); } ctxt.LogError(new AmbiguityError(isa.Type, m__)); } var bt = mods.Count != 0 ? (AbstractType) new ModuleSymbol(mods[0], td) : null; //TODO: Is this correct behaviour? if (!isa.IsModuleAlias) { var furtherId = ResolveFurtherTypeIdentifier(isa.Type.ToString(false), new[] { bt }, ctxt, isa.Type); ctxt.CheckForSingleResult(furtherId, isa.Type); if (furtherId != null && furtherId.Length != 0) { bt = furtherId[0]; } else { bt = null; } } ret = new AliasedType(isa, bt, isa.Type); } } else if (m is DVariable) { var v = (DVariable)m; AbstractType bt = null; if (DoResolveBaseType) { var bts = TypeDeclarationResolver.Resolve(v.Type, ctxt); if (bts != null && bts.Length != 0 && ctxt.CheckForSingleResult(bts, v.Type)) { bt = bts[0]; } // For auto variables, use the initializer to get its type else if (v.Initializer != null) { bt = ExpressionSemantics.Evaluation.EvaluateType(v.Initializer, ctxt); } // Check if inside an foreach statement header if (bt == null && ctxt.ScopedStatement != null) { bt = GetForeachIteratorType(v, ctxt); } } // Note: Also works for aliases! In this case, we simply try to resolve the aliased type, otherwise the variable's base type ret = v.IsAlias ? (DSymbol) new AliasedType(v, bt, typeBase as ISyntaxRegion) : new MemberSymbol(v, bt, typeBase as ISyntaxRegion); } else if (m is DMethod) { ret = new MemberSymbol((DNode)m, DoResolveBaseType ? GetMethodReturnType((DMethod)m, ctxt) : null , typeBase as ISyntaxRegion); } else if (m is DClassLike) { UserDefinedType udt = null; var dc = (DClassLike)m; var invisibleTypeParams = new Dictionary <string, TemplateParameterSymbol>(); /* * Add 'superior' template parameters to the current symbol because the parameters * might be re-used in the nested class. */ var tStk = new Stack <ResolverContext>(); do { var curCtxt = ctxt.Pop(); tStk.Push(curCtxt); foreach (var kv in curCtxt.DeducedTemplateParameters) { if (!dc.ContainsTemplateParameter(kv.Key) && !invisibleTypeParams.ContainsKey(kv.Key)) { invisibleTypeParams.Add(kv.Key, kv.Value); } } } while (ctxt.PrevContextIsInSameHierarchy); while (tStk.Count != 0) { ctxt.Push(tStk.Pop()); } switch (dc.ClassType) { case DTokens.Struct: ret = new StructType(dc, typeBase as ISyntaxRegion, invisibleTypeParams); break; case DTokens.Union: ret = new UnionType(dc, typeBase as ISyntaxRegion, invisibleTypeParams); break; case DTokens.Class: udt = new ClassType(dc, typeBase as ISyntaxRegion, null, null, invisibleTypeParams); break; case DTokens.Interface: udt = new InterfaceType(dc, typeBase as ISyntaxRegion, null, invisibleTypeParams); break; case DTokens.Template: ret = new TemplateType(dc, typeBase as ISyntaxRegion, invisibleTypeParams); break; default: ctxt.LogError(new ResolutionError(m, "Unknown type (" + DTokens.GetTokenString(dc.ClassType) + ")")); break; } if (dc.ClassType == DTokens.Class || dc.ClassType == DTokens.Interface) { if (canResolveBaseGenerally && !ctxt.Options.HasFlag(ResolutionOptions.DontResolveBaseClasses)) { ret = DResolver.ResolveBaseClasses(udt, ctxt); } else { ret = udt; } } } else if (m is IAbstractSyntaxTree) { var mod = (IAbstractSyntaxTree)m; if (typeBase != null && typeBase.ToString() != mod.ModuleName) { var pack = ctxt.ParseCache.LookupPackage(typeBase.ToString()).First(); if (pack != null) { ret = new PackageSymbol(pack, typeBase as ISyntaxRegion); } } else { ret = new ModuleSymbol(m as DModule, typeBase as ISyntaxRegion); } } else if (m is DEnum) { ret = new EnumType((DEnum)m, typeBase as ISyntaxRegion); } else if (m is TemplateParameterNode) { //ResolveResult[] templateParameterType = null; //TODO: Resolve the specialization type //var templateParameterType = TemplateInstanceHandler.ResolveTypeSpecialization(tmp, ctxt); ret = new TemplateParameterSymbol((TemplateParameterNode)m, null, typeBase as ISyntaxRegion); } if (canResolveBaseGenerally && resultBase is DSymbol) { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals((DSymbol)resultBase); } if (popAfterwards) { ctxt.Pop(); } stackNum_HandleNodeMatch--; return(ret); }
/// <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()); }
public static AbstractType[] ResolveIdentifier(string id, ResolverContextStack ctxt, object idObject, bool ModuleScope = false) { var loc = idObject is ISyntaxRegion ? ((ISyntaxRegion)idObject).Location:CodeLocation.Empty; if (ModuleScope) ctxt.PushNewScope(ctxt.ScopedBlock.NodeRoot as IAbstractSyntaxTree); // If there are symbols that must be preferred, take them instead of scanning the ast else { var tstk = new Stack<ResolverContext>(); D_Parser.Resolver.Templates.TemplateParameterSymbol dedTemplateParam = null; while (!ctxt.CurrentContext.DeducedTemplateParameters.TryGetValue(id, out dedTemplateParam)) { if (ctxt.PrevContextIsInSameHierarchy) tstk.Push(ctxt.Pop()); else break; } while (tstk.Count > 0) ctxt.Push(tstk.Pop()); if (dedTemplateParam!=null) return new[]{ dedTemplateParam }; } var matches = NameScan.SearchMatchesAlongNodeHierarchy(ctxt, loc, id); var res= HandleNodeMatches(matches, ctxt, null, idObject); if (ModuleScope) ctxt.Pop(); return res; }
/// <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(); }
/// <summary> /// The variable's or method's base type will be resolved (if auto type, the intializer's type will be taken). /// A class' base class will be searched. /// etc.. /// </summary> public static AbstractType HandleNodeMatch( INode m, ResolverContextStack ctxt, AbstractType resultBase = null, object typeBase = null) { stackNum_HandleNodeMatch++; bool popAfterwards = m.Parent != ctxt.ScopedBlock && m.Parent is IBlockNode; if (popAfterwards) ctxt.PushNewScope((IBlockNode)m.Parent); //HACK: Really dirty stack overflow prevention via manually counting call depth var canResolveBaseGenerally = stackNum_HandleNodeMatch < 6; var DoResolveBaseType = canResolveBaseGenerally && !ctxt.Options.HasFlag(ResolutionOptions.DontResolveBaseClasses) && (m.Type == null || m.Type.ToString(false) != m.Name); AbstractType ret = null; // To support resolving type parameters to concrete types if the context allows this, introduce all deduced parameters to the current context if (canResolveBaseGenerally && resultBase is DSymbol) ctxt.CurrentContext.IntroduceTemplateParameterTypes((DSymbol)resultBase); // Only import symbol aliases are allowed to search in the parse cache if (m is ImportSymbolAlias) { var isa = (ImportSymbolAlias)m; if (isa.IsModuleAlias ? isa.Type != null : isa.Type.InnerDeclaration != null) { var mods = new List<DModule>(); var td=isa.IsModuleAlias ? isa.Type : isa.Type.InnerDeclaration; foreach (var mod in ctxt.ParseCache.LookupModuleName(td.ToString())) mods.Add(mod as DModule); if(mods.Count == 0) ctxt.LogError(new NothingFoundError(isa.Type)); else if(mods.Count > 1) { var m__=new List<ISemantic>(); foreach(var mod in mods) m__.Add(new ModuleSymbol(mod, isa.Type)); ctxt.LogError(new AmbiguityError(isa.Type,m__)); } var bt=mods.Count != 0 ? (AbstractType)new ModuleSymbol(mods[0], td) : null; //TODO: Is this correct behaviour? if (!isa.IsModuleAlias){ var furtherId = ResolveFurtherTypeIdentifier(isa.Type.ToString(false), new[]{ bt }, ctxt, isa.Type); ctxt.CheckForSingleResult(furtherId, isa.Type); if (furtherId != null && furtherId.Length != 0) bt = furtherId[0]; else bt = null; } ret = new AliasedType(isa, bt, isa.Type); } } else if (m is DVariable) { var v = (DVariable)m; AbstractType bt = null; if (DoResolveBaseType) { var bts = TypeDeclarationResolver.Resolve(v.Type, ctxt); if (bts != null && bts.Length != 0 && ctxt.CheckForSingleResult(bts, v.Type)) bt = bts[0]; // For auto variables, use the initializer to get its type else if (v.Initializer != null) bt = ExpressionSemantics.Evaluation.EvaluateType(v.Initializer, ctxt); // Check if inside an foreach statement header if (bt == null && ctxt.ScopedStatement != null) bt = GetForeachIteratorType(v, ctxt); } // Note: Also works for aliases! In this case, we simply try to resolve the aliased type, otherwise the variable's base type ret=v.IsAlias ? (DSymbol)new AliasedType(v, bt, typeBase as ISyntaxRegion) : new MemberSymbol(v, bt, typeBase as ISyntaxRegion); } else if (m is DMethod) { ret = new MemberSymbol((DNode)m, DoResolveBaseType ? GetMethodReturnType((DMethod)m, ctxt) : null , typeBase as ISyntaxRegion); } else if (m is DClassLike) { UserDefinedType udt = null; var dc=(DClassLike)m; switch (dc.ClassType) { case DTokens.Struct: udt = new StructType(dc, typeBase as ISyntaxRegion); break; case DTokens.Union: udt = new UnionType(dc, typeBase as ISyntaxRegion); break; case DTokens.Class: udt = new ClassType(dc, typeBase as ISyntaxRegion, null); break; case DTokens.Template: udt = new TemplateType(dc, typeBase as ISyntaxRegion); break; case DTokens.Interface: udt = new InterfaceType(dc, typeBase as ISyntaxRegion); break; default: ctxt.LogError(new ResolutionError(m, "Unknown type ("+DTokens.GetTokenString(dc.ClassType)+")")); break; } if (canResolveBaseGenerally && !ctxt.Options.HasFlag(ResolutionOptions.DontResolveBaseClasses)) ret = DResolver.ResolveBaseClasses(udt, ctxt); else ret = udt; } else if (m is IAbstractSyntaxTree) { var mod = (IAbstractSyntaxTree)m; if (typeBase != null && typeBase.ToString() != mod.ModuleName) { var pack = ctxt.ParseCache.LookupPackage(typeBase.ToString()).First(); if (pack != null) ret = new PackageSymbol(pack, typeBase as ISyntaxRegion); } else ret = new ModuleSymbol(m as DModule, typeBase as ISyntaxRegion); } else if (m is DEnum) ret = new EnumType((DEnum)m, typeBase as ISyntaxRegion); else if (m is TemplateParameterNode) { var tmp = ((TemplateParameterNode)m).TemplateParameter; //ResolveResult[] templateParameterType = null; //TODO: Resolve the specialization type //var templateParameterType = TemplateInstanceHandler.ResolveTypeSpecialization(tmp, ctxt); ret = new MemberSymbol((DNode)m, null, typeBase as ISyntaxRegion); } if (canResolveBaseGenerally && resultBase is DSymbol) ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals((DSymbol)resultBase); if (popAfterwards) ctxt.Pop(); stackNum_HandleNodeMatch--; return ret; }
public static AbstractType GetMethodReturnType(DMethod method, ResolverContextStack ctxt) { if (ctxt!=null && ctxt.Options.HasFlag(ResolutionOptions.DontResolveBaseTypes)) return null; /* * If a method's type equals null, assume that it's an 'auto' function.. * 1) Search for a return statement * 2) Resolve the returned expression * 3) Use that one as the method's type */ if (method.Type != null) { var returnType = TypeDeclarationResolver.Resolve(method.Type, ctxt); if (ctxt.CheckForSingleResult(returnType, method.Type)) return returnType[0]; } else if (method.Body != null) { ReturnStatement returnStmt = null; var list = new List<IStatement> { method.Body }; var list2 = new List<IStatement>(); bool foundMatch = false; while (!foundMatch && list.Count > 0) { foreach (var stmt in list) { if (stmt is ReturnStatement) { returnStmt = stmt as ReturnStatement; if (!(returnStmt.ReturnExpression is TokenExpression) || (returnStmt.ReturnExpression as TokenExpression).Token != DTokens.Null) { foundMatch = true; break; } } if (stmt is StatementContainingStatement) list2.AddRange((stmt as StatementContainingStatement).SubStatements); } list = list2; list2 = new List<IStatement>(); } if (returnStmt != null && returnStmt.ReturnExpression != null) { ctxt.PushNewScope(method); var t= Evaluation.EvaluateType(returnStmt.ReturnExpression, ctxt); ctxt.Pop(); return t; } } return null; }
public static MemberSymbol[] TryResolveUFCS( ISemantic firstArgument, PostfixExpression_Access acc, ResolverContextStack ctxt) { if (ctxt == null) { return(null); } var name = ""; if (acc.AccessExpression is IdentifierExpression) { name = ((IdentifierExpression)acc.AccessExpression).Value as string; } else if (acc.AccessExpression is TemplateInstanceExpression) { name = ((TemplateInstanceExpression)acc.AccessExpression).TemplateIdentifier.Id; } else { return(null); } var methodMatches = new List <MemberSymbol>(); if (ctxt.ParseCache != null) { foreach (var pc in ctxt.ParseCache) { var tempResults = pc.UfcsCache.FindFitting(ctxt, acc.Location, firstArgument, name); if (tempResults != null) { foreach (var m in tempResults) { ctxt.PushNewScope(m); if (m.TemplateParameters != null && m.TemplateParameters.Length != 0) { var ov = TemplateInstanceHandler.DeduceParamsAndFilterOverloads( new[] { new MemberSymbol(m, null, acc) }, new[] { firstArgument }, true, ctxt); if (ov == null || ov.Length == 0) { continue; } var ms = (DSymbol)ov[0]; ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); } var mr = TypeDeclarationResolver.HandleNodeMatch(m, ctxt, null, acc) as MemberSymbol; ctxt.Pop(); if (mr != null) { mr.IsUFCSResult = true; methodMatches.Add(mr); } } } } } return(methodMatches.Count == 0 ? null : methodMatches.ToArray()); }