| File: Actions\GrammarActions.Types.cs | Web Access |
| Project: ILAssembler.csproj (ILAssembler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Reflection.Metadata; using Antlr4.Runtime; namespace ILAssembler; internal sealed partial class GrammarActions { // Active namespace and type scopes are paired with their owning declaration so a rule's // finally block can unwind real compiler state after syntax-error recovery. private readonly Stack<RuleContext> _namespaceOwners = new(); private readonly Stack<RuleContext> _typeOwners = new(); // Invalid scopes also retain their owners so nested declarations stay suppressed until the // matching declaration finally block unwinds them. private readonly Stack<RuleContext> _suppressedDeclarationOwners = new(); private bool IsDeclarationSuppressed => _suppressedDeclarationOwners.Count != 0; private bool EnterDeclarationScope(RuleContext owner, bool hasValidHeader) { if (hasValidHeader && !IsDeclarationSuppressed) { return true; } _suppressedDeclarationOwners.Push(owner); return false; } /// <summary> /// Releases the namespace, type and method state that a top-level declaration introduced. /// </summary> /// <remarks> /// This runs from the <c>decl</c> rule's <c>finally</c> block so that a syntax error inside the /// declaration body cannot leak a namespace, type or method scope into the following declarations. /// </remarks> internal void EndDeclaration(CILParser.DeclContext context) { EndScopesOwnedBy(context); } /// <summary> /// Releases the type and method state that a class member declaration introduced. /// </summary> internal void EndClassDeclaration(CILParser.ClassDeclContext context) { EndScopesOwnedBy(context); } private void EndScopesOwnedBy(RuleContext owner) { if (ReferenceEquals(_methodOwner, owner)) { EndMethod(); } if (_suppressedDeclarationOwners.Count > 0 && ReferenceEquals(_suppressedDeclarationOwners.Peek(), owner)) { _suppressedDeclarationOwners.Pop(); ClearPendingCustomAttributeOwners(); return; } if (_typeOwners.Count > 0 && ReferenceEquals(_typeOwners.Peek(), owner)) { EndType(); } if (_namespaceOwners.Count > 0 && ReferenceEquals(_namespaceOwners.Peek(), owner)) { EndNamespace(); } } private void EndType() { CompleteClassMethodOverrides(_currentTypeDefinition.Peek()); _typeOwners.Pop(); _currentTypeDefinition.Pop(); ClearPendingCustomAttributeOwners(); } private void EndNamespace() { _namespaceOwners.Pop(); _currentNamespace.Pop(); ClearPendingCustomAttributeOwners(); } private void ResetTypeScopes() { _typeOwners.Clear(); _currentTypeDefinition.Clear(); _namespaceOwners.Clear(); _currentNamespace.Clear(); _suppressedDeclarationOwners.Clear(); } /// <summary> /// Drops the owners that a trailing <c>.custom</c> directive would bind to. /// </summary> /// <remarks> /// A trailing custom attribute only binds to the preceding field, generic parameter or generic /// constraint within the same type body, so the pending owners must be dropped whenever a /// namespace, type or method boundary is crossed. /// </remarks> private void ClearPendingCustomAttributeOwners() { _lastFieldDefinition = null; _pendingClassCustomAttributeOwner = null; } }