From 265473b9f0386ca2e5af7f3365c471e40bbb9391 Mon Sep 17 00:00:00 2001 From: AnimatedSwine37 <24914353+AnimatedSwine37@users.noreply.github.com> Date: Sun, 20 Oct 2024 11:04:31 +1000 Subject: [PATCH 1/4] Add TryGetImports --- .../Compiler/FlowScriptCompiler.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs index 0d4a3497..9ffecb1a 100644 --- a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs +++ b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs @@ -125,6 +125,37 @@ public void AddListener(LogListener listener) listener.Subscribe(mLogger); } + /// + /// Tries to get a list of all files imported (directly or transitively) by a list of base flow files. + /// + /// A List of paths to .bf, .flow, and .msg files that will be added on top of the base flow + /// A list of all imports found. + /// + public bool TryGetImports(List files, out string[] resolvedImports) + { + CompilationUnit compilationUnit = new CompilationUnit(); + compilationUnit.Imports.AddRange(files.Select(import => new Import(import))); + mCurrentBaseDirectory = ""; + InitializeCompilationState(); + + // Resolve imports + if (compilationUnit.Imports.Count > 0) + { + do + { + if (!TryResolveImports(compilationUnit)) + { + Error(compilationUnit, "Failed to resolve imports"); + resolvedImports = Array.Empty(); + return false; + } + } while (mReresolveImports); + } + + resolvedImports = compilationUnit.Imports.Select(import => import.CompilationUnitFileName).ToArray(); + return true; + } + /// /// Tries to compile the provided FlowScript source with given imports. Returns a boolean indicating if the operation succeeded. /// From 551c611a066c9d44385b7d8b866d8f5b4d36cc02 Mon Sep 17 00:00:00 2001 From: AnimatedSwine37 <24914353+AnimatedSwine37@users.noreply.github.com> Date: Sun, 20 Oct 2024 11:05:05 +1000 Subject: [PATCH 2/4] Add sources output to TryCompileWithImports --- .../Compiler/FlowScriptCompiler.cs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs index 9ffecb1a..a11decdc 100644 --- a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs +++ b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs @@ -164,6 +164,20 @@ public bool TryGetImports(List files, out string[] resolvedImports) /// The compiled FlowScript /// True if the file successfully compiled, false otherwise public bool TryCompileWithImports(FileStream baseBfStream, List imports, string baseFlow, out FlowScript flowScript) + { + return TryCompileWithImports(baseBfStream, imports, baseFlow, out flowScript, out _); + } + + /// + /// Tries to compile the provided FlowScript source with given imports. Returns a boolean indicating if the operation succeeded. + /// + /// A FileStream of the base bf file + /// A List of paths to .bf, .flow, and .msg files that will be forcibly imported + /// A full path to the base .flow file to use for compilation + /// The compiled FlowScript or null if compilation failed + /// A list of full paths to all source files used to compile this bf or null if compilation failed + /// True if the file successfully compiled, false otherwise + public bool TryCompileWithImports(FileStream baseBfStream, List imports, string baseFlow, out FlowScript flowScript, out List sources) { // Parse base flow file CompilationUnit compilationUnit; @@ -191,6 +205,7 @@ public bool TryCompileWithImports(FileStream baseBfStream, List imports, { Error("Failed to parse compilation unit"); flowScript = null; + sources = null; return false; } } @@ -209,7 +224,17 @@ public bool TryCompileWithImports(FileStream baseBfStream, List imports, compilationUnit.Imports.AddRange(imports.Select(import => new Import(import))); mCurrentBaseDirectory = ""; - return TryCompile(compilationUnit, out flowScript); + if (TryCompile(compilationUnit, out flowScript)) + { + sources = compilationUnit.Imports.Select(import => import.CompilationUnitFileName).ToList(); + sources.Add(baseFlow); + return true; + } + else + { + sources = null; + return false; + } } /// From 85098f58cd44a556d559c8526239397fbfedf632 Mon Sep 17 00:00:00 2001 From: AnimatedSwine37 <24914353+AnimatedSwine37@users.noreply.github.com> Date: Sun, 20 Oct 2024 11:17:05 +1000 Subject: [PATCH 3/4] Improve summary comment for TryGetImports --- .../FlowScriptLanguage/Compiler/FlowScriptCompiler.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs index a11decdc..81aae00b 100644 --- a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs +++ b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs @@ -126,11 +126,11 @@ public void AddListener(LogListener listener) } /// - /// Tries to get a list of all files imported (directly or transitively) by a list of base flow files. + /// Tries to get a list of all files that would be imported (directly or transitively) when compiling a flowscript file. /// - /// A List of paths to .bf, .flow, and .msg files that will be added on top of the base flow - /// A list of all imports found. - /// + /// A List of paths to .bf, .flow, and .msg files to be used as a base when checking for imports. + /// A list of all imports found. This includes the passed in . + /// True if imports could be resolved, false otherwise public bool TryGetImports(List files, out string[] resolvedImports) { CompilationUnit compilationUnit = new CompilationUnit(); From 805da0feb0662ae7c6d1b712a0c2bfd5c841210b Mon Sep 17 00:00:00 2001 From: AnimatedSwine37 <24914353+AnimatedSwine37@users.noreply.github.com> Date: Sat, 30 Nov 2024 13:02:06 +1000 Subject: [PATCH 4/4] Only parse Flowscript files in TryGetImports --- .../Compiler/FlowScriptCompiler.cs | 106 +++++++++++++++++- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs index 81aae00b..bbee33b6 100644 --- a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs +++ b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs @@ -133,26 +133,25 @@ public void AddListener(LogListener listener) /// True if imports could be resolved, false otherwise public bool TryGetImports(List files, out string[] resolvedImports) { - CompilationUnit compilationUnit = new CompilationUnit(); - compilationUnit.Imports.AddRange(files.Select(import => new Import(import))); + var imports = files.Select(import => new Import(import)).ToList(); mCurrentBaseDirectory = ""; InitializeCompilationState(); // Resolve imports - if (compilationUnit.Imports.Count > 0) + if (imports.Count > 0) { do { - if (!TryResolveImports(compilationUnit)) + if (!TryResolveImportsSimple(imports)) { - Error(compilationUnit, "Failed to resolve imports"); + Error("Failed to resolve imports"); resolvedImports = Array.Empty(); return false; } } while (mReresolveImports); } - resolvedImports = compilationUnit.Imports.Select(import => import.CompilationUnitFileName).ToArray(); + resolvedImports = imports.Select(import => import.CompilationUnitFileName).ToArray(); return true; } @@ -161,6 +160,7 @@ public bool TryGetImports(List files, out string[] resolvedImports) /// /// A FileStream of the base bf file /// A List of paths to .bf, .flow, and .msg files that will be forcibly imported + /// A full path to the base .flow file to use for compilation /// The compiled FlowScript /// True if the file successfully compiled, false otherwise public bool TryCompileWithImports(FileStream baseBfStream, List imports, string baseFlow, out FlowScript flowScript) @@ -498,7 +498,101 @@ private void ExpandImportStatementsPaths(CompilationUnit compilationUnit, string import.CompilationUnitFileName = Path.Combine(baseDirectory, import.CompilationUnitFileName); } } + + private void ExpandImportStatementsPaths(List imports, string baseDirectory) + { + foreach (var import in imports) + { + import.CompilationUnitFileName = Path.Combine(baseDirectory, import.CompilationUnitFileName); + } + } + + /// + /// Tries to resolve a list of imports whilst only parsing flowscript files (since they can contain additional imports). + /// Compiled flowscript and message files are not parsed, they are just added to the list of imports. + /// + /// This can be used to determine a list of all imports starting from some initial ones. + /// It is not sufficient to actually compile the flowscript. + /// + /// is set to true this should be run again to determine additional imports from + /// flowscript files. + /// + /// The imports to resolve. Newly found imports are added to this. + /// True if imports could be resolved, false otherwise + private bool TryResolveImportsSimple(List imports) + { + Info("Resolving imports"); + + ExpandImportStatementsPaths(imports, mCurrentBaseDirectory); + + var importedFlowScripts = new List(); + var importedMsgAndBfs = new List(); + + foreach (var import in imports) + { + var ext = Path.GetExtension(import.CompilationUnitFileName).ToLowerInvariant(); + switch (ext) + { + case ".msg" or ".bf": + { + if (!TryGetFullImportPath(import, out var compilationUnitFilePath)) + { + Error($"Failed to resolve import: {import.CompilationUnitFileName}"); + return false; + } + importedMsgAndBfs.Add(new Import(compilationUnitFilePath)); + } + break; + + case ".flow": + { + // FlowScript + if (!TryResolveFlowScriptImport(import, out var importedCompilationUnit)) + { + Error(import, $"Failed to resolve FlowScript import: {import.CompilationUnitFileName}"); + return false; + } + + // Will be null if it was already imported before + if (importedCompilationUnit != null) + importedFlowScripts.Add(importedCompilationUnit); + } + break; + + default: + // Unknown + Error(import, $"Unknown import file type: {import.CompilationUnitFileName}"); + return false; + } + } + + // Resolve FlowScript imports + bool shouldReresolveImports = false; + if (importedFlowScripts.Count > 0) + { + // Merge compilation units + foreach (var importedFlowScript in importedFlowScripts) + { + if (importedFlowScript.Imports.Count > 0) + { + // If any of the imported FlowScripts have import, we have to re-resolve the imports again + shouldReresolveImports = true; + imports.AddRange(importedFlowScript.Imports); + } + } + } + + mReresolveImports = shouldReresolveImports; + + if (!mReresolveImports) + Info("Done resolving imports"); + + imports.AddRange(importedMsgAndBfs); + + return true; + } + // // Resolving imports //