public static (ASTNode node, string text) DecompileExport(ExportEntry export, FileLib lib = null) { try { ASTNode astNode = null; switch (export.ClassName) { case "Class": astNode = ME3ObjectToASTConverter.ConvertClass(export.GetBinaryData <UClass>(), true, lib); break; case "Function": astNode = ME3ObjectToASTConverter.ConvertFunction(export.GetBinaryData <UFunction>(), lib: lib); break; case "State": astNode = ME3ObjectToASTConverter.ConvertState(export.GetBinaryData <UState>(), lib: lib); break; case "Enum": astNode = ME3ObjectToASTConverter.ConvertEnum(export.GetBinaryData <UEnum>()); break; case "ScriptStruct": astNode = ME3ObjectToASTConverter.ConvertStruct(export.GetBinaryData <UScriptStruct>()); break; default: if (export.ClassName.EndsWith("Property") && ObjectBinary.From(export) is UProperty uProp) { astNode = ME3ObjectToASTConverter.ConvertVariable(uProp); } else { astNode = ME3ObjectToASTConverter.ConvertDefaultProperties(export); } break; } if (astNode != null) { var codeBuilder = new CodeBuilderVisitor(); astNode.AcceptVisitor(codeBuilder); return(astNode, codeBuilder.GetCodeString()); } } catch (Exception e) when(!App.IsDebug) { return(null, $"Error occured while decompiling {export?.InstancedFullPath}:\n\n{e.FlattenException()}"); } return(null, "Could not decompile!"); }
public static bool ResolveAllClassesInPackage(IMEPackage pcc, ref SymbolTable symbols) { string fileName = Path.GetFileNameWithoutExtension(pcc.FilePath); #if DEBUGSCRIPT string dumpFolderPath = Path.Combine(ME3Directory.gamePath, "ScriptDump", fileName); Directory.CreateDirectory(dumpFolderPath); #endif var log = new MessageLog(); Debug.WriteLine($"{fileName}: Beginning Parse."); var classes = new List <(Class ast, string scriptText)>(); foreach (ExportEntry export in pcc.Exports.Where(exp => exp.IsClass)) { Class cls = ME3ObjectToASTConverter.ConvertClass(export.GetBinaryData <UClass>(), false); string scriptText = ""; try { #if DEBUGSCRIPT var codeBuilder = new CodeBuilderVisitor(); cls.AcceptVisitor(codeBuilder); scriptText = codeBuilder.GetCodeString(); File.WriteAllText(Path.Combine(dumpFolderPath, $"{cls.Name}.uc"), scriptText); var parser = new ClassOutlineParser(new TokenStream <string>(new StringLexer(scriptText, log)), log); cls = parser.TryParseClass(); if (cls == null || log.Content.Any()) { DisplayError(scriptText, log.ToString()); return(false); } #endif if (export.ObjectName == "Object") { symbols = SymbolTable.CreateIntrinsicTable(cls); } else { symbols.AddType(cls); } classes.Add(cls, scriptText); } catch (Exception e) when(!App.IsDebug) { DisplayError(scriptText, log.ToString()); return(false); } } Debug.WriteLine($"{fileName}: Finished parse."); foreach (var validationPass in Enums.GetValues <ValidationPass>()) { foreach ((Class ast, string scriptText) in classes) { try { var validator = new ClassValidationVisitor(log, symbols, validationPass); ast.AcceptVisitor(validator); if (log.Content.Any()) { DisplayError(scriptText, log.ToString()); return(false); } } catch (Exception e) when(!App.IsDebug) { DisplayError(scriptText, log.ToString()); return(false); } } Debug.WriteLine($"{fileName}: Finished validation pass {validationPass}."); } switch (fileName) { case "Core": symbols.InitializeOperators(); break; case "Engine": symbols.ValidateIntrinsics(); break; } #if DEBUGSCRIPT //parse function bodies for testing purposes foreach ((Class ast, string scriptText) in classes) { symbols.RevertToObjectStack(); if (!ast.Name.CaseInsensitiveEquals("Object")) { symbols.GoDirectlyToStack(((Class)ast.Parent).GetInheritanceString()); symbols.PushScope(ast.Name); } foreach (Function function in ast.Functions.Where(func => !func.IsNative && func.IsDefined)) { CodeBodyParser.ParseFunction(function, scriptText, symbols, log); if (log.Content.Any()) { DisplayError(scriptText, log.ToString()); } } } #endif symbols.RevertToObjectStack(); return(true); }