MegaBites-AI/Windows-powershell
0308
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 