// 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) /*************************************************************************** * * Управляющий блок компилятора, алгоритм компиляции модулей * Зависит от Errors,SyntaxTree,SemanticTree,Parsers,TreeConvertor, * CodeGenerators * ***************************************************************************/ #region algorithm /*************************************************************************** * Рекурсивный алгоритм компиляции модулей * версия 1.4 * * CompileUnit(ИмяФайла) * 1.CompileUnit(new СписокМодулей,ИмяФайла) * 2.Докомпилировать модули из СписокОтложенойКомпиляции; * * CompileUnit(СписокМодулей,ИмяФайла) * 1.ТекущийМодуль=ТаблицаМодулей[ИмяФайла]; * Если (ТекущийМодуль!=0) то * Если (ТекущийМодуль.Состояние==BeginCompilation) * СписокМодулей.Добавить(ТекущийМодуль); * Выход; * иначе перейти к пункту 5 * * 2.Если ЭтоФайлDLL(ИмяФайла) то * Если ((ТекущийМодуль=СчитатьDLL(ИмяФайла))!=0) то * СписокМодулей.Добавить(ТекущийМодуль); * ТаблицаМодулей.Добавить(ТекущийМодуль); * Выход; * иначе * Ошибка("Не могу подключить сборку"); * Выход; * * 3.Если ЭтоФайлPCU(ИмяФайла) то * Если ((ТекущийМодуль=СчитатьPCU(ИмяФайла))!=0) то * СписокМодулей.Добавить(ТекущийМодуль); * ТаблицаМодулей.Добавить(ТекущийМодуль); * Выход; * иначе * иначе перейти к пункту 4; * * 4.ТекущийМодуль=новыйМодуль(); * ТекущийМодуль.СинтаксическоеДерево=Парасеры.Парсить(ИмяФайла,ТекущийМодуль.СписокОшибок); * Если (ТекущийМодуль.СинтаксическоеДерево==0) то * Если (ТекущийМодуль.СписокОшибок.Количество==0) то * Ошибка("Модуль не неайден"); * иначе * Ошибка(ТекущийМодуль.СписокОшибок[0]); * ТаблицаМодулей[ИмяФайла]=ТекущийМодуль; * ТекущийМодуль.Состояние=BeginCompilation; * * 5.СинтаксическийСписокМодулей=ТекущийМодуль.СинтаксическоеДерево.Interface.usesList; * Для(i=СинтаксическийСписокМодулей.Количество-1-ТекущийМодуль.КомпилированыеВInterface.Количество;i>=0;i--) * ТекушийМодуль.ТекущийUsesМодуль=СинтаксическийСписокМодулей[i].ИмяФайла; * ИмяUsesФайла=СинтаксическийСписокМодулей[i].ИмяФайла; * Если (ТаблицаМодулей[ИмяUsesФайла]!=0) * Если (ТаблицаМодулей[ИмяUsesФайла].Состояние==BeginCompilation) * Если (ТаблицаМодулей[ТаблицаМодулей[ИмяUsesФайла].ТекущийUsesМодуль].Состояние=BeginCompilation) * Ошибка("Циклическая связь модулей"); * CompileUnit(ТекущийМодуль.КомпилированыеВInterface,ИмяUsesФайла); * Если (ТекушийМодуль.Состояние==Compiled) то * СписокМодулей.Добавить(ТекушийМодуль); * Выход; * * 6.ТекущийМодуль.СемантическоеДерево=КонверторДерева.КонвертироватьInterfaceЧасть( * ТекущийМодуль.СинтаксическоеДерево, * ТекущийМодуль.КомпилированыеВInterface, * ТекущийМодуль.СписокОшибок); * СписокМодулей.Добавить(ТекущийМодуль); * СинтаксическийСписокМодулей=ТекущийМодуль.СинтаксическоеДерево.Implementation.usesList; * Для(i=СинтаксическийСписокМодулей.Количество-1;i>=0;i--) * Если (ТаблицаМодулей[СинтаксическийСписокМодулей[i].ИмяФайла].Состояние=BeginCompilation) * СписокОтложенойКомпиляции.Добавить(ТаблицаМодулей[СинтаксическийСписокМодулей[i].ИмяФайла]); * иначе * CompileUnit(ТекущийМодуль.КомпилированыеВImplementation,СинтаксическийСписокМодулей[i].ИмяФайла); * Если(ДобавлялиХотябыОдинВСписокОтложенойКомпиляции) * СписокОтложенойКомпиляции.Добавить(ТекущийМодуль); * выход; * иначе * КонверторДерева.КонвертироватьImplementationЧасть( * ТекущийМодуль.СинтаксическоеДерево, * ТекущийМодуль.СемантическоеДерево, * ТекущийМодуль.КомпилированыеВImplementation * ТекущийМодуль.СписокОшибок); * ТекущийМодуль.Состояние=Compiled; * СохранитьPCU(ТекущийМодуль); * * * * [краткая верcия алгоритма компиляции модулей] * CompileUnit(ИмяФайла) * 1.CompileUnit(new СписокМодулей,ИмяФайла) * 2.Докомпилировать модули из СписокОтложенойКомпиляции; * * CompileUnit(СписокМодулей,ИмяФайла); * 1.Если у этого модуля откомпилирован хотябы интерфейс то * добавить его в СписокМодулей * выход * 2.Если это DLL то * считать * добавить его в СписокМодулей * выход * 3.Если это PCU то * считать * добавить его в СписокМодулей * выход * 4.создать новый компилируемыйМодуль * РаспарситьТекст(ИмяФайла) * Состояние компилируемогоМодуля установить на BeginCompilation * 5.Для всех модулей из Interface части компилируемогоМодуля справа налево * Если мы уже начаинали компилировать этот модуль * Если состояние модуля BeginCompilation * Если состояние последнего компилируемого им модуля BeginCompilation * ошибка("Циклическая связь модулей") * выход * CompileUnit(Список из Interface части компилируемогоМодуля,модуль.имя) * Если компилируемыйМодуль.Состояние Compiled то * добавить его в СписокМодулей * выход * 6.Откомпилировать Interface часть компилируемогоМодуля * Для всех модулей из Implementation части компилируемогоМодуля справа налево * Если состояние очередного модуля BeginCompilation то * добавить его в список отложеной компиляции; * иначе * CompileUnit(Список из Implementation части компилируемогоМодуля,модуль.имя) * Если Добавляли Хотябы Один В Список Отложеной Компиляции то * добавить компилируемыйМодуль в список отложеной компиляции * выход * Откомпилировать Implementation часть компилируемогоМодуля * Состояние компилируемогоМодуля установить на Compiled * добавить его в СписокМодулей * Сохранить компилируемыйМодуль в виде PCU файла на диск * * * ***************************************************************************/ #endregion #define DEBUG using ICSharpCode.NRefactory; using Microsoft.Scripting; using Microsoft.Scripting.Hosting; using PascalABCCompiler.Errors; using PascalABCCompiler.PCU; using PascalABCCompiler.SemanticTreeConverters; using PascalABCCompiler.SyntaxTreeConverters; using PascalABCCompiler.TreeRealization; using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; namespace PascalABCCompiler { public class CompilerCompilationError : LocatedError { public CompilerCompilationError(string message) : base(message) { } public CompilerCompilationError(string message, string FileName) : base(message, FileName) { } public override string ToString() { return Message; } } public class ReadPCUError : CompilerCompilationError { public ReadPCUError(string FileName) : base(string.Format(StringResources.Get("COMPILATIONERROR_READ_PCU{0}_ERROR"), FileName)) { } } public class NamespaceCannotHaveInSection : CompilerCompilationError { public NamespaceCannotHaveInSection(SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_NAMESPACE_CANNOT_HAVE_IN_SECTION"))) { this.source_context = sc; } } public class ProgramModuleExpected : CompilerCompilationError { public ProgramModuleExpected(string FileName, SyntaxTree.SourceContext sc) : base(StringResources.Get("COMPILATIONERROR_PROGRAM_MODULE_EXPECTED"), FileName) { this.source_context = sc; } } public class UnitModuleExpected : CompilerCompilationError { public UnitModuleExpected(string FileName, SyntaxTree.SourceContext sc) : base(StringResources.Get("COMPILATIONERROR_UNIT_MODULE_EXPECTED"), FileName) { this.source_context = sc; } } public class AppTypeDllIsAllowedOnlyForLibraries : CompilerCompilationError { public AppTypeDllIsAllowedOnlyForLibraries(string FileName, SyntaxTree.SourceContext sc) : base(StringResources.Get("COMPILATIONERROR_APPTYPE_DLL_IS_ALLOWED_ONLY_FOR_LIBRARIES"), FileName) { this.source_context = sc; } } public class UnitModuleExpectedLibraryFound : CompilerCompilationError { public UnitModuleExpectedLibraryFound(string FileName, SyntaxTree.SourceContext sc) : base(StringResources.Get("COMPILATIONERROR_UNIT_MODULE_EXPECTED_LIBRARY_FOUND"), FileName) { this.source_context = sc; } } public class AssemblyNotFound : CompilerCompilationError { public string AssemblyFileName; public AssemblyNotFound(string FileName, string AssemblyFileName, SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_ASSEMBLY_{0}_NOT_FOUND"), AssemblyFileName), FileName) { this.AssemblyFileName = AssemblyFileName; this.source_context = sc; } } public class AssemblyReadingError : CompilerCompilationError { public string AssemblyFileName; public AssemblyReadingError(string FileName, string AssemblyFileName, SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_ASSEMBLY_{0}_READING_ERROR"), AssemblyFileName), FileName) { this.AssemblyFileName = AssemblyFileName; this.source_context = sc; } } public class InvalidAssemblyPathError : CompilerCompilationError { public InvalidAssemblyPathError(string FileName, SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_INVALID_ASSEMBLY_PATH")), FileName) { this.source_context = sc; } } public class InvalidPathError : CompilerCompilationError { public InvalidPathError(SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_INVALID_PATH"))) { this.source_context = sc; this.fileName = sc.FileName; } } public class ResourceFileNotFound : CompilerCompilationError { public ResourceFileNotFound(string ResFileName, TreeRealization.location sl) : base(string.Format(StringResources.Get("COMPILATIONERROR_RESOURCEFILE_{0}_NOT_FOUND"), ResFileName), sl.doc.file_name) { this.sourceLocation = new SourceLocation(sl.doc.file_name, sl.begin_line_num, sl.begin_column_num, sl.end_line_num, sl.end_column_num); } public ResourceFileNotFound(string ResFileName) : base(string.Format(StringResources.Get("COMPILATIONERROR_RESOURCEFILE_{0}_NOT_FOUND"), ResFileName), null) { //this.sourceLocation = new SourceLocation(sl.doc.file_name, sl.begin_line_num, sl.begin_column_num, sl.end_line_num, sl.end_column_num); } } public class IncludeNamespaceInUnitError : CompilerCompilationError { public IncludeNamespaceInUnitError(string FileName, SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_INCLUDE_NAMESPACE_IN_UNIT")), FileName) { this.source_context = sc; } } public class NamespaceModuleExpected : CompilerCompilationError { public NamespaceModuleExpected(SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_NAMESPACE_MODULE_EXPECTED"))) { this.source_context = sc; } } public class MainResourceNotAllowed : CompilerCompilationError { public MainResourceNotAllowed(TreeRealization.location sl) : base(string.Format(StringResources.Get("COMPILATIONERROR_MAINRESOURCE_NOT_ALLOWED")), sl.doc.file_name) { this.sourceLocation = new SourceLocation(sl.doc.file_name, sl.begin_line_num, sl.begin_column_num, sl.end_line_num, sl.end_column_num); } } public class DuplicateUsesUnit : CompilerCompilationError { public string UnitName; public DuplicateUsesUnit(string FileName, string UnitName, SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_DUPLICATE_USES_UNIT{0}"), UnitName), FileName) { this.UnitName = UnitName; this.source_context = sc; } } public class DuplicateDirective : CompilerCompilationError { public string DirectiveName; public DuplicateDirective(string FileName, string DirectiveName, SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_DUPLICATE_DIRECTIVE{0}"), DirectiveName), FileName) { this.DirectiveName = DirectiveName; this.source_context = sc; } } public class NamespacesCanBeCompiledOnlyInProjects : CompilerCompilationError { public NamespacesCanBeCompiledOnlyInProjects(SyntaxTree.SourceContext sc) : base(StringResources.Get("COMPILATIONERROR_NAMESPACE_CAN_BE_COMPILED_ONLY_IN_PROJECTS")) { this.source_context = sc; } } public class UnitNotFound : CompilerCompilationError { public string UnitName; public UnitNotFound(string FileName, string UnitName, SyntaxTree.SourceContext sc) : base(string.Format(StringResources.Get("COMPILATIONERROR_UNIT_{0}_NOT_FOUND"), UnitName), FileName) { this.UnitName = UnitName; this.source_context = sc; } } 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) : base(string.Format(StringResources.Get("COMPILATIONERROR_SOURCE_FILE_{0}_NOT_FOUND"), FileName)) { } } public class UnauthorizedAccessToFile : CompilerCompilationError { public UnauthorizedAccessToFile(string FileName) : base(string.Format(StringResources.Get("COMPILATIONERROR_NO_ACCESS_TO_FILE{0}"), FileName)) { } } public class CycleUnitReference : CompilerCompilationError { public SyntaxTree.unit_or_namespace SyntaxUsesUnit; public CycleUnitReference(string FileName, SyntaxTree.unit_or_namespace SyntaxUsesUnit) : base(string.Format(StringResources.Get("COMPILATIONERROR_CYCLIC_UNIT_REFERENCE_WITH_UNIT_{0}"), SyntaxTree.Utils.IdentListToString(SyntaxUsesUnit.name.idents, ".")), FileName) { this.SyntaxUsesUnit = SyntaxUsesUnit; this.source_context = SyntaxUsesUnit.source_context; } } public class UnsupportedTargetFramework : CompilerCompilationError { public UnsupportedTargetFramework(string FrameworkName, TreeRealization.location sl) : base(string.Format(StringResources.Get("COMPILATIONERROR_UNSUPPORTED_TARGETFRAMEWORK_{0}"), FrameworkName)) { this.sourceLocation = new SourceLocation(sl.doc.file_name, sl.begin_line_num, sl.begin_column_num, sl.end_line_num, sl.end_column_num); } } public enum UnitState { BeginCompilation, InterfaceCompiled, Compiled } public class CompilationUnit { internal bool CaseSensitive = false; /// /// поле для проверки на циклическую зависимость интерфейсов модулей /// public string currentUsedUnitId; public PascalABCCompiler.Errors.SyntaxError syntax_error; 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(); /// /// Только "реальные" юниты (не dll и namespace) /// public Dictionary InterfaceUsedDirectUnits { get; } = new Dictionary(); public unit_node_list InterfaceUsedUnits { get; } = new unit_node_list(); /// /// Только "реальные" юниты (не dll и namespace) /// public Dictionary ImplementationUsedDirectUnits { get; } = new Dictionary(); public unit_node_list ImplementationUsedUnits { get; } = new unit_node_list(); public bool ForEachDirectCompilationUnit(Func on_unit) { foreach (var kvp in InterfaceUsedDirectUnits) if (!on_unit(kvp.Value, InterfaceUsedUnits.unit_uses_paths[kvp.Key])) return false; foreach (var kvp in ImplementationUsedDirectUnits) if (!on_unit(kvp.Value, ImplementationUsedUnits.unit_uses_paths[kvp.Key])) return false; return true; } private SyntaxTree.compilation_unit _syntaxTree = null; public SyntaxTree.compilation_unit SyntaxTree { get { return _syntaxTree; } set { _syntaxTree = value; } } private PascalABCCompiler.TreeRealization.unit_node _semanticTree = null; public PascalABCCompiler.TreeRealization.unit_node SemanticTree { get { return _semanticTree; } set { _semanticTree = value; } } private SyntaxTree.unit_or_namespace _syntaxUnitName = null; public SyntaxTree.unit_or_namespace SyntaxUnitName { get { return _syntaxUnitName; } set { _syntaxUnitName = value; } } private TreeRealization.using_namespace_list _interface_using_namespace_list = new TreeRealization.using_namespace_list(); public TreeRealization.using_namespace_list InterfaceUsingNamespaceList { get { return _interface_using_namespace_list; } set { _interface_using_namespace_list = value; } } private TreeRealization.using_namespace_list _implementation_using_namespace_list = new TreeRealization.using_namespace_list(); public TreeRealization.using_namespace_list ImplementationUsingNamespaceList { get { return _implementation_using_namespace_list; } set { _implementation_using_namespace_list = value; } } public UnitState State = UnitState.BeginCompilation; } public class CompilationUnitHashTable : Hashtable { public CompilationUnitHashTable() : base(StringComparer.InvariantCultureIgnoreCase) { } public CompilationUnit this[string key] { get { if (key != null) return (base[key] as CompilationUnit); return null; } set { base[key] = value; } } } /// /// Опции компиляции /// //[Serializable()] public class CompilerOptions : MarshalByRefObject { public enum OutputType { ClassLibrary = 0, ConsoleApplicaton = 1, WindowsApplication = 2, PascalCompiledUnit = 3, SemanticTree = 4 } public bool Debug = false; public bool ForDebugging = false; public bool ForIntellisense = false; public bool Rebuild = false; public bool Optimise = false; public bool SavePCUInThreadPull = false; public bool RunWithEnvironment = false; public string CompiledUnitExtension = ".pcu"; public bool ProjectCompiled = false; public IProjectInfo CurrentProject = null; public OutputType OutputFileType = OutputType.ConsoleApplicaton; public bool GenerateCode = true; public bool SaveDocumentation = true; public bool SavePCU = true; public bool IgnoreRtlErrors = true; public bool Only32Bit = false; public string Locale = "ru"; public SyntaxTree.compilation_unit UnitSyntaxTree = null; private string sourceFileName = null; ///имя исходного файла ///при измененнии меняется OutputFileName,OutputDirectory,SourceFileDirectory public string SourceFileName { get { return sourceFileName; } set { sourceFileName = value; OutputFileName = value; sourceFileDirectory = Path.GetDirectoryName(value); if (sourceFileDirectory == "") sourceFileDirectory = Environment.CurrentDirectory; outputDirectory = SourceFileDirectory; useOutputDirectory = false; } } private string sourceFileDirectory = null; public string SourceFileDirectory { get { return sourceFileDirectory; } } private string outputFileName = null; // имя выходного файла без расширения // если имя указано без пути то в качестве пути используетя OutputDirectory public string OutputFileName { get { string FileName = outputFileName; switch (OutputFileType) { case OutputType.ConsoleApplicaton: case OutputType.WindowsApplication: FileName = FileName + ".exe"; break; case OutputType.ClassLibrary: FileName = FileName + ".dll"; break; case OutputType.PascalCompiledUnit: FileName = FileName + CompiledUnitExtension; break; } if (Path.GetDirectoryName(FileName) == "") FileName = Path.Combine(OutputDirectory, FileName); return FileName; } set { outputFileName = Path.GetFileNameWithoutExtension(value); } } public string SystemDirectory; public List ForceDefines = new List(); public List SearchDirectory; private bool useDllForSystemUnits = false; public bool UseDllForSystemUnits { get { return useDllForSystemUnits; } set { useDllForSystemUnits = value; NetHelper.NetHelper.UsePABCRtl = value; } } public string[] ParserSearchPaths; public enum StandardModuleAddMethod { LeftToAll, RightToMain }; [Serializable()] public class StandardModule : MarshalByRefObject { public string Name = null; public StandardModuleAddMethod AddMethod = StandardModuleAddMethod.LeftToAll; public SyntaxTree.LanguageId AddToLanguages = SyntaxTree.LanguageId.PascalABCNET; public StandardModule(string Name, StandardModuleAddMethod AddMethod) { this.Name = Name; this.AddMethod = AddMethod; } public StandardModule(string Name, StandardModuleAddMethod AddMethod, SyntaxTree.LanguageId AddToLanguages) { this.Name = Name; this.AddToLanguages = AddToLanguages; this.AddMethod = AddMethod; } public StandardModule(string Name) { this.Name = Name; } public StandardModule(string Name, SyntaxTree.LanguageId AddToLanguages) { this.AddToLanguages = AddToLanguages; this.Name = Name; } } /// /// module at index 0 is System module /// public List StandardModules; public void RemoveStandardModule(string name) { int moduleIndex = StandardModules.FindIndex(module => module.Name == name); if (moduleIndex != -1) StandardModules.RemoveAt(moduleIndex); } public void RemoveStandardModuleAtIndex(int index) { if (index < StandardModules.Count) StandardModules.RemoveAt(index); } internal string outputDirectory = null; internal bool useOutputDirectory = false; //для поиска pcu во вторую очередь //для сохранения сюда .exe, .dll и .pdb файлов public string OutputDirectory { get { return outputDirectory; } set { outputDirectory = value; useOutputDirectory = outputDirectory != null; } } //для поиска pcu в третью очередь исп. путь к pas файлу public Hashtable StandardDirectories; private void SetStandardModules() { StandardModules = new List(); StandardModules.Add(new StandardModule("PABCSystem", SyntaxTree.LanguageId.PascalABCNET)); StandardModules.Add(new StandardModule("PABCExtensions", SyntaxTree.LanguageId.PascalABCNET)); } private void SetDirectories() { SystemDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName); StandardDirectories = new Hashtable(StringComparer.InvariantCultureIgnoreCase); StandardDirectories.Add("%PABCSYSTEM%", SystemDirectory); ParserSearchPaths = new string[] { Path.Combine(SystemDirectory, "Lib") }; SearchDirectory = ParserSearchPaths.ToList(); } public CompilerOptions() { SetDirectories(); SetStandardModules(); } public CompilerOptions(string SourceFileName, OutputType OutputFileType) { SetDirectories(); SetStandardModules(); this.SourceFileName = SourceFileName; this.OutputFileType = OutputFileType; } } public enum CompilerState { Ready, CompilationStarting, Reloading, ParserConnected, BeginCompileFile, BeginParsingFile, EndParsingFile, CompileInterface, CompileImplementation, EndCompileFile, ReadDLL, ReadPCUFile, SavePCUFile, CodeGeneration, CompilationFinished, PCUReadingError, PCUWritingError, SemanticTreeConverterConnected, SemanticTreeConversion, SyntaxTreeConversion, SyntaxTreeConverterConnected } [Serializable()] public class CompilerInternalDebug { public bool CodeGeneration = true; public bool SemanticAnalysis = true; public bool PCUGenerate = true; public bool AddStandartUnits = true; public bool SkipPCUErrors = true; public bool IncludeDebugInfoInPCU = true; public bool AlwaysGenerateXMLDoc = false; public bool SkipInternalErrorsIfSyntaxTreeIsCorrupt = true; public bool UseStandarParserForIntellisense = true; public bool RunOnMono = false; public List DocumentedUnits = new List(); #if DEBUG public bool DebugVersion { get { return true; } } #elif !DEBUG public bool DebugVersion { get { return false; } } #endif } public class SupportedSourceFile { private string[] extensions; public string[] Extensions { get { return extensions; } } private string languageName; public string LanguageName { get { return languageName; } } public SupportedSourceFile(string[] extensions, string lname) { this.extensions = extensions; languageName = lname; } public static SupportedSourceFile Make(Parsers.IParser parser) { List ext = new List(); foreach (string ex in parser.FilesExtensions) if (ex[ex.Length - 1] != Parsers.Controller.HideParserExtensionPostfixChar) ext.Add(ex); if (ext.Count > 0) return new SupportedSourceFile(ext.ToArray(), parser.Name); return null; } public override string ToString() { return string.Format("{0} ({1})", LanguageName, FormatTools.ExtensionsToString(Extensions, "*", ";")); } } public delegate void ChangeCompilerStateEventDelegate(ICompiler sender, CompilerState State, string FileName); public class Compiler : MarshalByRefObject, ICompiler { //public ISyntaxTreeChanger SyntaxTreeChanger = null; // SSM 17/08/15 - для операций над синтаксическим деревом после его построения int pABCCodeHealth = 0; public int PABCCodeHealth { get { return pABCCodeHealth; } } public static string Version { get { return RevisionClass.FullVersion; } } public static string ShortVersion { get { if (RevisionClass.Build == "0") return RevisionClass.MainVersion; else // TODO: Недостижимый код | EVA return RevisionClass.MainVersion + "." + RevisionClass.Build; } } public static DateTime VersionDateTime { get { return File.GetLastWriteTime(System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName); } } public static string Banner { get { return "PascalABCCompiler.Core v" + Version; } } public override string ToString() { return Banner; } private SyntaxTreeConvertersController syntaxTreeConvertersController = null; public SyntaxTreeConvertersController SyntaxTreeConvertersController { get { return syntaxTreeConvertersController; } } private SemanticTreeConvertersController semanticTreeConvertersController = null; public SemanticTreeConvertersController SemanticTreeConvertersController { get { return semanticTreeConvertersController; } } private Hashtable BadNodesInSyntaxTree = new Hashtable(); program_node semanticTree = null; public SemanticTree.IProgramNode SemanticTree { get { return semanticTree; } } public program_node semantic_tree { get { return semanticTree; } } public List CompiledVariables = new List(); private Dictionary> compilerDirectives = null; //public Hashtable CompilerDirectives //{ // get { return compiler_directives; } //} private uint linesCompiled; public uint LinesCompiled { get { return linesCompiled; } } private CompilerInternalDebug internalDebug; public CompilerInternalDebug InternalDebug { get { return internalDebug; } set { internalDebug = value; } } private CompilerState state = CompilerState.Ready; public CompilerState State { get { return state; } } private void SetSupportedSourceFiles() { List supportedSourceFilesList = new List(); for (int i = 0; i < ParsersController.Parsers.Count; i++) { SupportedSourceFile sf = SupportedSourceFile.Make(ParsersController.Parsers[i]); if (sf != null) supportedSourceFilesList.Add(sf); } supportedSourceFiles = supportedSourceFilesList.ToArray(); } private void SetSupportedProjectFiles() { List supportedProjectFilesList = new List(); /*for (int i = 0; i < ParsersController.Parsers.Count; i++) { SupportedSourceFile sf = SupportedSourceFile.Make(ParsersController.Parsers[i]); if (sf != null) supportedSourceFilesList.Add(sf); }*/ //vremenno supportedProjectFilesList.Add(new SupportedSourceFile(new string[1] { ".pabcproj" }, "PascalABC.NET")); supportedProjectFiles = supportedProjectFilesList.ToArray(); } private SupportedSourceFile[] supportedSourceFiles = null; public SupportedSourceFile[] SupportedSourceFiles { get { return supportedSourceFiles; } set { supportedSourceFiles = value; } } private SupportedSourceFile[] supportedProjectFiles = null; public SupportedSourceFile[] SupportedProjectFiles { get { return supportedProjectFiles; } } private CompilationUnitHashTable unitTable = new CompilationUnitHashTable(); public CompilationUnitHashTable UnitTable { get { return unitTable; } } public List UnitsLogicallySortedList = new List(); private List StandardModules = new List(); public CompilerOptions CompilerOptions { get; set; } = new CompilerOptions(); internal Dictionary DLLCache = new Dictionary(); private Parsers.Controller parsersController = null; public Parsers.Controller ParsersController { get { return parsersController; } set { parsersController = value; } } public TreeConverter.SyntaxTreeToSemanticTreeConverter SyntaxTreeToSemanticTreeConverter = null; public CodeGenerators.Controller CodeGeneratorsController = null; //public LLVMConverter.Controller LLVMCodeGeneratorsController = null; //public PascalToCppConverter.Controller PABCToCppCodeGeneratorsController = null; public SyntaxTree.unit_or_namespace currentUnitSyntaxTree; /// /// список отложенной компиляции реализации (она будет откомпилирована в Compile, а не в СompileUnit) /// private List UnitsToCompileDelayedList = new List(); public Hashtable RecompileList = new Hashtable(StringComparer.OrdinalIgnoreCase); private Hashtable CycleUnits = new Hashtable(); public CompilationUnit currentCompilationUnit = null; private CompilationUnit firstCompilationUnit = null; private bool PCUReadersAndWritersClosed; /// /// Начало основной программы /// public int beginOffset; /// /// Положение первых переменных в пространстве имен основной программы /// public int varBeginOffset; private bool _clear_after_compilation = true; private static Dictionary pcuCompilationUnits = new Dictionary(); public bool ClearAfterCompilation { get { return _clear_after_compilation; } set { _clear_after_compilation = value; } } public int BeginOffset { get { return beginOffset; } } public int VarBeginOffset { get { return varBeginOffset; } } private List warnings = new List(); public List Warnings { get { return warnings; } } public Dictionary, Tuple> SourceFileNamesDictionary { get; } = new Dictionary, Tuple>(); public Dictionary, Tuple> PCUFileNamesDictionary { get; } = new Dictionary, Tuple>(); public Dictionary, string> GetUnitFileNameCache { get; } = new Dictionary, string>(); public void AddWarnings(List WarningList) { foreach (CompilerWarning cw in WarningList) warnings.Add(cw); } public event ChangeCompilerStateEventDelegate OnChangeCompilerState; private void ChangeCompilerStateEvent(ICompiler sender, CompilerState State, string FileName) { this.state = State; } private bool SourceFileExists(string FileName) { if (FileName == null) return false; return (bool)SourceFilesProvider(FileName, SourceFileOperation.Exists); } private DateTime SourceFileGetLastWriteTime(string FileName) { return (DateTime)SourceFilesProvider(FileName, SourceFileOperation.GetLastWriteTime); } private SourceFilesProviderDelegate sourceFilesProvider = SourceFilesProviders.DefaultSourceFilesProvider; public SourceFilesProviderDelegate SourceFilesProvider { get { return sourceFilesProvider; } } private List errorsList = new List(); public List ErrorsList { get { return errorsList; } } public Compiler() { //SyntaxTreeChanger = new SyntaxTreeChanger.SyntaxTreeChange(); OnChangeCompilerState += ChangeCompilerStateEvent; Reload(); } public Compiler(ICompiler comp, SourceFilesProviderDelegate SourceFilesProvider, ChangeCompilerStateEventDelegate ChangeCompilerState) { //SyntaxTreeChanger = new SyntaxTreeChanger.SyntaxTreeChange(); // SSM 01/05/16 - подключение изменяльщика синтаксического дерева this.ParsersController = comp.ParsersController; this.internalDebug = comp.InternalDebug; OnChangeCompilerState += ChangeCompilerStateEvent; if (SourceFilesProvider != null) this.sourceFilesProvider = SourceFilesProvider; if (ChangeCompilerState != null) OnChangeCompilerState += ChangeCompilerState; this.supportedSourceFiles = comp.SupportedSourceFiles; this.supportedProjectFiles = comp.SupportedProjectFiles; } public Compiler(SourceFilesProviderDelegate SourceFilesProvider, ChangeCompilerStateEventDelegate ChangeCompilerState) { //SyntaxTreeChanger = new SyntaxTreeChanger.SyntaxTreeChange(); // SSM 01/05/16 - подключение изменяльщика синтаксического дерева OnChangeCompilerState += ChangeCompilerStateEvent; if (SourceFilesProvider != null) this.sourceFilesProvider = SourceFilesProvider; if (ChangeCompilerState != null) OnChangeCompilerState += ChangeCompilerState; Reload(); } public void Reload() { OnChangeCompilerState(this, CompilerState.Reloading, null); pABCCodeHealth = 0; //А это что? TreeRealization.type_node tn = SystemLibrary.SystemLibrary.void_type; ClearAll(); errorsList.Clear(); Warnings.Clear(); InternalDebug = new CompilerInternalDebug(); ParsersController = new Parsers.Controller(); ParsersController.ParserConnected += new PascalABCCompiler.Parsers.Controller.ParserConnectedDeleagte(ParsersController_ParserConnected); ParsersController.SourceFilesProvider = sourceFilesProvider; ParsersController.Reload(); SyntaxTreeToSemanticTreeConverter = new TreeConverter.SyntaxTreeToSemanticTreeConverter(); CodeGeneratorsController = new CodeGenerators.Controller(); //PABCToCppCodeGeneratorsController = new PascalToCppConverter.Controller(); SetSupportedSourceFiles(); SetSupportedProjectFiles(); syntaxTreeConvertersController = new SyntaxTreeConvertersController(this); syntaxTreeConvertersController.ChangeState += syntaxTreeConvertersController_ChangeState; syntaxTreeConvertersController.AddConverters(); semanticTreeConvertersController = new SemanticTreeConvertersController(this); semanticTreeConvertersController.ChangeState += semanticTreeConvertersController_ChangeState; semanticTreeConvertersController.AddConverters(); OnChangeCompilerState(this, CompilerState.Ready, null); } void ParsersController_ParserConnected(PascalABCCompiler.Parsers.IParser Parser) { if (OnChangeCompilerState != null) OnChangeCompilerState(this, CompilerState.ParserConnected, Parser.GetType().Assembly.ManifestModule.FullyQualifiedName); } void syntaxTreeConvertersController_ChangeState(SyntaxTreeConvertersController.State State, ISyntaxTreeConverter SyntaxTreeConverter) { switch (State) { case SyntaxTreeConvertersController.State.Convert: OnChangeCompilerState(this, CompilerState.SyntaxTreeConversion, SyntaxTreeConverter.Name); break; case SyntaxTreeConvertersController.State.ConnectConverter: OnChangeCompilerState(this, CompilerState.SyntaxTreeConverterConnected, SyntaxTreeConverter.Name); break; } } void semanticTreeConvertersController_ChangeState(SemanticTreeConvertersController.State State, ISemanticTreeConverter SemanticTreeConverter) { switch (State) { case SemanticTreeConvertersController.State.Convert: OnChangeCompilerState(this, CompilerState.SemanticTreeConversion, SemanticTreeConverter.Name); break; case SemanticTreeConvertersController.State.ConnectConverter: OnChangeCompilerState(this, CompilerState.SemanticTreeConverterConnected, SemanticTreeConverter.Name); break; } } private Dictionary> GetCompilerDirectives(List Units) { Dictionary> directives = new Dictionary>(StringComparer.CurrentCultureIgnoreCase); for (int i = 0; i < Units.Count; i++) { common_unit_node unitNode = Units[i].SemanticTree as common_unit_node; if (unitNode != null) { foreach (compiler_directive cd in unitNode.compiler_directives) { if (!directives.ContainsKey(cd.name)) directives.Add(cd.name, new List()); else if (cd.name.Equals("mainresource", StringComparison.CurrentCultureIgnoreCase)) throw new DuplicateDirective(cd.location.doc.file_name, "mainresource", cd.location); directives[cd.name].Insert(0, cd); } } } return directives; } private Hashtable GetCompilerDirectives(CompilationUnit Unit) { Hashtable Directives = new Hashtable(StringComparer.CurrentCultureIgnoreCase); TreeRealization.common_unit_node cun = Unit.SemanticTree as TreeRealization.common_unit_node; if (cun != null) foreach (TreeRealization.compiler_directive cd in cun.compiler_directives) Directives[cd.name] = cd; return Directives; } private TreeRealization.location get_location_from_treenode(SyntaxTree.syntax_tree_node tn, string FileName) { if (tn.source_context == null) { return null; } return new TreeRealization.location(tn.source_context.begin_position.line_num, tn.source_context.begin_position.column_num, tn.source_context.end_position.line_num, tn.source_context.end_position.column_num, new TreeRealization.document(FileName)); } /// /// преобразует в директивы семантического уровня /// private List GetDirectivesAsSemanticNodes(List compilerDirectives, string unitFileName) { List list = new List(); foreach (SyntaxTree.compiler_directive directive in compilerDirectives) { list.Add(new compiler_directive(directive.Name.text, directive.Directive?.text ?? "", get_location_from_treenode(directive, unitFileName), unitFileName)); } return list; } void syncStartCompile() { Compile(); } public void StartCompile() { System.Threading.Thread th = new System.Threading.Thread(syncStartCompile); th.SetApartmentState(System.Threading.ApartmentState.STA); th.Start(); } public string Compile(CompilerOptions CompilerOptions) { this.CompilerOptions = CompilerOptions; return Compile(); } private void Reset() { SourceFileNamesDictionary.Clear(); PCUFileNamesDictionary.Clear(); GetUnitFileNameCache.Clear(); Warnings.Clear(); errorsList.Clear(); //if (!File.Exists(CompilerOptions.SourceFileName)) throw new SourceFileNotFound(CompilerOptions.SourceFileName); currentCompilationUnit = null; firstCompilationUnit = null; linesCompiled = 0; pABCCodeHealth = 0; PCUReadersAndWritersClosed = false; ParsersController.Reset(); SyntaxTreeToSemanticTreeConverter.Reset(); CodeGeneratorsController.Reset(); //PABCToCppCodeGeneratorsController.Reset(); UnitsToCompileDelayedList.Clear(); DLLCache.Clear(); project = null; } void CheckErrorsAndThrowTheFirstOne() { if (CompilerOptions.ForIntellisense) return; if (ErrorsList.Count > 0) throw ErrorsList[0]; } private void MoveSystemUnitForwardInUnitLogicallySortedList() { if (CompilerOptions.StandardModules.Count == 0) return; CompilationUnit system_unit = null; foreach (CompilationUnit unit in UnitsLogicallySortedList) { if (unit.SemanticTree != null && unit.SemanticTree is common_unit_node) { if ((unit.SemanticTree as common_unit_node).unit_name == CompilerOptions.StandardModules[0].Name) { system_unit = unit; break; } } } if (system_unit != null && system_unit != UnitsLogicallySortedList[0]) { UnitsLogicallySortedList.Remove(system_unit); UnitsLogicallySortedList.Insert(0, system_unit); } } private uint get_compiled_lines(string FileName) { StreamReader sr = File.OpenText(FileName); uint line = 0; while (!sr.EndOfStream) { sr.ReadLine(); line++; } sr.Close(); return line; } class ProgInfo { public string entry_module; public int entry_method_name_pos; public int entry_method_line; public int using_pos = -1; public List modules = new List(); public List addit_imports = new List(); public List addit_project_files = new List(); } private void add_import_info(ProgInfo info, List imports) { Hashtable ht = new Hashtable(StringComparer.CurrentCultureIgnoreCase); ht["GraphABC"] = "GraphABC"; ht["GraphABCHelper"] = "GraphABCHelper"; ht["ABCObjects"] = "ABCObjects"; ht["Robot"] = "Robot"; ht["Drawman"] = "Drawman"; ht["DrawManField"] = "DrawManField"; foreach (string s in imports) { string low_s = s.ToLower(); //string mod_file = FindSourceFileInDirectories(s+".mod",Path.Combine(this.CompilerOptions.SystemDirectory,"lib")); if (ht[s] != null) { string name = ht[s] as string; if (!info.modules.Contains(name)) { info.modules.Add(name); info.addit_imports.Add(name + "." + name); } } /*if (!string.IsNullOrEmpty(mod_file)) { switch (low_s) { case "graphabc" : if (!info.modules.Contains("GraphABC") && !info.modules.Contains("ABCObjects") && !info.modules.Contains("ABCButtons") && !info.modules.Contains("ABCHouse") && !info.modules.Contains("ABCSprites") && !info.modules.Contains("RobotField")) { info.modules.Add("GraphABC"); info.addit_imports.Add("GraphABC.GraphABC"); } else if (!info.addit_imports.Contains("GraphABC.GraphABC")) { info.addit_imports.Add("GraphABC.GraphABC"); } break; case "abcobjects" : if (!info.modules.Contains("ABCObjects") && !info.modules.Contains("ABCButtons") && !info.modules.Contains("ABCHouse") && !info.modules.Contains("ABCSprites") && !info.modules.Contains("RobotField")) { info.modules.Add("ABCObjects"); info.addit_imports.Add("ABCObjects.ABCObjects"); if (info.modules.Contains("GraphABC")) { info.modules.Remove("GraphABC"); //info.addit_imports.Remove("GraphABC.GraphABC"); } } break; default: if (!info.modules.Contains(s)) { info.modules.Add(s); info.addit_imports.Add(s+"."+s); } break; } }*/ else { string source_file = FindFileInDirs(s + ".vb", out _, Path.GetDirectoryName(CompilerOptions.SourceFileName), Path.Combine(this.CompilerOptions.SystemDirectory, "lib"), Path.Combine(this.CompilerOptions.SystemDirectory, "LibSource")); if (!string.IsNullOrEmpty(source_file)) { if (!info.addit_project_files.Contains(source_file)) { info.addit_project_files.Add(source_file); } } } } /*List mods = new List(); List inds = new List(); for (int i=0; i usings = new List(); foreach (ICSharpCode.NRefactory.Ast.INode node in cu.Children) { if (node is ICSharpCode.NRefactory.Ast.TypeDeclaration) { ICSharpCode.NRefactory.Ast.TypeDeclaration td = node as ICSharpCode.NRefactory.Ast.TypeDeclaration; if (td.Type == ICSharpCode.NRefactory.Ast.ClassType.Module) { foreach (ICSharpCode.NRefactory.Ast.INode node2 in td.Children) { if (node2 is ICSharpCode.NRefactory.Ast.MethodDeclaration) { ICSharpCode.NRefactory.Ast.MethodDeclaration meth = node2 as ICSharpCode.NRefactory.Ast.MethodDeclaration; if (string.Compare(meth.Name, "Main", true) == 0 && (meth.Parameters == null || meth.Parameters.Count == 0)) { //info = new ProgInfo(); info.entry_module = (meth.Parent as ICSharpCode.NRefactory.Ast.TypeDeclaration).Name; //info.entry_method_name_line = meth.StartLocation.Line; //info.entry_method_name_col = meth.StartLocation.Column; info.entry_method_name_pos = find_pos(source, meth.StartLocation.Line, meth.StartLocation.Column, true); if (meth.Body.Children.Count > 0) { for (int i = 0; i < meth.Body.Children.Count; i++) { if (!(meth.Body.Children[i] is ICSharpCode.NRefactory.Ast.LocalVariableDeclaration)) { info.entry_method_line = meth.Body.Children[i].StartLocation.Line; break; } } } else info.entry_method_line = meth.Body.EndLocation.Line; } } } } } else if (node is ICSharpCode.NRefactory.Ast.UsingDeclaration) { ICSharpCode.NRefactory.Ast.UsingDeclaration using_node = node as ICSharpCode.NRefactory.Ast.UsingDeclaration; foreach (ICSharpCode.NRefactory.Ast.Using us in using_node.Usings) if (!string.IsNullOrEmpty(us.Name)) usings.Add(us.Name); if (info.using_pos == -1) info.using_pos = find_pos(source, using_node.EndLocation.Line, using_node.EndLocation.Column, false); } } if (info.entry_module != null) { add_import_info(info, usings); return info; } return null; } public string CompileWithProvider(string[] sources, System.CodeDom.Compiler.CodeDomProvider cp, params string[] RefAssemblies) { OnChangeCompilerState(this, CompilerState.CompilationStarting, CompilerOptions.SourceFileName); OnChangeCompilerState(this, CompilerState.BeginCompileFile, CompilerOptions.SourceFileName); Reset(); //var cscp = new Microsoft.CSharp.CSharpCodeProvider(); var comp_opt = new CompilerParameters(); comp_opt.IncludeDebugInformation = CompilerOptions.Debug; comp_opt.GenerateExecutable = true; comp_opt.WarningLevel = 3; comp_opt.CompilerOptions = "/platform:x86 "; comp_opt.OutputAssembly = CompilerOptions.OutputFileName; if (RefAssemblies != null) comp_opt.ReferencedAssemblies.AddRange(RefAssemblies); //string source = GetSourceFileText(CompilerOptions.SourceFileName); var res = cp.CompileAssemblyFromSource(comp_opt, sources); if (res.Errors.Count > 0) { for (int i = 0; i < res.Errors.Count; i++) { if (!res.Errors[i].IsWarning && errorsList.Count == 0 /*&& dlls.Errors[i].file_name != redirect_fname*/) { if (File.Exists(res.Errors[i].FileName)) errorsList.Add(new Errors.CommonCompilerError(res.Errors[i].ErrorText, res.Errors[i].FileName, res.Errors[i].Line != 0 ? res.Errors[i].Line : 1, res.Errors[i].Column != 0 ? res.Errors[i].Column : 1)); else errorsList.Add(new Errors.CommonCompilerError(res.Errors[i].ErrorText, CompilerOptions.SourceFileName, res.Errors[i].Line != 0 ? res.Errors[i].Line : 1, res.Errors[i].Column != 0 ? res.Errors[i].Column : 1)); } else if (res.Errors[i].IsWarning) { warnings.Add(new Errors.CommonWarning(res.Errors[i].ErrorText, res.Errors[i].FileName, res.Errors[i].Line, res.Errors[i].Column)); } } } //linesCompiled = get_compiled_lines(CompilerOptions.SourceFileName); OnChangeCompilerState(this, CompilerState.CompilationFinished, CompilerOptions.SourceFileName); ClearAll(); OnChangeCompilerState(this, CompilerState.Ready, null); if (errorsList.Count > 0) return null; else return res.PathToAssembly; } class PyErrorHandler : ErrorListener { Compiler c; public PyErrorHandler(Compiler cc) { c = cc; } public override void ErrorReported(ScriptSource source, string message, SourceSpan span, int errorCode, Severity severity) { if (severity == Severity.Warning) c.warnings.Add(new Errors.CommonWarning(message, c.CompilerOptions.SourceFileName, span.Start.Line, span.Start.Column)); else c.errorsList.Add(new Errors.CommonCompilerError(message, c.CompilerOptions.SourceFileName, span.Start.Line, span.Start.Column)); } } private Assembly IronPythonAssembly; private MethodInfo PythonCreateEngineMethod; public string CompilePy() { OnChangeCompilerState(this, CompilerState.CompilationStarting, CompilerOptions.SourceFileName); OnChangeCompilerState(this, CompilerState.BeginCompileFile, CompilerOptions.SourceFileName); Reset(); if (IronPythonAssembly == null) { IronPythonAssembly = Assembly.LoadFrom("IronPython.dll"); PythonCreateEngineMethod = IronPythonAssembly.GetType("IronPython.Hosting.Python").GetMethod("CreateEngine"); } string source = GetSourceFileText(CompilerOptions.SourceFileName); ScriptEngine pyEngine = (ScriptEngine)PythonCreateEngineMethod.Invoke(null, new object[0]); ; ScriptSource src = pyEngine.CreateScriptSourceFromString(source); CompiledCode compiled = src.Compile(new PyErrorHandler(this)); if (compiled != null) compiled.Execute(); linesCompiled = get_compiled_lines(CompilerOptions.SourceFileName); OnChangeCompilerState(this, CompilerState.CompilationFinished, CompilerOptions.SourceFileName); ClearAll(); OnChangeCompilerState(this, CompilerState.Ready, null); //if (errorsList.Count > 0) return null; //else return dlls.PathToAssembly; } public string CompileCS() { OnChangeCompilerState(this, CompilerState.CompilationStarting, CompilerOptions.SourceFileName); OnChangeCompilerState(this, CompilerState.BeginCompileFile, CompilerOptions.SourceFileName); Reset(); var d = new Dictionary(); d["CompilerVersion"] = "v4.0"; var cscp = new Microsoft.CSharp.CSharpCodeProvider(d); //var cscp = new Microsoft.CSharp.CSharpCodeProvider(); var comp_opt = new CompilerParameters(); comp_opt.IncludeDebugInformation = CompilerOptions.Debug; comp_opt.GenerateExecutable = true; comp_opt.WarningLevel = 3; comp_opt.OutputAssembly = CompilerOptions.OutputFileName; //comp_opt.ReferencedAssemblies.Add() string source = GetSourceFileText(CompilerOptions.SourceFileName); using (StringReader sr = new StringReader(source)) { do { var s = sr.ReadLine(); if (s == null) break; if (s.ToLower().StartsWith("//#reference ")) { s = s.Remove(0, 13); s = s.Trim(); comp_opt.ReferencedAssemblies.Add(s); } else break; } while (true); } var res = cscp.CompileAssemblyFromSource(comp_opt, source); if (res.Errors.Count > 0) { for (int i = 0; i < res.Errors.Count; i++) { if (!res.Errors[i].IsWarning && errorsList.Count == 0 /*&& dlls.Errors[i].file_name != redirect_fname*/) { if (File.Exists(res.Errors[i].FileName)) errorsList.Add(new Errors.CommonCompilerError(res.Errors[i].ErrorText, res.Errors[i].FileName, res.Errors[i].Line != 0 ? res.Errors[i].Line : 1, res.Errors[i].Column != 0 ? res.Errors[i].Column : 1)); else errorsList.Add(new Errors.CommonCompilerError(res.Errors[i].ErrorText, CompilerOptions.SourceFileName, res.Errors[i].Line != 0 ? res.Errors[i].Line : 1, res.Errors[i].Column != 0 ? res.Errors[i].Column : 1)); } else if (res.Errors[i].IsWarning) { warnings.Add(new Errors.CommonWarning(res.Errors[i].ErrorText, res.Errors[i].FileName, res.Errors[i].Line, res.Errors[i].Column)); } } } linesCompiled = get_compiled_lines(CompilerOptions.SourceFileName); OnChangeCompilerState(this, CompilerState.CompilationFinished, CompilerOptions.SourceFileName); ClearAll(); OnChangeCompilerState(this, CompilerState.Ready, null); if (errorsList.Count > 0) return null; else return res.PathToAssembly; } public string CompileVB() { OnChangeCompilerState(this, CompilerState.CompilationStarting, CompilerOptions.SourceFileName); OnChangeCompilerState(this, CompilerState.BeginCompileFile, CompilerOptions.SourceFileName); Reset(); Microsoft.VisualBasic.VBCodeProvider vbcp = new Microsoft.VisualBasic.VBCodeProvider(); List sources = new List(); sources.Add(CompilerOptions.SourceFileName); System.CodeDom.Compiler.CompilerParameters comp_opt = new System.CodeDom.Compiler.CompilerParameters(); comp_opt.OutputAssembly = CompilerOptions.OutputFileName; comp_opt.WarningLevel = 3; comp_opt.ReferencedAssemblies.Add("System.Windows.Forms.dll"); comp_opt.ReferencedAssemblies.Add("System.Drawing.dll"); comp_opt.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll"); comp_opt.IncludeDebugInformation = CompilerOptions.Debug; comp_opt.GenerateExecutable = true; string fname = Path.Combine(Path.GetDirectoryName(CompilerOptions.SourceFileName), "_temp$" + Path.GetFileName(CompilerOptions.SourceFileName)); File.Copy(CompilerOptions.SourceFileName, fname, true); string source = GetSourceFileText(CompilerOptions.SourceFileName); IParser parser = ICSharpCode.NRefactory.ParserFactory.CreateParser(ICSharpCode.NRefactory.SupportedLanguage.VBNet, new StringReader(source)); parser.Parse(); ProgInfo info = get_programm_info(parser.CompilationUnit, source); parser.Dispose(); if (info != null) sources.AddRange(info.addit_project_files); string redirect_base_fname = FindFileInDirs("__RedirectIOMode.vb", out _, Path.Combine(this.CompilerOptions.SystemDirectory, "Lib"), Path.Combine(this.CompilerOptions.SystemDirectory, "LibSource")); string system_unit_name = FindFileInDirs("VBSystem.vb", out _, 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(); sr.Close(); if (info != null) { System.Text.StringBuilder tmp_sb = new System.Text.StringBuilder(); if (info.modules.Count > 0) { tmp_sb.AppendLine("GetType(Fictive.Fictive).Assembly.GetType(\"PABCSystem_implementation$.PABCSystem_implementation$\").GetMethod(\"$Initialization\").Invoke(Nothing,Nothing)"); } for (int i = 0; i < info.modules.Count; i++) { tmp_sb.AppendLine("GetType(Fictive.Fictive).Assembly.GetType(\"" + info.modules[i] + "_implementation$." + info.modules[i] + "_implementation$\").GetMethod(\"$Initialization\").Invoke(Nothing,Nothing)"); } tmp_sb.AppendLine(info.entry_module + "." + "___Main()"); for (int i = 0; i < info.modules.Count; i++) { tmp_sb.AppendLine("GetType(Fictive.Fictive).Assembly.GetType(\"" + info.modules[i] + "_implementation$." + info.modules[i] + "_implementation$\").GetMethod(\"$Finalization\").Invoke(Nothing,Nothing)"); } redirect_module = redirect_module.Replace("%MAIN%", tmp_sb.ToString()); } StreamWriter sw = new StreamWriter(redirect_fname, false); if (info != null) { sw.WriteLine(redirect_module); } else { sw.WriteLine("module _RedirectIOMode"); sw.WriteLine("End module"); } sw.Close(); sw = new StreamWriter(CompilerOptions.SourceFileName, false); if (info != null && info.entry_method_name_pos != -1) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); int start_pos = 0; if (info.using_pos != -1) { start_pos = info.using_pos; sb.Append(source.Substring(0, info.using_pos)); for (int i = 0; i < info.addit_imports.Count; i++) { sb.Append("," + info.addit_imports[i]); } sb.Append(",System.Collections.Generic"); sb.Append(",Microsoft.VisualBasic.Strings"); sb.Append(",Microsoft.VisualBasic.Constants"); sb.Append(",Microsoft.VisualBasic.VBMath"); sb.Append(",Microsoft.VisualBasic.Information"); sb.Append(",Microsoft.VisualBasic.Interaction"); sb.Append(",Microsoft.VisualBasic.FileSystem"); sb.Append(",Microsoft.VisualBasic.Financial"); sb.Append(",Microsoft.VisualBasic.DateAndTime"); } else { start_pos = 0; sb.Append("Imports System"); sb.Append(",System.Collections.Generic"); sb.Append(",Microsoft.VisualBasic.Strings"); sb.Append(",Microsoft.VisualBasic.Constants"); sb.Append(",Microsoft.VisualBasic.VBMath"); sb.Append(",Microsoft.VisualBasic.Information"); sb.Append(",Microsoft.VisualBasic.Interaction"); sb.Append(",Microsoft.VisualBasic.FileSystem"); sb.Append(",Microsoft.VisualBasic.Financial"); sb.Append(",Microsoft.VisualBasic.DateAndTime"); sb.Append(":"); } sb.Append(source.Substring(start_pos, info.entry_method_name_pos - start_pos)); sb.Append("___"); sb.Append(source.Substring(info.entry_method_name_pos)); sw.Write(sb.ToString()); } else { sw.Write(source); } sw.Close(); 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 = FindFileInDirs("PABCRtl.dll", out _, 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) { comp_opt.ReferencedAssemblies.Add(Path.Combine(Path.GetDirectoryName(CompilerOptions.SourceFileName),mod+".dll")); string mod_file_name = FindSourceFileInDirectories(mod+".mod",Path.Combine(this.CompilerOptions.SystemDirectory,"lib")); File.Copy(mod_file_name,Path.Combine(Path.GetDirectoryName(CompilerOptions.SourceFileName),mod+".dll"),true); }*/ } sources.Add(redirect_fname); sources.Add(system_unit_name); System.CodeDom.Compiler.CompilerResults res = vbcp.CompileAssemblyFromFile(comp_opt, sources.ToArray()); if (res.Errors.Count > 0) { for (int i = 0; i < res.Errors.Count; i++) { if (!res.Errors[i].IsWarning && errorsList.Count == 0 /*&& dlls.Errors[i].file_name != redirect_fname*/) { if (File.Exists(res.Errors[i].FileName)) errorsList.Add(new Errors.CommonCompilerError(res.Errors[i].ErrorText, res.Errors[i].FileName, res.Errors[i].Line != 0 ? res.Errors[i].Line : 1, 1)); else errorsList.Add(new Errors.CommonCompilerError(res.Errors[i].ErrorText, CompilerOptions.SourceFileName, res.Errors[i].Line != 0 ? res.Errors[i].Line : 1, 1)); } else if (res.Errors[i].IsWarning) { warnings.Add(new Errors.CommonWarning(res.Errors[i].ErrorText, res.Errors[i].FileName, res.Errors[i].Line, 1)); } } } linesCompiled = get_compiled_lines(CompilerOptions.SourceFileName); if (info != null) { beginOffset = info.entry_method_line; //if (info.using_pos == -1) // beginOffset -= 1; } OnChangeCompilerState(this, CompilerState.CompilationFinished, CompilerOptions.SourceFileName); ClearAll(); File.Copy(fname, CompilerOptions.SourceFileName, true); File.Delete(fname); File.Delete(redirect_fname); OnChangeCompilerState(this, CompilerState.Ready, null); if (errorsList.Count > 0) return null; else return res.PathToAssembly; } private ProjectInfo project; private void PrepareCompileOptionsForProject() { project = new ProjectInfo(); project.Load(CompilerOptions.SourceFileName); //LoadProject(CompilerOptions.SourceFileName); switch (project.ProjectType) { case ProjectType.ConsoleApp: CompilerOptions.OutputFileType = CompilerOptions.OutputType.ConsoleApplicaton; break; case ProjectType.WindowsApp: CompilerOptions.OutputFileType = CompilerOptions.OutputType.WindowsApplication; break; case ProjectType.Library: CompilerOptions.OutputFileType = CompilerOptions.OutputType.ClassLibrary; break; } CompilerOptions.SourceFileName = project.main_file; CompilerOptions.Debug = project.include_debug_info; CompilerOptions.OutputFileName = project.output_file_name; CompilerOptions.OutputDirectory = project.output_directory; } public static bool CheckPathValid(string path) { return !Path.GetInvalidPathChars().Any(path.Contains); } public static void TryThrowInvalidPath(string path, SyntaxTree.SourceContext loc) { if (CheckPathValid(path)) return; throw new InvalidPathError(loc); } private void CompileUnitsFromDelayedList() { // проход по всем юнитам из списка отложенной компиляции foreach (CompilationUnit CurrentUnit in UnitsToCompileDelayedList) { if (CurrentUnit.State != UnitState.Compiled) { currentCompilationUnit = CurrentUnit; string unitFileName = currentCompilationUnit.SyntaxTree.file_name; // получение списка используемых модулей в файле (uses 1, 2, 3...) List implementationUsesList = GetImplementationUsesSection(CurrentUnit.SyntaxTree); CurrentUnit.possibleNamespaces.Clear(); if (HasIncludeNamespaceDirective(CurrentUnit)) CompilerOptions.UseDllForSystemUnits = false; if (implementationUsesList != null) { SetUseDLLForSystemUnits(Path.GetDirectoryName(unitFileName), implementationUsesList, implementationUsesList.Count - 1); for (int i = implementationUsesList.Count - 1; i >= 0; i--) { if (!IsPossibleNetNamespaceOrStandardPasFile(implementationUsesList[i], true, Path.GetDirectoryName(unitFileName))) { // докомпилируем юнит, если он не является пространством имен или стандартным pas файлом из Lib CompileUnit(CurrentUnit.ImplementationUsedUnits, CurrentUnit.ImplementationUsedDirectUnits, implementationUsesList[i], Path.GetDirectoryName(unitFileName)); } else { // добавление в списки только пространств имен CurrentUnit.ImplementationUsedUnits.AddElement(new namespace_unit_node(GetNamespace(implementationUsesList[i])), null); CurrentUnit.possibleNamespaces.Add(implementationUsesList[i]); } } } AddNamespacesToUsingList(CurrentUnit.ImplementationUsingNamespaceList, CurrentUnit.possibleNamespaces, true, null); // Console.WriteLine("Compiling implementation delayed " + unitFileName); CompileCurrentUnitImplementation(unitFileName, CurrentUnit, null); CurrentUnit.State = UnitState.Compiled; // отметка о скомпилированности OnChangeCompilerState(this, CompilerState.EndCompileFile, unitFileName); // состояние конец компиляции //SavePCU(compilationUnit, unitFileName); CurrentUnit.UnitFileName = unitFileName; } } } private void SetOutputFileTypeOption() { if (compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.compiler_directive_apptype)) { string directive = compilerDirectives[TreeConverter.compiler_string_consts.compiler_directive_apptype][0].directive.ToLower(); switch (directive) { case "console": CompilerOptions.OutputFileType = CompilerOptions.OutputType.ConsoleApplicaton; break; case "windows": CompilerOptions.OutputFileType = CompilerOptions.OutputType.WindowsApplication; break; case "dll": CompilerOptions.OutputFileType = CompilerOptions.OutputType.ClassLibrary; break; case "pcu": CompilerOptions.OutputFileType = CompilerOptions.OutputType.PascalCompiledUnit; break; default: throw new Exception("No possible OutputFileType!"); } } } private void SetOutputPlatformOption(NETGenerator.CompilerOptions compilerOptions) { List compilerDirectivesList = new List(); if (compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.compiler_directive_platformtarget, out compilerDirectivesList)) { string plt = compilerDirectivesList[0].directive.ToLower(); switch (plt) { case "x86": compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.x86; break; case "x64": compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.x64; break; case "anycpu": compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.AnyCPU; break; case "dotnet5win": compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.dotnet5win; break; case "dotnet5linux": compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.dotnet5linux; break; case "dotnet5macos": compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.dotnet5macos; break; case "native": if (Environment.OSVersion.Platform == PlatformID.Unix) { compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.dotnetlinuxnative; } else if (Environment.OSVersion.Platform == PlatformID.MacOSX) { compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.dotnetmacosnative; } else { compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.dotnetwinnative; } break; default: throw new Exception("Unknown platform!"); } if (CompilerOptions.Only32Bit) compilerOptions.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.x86; // целевой framework if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.compiler_directive_targetframework, out compilerDirectivesList)) { compilerOptions.TargetFramework = compilerDirectivesList[0].directive; if (!(new string[] { "net40", "net403", "net45", "net451", "net452", "net46", "net461", "net462", "net47", "net471", "net472", "net48", "net481" }) .Contains(compilerOptions.TargetFramework)) ErrorsList.Add(new UnsupportedTargetFramework(compilerOptions.TargetFramework, compilerDirectivesList[0].location)); } } } private void FillCompilerInfoOptions(NETGenerator.CompilerOptions compilerOptions) { var compilerDirectives = new List(); if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.product_string, out compilerDirectives)) { compilerOptions.Product = compilerDirectives[0].directive; } if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.version_string, out compilerDirectives)) { compilerOptions.ProductVersion = compilerDirectives[0].directive; } if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.company_string, out compilerDirectives)) { compilerOptions.Company = compilerDirectives[0].directive; } if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.trademark_string, out compilerDirectives)) { compilerOptions.TradeMark = compilerDirectives[0].directive; } if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.copyright_string, out compilerDirectives)) { compilerOptions.Copyright = compilerDirectives[0].directive; } if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.title_string, out compilerDirectives)) { compilerOptions.Title = compilerDirectives[0].directive; } if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.description_string, out compilerDirectives)) { compilerOptions.Description = compilerDirectives[0].directive; } if (this.compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.main_resource_string, out compilerDirectives)) { if (this.compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.product_string) || this.compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.version_string) || this.compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.company_string) || this.compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.trademark_string) || this.compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.title_string) || this.compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.description_string) || this.compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.copyright_string)) { ErrorsList.Add(new MainResourceNotAllowed(compilerDirectives[0].location)); } TryThrowInvalidPath(compilerDirectives[0].directive, compilerDirectives[0].location); // Тут не обязательно нормализовывать путь // И если он слишком длинный - File.Exists вернёт false compilerOptions.MainResourceFileName = Path.Combine(Path.GetDirectoryName(compilerDirectives[0].source_file), compilerDirectives[0].directive); if (!File.Exists(compilerOptions.MainResourceFileName)) ErrorsList.Add(new ResourceFileNotFound(compilerDirectives[0].directive, compilerDirectives[0].location)); } } private void FillCompilerOptionsFromProject(NETGenerator.CompilerOptions compilerOptions) { if (project != null) { if (!(project.major_version == 0 && project.minor_version == 0 && project.build_version == 0 && project.revision_version == 0)) compilerOptions.ProductVersion = project.major_version + "." + project.minor_version + "." + project.build_version + "." + project.revision_version; if (!string.IsNullOrEmpty(project.product)) compilerOptions.Product = project.product; if (!string.IsNullOrEmpty(project.company)) compilerOptions.Company = project.company; if (!string.IsNullOrEmpty(project.trademark)) compilerOptions.TradeMark = project.trademark; if (!string.IsNullOrEmpty(project.copyright)) compilerOptions.Copyright = project.copyright; if (!string.IsNullOrEmpty(project.title)) compilerOptions.Title = project.title; if (!string.IsNullOrEmpty(project.description)) compilerOptions.Description = project.description; if (project.ProjectType == ProjectType.WindowsApp) compilerOptions.target = NETGenerator.TargetType.WinExe; // возможно, требуется переименование EVA // CreateRCFile(compilerOptions); } } private void CreateRCFile(NETGenerator.CompilerOptions compilerOptions) { if (!string.IsNullOrEmpty(project.app_icon)) { //cdo.MainResourceFileName = project.app_icon; string rc_file = Path.GetFileNameWithoutExtension(project.app_icon) + ".rc"; StreamWriter sw = File.CreateText(rc_file); sw.WriteLine("1 ICON \"" + project.app_icon.Replace("\\", "\\\\") + "\""); if (compilerOptions.NeedDefineVersionInfo) { compilerOptions.NeedDefineVersionInfo = false; sw.WriteLine("1 VERSIONINFO"); string ver = project.major_version + "," + project.minor_version + "," + project.build_version + "," + project.revision_version; sw.WriteLine("FILEVERSION " + ver); /*sw.WriteLine("FILEFLAGSMASK VS_FFI_FILEFLAGSMASK"); sw.WriteLine("FILEFLAGS VER_DEBUG"); sw.WriteLine("FILEOS VOS__WINDOWS32"); if (project.project_type != ProjectType.Library) sw.WriteLine("FILETYPE VFT_APP"); else sw.WriteLine("FILETYPE VFT_DLL"); sw.WriteLine("FILESUBTYPE VFT2_UNKNOWN");*/ sw.WriteLine("BEGIN \r\n BLOCK \"StringFileInfo\"\r\n BEGIN \r\n BLOCK \"041904E3\"\r\nBEGIN"); sw.WriteLine("VALUE \"ProductName\"," + "\"" + compilerOptions.Product + "\""); sw.WriteLine("VALUE \"FileVersion\"," + "\"" + ver + "\""); sw.WriteLine("VALUE \"ProductVersion\"," + "\"" + ver + "\""); sw.WriteLine("VALUE \"FileDescription\"," + "\"" + compilerOptions.Description + "\""); sw.WriteLine("VALUE \"OriginalFileName\"," + "\"" + Path.GetFileName(CompilerOptions.OutputFileName) + "\""); sw.WriteLine("VALUE \"InternalName\"," + "\"" + Path.GetFileNameWithoutExtension(CompilerOptions.OutputFileName) + "\""); sw.WriteLine("VALUE \"CompanyName\"," + "\"" + compilerOptions.Company + "\""); sw.WriteLine("VALUE \"LegalTrademarks1\"," + "\"" + compilerOptions.TradeMark + "\""); sw.WriteLine("VALUE \"LegalCopyright\"," + "\"" + compilerOptions.Copyright + "\""); sw.WriteLine("END"); sw.WriteLine("END"); sw.WriteLine("BLOCK \"VarFileInfo\"\r\nBEGIN"); sw.WriteLine("VALUE \"Translation\", 0x0419, 1251"); sw.WriteLine("END"); sw.WriteLine("END"); } sw.Close(); System.Diagnostics.Process prc = new System.Diagnostics.Process(); prc.StartInfo.FileName = Path.Combine(this.CompilerOptions.SystemDirectory, "rc.exe"); prc.StartInfo.Arguments = Path.Combine(Path.GetDirectoryName(project.app_icon), Path.GetFileNameWithoutExtension(project.app_icon) + ".rc"); prc.StartInfo.CreateNoWindow = true; prc.StartInfo.UseShellExecute = false; prc.StartInfo.RedirectStandardOutput = true; prc.StartInfo.RedirectStandardError = true; prc.Start(); prc.WaitForExit(); string res_file = Path.Combine(Path.GetDirectoryName(project.app_icon), Path.GetFileNameWithoutExtension(project.app_icon) + ".res"); if (File.Exists(res_file)) { compilerOptions.MainResourceFileName = res_file; // !!! главный ресурсный файл } File.Delete(rc_file); } } private void SetTargetTypeOption(NETGenerator.CompilerOptions compilerOptions) { compilerOptions.ForRunningWithEnvironment = CompilerOptions.RunWithEnvironment; // тип выходного файла if (compilerOptions.target == NETGenerator.TargetType.Exe) // если еще не установлен согласно проекту { switch (CompilerOptions.OutputFileType) { case CompilerOptions.OutputType.ClassLibrary: compilerOptions.target = NETGenerator.TargetType.Dll; break; case CompilerOptions.OutputType.ConsoleApplicaton: compilerOptions.target = NETGenerator.TargetType.Exe; break; case CompilerOptions.OutputType.WindowsApplication: compilerOptions.target = NETGenerator.TargetType.WinExe; break; } } // Debug / Release compilerOptions.dbg_attrs = CompilerOptions.Debug ? NETGenerator.DebugAttributes.Debug : NETGenerator.DebugAttributes.Release; if (CompilerOptions.ForDebugging) compilerOptions.dbg_attrs = NETGenerator.DebugAttributes.ForDebugging; } public string Compile() { try { // компиляция C# if (Path.GetExtension(CompilerOptions.SourceFileName) == ".cs") { return CompileCS(); } // вызов события смены состояния компилятора - начало компиляции // событие имеет много потенциальных обработчиков OnChangeCompilerState(this, CompilerState.CompilationStarting, CompilerOptions.SourceFileName); // очистка всех переменных и списков, используемых в процессе Reset(); // если проект скомпилирован, то заполнение информации о проекте в опциях компилятора if (CompilerOptions.ProjectCompiled) { PrepareCompileOptionsForProject(); } #region CONSTRUCTING SYNTAX AND SEMANTIC TREES STAGE // компиляция всех юнитов произойдет рекурсивно (кроме отложенных) CompileUnit( new unit_node_list(), new Dictionary(), new SyntaxTree.uses_unit_in(null, new SyntaxTree.string_const(Path.GetFullPath(CompilerOptions.SourceFileName))), null); // компиляция юнитов из списка отложенной компиляции, если он не пуст CompileUnitsFromDelayedList(); #endregion // Закрытие чтения и записи .pcu файлов ClosePCUReadersAndWriters(); PrebuildMainSemanticTreeActions(out var compilerOptions, out var resourceFiles); #region GENERATING CODE STAGE if (ErrorsList.Count == 0) { //TODO: Разобратся c location для program_node и правильно передавать main_function. Добавить генератор main_function в SyntaxTreeToSemanticTreeConverter. | Думать позже EVA // получние полного семантического дерева, включающего все зависимости program_node semanticTree = ConstructMainSemanticTree(compilerOptions); if (firstCompilationUnit.SyntaxTree is SyntaxTree.unit_module && CompilerOptions.OutputFileType != CompilerOptions.OutputType.ClassLibrary) { // если мы комилируем PCU CompilerOptions.OutputFileType = CompilerOptions.OutputType.PascalCompiledUnit; } // генерация IL кода else if (CompilerOptions.GenerateCode) { if (CompilerOptions.UseDllForSystemUnits) compilerOptions.RtlPABCSystemType = NetHelper.NetHelper.FindRtlType("PABCSystem.PABCSystem"); GenerateILCode(semanticTree, compilerOptions, resourceFiles); } } #endregion } // TODO: просмотреть возможные ParserError EVA catch (TreeConverter.ParserError) { // конвертор уткнулся в ошибку. ничего не делаем } catch (CompilerInternalError err) { AddInternalErrorToErrorList(err); } catch (Error err) { // здесь учитывается позиция Located error AddErrorToErrorListConsideringPosition(err); } catch (Exception err) { // здесь добавляются только ошибки генерации кода AddCodeGenerationErrorToErrorList(err); } // на случай если мы вывалились по исключению, но у нас есть откомпилированные модули try { ClosePCUReadersAndWriters(); } catch (Exception e) { ErrorsList.Add(new CompilerInternalError("Compiler.ClosePCUReadersAndWriters", e)); } // на случай ошибки в самом .pcu формате (имеются в виду ошибки, связанные с невозможностью использования RTL) bool recompilationNeeded = CheckForRTLErrors(); OnChangeCompilerState(this, CompilerState.CompilationFinished, CompilerOptions.SourceFileName); // compilation finished state if (ClearAfterCompilation) ClearAll(); if (!recompilationNeeded) OnChangeCompilerState(this, CompilerState.Ready, null); // компилятор окончательно завершил работу if (ErrorsList.Count > 0) { return null; } else if (recompilationNeeded) { //Compiler c = new Compiler(sourceFilesProvider,OnChangeCompilerState); //return c.Compile(this.compilerOptions); return Compile(); } else return CompilerOptions.OutputFileName; } private void PrebuildMainSemanticTreeActions(out NETGenerator.CompilerOptions compilerOptions, out List resourceFiles) { if (CompilerOptions.SaveDocumentation) { SaveDocumentationsForUnits(); } compilerDirectives = GetCompilerDirectives(UnitsLogicallySortedList); // выяснение типа выходного файла по соотв. директиве компилятора SetOutputFileTypeOption(); // перемещаем PABCSystem в начало списка MoveSystemUnitForwardInUnitLogicallySortedList(); // передача информации о типе выходного файла системному юниту if (UnitsLogicallySortedList.Count > 0) { bool isConsoleApplication = CompilerOptions.OutputFileType == CompilerOptions.OutputType.ConsoleApplicaton; common_unit_node systemUnit = UnitsLogicallySortedList[0].SemanticTree as common_unit_node; systemUnit.IsConsoleApplicationVariable = isConsoleApplication; } compilerOptions = new NETGenerator.CompilerOptions(); // выяснение целевой платформы SetOutputPlatformOption(compilerOptions); // остальные директивы FillCompilerInfoOptions(compilerOptions); // заполнение опций компилятора из заголовка проекта FillCompilerOptionsFromProject(compilerOptions); // Устанавливает опции компилятора, связанные с типом выходного файла SetTargetTypeOption(compilerOptions); resourceFiles = GetResourceFilesFromCompilerDirectives(); } private program_node ConstructMainSemanticTree(NETGenerator.CompilerOptions compilerOptions) { program_node mainSemanticTree = new program_node(null, null); for (int i = 0; i < UnitsLogicallySortedList.Count; i++) mainSemanticTree.units.AddElement(UnitsLogicallySortedList[i].SemanticTree as common_unit_node); bool targetTypeIsExe = compilerOptions.target == NETGenerator.TargetType.Exe || compilerOptions.target == NETGenerator.TargetType.WinExe; // если компилируем exe или WinExe (первый модуль - основная программа) if (firstCompilationUnit.SyntaxTree is SyntaxTree.program_module && targetTypeIsExe && UnitsLogicallySortedList.Count > 0) { mainSemanticTree.main_function = ((common_unit_node)UnitsLogicallySortedList.Last().SemanticTree).main_function; PrepareFinalMainFunctionForExe(mainSemanticTree); } // если мы компилируем dll else if (firstCompilationUnit.SyntaxTree is SyntaxTree.unit_module) { // TODO: посмотреть инициализирующий код .dll EVA mainSemanticTree.create_main_function_as_in_module(); } if (CompilerOptions.GenerateCode) // семантические преобразования с оптимизацией кода mainSemanticTree = semanticTreeConvertersController.Convert(mainSemanticTree) as program_node; semanticTree = mainSemanticTree; return mainSemanticTree; } public void PrepareFinalMainFunctionForExe(program_node mainSemanticTree) { // вычисляем номер строку первой переменной и строки с началом основной программы if (mainSemanticTree.main_function.function_code.location != null) { common_namespace_node main_ns = mainSemanticTree.main_function.namespace_node; foreach (namespace_variable variable in main_ns.variables) { if (variable.inital_value?.location != null && !(variable.inital_value is constant_node) && !(variable.inital_value is record_initializer) && !(variable.inital_value is array_initializer)) { varBeginOffset = variable.inital_value.location.begin_line_num; break; } } beginOffset = mainSemanticTree.main_function.function_code.location.begin_line_num; } // локализация Dictionary config_dict = new Dictionary(); if (CompilerOptions.Locale != null && StringResourcesLanguage.GetLCIDByTwoLetterISO(CompilerOptions.Locale) != null) { config_dict["locale"] = CompilerOptions.Locale; config_dict["full_locale"] = StringResourcesLanguage.GetLCIDByTwoLetterISO(CompilerOptions.Locale); } mainSemanticTree.create_main_function(StandardModules.ToArray(), config_dict); } private void AddErrorToErrorListConsideringPosition(Error err) { if (ErrorsList.Count == 0) ErrorsList.Add(err); else if (err != ErrorsList[0]) { if (err is SemanticError) { int position = FindPositionForSemanticErrorInTheErrorList(err); // семантические ошибки отсортированы по location ErrorsList.Insert(position, err); } else ErrorsList.Add(err); } } private int FindPositionForSemanticErrorInTheErrorList(Error err) { int position = ErrorsList.Count; SourceLocation location = (err as SemanticError).SourceLocation; SourceLocation locationTemp; if (location != null) { for (int i = 0; i < ErrorsList.Count; i++) { if ((locationTemp = (ErrorsList[i] as LocatedError)?.SourceLocation) != null) { if (locationTemp > location) { position = i; break; } } } } return position; } private void AddCodeGenerationErrorToErrorList(Exception err) { string fileName = Path.GetFileName(currentCompilationUnit?.SyntaxTree?.file_name) ?? "Compiler"; CompilerInternalError compilationError = new CompilerInternalError(string.Format("Compiler.Compile[{0}]", fileName), err); AddInternalErrorToErrorList(compilationError); } private void AddInternalErrorToErrorList(CompilerInternalError internalError) { if (ErrorsList.Count == 0) ErrorsList.Add(internalError); else { #if DEBUG if (!InternalDebug.SkipInternalErrorsIfSyntaxTreeIsCorrupt) ErrorsList.Add(internalError); #endif } } private bool CheckForRTLErrors() { bool anyRTLErrors = false; if (ErrorsList.Count > 0) { if (CompilerOptions.UseDllForSystemUnits && !HasOnlySyntaxErrors(ErrorsList) && CompilerOptions.IgnoreRtlErrors) { CompilerOptions.UseDllForSystemUnits = false; ErrorsList.Clear(); anyRTLErrors = true; } } return anyRTLErrors; } private void GenerateILCode(program_node programNode, NETGenerator.CompilerOptions compilerOptions, List resourceFiles) { if (CompilerOptions.OutputFileType != CompilerOptions.OutputType.SemanticTree) #if DEBUG if (InternalDebug.CodeGeneration) #endif { // генерация файла .pdb для дебага DebugOutputFileCreationUsingPDB(); OnChangeCompilerState(this, CompilerState.CodeGeneration, CompilerOptions.OutputFileName); // состояние генерации кода // трансляция в IL-код | В semanticTree находится ЕДИНСТВЕННОЕ семантическое дерево, содержащее программу и все семантические модули CodeGeneratorsController.GenerateILCodeAndSaveAssembly(programNode, CompilerOptions.OutputFileName, CompilerOptions.SourceFileName, compilerOptions, CompilerOptions.StandardDirectories, resourceFiles?.ToArray()); CodeGeneratorsController.EmitAssemblyRedirects( assemblyResolveScope, CompilerOptions.OutputFileName); if (compilerOptions.MainResourceFileName != null) File.Delete(compilerOptions.MainResourceFileName); } } private void DebugOutputFileCreationUsingPDB() { int n = 1; try { n = 2; var fs = File.Create(CompilerOptions.OutputFileName); n = 3; fs.Close(); n = 4; ///////File.Delete(CompilerOptions.OutputFileName); string pdb_file_name = Path.ChangeExtension(CompilerOptions.OutputFileName, ".pdb"); if (File.Exists(pdb_file_name)) File.Delete(pdb_file_name); n = 5; // PVS 01/2022 } catch (Exception e) { throw new UnauthorizedAccessToFile(CompilerOptions.OutputFileName + " -- " + n + " " + e.ToString()); //throw e; } } private List GetResourceFilesFromCompilerDirectives() { List ResourceFiles = null; if (compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.compiler_directive_resource)) { ResourceFiles = new List(); List ResourceDirectives = compilerDirectives[TreeConverter.compiler_string_consts.compiler_directive_resource]; foreach (compiler_directive cd in ResourceDirectives) { TryThrowInvalidPath(cd.directive, cd.location); var resourceFileName = Path.Combine(Path.GetDirectoryName(cd.source_file), cd.directive); // Так же как с main_resource if (File.Exists(resourceFileName)) ResourceFiles.Add(resourceFileName); else ErrorsList.Add(new ResourceFileNotFound(cd.directive, cd.location)); } } return ResourceFiles; } private bool HasOnlySyntaxErrors(List errors) { foreach (Error err in errors) { if (!(err is SyntaxError)) return false; } return true; } private void SaveDocumentationsForUnits() { DocXmlManager dxm = new DocXmlManager(); foreach (CompilationUnit cu in UnitsLogicallySortedList) { if (cu.Documented) dxm.SaveXml(cu); } } private void ClosePCUReadersAndWriters() { if (PCUReadersAndWritersClosed) return; PCUReadersAndWritersClosed = true; bool all_restored = false; while (!all_restored) { foreach (PCUReader p in PCUReader.AllReaders) { p.AddInitFinalMethods(); SystemLibrary.SystemLibInitializer.RestoreStandardFunctions(); p.ProcessWaitedToRestoreFields(); p.RestoreWaitedMethodCodes(); } bool rest = true; for (int i = 0; i < PCUReader.AllReaders.Count; i++) if (PCUReader.AllReaders[i].waited_types_to_restore_fields.Count != 0) { rest = false; break; } all_restored = rest; } PCUReader.AddUsedMembersInAllUnits(); if (CompilerOptions.SavePCUInThreadPull) AsyncClosePCUWriters(); else ClosePCUWriters(); } void WaitCallback_ClosePCUWriters(object state) { ClosePCUWriters(); } private void AsyncClosePCUWriters() { System.Threading.ThreadPool.QueueUserWorkItem(WaitCallback_ClosePCUWriters); } private void ClosePCUWriters() { foreach (CompilationUnit cu in UnitsLogicallySortedList) { SavePCU(cu); } foreach (PCUWriter pw in PCUWriter.AllWriters) { pw.CloseWriter(); } } /// /// Бросает ошибку если находит дупликаты в секции uses /// void CheckForDuplicatesInUsesSection(List usesList) { if (usesList == null) return; List names = new List(); foreach (SyntaxTree.unit_or_namespace un in usesList) { string name = SyntaxTree.Utils.IdentListToString(un.name.idents, ".").ToLower(); if (un.source_context != null) { if (names.Contains(name)) throw new DuplicateUsesUnit(currentCompilationUnit.SyntaxTree.file_name, name, un.source_context); else names.Add(name); } } } /// /// Возвращает список зависимостей из интерфейсной части модуля (или основной программы) /// public List GetInterfaceUsesSection(SyntaxTree.compilation_unit unitSyntaxTree) { List usesList = null; if (unitSyntaxTree is SyntaxTree.unit_module unitModule) { if (unitModule.interface_part.uses_modules == null) { if (CompilerOptions.StandardModules.Count > 0) { unitModule.interface_part.uses_modules = new SyntaxTree.uses_list(); unitModule.interface_part.uses_modules.source_context = new SyntaxTree.SourceContext(); } else return null; } usesList = unitModule.interface_part.uses_modules.units; } else if (unitSyntaxTree is SyntaxTree.program_module programModule) { if (programModule.used_units == null) { if (CompilerOptions.StandardModules.Count > 0) { programModule.used_units = new SyntaxTree.uses_list(); programModule.used_units.source_context = new SyntaxTree.SourceContext(); } else return null; } usesList = programModule.used_units.units; } CheckForDuplicatesInUsesSection(usesList); return usesList; } private List GetImplementationUsesSection(SyntaxTree.compilation_unit unitSyntaxTree) { List usesSection = (unitSyntaxTree as SyntaxTree.unit_module)?.implementation_part?.uses_modules?.units; CheckForDuplicatesInUsesSection(usesSection); return usesSection; } public string FindPCUFileName(string fname, string curr_path, out int folder_priority) { 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)) { if (FindFileInDirs(fname, out _, curr_path) is string res_s1) res = Tuple.Create(res_s1, 1); else if (FindFileInDirs(Path.GetFileName(fname), out _, CompilerOptions.OutputDirectory) is string res_s2) res = Tuple.Create(res_s2, 2); else if (FindFileInDirs(fname, out var dir_ind, CompilerOptions.SearchDirectory.ToArray()) is string res_s3) res = Tuple.Create(res_s3, 3 + dir_ind); else res = null; PCUFileNamesDictionary[cache_key] = res; } folder_priority = res == null ? 0 : res.Item2; return res?.Item1; } public string FindSourceFileName(string fname, string curr_path, out int folder_priority) { var cache_key = Tuple.Create(fname.ToLower(), curr_path?.ToLower()); if (!SourceFileNamesDictionary.TryGetValue(cache_key, out var res)) { if (FindSourceFileNameInDirs(fname, out _, curr_path) is string res_s1) res = Tuple.Create(res_s1, 1); else if (FindSourceFileNameInDirs(fname, out var dir_ind, CompilerOptions.SearchDirectory.ToArray()) is string res_s3) res = Tuple.Create(res_s3, 3 + dir_ind); else res = null; SourceFileNamesDictionary[cache_key] = res; } folder_priority = res == null ? 0 : res.Item2; return res?.Item1; } public string FindSourceFileNameInDirs(string fname, out int found_dir_ind, params string[] Dirs) { var fname_ext = Path.GetExtension(fname); var need_ext = string.IsNullOrEmpty(fname_ext); foreach (SupportedSourceFile sf in SupportedSourceFiles) foreach (string ext in sf.Extensions) if (need_ext || fname_ext == ext) { var res = FindFileInDirs(need_ext ? fname + ext : fname, out found_dir_ind, Dirs); //if (!(CompilerOptions.UseDllForSystemUnits && Path.GetDirectoryName(dlls) == CompilerOptions.SearchDirectory)) if (res != null) return res; } found_dir_ind = 0; return null; } public static string CombinePathsRelatively(string path1, string path2) { if (Path.IsPathRooted(path2)) return path2; int i = 0; foreach (var s in path2.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar })) { if (s == ".") continue; if (s == ".." && !string.IsNullOrWhiteSpace(path1) && !path1.EndsWith("..")) { path1 = Path.GetDirectoryName(path1); if (path1 == null) return null; // Path.GetDirectoryName("C:\") возвращает null } else path1 = Path.Combine(path1, s); } return path1; } public static string GetUnitPath(CompilationUnit u1, CompilationUnit u2) { if (u1 == null) throw new ArgumentNullException(nameof(u1)); if (u2 == null) throw new ArgumentNullException(nameof(u2)); var curr = new Dictionary(); var done = new HashSet(); var res_path = default(string); Func register_unit = (CompilationUnit u, string path) => { if (!done.Add(u)) return true; if (u == u2) { res_path = path; return false; } curr.Add(u, path); return true; }; if (!u1.ForEachDirectCompilationUnit(register_unit)) return res_path; while (curr.Count != 0) { var prev = curr; curr = new Dictionary(); foreach (var kvp in prev) if (!kvp.Key.ForEachDirectCompilationUnit((u, path) => { // Важно "..\a\b" + "..\c\d" превращать в "..\a\c\d", а не полный путь return register_unit(u, CombinePathsRelatively(Path.GetDirectoryName(kvp.Value), path)); })) return res_path; } throw new InvalidOperationException($"Could not find path to \"{u2.UnitFileName}\" relative to \"{u1.UnitFileName}\""); } private string FindFileInDirs(string FileName, out int found_dir_ind, params string[] Dirs) { if (Path.IsPathRooted(FileName)) { found_dir_ind = 0; return File.Exists(FileName) ? FileName : null; } for (int dir_i = 0; dir_i < Dirs.Length; ++dir_i) try { var Dir = Dirs[dir_i]; var res = Path.Combine(Dir, FileName); if (File.Exists(res)) { found_dir_ind = dir_i; // Path.GetFullPath чтобы нормализовать // File.Exists не может кинуть исключение или дать true // если путь слишком длинный или содержит нерпавильные знаки return Path.GetFullPath(res); } } catch (PathTooLongException) { continue; } found_dir_ind = 0; return null; } public static string GetReferenceFileName(string FileName, string curr_path = null) { // Вначале - кешированные стандартные dll if (standart_assembly_dict.ContainsKey(FileName)) return standart_assembly_dict[FileName]; if (curr_path != null && System.IO.File.Exists(Path.Combine(curr_path, FileName))) return Path.Combine(curr_path, FileName); if (System.IO.File.Exists(FileName)) { return FileName;//.ToLower();//? а надо ли tolover? } else { return get_assembly_path(FileName, false); } } private string GetReferenceFileName(string FileName, SyntaxTree.SourceContext sc, string curr_path, bool overwrite) { FileName = FileName.Trim(); if (standart_assembly_dict.ContainsKey(FileName)) return standart_assembly_dict[FileName]; // Наверное, этот код MikhailoMMX лишний //MikhailoMMX PABCRtl.dll будем искать сначала в GAC, а потом в папке с программой if (FileName == TreeConverter.compiler_string_consts.pabc_rtl_dll_name) { string name = get_assembly_path(FileName, true); if ((name != null) && (File.Exists(name))) return name; } //\MikhailoMMX try { var FullFileName = Path.Combine(curr_path, FileName); if (System.IO.File.Exists(FullFileName)) { var NewFileName = Path.Combine(CompilerOptions.OutputDirectory, Path.GetFileName(FullFileName)); if (FullFileName != NewFileName) { if (overwrite) File.Copy(FullFileName, NewFileName, true); else if (!File.Exists(NewFileName)) File.Copy(FullFileName, NewFileName, false); } return NewFileName; } else { string name = get_assembly_path(FileName, false);//? а надо ли tolover? if (name == null) throw new AssemblyNotFound(currentCompilationUnit.SyntaxTree.file_name, FileName, sc); else if (File.Exists(name)) return name; else throw new AssemblyNotFound(currentCompilationUnit.SyntaxTree.file_name, FileName, sc); } } catch (ArgumentException ex) { throw new InvalidAssemblyPathError(currentCompilationUnit.SyntaxTree.file_name, sc); } } public string GetUnitFileName(SyntaxTree.unit_or_namespace unitNode, string currentPath) { if (unitNode is SyntaxTree.uses_unit_in unitNodeCasted && unitNodeCasted.name == null) return unitNodeCasted.in_file.Value; if (currentPath == null) throw new InvalidOperationException(unitNode.UsesPath()); var UnitName = unitNode.name.idents[0].name; if (unitNode is SyntaxTree.uses_unit_in uui) { TryThrowInvalidPath(uui.in_file.Value, uui.in_file.source_context); if (UnitName.ToLower() != Path.GetFileNameWithoutExtension(uui.in_file.Value).ToLower()) throw new UsesInWrongName(unitNode.source_context.FileName, UnitName, Path.GetFileNameWithoutExtension(uui.in_file.Value), uui.in_file.source_context); } return GetUnitFileName(UnitName, unitNode.UsesPath(), currentPath, unitNode.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 || !SourceFileExists) && PCUFileName != null; if (!PCUFileExists && !SourceFileExists) if (UnitName == null) // вызов с "unitFileName == null" должен быть только там, где уже известно что хотя бы какой то файл есть // если где то ещё будет исопльзоваться unitFileName или source_context - надо будет добавить такую же проверку throw new InvalidOperationException(nameof(UnitName)); else throw new UnitNotFound(source_context.FileName, 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; } public void AddStandardUnitsToInterfaceUsesSection(SyntaxTree.compilation_unit unitSyntaxTree) { if (CompilerOptions.StandardModules.Count == 0) return; List usesList = GetInterfaceUsesSection(unitSyntaxTree); string currentModuleName = Path.GetFileNameWithoutExtension(unitSyntaxTree.file_name).ToLower(); foreach (CompilerOptions.StandardModule module in CompilerOptions.StandardModules) { string moduleName = Path.GetFileNameWithoutExtension(module.Name); if (moduleName.ToLower() == currentModuleName) return; } foreach (CompilerOptions.StandardModule module in CompilerOptions.StandardModules) { if ((module.AddToLanguages & firstCompilationUnit.SyntaxTree.Language) != firstCompilationUnit.SyntaxTree.Language && (module.AddToLanguages & currentCompilationUnit.SyntaxTree.Language) != currentCompilationUnit.SyntaxTree.Language) continue; if (module.AddMethod == CompilerOptions.StandardModuleAddMethod.RightToMain && currentCompilationUnit != firstCompilationUnit) continue; string moduleName = Path.GetFileNameWithoutExtension(module.Name); // если стандартный модуль уже подключен bool isModuleAlreadyInUsesSection = false; foreach (SyntaxTree.unit_or_namespace currentUnitNode in usesList) { if (currentUnitNode.name.idents.Count == 1 && currentUnitNode.name.idents[0].name.ToLower() == moduleName.ToLower()) { isModuleAlreadyInUsesSection = true; break; } } if (isModuleAlreadyInUsesSection) continue; // здесь присвоится либо паскалевский юнит, либо пространство имен SyntaxTree.unit_or_namespace unitToAdd; if (Path.GetExtension(module.Name) != "" /*&& Path.GetExtension(ModuleFileName).ToLower() != ".dll"*/) { unitToAdd = new SyntaxTree.uses_unit_in( new SyntaxTree.ident_list(new SyntaxTree.ident(moduleName)), 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); Вопрос EVA } else { unitToAdd = 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); } // добавление if (module.AddMethod == CompilerOptions.StandardModuleAddMethod.RightToMain) { usesList.Add(unitToAdd); } else if (module.AddMethod == CompilerOptions.StandardModuleAddMethod.LeftToAll) { usesList.Insert(0, unitToAdd); } } } private Assembly PreloadReference(compiler_directive reference) { var sc = GetSourceContext(reference); var fileName = GetReferenceFileName(reference.directive, sc, Path.GetDirectoryName(reference.source_file), true); return assemblyResolveScope.PreloadAssembly(fileName); } private CompilationUnit CompileReference(unit_node_list dlls, compiler_directive reference) { var sourceContext = GetSourceContext(reference); string unitName; try { unitName = GetReferenceFileName(reference.directive, sourceContext, Path.GetDirectoryName(reference.source_file), false); } catch (AssemblyNotFound) { throw; } // ToDo плохо, пока дебажил - тут постоянно ловились другие исключения, не связанные с неправильным знаками в пути к сборке | // EVA (проверить) catch (Exception) { throw new InvalidAssemblyPathError(currentCompilationUnit.SyntaxTree.file_name, sourceContext); } CompilationUnit currentUnit = null; if (UnitTable.Count == 0) throw new ProgramModuleExpected(unitName, null); if ((currentUnit = ReadDLL(unitName, sourceContext)) != null) { dlls.AddElement(currentUnit.SemanticTree, null); UnitTable[unitName] = currentUnit; return currentUnit; } else throw new AssemblyReadingError(currentCompilationUnit.SyntaxTree.file_name, unitName, sourceContext); } private SyntaxTree.SourceContext GetSourceContext(compiler_directive directive) { var loc = directive.location; if (loc == null) return null; return new SyntaxTree.SourceContext(loc.begin_line_num, loc.begin_column_num, loc.end_line_num, loc.end_column_num, 0, 0); } private bool HasIncludeNamespaceDirective(CompilationUnit unit) { var directives = GetDirectivesAsSemanticNodes(unit.SyntaxTree.compiler_directives, unit.SyntaxTree.file_name); return directives.Any(directive => directive.name.ToLower() == TreeConverter.compiler_string_consts.include_namespace_directive); } private Dictionary PrepareUserNamespacesUsedInTheCurrentUnit(CompilationUnit compilationUnit) { var directives = GetDirectivesAsSemanticNodes(compilationUnit.SyntaxTree.compiler_directives, compilationUnit.SyntaxTree.file_name); List files = GetIncludedFilesFromDirectives(compilationUnit, directives); Dictionary namespaces = new Dictionary(StringComparer.OrdinalIgnoreCase); List namespaceModules = new List(); foreach (string file in files) { SyntaxTree.compilation_unit syntaxTree = GetNamespaceSyntaxTree(file); #region SEMANTIC CHECKS : PASCAL NAMESPACE SemanticCheckIsPascalNamespace(syntaxTree); #endregion SyntaxTree.unit_module unitModule = syntaxTree as SyntaxTree.unit_module; SyntaxTree.syntax_namespace_node namespaceNode = null; if (!namespaces.TryGetValue(unitModule.unit_name.idunit_name.name, out namespaceNode)) { namespaceNode = new SyntaxTree.syntax_namespace_node(unitModule.unit_name.idunit_name.name); namespaceNode.referenced_units = new unit_node_list(); namespaces[unitModule.unit_name.idunit_name.name] = namespaceNode; } AddDeclarationsAndReferencedUnitsToNamespaces(namespaceModules, file, unitModule, namespaceNode); } // TODO: выделить в другой метод SyntaxTree.unit_module mainLibrary = compilationUnit.SyntaxTree as SyntaxTree.unit_module; SyntaxTree.program_module main_program = compilationUnit.SyntaxTree as SyntaxTree.program_module; foreach (string s in namespaces.Keys) { if (mainLibrary != null) mainLibrary.interface_part.interface_definitions.Insert(0, namespaces[s]); else main_program.program_block.defs.Insert(0, namespaces[s]); } SyntaxTree.uses_list mainUsesList = GetMainUsesList(mainLibrary, main_program, namespaceModules); if (mainLibrary != null) mainLibrary.interface_part.uses_modules = mainUsesList; else main_program.used_units = mainUsesList; return namespaces; } private static SyntaxTree.uses_list GetMainUsesList(SyntaxTree.unit_module mainLibrary, SyntaxTree.program_module main_program, List namespaceModules) { SyntaxTree.uses_list mainUsesList = null; if (mainLibrary != null) { if (mainLibrary.interface_part.uses_modules != null) mainUsesList = mainLibrary.interface_part.uses_modules; } else if (main_program.used_units != null) mainUsesList = main_program.used_units; if (mainUsesList == null) mainUsesList = new SyntaxTree.uses_list(); HashSet set = new HashSet(); foreach (SyntaxTree.unit_or_namespace name_space in namespaceModules) { string name = SyntaxTree.Utils.IdentListToString(name_space.name.idents, ".").ToLower(); if (!set.Contains(name)) { mainUsesList.Add(name_space); set.Add(name); } } return mainUsesList; } private void AddDeclarationsAndReferencedUnitsToNamespaces(List namespace_modules, string file, SyntaxTree.unit_module unitModule, SyntaxTree.syntax_namespace_node namespaceNode) { if (unitModule.interface_part.interface_definitions != null) { foreach (SyntaxTree.declaration decl in unitModule.interface_part.interface_definitions.defs) { namespaceNode.defs.Add(decl); } if (unitModule.interface_part.uses_modules != null) { CheckForDuplicatesInUsesSection(unitModule.interface_part.uses_modules.units); foreach (SyntaxTree.unit_or_namespace name_space in unitModule.interface_part.uses_modules.units) { if (IsPossibleNetNamespaceOrStandardPasFile(name_space, false, Path.GetDirectoryName(file))) { namespaceNode.referenced_units.AddElement(new namespace_unit_node(GetNamespace(name_space), get_location_from_treenode(name_space, unitModule.file_name)), null); } else { namespace_modules.Add(name_space); } } } } } private void SemanticCheckIsPascalNamespace(SyntaxTree.compilation_unit unitSyntaxTree) { if (!(unitSyntaxTree is SyntaxTree.unit_module)) throw new NamespaceModuleExpected(unitSyntaxTree.source_context); SyntaxTree.unit_module unitModule = unitSyntaxTree as SyntaxTree.unit_module; if (unitModule.unit_name.HeaderKeyword != SyntaxTree.UnitHeaderKeyword.Namespace) throw new NamespaceModuleExpected(unitModule.unit_name.source_context); if (unitModule.implementation_part != null) throw new NamespaceModuleExpected(unitModule.implementation_part.source_context); if (unitModule.finalization_part != null) throw new NamespaceModuleExpected(unitModule.finalization_part.source_context); if (unitModule.initialization_part != null && unitModule.initialization_part.list.Count > 0) throw new NamespaceModuleExpected(unitModule.initialization_part.source_context); } private static List GetIncludedFilesFromDirectives(CompilationUnit compilationUnit, List directives) { List files = new List(); foreach (compiler_directive cd in directives) { if (cd.name.ToLower() == TreeConverter.compiler_string_consts.include_namespace_directive) { string directive = cd.directive.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar); if (directive == "*.pas" || directive.EndsWith(Path.DirectorySeparatorChar + "*.pas")) { string dir = Path.Combine(Path.GetDirectoryName(compilationUnit.SyntaxTree.file_name), directive.Replace(Path.DirectorySeparatorChar + "*.pas", "")); foreach (string file in Directory.EnumerateFiles(dir, "*.pas")) { if (!File.Exists(file)) throw new FileNotFound(file, cd.location); files.Add(file); } } else { string file = Path.Combine(Path.GetDirectoryName(compilationUnit.SyntaxTree.file_name), directive); if (!File.Exists(file)) throw new FileNotFound(file, cd.location); files.Add(file); } } } return files; } private void SemanticCheckNoIncludeDirectivesInPascalUnit(CompilationUnit compilationUnit) { if (HasIncludeNamespaceDirective(compilationUnit) && compilationUnit.SyntaxTree is SyntaxTree.unit_module unitModule && unitModule.unit_name.HeaderKeyword != SyntaxTree.UnitHeaderKeyword.Library) { throw new IncludeNamespaceInUnitError(currentCompilationUnit.SyntaxTree.file_name, currentCompilationUnit.SyntaxTree.source_context); } } private SyntaxTree.compilation_unit GetNamespaceSyntaxTree(string fileName) { string sourceText = GetSourceFileText(fileName); List definesList = new List { "PASCALABC" }; // SSM 11/07/20 if (!CompilerOptions.Debug && !CompilerOptions.ForDebugging) definesList.Add("RELEASE"); else definesList.Add("DEBUG"); definesList.AddRange(CompilerOptions.ForceDefines); SyntaxTree.compilation_unit syntaxTree = InternalParseText(fileName, sourceText, errorsList, warnings, definesList); if (errorsList.Count > 0) throw errorsList[0]; syntaxTree = syntaxTreeConvertersController.Convert(syntaxTree) as SyntaxTree.compilation_unit; return syntaxTree; } public unit_node_list GetReferences(CompilationUnit compilationUnit) { unit_node_list dlls = new unit_node_list(); List directives; if (compilationUnit.SemanticTree is common_unit_node) directives = (compilationUnit.SemanticTree as common_unit_node).compiler_directives; else directives = GetDirectivesAsSemanticNodes(compilationUnit.SyntaxTree.compiler_directives, compilationUnit.SyntaxTree.file_name); AddReferencesToSystemUnits(compilationUnit, directives); var referenceDirectives = new List(); foreach (compiler_directive directive in directives) { if (directive.name.ToLower() == TreeConverter.compiler_string_consts.compiler_directive_reference) { #region SEMANTIC CHECKS : EMPTY REFERENCE if (string.IsNullOrEmpty(directive.directive)) throw new TreeConverter.SimpleSemanticError(directive.location, "EXPECTED_ASSEMBLY_NAME"); // Семантическая ошибка #endregion referenceDirectives.Add(directive); } } if (CompilerOptions.ProjectCompiled) { foreach (ReferenceInfo ri in project.references) { referenceDirectives.Add(new compiler_directive("reference", ri.full_assembly_name, null, project.MainFile)); } } if (assemblyResolveScope == null) assemblyResolveScope = new NetHelper.AssemblyResolveScope(AppDomain.CurrentDomain); // It's important to preload all the referenced assemblies before starting the compilation. During the // compilation, we need to access types from every referenced assembly. An attempt to access them could fail // if a transitively dependent assembly is not loaded, yet. // // It's not always possible to solve by re-ordering the references, since there are cases of // mutually-dependent assemblies (i.e. dependency loops) in the wild. foreach (var reference in referenceDirectives) PreloadReference(reference); foreach (var reference in referenceDirectives) CompileReference(dlls, reference); return dlls; } private void AddReferencesToSystemUnits(CompilationUnit compilationUnit, List directives) { foreach (compiler_directive cd in directives) { if (cd.name.ToLower() == TreeConverter.compiler_string_consts.compiler_directive_platformtarget && !string.IsNullOrEmpty(cd.directive) && cd.directive.IndexOf("dotnet5") != -1) { CompilerOptions.UseDllForSystemUnits = false; } } if (CompilerOptions.UseDllForSystemUnits) { directives.Add(new compiler_directive("reference", "%GAC%\\PABCRtl.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\mscorlib.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\System.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\System.Core.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\System.Numerics.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\System.Windows.Forms.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\System.Drawing.dll", null, ".")); if (compilationUnit.SyntaxTree is SyntaxTree.program_module && (compilationUnit.SyntaxTree as SyntaxTree.program_module).used_units != null) { foreach (SyntaxTree.unit_or_namespace usedUnit in (compilationUnit.SyntaxTree as SyntaxTree.program_module).used_units.units) { if (usedUnit.name.ToString() == "Graph3D") { directives.Add(new compiler_directive("reference", "%GAC%\\PresentationFramework.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\WindowsBase.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\PresentationCore.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\HelixToolkit.Wpf.dll", null, ".")); directives.Add(new compiler_directive("reference", "%GAC%\\HelixToolkit.dll", null, ".")); break; } } } } } NetHelper.AssemblyResolveScope assemblyResolveScope; private bool IsPossibleNetNamespaceOrStandardPasFile(SyntaxTree.unit_or_namespace name_space, bool addToStandardModules, string currentPath) { if (name_space is SyntaxTree.uses_unit_in) return false; // если это "что-то"."что-то"... (полный путь к пространству имен) if (name_space.name.idents.Count > 1) return true; string sourceFileName = FindSourceFileName(name_space.name.idents[0].name, currentPath, out _); string pcuFileName = FindPCUFileName(name_space.name.idents[0].name, currentPath, out _); // если нет исходников и pcu if (sourceFileName == null && pcuFileName == null) return true; // если есть что-то одно string fileName = sourceFileName ?? pcuFileName; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); // оставить только PT4 и протестировать string[] standardFilesExcludedFromRTL = new string[] { "PT4", "School", "CRT", "Arrays", "MPI", "Collections", "Core"}; bool includeInRTL = standardFilesExcludedFromRTL.All(file => !file.Equals(fileNameWithoutExtension, StringComparison.CurrentCultureIgnoreCase)); // если это исходный файл из папки Lib (стандартные паскалевские библиотеки) if (CompilerOptions.UseDllForSystemUnits && Path.GetDirectoryName(fileName).Equals(Path.Combine(CompilerOptions.SystemDirectory, "Lib"), StringComparison.CurrentCultureIgnoreCase) && includeInRTL) { string s = Path.GetFileNameWithoutExtension(fileName).ToLower(); if (addToStandardModules && !StandardModules.Contains(s)) StandardModules.Add(s); return true; } return false; } public using_namespace GetNamespace(SyntaxTree.unit_or_namespace _name_space) { return new using_namespace(SyntaxTree.Utils.IdentListToString(_name_space.name.idents, ".")); } /// /// Формирует узел семантического дерева, соответствующий пространству имен (.NET или пользовательскому) /// /// /// private using_namespace GetNamespace(using_namespace_list usingList, string fullNamespaceName, SyntaxTree.unit_or_namespace name_space, bool mightBeUnit, Dictionary namespaces) { if (!NetHelper.NetHelper.NamespaceExists(fullNamespaceName) && (namespaces == null || !namespaces.ContainsKey(fullNamespaceName))) { if (mightBeUnit && !fullNamespaceName.Contains(".")) throw new UnitNotFound(currentCompilationUnit.SyntaxTree.file_name, fullNamespaceName, name_space.source_context); throw new TreeConverter.NamespaceNotFound(fullNamespaceName, get_location_from_treenode(name_space.name, currentCompilationUnit.SyntaxTree.file_name)); } return new using_namespace(fullNamespaceName); } public void AddNamespacesToUsingList(using_namespace_list usingList, List possibleNamespaces, bool mightContainUnits, Dictionary namespaces) { foreach (SyntaxTree.unit_or_namespace name_space in possibleNamespaces) { usingList.AddElement(GetNamespace(usingList, SyntaxTree.Utils.IdentListToString(name_space.name.idents, "."), name_space, mightContainUnits, namespaces)); } } public void AddNamespacesToUsingList(using_namespace_list using_list, SyntaxTree.using_list ul) { if (ul != null) AddNamespacesToUsingList(using_list, ul.namespaces, false, null); } /// /// получение списка using - legacy code !!! /// public SyntaxTree.using_list GetInterfaceUsingList(SyntaxTree.compilation_unit cu) { if (cu is SyntaxTree.unit_module) return (cu as SyntaxTree.unit_module).interface_part.using_namespaces; if (cu is SyntaxTree.program_module) return (cu as SyntaxTree.program_module).using_namespaces; return null; } /// /// получение списка using - legacy code !!! /// private SyntaxTree.using_list GetImplementationSyntaxUsingList(SyntaxTree.compilation_unit cu) { if (cu is SyntaxTree.unit_module) if ((cu as SyntaxTree.unit_module).implementation_part != null) return (cu as SyntaxTree.unit_module).implementation_part.using_namespaces; return null; } /// /// получение списка using - legacy code !!! /// public string GetSourceFileText(string FileName) { return (string)SourceFilesProvider(FileName, SourceFileOperation.GetText); } public SyntaxTree.compilation_unit ParseText(string fileName, string text, List errorList, List warnings) { Reset(); OnChangeCompilerState(this, CompilerState.CompilationStarting, fileName); SyntaxTree.compilation_unit cu = InternalParseText(fileName, text, ErrorsList, warnings); OnChangeCompilerState(this, CompilerState.Ready, fileName); return cu; } private SyntaxTree.compilation_unit InternalParseText(string fileName, string text, List errorList, List warnings, List definesList = null) { OnChangeCompilerState(this, CompilerState.BeginParsingFile, fileName); SyntaxTree.compilation_unit unitSyntaxTree = ParsersController.GetCompilationUnit(fileName, text, ErrorsList, warnings, definesList); OnChangeCompilerState(this, CompilerState.EndParsingFile, fileName); //Вычисляем сколько строк скомпилировали if (errorList.Count == 0 && unitSyntaxTree != null && unitSyntaxTree.source_context != null) { linesCompiled += (uint)(unitSyntaxTree.source_context.end_position.line_num - unitSyntaxTree.source_context.begin_position.line_num + 1); // 500 - это наибольшая программа для начинающих. БОльшая программа - здоровье кода только по кнопке (чтобы не замедлять) if (linesCompiled <= 500) { // Это только для локального компилятора? var stat = new SyntaxVisitors.ABCStatisticsVisitor(); stat.ProcessNode(unitSyntaxTree); pABCCodeHealth = stat.CalcHealth(out int neg, out int pos); } } return unitSyntaxTree; } /// /// Проверяет, является ли модуль dll по соответствующей директиве /// public static bool IsDll(SyntaxTree.compilation_unit unitSyntaxTree) { foreach (SyntaxTree.compiler_directive directive in unitSyntaxTree.compiler_directives) { if (string.Equals(directive.Name.text, "apptype", StringComparison.CurrentCultureIgnoreCase) && string.Equals(directive.Directive.text, "dll", StringComparison.CurrentCultureIgnoreCase)) { return true; } } return false; } /// /// Проверяет, является ли модуль dll по соответствующей директиве и возвращает эту директиву выходным параметром /// public static bool IsDll(SyntaxTree.compilation_unit unitSyntaxTree, out SyntaxTree.compiler_directive dllDirective) { foreach (SyntaxTree.compiler_directive directive in unitSyntaxTree.compiler_directives) { if (string.Equals(directive.Name.text, "apptype", StringComparison.CurrentCultureIgnoreCase) && string.Equals(directive.Directive.text, "dll", StringComparison.CurrentCultureIgnoreCase)) { dllDirective = directive; return true; } } dllDirective = null; return false; } /// /// Компилирует основную программу и все используемые ей юниты рекурсивно /// /// Вспомогательная переменная для заполнения CompilationUnit.interfaceUsedUnits и /// CompilationUnit.implementationUsedUnits (здесь могут содержаться юниты и dll) /// /// Вспомогательная переменная для заполнения CompilationUnit.interfaceUsedDirectUnits и /// CompilationUnit.implementationUsedDirectUnits /// /// Синтаксический узел текущего модуля (или пространства имен) /// Директория родительского модуля /// Скомпилированный юнит public CompilationUnit CompileUnit(unit_node_list unitsFromUsesSection, Dictionary directUnitsFromUsesSection, SyntaxTree.unit_or_namespace currentUnitNode, string previousPath) { string unitFileName = GetUnitFileName(currentUnitNode, previousPath); string unitId = Path.ChangeExtension(unitFileName, null); // Имя папки, в которой лежит текущий модуль // Используется для подключения модулей, $include и т.п. из модуля, подключённого с uses-in var currentDirectory = Path.GetDirectoryName(unitFileName); // вернет null, если юнит еще не был инициализирован CompilationUnit currentUnit = UnitTable[unitId]; Dictionary docs = null; if (currentUnit != null) { #region SEMANTIC CHECKS : USES IN SECTION LOGIC // ошибка - пространство имен не может содержать in секцию (для указания файла) SemanticCheckUsesInIsNotNamespace(currentUnitNode, currentUnit); #endregion // если модуль уже скомпилирован - возвращаем (возможно, только интерфейс модуля и тогда он докомпилируется в другом рекурсивном вызове) EVA if (currentUnit.State != UnitState.BeginCompilation || currentUnit.SemanticTree != null) //TODO: ИЗБАВИТЬСЯ ОТ ВТОРОГО УСЛОВИЯ { AddCurrentUnitAndItsReferencesToUsesLists(unitsFromUsesSection, directUnitsFromUsesSection, currentUnitNode, currentUnit, GetReferences(currentUnit)); return currentUnit; } } else { // если есть pcu - возврат EVA if (UnitHasPCU(unitsFromUsesSection, directUnitsFromUsesSection, currentUnitNode, ref unitFileName, ref currentUnit)) return currentUnit; // нет pcu и модуль не откомпилирован => новый модуль EVA InitializeNewUnit(currentUnitNode, unitFileName, unitId, ref currentUnit, ref docs); } // формирование списков зависимостей текущего модуля (uses list, dll, пространства имен) CreateDependencyListsForCurrentUnit(currentUnit, currentDirectory, out var interfaceUsesList, out var references, out var namespaces); #region INTERFACE PART // комплируем зависимости из интерфейса EVA if (interfaceUsesList != null) { CompileInterfaceDependencies(unitsFromUsesSection, directUnitsFromUsesSection, currentUnitNode, unitFileName, currentDirectory, currentUnit, interfaceUsesList, references, namespaces, out bool shouldReturnCurUnit); if (shouldReturnCurUnit) return currentUnit; } currentCompilationUnit = currentUnit; currentUnit.InterfaceUsedUnits.AddRange(references); // Добавление пространств имен из uses list (могут быть разных видов) AddNamespacesToUsingList(currentUnit.InterfaceUsingNamespaceList, currentUnit.possibleNamespaces, true, namespaces); #region USING LIST LEGACY CODE // Добавление пространств имен NET из using list - устаревшее ключевое слово using AddNamespacesToUsingList(currentUnit.InterfaceUsingNamespaceList, GetInterfaceUsingList(currentUnit.SyntaxTree)); #endregion //Console.WriteLine("Compiling Interface "+ unitFileName);//DEBUG // компилируем интерфейс текущего модуля EVA CompileCurrentUnitInterface(unitFileName, currentUnit, docs); // интерфейс скомпилирован - переходим к секции реализации currentUnit.State = UnitState.InterfaceCompiled; // заполнение списков uses семантического уровня AddCurrentUnitAndItsReferencesToUsesLists(unitsFromUsesSection, directUnitsFromUsesSection, currentUnitNode, currentUnit, references); #endregion #region IMPLEMENTATION PART // берем модули из секции uses в реализации List implementationUsesList = GetImplementationUsesSection(currentUnit.SyntaxTree); currentUnit.ImplementationUsedUnits.Clear(); currentUnit.possibleNamespaces.Clear(); common_unit_node semanticTreeAsCommonNode = currentUnit.SemanticTree as common_unit_node; // Компиляция зависимостей в области реализации EVA CompileImplementationDependencies(currentDirectory, currentUnit, implementationUsesList, namespaces, semanticTreeAsCommonNode, out bool shouldReturnCurrentUnit); if (shouldReturnCurrentUnit) return currentUnit; // Console.WriteLine("Compiling Implementation "+ unitFileName);//DEBUG // компилируем реализацию текущего модуля EVA CompileCurrentUnitImplementation(unitFileName, currentUnit, docs); #endregion currentUnit.State = UnitState.Compiled; if (semanticTreeAsCommonNode != null) { if (!UnitsLogicallySortedList.Contains(currentUnit))//vnimanie zdes inogda pri silnoj zavisimosti modulej moduli popadajut neskolko raz UnitsLogicallySortedList.Add(currentUnit); } OnChangeCompilerState(this, CompilerState.EndCompileFile, unitFileName); //SavePCU(currentUnit, unitFileName); currentUnit.UnitFileName = unitFileName; return currentUnit; /*if(currentUnit.State!=UnitState.Compiled) { //Console.WriteLine("Compile Interface "+unitFileName);//DEBUG currentUnit.SemanticTree=SyntaxTreeToSemanticTreeConverter.CompileInterface(currentUnit.SyntaxTree, currentUnit.InterfaceUsedUnits,currentUnit.syntax_error); currentUnit.State=UnitState.InterfaceCompiled; implementationUsesList=GetSemanticImplementationUsesList(currentUnit.SyntaxTree); if(implementationUsesList!=null) for(int i=implementationUsesList.Count-1;i>=0;i--) CompileUnit(currentUnit.ImplementationUsedUnits,implementationUsesList[i]); //Console.WriteLine("Compile Implementation "+unitFileName);//DEBUG if (currentUnit.SyntaxTree is SyntaxTree.unit_module) { SyntaxTreeToSemanticTreeConverter.CompileImplementation(currentUnit.SemanticTree, currentUnit.SyntaxTree,currentUnit.ImplementationUsedUnits,currentUnit.syntax_error); } currentUnit.State=UnitState.Compiled; unitsFromUsesSection.Add(currentUnit.SemanticTree); SaveSemanticTreeToFile(currentUnit,unitFileName); }*/ } private void CreateDependencyListsForCurrentUnit(CompilationUnit currentUnit, string currentDirectory, out List interfaceUsesList, out unit_node_list references, out Dictionary namespaces) { interfaceUsesList = GetInterfaceUsesSection(currentUnit.SyntaxTree); SetUseDLLForSystemUnits(currentDirectory, interfaceUsesList, interfaceUsesList.Count - 1 - currentUnit.InterfaceUsedUnits.Count); references = GetReferences(currentUnit); // TODO: закончить рефакторинг | Вопрос, как мы будем подключать про-ва имен из других языков EVA namespaces = PrepareUserNamespacesUsedInTheCurrentUnit(currentUnit); } private void AddCurrentUnitAndItsReferencesToUsesLists(unit_node_list unitsFromUsesSection, Dictionary directUnitsFromUsesSection, SyntaxTree.unit_or_namespace currentUnitNode, CompilationUnit currentUnit, unit_node_list references) { if (unitsFromUsesSection != null) { if (unitsFromUsesSection.AddElement(currentUnit.SemanticTree, currentUnitNode.UsesPath())) directUnitsFromUsesSection.Add(currentUnit.SemanticTree, currentUnit); unitsFromUsesSection.AddRange(references); } } private void SemanticCheckUsesInIsNotNamespace(SyntaxTree.unit_or_namespace currentUnitNode, CompilationUnit currentUnit) { if (currentUnit.SemanticTree is dot_net_unit_node && currentUnitNode is SyntaxTree.uses_unit_in ui && ui.in_file != null) // значит, это пространство имен и секция in у него должна отсутствовать { ErrorsList.Add(new NamespaceCannotHaveInSection(ui.in_file.source_context)); } } private void CompileCurrentUnitImplementation(string UnitFileName, CompilationUnit currentUnit, Dictionary docs) { if (currentUnit.SyntaxTree is SyntaxTree.unit_module) { #if DEBUG if (InternalDebug.SemanticAnalysis) #endif { OnChangeCompilerState(this, CompilerState.CompileImplementation, UnitFileName); TreeConverter.SemanticRules.SymbolTableCaseSensitive = currentUnit.CaseSensitive; SyntaxTreeToSemanticTreeConverter.CompileImplementation( (common_unit_node)currentUnit.SemanticTree, currentUnit.SyntaxTree, buildImplementationUsesList(currentUnit), ErrorsList, Warnings, currentUnit.syntax_error, BadNodesInSyntaxTree, currentUnit.InterfaceUsingNamespaceList, currentUnit.ImplementationUsingNamespaceList, docs, CompilerOptions.Debug, CompilerOptions.ForDebugging, CompilerOptions.ForIntellisense, CompiledVariables ); CheckErrorsAndThrowTheFirstOne(); } } } /// /// Компилирует модули из секции uses текущего модуля реализации рекурсивно /// private void CompileImplementationDependencies(string currentPath, CompilationUnit currentUnit, List implementationUsesList, Dictionary namespaces, common_unit_node commonUnitNode, out bool shouldReturnCurrentUnit) { shouldReturnCurrentUnit = false; if (implementationUsesList != null) { for (int i = implementationUsesList.Count - 1; i >= 0; i--) { if (!IsPossibleNetNamespaceOrStandardPasFile(implementationUsesList[i], true, currentPath)) { CompilationUnit unitFromUsesSection = UnitTable[Path.ChangeExtension(GetUnitFileName(implementationUsesList[i], currentPath), null)]; // защита от попадания в бесконечный цикл (когда мы вернемся в тот юнит, в котором уже были (еще не скомпилированный), а затем спустимся по дереву зависимостей сюда же и т.д.) // первая часть условия - если мы встречаем юнит не первый раз, вторая часть - если интерфейс еще не скомпилирован if (unitFromUsesSection != null && unitFromUsesSection.State == UnitState.BeginCompilation) { UnitsToCompileDelayedList.Add(unitFromUsesSection); shouldReturnCurrentUnit = true; // обрубаем компиляцию реализации в CompileUnit - не все интерфейсы еще откомпилированы !!! #if DEBUG // Console.WriteLine("[DEBUGINFO]Send compile to end " + Path.GetFileName(GetUnitFileName(implementationUsesList[i])));//DEBUG #endif } else { CompileUnit(currentUnit.ImplementationUsedUnits, currentUnit.ImplementationUsedDirectUnits, implementationUsesList[i], currentPath); } } else { currentUnit.ImplementationUsedUnits.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(implementationUsesList[i])), null); currentUnit.possibleNamespaces.Add(implementationUsesList[i]); } } } currentCompilationUnit = currentUnit; AddNamespacesToUsingList(currentUnit.ImplementationUsingNamespaceList, currentUnit.possibleNamespaces, true, namespaces); #region USING LIST LEGACY CODE AddNamespacesToUsingList(currentUnit.ImplementationUsingNamespaceList, GetImplementationSyntaxUsingList(currentUnit.SyntaxTree)); #endregion if (shouldReturnCurrentUnit) { // помещаем текущий модуль в список отложенной компиляции UnitsToCompileDelayedList.Add(currentUnit); if (commonUnitNode != null) { if (!UnitsLogicallySortedList.Contains(currentUnit))//vnimanie zdes inogda pri silnoj zavisimosti modulej moduli popadajut neskolko raz UnitsLogicallySortedList.Add(currentUnit); } //Console.WriteLine("Send compile to end "+unitFileName);//DEBUG } } private void CompileCurrentUnitInterface(string UnitFileName, CompilationUnit currentUnit, Dictionary docs) { #if DEBUG if (InternalDebug.SemanticAnalysis) #endif { if (currentUnit.State != UnitState.InterfaceCompiled) { OnChangeCompilerState(this, CompilerState.CompileInterface, UnitFileName); TreeConverter.SemanticRules.SymbolTableCaseSensitive = currentUnit.CaseSensitive; currentUnit.SemanticTree = SyntaxTreeToSemanticTreeConverter.CompileInterface( currentUnit.SyntaxTree, currentUnit.InterfaceUsedUnits, ErrorsList, Warnings, currentUnit.syntax_error, BadNodesInSyntaxTree, currentUnit.InterfaceUsingNamespaceList, docs, CompilerOptions.Debug, CompilerOptions.ForDebugging, CompilerOptions.ForIntellisense, CompiledVariables ); CheckErrorsAndThrowTheFirstOne(); } } } /// /// Компилирует модули из секции uses интерфейса текущего модуля рекурсивно /// /// private void CompileInterfaceDependencies(unit_node_list unitsFromUsesSection, Dictionary directUnitsFromUsesSection, SyntaxTree.unit_or_namespace currentUnitNode, string unitFileName, string currentPath, CompilationUnit currentUnit, List interfaceUsesList, unit_node_list references, Dictionary namespaces, out bool shouldReturnCurrentUnit) { shouldReturnCurrentUnit = false; for (int i = interfaceUsesList.Count - 1 - currentUnit.InterfaceUsedUnits.Count; i >= 0; i--) // здесь откидываются модули с уже откомпилированными интерфейсами из секции uses (см. комментарий, обозначенный #1710) { if (IsPossibleNetNamespaceOrStandardPasFile(interfaceUsesList[i], true, currentPath) || namespaces.ContainsKey(interfaceUsesList[i].name.idents[0].name)) { currentUnit.InterfaceUsedUnits.AddElement(new namespace_unit_node(GetNamespace(interfaceUsesList[i])), null); currentUnit.possibleNamespaces.Add(interfaceUsesList[i]); } else { #region SEMANTIC CHECKS : CYCLE DEPENDENCY OF INTERFACES SemanticCheckNoLoopDependenciesOfInterfaces(currentUnit, unitFileName, interfaceUsesList[i], currentPath); #endregion // компиляция модулей из интерфейса текущего модуля CompileUnit(currentUnit.InterfaceUsedUnits, currentUnit.InterfaceUsedDirectUnits, interfaceUsesList[i], currentPath); // если текущий модуль был откомпилирован в другом рекурсивном вызове if (currentUnit.State == UnitState.Compiled) { AddCurrentUnitAndItsReferencesToUsesLists(unitsFromUsesSection, directUnitsFromUsesSection, currentUnitNode, currentUnit, references); // #1710 добавление в список модулей из uses происходит только в конце компиляции интерфейса юнита или позже во всех случаях shouldReturnCurrentUnit = true; } } } } private void SemanticCheckNoLoopDependenciesOfInterfaces(CompilationUnit currentUnit, string unitFileName, SyntaxTree.unit_or_namespace usedUnitNode, string currentPath) { var usedUnitFileName = GetUnitFileName(usedUnitNode, currentPath); var usedUnitId = Path.ChangeExtension(usedUnitFileName, null); // когда образуется цикл здесь сохранится инцидентная вершина графа (используемый юнит), которая тоже принадлежит циклу currentUnit.currentUsedUnitId = usedUnitId; // если используемый юнит имеет не скомпилированный интерфейс, но был инициализирован if (UnitTable[usedUnitId] != null && UnitTable[usedUnitId].State == UnitState.BeginCompilation) { string transitivelyUsedUnit = UnitTable[usedUnitId].currentUsedUnitId; if (transitivelyUsedUnit != null) { // если сначала взяли pcu а потом решили его перекомпилировать, поэтому в таблице его нет if (UnitTable[transitivelyUsedUnit] == null) UnitTable[usedUnitId].currentUsedUnitId = transitivelyUsedUnit; // Вопрос EVA // если "используемый используемого" (транзитивно зависимый) модуль находится в том же состоянии, что и просто используемый, то это означает циклическую зависимость if (UnitTable[usedUnitId].currentUsedUnitId != null && UnitTable[UnitTable[usedUnitId].currentUsedUnitId].State == UnitState.BeginCompilation) throw new CycleUnitReference(unitFileName, usedUnitNode); } } } /// /// Если в программе в секции uses есть не про-во имен и не стандартный модуль, то использование PABCRtl.dll отменяется /// private void SetUseDLLForSystemUnits(string currentDirectory, List usesList, int lastUnitIndex) { if (usesList != null && CompilerOptions.UseDllForSystemUnits) { for (int i = lastUnitIndex; i >= 0; i--) { if (!IsPossibleNetNamespaceOrStandardPasFile(usesList[i], false, currentDirectory)) { CompilerOptions.UseDllForSystemUnits = false; break; } } } } /// /// Получение исходного кода модуля, заполнение документации, /// генерация синтаксического дерева, /// обработка синтаксических ошибок /// private void InitializeNewUnit(SyntaxTree.unit_or_namespace currentUnitNode, string UnitFileName, string UnitId, ref CompilationUnit currentUnit, ref Dictionary docs) { currentUnit = new CompilationUnit(); if (firstCompilationUnit == null) firstCompilationUnit = currentUnit; OnChangeCompilerState(this, CompilerState.BeginCompileFile, UnitFileName); // начало компиляции модуля #region SYNTAX TREE CONSTRUCTING // получение синтаксического дерева string sourceText = GetSourceCode(currentUnitNode, UnitFileName, currentUnit); currentUnit.SyntaxTree = ConstructSyntaxTree(UnitFileName, currentUnit, sourceText); #endregion if (currentUnit.SyntaxTree is SyntaxTree.unit_module) CompilerOptions.UseDllForSystemUnits = false; if (errorsList.Count == 0) // SSM 2/05/16 - для преобразования синтаксических деревьев извне (синтаксический сахар) { currentUnit.SyntaxTree = syntaxTreeConvertersController.Convert(currentUnit.SyntaxTree) as SyntaxTree.compilation_unit; } // генерация документации к узлам синтаксического дерева EVA docs = GenUnitDocumentation(currentUnit, sourceText); #region SEMANTIC CHECKS : DIRECTIVES AND OUTPUT FILE TYPE // SSM 21/05/20 Проверка, что мы не записали apptype dll в небиблиотеку bool isDll = IsDll(currentUnit.SyntaxTree, out var dllDirective); SemanticCheckDLLDirectiveOnlyForLibraries(currentUnit.SyntaxTree, isDll, dllDirective); // ошибка - компилируем вторую основную программу или вторую dll вместо юнита SemanticCheckCurrentUnitMustBePascalUnit(UnitFileName, currentUnit, isDll); // ошибка директива include в паскалевском юните SemanticCheckNoIncludeDirectivesInPascalUnit(currentUnit); #endregion // Set output file type for dll if (isDll) CompilerOptions.OutputFileType = CompilerOptions.OutputType.ClassLibrary; // Вопрос, нужно ли это здесь, если это есть в Compile в конце EVA if (ParsersController.LastParser != null) currentUnit.CaseSensitive = ParsersController.LastParser.CaseSensitive; currentCompilationUnit = currentUnit; currentUnit.SyntaxUnitName = currentUnitNode; // сопоставление нодам ошибок EVA MatchErrorsToBadNodes(currentUnit); CheckErrorsAndThrowTheFirstOne(); UnitTable[UnitId] = currentUnit; // здесь добавляем стандартные модули в секцию uses интерфейса #if DEBUG if (InternalDebug.AddStandartUnits) #endif AddStandardUnitsToInterfaceUsesSection(currentUnit.SyntaxTree); currentCompilationUnit = currentUnit; currentUnit.possibleNamespaces.Clear(); } private void SemanticCheckNamespacesOnlyInProjects(CompilationUnit currentUnit) { // legacy if (currentUnit.SyntaxTree is SyntaxTree.unit_module) { // Проверка на явный namespace (паскалевский) if ((currentUnit.SyntaxTree as SyntaxTree.unit_module).unit_name.HeaderKeyword == SyntaxTree.UnitHeaderKeyword.Namespace) throw new NamespacesCanBeCompiledOnlyInProjects(currentUnit.SyntaxTree.source_context); } } // Синтактико-семантическая ошибка - проверка, что compilationUnit является модулем, // а не основной программой и не dll EVA private void SemanticCheckCurrentUnitMustBePascalUnit(string UnitFileName, CompilationUnit currentUnit, bool isDll) { if (UnitTable.Count > 0) // если это не главный модуль (программа в unittable всегда идет первой) { if (currentUnit.SyntaxTree is SyntaxTree.program_module) throw new UnitModuleExpected(UnitFileName, currentUnit.SyntaxTree.source_context.LeftSourceContext); else if (isDll) throw new UnitModuleExpectedLibraryFound(UnitFileName, currentUnit.SyntaxTree.source_context.LeftSourceContext); } } private void MatchErrorsToBadNodes(CompilationUnit currentUnit) { if (errorsList.Count > 0) { currentUnit.syntax_error = errorsList[0] as SyntaxError; foreach (Error er in errorsList) if (er is SyntaxError && (er as SyntaxError).bad_node != null) BadNodesInSyntaxTree[(er as SyntaxError).bad_node] = er; } } /// /// Проверка, что директива dll только в Library - требует передачи директивы dll /// private void SemanticCheckDLLDirectiveOnlyForLibraries(SyntaxTree.compilation_unit unitSyntaxTree, bool isDll, SyntaxTree.compiler_directive dllDirective) { // Если Library и apptype dll не указано, то никакой ошибки нет EVA if (unitSyntaxTree != null && isDll) { if (!(unitSyntaxTree is SyntaxTree.unit_module) || (unitSyntaxTree is SyntaxTree.unit_module unitNode && unitNode.unit_name.HeaderKeyword != SyntaxTree.UnitHeaderKeyword.Library)) { // если в директивах появилось {$apptype dll}, но это не Library ErrorsList.Add(new AppTypeDllIsAllowedOnlyForLibraries(unitSyntaxTree.file_name, dllDirective.source_context)); } } } private SyntaxTree.compilation_unit ConstructSyntaxTree(string unitFileName, CompilationUnit currentUnit, string sourceText) { List DefinesList = new List { "PASCALABC" }; if (!CompilerOptions.Debug && !CompilerOptions.ForDebugging) DefinesList.Add("RELEASE"); else DefinesList.Add("DEBUG"); DefinesList.AddRange(CompilerOptions.ForceDefines); SyntaxTree.compilation_unit syntaxTree; if (CompilerOptions.UnitSyntaxTree != null) { syntaxTree = CompilerOptions.UnitSyntaxTree; CompilerOptions.UnitSyntaxTree = null; } // синтаксический анализ else syntaxTree = InternalParseText(unitFileName, sourceText, errorsList, warnings, DefinesList); // проверка, что пространства имен только в проектах SemanticCheckNamespacesOnlyInProjects(currentUnit); return syntaxTree; } private string GetSourceCode(SyntaxTree.unit_or_namespace currentUnitNode, string UnitFileName, CompilationUnit currentUnit) { string SourceText = null; if (CompilerOptions.UnitSyntaxTree == null) { SourceText = GetSourceFileText(UnitFileName); if (SourceText == null) { if (currentUnit == firstCompilationUnit) throw new SourceFileNotFound(UnitFileName); else throw new UnitNotFound(currentCompilationUnit.SyntaxTree.file_name, UnitFileName, currentUnitNode.source_context); } } return SourceText; } private Dictionary GenUnitDocumentation(CompilationUnit currentUnit, string SourceText) { Dictionary docs = null; if (errorsList.Count == 0 && IsDocumentationNeeded(currentUnit.SyntaxTree)) { if (SourceText != null) { docs = AddDocumentationToNodes(currentUnit.SyntaxTree, SourceText); if (docs != null) currentUnit.Documented = true; } } return docs; } private bool UnitHasPCU(unit_node_list unitsFromUsesSection, Dictionary directUnitsFromUsesSection, SyntaxTree.unit_or_namespace currentUnitNode, ref string UnitFileName, ref CompilationUnit currentUnit) { if (Path.GetExtension(UnitFileName).ToLower() == CompilerOptions.CompiledUnitExtension) { if (File.Exists(UnitFileName)) { if (UnitTable.Count == 0) throw new ProgramModuleExpected(UnitFileName, null); try { if ((currentUnit = ReadPCU(UnitFileName)) != null) { AddCurrentUnitAndItsReferencesToUsesLists(unitsFromUsesSection, directUnitsFromUsesSection, currentUnitNode, currentUnit, GetReferences(currentUnit)); UnitTable[Path.ChangeExtension(UnitFileName, null)] = currentUnit; return true; } } catch (InvalidPCUFule) { //Перекомпилируем.... } // Так надо (для дебага) catch (Error) { throw; } catch (Exception e) { OnChangeCompilerState(this, CompilerState.PCUReadingError, UnitFileName); // ошибка чтения PCU #if DEBUG if (!InternalDebug.SkipPCUErrors) throw new CompilerInternalError("PCUReader", e); #endif } string SourceFileName = FindSourceFileName(Path.ChangeExtension(UnitFileName, null), null, out _); if (SourceFileName == null) throw new ReadPCUError(UnitFileName); else UnitFileName = SourceFileName; } } return false; } private Dictionary AddDocumentationToNodes(SyntaxTree.compilation_unit unitSyntaxTree, string text) { List errors = new List(); string doctagsParserExtension = Path.GetExtension(unitSyntaxTree.file_name) + "dt" + Parsers.Controller.HideParserExtensionPostfixChar; SyntaxTree.documentation_comment_list docCommentList = ParsersController.Compile(Path.ChangeExtension(unitSyntaxTree.file_name, doctagsParserExtension), text, errors, new List(), Parsers.ParseMode.Normal) as SyntaxTree.documentation_comment_list; if (errors.Count > 0) return null; return new DocumentationConstructor().Construct(unitSyntaxTree, docCommentList); } private bool IsDocumentationNeeded(SyntaxTree.compilation_unit unitSyntaxTree) { if (project != null && project.generate_xml_doc) return true; if (unitSyntaxTree == null) return false; if (unitSyntaxTree.file_name != null && internalDebug.DocumentedUnits.Contains(unitSyntaxTree.file_name.ToLower())) return true; foreach (SyntaxTree.compiler_directive directive in unitSyntaxTree.compiler_directives) { if (string.Equals(directive.Name.text, "gendoc", StringComparison.CurrentCultureIgnoreCase) && string.Equals(directive.Directive.text, "true", StringComparison.CurrentCultureIgnoreCase)) { return true; } } return false; } private TreeRealization.unit_node_list buildImplementationUsesList(CompilationUnit cu) { TreeRealization.unit_node_list unl = new PascalABCCompiler.TreeRealization.unit_node_list(); unl.AddRange(cu.ImplementationUsedUnits); foreach (TreeRealization.unit_node un in cu.InterfaceUsedUnits) { if (un is TreeRealization.dot_net_unit_node) unl.AddElement(un, null); } return unl; } public void SavePCU(CompilationUnit Unit) { //#if DEBUG try { if (Unit.SyntaxTree != null && Unit.SyntaxTree is SyntaxTree.unit_module) { if (((SyntaxTree.unit_module)Unit.SyntaxTree).unit_name.HeaderKeyword == PascalABCCompiler.SyntaxTree.UnitHeaderKeyword.Library) return; foreach (SyntaxTree.compiler_directive cd in Unit.SyntaxTree.compiler_directives) if (cd.Name.text.ToLower() == TreeConverter.compiler_string_consts.compiler_savepcu) if (!Convert.ToBoolean(cd.Directive.text)) return; } } catch { } //#endif PCUWriter writer = null; try { #if DEBUG if (InternalDebug.PCUGenerate) #endif if (CompilerOptions.SavePCU) if ((Unit.SemanticTree as TreeRealization.common_unit_node).namespaces.Count > 1 && Unit.SyntaxTree != null && Unit.State == UnitState.Compiled) { writer = new PCUWriter(this, pr_ChangeState); bool dbginfo = true;/*CompilerOptions.Debug*/ #if DEBUG dbginfo = InternalDebug.IncludeDebugInfoInPCU; #endif 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, Unit.UnitFileName); #if DEBUG if (!InternalDebug.SkipPCUErrors) throw new Errors.CompilerInternalError(string.Format("Compiler.Compile[{0}]", Path.GetFileName(this.currentCompilationUnit.SyntaxTree.file_name)), err); writer.RemoveSelf(); #endif } } public CompilationUnit ReadPCU(string FileName) { if (CompilerOptions.ForIntellisense && false) { CompilationUnit unit = null; if (pcuCompilationUnits.ContainsKey(FileName)) { unit = pcuCompilationUnits[FileName]; return unit; } PCUReader pr = new PCUReader(this, pr_ChangeState); unit = pr.GetCompilationUnit(FileName, CompilerOptions.Debug); pcuCompilationUnits[FileName] = unit; return unit; } else { PCUReader pr = new PCUReader(this, pr_ChangeState); return pr.GetCompilationUnit(FileName, CompilerOptions.Debug); } } void pr_ChangeState(object Sender, PCUReaderWriterState State, object obj) { switch (State) { case PCUReaderWriterState.BeginReadTree: OnChangeCompilerState(this, CompilerState.ReadPCUFile, (Sender as PCUReader).FileName); break; case PCUReaderWriterState.EndReadTree: CompilationUnit cu = obj as CompilationUnit; cu.State = UnitState.Compiled; unitTable[(Sender as PCUReader).FileName] = cu; UnitsLogicallySortedList.Add(cu); GetReferences(cu); break; case PCUReaderWriterState.EndSaveTree: OnChangeCompilerState(this, CompilerState.SavePCUFile, (Sender as PCUWriter).FileName); break; } } /* TreeRealization.common_unit_node cun11 = currentUnit.SemanticTree as TreeRealization.common_unit_node; if (cun11 != null) UnitsLogicallySortedList.AddElement(cun11);*/ static string standartAssemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(string)).ManifestModule.FullyQualifiedName); public static Dictionary standart_assembly_dict = new Dictionary(); static Compiler() { string[] ss = new string[] { "mscorlib.dll", "System.dll", "System.Core.dll", "System.Numerics.dll", "System.Windows.Forms.dll", "PABCRtl.dll" }; foreach (var x in ss) standart_assembly_dict[x] = get_standart_assembly_path(x); } public static string get_standart_assembly_path(string name) { name = name.Replace("%GAC%\\", ""); string ttn = System.IO.Path.GetFileNameWithoutExtension(name); string tn = Path.Combine(standartAssemblyPath, name); if (File.Exists(tn)) return tn; if (Environment.OSVersion.Platform != PlatformID.Unix && Environment.OSVersion.Platform != PlatformID.MacOSX) { string windir = Path.Combine(Environment.GetEnvironmentVariable("windir"), "Microsoft.NET"); tn = windir + @"\assembly\GAC_MSIL\"; tn += ttn + "\\"; System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(tn); if (!di.Exists) { tn = windir + @"\assembly\GAC_64\"; tn += ttn + "\\"; di = new System.IO.DirectoryInfo(tn); if (!di.Exists) { tn = windir + @"\assembly\GAC_32\"; tn += ttn + "\\"; di = new System.IO.DirectoryInfo(tn); if (!di.Exists) { tn = windir + @"\assembly\GAC\"; tn += ttn + "\\"; di = new System.IO.DirectoryInfo(tn); if (!di.Exists) { windir = Environment.GetEnvironmentVariable("windir"); tn = windir + @"\assembly\GAC_MSIL\"; tn += ttn + "\\"; di = new System.IO.DirectoryInfo(tn); if (!di.Exists) { tn = windir + @"\assembly\GAC_64\"; tn += ttn + "\\"; di = new System.IO.DirectoryInfo(tn); if (!di.Exists) { tn = windir + @"\assembly\GAC_32\"; tn += ttn + "\\"; di = new System.IO.DirectoryInfo(tn); if (!di.Exists) { tn = windir + @"\assembly\GAC\"; tn += ttn + "\\"; di = new System.IO.DirectoryInfo(tn); if (!di.Exists) { return null; } } } } } } } } System.IO.DirectoryInfo[] diarr = di.GetDirectories(); tn = Path.Combine((diarr[0]).FullName, name); } else { string gac_path = "/usr/lib/mono/4.0/gac"; DirectoryInfo di = new DirectoryInfo(Path.Combine(gac_path, ttn)); if (di.Exists) { System.IO.DirectoryInfo[] diarr = di.GetDirectories(); tn = Path.Combine((diarr[diarr.Length - 1]).FullName, name); } else return null; } return tn; } public static string get_assembly_path(string name, bool search_for_intellisense) { //если явно задан каталог то ищем только там if (Environment.OSVersion.Platform != PlatformID.Unix && Environment.OSVersion.Platform != PlatformID.MacOSX && !name.StartsWith("%GAC%\\")) { if (Path.GetDirectoryName(name) != string.Empty) if (File.Exists(name)) return name; else return null; } if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) { string SystemDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName); string SearchDirectory = Path.Combine(SystemDirectory, "Lib"); if (File.Exists(Path.Combine(Environment.CurrentDirectory, name))) return Path.Combine(Environment.CurrentDirectory, name); if (File.Exists(Path.Combine(SearchDirectory, name))) { File.Copy(Path.Combine(SearchDirectory, name), Path.Combine(Environment.CurrentDirectory, name), true); return Path.Combine(Environment.CurrentDirectory, name); } } if (!search_for_intellisense && !name.StartsWith("%GAC%\\")) { string dir = Environment.CurrentDirectory; if (File.Exists(Path.Combine(dir, name))) { return Path.Combine(dir, name); } } return get_standart_assembly_path(name); } public CompilationUnit ReadDLL(string FileName, SyntaxTree.SourceContext sc = null) { if (DLLCache.ContainsKey(FileName)) return DLLCache[FileName]; OnChangeCompilerState(this, CompilerState.ReadDLL, FileName); TreeRealization.using_namespace_list using_namespaces = new TreeRealization.using_namespace_list(); try { TreeRealization.dot_net_unit_node un = new TreeRealization.dot_net_unit_node(new NetHelper.NetScope(using_namespaces, /*System.Reflection.Assembly.LoadFrom(file_name)*/ PascalABCCompiler.NetHelper.NetHelper.LoadAssembly(FileName), SyntaxTreeToSemanticTreeConverter.SymbolTable)); CompilationUnit cu = new CompilationUnit(); cu.SemanticTree = un; //un.dotNetScope=new PascalABCCompiler.NetHelper.NetScope(using_namespaces, // System.Reflection.Assembly.LoadFrom(file_name),SyntaxTreeToSemanticTreeConverter.SymbolTable); DLLCache[FileName] = cu; return cu; } catch (ReflectionTypeLoadException e) { foreach (var assm in assemblyResolveScope.missingAssemblies) errorsList.Add(new AssemblyNotFound(currentCompilationUnit.UnitFileName, assm, sc)); /*Console.Error.WriteLine(e.Message); foreach (var eLoaderException in e.LoaderExceptions) { Console.Error.WriteLine(eLoaderException.Message); }*/ return null; } catch (Exception e) { Console.Error.WriteLine(e.Message); return null; } } /*public CompilationUnit RecompileUnit(string unit_name) { Console.WriteLine("recompile {0}", unit_name); currentUnit = new SyntaxTree.uses_unit_in(new SyntaxTree.string_const(program_folder + "\\" + unit_name+".pas")); CompileUnit(unitsFromUsesSection, compilationUnit); CompilationUnit compilationUnit = new CompilationUnit(); if (unitsFromUsesSection.Count != 0) compilationUnit.SemanticTree = unitsFromUsesSection[unitsFromUsesSection.Count - 1]; else return null; return compilationUnit; }*/ public bool NeedRecompiled(string pcu_name, string[] included, PCUReader pr) { 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; 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) { if (UnitTable[Path.ChangeExtension(used_unit_fname, null)] != null) return true; need = true; RecompileList[pcu_name] = pcu_name; } } if (need) return true; if (!SourceFileExists(pas_name)) return false; // 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], dir, out _); //TODO: Спросить у Сащи насчет < и <=. if ((File.Exists(pcu_name2) && File.GetLastWriteTime(pcu_name) < File.GetLastWriteTime(pcu_name2) && !pr.AlreadyCompiled(pcu_name2))) { pr.AddAlreadyCompiledUnit(pcu_name2); return true; } if (RecompileList.ContainsKey(pcu_name2)) { return true; } } return false; } public void ClearAll(bool close_pcu = true) { semanticTree = null; if (close_pcu) { PCUReader.CloseUnits(); PCUWriter.Clear(); } RecompileList.Clear(); CycleUnits.Clear(); UnitTable.Clear(); UnitsLogicallySortedList.Clear(); //TreeRealization.PCUReturner.Clear(); BadNodesInSyntaxTree.Clear(); if (close_pcu) PCUReader.AllReaders.Clear(); project = null; StandardModules.Clear(); CompiledVariables.Clear(); if (assemblyResolveScope != null) assemblyResolveScope.Dispose(); assemblyResolveScope = null; if (!close_pcu) { SyntaxTreeToSemanticTreeConverter = new TreeConverter.SyntaxTreeToSemanticTreeConverter(); } //SystemLibrary.SystemLibrary.RestoreStandartNames(); } public CompilerType CompilerType { get { return CompilerType.Standart; } } public void Free() { } } }