Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
SymbolResolver.cs764 linesDownload Raw Back to parser
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.Globalization;7using System.IO;8using System.Linq;9using System.Linq.Expressions;10using System.Management.Automation.Runspaces;11using System.Runtime.CompilerServices;12 13using Microsoft.PowerShell.Commands;14 15namespace System.Management.Automation.Language16{17    internal enum ScopeType18    {19        Type,           // class or enum20        Method,         // class method21        Function,       // function22        ScriptBlock     // script or anonymous script block23    }24 25    internal class TypeLookupResult26    {27        public TypeLookupResult(TypeDefinitionAst type = null)28        {29            Type = type;30        }31 32        public TypeDefinitionAst Type { get; set; }33 34        public List<string> ExternalNamespaces { get; set; }35 36        public bool IsAmbiguous()37        {38            return (ExternalNamespaces != null && ExternalNamespaces.Count > 1);39        }40    }41 42    internal class Scope43    {44        internal Ast _ast;45        internal ScopeType _scopeType;46        /// <summary>47        /// TypeTable maps namespace (currently it's module name) to the types under this namespace.48        /// For the types defined in the current namespace (module) we use CURRENT_NAMESPACE as a namespace.49        /// </summary>50        private readonly Dictionary<string, TypeLookupResult> _typeTable;51        private readonly Dictionary<string, Ast> _variableTable;52 53        internal Scope(IParameterMetadataProvider ast, ScopeType scopeType)54        {55            _ast = (Ast)ast;56            _scopeType = scopeType;57            _typeTable = new Dictionary<string, TypeLookupResult>(StringComparer.OrdinalIgnoreCase);58            _variableTable = new Dictionary<string, Ast>(StringComparer.OrdinalIgnoreCase);59        }60 61        internal Scope(TypeDefinitionAst typeDefinition)62        {63            _ast = typeDefinition;64            _scopeType = ScopeType.Type;65            _typeTable = new Dictionary<string, TypeLookupResult>(StringComparer.OrdinalIgnoreCase);66            _variableTable = new Dictionary<string, Ast>(StringComparer.OrdinalIgnoreCase);67            foreach (var member in typeDefinition.Members)68            {69                var propertyMember = member as PropertyMemberAst;70                if (propertyMember != null)71                {72                    // Duplicate members are an error, but we catch that later after all types73                    // have been resolved.  We could report errors for properties here, but74                    // we couldn't compare methods because overloads can't be compared until types75                    // are resolved.76                    if (!_variableTable.ContainsKey(propertyMember.Name))77                    {78                        _variableTable.Add(propertyMember.Name, propertyMember);79                    }80                }81            }82        }83 84        internal void AddType(Parser parser, TypeDefinitionAst typeDefinitionAst)85        {86            TypeLookupResult result;87            if (_typeTable.TryGetValue(typeDefinitionAst.Name, out result))88            {89                if (result.ExternalNamespaces != null)90                {91                    // override external type by the type defined in the current namespace92                    result.ExternalNamespaces = null;93                    result.Type = typeDefinitionAst;94                }95                else96                {97                    parser.ReportError(typeDefinitionAst.Extent,98                        nameof(ParserStrings.MemberAlreadyDefined),99                        ParserStrings.MemberAlreadyDefined,100                        typeDefinitionAst.Name);101                }102            }103            else104            {105                _typeTable.Add(typeDefinitionAst.Name, new TypeLookupResult(typeDefinitionAst));106            }107        }108 109        internal void AddTypeFromUsingModule(Parser parser, TypeDefinitionAst typeDefinitionAst, PSModuleInfo moduleInfo)110        {111            TypeLookupResult result;112            if (_typeTable.TryGetValue(typeDefinitionAst.Name, out result))113            {114                // override external type by the type defined in the current namespace115                result.ExternalNamespaces?.Add(moduleInfo.Name);116            }117            else118            {119                var newLookupEntry = new TypeLookupResult(typeDefinitionAst)120                {121                    ExternalNamespaces = new List<string>()122                };123                newLookupEntry.ExternalNamespaces.Add(moduleInfo.Name);124                _typeTable.Add(typeDefinitionAst.Name, newLookupEntry);125            }126 127            string fullName = SymbolResolver.GetModuleQualifiedName(moduleInfo.Name, typeDefinitionAst.Name);128            if (_typeTable.TryGetValue(fullName, out result))129            {130                parser.ReportError(typeDefinitionAst.Extent,131                    nameof(ParserStrings.MemberAlreadyDefined),132                    ParserStrings.MemberAlreadyDefined,133                    fullName);134            }135            else136            {137                _typeTable.Add(fullName, new TypeLookupResult(typeDefinitionAst));138            }139        }140 141        internal TypeLookupResult LookupType(TypeName typeName)142        {143            if (typeName.AssemblyName != null)144            {145                return null;146            }147 148            TypeLookupResult typeLookupResult;149            _typeTable.TryGetValue(typeName.Name, out typeLookupResult);150            return typeLookupResult;151        }152 153        public Ast LookupVariable(VariablePath variablePath)154        {155            Ast variabledefinition;156            _variableTable.TryGetValue(variablePath.UserPath, out variabledefinition);157            return variabledefinition;158        }159    }160 161    internal class SymbolTable162    {163        internal readonly List<Scope> _scopes;164        internal readonly Parser _parser;165 166        internal SymbolTable(Parser parser)167        {168            _scopes = new List<Scope>();169            _parser = parser;170        }171 172        internal void AddTypesInScope(Ast ast)173        {174            // On entering a scope, we first add all the types defined in this scope (but not any nested scopes)175            // This way, we can support types that refer to each other, e.g.176            //     class C1 { [C2]$x }177            //     class C2 { [C1]$c1 }178 179            var types = ast.FindAll(static x => x is TypeDefinitionAst, searchNestedScriptBlocks: false);180            foreach (var type in types)181            {182                AddType((TypeDefinitionAst)type);183            }184        }185 186        internal void EnterScope(IParameterMetadataProvider ast, ScopeType scopeType)187        {188            var scope = new Scope(ast, scopeType);189            _scopes.Add(scope);190            AddTypesInScope((Ast)ast);191        }192 193        internal void EnterScope(TypeDefinitionAst typeDefinition)194        {195            var scope = new Scope(typeDefinition);196            _scopes.Add(scope);197            AddTypesInScope(typeDefinition);198        }199 200        internal void LeaveScope()201        {202            Diagnostics.Assert(_scopes.Count > 0, "Scope stack can't be empty when leaving a scope");203            _scopes.RemoveAt(_scopes.Count - 1);204        }205 206        /// <summary>207        /// Add Type to the symbol Table.208        /// </summary>209        /// <param name="typeDefinitionAst"></param>210        public void AddType(TypeDefinitionAst typeDefinitionAst)211        {212            _scopes[_scopes.Count - 1].AddType(_parser, typeDefinitionAst);213        }214 215        /// <summary>216        /// Add Type from the different module to the symbol Table.217        /// </summary>218        /// <param name="typeDefinitionAst"></param>219        /// <param name="moduleInfo"></param>220        public void AddTypeFromUsingModule(TypeDefinitionAst typeDefinitionAst, PSModuleInfo moduleInfo)221        {222            _scopes[_scopes.Count - 1].AddTypeFromUsingModule(_parser, typeDefinitionAst, moduleInfo);223        }224 225        public TypeLookupResult LookupType(TypeName typeName)226        {227            TypeLookupResult result = null;228            for (int i = _scopes.Count - 1; i >= 0; i--)229            {230                result = _scopes[i].LookupType(typeName);231                if (result != null)232                    break;233            }234 235            return result;236        }237 238        public Ast LookupVariable(VariablePath variablePath)239        {240            Ast result = null;241            for (int i = _scopes.Count - 1; i >= 0; i--)242            {243                result = _scopes[i].LookupVariable(variablePath);244                if (result != null)245                    break;246            }247 248            return result;249        }250 251        /// <summary>252        /// Return the most deep typeDefinitionAst in the current context.253        /// </summary>254        /// <returns>TypeDefinitionAst or null, if currently not in type definition.</returns>255        public TypeDefinitionAst GetCurrentTypeDefinitionAst()256        {257            for (int i = _scopes.Count - 1; i >= 0; i--)258            {259                TypeDefinitionAst ast = _scopes[i]._ast as TypeDefinitionAst;260                if (ast != null)261                {262                    return ast;263                }264            }265 266            return null;267        }268 269        public bool IsInMethodScope()270        {271            return _scopes[_scopes.Count - 1]._scopeType == ScopeType.Method;272        }273    }274 275    internal sealed class SymbolResolver : AstVisitor2, IAstPostVisitHandler276    {277        private readonly SymbolResolvePostActionVisitor _symbolResolvePostActionVisitor;278        internal readonly SymbolTable _symbolTable;279        internal readonly Parser _parser;280        internal readonly TypeResolutionState _typeResolutionState;281 282        [ThreadStatic]283        private static PowerShell t_usingStatementResolvePowerShell;284 285        private static PowerShell UsingStatementResolvePowerShell286        {287            get288            {289                // The goal is to re-use runspaces, because creating runspace is an expensive part in creating PowerShell instance.290                if (t_usingStatementResolvePowerShell == null)291                {292                    if (Runspace.DefaultRunspace != null)293                    {294                        t_usingStatementResolvePowerShell = PowerShell.Create(RunspaceMode.CurrentRunspace);295                    }296                    else297                    {298                        // Create empty iss and populate only commands, that we want to use.299                        InitialSessionState iss = InitialSessionState.Create();300                        iss.Commands.Add(new SessionStateCmdletEntry("Get-Module", typeof(GetModuleCommand), null));301                        var sessionStateProviderEntry = new SessionStateProviderEntry(FileSystemProvider.ProviderName, typeof(FileSystemProvider), null);302                        var snapin = PSSnapInReader.ReadEnginePSSnapIns().FirstOrDefault(static snapIn => snapIn.Name.Equals("Microsoft.PowerShell.Core", StringComparison.OrdinalIgnoreCase));303                        sessionStateProviderEntry.SetPSSnapIn(snapin);304                        iss.Providers.Add(sessionStateProviderEntry);305                        t_usingStatementResolvePowerShell = PowerShell.Create(iss);306                    }307                }308                else if (Runspace.DefaultRunspace != null && t_usingStatementResolvePowerShell.Runspace != Runspace.DefaultRunspace)309                {310                    t_usingStatementResolvePowerShell = PowerShell.Create(RunspaceMode.CurrentRunspace);311                }312 313                return t_usingStatementResolvePowerShell;314            }315        }316 317        private SymbolResolver(Parser parser, TypeResolutionState typeResolutionState)318        {319            _symbolTable = new SymbolTable(parser);320            _parser = parser;321            _typeResolutionState = typeResolutionState;322            _symbolResolvePostActionVisitor = new SymbolResolvePostActionVisitor { _symbolResolver = this };323        }324 325        internal static void ResolveSymbols(Parser parser, ScriptBlockAst scriptBlockAst)326        {327            Diagnostics.Assert(scriptBlockAst.Parent == null, "Can only resolve starting from the root");328 329            var usingState = scriptBlockAst.UsingStatements.Count > 0330                ? new TypeResolutionState(TypeOps.GetNamespacesForTypeResolutionState(scriptBlockAst.UsingStatements), TypeResolutionState.emptyAssemblies)331                : TypeResolutionState.GetDefaultUsingState(null);332            var resolver = new SymbolResolver(parser, usingState);333            resolver._symbolTable.EnterScope(scriptBlockAst, ScopeType.ScriptBlock);334            scriptBlockAst.Visit(resolver);335            resolver._symbolTable.LeaveScope();336 337            Diagnostics.Assert(resolver._symbolTable._scopes.Count == 0, "Somebody missed removing a scope");338        }339 340        public override AstVisitAction VisitTypeDefinition(TypeDefinitionAst typeDefinitionAst)341        {342            _symbolTable.EnterScope(typeDefinitionAst);343            return AstVisitAction.Continue;344        }345 346        public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)347        {348            _symbolTable.EnterScope(scriptBlockExpressionAst.ScriptBlock, ScopeType.ScriptBlock);349            return AstVisitAction.Continue;350        }351 352        public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)353        {354            if (functionDefinitionAst.Parent is not FunctionMemberAst)355            {356                _symbolTable.EnterScope(functionDefinitionAst.Body, ScopeType.Function);357            }358 359            return AstVisitAction.Continue;360        }361 362        public override AstVisitAction VisitPropertyMember(PropertyMemberAst propertyMemberAst)363        {364            return AstVisitAction.Continue;365        }366 367        public override AstVisitAction VisitFunctionMember(FunctionMemberAst functionMemberAst)368        {369            _symbolTable.EnterScope(functionMemberAst.Body, ScopeType.Method);370            return AstVisitAction.Continue;371        }372 373        public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst)374        {375            if (_symbolTable.IsInMethodScope())376            {377                var targets = assignmentStatementAst.GetAssignmentTargets().ToArray();378                foreach (var expressionAst in targets)379                {380                    var expression = expressionAst;381                    var variableExpressionAst = expression as VariableExpressionAst;382                    while (variableExpressionAst == null && expression != null)383                    {384                        var convertExpressionAst = expression as ConvertExpressionAst;385                        if (convertExpressionAst != null)386                        {387                            expression = convertExpressionAst.Child;388                            variableExpressionAst = convertExpressionAst.Child as VariableExpressionAst;389                        }390                        else391                        {392                            break;393                        }394                    }395 396                    if (variableExpressionAst != null && variableExpressionAst.VariablePath.IsVariable)397                    {398                        var ast = _symbolTable.LookupVariable(variableExpressionAst.VariablePath);399                        var propertyMember = ast as PropertyMemberAst;400                        if (propertyMember != null)401                        {402                            if (propertyMember.IsStatic)403                            {404                                var typeAst = _symbolTable.GetCurrentTypeDefinitionAst();405                                Diagnostics.Assert(typeAst != null, "Method scopes can exist only inside type definitions.");406 407                                string typeString = string.Create(CultureInfo.InvariantCulture, $"[{typeAst.Name}]::");408                                _parser.ReportError(variableExpressionAst.Extent,409                                    nameof(ParserStrings.MissingTypeInStaticPropertyAssignment),410                                    ParserStrings.MissingTypeInStaticPropertyAssignment,411                                    typeString,412                                    propertyMember.Name);413                            }414                            else415                            {416                                _parser.ReportError(variableExpressionAst.Extent,417                                    nameof(ParserStrings.MissingThis),418                                    ParserStrings.MissingThis,419                                    "$this.",420                                    propertyMember.Name);421                            }422                        }423                    }424                }425                // TODO: static look for alias and function.426            }427 428            return AstVisitAction.Continue;429        }430 431        public override AstVisitAction VisitTypeExpression(TypeExpressionAst typeExpressionAst)432        {433            DispatchTypeName(typeExpressionAst.TypeName, genericArgumentCount: 0, isAttribute: false);434            return AstVisitAction.Continue;435        }436 437        public override AstVisitAction VisitTypeConstraint(TypeConstraintAst typeConstraintAst)438        {439            DispatchTypeName(typeConstraintAst.TypeName, genericArgumentCount: 0, isAttribute: false);440            return AstVisitAction.Continue;441        }442 443        /// <summary>444        /// Resolves using module to a collection of PSModuleInfos. Doesn't throw.445        /// PSModuleInfo objects are returned in the right order: i.e. if multiply versions of the module446        /// is presented on the system and user didn't specify version, we will return all of them, but newer one would go first.447        /// </summary>448        /// <param name="usingStatementAst">Using statement.</param>449        /// <param name="exception">If exception happens, return exception object.</param>450        /// <param name="wildcardCharactersUsed">451        /// True if in the module name uses wildcardCharacter.452        /// We don't want to resolve any wild-cards in using module.453        /// </param>454        /// <param name="isConstant">True if module hashtable contains constant value (it's our requirement).</param>455        /// <returns>Modules, if can resolve it. null if any problems happens.</returns>456        private Collection<PSModuleInfo> GetModulesFromUsingModule(UsingStatementAst usingStatementAst, out Exception exception, out bool wildcardCharactersUsed, out bool isConstant)457        {458            exception = null;459            wildcardCharactersUsed = false;460            isConstant = true;461 462            // fullyQualifiedName can be string or hashtable463            object fullyQualifiedName;464            if (usingStatementAst.ModuleSpecification != null)465            {466                object resultObject;467                if (!IsConstantValueVisitor.IsConstant(usingStatementAst.ModuleSpecification, out resultObject, forAttribute: false, forRequires: true))468                {469                    isConstant = false;470                    return null;471                }472 473                var hashtable = resultObject as System.Collections.Hashtable;474                var ms = new ModuleSpecification();475                exception = ModuleSpecification.ModuleSpecificationInitHelper(ms, hashtable);476                if (exception != null)477                {478                    return null;479                }480 481                if (WildcardPattern.ContainsWildcardCharacters(ms.Name))482                {483                    wildcardCharactersUsed = true;484                    return null;485                }486 487                fullyQualifiedName = ms;488            }489            else490            {491                string fullyQualifiedNameStr = usingStatementAst.Name.Value;492 493                if (WildcardPattern.ContainsWildcardCharacters(fullyQualifiedNameStr))494                {495                    wildcardCharactersUsed = true;496                    return null;497                }498 499                // case 1: relative path. Relative for file in the same folder should include .\ or ./500                bool isPath = fullyQualifiedNameStr.Contains('\\') || fullyQualifiedNameStr.Contains('/');501                if (isPath && !LocationGlobber.IsAbsolutePath(fullyQualifiedNameStr))502                {503                    string rootPath = Path.GetDirectoryName(_parser._fileName);504                    if (rootPath != null)505                    {506                        fullyQualifiedNameStr = Path.Combine(rootPath, fullyQualifiedNameStr);507                    }508                }509 510                // case 2: Module by name511                // case 3: Absolute Path512                // We don't need to do anything for these cases, FullyQualifiedName already handle it.513 514                fullyQualifiedName = fullyQualifiedNameStr;515            }516 517            var commandInfo = new CmdletInfo("Get-Module", typeof(GetModuleCommand));518            // TODO(sevoroby): we should consider an async call with cancellation here.519            UsingStatementResolvePowerShell.Commands.Clear();520            try521            {522                return UsingStatementResolvePowerShell.AddCommand(commandInfo)523                    .AddParameter("FullyQualifiedName", fullyQualifiedName)524                    .AddParameter("ListAvailable", true)525                    .Invoke<PSModuleInfo>();526            }527            catch (Exception e)528            {529                exception = e;530                return null;531            }532        }533 534        public override AstVisitAction VisitUsingStatement(UsingStatementAst usingStatementAst)535        {536            if (usingStatementAst.UsingStatementKind == UsingStatementKind.Module)537            {538                Exception exception;539                bool wildcardCharactersUsed;540                bool isConstant;541                var moduleInfo = GetModulesFromUsingModule(usingStatementAst, out exception, out wildcardCharactersUsed, out isConstant);542                if (!isConstant)543                {544                    _parser.ReportError(usingStatementAst.Extent,545                        nameof(ParserStrings.RequiresArgumentMustBeConstant),546                        ParserStrings.RequiresArgumentMustBeConstant);547                }548                else if (exception != null)549                {550                    // we re-using RequiresModuleInvalid string, semantic is very similar so it's fine to do that.551                    _parser.ReportError(usingStatementAst.Extent,552                        nameof(ParserStrings.RequiresModuleInvalid),553                        ParserStrings.RequiresModuleInvalid,554                        exception.Message);555                }556                else if (wildcardCharactersUsed)557                {558                    _parser.ReportError(usingStatementAst.Extent,559                        nameof(ParserStrings.WildCardModuleNameError),560                        ParserStrings.WildCardModuleNameError);561                }562                else if (moduleInfo != null && moduleInfo.Count > 0)563                {564                    // it's ok, if we get more then one module. They are already sorted in the right order565                    // we just need to use the first one566 567                    // We must add the same objects (in sense of object refs) to usingStatementAst typeTable and to symbolTable.568                    // Later, this same TypeDefinitionAsts would be used in DefineTypes(), by the module, where it was imported from at compile time.569                    var exportedTypes = usingStatementAst.DefineImportedModule(moduleInfo[0]);570                    foreach (var typePairs in exportedTypes)571                    {572                        _symbolTable.AddTypeFromUsingModule(typePairs.Value, moduleInfo[0]);573                    }574                }575                else576                {577                    // if there is no exception, but we didn't find the module then it's not present578                    string moduleText = usingStatementAst.Name != null ? usingStatementAst.Name.Value : usingStatementAst.ModuleSpecification.Extent.Text;579                    _parser.ReportError(usingStatementAst.Extent,580                        nameof(ParserStrings.ModuleNotFoundDuringParse),581                        ParserStrings.ModuleNotFoundDuringParse,582                        moduleText);583                }584            }585 586            return AstVisitAction.Continue;587        }588 589        public override AstVisitAction VisitAttribute(AttributeAst attributeAst)590        {591            DispatchTypeName(attributeAst.TypeName, genericArgumentCount: 0, isAttribute: true);592            return AstVisitAction.Continue;593        }594 595        private bool DispatchTypeName(ITypeName type, int genericArgumentCount, bool isAttribute)596        {597            RuntimeHelpers.EnsureSufficientExecutionStack();598            var typeName = type as TypeName;599            if (typeName != null)600            {601                return VisitTypeName(typeName, genericArgumentCount, isAttribute);602            }603            else604            {605                var arrayTypeName = type as ArrayTypeName;606                if (arrayTypeName != null)607                {608                    return VisitArrayTypeName(arrayTypeName);609                }610                else611                {612                    var genericTypeName = type as GenericTypeName;613                    if (genericTypeName != null)614                    {615                        return VisitGenericTypeName(genericTypeName);616                    }617                }618            }619 620            return false;621        }622 623        private bool VisitArrayTypeName(ArrayTypeName arrayTypeName)624        {625            bool resolved = DispatchTypeName(arrayTypeName.ElementType, genericArgumentCount: 0, isAttribute: false);626            if (resolved)627            {628                var resolvedType = arrayTypeName.GetReflectionType();629                TypeCache.Add(arrayTypeName, _typeResolutionState, resolvedType);630            }631 632            return resolved;633        }634 635        private bool VisitTypeName(TypeName typeName, int genericArgumentCount, bool isAttribute)636        {637            var classDefn = _symbolTable.LookupType(typeName);638 639            if (classDefn != null && classDefn.IsAmbiguous())640            {641                _parser.ReportError(typeName.Extent,642                    nameof(ParserStrings.AmbiguousTypeReference),643                    ParserStrings.AmbiguousTypeReference,644                    typeName.Name,645                    GetModuleQualifiedName(classDefn.ExternalNamespaces[0], typeName.Name),646                    GetModuleQualifiedName(classDefn.ExternalNamespaces[1], typeName.Name));647            }648            else if (classDefn != null && genericArgumentCount == 0)649            {650                typeName.SetTypeDefinition(classDefn.Type);651            }652            else653            {654                Exception e;655                TypeResolutionState trs = genericArgumentCount > 0 || isAttribute656                    ? new TypeResolutionState(_typeResolutionState, genericArgumentCount, isAttribute)657                    : _typeResolutionState;658 659                var type = TypeResolver.ResolveTypeNameWithContext(typeName, out e, null, trs);660                if (type == null)661                {662                    if (_symbolTable.GetCurrentTypeDefinitionAst() != null)663                    {664                        // [ordered] is an attribute, but it's looks like a type constraint.665                        if (!typeName.FullName.Equals(LanguagePrimitives.OrderedAttribute, StringComparison.OrdinalIgnoreCase))666                        {667                            string errorId;668                            string errorMsg;669                            if (isAttribute)670                            {671                                errorId = nameof(ParserStrings.CustomAttributeTypeNotFound);672                                errorMsg = ParserStrings.CustomAttributeTypeNotFound;673                            }674                            else675                            {676                                errorId = nameof(ParserStrings.TypeNotFound);677                                errorMsg = ParserStrings.TypeNotFound;678                            }679 680                            _parser.ReportError(typeName.Extent, errorId, errorMsg, typeName.Name);681                        }682                    }683                }684                else685                {686                    ((ISupportsTypeCaching)typeName).CachedType = type;687                    return true;688                }689            }690 691            return false;692        }693 694        private bool VisitGenericTypeName(GenericTypeName genericTypeName)695        {696            var foundType = TypeCache.Lookup(genericTypeName, _typeResolutionState);697            if (foundType != null)698            {699                ((ISupportsTypeCaching)genericTypeName).CachedType = foundType;700                return true;701            }702 703            bool resolved = true;704            resolved &= DispatchTypeName(genericTypeName.TypeName, genericTypeName.GenericArguments.Count, isAttribute: false);705            foreach (var typeArg in genericTypeName.GenericArguments)706            {707                resolved &= DispatchTypeName(typeArg, genericArgumentCount: 0, isAttribute: false);708            }709 710            if (resolved)711            {712                var resolvedType = genericTypeName.GetReflectionType();713                TypeCache.Add(genericTypeName, _typeResolutionState, resolvedType);714            }715 716            return resolved;717        }718 719        public void PostVisit(Ast ast)720        {721            ast.Accept(_symbolResolvePostActionVisitor);722        }723 724        internal static string GetModuleQualifiedName(string namespaceName, string typeName)725        {726            const char NAMESPACE_SEPARATOR = '.';727            return namespaceName + NAMESPACE_SEPARATOR + typeName;728        }729    }730 731    internal class SymbolResolvePostActionVisitor : DefaultCustomAstVisitor2732    {733        internal SymbolResolver _symbolResolver;734 735        public override object VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)736        {737            if (functionDefinitionAst.Parent is not FunctionMemberAst)738            {739                _symbolResolver._symbolTable.LeaveScope();740            }741 742            return null;743        }744 745        public override object VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)746        {747            _symbolResolver._symbolTable.LeaveScope();748            return null;749        }750 751        public override object VisitTypeDefinition(TypeDefinitionAst typeDefinitionAst)752        {753            _symbolResolver._symbolTable.LeaveScope();754            return null;755        }756 757        public override object VisitFunctionMember(FunctionMemberAst functionMemberAst)758        {759            _symbolResolver._symbolTable.LeaveScope();760            return null;761        }762    }763}764