| File: Actions\GrammarActions.Literals.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.Buffers.Binary; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using Antlr4.Runtime; using Antlr4.Runtime.Misc; namespace ILAssembler { #pragma warning disable CA1822 // Mark members as static internal sealed partial class GrammarActions { internal void AddComposedStringPart(StringBuilder builder, IToken token) => builder.Append(StringHelpers.ParseQuotedString(token.Text)); internal string EndComposedString(StringBuilder builder) => builder.ToString(); internal void AddDottedNamePart(CILParser.DottedNameBuilder builder, string value) { if (builder.HasPart) { builder.Value.Append('.'); } builder.Value.Append(value); builder.HasPart = true; } internal void AddDottedNameToken(CILParser.DottedNameBuilder builder, IToken token) => AddDottedNamePart(builder, ParseIdentifier(token)); internal string EndDottedName(CILParser.DottedNameBuilder builder) => builder.Value.ToString(); internal string ParseDottedNamePart(IToken token) => token.Text.Length >= 2 && token.Text[0] == '\'' ? StringHelpers.ParseQuotedString(token.Text) : token.Text; internal double ParseFloatingLiteral(IToken token) { string text = token.Text; bool neg = text.StartsWith('-'); if (!double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out double result)) { result = neg ? double.MinValue : double.MaxValue; } return result; } internal double ParseFloatingInteger(IToken token) { if (!ParseIntegerValue(token.Text.AsSpan(), out long value, out bool invalidOctal)) { ReportIntegerParseError(token, invalidOctal); value = 0; } return value; } internal double ParseFloat32Bits(IToken token) => BitConverter.Int32BitsToSingle(ParseInt32(token)); internal double ParseFloat64Bits(IToken token) => BitConverter.Int64BitsToDouble(ParseInt64(token)); internal static string GetIdentifier(CILParser.IdContext context) => ParseIdentifier(context.Start); private static string ParseIdentifier(IToken token) { string text = token.Text; return text.Length >= 2 && text[0] == '\'' ? text.Substring(1, text.Length - 2) : text; } private static bool ParseIntegerValue(ReadOnlySpan<char> value, out long result) => ParseIntegerValue(value, out result, out _); private static bool ParseIntegerValue(ReadOnlySpan<char> value, out long result, out bool invalidOctal) { NumberStyles parseStyle = NumberStyles.None; bool negate = false; invalidOctal = false; if (value.StartsWith("-".AsSpan())) { negate = true; value = value.Slice(1); } if (value.StartsWith("0x".AsSpan())) { parseStyle = NumberStyles.AllowHexSpecifier; value = value.Slice(2); } else if (value.StartsWith("0".AsSpan())) { // Octal support isn't built-in, so we'll do it manually. result = 0; for (int i = 0; i < value.Length; i++) { int digitValue = value[i] - '0'; if (digitValue < 0 || digitValue > 7) { result = 0; invalidOctal = true; return false; } if (i != 0) { result *= 8; } result += digitValue; } if (negate) result = -result; return true; } bool success = long.TryParse(value.ToString(), parseStyle, CultureInfo.InvariantCulture, out result); if (!success) { // Try parsing as unsigned to handle values like: // - Decimal overflow with negation: 9223372036854775808 (= -Int64.MinValue) // - Large unsigned decimal: 18444492274432737280 if (ulong.TryParse(value.ToString(), parseStyle, CultureInfo.InvariantCulture, out ulong uresult)) { result = unchecked((long)uresult); if (negate) result = unchecked(-result); return true; } // Handle oversized hex values (>64 bits) by truncating to low 64 bits, // matching native ilasm behavior for values like 0x94188556b24089e8b90c9c61f9f3088 if (parseStyle == NumberStyles.AllowHexSpecifier && value.Length > 16) { var truncated = value.Slice(value.Length - 16); if (ulong.TryParse(truncated.ToString(), parseStyle, CultureInfo.InvariantCulture, out uresult)) { result = unchecked((long)uresult); if (negate) result = unchecked(-result); return true; } } return false; } if (negate) result = -result; return true; } private void ReportIntegerParseError(IToken token, bool invalidOctal) { if (invalidOctal) { _diagnostics.Add(new Diagnostic( DiagnosticIds.InvalidOctalLiteral, DiagnosticSeverity.Error, string.Format(DiagnosticMessageTemplates.InvalidOctalLiteral, token.Text), Location.From(token, _documents))); } else { ReportLiteralOutOfRange(token); } } internal int ParseInt32(IToken token) { ReadOnlySpan<char> value = token.Text.AsSpan(); if (!ParseIntegerValue(value, out long num, out bool invalidOctal)) { ReportIntegerParseError(token, invalidOctal); return 0; } return (int)num; } private long ParseInt64(IToken token) { ReadOnlySpan<char> value = token.Text.AsSpan(); if (!ParseIntegerValue(value, out long num, out bool invalidOctal)) { ReportIntegerParseError(token, invalidOctal); return 0; } return num; } private void ReportLiteralOutOfRange(IToken token) { _diagnostics.Add(new Diagnostic( DiagnosticIds.LiteralOutOfRange, DiagnosticSeverity.Error, string.Format(DiagnosticMessageTemplates.LiteralOutOfRange, token.Text), Location.From(token, _documents))); } internal bool ParseBoolean(IToken token) => token.Text == "true"; } }