Include FinalEvaluate attribute

This commit is contained in:
Yoshi Askharoun
2025-08-02 22:58:32 -05:00
parent ad64ca47d7
commit cf2b553ba0
2 changed files with 34 additions and 24 deletions
+33 -22
View File
@@ -20,24 +20,19 @@ partial class Decompiler
private static readonly TypeSchema _listType = UIXTypes.MapIDToType(UIXTypeID.List); private static readonly TypeSchema _listType = UIXTypes.MapIDToType(UIXTypeID.List);
private static readonly TypeSchema _dictionaryType = UIXTypes.MapIDToType(UIXTypeID.Dictionary); private static readonly TypeSchema _dictionaryType = UIXTypes.MapIDToType(UIXTypeID.Dictionary);
private SyntaxTree DecompileScript(uint startOffset, MarkupTypeSchema export) private SyntaxTree DecompileScript(uint startOffset, MarkupTypeSchema export, string? attributeName = null)
{ {
var statements = DecompileMethod(startOffset, export); var statements = DecompileMethod(startOffset, export, attributeName);
return CreateTree(statements);
return SyntaxTree(
CompilationUnit().WithMembers(
[..statements.Select(GlobalStatement)]
)
);
} }
public List<StatementSyntax> DecompileMethod(uint startOffset, MarkupTypeSchema export) public List<StatementSyntax> DecompileMethod(uint startOffset, MarkupTypeSchema export, string? attributeName = null)
{ {
var methodBody = _context.GetMethodBody(startOffset).ToArray(); var methodBody = _context.GetMethodBody(startOffset).ToArray();
var controlBlocks = ControlFlowAnalyzer.CreateGraph(methodBody); var controlBlocks = ControlFlowAnalyzer.CreateGraph(methodBody);
var dotGraph = ControlFlowAnalyzer.SerializeToGraphviz(controlBlocks); var dotGraph = ControlFlowAnalyzer.SerializeToGraphviz(controlBlocks);
Console.WriteLine(dotGraph); //Console.WriteLine(dotGraph);
Stack<CodeBlockInfo> blockStack = []; Stack<CodeBlockInfo> blockStack = [];
blockStack.Push(new(0, methodBody[^1].Offset, SyntaxKind.Block, null)); blockStack.Push(new(0, methodBody[^1].Offset, SyntaxKind.Block, null));
@@ -81,7 +76,10 @@ partial class Decompiler
break; break;
case OpCode.DiscardValue: case OpCode.DiscardValue:
stack.Pop(); var value = stack.Pop();
if ((value is InvocationExpressionSyntax)
&& methodBody.Skip(i).Any(m => m.OpCode is not (OpCode.DiscardValue or OpCode.ReturnValue)))
blockStack.Peek().Statements.Add(ExpressionStatement((ExpressionSyntax)value));
break; break;
case OpCode.LookupSymbol: case OpCode.LookupSymbol:
@@ -216,7 +214,16 @@ partial class Decompiler
throw new InvalidOperationException($"Failed to decompile script for {export.Name}, no top-level code blocks"); 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 // Unwrap top-most block to avoid extra curly braces around entire script
return blockStack.Pop().Statements; var statements = blockStack.Pop().Statements;
if (attributeName is not null)
{
var scriptAttribute = Attribute(IdentifierName(attributeName));
statements[0] = statements[0]
.WithAttributeLists(SingletonList(AttributeList([scriptAttribute])));
}
return statements;
} }
private MethodDeclarationSyntax DecompileMethodDeclaration(MarkupMethodSchema method, MarkupTypeSchema export) private MethodDeclarationSyntax DecompileMethodDeclaration(MarkupMethodSchema method, MarkupTypeSchema export)
@@ -246,20 +253,24 @@ partial class Decompiler
.WithModifiers(modifiers); .WithModifiers(modifiers);
} }
public static string FormatInlineExpression(ExpressionSyntax expr, CancellationToken token = default) public static SyntaxTree CreateTree(IEnumerable<StatementSyntax> statements)
{ {
var exprStr = expr return SyntaxTree(
.NormalizeWhitespace() CompilationUnit().WithMembers(
.SyntaxTree [.. statements.Select(GlobalStatement)]
.GetText(token) )
.ToString(); );
return '{' + exprStr + '}';
} }
public static string FormatScript(SyntaxTree tree, CancellationToken token = default) public static string FormatInlineExpression(ExpressionSyntax expr, CancellationToken token = default) => '{' + FormatSyntaxNode(expr, token) + '}';
public static string FormatScript(SyntaxTree tree, CancellationToken token = default) => FormatSyntaxNode(tree.GetRoot(token), token);
public static string FormatScript(IEnumerable<StatementSyntax> statements, CancellationToken token = default) => FormatScript(CreateTree(statements), token);
public static string FormatSyntaxNode(SyntaxNode root, CancellationToken token = default)
{ {
return tree return root
.GetRoot(token)
.NormalizeWhitespace() .NormalizeWhitespace()
.SyntaxTree .SyntaxTree
.GetText(token) .GetText(token)
+1 -2
View File
@@ -85,11 +85,10 @@ public partial class Decompiler
foreach (var offset in export.FinalEvaluateOffsets) foreach (var offset in export.FinalEvaluateOffsets)
{ {
var syntaxTree = DecompileScript(offset, export); var syntaxTree = DecompileScript(offset, export, "FinalEvaluate");
var scriptText = FormatScript(syntaxTree); var scriptText = FormatScript(syntaxTree);
XElement xScript = new(_nsUix + "Script", scriptText); XElement xScript = new(_nsUix + "Script", scriptText);
xScripts.Add(new XComment("TODO: FinalEvaluateOffsets"));
xScripts.Add(xScript); xScripts.Add(xScript);
} }
} }