diff --git a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs
index 0d4a3497..bbee33b6 100644
--- a/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs
+++ b/Source/AtlusScriptLibrary/FlowScriptLanguage/Compiler/FlowScriptCompiler.cs
@@ -125,14 +125,59 @@ public void AddListener(LogListener listener)
listener.Subscribe(mLogger);
}
+ ///
+ /// 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 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)
+ {
+ var imports = files.Select(import => new Import(import)).ToList();
+ mCurrentBaseDirectory = "";
+ InitializeCompilationState();
+
+ // Resolve imports
+ if (imports.Count > 0)
+ {
+ do
+ {
+ if (!TryResolveImportsSimple(imports))
+ {
+ Error("Failed to resolve imports");
+ resolvedImports = Array.Empty();
+ return false;
+ }
+ } while (mReresolveImports);
+ }
+
+ resolvedImports = 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.
///
/// 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)
+ {
+ 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;
@@ -160,6 +205,7 @@ public bool TryCompileWithImports(FileStream baseBfStream, List imports,
{
Error("Failed to parse compilation unit");
flowScript = null;
+ sources = null;
return false;
}
}
@@ -178,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;
+ }
}
///
@@ -442,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
//