From 09047026790378b12129a46064e16076aabcd761 Mon Sep 17 00:00:00 2001 From: Yoshi Askharoun Date: Wed, 29 Jan 2025 14:23:12 -0600 Subject: [PATCH] [WIP] Importing shared data tables --- UIXC/Properties/launchSettings.json | 2 +- libs/UIX.Asm/AsmMarkupLoader.cs | 98 ++++++++++++++++++----------- libs/UIX.Asm/Disassembler.cs | 31 +++++---- libs/UIX.Asm/Extensions.cs | 4 ++ libs/UIX.Asm/Lexer.Directives.cs | 47 ++++++++++++-- libs/UIX.Asm/Lexer.cs | 6 -- libs/UIX.Asm/Models/SyntaxModels.cs | 32 ++++++---- 7 files changed, 148 insertions(+), 72 deletions(-) diff --git a/UIXC/Properties/launchSettings.json b/UIXC/Properties/launchSettings.json index 1e728f9..cde3180 100644 --- a/UIXC/Properties/launchSettings.json +++ b/UIXC/Properties/launchSettings.json @@ -3,9 +3,9 @@ "UIXC": { "commandName": "Project", "commandLineArgs": "decompile C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources_uixa -t C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources_uixa\\_DATATABLE.uixa", + //"commandLineArgs": "decompile C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\_DATATABLE.UIB -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources_uixa", //"commandLineArgs": "compile C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\CreatePassport.uixa -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune", //"commandLineArgs": "compile C:\\Users\\jjask\\Documents\\Dump\\Zune\\_DATATABLE.uixa -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune", - //"commandLineArgs": "decompile C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources\\_DATATABLE.UIB -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o C:\\Users\\jjask\\Documents\\Dump\\Zune\\ZuneShellResources_uixa", //"commandLineArgs": "compile \"D:\\Documents\\REProj\\Zune\\UIXA\\ZuneShell.dll!_DataTable.uixa\" -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o D:\\Documents\\REProj\\Zune\\UIXA", //"commandLineArgs": "compile \"D:\\Documents\\REProj\\Zune\\UIXA\\ZuneShellResources.dll!_DataTable.uixa\" -A ZuneShell.dll -A UIXControls.dll -A ZuneDBApi.dll -o D:\\Documents\\REProj\\Zune\\UIXA", diff --git a/libs/UIX.Asm/AsmMarkupLoader.cs b/libs/UIX.Asm/AsmMarkupLoader.cs index 991142c..2a96165 100644 --- a/libs/UIX.Asm/AsmMarkupLoader.cs +++ b/libs/UIX.Asm/AsmMarkupLoader.cs @@ -16,7 +16,8 @@ internal class AsmMarkupLoader private readonly AsmMarkupLoadResult _loadResult; private LoadPass _currentValidationPass; private bool _usingSharedBinaryDataTable; - private SourceMarkupImportTables _importTables; + private AsmMarkupLoadResult _binaryDataTableLoadResult; + private MarkupBinaryDataTable _binaryDataTable; private ObjectSection _objectSection; private readonly Dictionary _importedNamespaces = new(); @@ -70,16 +71,6 @@ internal class AsmMarkupLoader var type = result.FindType(typeName); - //if (type is null) - //{ - // foreach (var tryResult in _importedNamespaces.Values) - // { - // type = tryResult.FindType(typeName); - // if (type is not null) - // break; - // } - //} - if (type is null) { ErrorManager.ReportError(qualifiedName.Line, qualifiedName.Column, @@ -105,11 +96,11 @@ internal class AsmMarkupLoader return; _currentValidationPass = currentPass; - if (_currentValidationPass == LoadPass.DeclareTypes) - { - if (_asmSource == null) - return; + if (_asmSource == null) + return; + if (Program is null && !HasErrors) + { var parseResult = Lexer.Program.TryParse(_asmSource); if (parseResult.WasSuccessful) { @@ -123,15 +114,48 @@ internal class AsmMarkupLoader return; } - if (_loadResult.BinaryDataTable != null) - { - _importTables = _loadResult.BinaryDataTable.SourceMarkupImportTables; - _usingSharedBinaryDataTable = true; + _usingSharedBinaryDataTable = Program.DataTableDirective is not null; + if (_usingSharedBinaryDataTable) + { + // Import the shared data table + var dataTableUri = Program.DataTableDirective.Uri; + var dataTableLoadResult = MarkupSystem.ResolveLoadResult(dataTableUri, _loadResult.IslandReferences); + if (dataTableLoadResult is null) + { + ReportError($"Unable to load '{dataTableUri}' (shared data table)", Program.DataTableDirective); + return; + } + + if (dataTableLoadResult is not AsmMarkupLoadResult) + { + ReportError($"Shared data table at '{dataTableUri}' was not UIXA", Program.DataTableDirective); + return; + } + + _binaryDataTableLoadResult = (AsmMarkupLoadResult)dataTableLoadResult; + if (_binaryDataTableLoadResult != null) + { + _binaryDataTableLoadResult.Load(_currentValidationPass); + _binaryDataTable = _binaryDataTableLoadResult.BinaryDataTable; + + _binaryDataTable.SharedDependenciesTableWithBinaryDataTable ??= [_binaryDataTableLoadResult]; + _loadResult.SetDependenciesTable(_binaryDataTable.SharedDependenciesTableWithBinaryDataTable); + } + else + MarkHasErrors(); } else { - _importTables = new SourceMarkupImportTables(); + _binaryDataTable = new MarkupBinaryDataTable(_loadResult.Uri); + _binaryDataTable.SetConstantsTable(new MarkupConstantsTable()); + _binaryDataTable.SetSourceMarkupImportTables(new SourceMarkupImportTables()); } + + _loadResult.SetBinaryDataTable(_binaryDataTable); + } + + if (_currentValidationPass == LoadPass.DeclareTypes) + { foreach (var nsImport in Program.Directives.OfType()) { @@ -256,9 +280,9 @@ internal class AsmMarkupLoader _loadResult.MarkLoadFailed(); MarkupImportTables importTables = null; - if (_importTables != null) + if (_binaryDataTable.SourceMarkupImportTables != null) { - importTables = _importTables.PrepareImportTables(); + importTables = _binaryDataTable.SourceMarkupImportTables.PrepareImportTables(); _loadResult.SetImportTables(importTables); } @@ -323,10 +347,10 @@ internal class AsmMarkupLoader var contentBuffer = binaryEncodedConstant.Content; - ByteCodeWriter binaryConstantWrtier = new(); - binaryConstantWrtier.Write(contentBuffer, (uint)contentBuffer.Length); + ByteCodeWriter binaryConstantWriter = new(); + binaryConstantWriter.Write(contentBuffer, (uint)contentBuffer.Length); - var binaryConstantReader = binaryConstantWrtier.CreateReader(); + var binaryConstantReader = binaryConstantWriter.CreateReader(); constantValue = constantTypeSchema.DecodeBinary(binaryConstantReader); persistData = constantValue; @@ -395,9 +419,9 @@ internal class AsmMarkupLoader { LoadResult[] loadResultArray = LoadResult.EmptyList; int length = 0; - if (_importTables != null) + if (_binaryDataTable.SourceMarkupImportTables != null) { - foreach (LoadResult importedLoadResult in _importTables.ImportedLoadResults) + foreach (LoadResult importedLoadResult in _binaryDataTable.SourceMarkupImportTables.ImportedLoadResults) { if (importedLoadResult != _loadResult) ++length; @@ -407,7 +431,7 @@ internal class AsmMarkupLoader { loadResultArray = new LoadResult[length]; int index = 0; - foreach (LoadResult importedLoadResult in _importTables.ImportedLoadResults) + foreach (LoadResult importedLoadResult in _binaryDataTable.SourceMarkupImportTables.ImportedLoadResults) { if (importedLoadResult != _loadResult) { @@ -472,12 +496,14 @@ internal class AsmMarkupLoader { if (loadResult == MarkupSystem.UIXGlobal) return; - for (int index = 0; index < _importTables.ImportedLoadResults.Count; ++index) + + for (int index = 0; index < _binaryDataTable.SourceMarkupImportTables.ImportedLoadResults.Count; ++index) { - if ((LoadResult)_importTables.ImportedLoadResults[index] == loadResult) + if ((LoadResult)_binaryDataTable.SourceMarkupImportTables.ImportedLoadResults[index] == loadResult) return; } - _importTables.ImportedLoadResults.Add(loadResult); + + _binaryDataTable.SourceMarkupImportTables.ImportedLoadResults.Add(loadResult); } public int TrackImportedType(TypeSchema type) @@ -485,14 +511,14 @@ internal class AsmMarkupLoader if (type is null) return -1; TrackImportedLoadResult(type.Owner); - return TrackImportedSchema(_importTables.ImportedTypes, type); + return TrackImportedSchema(_binaryDataTable.SourceMarkupImportTables.ImportedTypes, type); } public int TrackImportedConstructor(ConstructorSchema constructor) { if (constructor is null) return -1; - int num = TrackImportedSchema(_importTables.ImportedConstructors, constructor); + int num = TrackImportedSchema(_binaryDataTable.SourceMarkupImportTables.ImportedConstructors, constructor); TrackImportedType(constructor.Owner); foreach (TypeSchema parameterType in constructor.ParameterTypes) TrackImportedType(parameterType); @@ -503,7 +529,7 @@ internal class AsmMarkupLoader { if (property is null) return -1; - int num = TrackImportedSchema(_importTables.ImportedProperties, property); + int num = TrackImportedSchema(_binaryDataTable.SourceMarkupImportTables.ImportedProperties, property); TrackImportedType(property.Owner); return num; } @@ -512,7 +538,7 @@ internal class AsmMarkupLoader { if (method is null) return -1; - int num = TrackImportedSchema(_importTables.ImportedMethods, method); + int num = TrackImportedSchema(_binaryDataTable.SourceMarkupImportTables.ImportedMethods, method); TrackImportedType(method.Owner); foreach (TypeSchema parameterType in method.ParameterTypes) TrackImportedType(parameterType); @@ -523,7 +549,7 @@ internal class AsmMarkupLoader { if (evt is null) return -1; - int num = TrackImportedSchema(_importTables.ImportedEvents, evt); + int num = TrackImportedSchema(_binaryDataTable.SourceMarkupImportTables.ImportedEvents, evt); TrackImportedType(evt.Owner); return num; } diff --git a/libs/UIX.Asm/Disassembler.cs b/libs/UIX.Asm/Disassembler.cs index 65d93ec..7f9e2d1 100644 --- a/libs/UIX.Asm/Disassembler.cs +++ b/libs/UIX.Asm/Disassembler.cs @@ -3,6 +3,7 @@ using Microsoft.Iris.Asm.Models; using Microsoft.Iris.Markup; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; @@ -24,9 +25,8 @@ public class Disassembler { _loadResult = loadResult; - _dataTableLoadResult = dataTableLoadResult is not null - ? dataTableLoadResult - : loadResult.BinaryDataTable?.SharedDependenciesTableWithBinaryDataTable?.FirstOrDefault() as MarkupLoadResult; + _dataTableLoadResult = dataTableLoadResult + ?? loadResult.BinaryDataTable?.SharedDependenciesTableWithBinaryDataTable?.FirstOrDefault() as MarkupLoadResult; _importedUris = new() { @@ -57,7 +57,7 @@ public class Disassembler if (_loadResult.Status == LoadResultStatus.Error) throw new Exception($"Failed to load '{_loadResult.ErrorContextUri}'"); - if (_dataTableLoadResult is not null) + if (UseSharedDataTable) { _dataTableLoadResult.FullLoad(); if (_dataTableLoadResult.Status == LoadResultStatus.Error) @@ -75,7 +75,7 @@ public class Disassembler foreach (var segment in segments) body.AddRange(segment); - if (_dataTableLoadResult is not null) + if (UseSharedDataTable) body.Add(new SharedDataTableDirective(_dataTableLoadResult.Uri)); _program = new(body); @@ -86,6 +86,9 @@ public class Disassembler public string Write() => Disassemble().ToString(); + [MemberNotNullWhen(true, nameof(_dataTableLoadResult))] + private bool UseSharedDataTable => _dataTableLoadResult is not null; + private IEnumerable GetExports() { foreach (var typeSchema in _loadResult.ExportTable) @@ -148,6 +151,9 @@ public class Disassembler private IEnumerable EnumerateImports() { + if (UseSharedDataTable) + yield break; + // Ues _importedUris to keep track of what has already been imported. // Skip self and default UIX namespace. @@ -323,7 +329,7 @@ public class Disassembler private IEnumerable GetConstants() { - if (_dataTableLoadResult is not null) + if (UseSharedDataTable) { // Constants have already been disassembled from the shared binary table var asmConstants = _dataTableLoadResult is AsmMarkupLoadResult asmDataTableLoadResult @@ -333,9 +339,9 @@ public class Disassembler foreach (var info in EnumerateConstantInfo(_dataTableLoadResult)) { var constantName = asmConstants?[info.Index]?.Name - ?? $"sharedConst{info.Index:D}"; + ?? info.GenerateDefaultName(); - _constantsTable.Add(info.Index, constantName); + _constantsTable[info.Index] = constantName; } yield break; @@ -344,7 +350,7 @@ public class Disassembler { foreach (var info in EnumerateConstantInfo(_loadResult)) { - var constantName = $"const{info.Index:D}"; + var constantName = info.GenerateDefaultName(); _constantsTable[info.Index] = constantName; yield return EncodeConstant(info.Value, constantName, info.Type); } @@ -397,7 +403,7 @@ public class Disassembler { var qualifiedTypeName = GetQualifiedName(typeSchema); - // ILayout has a number of derived classes with special named instacnes, + // ILayout has a number of derived classes with special named instances, // but aren't implemented as canonical instances. if (constantValue is Layout.ILayout constantLayout && Layout.PredefinedLayouts.TryConvertToString(constantLayout, out var constantLayoutString)) { @@ -456,5 +462,8 @@ public class Disassembler throw new NotSupportedException($"Unable to encode constant value '{constantValue}' of type '{qualifiedTypeName}'"); } - private record RawConstantInfo(int Index, TypeSchema Type, object Value); + private record RawConstantInfo(int Index, TypeSchema Type, object Value) + { + public string GenerateDefaultName() => $"const{Index:D}"; + } } diff --git a/libs/UIX.Asm/Extensions.cs b/libs/UIX.Asm/Extensions.cs index 6df4928..7c0ba8c 100644 --- a/libs/UIX.Asm/Extensions.cs +++ b/libs/UIX.Asm/Extensions.cs @@ -9,6 +9,9 @@ public static class Extensions { public static void FullLoad(this LoadResult result) { + if (result.Status is LoadResultStatus.Success) + return; + result.Load(LoadPass.DeclareTypes); result.Load(LoadPass.PopulatePublicModel); result.Load(LoadPass.Full); @@ -73,6 +76,7 @@ public static class Extensions '\t' => @"\t", '\'' => @"\'", '"' => "\"", + '\\' => @"\\", _ => null }; diff --git a/libs/UIX.Asm/Lexer.Directives.cs b/libs/UIX.Asm/Lexer.Directives.cs index 973b592..555ec66 100644 --- a/libs/UIX.Asm/Lexer.Directives.cs +++ b/libs/UIX.Asm/Lexer.Directives.cs @@ -3,6 +3,7 @@ using Sprache; using System; using System.Globalization; using System.Linq; +using System.Text; namespace Microsoft.Iris.Asm; @@ -86,13 +87,49 @@ partial class Lexer if (!encodingMarkerResult.WasSuccessful) { // Support defining constants from string literals - var stringLiteralResult = ExpressionInBraces(StringLiteral)(input); - input = stringLiteralResult.Remainder; - if (!stringLiteralResult.WasSuccessful) - return stringLiteralResult.ForType(); + + // Skip the opening brace + input = input.Advance(); + if (input.Current != '"') + return Result.Failure(input, "Invalid constant", ["Expected a string literal."]); + + input = input.Advance(); + + StringBuilder literalBuilder = new(); + char c; + while (true) + { + c = input.Current; + if (c == '\\') + { + // https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure#unicode-character-escape-sequences + input = input.Advance(); + c = input.Current switch + { + '0' => '\0', + 'b' => '\b', + 'n' => '\n', + 'r' => '\r', + 't' => '\t', + _ => input.Current + }; + } + + input = input.Advance(); + + if (c == '"') + break; + + literalBuilder.Append(c); + } + + if (input.Current != ')') + return Result.Failure(input, "Invalid constant", ["Missing closed brace."]); + + input = input.Advance(); persistMode = Markup.MarkupConstantPersistMode.FromString; - content = stringLiteralResult.Value[1..^1].Unescape(); + content = literalBuilder.ToString(); } else { diff --git a/libs/UIX.Asm/Lexer.cs b/libs/UIX.Asm/Lexer.cs index 0f989e1..1cb8b47 100644 --- a/libs/UIX.Asm/Lexer.cs +++ b/libs/UIX.Asm/Lexer.cs @@ -130,10 +130,4 @@ public static partial class Lexer return Result.Success(qualifiedName, input); } - - private static Parser ExpressionInBraces(Parser parser, char open = '(', char close = ')') => - from openBrace in Parse.Char(open).Token() - from expression in parser.Optional() - from closeBrace in Parse.Char(close).Token() - select expression.GetOrElse(string.Empty).Trim(); } diff --git a/libs/UIX.Asm/Models/SyntaxModels.cs b/libs/UIX.Asm/Models/SyntaxModels.cs index 166a9d3..43ae2ef 100644 --- a/libs/UIX.Asm/Models/SyntaxModels.cs +++ b/libs/UIX.Asm/Models/SyntaxModels.cs @@ -27,23 +27,29 @@ public record Program public Program(IEnumerable body) { Body = body.Cached(); - - Directives = body.OfType().Cached(); - DataTableDirective = Directives.OfType().SingleOrDefault(); - Imports = Directives.OfType().Cached(); - Exports = Directives.OfType().Cached(); - - Code = body.OfType().Cached(); } - public IEnumerable Body { get; } + public IEnumerable Body { get; private set; } - public IEnumerable Directives { get; } - public SharedDataTableDirective DataTableDirective { get; } - public IEnumerable Imports { get; } - public IEnumerable Exports { get; } + public IEnumerable Directives => Body.OfType(); - public IEnumerable Code { get; } + public SharedDataTableDirective DataTableDirective => Body.OfType().SingleOrDefault(); + + public IEnumerable Imports => Directives.OfType(); + + public IEnumerable Exports => Directives.OfType(); + + public IEnumerable Code => Body.OfType(); + + public void ImportSharedDataTable(Program dataTable) + { + List newBody = Exports.ToList(); + + newBody.AddRange(dataTable.Directives.Where(d => d is not ExportDirective)); + newBody.AddRange(Code); + + Body = newBody.Cached(); + } public override string ToString() {