diff --git a/CodeCompletion/CodeCompletion.cs b/CodeCompletion/CodeCompletion.cs index d17c57988..36ec2f658 100644 --- a/CodeCompletion/CodeCompletion.cs +++ b/CodeCompletion/CodeCompletion.cs @@ -372,7 +372,7 @@ namespace CodeCompletion Dirs.Add(CodeCompletionController.comp.CompilerOptions.SearchDirectory); if (CodeCompletionController.StandartDirectories.ContainsKey(LibSourceDirectoryIdent)) Dirs.Add((string)CodeCompletionController.StandartDirectories[LibSourceDirectoryIdent]); - return CodeCompletionController.comp.FindSourceFileName(unit_name, Dirs.ToArray()); + return CodeCompletionController.comp.FindSourceFileNameInDirs(unit_name, Dirs.ToArray()); } public static CodeCompletionNameHelper Helper diff --git a/CodeCompletion/DomSyntaxTreeVisitor.cs b/CodeCompletion/DomSyntaxTreeVisitor.cs index b6d4e9f48..fca361f2e 100644 --- a/CodeCompletion/DomSyntaxTreeVisitor.cs +++ b/CodeCompletion/DomSyntaxTreeVisitor.cs @@ -2414,7 +2414,7 @@ namespace CodeCompletion public string FindPCUFileName(string UnitName) { - return CodeCompletionController.comp.FindPCUFileNameWithoutSources(UnitName,System.IO.Path.GetDirectoryName(doc.file_name)); + return CodeCompletionController.comp.FindPCUFileName(UnitName,System.IO.Path.GetDirectoryName(doc.file_name), out _); } private void add_system_unit() @@ -2612,20 +2612,9 @@ namespace CodeCompletion NamespaceScope ns_scope = null; if (i == 0) { - string unit_name = null; string pcu_unit_name = FindPCUFileName(str); - if (s is uses_unit_in) - { - string unit_in_file = (s as uses_unit_in).in_file.Value; - string unit_in_dir = null; - if (Path.IsPathRooted(unit_in_file)) - unit_in_dir = Path.GetDirectoryName(unit_in_file); - else - unit_in_dir = Path.Combine(Path.GetDirectoryName(_program_module.file_name),Path.GetDirectoryName(unit_in_file)); - unit_name = CodeCompletionNameHelper.FindSourceFileName(Path.GetFileNameWithoutExtension(unit_in_file), unit_in_dir); - } - else - unit_name = CodeCompletionNameHelper.FindSourceFileName(str, System.IO.Path.GetDirectoryName(_program_module.file_name)); + string unit_name = CodeCompletionNameHelper.FindSourceFileName(s is uses_unit_in uui ? uui.in_file.Value : str, Path.GetDirectoryName(_program_module.file_name)); + /*if (pcu_unit_name != null && unit_name != null && string.Compare(System.IO.Path.GetDirectoryName(_program_module.file_name), System.IO.Path.GetDirectoryName(pcu_unit_name), true) == 0 && string.Compare(System.IO.Path.GetDirectoryName(_program_module.file_name), System.IO.Path.GetDirectoryName(unit_name), true) != 0) unit_name = null;*/ @@ -4370,20 +4359,9 @@ namespace CodeCompletion { try { - string unit_name = null; string pcu_unit_name = FindPCUFileName(str); - if (s is uses_unit_in) - { - string unit_in_file = (s as uses_unit_in).in_file.Value; - string unit_in_dir = null; - if (Path.IsPathRooted(unit_in_file)) - unit_in_dir = Path.GetDirectoryName(unit_in_file); - else - unit_in_dir = Path.Combine(Path.GetDirectoryName(this.cur_unit_file_name),Path.GetDirectoryName(unit_in_file)); - unit_name = CodeCompletionNameHelper.FindSourceFileName(Path.GetFileNameWithoutExtension(unit_in_file), unit_in_dir); - } - else - unit_name = CodeCompletionNameHelper.FindSourceFileName(str, System.IO.Path.GetDirectoryName(this.cur_unit_file_name)); + string unit_name = CodeCompletionNameHelper.FindSourceFileName(s is uses_unit_in uui ? uui.in_file.Value : str, Path.GetDirectoryName(this.cur_unit_file_name)); + /*if (pcu_unit_name != null && unit_name != null && string.Compare(System.IO.Path.GetDirectoryName(this.cur_unit_file_name), System.IO.Path.GetDirectoryName(pcu_unit_name), true) == 0 && string.Compare(System.IO.Path.GetDirectoryName(this.cur_unit_file_name), System.IO.Path.GetDirectoryName(unit_name), true) != 0) unit_name = null;*/ @@ -4503,12 +4481,9 @@ namespace CodeCompletion { try { - string unit_name = null; string pcu_unit_name = FindPCUFileName(str); - if (s is uses_unit_in) - unit_name = (s as uses_unit_in).in_file.Value; - else - unit_name = CodeCompletionNameHelper.FindSourceFileName(str, System.IO.Path.GetDirectoryName(this.cur_unit_file_name)); + string unit_name = CodeCompletionNameHelper.FindSourceFileName(s is uses_unit_in uui ? uui.in_file.Value : str, Path.GetDirectoryName(this.cur_unit_file_name)); + /*if (pcu_unit_name != null && unit_name != null && string.Compare(System.IO.Path.GetDirectoryName(this.cur_unit_file_name), System.IO.Path.GetDirectoryName(pcu_unit_name), true) == 0 && string.Compare(System.IO.Path.GetDirectoryName(this.cur_unit_file_name), System.IO.Path.GetDirectoryName(unit_name), true) != 0) unit_name = null;*/ @@ -5162,7 +5137,7 @@ namespace CodeCompletion } else { - string unit_name = CodeCompletionController.comp.FindSourceFileName(str); + string unit_name = CodeCompletionController.comp.FindSourceFileName(str, System.IO.Path.GetDirectoryName(_c_module.file_name), out _); if (unit_name == null) { unit_name = Path.Combine(System.IO.Path.GetDirectoryName(_c_module.file_name), str) + System.IO.Path.GetExtension(_c_module.file_name); diff --git a/Compiler/Compiler.cs b/Compiler/Compiler.cs index 5c13e12a1..9dfc071b8 100644 --- a/Compiler/Compiler.cs +++ b/Compiler/Compiler.cs @@ -163,7 +163,9 @@ using Microsoft.Scripting; using System.Reflection; //using SyntaxTreeChanger; using PascalABCCompiler.SyntaxTreeConverters; - +using System.Text; +using PascalABCCompiler.TreeRealization; +using System.Linq; namespace PascalABCCompiler { @@ -352,6 +354,19 @@ namespace PascalABCCompiler } } + public class UsesInWrongName : CompilerCompilationError + { + public string UnitName1; + public string UnitName2; + public UsesInWrongName(string FileName, string UnitName1, string UnitName2, SyntaxTree.SourceContext sc) + : base(string.Format(StringResources.Get("COMPILATIONERROR_USES_IN_WRONG_NAME"), UnitName1, UnitName2), FileName) + { + this.UnitName1 = UnitName1; + this.UnitName2 = UnitName2; + this.source_context = sc; + } + } + public class SourceFileNotFound : CompilerCompilationError { public SourceFileNotFound(string FileName) @@ -384,29 +399,23 @@ namespace PascalABCCompiler public class CompilationUnit { internal bool CaseSensitive = false; - public string CurrentUsesUnit; + public string CurrentUsesUnitId; public PascalABCCompiler.Errors.SyntaxError syntax_error; - public string UnitName; + public string UnitFileName; public List ErrorList=new List(); public bool Documented; internal List PossibleNamespaces = new List(); //internal List AssemblyReferences = new List(); - //private SemanticTree.compilation_unitArrayList _interfaceUsedUnits=new SemanticTree.compilation_unitArrayList(); + //private SemanticTree.compilation_unitArrayList _interfaceUsedUnits=new SemanticTree.compilation_unitArrayList(); - private PascalABCCompiler.TreeRealization.unit_node_list _interfaceUsedUnits = new PascalABCCompiler.TreeRealization.unit_node_list(); - public PascalABCCompiler.TreeRealization.unit_node_list InterfaceUsedUnits - { - get {return _interfaceUsedUnits;} - } + public Dictionary DirectInterfaceCompilationUnits { get; } = new Dictionary(); + public PascalABCCompiler.TreeRealization.unit_node_list InterfaceUsedUnits { get; } = new PascalABCCompiler.TreeRealization.unit_node_list(); - private PascalABCCompiler.TreeRealization.unit_node_list _implementationUsedUnits = new PascalABCCompiler.TreeRealization.unit_node_list(); - public PascalABCCompiler.TreeRealization.unit_node_list ImplementationUsedUnits - { - get {return _implementationUsedUnits;} - } + public Dictionary DirectImplementationCompilationUnits { get; } = new Dictionary(); + public PascalABCCompiler.TreeRealization.unit_node_list ImplementationUsedUnits { get; } = new PascalABCCompiler.TreeRealization.unit_node_list(); - private SyntaxTree.compilation_unit _syntaxTree=null; + private SyntaxTree.compilation_unit _syntaxTree=null; public SyntaxTree.compilation_unit SyntaxTree { get {return _syntaxTree;} @@ -614,7 +623,7 @@ namespace PascalABCCompiler internal string outputDirectory = null; internal bool useOutputDirectory = false; //для поиска pcu во вторую очередь - //для сохранения сюда pcu и pdb файлов + //для сохранения сюда .exe, .dll и .pdb файлов public string OutputDirectory { get @@ -862,7 +871,7 @@ namespace PascalABCCompiler supportedProjectFilesList.Add(new SupportedSourceFile(new string[1]{".pabcproj"},"PascalABC.NET")); supportedProjectFiles = supportedProjectFilesList.ToArray(); } - + private SupportedSourceFile[] supportedSourceFiles = null; public SupportedSourceFile[] SupportedSourceFiles { @@ -916,7 +925,6 @@ namespace PascalABCCompiler public SyntaxTree.unit_or_namespace CurrentSyntaxUnit; private List UnitsToCompile = new List(); public Hashtable RecompileList = new Hashtable(StringComparer.OrdinalIgnoreCase); - private PascalABCCompiler.TreeRealization.unit_node_list Units; private Hashtable CycleUnits = new Hashtable(); public CompilationUnit CurrentCompilationUnit = null; private CompilationUnit FirstCompilationUnit = null; @@ -960,26 +968,11 @@ namespace PascalABCCompiler } } - private Dictionary sourceFileNamesDictionary = new Dictionary(); + public Dictionary, Tuple> SourceFileNamesDictionary { get; } = new Dictionary, Tuple>(); - public Dictionary SourceFileNamesDictionary - { - get - { - return sourceFileNamesDictionary; - } - } - - private Dictionary pcuFileNamesDictionary = new Dictionary(); - - public Dictionary PCUFileNamesDictionary - { - get - { - return pcuFileNamesDictionary; - } - } + public Dictionary, Tuple> PCUFileNamesDictionary { get; } = new Dictionary, Tuple>(); + public Dictionary, string> GetUnitFileNameCache { get; } = new Dictionary, string>(); public void AddWarnings(List WarningList) { @@ -1162,7 +1155,7 @@ namespace PascalABCCompiler System.Collections.Generic.List list = new System.Collections.Generic.List(); foreach (SyntaxTree.compiler_directive sncd in cu.compiler_directives) { - list.Add(new TreeRealization.compiler_directive(sncd.Name.text, sncd.Directive!=null?sncd.Directive.text:"", get_location_from_treenode(sncd,cu.file_name))); + list.Add(new TreeRealization.compiler_directive(sncd.Name.text, sncd.Directive!=null?sncd.Directive.text:"", get_location_from_treenode(sncd,cu.file_name), cu.file_name)); } return list; } @@ -1189,7 +1182,8 @@ namespace PascalABCCompiler { SourceFileNamesDictionary.Clear(); PCUFileNamesDictionary.Clear(); - Warnings.Clear(); + GetUnitFileNameCache.Clear(); + Warnings.Clear(); errorsList.Clear(); //if (!File.Exists(CompilerOptions.SourceFileName)) throw new SourceFileNotFound(CompilerOptions.SourceFileName); CurrentCompilationUnit = null; @@ -1318,7 +1312,7 @@ namespace PascalABCCompiler }*/ else { - string source_file = FindSourceFileInDirectories(s+".vb",Path.GetDirectoryName(CompilerOptions.SourceFileName),Path.Combine(this.CompilerOptions.SystemDirectory,"lib"), + string source_file = FindFileInDirs(s+".vb",Path.GetDirectoryName(CompilerOptions.SourceFileName),Path.Combine(this.CompilerOptions.SystemDirectory,"lib"), Path.Combine(this.CompilerOptions.SystemDirectory,"LibSource")); if (!string.IsNullOrEmpty(source_file)) { @@ -1638,8 +1632,8 @@ namespace PascalABCCompiler parser.Dispose(); if (info != null) sources.AddRange(info.addit_project_files); - string redirect_base_fname = FindSourceFileInDirectories("__RedirectIOMode.vb",Path.Combine(this.CompilerOptions.SystemDirectory,"Lib"),Path.Combine(this.CompilerOptions.SystemDirectory,"LibSource")); - string system_unit_name = FindSourceFileInDirectories("VBSystem.vb",Path.Combine(this.CompilerOptions.SystemDirectory,"lib"),Path.Combine(this.CompilerOptions.SystemDirectory,"LibSource")); + string redirect_base_fname = FindFileInDirs("__RedirectIOMode.vb",Path.Combine(this.CompilerOptions.SystemDirectory,"Lib"),Path.Combine(this.CompilerOptions.SystemDirectory,"LibSource")); + string system_unit_name = FindFileInDirs("VBSystem.vb",Path.Combine(this.CompilerOptions.SystemDirectory,"lib"),Path.Combine(this.CompilerOptions.SystemDirectory,"LibSource")); string redirect_fname = Path.Combine(Path.GetDirectoryName(CompilerOptions.SourceFileName),"_RedirectIOMode.vb"); StreamReader sr = File.OpenText(redirect_base_fname); string redirect_module = sr.ReadToEnd(); @@ -1731,7 +1725,7 @@ namespace PascalABCCompiler if (info != null && info.modules.Count > 0) { comp_opt.ReferencedAssemblies.Add(Path.Combine(Path.GetDirectoryName(CompilerOptions.SourceFileName),PascalABCCompiler.TreeConverter.compiler_string_consts.pabc_rtl_dll_name)); - string mod_file_name = FindSourceFileInDirectories("PABCRtl.dll",Path.Combine(this.CompilerOptions.SystemDirectory,"Lib")); + string mod_file_name = FindFileInDirs("PABCRtl.dll",Path.Combine(this.CompilerOptions.SystemDirectory,"Lib")); File.Copy(mod_file_name,Path.Combine(Path.GetDirectoryName(CompilerOptions.SourceFileName),"PABCRtl.dll"),true); /*foreach (string mod in info.modules) { @@ -1824,19 +1818,19 @@ namespace PascalABCCompiler { PrepareCompileOptionsForProject(); } - Environment.CurrentDirectory = CompilerOptions.SourceFileDirectory; // нужно для подключения *.inc и *.resources - Units = new PascalABCCompiler.TreeRealization.unit_node_list(); - CurrentSyntaxUnit = new SyntaxTree.uses_unit_in(new SyntaxTree.string_const(CompilerOptions.SourceFileName)); + CurrentSyntaxUnit = new SyntaxTree.uses_unit_in(null, new SyntaxTree.string_const(Path.GetFullPath(CompilerOptions.SourceFileName))); - CompileUnit(Units, CurrentSyntaxUnit); - //Environment.CurrentDirectory = CompilerOptions.SourceFileDirectory; // 02.10.19 SunSerega: CompileUnit меняет CurrentDirectory чтоб работало относительное uses-in + CompileUnit( + new PascalABCCompiler.TreeRealization.unit_node_list(), + new Dictionary(), + CurrentSyntaxUnit, null); //Console.WriteLine(timer.ElapsedMilliseconds / 1000.0); ////// foreach (CompilationUnit CurrentUnit in UnitsToCompile) if (CurrentUnit.State != UnitState.Compiled) { CurrentCompilationUnit = CurrentUnit; - string UnitName = GetUnitFileName(CurrentUnit.SyntaxUnitName); + string UnitName = CurrentCompilationUnit.SyntaxTree.file_name; //if(CurrentUnit.State!=UnitState.InterfaceCompiled) //DEBUG //Console.WriteLine("ERROR! interface not compiled "+GetUnitFileName(CurrentUnit.SyntaxUnitName));//DEBUG System.Collections.Generic.List SyntaxUsesList = GetSyntaxImplementationUsesList(CurrentUnit.SyntaxTree); @@ -1846,20 +1840,19 @@ namespace PascalABCCompiler if (SyntaxUsesList != null) { for (int i = SyntaxUsesList.Count - 1; i >= 0; i--) - if (!IsPossibleNamespace(SyntaxUsesList[i], false)) + if (!IsPossibleNamespace(SyntaxUsesList[i], false, Path.GetDirectoryName(UnitName))) { compilerOptions.UseDllForSystemUnits = false; break; } for (int i = SyntaxUsesList.Count - 1; i >= 0; i--) - if (!IsPossibleNamespace(SyntaxUsesList[i], true)) + if (!IsPossibleNamespace(SyntaxUsesList[i], true, Path.GetDirectoryName(UnitName))) { - CompileUnit(CurrentUnit.ImplementationUsedUnits, SyntaxUsesList[i]); - //Environment.CurrentDirectory = CompilerOptions.SourceFileDirectory; // 02.10.19 SunSerega: CompileUnit меняет CurrentDirectory чтоб работало относительное uses-in + CompileUnit(CurrentUnit.ImplementationUsedUnits, CurrentUnit.DirectImplementationCompilationUnits, SyntaxUsesList[i], Path.GetDirectoryName(UnitName)); } else { - CurrentUnit.ImplementationUsedUnits.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(SyntaxUsesList[i]))); + CurrentUnit.ImplementationUsedUnits.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(SyntaxUsesList[i])), null); CurrentUnit.PossibleNamespaces.Add(SyntaxUsesList[i]); } } @@ -1891,7 +1884,7 @@ namespace PascalABCCompiler CurrentUnit.State = UnitState.Compiled; OnChangeCompilerState(this, CompilerState.EndCompileFile, UnitName); //SavePCU(CurrentUnit, UnitName); - CurrentUnit.UnitName = UnitName; + CurrentUnit.UnitFileName = UnitName; } ClosePCUReadersAndWriters(); @@ -1900,8 +1893,6 @@ namespace PascalABCCompiler compilerDirectives = GetCompilerDirectives(UnitsSortedList); - - TreeRealization.compiler_directive compilerDirective; if (compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.compiler_directive_apptype)) { string directive = compilerDirectives[TreeConverter.compiler_string_consts.compiler_directive_apptype][0].directive; @@ -1998,29 +1989,15 @@ namespace PascalABCCompiler ResourceFiles = new List(); List ResourceDirectives = compilerDirectives[TreeConverter.compiler_string_consts.compiler_directive_resource]; foreach (TreeRealization.compiler_directive cd in ResourceDirectives) - if (!File.Exists(cd.directive)) - { - if (cd.location.doc == null) - { - ErrorsList.Add(new ResourceFileNotFound(cd.directive)); - continue; - } - - try - { - string fileName = Path.Combine(cd.location.doc.file_name, cd.directive); - if (File.Exists(fileName)) - ResourceFiles.Add(fileName); - else - ErrorsList.Add(new ResourceFileNotFound(cd.directive, cd.location)); - } - catch (Exception e) - { - ErrorsList.Add(new ResourceFileNotFound(cd.directive, cd.location)); - } - } + { + var resource_fname = Path.Combine(Path.GetDirectoryName(cd.source_file), cd.directive); + + if (File.Exists(resource_fname)) + ResourceFiles.Add(resource_fname); else - ResourceFiles.Add(cd.directive); + ErrorsList.Add(new ResourceFileNotFound(cd.directive, cd.location)); + + } } string res_file = null; if (project != null) @@ -2279,7 +2256,6 @@ namespace PascalABCCompiler #endif } } - //Environment.CurrentDirectory = CompilerOptions.SourceFileDirectory; // 03.10.19 SunSerega: CompileUnit меняет CurrentDirectory чтоб работало относительное uses-in //удаляем лишние ошибки /*foreach(Error er in errorsList) @@ -2395,7 +2371,7 @@ namespace PascalABCCompiler { foreach (CompilationUnit cu in UnitsSortedList) { - SavePCU(cu, cu.UnitName); + SavePCU(cu); } foreach (PCUWriter pw in PCUWriter.AllWriters) { @@ -2483,104 +2459,143 @@ namespace PascalABCCompiler return null; } - private string FindFileInDirectories(string FileName, params string[] Dirs) + public string FindPCUFileName(string fname, string curr_path, out int folder_priority) { - FileName = Path.GetFileName(FileName); - string temp; - foreach (string Dir in Dirs) + if (string.IsNullOrEmpty(Path.GetExtension(fname))) + fname += CompilerOptions.CompiledUnitExtension; + var cache_key = Tuple.Create(fname.ToLower(), curr_path?.ToLower()); + + if (!PCUFileNamesDictionary.TryGetValue(cache_key, out var res)) { - temp = Path.Combine(Dir, FileName); - if (File.Exists(temp)) - //if (!(CompilerOptions.UseDllForSystemUnits && Path.GetDirectoryName(temp) == CompilerOptions.SearchDirectory)) - return temp; + + if (FindFileInDirs(fname, curr_path) is string res_s1) + res = Tuple.Create(res_s1, 1); + else if (FindFileInDirs(Path.GetFileName(fname), CompilerOptions.OutputDirectory) is string res_s2) + res = Tuple.Create(res_s2, 2); + else if (FindFileInDirs(fname, CompilerOptions.SearchDirectory) is string res_s3) + res = Tuple.Create(res_s3, 3); + else + res = null; + + PCUFileNamesDictionary[cache_key] = res; } - return null; + + folder_priority = res == null ? 0 : res.Item2; + return res?.Item1; } - private string FindSourceFileInDirectories(string FileName, params string[] Dirs) + + public string FindSourceFileName(string fname, string curr_path, out int folder_priority) { - FileName = Path.GetFileName(FileName); - string temp; - foreach (string Dir in Dirs) + var cache_key = Tuple.Create(fname.ToLower(), curr_path?.ToLower()); + + if (!SourceFileNamesDictionary.TryGetValue(cache_key, out var res)) { - temp = Path.Combine(Dir, FileName); - if (SourceFileExists(temp)) - return temp; + + if (FindSourceFileNameInDirs(fname, curr_path) is string res_s1) + res = Tuple.Create(res_s1, 1); + else if (FindSourceFileNameInDirs(fname, CompilerOptions.SearchDirectory) is string res_s3) + res = Tuple.Create(res_s3, 3); + else + res = null; + + SourceFileNamesDictionary[cache_key] = res; } - return null; - } - public string FindPCUFileName(string UnitName) - { - if (PCUFileNamesDictionary.ContainsKey(UnitName)) - return PCUFileNamesDictionary[UnitName]; - - string fpfn = null; - fpfn = FindFileInDirectories(UnitName + CompilerOptions.CompiledUnitExtension, CompilerOptions.OutputDirectory, CompilerOptions.SourceFileDirectory, CompilerOptions.SearchDirectory); - - PCUFileNamesDictionary[UnitName] = fpfn; - return fpfn; - } - - public string FindPCUFileNameWithoutSources(string UnitName, string FileDir) - { - return FindFileInDirectories(UnitName + CompilerOptions.CompiledUnitExtension, FileDir, CompilerOptions.OutputDirectory, CompilerOptions.SourceFileDirectory, CompilerOptions.SearchDirectory); + folder_priority = res == null ? 0 : res.Item2; + return res?.Item1; } - public string FindPCUFileName(string UnitName, string SourceFileName) + public string FindSourceFileNameInDirs(string fname, params string[] Dirs) { - if (PCUFileNamesDictionary.ContainsKey(UnitName)) - return PCUFileNamesDictionary[UnitName]; + var fname_ext = Path.GetExtension(fname); + var need_ext = string.IsNullOrEmpty(fname_ext); - string fpfn = null; - if (SourceFileName == null) - fpfn = FindPCUFileName(UnitName); - else - fpfn = FindFileInDirectories(UnitName + CompilerOptions.CompiledUnitExtension, Path.GetDirectoryName(SourceFileName)); - - PCUFileNamesDictionary[UnitName] = fpfn; - return fpfn; - } - - public string FindSourceFileName(string UnitName) - { - // Если есть в кеше, то пользуемся кешем - if (SourceFileNamesDictionary.ContainsKey(UnitName)) - return SourceFileNamesDictionary[UnitName]; - - - string d = CompilerOptions.SourceFileDirectory; - if (CurrentCompilationUnit != null && CurrentCompilationUnit.SyntaxTree != null) - d = Path.GetDirectoryName(CurrentCompilationUnit.SyntaxTree.file_name); - if (Path.GetDirectoryName(UnitName) != string.Empty) - d = Path.GetDirectoryName(UnitName); - - //string d = Environment.CurrentDirectory; // 03.10.19 SunSerega: вообще использовать Environment.CurrentDirectory всюду - говнокод, но если без него - надо очень много переписывать, проще уже всюду его использовать - - string fsfn = null; - if (d.Equals(CompilerOptions.SourceFileDirectory)) - fsfn = FindSourceFileName(UnitName, CompilerOptions.SourceFileDirectory, CompilerOptions.SearchDirectory); - else fsfn = FindSourceFileName(UnitName, d, CompilerOptions.SourceFileDirectory, CompilerOptions.SearchDirectory); - - // Кешируем исходники файлов и их полные имена - SourceFileNamesDictionary[UnitName] = fsfn; - - return fsfn; - } - - public string FindSourceFileName(string UnitName, params string[] Dirs) - { - string temp = null; foreach (SupportedSourceFile sf in SupportedSourceFiles) - { foreach (string ext in sf.Extensions) - temp = FindSourceFileInDirectories(UnitName + ext, Dirs); - if (temp != null) - //if (!(CompilerOptions.UseDllForSystemUnits && Path.GetDirectoryName(temp) == CompilerOptions.SearchDirectory)) - return temp;//.ToLower();?????? + if (need_ext || fname_ext==ext) + { + var res = FindFileInDirs(need_ext ? fname+ext : fname, Dirs); + //if (!(CompilerOptions.UseDllForSystemUnits && Path.GetDirectoryName(res) == CompilerOptions.SearchDirectory)) + if (res != null) + return res; + } + + return null; + } + + public static string CombinePath(string dir, string path) + { + if (Path.IsPathRooted(path)) return path; + int i = 0; + + for (; dir!="" && i < path.Length && path[i] == '.' && path[i + 1] == '.'; ) + { + dir = Path.GetDirectoryName(dir); + if (string.IsNullOrEmpty(dir)) return null; + i += 2; + if (path[i] == Path.DirectorySeparatorChar || path[i] == Path.AltDirectorySeparatorChar) i += 1; + } + + return Path.Combine(dir, path.Substring(i)); + } + + public static string GetUnitPath(CompilationUnit u1, CompilationUnit u2) + { + if (u1 == null) throw new ArgumentException(nameof(u1)); + if (u2 == null) throw new ArgumentException(nameof(u2)); + + if (u1.DirectInterfaceCompilationUnits .Values.Contains(u2)) return u1.InterfaceUsedUnits .unit_uses_paths[u2.SemanticTree]; + if (u1.DirectImplementationCompilationUnits .Values.Contains(u2)) return u1.ImplementationUsedUnits .unit_uses_paths[u2.SemanticTree]; + + var last = new Dictionary(); + var done = new HashSet(); + + foreach (var u in u1.DirectInterfaceCompilationUnits.Values.Concat(u1.DirectImplementationCompilationUnits.Values)) + { + last.Add(u, u1.InterfaceUsedUnits.unit_uses_paths[u.SemanticTree]); + done.Add(u); + } + + while (last.Count != 0) + { + var next = new Dictionary(); + + foreach (var u in last.Keys) + { + foreach (var used_u in u.DirectInterfaceCompilationUnits.Values) + { + if (!done.Add(used_u)) continue; + var path = CombinePath(Path.GetDirectoryName(last[u]), u.InterfaceUsedUnits.unit_uses_paths[used_u.SemanticTree]); + if (used_u == u2) return path; + next.Add(used_u, path); + } + + foreach (var used_u in u.DirectImplementationCompilationUnits.Values) + { + if (!done.Add(used_u)) continue; + var path = CombinePath(Path.GetDirectoryName(last[u]), u.ImplementationUsedUnits.unit_uses_paths[used_u.SemanticTree]); + if (used_u == u2) return path; + next.Add(used_u, path); + } + } + + last = next; + } + + throw new InvalidOperationException($"Could not find path to \"{u2.UnitFileName}\" relative to \"{u1.UnitFileName}\""); + } + + private string FindFileInDirs(string FileName, params string[] Dirs) + { + foreach (string Dir in Dirs) + { + var res = CombinePath(Dir, FileName); + if (File.Exists(res)) + return res; } return null; } - + public static string GetReferenceFileName(string FileName) { // Вначале - кешированные стандартные dll @@ -2597,7 +2612,7 @@ namespace PascalABCCompiler } } - private string GetReferenceFileName(string FileName, SyntaxTree.SourceContext sc) + private string GetReferenceFileName(string FileName, SyntaxTree.SourceContext sc, string curr_path) { if (standart_assembly_dict.ContainsKey(FileName)) return standart_assembly_dict[FileName]; @@ -2614,16 +2629,12 @@ namespace PascalABCCompiler } //\MikhailoMMX - if (System.IO.File.Exists(FileName)) // для отладки с *.inc файлами + var FullFileName = Path.Combine(curr_path, FileName); + if (System.IO.File.Exists(FullFileName)) { - if (FileName.IndexOf(Path.DirectorySeparatorChar) != -1) - { - File.Copy(Path.Combine(Environment.CurrentDirectory, FileName), Path.Combine(Environment.CurrentDirectory, Path.GetFileName(FileName)), true); - if (CompilerOptions.useOutputDirectory) - File.Copy(Path.Combine(Environment.CurrentDirectory, FileName), Path.Combine(CompilerOptions.OutputDirectory, Path.GetFileName(FileName)), true); - return Path.Combine(Environment.CurrentDirectory, Path.GetFileName(FileName)); - } - return Path.Combine(Environment.CurrentDirectory, FileName);//.ToLower();//? а надо ли tolover? + var NewFileName = Path.Combine(compilerOptions.OutputDirectory, Path.GetFileName(FullFileName)); + if (FullFileName != NewFileName) File.Copy(FullFileName, NewFileName, true); + return NewFileName; } else { @@ -2638,71 +2649,82 @@ namespace PascalABCCompiler } } - public string GetUnitFileName(SyntaxTree.unit_or_namespace SyntaxUsesUnit) + public string GetUnitFileName(SyntaxTree.unit_or_namespace SyntaxUsesUnit, string curr_path) { - string PCUFileName = null; - bool PCUFileExists = false; - string SourceFileName = null; - bool SourceFileExists = false; - string UnitName = null; + //ToDo В корневом Compile() создаётся uses_unit_in без name. Выглядит как костыль + if (SyntaxUsesUnit is SyntaxTree.uses_unit_in && (SyntaxUsesUnit as SyntaxTree.uses_unit_in).name == null) return (SyntaxUsesUnit as SyntaxTree.uses_unit_in).in_file.Value; + var UnitName = SyntaxUsesUnit.name.idents[0].name; - if (SyntaxUsesUnit is SyntaxTree.uses_unit_in) + if (SyntaxUsesUnit is SyntaxTree.uses_unit_in uui) { - SyntaxTree.uses_unit_in uui = (SyntaxUsesUnit as SyntaxTree.uses_unit_in); - string file_ext = System.IO.Path.GetExtension(uui.in_file.Value).ToLower(); - if (file_ext == ".dll" || file_ext == ".exe") - return GetReferenceFileName(uui.in_file.Value, uui.in_file.source_context); - if (uui.name == null) - return uui.in_file.Value;//.ToLower(); - UnitName = uui.name.idents[0].name;//.ToLower(); - SourceFileName = uui.in_file.Value;//.ToLower(); - SourceFileExists = this.SourceFileExists(SourceFileName); - PCUFileName = Path.ChangeExtension(SourceFileName, CompilerOptions.CompiledUnitExtension); - PCUFileExists = File.Exists(PCUFileName); - /*if (!PCUFileExists) - { - PCUFileName = FindPCUFileName(UnitName); - PCUFileExists = PCUFileName!=null && File.Exists(PCUFileName); - }*/ - } - else - { - UnitName = SyntaxUsesUnit.name.idents[0].name;//.ToLower();? - SourceFileName = FindSourceFileName(UnitName); - if (SourceFileName != null ) - SourceFileExists = SourceFileName != null; - PCUFileName = FindPCUFileName(UnitName, SourceFileName); - PCUFileExists = PCUFileName != null; - if (SourceFileExists && PCUFileExists) - if (Path.GetDirectoryName(SourceFileName) != Path.GetDirectoryName(PCUFileName)) - { - PCUFileName = null; - PCUFileExists = false; - } + + if (UnitName.ToLower() != Path.GetFileNameWithoutExtension(uui.in_file.Value).ToLower()) + throw new UsesInWrongName(CurrentCompilationUnit.SyntaxTree.file_name, UnitName, Path.GetFileNameWithoutExtension(uui.in_file.Value), uui.in_file.source_context); + } - if (SourceFileExists && UnitTable[SourceFileName] != null) - return Path.GetFullPath(SourceFileName); - if (PCUFileExists && !SourceFileExists) - return Path.GetFullPath(PCUFileName); - if (!CompilerOptions.Rebuild && RecompileList[UnitName] == null && PCUFileExists && (File.GetLastWriteTime(PCUFileName) > SourceFileGetLastWriteTime(SourceFileName))) - return Path.GetFullPath(PCUFileName); - - - if (SourceFileExists) - return Path.GetFullPath(SourceFileName); - - //dll по uses??? странно. хотя сам же писал - string DLLFileName = Path.Combine(CompilerOptions.SourceFileDirectory, UnitName+".dll");//(string.Format("{0}\\{1}.{2}", CompilerOptions.SourceFileDirectory, UnitName, "dll")).ToLower(); - if (File.Exists(DLLFileName)) - return DLLFileName.ToLower(); - DLLFileName = get_assembly_path(UnitName + ".dll", false); - if ((DLLFileName != null) && (File.Exists(DLLFileName))) return DLLFileName; - - return UnitName; - - } + return GetUnitFileName(UnitName, SyntaxUsesUnit.UsesPath(), curr_path, SyntaxUsesUnit.source_context); + } + public string GetUnitFileName(string UnitName, string path, string curr_path, SyntaxTree.SourceContext source_context) + { + var cache_key = Tuple.Create(path.ToLower(), curr_path?.ToLower()); + string res; + if (GetUnitFileNameCache.TryGetValue(cache_key, out res)) + return res; + + // число приоритета меньше = более важная папка + // может выглядеть задом-наперёд, но так должно быть проще в будущем добавлять папки... + var SourceFileName = FindSourceFileName(path, curr_path, out var SourceFilePriority); + var PCUFileName = FindPCUFileName(path, curr_path, out var PCUFilePriority); + + var SourceFileExists = SourceFileName != null; + //ToDo то есть Rebuild режим игнорирует .pcu, даже если нет .pas файла? + // а ещё ниже стоит ещё 1 проверка Rebuild... + var PCUFileExists = !CompilerOptions.Rebuild && PCUFileName != null; + + if (!PCUFileExists && !SourceFileExists) + if (UnitName == null) + // вызов с "UnitName == null" должен быть только там, где уже известно что хотя бы какой то файл есть + // если где то ещё будет исопльзоваться UnitName или source_context - надо будет добавить такую же проверку + throw new InvalidOperationException(nameof(UnitName)); + else + throw new UnitNotFound(CurrentCompilationUnit.SyntaxTree.file_name, UnitName, source_context); + + if (PCUFileExists && SourceFileExists) + { + + //ToDo из за проверки Rebuild выше - тут всегда будет false + // но я не понимаю какая из этих 2 проверок правильная + if (CompilerOptions.Rebuild && !RecompileList.ContainsKey(PCUFileName)) + PCUFileExists = false; + + else if (SourceFilePriority != PCUFilePriority) + { + if (SourceFilePriority < PCUFilePriority) + PCUFileExists = false; + else + SourceFileExists = false; + } + else if (Path.GetDirectoryName(SourceFileName) != Path.GetDirectoryName(PCUFileName)) + throw new InvalidOperationException("priority"); // не должно происходить, раз приоритет одинаковый + + else if (File.GetLastWriteTime(PCUFileName) < File.GetLastWriteTime(SourceFileName)) + PCUFileExists = false; + + } + + if (PCUFileExists) + res = Path.Combine(curr_path, PCUFileName); + else if (SourceFileExists) + res = Path.Combine(curr_path, SourceFileName); + else + throw new InvalidOperationException(nameof(SourceFileExists)); // тело "if (PCUFileExists && SourceFileExists)" не должно присваивать false обоим переменным + + GetUnitFileNameCache[cache_key] = res; + return res; + } + private bool FileInSearchDirectory(string FileName) { return Path.GetDirectoryName(FileName).ToLower() == CompilerOptions.SearchDirectory.ToLower(); @@ -2743,18 +2765,15 @@ namespace PascalABCCompiler PascalABCCompiler.SyntaxTree.unit_or_namespace to_add; if (Path.GetExtension(Module.Name) != "" /*&& Path.GetExtension(ModuleFileName).ToLower() != ".dll"*/) { - uses_unit_in = new SyntaxTree.uses_unit_in(); - uses_unit_in.in_file = new PascalABCCompiler.SyntaxTree.string_const(Module.Name); - uses_unit_in.name = new PascalABCCompiler.SyntaxTree.ident_list(); - uses_unit_in.name.idents.Add(new SyntaxTree.ident(ModuleName)); + uses_unit_in = new SyntaxTree.uses_unit_in( + _name: new SyntaxTree.ident_list(new SyntaxTree.ident(ModuleName)), + _in_file: new SyntaxTree.string_const(Module.Name)); //uses_unit_in.source_context = uses_unit_in.in_file.source_context = uses_unit_in.name.source_context = new SyntaxTree.SourceContext(1, 1, 1, 1); to_add = uses_unit_in; } else { - uses_unit = new SyntaxTree.unit_or_namespace(); - uses_unit.name = new PascalABCCompiler.SyntaxTree.ident_list(); - uses_unit.name.idents.Add(new SyntaxTree.ident(ModuleName)); + uses_unit = new SyntaxTree.unit_or_namespace(new SyntaxTree.ident_list(new SyntaxTree.ident(ModuleName))); //uses_unit.source_context = uses_unit.name.source_context = new SyntaxTree.SourceContext(1, 1, 1, 1); to_add = uses_unit; } @@ -2780,12 +2799,13 @@ namespace PascalABCCompiler string UnitName = null; try { - UnitName = GetReferenceFileName(cd.directive, sc); + UnitName = GetReferenceFileName(cd.directive, sc, Path.GetDirectoryName(cd.source_file)); } catch (AssemblyNotFound ex) { throw; } + //ToDo плохо, пока дебажил - тут постоянно ловились другие исключения, не связанные с неправильным знаками в пути к сборке catch (Exception ex) { throw new InvalidAssemblyPathError(CurrentCompilationUnit.SyntaxTree.file_name, sc); @@ -2794,7 +2814,7 @@ namespace PascalABCCompiler if (UnitTable.Count == 0) throw new ProgramModuleExpected(UnitName, null); if ((CurrentUnit = ReadDLL(UnitName)) != null) { - Units.AddElement(CurrentUnit.SemanticTree); + Units.AddElement(CurrentUnit.SemanticTree, null); UnitTable[UnitName] = CurrentUnit; return CurrentUnit; } @@ -2889,9 +2909,9 @@ namespace PascalABCCompiler checkDuplicateUsesUnit(unit.interface_part.uses_modules.units); foreach (SyntaxTree.unit_or_namespace name_space in unit.interface_part.uses_modules.units) { - if (IsPossibleNamespace(name_space, false)) + if (IsPossibleNamespace(name_space, false, Path.GetDirectoryName(file))) { - ns.referenced_units.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(name_space), get_location_from_treenode(name_space, tree.file_name))); + ns.referenced_units.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(name_space), get_location_from_treenode(name_space, tree.file_name)), null); } else { @@ -2967,23 +2987,23 @@ namespace PascalABCCompiler } if (CompilerOptions.UseDllForSystemUnits) { - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\PABCRtl.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\mscorlib.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.Core.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.Numerics.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.Windows.Forms.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.Drawing.dll", null)); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\PABCRtl.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\mscorlib.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.Core.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.Numerics.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.Windows.Forms.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\System.Drawing.dll", null, ".")); if (Unit.SyntaxTree is SyntaxTree.program_module && (Unit.SyntaxTree as SyntaxTree.program_module).used_units != null) foreach (SyntaxTree.unit_or_namespace uui in (Unit.SyntaxTree as SyntaxTree.program_module).used_units.units) { if (uui.name.ToString() == "Graph3D") { - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\PresentationFramework.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\WindowsBase.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\PresentationCore.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\HelixToolkit.Wpf.dll", null)); - directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\HelixToolkit.dll", null)); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\PresentationFramework.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\WindowsBase.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\PresentationCore.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\HelixToolkit.Wpf.dll", null, ".")); + directives.Add(new TreeRealization.compiler_directive("reference", "%GAC%\\HelixToolkit.dll", null, ".")); } } @@ -3002,20 +3022,20 @@ namespace PascalABCCompiler { foreach (ReferenceInfo ri in project.references) { - CompileReference(res,new TreeRealization.compiler_directive("reference",ri.full_assembly_name,null)); + CompileReference(res, new TreeRealization.compiler_directive("reference", ri.full_assembly_name, null, project.MainFile)); } } return res; } - private bool IsPossibleNamespace(SyntaxTree.unit_or_namespace name_space, bool add_to_standard_modules) + private bool IsPossibleNamespace(SyntaxTree.unit_or_namespace name_space, bool add_to_standard_modules, string curr_path) { if (name_space is SyntaxTree.uses_unit_in) return false; if (name_space.name.idents.Count > 1) return true; - string src = FindSourceFileName(name_space.name.idents[0].name); - string pcu = FindPCUFileName(name_space.name.idents[0].name); + string src = FindSourceFileName(name_space.name.idents[0].name, curr_path, out _); + string pcu = FindPCUFileName(name_space.name.idents[0].name, curr_path, out _); if (src == null && pcu == null) return true; if (CompilerOptions.UseDllForSystemUnits && src != null && string.Compare(Path.GetDirectoryName(src), Path.Combine(CompilerOptions.SystemDirectory, "Lib"), true) == 0 @@ -3136,28 +3156,6 @@ namespace PascalABCCompiler return cu; } - private bool IsAssemblyReference(SyntaxTree.unit_or_namespace SyntaxUsesUnit) - { - string UnitName = GetUnitFileName(SyntaxUsesUnit); - if (UnitName.ToLower().LastIndexOf(".dll") >= 0 || UnitName.ToLower().LastIndexOf(".exe") >= 0) - if (File.Exists(UnitName)) - return true; - return false; - } - - private CompilationUnit GetAssemblyReference(SyntaxTree.unit_or_namespace SyntaxUsesUnit) - { - string UnitName = GetUnitFileName(SyntaxUsesUnit); - if (UnitTable.Count == 0) - throw new ProgramModuleExpected(UnitName, null); - CompilationUnit res = ReadDLL(UnitName); - if (res != null) - return res; - else - //throw new DLLReadingError(UnitName); - throw new AssemblyReadingError(CurrentCompilationUnit.SyntaxTree.file_name,UnitName,SyntaxUsesUnit.source_context); - } - /*private bool check_for_library(List directives) { foreach (compiler_directive cd in directives) @@ -3176,61 +3174,42 @@ namespace PascalABCCompiler return false; } - public CompilationUnit CompileUnit(PascalABCCompiler.TreeRealization.unit_node_list Units, SyntaxTree.unit_or_namespace SyntaxUsesUnit) + public CompilationUnit CompileUnit(PascalABCCompiler.TreeRealization.unit_node_list Units, Dictionary DirectCompilationUnits, SyntaxTree.unit_or_namespace SyntaxUsesUnit, string prev_path) { - string UnitName = GetUnitFileName(SyntaxUsesUnit); - if (!UnitName.Contains("\\")) UnitName = Path.GetFullPath(UnitName); - //Environment.CurrentDirectory = Path.GetDirectoryName(UnitName); // 02.10.19 SunSerega: Эта строчка нужна чтоб работало рекурсивное uses-in - //if (UnitName == null) throw new UnitNotFound(SyntaxUsesUnit.name, - CompilationUnit CurrentUnit = UnitTable[UnitName]; + string UnitFileName = GetUnitFileName(SyntaxUsesUnit, prev_path); + string UnitId = Path.ChangeExtension(UnitFileName, null); + // Имя папки, в которой лежит текущий модуль + // Используется для подключения модулей, $include и т.п. из модуля, подключённого с uses-in + var curr_path = Path.GetDirectoryName(UnitFileName); + + CompilationUnit CurrentUnit = UnitTable[UnitId]; if (CurrentUnit != null && CurrentUnit.SemanticTree is PascalABCCompiler.TreeRealization.dot_net_unit_node && SyntaxUsesUnit is PascalABCCompiler.SyntaxTree.uses_unit_in ui && ui.in_file != null) // значит, это пространство имен и секция in у него должна отсутствовать { ErrorsList.Add(new NamespaceCannotHaveInSection(ui.in_file.source_context)); } - string name = Path.GetFileNameWithoutExtension(UnitName); - if (Path.GetExtension(UnitName).ToLower() == CompilerOptions.CompiledUnitExtension) - { - string sfn = FindSourceFileName(Path.GetFileNameWithoutExtension(UnitName)); - if (sfn != null && UnitTable[sfn] != null) - CurrentUnit = UnitTable[sfn]; - } - if (CurrentUnit != null) if (CurrentUnit.State != UnitState.BeginCompilation || CurrentUnit.SemanticTree != null) //ИЗБАВИТЬСЯ ОТ ВТОРОГО УСЛОВИЯ { - Units.AddElement(CurrentUnit.SemanticTree); + if (Units.AddElement(CurrentUnit.SemanticTree, SyntaxUsesUnit.UsesPath())) + DirectCompilationUnits.Add(CurrentUnit.SemanticTree, CurrentUnit); Units.AddRange(GetReferences(CurrentUnit)); return CurrentUnit; } - if (UnitName.ToLower().LastIndexOf(".dll") >= 0 || UnitName.ToLower().LastIndexOf(".exe") >= 0) - if (File.Exists(UnitName)) + if (CurrentUnit==null && Path.GetExtension(UnitFileName).ToLower() == CompilerOptions.CompiledUnitExtension) + if (File.Exists(UnitFileName)) { - if (UnitTable.Count == 0) throw new ProgramModuleExpected(UnitName, null); - if ((CurrentUnit = ReadDLL(UnitName)) != null) - { - Units.AddElement(CurrentUnit.SemanticTree); - UnitTable[UnitName] = CurrentUnit; - return CurrentUnit; - } - else - //throw new DLLReadingError(UnitName); - throw new AssemblyReadingError(CurrentCompilationUnit.SyntaxTree.file_name, UnitName, SyntaxUsesUnit.source_context); - } - if (Path.GetExtension(UnitName).ToLower() == CompilerOptions.CompiledUnitExtension) - if (File.Exists(UnitName)) - { - if (UnitTable.Count == 0) throw new ProgramModuleExpected(UnitName, null); - string SourceFileName = FindSourceFileName(Path.Combine(Path.GetDirectoryName(UnitName), Path.GetFileNameWithoutExtension(UnitName))); + if (UnitTable.Count == 0) throw new ProgramModuleExpected(UnitFileName, null); try { - if ((CurrentUnit = ReadPCU(UnitName)) != null) + if ((CurrentUnit = ReadPCU(UnitFileName)) != null) { - Units.AddElement(CurrentUnit.SemanticTree); + if (Units.AddElement(CurrentUnit.SemanticTree, SyntaxUsesUnit.UsesPath())) + DirectCompilationUnits.Add(CurrentUnit.SemanticTree, CurrentUnit); Units.AddRange(GetReferences(CurrentUnit)); - UnitTable[UnitName] = CurrentUnit; + UnitTable[UnitId] = CurrentUnit; return CurrentUnit; } } @@ -3244,16 +3223,17 @@ namespace PascalABCCompiler } catch (Exception e) { - OnChangeCompilerState(this, CompilerState.PCUReadingError, UnitName); + OnChangeCompilerState(this, CompilerState.PCUReadingError, UnitFileName); #if DEBUG if (!InternalDebug.SkipPCUErrors) throw new Errors.CompilerInternalError("PCUReader", e); #endif } + string SourceFileName = FindSourceFileName(Path.ChangeExtension(UnitFileName, null), null, out _); if (SourceFileName == null) - throw new ReadPCUError(UnitName); + throw new ReadPCUError(UnitFileName); else - UnitName = SourceFileName; + UnitFileName = SourceFileName; } string SourceText = null; Dictionary docs = null; @@ -3263,20 +3243,20 @@ namespace PascalABCCompiler CurrentUnit = new CompilationUnit(); if (FirstCompilationUnit == null) FirstCompilationUnit = CurrentUnit; - OnChangeCompilerState(this, CompilerState.BeginCompileFile, UnitName); - SourceText = GetSourceFileText(UnitName); + OnChangeCompilerState(this, CompilerState.BeginCompileFile, UnitFileName); + SourceText = GetSourceFileText(UnitFileName); if (SourceText == null) if (CurrentUnit == FirstCompilationUnit) - throw new SourceFileNotFound(UnitName); + throw new SourceFileNotFound(UnitFileName); else - throw new UnitNotFound(CurrentCompilationUnit.SyntaxTree.file_name, UnitName, SyntaxUsesUnit.source_context); + throw new UnitNotFound(CurrentCompilationUnit.SyntaxTree.file_name, UnitFileName, SyntaxUsesUnit.source_context); List DefinesList = new List(); DefinesList.Add("PASCALABC"); if (!compilerOptions.Debug && !compilerOptions.ForDebugging) DefinesList.Add("RELEASE"); else DefinesList.Add("DEBUG"); - CurrentUnit.SyntaxTree = InternalParseText(UnitName, SourceText, errorsList, warnings, DefinesList); + CurrentUnit.SyntaxTree = InternalParseText(UnitFileName, SourceText, errorsList, warnings, DefinesList); if (errorsList.Count == 0) // SSM 2/05/16 - для преобразования синтаксических деревьев извне { @@ -3339,13 +3319,13 @@ namespace PascalABCCompiler throw errorsList[0]; } - UnitTable[UnitName] = CurrentUnit; + UnitTable[UnitId] = CurrentUnit; if (UnitTable.Count > 1)//если это не главный модуль if (CurrentUnit.SyntaxTree is SyntaxTree.program_module) - throw new UnitModuleExpected(UnitName, CurrentUnit.SyntaxTree.source_context.LeftSourceContext); + throw new UnitModuleExpected(UnitFileName, CurrentUnit.SyntaxTree.source_context.LeftSourceContext); else if (is_dll(CurrentUnit.SyntaxTree)) - throw new UnitModuleExpectedLibraryFound(UnitName, CurrentUnit.SyntaxTree.source_context.LeftSourceContext); + throw new UnitModuleExpectedLibraryFound(UnitFileName, CurrentUnit.SyntaxTree.source_context.LeftSourceContext); //здесь в начало uses добавляем стандартные модули #if DEBUG if (InternalDebug.AddStandartUnits) @@ -3368,7 +3348,7 @@ namespace PascalABCCompiler { for (int i = SyntaxUsesList.Count - 1 - CurrentUnit.InterfaceUsedUnits.Count; i >= 0; i--) { - if (!IsPossibleNamespace(SyntaxUsesList[i], false)) + if (!IsPossibleNamespace(SyntaxUsesList[i], false, curr_path)) { compilerOptions.UseDllForSystemUnits = false; break; @@ -3382,34 +3362,36 @@ namespace PascalABCCompiler for (int i = SyntaxUsesList.Count - 1 - CurrentUnit.InterfaceUsedUnits.Count; i >= 0; i--) { - if (IsPossibleNamespace(SyntaxUsesList[i], true) || namespaces.ContainsKey(SyntaxUsesList[i].name.idents[0].name)) + if (IsPossibleNamespace(SyntaxUsesList[i], true, curr_path) || namespaces.ContainsKey(SyntaxUsesList[i].name.idents[0].name)) { - CurrentUnit.InterfaceUsedUnits.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(SyntaxUsesList[i]))); + CurrentUnit.InterfaceUsedUnits.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(SyntaxUsesList[i])), null); CurrentUnit.PossibleNamespaces.Add(SyntaxUsesList[i]); } else { - string CurrentSyntaxUnitName = GetUnitFileName(SyntaxUsesList[i]); - CurrentUnit.CurrentUsesUnit = CurrentSyntaxUnitName; - if (UnitTable[CurrentSyntaxUnitName] != null) - if (UnitTable[CurrentSyntaxUnitName].State == UnitState.BeginCompilation) + var CurrentSyntaxUnitFileName = GetUnitFileName(SyntaxUsesList[i], curr_path); + var CurrentSyntaxUnitId = Path.ChangeExtension(CurrentSyntaxUnitFileName, null); + CurrentUnit.CurrentUsesUnitId = CurrentSyntaxUnitId; + + if (UnitTable[CurrentSyntaxUnitId] != null) + if (UnitTable[CurrentSyntaxUnitId].State == UnitState.BeginCompilation) { - string CurrentSyntaxUnitNameCurrentUsesUnit = UnitTable[CurrentSyntaxUnitName].CurrentUsesUnit; - if (CurrentSyntaxUnitNameCurrentUsesUnit != null) + string CurrentSyntaxUnit_CurrentUsesUnitId = UnitTable[CurrentSyntaxUnitId].CurrentUsesUnitId; + if (CurrentSyntaxUnit_CurrentUsesUnitId != null) { - //если сначало взали pcu а потом решили его перекомпилировать, поэтому в таблице его нет - if (UnitTable[CurrentSyntaxUnitNameCurrentUsesUnit] == null) - UnitTable[CurrentSyntaxUnitName].CurrentUsesUnit = FindSourceFileName(Path.GetFileNameWithoutExtension(CurrentSyntaxUnitNameCurrentUsesUnit)); + //если сначало взяли pcu а потом решили его перекомпилировать, поэтому в таблице его нет + if (UnitTable[CurrentSyntaxUnit_CurrentUsesUnitId] == null) + UnitTable[CurrentSyntaxUnitId].CurrentUsesUnitId = CurrentSyntaxUnit_CurrentUsesUnitId; //далее финальная поверка на зацикливание - if (UnitTable[CurrentSyntaxUnitName].CurrentUsesUnit != null && UnitTable[UnitTable[CurrentSyntaxUnitName].CurrentUsesUnit].State == UnitState.BeginCompilation) - throw new CycleUnitReference(UnitName, SyntaxUsesList[i]); + if (UnitTable[CurrentSyntaxUnitId].CurrentUsesUnitId != null && UnitTable[UnitTable[CurrentSyntaxUnitId].CurrentUsesUnitId].State == UnitState.BeginCompilation) + throw new CycleUnitReference(UnitFileName, SyntaxUsesList[i]); } } - CompileUnit(CurrentUnit.InterfaceUsedUnits, SyntaxUsesList[i]); - //Environment.CurrentDirectory = Path.GetDirectoryName(UnitName); // 02.10.19 SunSerega: CompileUnit меняет CurrentDirectory чтоб работало относительное uses-in + CompileUnit(CurrentUnit.InterfaceUsedUnits, CurrentUnit.DirectInterfaceCompilationUnits, SyntaxUsesList[i], curr_path); if (CurrentUnit.State == UnitState.Compiled) { - Units.AddElement(CurrentUnit.SemanticTree); + if (Units.AddElement(CurrentUnit.SemanticTree, SyntaxUsesUnit.UsesPath())) + DirectCompilationUnits.Add(CurrentUnit.SemanticTree, CurrentUnit); Units.AddRange(References); return CurrentUnit; } @@ -3432,7 +3414,7 @@ namespace PascalABCCompiler { if (CurrentUnit.State != UnitState.InterfaceCompiled) { - OnChangeCompilerState(this, CompilerState.CompileInterface, UnitName); + OnChangeCompilerState(this, CompilerState.CompileInterface, UnitFileName); PascalABCCompiler.TreeConverter.SemanticRules.SymbolTableCaseSensitive = CurrentUnit.CaseSensitive; CurrentUnit.SemanticTree = SyntaxTreeToSemanticTreeConverter.CompileInterface( CurrentUnit.SyntaxTree, @@ -3457,7 +3439,8 @@ namespace PascalABCCompiler CurrentUnit.State = UnitState.InterfaceCompiled; if (Units != null) { - Units.AddElement(CurrentUnit.SemanticTree); + if (Units.AddElement(CurrentUnit.SemanticTree, SyntaxUsesUnit.UsesPath())) + DirectCompilationUnits.Add(CurrentUnit.SemanticTree, CurrentUnit); Units.AddRange(References); } SyntaxUsesList = GetSyntaxImplementationUsesList(CurrentUnit.SyntaxTree); @@ -3467,9 +3450,9 @@ namespace PascalABCCompiler if (SyntaxUsesList != null) { for (int i = SyntaxUsesList.Count - 1; i >= 0; i--) - if (!IsPossibleNamespace(SyntaxUsesList[i], true)) + if (!IsPossibleNamespace(SyntaxUsesList[i], true, curr_path)) { - cu = UnitTable[GetUnitFileName(SyntaxUsesList[i])]; + cu = UnitTable[Path.ChangeExtension(GetUnitFileName(SyntaxUsesList[i], curr_path), null)]; if (cu != null && cu.State == UnitState.BeginCompilation) { UnitsToCompile.Add(cu); @@ -3480,13 +3463,12 @@ namespace PascalABCCompiler } else { - CompileUnit(CurrentUnit.ImplementationUsedUnits, SyntaxUsesList[i]); - //Environment.CurrentDirectory = Path.GetDirectoryName(UnitName); // 02.10.19 SunSerega: CompileUnit меняет CurrentDirectory чтоб работало относительное uses-in + CompileUnit(CurrentUnit.ImplementationUsedUnits, CurrentUnit.DirectImplementationCompilationUnits, SyntaxUsesList[i], curr_path); } } else { - CurrentUnit.ImplementationUsedUnits.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(SyntaxUsesList[i]))); + CurrentUnit.ImplementationUsedUnits.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(SyntaxUsesList[i])), null); CurrentUnit.PossibleNamespaces.Add(SyntaxUsesList[i]); } } @@ -3515,7 +3497,7 @@ namespace PascalABCCompiler if (InternalDebug.SemanticAnalysis) #endif { - OnChangeCompilerState(this, CompilerState.CompileImplementation, UnitName); + OnChangeCompilerState(this, CompilerState.CompileImplementation, UnitFileName); PascalABCCompiler.TreeConverter.SemanticRules.SymbolTableCaseSensitive = CurrentUnit.CaseSensitive; SyntaxTreeToSemanticTreeConverter.CompileImplementation( (PascalABCCompiler.TreeRealization.common_unit_node)CurrentUnit.SemanticTree, @@ -3539,9 +3521,9 @@ namespace PascalABCCompiler if (!UnitsSortedList.Contains(CurrentUnit))//vnimanie zdes inogda pri silnoj zavisimosti modulej moduli popadajut neskolko raz UnitsSortedList.Add(CurrentUnit); } - OnChangeCompilerState(this, CompilerState.EndCompileFile, UnitName); + OnChangeCompilerState(this, CompilerState.EndCompileFile, UnitFileName); //SavePCU(CurrentUnit, UnitName); - CurrentUnit.UnitName = UnitName; + CurrentUnit.UnitFileName = UnitFileName; return CurrentUnit; /*if(CurrentUnit.State!=UnitState.Compiled) { @@ -3597,12 +3579,12 @@ namespace PascalABCCompiler foreach (TreeRealization.unit_node un in cu.InterfaceUsedUnits) { if (un is TreeRealization.dot_net_unit_node) - unl.AddElement(un); + unl.AddElement(un, null); } return unl; } - public void SavePCU(CompilationUnit Unit,string TagertFileName) + public void SavePCU(CompilationUnit Unit) { //#if DEBUG try @@ -3633,27 +3615,20 @@ namespace PascalABCCompiler Unit.State == UnitState.Compiled) { writer = new PCUWriter(this, pr_ChangeState); - if (FileInSearchDirectory(TagertFileName)) - TagertFileName = Path.ChangeExtension(TagertFileName, CompilerOptions.CompiledUnitExtension); - else - { - if(CompilerOptions.useOutputDirectory) - TagertFileName = Path.Combine(CompilerOptions.OutputDirectory, Path.GetFileName(Path.ChangeExtension(TagertFileName, CompilerOptions.CompiledUnitExtension))); - else - TagertFileName = Path.Combine(Path.GetDirectoryName(Unit.SyntaxTree.file_name), Path.GetFileName(Path.ChangeExtension(TagertFileName, CompilerOptions.CompiledUnitExtension))); - } + bool dbginfo = true;/*CompilerOptions.Debug*/ #if DEBUG dbginfo = InternalDebug.IncludeDebugInfoInPCU; #endif - writer.SaveSemanticTree(Unit, TagertFileName, dbginfo); + + writer.SaveSemanticTree(Unit, Path.ChangeExtension(Unit.UnitFileName, CompilerOptions.CompiledUnitExtension), dbginfo); } } catch (Exception err) { //ErrorsList.Add(new Errors.CompilerInternalError(string.Format("Compiler.Compile[{0}]", Path.GetFileName(this.CurrentCompilationUnit.SyntaxTree.file_name)), err)); - OnChangeCompilerState(this, CompilerState.PCUWritingError, TagertFileName); + OnChangeCompilerState(this, CompilerState.PCUWritingError, Unit.UnitFileName); #if DEBUG if (!InternalDebug.SkipPCUErrors) throw new Errors.CompilerInternalError(string.Format("Compiler.Compile[{0}]", Path.GetFileName(this.CurrentCompilationUnit.SyntaxTree.file_name)), err); @@ -3869,49 +3844,50 @@ namespace PascalABCCompiler return null; return cu; }*/ - public bool NeedRecompiled(string name, string dir, string[] included, PCUReader pr) + public bool NeedRecompiled(string pcu_name, string[] included, PCUReader pr) { - string pas_name = FindSourceFileName(Path.Combine(dir,name)); - string pcu_name = FindPCUFileName(name,pas_name); - if (UnitTable[pas_name] != null) + if (!Path.IsPathRooted(pcu_name)) throw new InvalidOperationException(); + string pas_name = FindSourceFileName(Path.ChangeExtension(pcu_name, null), null, out _); + var dir = Path.GetDirectoryName(pcu_name); + + if (UnitTable[Path.ChangeExtension(pas_name, null)] != null) return true; + bool need = false; for (int i = 0; i < included.Length; i++) { //if (included[i].Contains("$")) - // continue; - string pas_name2 = FindSourceFileName(Path.Combine(dir,included[i])); - string pcu_name2 = FindPCUFileName(included[i],pas_name2); - if (UnitTable[pas_name2] != null) - return true; - if (!File.Exists(pcu_name2)) + // continue; + var used_unit_fname = GetUnitFileName(Path.GetFileNameWithoutExtension(included[i]), included[i], dir, null); + var used_unit_is_pcu = Path.GetExtension(used_unit_fname) == CompilerOptions.CompiledUnitExtension; + + if (!used_unit_is_pcu) { - need = true; RecompileList[name] = name; - RecompileList[included[i]] = included[i]; + if (UnitTable[Path.ChangeExtension(used_unit_fname, null)] != null) return true; + need = true; + RecompileList[pcu_name] = pcu_name; } - else - if (SourceFileExists(pas_name2) && File.GetLastWriteTime(pcu_name2) <= SourceFileGetLastWriteTime(pas_name2)) - { - need = true; CycleUnits[name] = name; RecompileList[name] = name; - RecompileList[included[i]] = included[i]; - } } if (need) return true; + if (!SourceFileExists(pas_name)) return false; - if (!File.Exists(pcu_name)) return true; + + // NeedRecompiled вызывается уже после успешного прочтения заголовка модуля (иначе откуда included) + //if (!File.Exists(pcu_name)) return true; + if (File.GetLastWriteTime(pcu_name) < SourceFileGetLastWriteTime(pas_name)) return true; //Console.WriteLine("{0} {1}",name,RecompileList.Count); for (int i = 0; i < included.Length; i++) { - string pcu_name2 = FindPCUFileName(included[i]); + string pcu_name2 = FindPCUFileName(included[i], dir, out _); //TODO: Спросить у Сащи насчет < и <=. if ((File.Exists(pcu_name2) && File.GetLastWriteTime(pcu_name) < File.GetLastWriteTime(pcu_name2) && !pr.AlreadyCompiled(pcu_name2))) { - pr.AddAlreadyCompiledUnit(included[i]); + pr.AddAlreadyCompiledUnit(pcu_name2); return true; } - if (RecompileList.ContainsKey(included[i])) + if (RecompileList.ContainsKey(pcu_name2)) { return true; } diff --git a/Compiler/DocXml.cs b/Compiler/DocXml.cs index 8e0d8c02d..aa6375082 100644 --- a/Compiler/DocXml.cs +++ b/Compiler/DocXml.cs @@ -28,15 +28,15 @@ namespace PascalABCCompiler XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = Encoding.UTF8; settings.Indent = true; - xtw = XmlTextWriter.Create(Path.ChangeExtension(cu.UnitName, ".xml"), settings); - unit_name = Path.GetFileNameWithoutExtension(cu.UnitName); + xtw = XmlTextWriter.Create(Path.ChangeExtension(cu.UnitFileName, ".xml"), settings); + unit_name = Path.GetFileNameWithoutExtension(cu.UnitFileName); xtw.WriteStartDocument(); xtw.WriteStartElement("doc"); if (is_assembly) { xtw.WriteStartElement("assembly"); xtw.WriteStartElement("name"); - xtw.WriteString(Path.GetFileNameWithoutExtension(cu.UnitName)); + xtw.WriteString(Path.GetFileNameWithoutExtension(cu.UnitFileName)); xtw.WriteEndElement(); xtw.WriteEndElement(); } @@ -45,7 +45,7 @@ namespace PascalABCCompiler xtw.WriteStartElement("unit"); xtw.WriteStartAttribute("name"); //xtw.WriteString((cu.SemanticTree as common_unit_node).unit_name); - xtw.WriteString(Path.GetFileNameWithoutExtension(cu.UnitName)); + xtw.WriteString(Path.GetFileNameWithoutExtension(cu.UnitFileName)); xtw.WriteEndAttribute(); xtw.WriteString(cu.SemanticTree.documentation); xtw.WriteEndElement(); diff --git a/Compiler/PCU/PCUReader.cs b/Compiler/PCU/PCUReader.cs index fcca851b7..4aa1ab2bb 100644 --- a/Compiler/PCU/PCUReader.cs +++ b/Compiler/PCU/PCUReader.cs @@ -189,14 +189,6 @@ namespace PascalABCCompiler.PCU return already_compiled[name] != null; } - public static bool ContainsUnit(string FileName, out PCUReader pr) - { - string unit_name = System.IO.Path.GetFileNameWithoutExtension(FileName); - pr = (PCUReader)units[unit_name]; - if (pr != null) return true; - return false; - } - public static void CloseUnits() { AllReadOrWritedDefinitionNodesOffsets.Clear(); @@ -226,40 +218,69 @@ namespace PascalABCCompiler.PCU ReadPCUHeader(); } - //десериализация модуля - //читается только шапка PCU и заполняются имена сущностей модуля в таблицу символов - public CompilationUnit GetCompilationUnit(string FileName, bool readDebugInfo) + public string GetFullUnitName(string UnitName) + { + + var FullUnitName = comp.FindPCUFileName(UnitName, dir, out _); + if (FullUnitName == null) throw new FileNotFound(UnitName, null); + + return FullUnitName; + } + + private PCUReader GetPCUReaderForUnitId(int id) + { + if (id == -1) return this; + string s = GetFullUnitName(pcu_file.incl_modules[id]); + var pr = (PCUReader)units[s]; + if (pr == null) + { + pr = new PCUReader(this); + pr.GetCompilationUnit(s, this.readDebugInfo); + } + return pr; + } + + //десериализация модуля + //читается только шапка PCU и заполняются имена сущностей модуля в таблицу символов + public CompilationUnit GetCompilationUnit(string FileName, bool readDebugInfo) { try { + // Compiler.CombinePath всегда должно быть применено к имени файла, перед тем как кидать его сюда + if (!Path.IsPathRooted(FileName)) throw new InvalidOperationException(); + + FileName = GetFullUnitName(FileName); + dir = Path.GetDirectoryName(FileName); + this.FileName = FileName; this.readDebugInfo = readDebugInfo; unit_name = System.IO.Path.GetFileNameWithoutExtension(FileName); - PCUReader pr = (PCUReader)units[unit_name]; + PCUReader pr = (PCUReader)units[FileName]; if (pr != null) return pr.unit; if (!File.Exists(FileName)) return null; - dir = System.IO.Path.GetDirectoryName(FileName); //fs = new FileStream(FileName, FileMode.Open, FileAccess.Read); ms = new MemoryStream(File.ReadAllBytes(FileName)); br = new BinaryReader(ms); ReadPCUHeader(); - units[unit_name] = this; - if (NeedRecompiled()) - { - CloseUnit(); - need = true; - return null; // return comp.RecompileUnit(unit_name); - } + units[FileName] = this; unit = new CompilationUnit(); + unit.UnitFileName = FileName; cun = new common_unit_node(); cun.compiler_directives = pcu_file.compiler_directives; unit.SemanticTree = cun; + if (NeedRecompiled()) + { + CloseUnit(); + this.unit = null; + need = true; + return null; // return comp.RecompileUnit(FileName); + } ChangeState(this, PCUReaderWriterState.BeginReadTree, unit); cun.scope = new WrappedUnitInterfaceScope(this); //TODO сохранить в PCU cun.scope.CaseSensitive = false; - if (string.Compare(unit_name,PascalABCCompiler.TreeConverter.compiler_string_consts.system_unit_file_name, true)==0) + if (string.Compare(unit_name, compiler_string_consts.system_unit_file_name, true)==0) PascalABCCompiler.TreeConverter.syntax_tree_visitor.init_system_module(cun); //ssyy //Создаём область видимости для implementation - части @@ -321,10 +342,10 @@ namespace PascalABCCompiler.PCU need = true; return need; }*/ - if (comp.NeedRecompiled(unit_name, Path.GetDirectoryName(FileName), pcu_file.incl_modules,this)) + if (comp.NeedRecompiled(FileName, pcu_file.incl_modules, this)) { //comp.RecompileList.Add(unit_name,unit_name); - comp.RecompileList[unit_name] = unit_name; + comp.RecompileList[FileName] = FileName; need = true; return need; } @@ -332,19 +353,24 @@ namespace PascalABCCompiler.PCU for (int i = 0; i < pcu_file.incl_modules.Length; i++) { //if (pcu_file.incl_modules[i].Contains("$")) - // continue; - string source_file_name = comp.FindSourceFileName(Path.Combine(dir, pcu_file.incl_modules[i])); - if (source_file_name != null && comp.UnitTable[source_file_name] != null) - return true; - PCUReader pr = (PCUReader)units[pcu_file.incl_modules[i]]; + // continue; + var used_unit_fname = comp.GetUnitFileName(Path.GetFileNameWithoutExtension(pcu_file.incl_modules[i]), pcu_file.incl_modules[i], dir, new SyntaxTree.SourceContext(0,0,0,0, FileName)); + if (Path.GetExtension(used_unit_fname) != comp.CompilerOptions.CompiledUnitExtension) return true; + + PCUReader pr = (PCUReader)units[used_unit_fname]; if (pr == null) pr = new PCUReader(this); pr.AddAlreadyCompiledUnit(FileName); - if (used_units[pcu_file.incl_modules[i]] == null) + if (used_units[used_unit_fname] == null) { - used_units[pcu_file.incl_modules[i]] = used_units; - if (already_compiled[pcu_file.incl_modules[i]] == null) - pr.GetCompilationUnit(comp.FindPCUFileName(pcu_file.incl_modules[i], source_file_name), this.readDebugInfo); + used_units[used_unit_fname] = used_units; + if (already_compiled[used_unit_fname] == null) + { + var sub_u = pr.GetCompilationUnit(used_unit_fname, this.readDebugInfo); + if (sub_u == null) return true; + this.unit.DirectInterfaceCompilationUnits.Add(sub_u.SemanticTree, sub_u); + this.unit.InterfaceUsedUnits.AddElement(sub_u.SemanticTree, pcu_file.incl_modules[i]); + } } if (need == false) need = pr.need; } @@ -414,7 +440,7 @@ namespace PascalABCCompiler.PCU private void AddNamespaces() { cun.unit_name=br.ReadString(); - + common_namespace_node cnn = new common_namespace_node(null, cun, cun.unit_name, cun.scope, ReadDebugInfo()); cun.namespaces.AddElement(cnn); @@ -585,7 +611,7 @@ namespace PascalABCCompiler.PCU pcu_file.compiler_directives = new List(); for (int i = 0; i < num_directives; i++) { - pcu_file.compiler_directives.Add(new compiler_directive(br.ReadString(),br.ReadString(),ReadDebugInfo())); + pcu_file.compiler_directives.Add(new compiler_directive(br.ReadString(),br.ReadString(),ReadDebugInfo(), this.FileName)); } ReadAllAssemblies(); int num_imp_entity = br.ReadInt32(); @@ -989,45 +1015,17 @@ namespace PascalABCCompiler.PCU } //получение импорт. типа - private type_node ReadCommonExtType() - { - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s];//вдруг этот модуль уже читается - if (pr == null)//это по моему чёс, так как все модули уже добавлены - { - pr = new PCUReader(this);//если нет, то создаем ридер - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - type_node tn = pr.GetTypeReference(br.ReadInt32()); - units[s] = pr;//добавляем в таблицу ридеров - return tn; - } - else - { - type_node tn = pr.GetTypeReference(br.ReadInt32()); - return tn; - } + private type_node ReadCommonExtType() + { + var pr = GetPCUReaderForUnitId(br.ReadInt32()); + return pr.GetTypeReference(br.ReadInt32()); } //(ssyy) Получение шаблонного класса private template_class ReadTemplateExtClass() { - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s];//вдруг этот модуль уже читается - if (pr == null)//это по моему чёс, так как все модули уже добавлены - { - pr = new PCUReader(this);//если нет, то создаем ридер - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - template_class tc = pr.GetTemplateClass(br.ReadInt32()); - units[s] = pr;//добавляем в таблицу ридеров - return tc; - } - else - { - template_class tc = pr.GetTemplateClass(br.ReadInt32()); - return tc; - } + var pr = GetPCUReaderForUnitId(br.ReadInt32()); + return pr.GetTemplateClass(br.ReadInt32()); } //получение откомпил. типа @@ -1095,68 +1093,28 @@ namespace PascalABCCompiler.PCU ext_members[offset] = ctn; br.BaseStream.Seek(tmp,SeekOrigin.Begin); return ctn; - } - - //получение импортируемой функции - private common_namespace_function_node ReadCommonExtNamespaceFunc() + } + + //получение импортируемой функции + private common_namespace_function_node ReadCommonExtNamespaceFunc() { br.ReadByte(); - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s]; - if (pr == null) - { - pr = new PCUReader(this); - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - int offset = br.ReadInt32(); - common_namespace_function_node cffn = pr.GetNamespaceFunction(offset); - return cffn; - } - else - { - common_namespace_function_node cffn = pr.GetNamespaceFunction(br.ReadInt32()); - return cffn; - } + var pr = GetPCUReaderForUnitId(br.ReadInt32()); + return pr.GetNamespaceFunction(br.ReadInt32()); } private namespace_variable ReadExtNamespaceVariable() { br.ReadByte(); - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s]; - if (pr == null) - { - pr = new PCUReader(this); - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - namespace_variable nv = pr.GetNamespaceVariable(br.ReadInt32()); - return nv; - } - else - { - namespace_variable nv = pr.GetNamespaceVariable(br.ReadInt32()); - return nv; - } + var pr = GetPCUReaderForUnitId(br.ReadInt32()); + return pr.GetNamespaceVariable(br.ReadInt32()); } private namespace_constant_definition ReadExtNamespaceConstant() { br.ReadByte(); - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s]; - if (pr == null) - { - pr = new PCUReader(this); - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - namespace_constant_definition nv = pr.GetConstantDefinition(br.ReadInt32()); - return nv; - } - else - { - namespace_constant_definition nv = pr.GetConstantDefinition(br.ReadInt32()); - return nv; - } + var pr = GetPCUReaderForUnitId(br.ReadInt32()); + return pr.GetConstantDefinition(br.ReadInt32()); } private common_namespace_event ReadCommonNamespaceExtEvent() @@ -1166,22 +1124,9 @@ namespace PascalABCCompiler.PCU int tmp = (int)br.BaseStream.Position; br.BaseStream.Seek(ext_pos + offset, SeekOrigin.Begin); br.ReadByte();//DS Changed - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s]; + var pr = GetPCUReaderForUnitId(br.ReadInt32()); br.BaseStream.Seek(tmp, SeekOrigin.Begin); - if (pr == null) - { - pr = new PCUReader(this); - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - common_namespace_event ev = pr.GetNamespaceEventNode(br.ReadInt32()); - return ev; - } - else - { - common_namespace_event ev = pr.GetNamespaceEventNode(br.ReadInt32()); - return ev; - } + return pr.GetNamespaceEventNode(br.ReadInt32()); } private common_event ReadCommonExtEvent() @@ -1191,22 +1136,9 @@ namespace PascalABCCompiler.PCU int tmp = (int)br.BaseStream.Position; br.BaseStream.Seek(ext_pos + offset, SeekOrigin.Begin); br.ReadByte();//DS Changed - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s]; + var pr = GetPCUReaderForUnitId(br.ReadInt32()); br.BaseStream.Seek(tmp, SeekOrigin.Begin); - if (pr == null) - { - pr = new PCUReader(this); - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - common_event ev = pr.GetEventNode(br.ReadInt32()); - return ev; - } - else - { - common_event ev = pr.GetEventNode(br.ReadInt32()); - return ev; - } + return pr.GetEventNode(br.ReadInt32()); } private class_field ReadCommonExtField() @@ -1216,22 +1148,9 @@ namespace PascalABCCompiler.PCU int tmp = (int)br.BaseStream.Position; br.BaseStream.Seek(ext_pos + offset, SeekOrigin.Begin); br.ReadByte();//DS Changed - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s]; + var pr = GetPCUReaderForUnitId(br.ReadInt32()); br.BaseStream.Seek(tmp, SeekOrigin.Begin); - if (pr == null) - { - pr = new PCUReader(this); - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - class_field field = pr.GetClassField(br.ReadInt32()); - return field; - } - else - { - class_field field = pr.GetClassField(br.ReadInt32()); - return field; - } + return pr.GetClassField(br.ReadInt32()); } private common_method_node ReadCommonExtMethod() @@ -1241,22 +1160,9 @@ namespace PascalABCCompiler.PCU int tmp = (int)br.BaseStream.Position; br.BaseStream.Seek(ext_pos + offset, SeekOrigin.Begin); br.ReadByte();//DS Changed - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s]; + var pr = GetPCUReaderForUnitId(br.ReadInt32()); br.BaseStream.Seek(tmp, SeekOrigin.Begin); - if (pr == null) - { - pr = new PCUReader(this); - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - common_method_node meth = pr.GetClassMethod(br.ReadInt32()); - return meth; - } - else - { - common_method_node meth = pr.GetClassMethod(br.ReadInt32()); - return meth; - } + return pr.GetClassMethod(br.ReadInt32()); } private common_property_node ReadCommonExtProperty() @@ -1266,22 +1172,9 @@ namespace PascalABCCompiler.PCU int tmp = (int)br.BaseStream.Position; br.BaseStream.Seek(ext_pos + offset, SeekOrigin.Begin); br.ReadByte();//DS Changed - int pos = br.ReadInt32(); - string s = pcu_file.incl_modules[pos]; - PCUReader pr = (PCUReader)units[s]; + var pr = GetPCUReaderForUnitId(br.ReadInt32()); br.BaseStream.Seek(tmp, SeekOrigin.Begin); - if (pr == null) - { - pr = new PCUReader(this); - CompilationUnit cu = pr.GetCompilationUnit(dir + s + comp.CompilerOptions.CompiledUnitExtension, this.readDebugInfo); - common_property_node prop = pr.GetPropertyNode(br.ReadInt32()); - return prop; - } - else - { - common_property_node prop = pr.GetPropertyNode(br.ReadInt32()); - return prop; - } + return pr.GetPropertyNode(br.ReadInt32()); } //получение типа, описанного в этом модуле (может вызываться извне) @@ -2524,7 +2417,7 @@ namespace PascalABCCompiler.PCU //Добавляем подключенные модули for (int i = 0; i < uses_count; i++) { - PCUReader pcu_r = units[pcu_file.incl_modules[i]] as PCUReader; + PCUReader pcu_r = units[GetFullUnitName(pcu_file.incl_modules[i])] as PCUReader; if (pcu_r != null) { top_scopes.Add(pcu_r.cun.scope); diff --git a/Compiler/PCU/PCUWriter.cs b/Compiler/PCU/PCUWriter.cs index 1dc21a210..aa6dced50 100644 --- a/Compiler/PCU/PCUWriter.cs +++ b/Compiler/PCU/PCUWriter.cs @@ -8,7 +8,8 @@ using TreeConverter; using PascalABCCompiler.TreeConverter; using PascalABCCompiler.TreeRealization; using System.Collections.Generic; - +using System.Linq; + namespace PascalABCCompiler.PCU { public class PCUConsts @@ -213,7 +214,7 @@ namespace PascalABCCompiler.PCU private List ref_assemblies = new List();//список подключаемых сборок, заполняется в процессе private Dictionary assm_refs = new Dictionary();//таблица для привязывания сборки private Dictionary func_codes = new Dictionary();//таблица, хранящая смещения тел методов в PCU - private Dictionary used_units = new Dictionary(); + private Dictionary used_units = new Dictionary(); private Dictionary ext_members = new Dictionary();//таблица, привязывающая импорт. сущность с записью в списке имп. сущ-тей private common_namespace_node cur_cnn;//текущее пространство имен private bool is_interface = true;//переводим ли интерфейсную часть @@ -876,12 +877,15 @@ namespace PascalABCCompiler.PCU if (tn is common_type_node) { common_namespace_node comp_cnn = (tn as common_type_node).comprehensive_namespace; - if (comp_cnn != null && !ns_dict.ContainsKey(comp_cnn)) + if (comp_cnn != null && !ns_dict.ContainsKey(comp_cnn) && unit.SemanticTree != comp_cnn.cont_unit) { + var path = Compiler.GetUnitPath(unit, compiler.UnitsSortedList.Find(u => u.SemanticTree == comp_cnn.cont_unit)); + if (interf) - unit.InterfaceUsedUnits.AddElement(comp_cnn.cont_unit); + unit.InterfaceUsedUnits.AddElement(comp_cnn.cont_unit, path); else - unit.ImplementationUsedUnits.AddElement(comp_cnn.cont_unit); + unit.ImplementationUsedUnits.AddElement(comp_cnn.cont_unit, path); + ns_dict[comp_cnn] = true; } if (tn.base_type is common_type_node) @@ -1034,79 +1038,52 @@ namespace PascalABCCompiler.PCU //заполнение списка подключаемых модулей private void GetUsedUnits() { - int num = 0; - common_unit_node unt = null; AddIndirectInteraceUsedUnits(); - AddIndirectImplementationUsedUnits(); - for (int j = 0; j < unit.InterfaceUsedUnits.Count; j++) + AddIndirectImplementationUsedUnits(); + + var c1 = unit.InterfaceUsedUnits.unit_uses_paths.Count; + var c2 = unit.ImplementationUsedUnits.unit_uses_paths.Count; + pcu_file.interface_uses_count = c1; + + var incl_modules = new List(c1 + c2); + foreach (var used_unit in unit.InterfaceUsedUnits.OfType()) { - unt = unit.InterfaceUsedUnits[j] as common_unit_node; - if (unt == null) continue; - if (unt.namespaces.Count != 0) - num += 1;//unt.namespaces.Count; + // Каждый модуль, зачем то, подключён сам к себе + // Конечно, записи в unit_uses_paths для такого подключения - нет + if (unit.SemanticTree == used_unit) continue; + + // AddIndirectInteraceUsedUnits может добавлять один и тот же модуль несколько раз + if (used_units.ContainsKey(used_unit)) continue; + + // раньше вместо пути модуля - брало имя его первого пространства имён + // и сразу стояла эта проверка. Если будет тут вылетать - наверное надо заменить throw на continue + if (used_unit.namespaces.Count == 0) throw new InvalidOperationException(); + + this.used_units.Add(used_unit, used_units.Count); + incl_modules.Add(unit.InterfaceUsedUnits.unit_uses_paths[used_unit]); + } - for (int j = 0; j < unit.ImplementationUsedUnits.Count; j++) - { - unt = unit.ImplementationUsedUnits[j] as common_unit_node; - if (unt == null) continue; - if (unt.namespaces.Count != 0) - num += 1;//unt.namespaces.Count; + foreach (var used_unit in unit.ImplementationUsedUnits.OfType()) + { + if (unit.SemanticTree == used_unit) continue; + if (used_units.ContainsKey(used_unit)) continue; + if (used_unit.namespaces.Count == 0) throw new InvalidOperationException(); + + this.used_units.Add(used_unit, used_units.Count); + incl_modules.Add(unit.ImplementationUsedUnits.unit_uses_paths[used_unit]); + } - - pcu_file.incl_modules = new string[num]; - int i = 0; num = 0; - for (i=0; i 1) - { - pcu_file.incl_modules[num] = unt.namespaces[1].namespace_name; - used_units[unt.namespaces[1]] = num; - num++; - }*/ - } - } - //(ssyy) Запомнили, какие модули относятся к секции interface - pcu_file.interface_uses_count = num; + used_units.Add(unit.SemanticTree as common_unit_node, -1); - for (int j=0; j 1) - { - pcu_file.incl_modules[num] = unt.namespaces[1].namespace_name; - used_units[unt.namespaces[1]] = num; - num++; - }*/ - } - } - - - pcu_file.used_namespaces = cun.used_namespaces.ToArray(); + pcu_file.incl_modules = incl_modules.ToArray(); + pcu_file.used_namespaces = cun.used_namespaces.ToArray(); } //получения индекса модуля в списке подключ. модулей private int GetUnitToken(common_namespace_node ns) { - int tok = 0; - if (!used_units.TryGetValue(ns,out tok)) - { - return used_units[(ns.cont_unit as common_unit_node).namespaces[0]]; - } - return tok; + return used_units[ns.cont_unit as common_unit_node]; } private int GetTokenForNetEntity(FieldInfo val) @@ -1728,7 +1705,7 @@ namespace PascalABCCompiler.PCU is_def = 1; return off;//возвращаем его смещение } - if (!used_units.ContainsKey(nv.namespace_node)) + if (!used_units.ContainsKey(nv.namespace_node.cont_unit as common_unit_node)) { is_def = 1; return -1; @@ -1758,7 +1735,7 @@ namespace PascalABCCompiler.PCU is_def = 1; return off;//возвращаем его смещение } - if (!used_units.ContainsKey(nv.comprehensive_namespace)) + if (!used_units.ContainsKey(nv.comprehensive_namespace.cont_unit as common_unit_node)) { is_def = 1; return -1; diff --git a/SyntaxTree/tree/Tree.cs b/SyntaxTree/tree/Tree.cs index f7381b23b..eddba80b2 100644 --- a/SyntaxTree/tree/Tree.cs +++ b/SyntaxTree/tree/Tree.cs @@ -11288,6 +11288,9 @@ namespace PascalABCCompiler.SyntaxTree } } + // имя модуля в случае обычного uses + // или путь к модулю в случае uses-in + public virtual string UsesPath() => name.idents[0].name; /// Создает копию узла public override syntax_tree_node Clone() @@ -11456,9 +11459,10 @@ namespace PascalABCCompiler.SyntaxTree if (_in_file != null) _in_file.Parent = this; } - } - - + } + + public override string UsesPath() => in_file.Value; + /// Создает копию узла public override syntax_tree_node Clone() { diff --git a/TestSuite/usesunits/UsesInUnits/2/u2.pas b/TestSuite/usesunits/UsesInUnits/2/u2.pas index e8f55c863..1487a1530 100644 --- a/TestSuite/usesunits/UsesInUnits/2/u2.pas +++ b/TestSuite/usesunits/UsesInUnits/2/u2.pas @@ -1,3 +1,5 @@ unit u2; +{$savepcu false} + end. \ No newline at end of file diff --git a/TestSuite/usesunits/UsesInUnits/u1.pas b/TestSuite/usesunits/UsesInUnits/u1.pas index 896fafca5..c1d13cc2f 100644 --- a/TestSuite/usesunits/UsesInUnits/u1.pas +++ b/TestSuite/usesunits/UsesInUnits/u1.pas @@ -1,7 +1,10 @@ unit u1; +{$savepcu false} + uses u2 in '2\u2.pas'; uses u3; +uses u4; {$include test.h} diff --git a/TestSuite/usesunits/UsesInUnits/u3.pas b/TestSuite/usesunits/UsesInUnits/u3.pas index d387f9d4b..7d877f394 100644 --- a/TestSuite/usesunits/UsesInUnits/u3.pas +++ b/TestSuite/usesunits/UsesInUnits/u3.pas @@ -1,3 +1,5 @@ unit u3; +{$savepcu false} + end. \ No newline at end of file diff --git a/TestSuite/usesunits/UsesInUnits/u4.pas b/TestSuite/usesunits/UsesInUnits/u4.pas index cb2311002..7ff769506 100644 --- a/TestSuite/usesunits/UsesInUnits/u4.pas +++ b/TestSuite/usesunits/UsesInUnits/u4.pas @@ -1,5 +1,7 @@ unit u4; +{$savepcu false} + {$include test.h} begin diff --git a/TestSuite/usesunits/UsesInUnits2/u0.pas b/TestSuite/usesunits/UsesInUnits2/u0.pas index 4374c4442..3d2b76bc9 100644 --- a/TestSuite/usesunits/UsesInUnits2/u0.pas +++ b/TestSuite/usesunits/UsesInUnits2/u0.pas @@ -1,5 +1,7 @@ unit u0; +{$savepcu false} + uses u1; uses u2 in '..\UsesInUnits2_F2\u2.pas'; diff --git a/TestSuite/usesunits/UsesInUnits2/u1.pas b/TestSuite/usesunits/UsesInUnits2/u1.pas index 91c7e1fa5..5c83f42c7 100644 --- a/TestSuite/usesunits/UsesInUnits2/u1.pas +++ b/TestSuite/usesunits/UsesInUnits2/u1.pas @@ -1,3 +1,5 @@ unit u1; +{$savepcu false} + end. \ No newline at end of file diff --git a/TestSuite/usesunits/UsesInUnits2_F2/u2.pas b/TestSuite/usesunits/UsesInUnits2_F2/u2.pas index e8f55c863..1487a1530 100644 --- a/TestSuite/usesunits/UsesInUnits2_F2/u2.pas +++ b/TestSuite/usesunits/UsesInUnits2_F2/u2.pas @@ -1,3 +1,5 @@ unit u2; +{$savepcu false} + end. \ No newline at end of file diff --git a/TestSuite/usesunits/UsesInUnits3/1.txt b/TestSuite/usesunits/UsesInUnits3/1.txt new file mode 100644 index 000000000..f2ba8f84a --- /dev/null +++ b/TestSuite/usesunits/UsesInUnits3/1.txt @@ -0,0 +1 @@ +abc \ No newline at end of file diff --git a/TestSuite/usesunits/UsesInUnits3/u.pas b/TestSuite/usesunits/UsesInUnits3/u.pas new file mode 100644 index 000000000..be8da2841 --- /dev/null +++ b/TestSuite/usesunits/UsesInUnits3/u.pas @@ -0,0 +1,10 @@ +unit u; + +{$savepcu false} + +{$resource '1.txt'} +{$reference 'uui3_lib.dll'} + +begin + Assert('abc' = System.IO.StreamReader.Create(GetResourceStream('1.txt')).ReadToEnd); +end. \ No newline at end of file diff --git a/TestSuite/usesunits/UsesInUnits3/uui3_lib.dll b/TestSuite/usesunits/UsesInUnits3/uui3_lib.dll new file mode 100644 index 000000000..c2f6bbe8f Binary files /dev/null and b/TestSuite/usesunits/UsesInUnits3/uui3_lib.dll differ diff --git a/TestSuite/usesunits/UsesInUnits3/uui3_lib.pas b/TestSuite/usesunits/UsesInUnits3/uui3_lib.pas new file mode 100644 index 000000000..1a579a5cc --- /dev/null +++ b/TestSuite/usesunits/UsesInUnits3/uui3_lib.pas @@ -0,0 +1,3 @@ +library uui3_lib; + +end. \ No newline at end of file diff --git a/TestSuite/usesunits/UsesInUnits4/u2.pas b/TestSuite/usesunits/UsesInUnits4/u2.pas new file mode 100644 index 000000000..c206b9ccd --- /dev/null +++ b/TestSuite/usesunits/UsesInUnits4/u2.pas @@ -0,0 +1,12 @@ +unit u2; +{$savepcu false} + +interface + + + +implementation + +uses uses_in4_cycle_uses in '..\uses_in4_cycle_uses'; + +end. \ No newline at end of file diff --git a/TestSuite/usesunits/uses_in1.pas b/TestSuite/usesunits/uses_in1.pas new file mode 100644 index 000000000..8e3cd8270 --- /dev/null +++ b/TestSuite/usesunits/uses_in1.pas @@ -0,0 +1,3 @@ +uses u1 in 'UsesInUnits\u1.pas'; + +begin end. \ No newline at end of file diff --git a/TestSuite/usesunits/uses_in2.pas b/TestSuite/usesunits/uses_in2.pas new file mode 100644 index 000000000..3c9b0f331 --- /dev/null +++ b/TestSuite/usesunits/uses_in2.pas @@ -0,0 +1,3 @@ +uses u0 in 'UsesInUnits2\u0.pas'; + +begin end. \ No newline at end of file diff --git a/TestSuite/usesunits/uses_in3_derectives.pas b/TestSuite/usesunits/uses_in3_derectives.pas new file mode 100644 index 000000000..42bc7f13b --- /dev/null +++ b/TestSuite/usesunits/uses_in3_derectives.pas @@ -0,0 +1,3 @@ +uses u in 'UsesInUnits3\u'; + +begin end. \ No newline at end of file diff --git a/TestSuite/usesunits/uses_in4_cycle_uses.pas b/TestSuite/usesunits/uses_in4_cycle_uses.pas new file mode 100644 index 000000000..68685ae2d --- /dev/null +++ b/TestSuite/usesunits/uses_in4_cycle_uses.pas @@ -0,0 +1,12 @@ +unit uses_in4_cycle_uses; +{$savepcu false} + +interface + +uses u2 in 'UsesInUnits4\u2'; + +implementation + + + +end. \ No newline at end of file diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index fd661c03b..8c4c0a9eb 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -10926,7 +10926,7 @@ namespace PascalABCCompiler.TreeConverter System.Collections.Generic.List list = new System.Collections.Generic.List(); foreach (SyntaxTree.compiler_directive sncd in cu.compiler_directives) { - list.Add(new compiler_directive(sncd.Name.text, sncd.Directive!=null?sncd.Directive.text:"", get_location(sncd))); + list.Add(new compiler_directive(sncd.Name.text, sncd.Directive!=null?sncd.Directive.text:"", get_location(sncd), cu.file_name)); } return list; } diff --git a/TreeConverter/TreeRealization/Collections.cs b/TreeConverter/TreeRealization/Collections.cs index f59ffb63f..b815c3d8c 100644 --- a/TreeConverter/TreeRealization/Collections.cs +++ b/TreeConverter/TreeRealization/Collections.cs @@ -1,9 +1,9 @@ // Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; - -using PascalABCCompiler.Collections; - +using System.Collections.Generic; +using PascalABCCompiler.Collections; + namespace PascalABCCompiler.TreeRealization { /// @@ -104,7 +104,28 @@ namespace PascalABCCompiler.TreeRealization /// [Serializable] public class unit_node_list : extended_collection - { + { + public Dictionary unit_uses_paths = new Dictionary(); + + public new void AddElement(unit_node unit) + { + throw new InvalidOperationException("Use second overload of \"unit_node_list.AddElement\""); + } + + /// + /// Adds element to the "uses" list + /// + /// Element to add. Can be unit, namespace, .dll reference, etc. + /// Path to unit. Can be relative string, null for non-pascal_unit's + /// Returns true if new pascal unit (not .dll, namespace, etc.) was added + public bool AddElement(unit_node unit, string unit_uses_path) + { + if (unit_uses_paths.ContainsKey(unit)) return false; + base.AddElement(unit); + if (unit_uses_path != null) unit_uses_paths.Add(unit, unit_uses_path); + return true; + } + } /// diff --git a/TreeConverter/TreeRealization/CompilerDirective.cs b/TreeConverter/TreeRealization/CompilerDirective.cs index ed386b47f..d8c2c1bf1 100644 --- a/TreeConverter/TreeRealization/CompilerDirective.cs +++ b/TreeConverter/TreeRealization/CompilerDirective.cs @@ -10,12 +10,15 @@ namespace PascalABCCompiler.TreeRealization { public string name; public string directive; - public location location; - public compiler_directive(string name,string directive,location loc) + public location location; + public string source_file; // Файл из которого загрузили директиву. В отличии от location - может указывать на .pcu + + public compiler_directive(string name, string directive, location loc, string source_file) { this.name = name; this.directive = directive; this.location = loc; + this.source_file = source_file; } } } \ No newline at end of file diff --git a/TreeConverter/TreeRealization/units.cs b/TreeConverter/TreeRealization/units.cs index 4b6fca387..b4db08a77 100644 --- a/TreeConverter/TreeRealization/units.cs +++ b/TreeConverter/TreeRealization/units.cs @@ -89,7 +89,7 @@ namespace PascalABCCompiler.TreeRealization } [Serializable] - public class common_unit_node : unit_node + public sealed class common_unit_node : unit_node { private readonly common_namespace_node_list _namespaces = new common_namespace_node_list(); @@ -100,7 +100,7 @@ namespace PascalABCCompiler.TreeRealization private common_namespace_function_node _main_function; private common_namespace_function_node _finalization_method; - private string _unit_name; + public string unit_name { get; set; } internal common_parameter MainArgsParameter = null; internal expression_node MainArgsAssignExpr = null; @@ -154,7 +154,7 @@ namespace PascalABCCompiler.TreeRealization public common_unit_node(string name) { - _unit_name = name; + this.unit_name = name; } public void add_unit_name_to_namespace() @@ -162,18 +162,6 @@ namespace PascalABCCompiler.TreeRealization this.scope.AddSymbol(unit_name, new TreeConverter.SymbolInfo(this)); } - public string unit_name - { - get - { - return _unit_name; - } - set - { - _unit_name = value; - } - } - public common_namespace_function_node main_function { get diff --git a/bin/Lng/Eng/CompilerErrors.dat b/bin/Lng/Eng/CompilerErrors.dat index ad5a5bbbc..cde250d65 100644 --- a/bin/Lng/Eng/CompilerErrors.dat +++ b/bin/Lng/Eng/CompilerErrors.dat @@ -18,6 +18,7 @@ FILE_{0}_NOT_FOUND=File '{0}' not found NAMESPACE_CAN_BE_COMPILED_ONLY_IN_PROJECTS=Files with namespaces can be compiled only inside projects NAMESPACE_CANNOT_HAVE_IN_SECTION=Namespace cannot have 'in' section APPTYPE_DLL_IS_ALLOWED_ONLY_FOR_LIBRARIES= {$apptype dll} directive is allowed only for libraries +USES_IN_WRONG_NAME=Unit name in uses-in ({0}) must be same as file name ({1}) %PREFIX%= COMPILER_INTERNAL_ERROR_IN_UNIT_{0}_:{1}=Internal compiler error in module {0} :'{1}' \ No newline at end of file diff --git a/bin/Lng/Rus/CompilerErrors.dat b/bin/Lng/Rus/CompilerErrors.dat index b62ae7ed4..0ab6b9458 100644 --- a/bin/Lng/Rus/CompilerErrors.dat +++ b/bin/Lng/Rus/CompilerErrors.dat @@ -18,6 +18,7 @@ NAMESPACE_CAN_BE_COMPILED_ONLY_IN_PROJECTS=Компиляция файлов с FILE_{0}_NOT_FOUND=Файл '{0}' не найден NAMESPACE_CANNOT_HAVE_IN_SECTION=Для пространства имен не может указываться секция in APPTYPE_DLL_IS_ALLOWED_ONLY_FOR_LIBRARIES=Директива {$apptype dll} возможна только для библиотек +USES_IN_WRONG_NAME=Имя модуля в uses-in ({0}) должно совпадать с именем файла ({1}) %PREFIX%= COMPILER_INTERNAL_ERROR_IN_UNIT_{0}_:{1}=Внутренняя ошибка компилятора в модуле {0} :'{1}' \ No newline at end of file diff --git a/bin/Lng/Ukr/CompilerErrors.dat b/bin/Lng/Ukr/CompilerErrors.dat index 2fbf70d9e..44b41dfda 100644 --- a/bin/Lng/Ukr/CompilerErrors.dat +++ b/bin/Lng/Ukr/CompilerErrors.dat @@ -16,6 +16,7 @@ MAINRESOURCE_NOT_ALLOWED=Неприпустимо сумісне викорис DUPLICATE_DIRECTIVE{0}=Повторное объявление директивы {0} FILE_{0}_NOT_FOUND=Файл '{0}' не знайдено NAMESPACE_CAN_BE_COMPILED_ONLY_IN_PROJECTS=Компиляция файлов с пространствами имен допустима только в проектах +USES_IN_WRONG_NAME=Ім'я модуля в uses-in ({0}) має збігатися з ім'ям файлу ({1}) %PREFIX%= COMPILER_INTERNAL_ERROR_IN_UNIT_{0}_:{1}=Внутрішня помилка компілятора в модулі {0} :'{1}' \ No newline at end of file