[WIP] Class method exports

This commit is contained in:
Yoshi Askharoun
2025-07-21 01:46:38 -05:00
parent e74c47e480
commit 2e8f22b963
7 changed files with 11383 additions and 19 deletions
+52 -8
View File
@@ -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;
}
+21 -6
View File
@@ -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;
+24 -3
View File
@@ -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);
}
}