Add binary encoded constants to lexer and disassembler

This commit is contained in:
Yoshi Askharoun
2024-02-21 09:10:18 -06:00
parent 1125127171
commit 3c95c4e9ce
4 changed files with 107 additions and 13 deletions
+1 -1
View File
@@ -259,7 +259,7 @@ internal class AsmMarkupLoader
object constantValue, persistData = null; object constantValue, persistData = null;
var constantTypeSchema = ResolveTypeFromQualifiedName(constant.TypeName); var constantTypeSchema = ResolveTypeFromQualifiedName(constant.TypeName);
if (constant is EncodedConstantDirective encodedConstant) if (constant is StringEncodedConstantDirective encodedConstant)
{ {
var parseResult = constantTypeSchema.TypeConverter(encodedConstant.Content, stringTypeSchema, out constantValue); var parseResult = constantTypeSchema.TypeConverter(encodedConstant.Content, stringTypeSchema, out constantValue);
if (parseResult.Failed) if (parseResult.Failed)
+17 -5
View File
@@ -4,6 +4,7 @@ using Microsoft.Iris.Markup;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Xml.Linq; using System.Xml.Linq;
namespace Microsoft.Iris.Asm; namespace Microsoft.Iris.Asm;
@@ -226,17 +227,28 @@ public class Disassembler
if (constantValue is IStringEncodable encodable) if (constantValue is IStringEncodable encodable)
{ {
var encodedValue = encodable.EncodeString(); var encodedValue = encodable.EncodeString();
yield return new EncodedConstantDirective(constantName, qualifiedTypeName, encodedValue); yield return new StringEncodedConstantDirective(constantName, qualifiedTypeName, encodedValue);
}
else if (constantValue is Layout.ILayout constantLayout && Layout.PredefinedLayouts.TryConvertToString(constantLayout, out var constantLayoutString))
{
qualifiedTypeName = GetQualifiedName(UIXTypes.MapIDToType(UIXTypeID.Layout));
yield return new StringEncodedConstantDirective(constantName, qualifiedTypeName, constantLayoutString);
} }
else if (typeSchema.SupportsTypeConversion(stringTypeSchema)) else if (typeSchema.SupportsTypeConversion(stringTypeSchema))
{ {
var encodedValue = constantValue.ToString(); var encodedValue = constantValue.ToString();
yield return new EncodedConstantDirective(constantName, qualifiedTypeName, encodedValue); yield return new StringEncodedConstantDirective(constantName, qualifiedTypeName, encodedValue);
} }
else if (constantValue is Layout.ILayout constantLayout && Layout.PredefinedLayouts.TryConvertToString(constantLayout, out var constantLayoutString)) else if (typeSchema.SupportsBinaryEncoding)
{ {
qualifiedTypeName = GetQualifiedName(typeSchema.Base); ByteCodeWriter writer = new();
yield return new EncodedConstantDirective(constantName, qualifiedTypeName, constantLayoutString); typeSchema.EncodeBinary(writer, constantValue);
var reader = writer.CreateReader();
byte[] encodedBytes = new byte[reader.Size];
Marshal.Copy(reader.GetAddress(0), encodedBytes, 0, (int)reader.Size);
yield return new BinaryEncodedConstantDirective(constantName, qualifiedTypeName, encodedBytes);
} }
else else
{ {
+52 -1
View File
@@ -1,5 +1,7 @@
using Microsoft.Iris.Asm.Models; using Microsoft.Iris.Asm.Models;
using Sprache; using Sprache;
using System;
using System.Globalization;
using System.Linq; using System.Linq;
namespace Microsoft.Iris.Asm; namespace Microsoft.Iris.Asm;
@@ -85,6 +87,10 @@ partial class Lexer
if (!typeNameResult.WasSuccessful) if (!typeNameResult.WasSuccessful)
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected qualified name of type to construct"]); return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected qualified name of type to construct"]);
var binaryEncodingMarkerResult = Parse.String(".bin")(input);
input = binaryEncodingMarkerResult.Remainder;
var binaryEncoded = binaryEncodingMarkerResult.WasSuccessful;
var openBracketResult = Parse.Char('(').Token()(input); var openBracketResult = Parse.Char('(').Token()(input);
input = openBracketResult.Remainder; input = openBracketResult.Remainder;
if (!openBracketResult.WasSuccessful) if (!openBracketResult.WasSuccessful)
@@ -100,12 +106,57 @@ partial class Lexer
if (!closeBracketResult.WasSuccessful) if (!closeBracketResult.WasSuccessful)
return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected ')'"]); return Result.Failure<IDirective>(input, "Invalid constant directive", ["Expected ')'"]);
directive = new EncodedConstantDirective(constNameResult.Value, typeNameResult.Value, contentResult.Value) var constantName = constNameResult.Value;
var typeName = typeNameResult.Value;
if (!binaryEncoded)
{
directive = new StringEncodedConstantDirective(constantName, typeName, contentResult.Value)
{ {
Line = line, Line = line,
Column = column, Column = column,
}; };
} }
else
{
byte[] constantBytes;
var byteParts = contentResult.Value.Split(',');
if (byteParts.Length == 1)
{
var constantStr = byteParts[0].Trim().TrimStart('0', 'x');
if (constantStr.Length == 2)
{
constantBytes = [byte.Parse(constantStr, NumberStyles.HexNumber)];
}
else if (constantStr.Length == 4)
{
constantBytes = BitConverter.GetBytes(
ushort.Parse(constantStr, NumberStyles.HexNumber));
}
else if (constantStr.Length == 8)
{
constantBytes = BitConverter.GetBytes(
uint.Parse(constantStr, NumberStyles.HexNumber));
}
else
{
return Result.Failure<IDirective>(input, "Invalid constant directive", [$"Expected a 1, 2, or 4 hex number, or a list of bytes."]);
}
}
else
{
constantBytes = byteParts
.Select(s => byte.Parse(s.TrimStart('0', 'x'), NumberStyles.HexNumber))
.ToArray();
}
directive = new BinaryEncodedConstantDirective(constantName, typeName, constantBytes)
{
Line = line,
Column = column,
};
}
}
break; break;
case "EXPORT": case "EXPORT":
+34 -3
View File
@@ -1,4 +1,7 @@
namespace Microsoft.Iris.Asm.Models; using System;
using System.Linq;
namespace Microsoft.Iris.Asm.Models;
public record SectionDirective : Directive public record SectionDirective : Directive
{ {
@@ -28,9 +31,9 @@ public record ConstantDirective : Directive
public override string ToString() => $"{base.ToString()} {Name} = {Constructor}"; public override string ToString() => $"{base.ToString()} {Name} = {Constructor}";
} }
public record EncodedConstantDirective : ConstantDirective public record StringEncodedConstantDirective : ConstantDirective
{ {
public EncodedConstantDirective(string name, QualifiedTypeName typeName, string content) public StringEncodedConstantDirective(string name, QualifiedTypeName typeName, string content)
: base(name, typeName, $"{typeName}({content})") : base(name, typeName, $"{typeName}({content})")
{ {
Content = content; Content = content;
@@ -41,6 +44,34 @@ public record EncodedConstantDirective : ConstantDirective
public override string ToString() => base.ToString(); public override string ToString() => base.ToString();
} }
public record BinaryEncodedConstantDirective : ConstantDirective
{
public BinaryEncodedConstantDirective(string name, QualifiedTypeName typeName, byte[] content)
: base(name, typeName, GetConstructor(typeName, content))
{
Content = content;
}
public byte[] Content { get; }
public override string ToString() => base.ToString();
private static string GetConstructor(QualifiedTypeName typeName, byte[] content)
{
string contentStr;
if (content.Length == 1)
contentStr = $"0x{content[0]:X2}";
else if (content.Length == 2)
contentStr = $"0x{BitConverter.ToUInt16(content, 0):X4}";
else if (content.Length == 4)
contentStr = $"0x{BitConverter.ToUInt32(content, 0):X8}";
else
contentStr = string.Join(", ", content.Select(b => $"0x{b:X2}"));
return $"{typeName}.bin({contentStr})";
}
}
public record ExportDirective : Directive public record ExportDirective : Directive
{ {
public ExportDirective(string labelPrefix, uint listenerCount, string baseTypeName) : base("export") public ExportDirective(string labelPrefix, uint listenerCount, string baseTypeName) : base("export")