File: Actions\GrammarActions.Data.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.Collections.Immutable;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Antlr4.Runtime;

namespace ILAssembler;

internal sealed partial class GrammarActions
{
    internal CILParser.DataDeclarationBuilder CreateDataDeclaration(
        CILParser.DataDeclContext context)
        => new(
            !IsDeclarationSuppressed &&
            (context.Parent is not CILParser.MethodDeclContext ||
             _currentMethod is not null));

    internal void EndDataDeclaration(
        CILParser.DataDeclContext context,
        CILParser.DataDeclarationBuilder builder,
        int initialSyntaxErrorCount)
    {
        bool hasSyntaxError =
            HasSyntaxErrorsSince(initialSyntaxErrorCount) ||
            context.exception is not null;
        context.HasSyntaxError = hasSyntaxError;

        if (hasSyntaxError || !builder.ShouldCommit)
        {
            return;
        }

        int declarationOffset = _mappedFieldData.Count;
        if (builder.Name is not null && !_mappedFieldDataNames.ContainsKey(builder.Name))
        {
            _mappedFieldDataNames.Add(builder.Name, declarationOffset);
        }

        _mappedFieldData.LinkSuffix(builder.Data);
        if (builder.ReferenceFixups is null)
        {
            return;
        }

        foreach (CILParser.DataLabelReferenceValue reference in builder.ReferenceFixups)
        {
            _mappedFieldDataReferenceFixups.Add(reference with
            {
                DataOffset = declarationOffset + reference.DataOffset,
            });
        }
    }

#pragma warning disable CA1822 // Parser actions are invoked through the per-parser GrammarActions instance.
    internal void SetDataDeclarationHeader(
        CILParser.DataDeclarationBuilder builder,
        byte section,
        IToken name)
    {
        _ = section;
        builder.Name = ParseIdentifier(name);
    }

    internal void SetAnonymousDataDeclarationHeader(
        CILParser.DataDeclarationBuilder builder,
        byte section)
    {
        _ = builder;
        _ = section;
    }

    internal byte GetMappedDataSection() => 0;

    internal byte GetTlsDataSection(CILParser.TlsContext context)
    {
        ReportError(
            DiagnosticIds.UnsupportedTlsData,
            DiagnosticMessageTemplates.UnsupportedTlsData,
            context);
        return 1;
    }

    internal byte GetCilDataSection() => 2;
    internal int ParseDataItemCount(CILParser.DataDeclarationBuilder builder, IToken token)
    {
        int diagnosticCount = _diagnostics.Count;
        int count = ParseInt32(token);
        if (_diagnostics.Count != diagnosticCount)
        {
            builder.Invalidate();
        }

        return count;
    }

    internal void AddDataString(CILParser.DataDeclarationBuilder builder, string value)
        => builder.Data.WriteUTF16(value);

    internal void AddDataReference(
        CILParser.DataDeclarationBuilder builder,
        IToken targetToken)
    {
        string target = ParseIdentifier(targetToken);
        int pointerSize = VTableFixupSupport.GetPointerSize(
            _options.Machine ?? Machine.I386);
        builder.ReferenceFixups ??= new List<CILParser.DataLabelReferenceValue>();
        builder.ReferenceFixups.Add(new CILParser.DataLabelReferenceValue(
            target,
            builder.Data.Count,
            pointerSize,
            targetToken));
        builder.Data.ReserveBytes(pointerSize);
    }

    internal void AddDataBytes(
        CILParser.DataDeclarationBuilder builder,
        ImmutableArray<byte> value)
        => builder.Data.WriteBytes(value);

    internal void AddFloatingPointData(
        CILParser.DataDeclarationBuilder builder,
        IToken kind,
        double value,
        int count)
    {
        if (count <= 0)
        {
            return;
        }

        if (kind.Text == "float32")
        {
            float single = (float)value;
            for (int i = 0; i < count; i++)
            {
                builder.Data.WriteSingle(single);
            }
        }
        else
        {
            Debug.Assert(kind.Text == "float64");
            for (int i = 0; i < count; i++)
            {
                builder.Data.WriteDouble(value);
            }
        }
    }

    internal void AddInt64Data(
        CILParser.DataDeclarationBuilder builder,
        IToken kind,
        IToken value,
        int count)
    {
        Debug.Assert(kind.Text == "int64");
        if (count <= 0)
        {
            return;
        }

        long parsedValue = ParseInt64(value);
        for (int i = 0; i < count; i++)
        {
            builder.Data.WriteInt64(parsedValue);
        }
    }

    internal void AddIntegerData(
        CILParser.DataDeclarationBuilder builder,
        IToken kind,
        IToken value,
        int count)
    {
        if (count <= 0)
        {
            return;
        }

        int parsedValue = ParseInt32(value);
        switch (kind.Text)
        {
            case "int8":
                builder.Data.WriteBytes((byte)parsedValue, count);
                break;
            case "int16":
                for (int i = 0; i < count; i++)
                {
                    builder.Data.WriteInt16((short)parsedValue);
                }
                break;
            default:
                Debug.Assert(kind.Text == "int32");
                for (int i = 0; i < count; i++)
                {
                    builder.Data.WriteInt32(parsedValue);
                }
                break;
        }
    }

    internal void AddZeroData(
        CILParser.DataDeclarationBuilder builder,
        IToken kind,
        int count)
    {
        if (count <= 0)
        {
            return;
        }

        int elementSize = kind.Text switch
        {
            "int8" => sizeof(byte),
            "int16" => sizeof(short),
            "int32" or "float32" => sizeof(int),
            "int64" or "float64" => sizeof(long),
            _ => throw new UnreachableException(),
        };
        builder.Data.WriteBytes(0, checked(elementSize * count));
    }
#pragma warning restore CA1822


}