File: Actions\GrammarActions.Members.PropertiesEvents.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.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata;
using Antlr4.Runtime;

namespace ILAssembler;

#pragma warning disable CA1822 // Parser actions are invoked through the per-parser GrammarActions instance.
internal sealed partial class GrammarActions
{
    internal void AddPropertyAttribute(
        CILParser.PropertyHeaderBuilder builder,
        CILParser.AttributeValue<PropertyAttributes> value)
        => builder.Attributes = ApplyAttribute(builder.Attributes, value);

    internal PropertyHeaderValue CreatePropertyHeader(
        CILParser.PropHeadContext context,
        CILParser.PropertyHeaderBuilder builder,
        int initialSyntaxErrorCount,
        byte callingConvention,
        TypeValue propertyType,
        string name,
        System.Collections.Immutable.ImmutableArray<SignatureArgumentValue> arguments,
        FieldInitializerValue initializer)
    {
        if (HasSyntaxErrorsSince(initialSyntaxErrorCount) ||
            context.exception is not null)
        {
            return PropertyHeaderValue.Error;
        }

        return new PropertyHeaderValue(
            true,
            builder.Attributes,
            callingConvention,
            propertyType,
            name,
            arguments,
            initializer);
    }

    internal CILParser.AttributeValue<PropertyAttributes> CreatePropertyAttribute(IToken token)
        => token.Text switch
        {
            "specialname" => new CILParser.AttributeValue<PropertyAttributes>(
                PropertyAttributes.SpecialName,
                0,
                true),
            "rtspecialname" => new CILParser.AttributeValue<PropertyAttributes>(0, 0, true),
            _ => throw new UnreachableException(),
        };

    internal CILParser.PropertyBodyValue BeginProperty(PropertyHeaderValue value)
    {
        PrepareClassMember();
        EntityRegistry.PropertyEntity? property = null;
        if (!IsDeclarationSuppressed &&
            value.IsValid &&
            _currentTypeDefinition.PeekOrDefault() is { } currentType)
        {
            BlobBuilder signature = new();
            signature.WriteByte(
                (byte)(value.CallingConvention | (byte)SignatureKind.Property));
            signature.WriteCompressedInteger(value.Arguments.Length);
            MaterializeType(value.PropertyType).WriteContentTo(signature);
            foreach (SignatureArgumentValue argument in value.Arguments)
            {
                MaterializeSignatureArgument(argument).SignatureBlob.WriteContentTo(signature);
            }

            property = new EntityRegistry.PropertyEntity(value.Attributes, signature, value.Name);
            if (value.Initializer.HasValue)
            {
                property.ConstantValue = value.Initializer.ConstantValue;
                property.HasConstant = true;
                property.Attributes |= PropertyAttributes.HasDefault;
            }

            currentType.Properties.Add(property);
        }

        return new CILParser.PropertyBodyValue(property);
    }

    internal void AddPropertySetter(
        CILParser.PropertyBodyValue body,
        MethodReferenceValue value)
        => AddPropertyAccessor(body, MethodSemanticsAttributes.Setter, value);

    internal void AddPropertyGetter(
        CILParser.PropertyBodyValue body,
        MethodReferenceValue value)
        => AddPropertyAccessor(body, MethodSemanticsAttributes.Getter, value);

    internal void AddPropertyOther(
        CILParser.PropertyBodyValue body,
        MethodReferenceValue value)
        => AddPropertyAccessor(body, MethodSemanticsAttributes.Other, value);

    private void AddPropertyAccessor(
        CILParser.PropertyBodyValue body,
        MethodSemanticsAttributes semantics,
        MethodReferenceValue value)
    {
        if (body.Property is { } property)
        {
            property.Accessors.Add(
                (semantics, MaterializeMethodReference(value)));
        }
    }

    internal void AddPropertyCustomAttribute(
        CILParser.PropertyBodyValue body,
        CILParser.CustomAttrDeclContext attribute)
    {
        if (attribute.HasSyntaxError ||
            body.Property is not { } property)
        {
            return;
        }

        if (MaterializeCustomAttributeDeclaration(attribute) is { } customAttribute)
        {
            customAttribute.Owner ??= property;
        }
    }

    internal void ProcessPropertySourceDirective(
        CILParser.PropertyBodyValue body,
        CILParser.ExtSourceSpecContext context)
    {
        _ = body;
        _ = context;
    }

    internal void ProcessPropertyLanguageDirective(
        CILParser.PropertyBodyValue body,
        CILParser.LanguageDeclContext context)
    {
        _ = body;
        _ = context;
    }

    internal void AddEventAttribute(
        CILParser.EventHeaderBuilder builder,
        CILParser.AttributeValue<EventAttributes> value)
        => builder.Attributes = ApplyAttribute(builder.Attributes, value);

    internal EventHeaderValue CreateEventHeader(
        CILParser.EventHeadContext context,
        CILParser.EventHeaderBuilder builder,
        int initialSyntaxErrorCount,
        TypeSpecificationValue? eventType,
        string name)
    {
        if (HasSyntaxErrorsSince(initialSyntaxErrorCount) ||
            context.exception is not null)
        {
            return EventHeaderValue.Error;
        }

        return new EventHeaderValue(
            true,
            builder.Attributes,
            eventType,
            name);
    }

    internal CILParser.AttributeValue<EventAttributes> CreateEventAttribute(IToken token)
        => token.Text switch
        {
            "specialname" => new CILParser.AttributeValue<EventAttributes>(
                EventAttributes.SpecialName,
                0,
                true),
            "rtspecialname" => new CILParser.AttributeValue<EventAttributes>(0, 0, true),
            _ => throw new UnreachableException(),
        };

    internal CILParser.EventBodyValue BeginEvent(EventHeaderValue value)
    {
        PrepareClassMember();
        EntityRegistry.EventEntity? @event = null;
        if (!IsDeclarationSuppressed &&
            value.IsValid &&
            _currentTypeDefinition.PeekOrDefault() is { } currentType)
        {
            @event = new EntityRegistry.EventEntity(
                value.Attributes,
                value.EventType is null
                    ? null
                    : ResolveTypeSpecification(value.EventType),
                value.Name);
            currentType.Events.Add(@event);
        }

        return new CILParser.EventBodyValue(@event);
    }

    internal void AddEventAdder(CILParser.EventBodyValue body, MethodReferenceValue value)
        => AddEventAccessor(body, MethodSemanticsAttributes.Adder, value);

    internal void AddEventRemover(CILParser.EventBodyValue body, MethodReferenceValue value)
        => AddEventAccessor(body, MethodSemanticsAttributes.Remover, value);

    internal void AddEventRaiser(CILParser.EventBodyValue body, MethodReferenceValue value)
        => AddEventAccessor(body, MethodSemanticsAttributes.Raiser, value);

    internal void AddEventOther(CILParser.EventBodyValue body, MethodReferenceValue value)
        => AddEventAccessor(body, MethodSemanticsAttributes.Other, value);

    private void AddEventAccessor(
        CILParser.EventBodyValue body,
        MethodSemanticsAttributes semantics,
        MethodReferenceValue value)
    {
        if (body.Event is { } @event)
        {
            @event.Accessors.Add(
                (semantics, MaterializeMethodReference(value)));
        }
    }

    internal void AddEventCustomAttribute(
        CILParser.EventBodyValue body,
        CILParser.CustomAttrDeclContext attribute)
    {
        if (attribute.HasSyntaxError ||
            body.Event is not { } @event)
        {
            return;
        }

        if (MaterializeCustomAttributeDeclaration(attribute) is { } customAttribute)
        {
            customAttribute.Owner ??= @event;
        }
    }

    internal void ProcessEventSourceDirective(
        CILParser.EventBodyValue body,
        CILParser.ExtSourceSpecContext context)
    {
        _ = body;
        _ = context;
    }

    internal void ProcessEventLanguageDirective(
        CILParser.EventBodyValue body,
        CILParser.LanguageDeclContext context)
    {
        _ = body;
        _ = context;
    }
}