File: Actions\GrammarActions.Signatures.Actions.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;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
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 byte AddInstanceCallingConvention(byte callingConvention)
        => (byte)(callingConvention | (byte)SignatureAttributes.Instance);

    internal byte AddExplicitCallingConvention(byte callingConvention)
        => (byte)(callingConvention | (byte)(SignatureAttributes.ExplicitThis | SignatureAttributes.Instance));

    internal byte GetRawCallingConvention(IToken token) => (byte)ParseInt32(token);

    internal byte GetDefaultCallingConvention() => (byte)SignatureCallingConvention.Default;

    internal byte GetCallingConvention(IToken token)
        => (byte)(token.Type switch
        {
            CILParser.DEFAULT => SignatureCallingConvention.Default,
            CILParser.VARARG => SignatureCallingConvention.VarArgs,
            CILParser.CDECL => SignatureCallingConvention.CDecl,
            CILParser.STDCALL => SignatureCallingConvention.StdCall,
            CILParser.THISCALL => SignatureCallingConvention.ThisCall,
            CILParser.FASTCALL => SignatureCallingConvention.FastCall,
            CILParser.UNMANAGED => SignatureCallingConvention.Unmanaged,
            _ => throw new UnreachableException()
        });

    internal void InitializeBound(CILParser.BoundContext context)
    {
        context.Lower = 0;
        context.Upper = 0;
        context.HasLower = false;
        context.HasUpper = false;
    }

    internal void SetBoundSize(CILParser.BoundContext context, IToken sizeToken)
    {
        context.Lower = 0;
        context.Upper = ParseInt32(sizeToken);
        context.HasLower = true;
        context.HasUpper = true;
    }

    internal void SetBoundRange(CILParser.BoundContext context, IToken lowerToken, IToken upperToken)
    {
        int lower = ParseInt32(lowerToken);
        context.Lower = lower;
        context.Upper = ParseInt32(upperToken) - lower + 1;
        context.HasLower = true;
        context.HasUpper = true;
    }

    internal void SetBoundLower(CILParser.BoundContext context, IToken lowerToken)
    {
        context.Lower = ParseInt32(lowerToken);
        context.HasLower = true;
    }

    internal ArrayBoundValue CreateArrayBound(CILParser.BoundContext bound)
        => new(
            bound.HasLower ? bound.Lower : null,
            bound.HasUpper ? bound.Upper : null);

    internal SignatureArgumentValue CreateSentinelSignatureArgument()
        => new SignatureArgumentValue(true, 0, null, null, null);

    internal SignatureArgumentValue CreateSignatureArgument(
        int attributes,
        TypeValue type,
        MarshallingDescriptorValue marshalling,
        CILParser.IdContext? name)
        => new SignatureArgumentValue(
            false,
            attributes,
            type,
            marshalling,
            name is null ? null : GetIdentifier(name));

    internal void SetParameterAttributeElement(CILParser.ParamAttrElementContext context, IToken attribute)
    {
        context.Value = attribute.Text switch
        {
            "in" => (int)ParameterAttributes.In,
            "out" => (int)ParameterAttributes.Out,
            "opt" => (int)ParameterAttributes.Optional,
            _ => throw new UnreachableException()
        };
        context.ShouldAppend = true;
    }

    internal void SetRawParameterAttributeElement(CILParser.ParamAttrElementContext context, IToken token)
    {
        context.Value = ParseInt32(token) + 1;
        context.ShouldAppend = false;
    }

    internal int AddParameterAttribute(int attributes, int value, bool shouldAppend)
        => shouldAppend ? attributes | value : value;

    internal ElementTypeValue CreateClassElementType(ClassNameValue className, bool isValueType)
        => new ClassElementTypeValue(className, isValueType);

    internal ElementTypeValue CreateObjectElementType()
        => new PrimitiveElementTypeValue((byte)SignatureTypeCode.Object);

    internal ElementTypeValue CreateTypedReferenceElementType()
        => new PrimitiveElementTypeValue((byte)SignatureTypeCode.TypedReference);

    internal ElementTypeValue CreateVoidElementType()
        => new PrimitiveElementTypeValue((byte)SignatureTypeCode.Void);

    internal ElementTypeValue CreatePrimitiveElementType(byte typeCode)
        => new PrimitiveElementTypeValue(typeCode);

    internal ElementTypeValue CreateFunctionPointerElementType(
        byte callingConvention,
        TypeValue returnType,
        ImmutableArray<SignatureArgumentValue> arguments)
        => new FunctionPointerElementTypeValue(
            callingConvention,
            returnType,
            arguments);

    internal ElementTypeValue CreateIndexedGenericParameterElementType(
        bool isMethodParameter,
        IToken token)
        => new IndexedGenericParameterElementTypeValue(isMethodParameter, ParseInt32(token));

    internal ElementTypeValue CreateNamedGenericParameterElementType(
        IToken token,
        bool isMethodParameter,
        string name)
        => new NamedGenericParameterElementTypeValue(token, isMethodParameter, name);

    internal ElementTypeValue CreateTypedefElementType(IToken token, string alias)
        => new TypedefElementTypeValue(token, alias);

    internal ElementTypeValue CreateSentinelElementType(TypeValue type)
        => new SentinelElementTypeValue(type);

    internal TypeModifierValue CreateSzArrayTypeModifier()
        => new SimpleTypeModifierValue(SimpleTypeModifierKind.SzArray);

    internal TypeModifierValue CreateByReferenceTypeModifier()
        => new SimpleTypeModifierValue(SimpleTypeModifierKind.ByReference);

    internal TypeModifierValue CreatePointerTypeModifier()
        => new SimpleTypeModifierValue(SimpleTypeModifierKind.Pointer);

    internal TypeModifierValue CreatePinnedTypeModifier()
        => new SimpleTypeModifierValue(SimpleTypeModifierKind.Pinned);

    internal TypeModifierValue CreateArrayTypeModifier(ImmutableArray<ArrayBoundValue> bounds)
        => new ArrayTypeModifierValue(bounds);

    internal TypeModifierValue CreateCustomTypeModifier(
        TypeSpecificationValue type,
        bool isRequired)
        => new CustomTypeModifierValue(type, isRequired);

    internal TypeModifierValue CreateGenericArgumentsModifier(
        ImmutableArray<TypeValue> arguments)
        => new GenericArgumentsTypeModifierValue(arguments);

    internal byte GetSimpleType(IToken token, bool isUnsigned)
    {
        SignatureTypeCode typeCode = (token.Type, isUnsigned) switch
        {
            (CILParser.CHAR, false) => SignatureTypeCode.Char,
            (CILParser.STRING, false) => SignatureTypeCode.String,
            (CILParser.BOOL, false) => SignatureTypeCode.Boolean,
            (CILParser.INT8, false) => SignatureTypeCode.SByte,
            (CILParser.INT16, false) => SignatureTypeCode.Int16,
            (CILParser.INT32_, false) => SignatureTypeCode.Int32,
            (CILParser.INT64_, false) => SignatureTypeCode.Int64,
            (CILParser.FLOAT32, false) => SignatureTypeCode.Single,
            (CILParser.FLOAT64_, false) => SignatureTypeCode.Double,
            (CILParser.UINT8, false) => SignatureTypeCode.Byte,
            (CILParser.UINT16, false) => SignatureTypeCode.UInt16,
            (CILParser.UINT32, false) => SignatureTypeCode.UInt32,
            (CILParser.UINT64, false) => SignatureTypeCode.UInt64,
            (CILParser.INT8, true) => SignatureTypeCode.Byte,
            (CILParser.INT16, true) => SignatureTypeCode.UInt16,
            (CILParser.INT32_, true) => SignatureTypeCode.UInt32,
            (CILParser.INT64_, true) => SignatureTypeCode.UInt64,
            _ => throw new UnreachableException()
        };

        return (byte)typeCode;
    }

    internal byte GetNativeIntType() => (byte)SignatureTypeCode.IntPtr;

    internal byte GetNativeUIntType() => (byte)SignatureTypeCode.UIntPtr;

    internal TypeSpecificationValue CreateClassTypeSpecification(ClassNameValue className)
        => new ClassTypeSpecificationValue(className);

    internal TypeSpecificationValue CreateAssemblyTypeSpecification(string assemblyName)
        => new AssemblyTypeSpecificationValue(assemblyName);

    internal TypeSpecificationValue CreateModuleTypeSpecification(string moduleName)
        => new ModuleTypeSpecificationValue(moduleName);

    internal TypeSpecificationValue CreateSignatureTypeSpecification(TypeValue type)
        => new SignatureTypeSpecificationValue(type);

    internal int GetGenericArity(CILParser.GenArityNotEmptyContext? context)
        => context?.Value ?? 0;

    internal CalliSignatureValue CreateCalliSignature(
        byte callingConvention,
        TypeValue returnType,
        ImmutableArray<SignatureArgumentValue> arguments)
        => new CalliSignatureValue(
            callingConvention,
            returnType,
            arguments);

    private BlobBuilder MaterializeCalliSignature(CalliSignatureValue calliSignature)
    {
        BlobBuilder signature = new();
        signature.WriteByte(calliSignature.CallingConvention);
        ImmutableArray<SignatureArg> materializedArguments = MaterializeSignatureArguments(calliSignature.Arguments);
        signature.WriteCompressedInteger(materializedArguments.Count(argument => !argument.IsSentinel));
        MaterializeType(calliSignature.ReturnType).WriteContentTo(signature);
        foreach (SignatureArg argument in materializedArguments)
        {
            argument.SignatureBlob.WriteContentTo(signature);
        }

        return signature;
    }
}