mirror of
https://github.com/ZuneDev/ZuneUIXTools.git
synced 2026-07-27 13:11:59 -07:00
[WIP] Class method exports
This commit is contained in:
@@ -18,6 +18,17 @@ namespace Microsoft.Iris.DecompXml;
|
||||
partial class Decompiler
|
||||
{
|
||||
private SyntaxTree DecompileScript(uint startOffset, MarkupTypeSchema export)
|
||||
{
|
||||
var statements = DecompileMethod(startOffset, export);
|
||||
|
||||
return SyntaxTree(
|
||||
CompilationUnit().WithMembers(
|
||||
[..statements.Select(GlobalStatement)]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public List<StatementSyntax> DecompileMethod(uint startOffset, MarkupTypeSchema export)
|
||||
{
|
||||
var methodBody = _context.GetMethodBody(startOffset).ToArray();
|
||||
|
||||
@@ -48,7 +59,7 @@ partial class Decompiler
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var opCode = instruction.OpCode;
|
||||
|
||||
try
|
||||
@@ -164,9 +175,23 @@ partial class Decompiler
|
||||
blockStack.Push(ifBlock);
|
||||
break;
|
||||
|
||||
case OpCode.Jump:
|
||||
var jumpOffset = (uint)instruction.Operands.First().Value;
|
||||
var statementsJumpedTo = DecompileMethod(jumpOffset, export);
|
||||
|
||||
// TODO
|
||||
blockStack.Peek().Statements.Add(
|
||||
Block(List([..statementsJumpedTo]))
|
||||
.WithTrailingTrivia(EndOfLine(Environment.NewLine), Comment($"// TODO: {instruction}"))
|
||||
);
|
||||
break;
|
||||
|
||||
case not OpCode.ReturnVoid:
|
||||
if (!TryDecompileExpression(instruction, stack, blockStack))
|
||||
throw new NotImplementedException();
|
||||
{
|
||||
var unsupportedComment = Comment($"// Unsupported instruction: {instruction}");
|
||||
blockStack.Peek().Statements.Add(EmptyStatement().WithLeadingTrivia(unsupportedComment));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -182,13 +207,22 @@ partial class Decompiler
|
||||
throw new InvalidOperationException($"Failed to decompile script for {export.Name}, no top-level code blocks");
|
||||
|
||||
// Unwrap top-most block to avoid extra curly braces around entire script
|
||||
var topBlock = blockStack.Pop();
|
||||
return blockStack.Pop().Statements;
|
||||
}
|
||||
|
||||
return SyntaxTree(
|
||||
CompilationUnit().WithMembers(
|
||||
[..topBlock.Statements.Select(GlobalStatement)]
|
||||
)
|
||||
);
|
||||
private MethodDeclarationSyntax DecompileMethodDeclaration(MarkupMethodSchema method, MarkupTypeSchema export)
|
||||
{
|
||||
var targetType = export.ResolveScriptId(method.CodeOffset, out var offset);
|
||||
var methodBody = DecompileMethod(offset, export);
|
||||
|
||||
var parameters = method.ParameterTypes
|
||||
.Zip(method.ParameterNames, (t, n) => Parameter(Identifier(n)).WithType(IrisExpression.ToSyntax(t, _context)));
|
||||
|
||||
return MethodDeclaration(
|
||||
IrisExpression.ToSyntax(method.ReturnType, _context),
|
||||
method.Name)
|
||||
.WithParameterList(ParameterList([..parameters]))
|
||||
.WithBody(Block(methodBody));
|
||||
}
|
||||
|
||||
public static string FormatInlineExpression(ExpressionSyntax expr, CancellationToken token = default)
|
||||
@@ -321,6 +355,16 @@ partial class Decompiler
|
||||
DecompileOperation(instruction, stack);
|
||||
break;
|
||||
|
||||
case OpCode.IsCheck:
|
||||
var typeToCheckFor = _context.GetImportedType(instruction.Operands.First());
|
||||
var objToCheck = stack.Pop();
|
||||
|
||||
stack.Push(IsPatternExpression(
|
||||
IrisExpression.ToSyntax(objToCheck, _context),
|
||||
TypePattern(IrisExpression.ToSyntax(typeToCheckFor, _context))
|
||||
));
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,26 @@ public partial class Decompiler
|
||||
}
|
||||
}
|
||||
|
||||
if (export.FinalEvaluateOffsets is { Length: > 0 })
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (export.Methods is { Length: > 0 })
|
||||
{
|
||||
var xScripts = GetOrCreateElement(xExport, _nsUix + "Scripts");
|
||||
|
||||
foreach (var method in export.Methods.OfType<MarkupMethodSchema>())
|
||||
{
|
||||
var methodSyntax = DecompileMethodDeclaration(method, export);
|
||||
var scriptText = FormatScript(methodSyntax.SyntaxTree);
|
||||
|
||||
XElement xScript = new(_nsUix + "Script", scriptText);
|
||||
|
||||
xScripts.Add(xScript);
|
||||
}
|
||||
}
|
||||
|
||||
if (export.RefreshGroupOffsets is { Length: > 0 })
|
||||
{
|
||||
var xScripts = GetOrCreateElement(xExport, _nsUix + "Scripts");
|
||||
@@ -287,12 +307,7 @@ public partial class Decompiler
|
||||
if (instruction.OpCode is OpCode.DestructiveListen)
|
||||
refreshOffset = (uint)instruction.Operands.ElementAt(4).Value;
|
||||
|
||||
MarkupTypeSchema markupTypeSchema = initType;
|
||||
uint num = scriptId >> 27;
|
||||
while (num != markupTypeSchema.TypeDepth)
|
||||
markupTypeSchema = markupTypeSchema.MarkupTypeBase;
|
||||
|
||||
var scriptOffset = scriptId & 0x07FFFFFFU;
|
||||
var markupTypeSchema = initType.ResolveScriptId(scriptId, out var scriptOffset);
|
||||
|
||||
string watch = null;
|
||||
InstructionObjectSource watchSource = InstructionObjectSource.Dynamic;
|
||||
|
||||
@@ -3,13 +3,15 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.Iris.Asm;
|
||||
using Microsoft.Iris.Markup;
|
||||
using System;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
||||
|
||||
namespace Microsoft.Iris.DecompXml.Mock;
|
||||
|
||||
internal static class IrisExpression
|
||||
{
|
||||
private static Dictionary<ulong, SyntaxKind> _predefinedTypeMap = null;
|
||||
|
||||
public static ExpressionSyntax ToSyntax(object obj, DecompileContext context)
|
||||
{
|
||||
return obj switch
|
||||
@@ -31,8 +33,13 @@ internal static class IrisExpression
|
||||
};
|
||||
}
|
||||
|
||||
public static IdentifierNameSyntax ToSyntax(TypeSchema type, DecompileContext context) =>
|
||||
IdentifierName(context.GetQualifiedName(type).ToString());
|
||||
public static TypeSyntax ToSyntax(TypeSchema type, DecompileContext context)
|
||||
{
|
||||
if (TryMapPredefinedType(type, out var kind))
|
||||
return PredefinedType(Token(kind));
|
||||
|
||||
return IdentifierName(context.GetQualifiedName(type).ToString());
|
||||
}
|
||||
|
||||
public static IdentifierNameSyntax ToSyntax(SymbolReference symbolRef) =>
|
||||
IdentifierName(symbolRef.Symbol);
|
||||
@@ -50,4 +57,18 @@ internal static class IrisExpression
|
||||
_ => ToSyntax(obj, context),
|
||||
};
|
||||
}
|
||||
|
||||
private static bool TryMapPredefinedType(TypeSchema type, out SyntaxKind kind)
|
||||
{
|
||||
_predefinedTypeMap ??= new()
|
||||
{
|
||||
[UIXTypes.MapIDToType(UIXTypeID.Void).UniqueId] = SyntaxKind.VoidKeyword,
|
||||
[UIXTypes.MapIDToType(UIXTypeID.Int32).UniqueId] = SyntaxKind.IntKeyword,
|
||||
[UIXTypes.MapIDToType(UIXTypeID.Int64).UniqueId] = SyntaxKind.LongKeyword,
|
||||
[UIXTypes.MapIDToType(UIXTypeID.String).UniqueId] = SyntaxKind.StringKeyword,
|
||||
[UIXTypes.MapIDToType(UIXTypeID.Boolean).UniqueId] = SyntaxKind.BoolKeyword,
|
||||
};
|
||||
|
||||
return _predefinedTypeMap.TryGetValue(type.UniqueId, out kind);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user