* Add first comments
* Finish commenting for Compile and CompileUnit
* Write TODO sections
* Add a few clarifications
* splitted some functions from compile
* Written some methods from Compile to functions
* Update variable names
* Refactor - stage 1
Refactor GetUsesSection and IsPossibleNameSpace
* Refactor - stage 2
Rename a few functions and variables
* Correct an inaccuracy
* Added comments, look through CompileUnit
* Rename a few functions and add new comments
* Split CompileUnit to Subfunctions
Add IsUnitCompiled, IsUnitInPCU, InitializeNewUnit, GetSourceCode, GenSyntaxTree, GenUnitDocumentation, CheckDLLDirectiveOnlyForLibraries, MatchErrorsToBadNodes, CheckIfUnitModule, SetUseDLLForSystemUnits,
CompileInterfaceDependencies, CompileCurrentUnitInterface, GetImplementationUsesSection, CompileImplementationDependencies, CompileCurrentUnitImplementation
* Added some TODOs
* Return uses_unit_in original name
Renaming of syntax tree nodes leads to internal compiler errors
* Extract GenerateILCode method
* Add checking if recompilation needed method
Needs to be discussed and revised
* Add functions for catch blocks in Compile
* Extract building semantic tree method
Creating main function to be moved to another class
* Rename UnitsSortedList
* Edit CompileUnitsFromDelayedList method
* Change a few variable names, make CreateRCFile function and add comments
* Make code more "user-friendly"
* Add TODOs 31.11.23
* Create PrebuildSemanticTreeActionsMethod
* Refactor semantic checks section in initialize new unit method
* Refactor Adding standard units to uses method
* Return file_name and compiler_directives original names to avoid internal compilation errors
* Refactor GetReferences Method
* Initial refactoring of IncludeNamespaces function
* Create three more methods and wrap important code in regions
* Add TODO's
* Resolve merge conflicts
* Add returned value to ConstructSyntaxTree method
* Fix UnitsSortedList NotFoundError in PCUWriter
* Workaround commit
* Update PABCSystem after tests' changes
* Rename syntax trees in some methods
* Delete CurrentSyntaxUnit variable
* Revert unnecessary project files changes
* Squashed commit of the following:
commit f4d7599f1a39252feac97bd5391f46dfdc25f6f4
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 22 11:43:29 2023 +0300
added links to identarranger
commit 3bd5d33e2b2969884e61a3279ff9c353013b57fe
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 22 11:43:03 2023 +0300
Change extension for verybasic to yavb
commit 61294c6e7d405e1c68516cc81d3a109e8a1ee295
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Tue Nov 21 09:33:57 2023 +0300
Change Program Example
commit 86971488341ed6bf13c39e13a513d7ac0c51c285
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Tue Nov 21 09:28:59 2023 +0300
Add IndentArranger to Compile
commit 2ce50bbbf9db22c4243b247b870f6935ce206d26
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Fri Nov 17 10:00:31 2023 +0300
Add Semicolon After Each Statement
commit 796309d340e8d8ba730ff9418fa376f34fb7fd36
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Wed Nov 15 18:49:11 2023 +0300
Add Alpha Version of Python-style If-statement
commit 5eb88f946fe8254b4f5c5a56ed0a567b3be51227
Merge: ab4ce5b0 0162b637
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 15 16:54:26 2023 +0300
Merge branch 'IndentArranger' into VeryBasicLanguage
commit ab4ce5b0e32d42004726e3dc45cc0d8a65e53f56
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 15 16:53:51 2023 +0300
Fixes from seminar
commit af74012289d0d08517c13499a2a66cb543fc06d2
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Sun Nov 12 18:57:29 2023 +0300
finally working!
fully implemented compatibility
commit 58a39c313324b468d1eec207ba3f5f6eddf74ef2
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Sun Nov 12 11:58:16 2023 +0300
more compatibility with pabc
Now verybasic statements translate to pascal compiler
added .bat script for autobuilding verybasic
commit 0162b6376b8fe970704f26213bf9f0f670dfb12e
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Sun Nov 12 10:06:14 2023 +0300
Update test.txt
commit 1b759ab1cd7ee2ffeb14afff0418ddf0f30b0399
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Sun Nov 12 10:05:36 2023 +0300
Add Indent and Unindent Keywords to Generated File
commit cabda7f3985651cff2a8740f1a5bdea8fe7ac892
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Fri Nov 10 21:25:52 2023 +0300
Add Generation of Output File
commit 306f033d0176ab559e3622b8505427dbe2e0e203
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Thu Nov 9 20:42:18 2023 +0300
Update IndentArranger.sln
commit 60c0ceced1aa3a7d2e33de0facb1126e295f43b5
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Thu Nov 9 20:41:22 2023 +0300
Add IndentArranger
commit 1f4556c4573dae154fcc167b41ff6ab9e8122136
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Mon Nov 6 22:48:36 2023 +0300
Made my own VeryBasicParser project
Copied some code from SaushkinParser
Tried to compile it and implement into Pascal
Doesn't work due to grammatik issue
* Squashed commit of the following:
commit 4e73d9ac3ffef68312f06a74dc83afffcf3ccbee
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 22 15:08:10 2023 +0300
Fixed GPPG (i think so at least)
commit e5cfc220828b37fb2f35e565683019716ec3f0ce
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 22 11:44:27 2023 +0300
Update Compiler.cs
commit 4698e2e75a5f3b4f523a8bc7733a50e8abb4fca1
Merge: 22aaf2b2 f4d7599f
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 22 11:43:54 2023 +0300
Merge branch 'IndentArrangerTemp' into VeryBasicLanguage
commit f4d7599f1a39252feac97bd5391f46dfdc25f6f4
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 22 11:43:29 2023 +0300
added links to identarranger
commit 3bd5d33e2b2969884e61a3279ff9c353013b57fe
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 22 11:43:03 2023 +0300
Change extension for verybasic to yavb
commit 22aaf2b2508278a9ffce525ffed52419bf72c23f
Merge: c326174f 61294c6e
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 22 11:26:36 2023 +0300
Merge branch 'IndentArrangerTemp' into VeryBasicLanguage
commit 61294c6e7d405e1c68516cc81d3a109e8a1ee295
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Tue Nov 21 09:33:57 2023 +0300
Change Program Example
commit 86971488341ed6bf13c39e13a513d7ac0c51c285
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Tue Nov 21 09:28:59 2023 +0300
Add IndentArranger to Compile
commit c326174ff5ecccf9c4f76d58aea4653f047af049
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Sun Nov 19 15:03:19 2023 +0300
Added UniversalParserHelper and GPPG
ShiftReduceParser moved to another project
UniversalParserHelper project added, most of it copied from SaushkinParser
commit 2ce50bbbf9db22c4243b247b870f6935ce206d26
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Fri Nov 17 10:00:31 2023 +0300
Add Semicolon After Each Statement
commit 796309d340e8d8ba730ff9418fa376f34fb7fd36
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Wed Nov 15 18:49:11 2023 +0300
Add Alpha Version of Python-style If-statement
commit 5eb88f946fe8254b4f5c5a56ed0a567b3be51227
Merge: ab4ce5b0 0162b637
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 15 16:54:26 2023 +0300
Merge branch 'IndentArranger' into VeryBasicLanguage
commit ab4ce5b0e32d42004726e3dc45cc0d8a65e53f56
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Wed Nov 15 16:53:51 2023 +0300
Fixes from seminar
commit af74012289d0d08517c13499a2a66cb543fc06d2
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Sun Nov 12 18:57:29 2023 +0300
finally working!
fully implemented compatibility
commit 58a39c313324b468d1eec207ba3f5f6eddf74ef2
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Sun Nov 12 11:58:16 2023 +0300
more compatibility with pabc
Now verybasic statements translate to pascal compiler
added .bat script for autobuilding verybasic
commit 0162b6376b8fe970704f26213bf9f0f670dfb12e
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Sun Nov 12 10:06:14 2023 +0300
Update test.txt
commit 1b759ab1cd7ee2ffeb14afff0418ddf0f30b0399
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Sun Nov 12 10:05:36 2023 +0300
Add Indent and Unindent Keywords to Generated File
commit cabda7f3985651cff2a8740f1a5bdea8fe7ac892
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Fri Nov 10 21:25:52 2023 +0300
Add Generation of Output File
commit 306f033d0176ab559e3622b8505427dbe2e0e203
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Thu Nov 9 20:42:18 2023 +0300
Update IndentArranger.sln
commit 60c0ceced1aa3a7d2e33de0facb1126e295f43b5
Author: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Date: Thu Nov 9 20:41:22 2023 +0300
Add IndentArranger
commit 1f4556c4573dae154fcc167b41ff6ab9e8122136
Author: Владислав Крылов <krylov@sfedu.ru>
Date: Mon Nov 6 22:48:36 2023 +0300
Made my own VeryBasicParser project
Copied some code from SaushkinParser
Tried to compile it and implement into Pascal
Doesn't work due to grammatik issue
* Changed GPPG project NET Framework version, added .dll to gitignore
* Adding UniversalParserHelper to project, trying to include VeryBasic
* Managed dependencies and got VeryBasicLanguage to work
* Change extension of a test program
* Rebuild changes
What should be added to .gitignore?
* Fix bug related to err0524_res_unit.pas
* Rebuild Parser
* Change Indent and Unindent tokens
* Add Symbol Table to ParserABC.y
* Change Indent Space Number to 2
* Add While Loop
* Add Some Operations to Parser
* Make Initialization Node at the Beginning of a program
* Create Grammar.txt
* Test program added
* Add ELIF and SyntaxHighlight
* Fix TableSymbol
* Add Division
* Add Method Call
* Add For Loop
* Rename SPython Parser Folder
* Add documented comments for CompileUnit method
* Added Errors to SPython
Added Errors.cs
Removed link to PABCSaushkinParser
Minor fixes
* Create default constructor for SourceContext
* Move null check of currentUnit to upper level in CompileUnit
* Move CreateMainFunction method from Compiler to TreeConverter class
* Add gppg and parserhelper to visualpascalabcnet dependencies
* Updated installer files to include GPPG and UniversalParserHelper
* Rename GPPG to ShiftReduceParser
* Fix ShiftReduceParser project dependencies
* Fix ShiftReduceParserDependencies second iteration
* Workaround commit
* Update PABCSystem after tests' changes
* Refactor ConvertDirectives method
* Get rid of legacy standard modules code
* Return varBeginOffset and beginOffset calculation to Compiler class
Размещение метода в SyntaxTreeToSemanticTreeConverter не целесообразно. В комментарии видимо имелось в виду что-то другое.
* Workaround commit
* Update PABCSystem after tests' changes
* Revert SPython changes
Оставляем только изменения связанные с рефакторингом.
* Update .gitignore
Co-authored-by: Sun Serega <sunserega2@gmail.com>
* Resolve a few Sun Serega treds
* Delete comments in ParsersController.cs
* Replace specific path with path variable in Studio.bat
* Add comment in Studio.bat file and return FileName in CompilerError.cs
* Fix TreeSubsidiary.cs encoding and sectCore.nsh indents
* Return old version of TestRunner.exe
* Rename some variables and polish a few methods
* Uncomment accidentally commented code
* Replace spaces with tabs
* Changed dll name from GPPG
* Revert "Changed dll name from GPPG"
This reverts commit c485cc8cb787809b7e9dfa8a361e75f17ed39893.
* Update .gitignore
* Delete Libraries/ShiftReduceParser.dll
* Delete bin\ShiftReduceParser.dll
* Replace tabs with spaces
* Update encoding in Studio.bat
* Fix bug with PABCrtl excluded files
* Refactor StandardModule class
* Add null checks to make debuging easier
* Delete unnecessary null checks in SymTable.cs
---------
Co-authored-by: Владислав Крылов <krylov@sfedu.ru>
Co-authored-by: MovchanGitHub <92666028+MovchanGitHub@users.noreply.github.com>
Co-authored-by: Sun Serega <sunserega2@gmail.com>
4614 lines
219 KiB
C#
4614 lines
219 KiB
C#
// 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;
|
||
/// <summary>
|
||
/// поле для проверки на циклическую зависимость интерфейсов модулей
|
||
/// </summary>
|
||
public string currentUsedUnitId;
|
||
public PascalABCCompiler.Errors.SyntaxError syntax_error;
|
||
public string UnitFileName;
|
||
public List<Errors.Error> ErrorList = new List<Errors.Error>();
|
||
public bool Documented;
|
||
internal List<SyntaxTree.unit_or_namespace> possibleNamespaces = new List<PascalABCCompiler.SyntaxTree.unit_or_namespace>();
|
||
//internal List<CompilationUnit> AssemblyReferences = new List<CompilationUnit>();
|
||
|
||
//private SemanticTree.compilation_unitArrayList _interfaceUsedUnits=new SemanticTree.compilation_unitArrayList();
|
||
|
||
/// <summary>
|
||
/// Только "реальные" юниты (не dll и namespace)
|
||
/// </summary>
|
||
public Dictionary<unit_node, CompilationUnit> InterfaceUsedDirectUnits { get; } = new Dictionary<unit_node, CompilationUnit>();
|
||
|
||
public unit_node_list InterfaceUsedUnits { get; } = new unit_node_list();
|
||
/// <summary>
|
||
/// Только "реальные" юниты (не dll и namespace)
|
||
/// </summary>
|
||
public Dictionary<unit_node, CompilationUnit> ImplementationUsedDirectUnits { get; } = new Dictionary<unit_node, CompilationUnit>();
|
||
public unit_node_list ImplementationUsedUnits { get; } = new unit_node_list();
|
||
|
||
public bool ForEachDirectCompilationUnit(Func<CompilationUnit, string, bool> 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;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Опции компиляции
|
||
/// </summary>
|
||
//[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<string> ForceDefines = new List<string>();
|
||
|
||
public List<string> 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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// module at index 0 is System module
|
||
/// </summary>
|
||
public List<StandardModule> 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<StandardModule>();
|
||
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<string> DocumentedUnits = new List<string>();
|
||
|
||
#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<string> ext = new List<string>();
|
||
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<var_definition_node> CompiledVariables = new List<var_definition_node>();
|
||
|
||
private Dictionary<string, List<TreeRealization.compiler_directive>> 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<SupportedSourceFile> supportedSourceFilesList = new List<SupportedSourceFile>();
|
||
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<SupportedSourceFile> supportedProjectFilesList = new List<SupportedSourceFile>();
|
||
/*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<CompilationUnit> UnitsLogicallySortedList = new List<CompilationUnit>();
|
||
|
||
private List<string> StandardModules = new List<string>();
|
||
public CompilerOptions CompilerOptions { get; set; } = new CompilerOptions();
|
||
|
||
internal Dictionary<string, CompilationUnit> DLLCache = new Dictionary<string, CompilationUnit>();
|
||
|
||
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;
|
||
|
||
/// <summary>
|
||
/// список отложенной компиляции реализации (она будет откомпилирована в Compile, а не в СompileUnit)
|
||
/// </summary>
|
||
private List<CompilationUnit> UnitsToCompileDelayedList = new List<CompilationUnit>();
|
||
public Hashtable RecompileList = new Hashtable(StringComparer.OrdinalIgnoreCase);
|
||
private Hashtable CycleUnits = new Hashtable();
|
||
public CompilationUnit currentCompilationUnit = null;
|
||
private CompilationUnit firstCompilationUnit = null;
|
||
private bool PCUReadersAndWritersClosed;
|
||
/// <summary>
|
||
/// Начало основной программы
|
||
/// </summary>
|
||
public int beginOffset;
|
||
/// <summary>
|
||
/// Положение первых переменных в пространстве имен основной программы
|
||
/// </summary>
|
||
public int varBeginOffset;
|
||
private bool _clear_after_compilation = true;
|
||
private static Dictionary<string, CompilationUnit> pcuCompilationUnits = new Dictionary<string, CompilationUnit>();
|
||
|
||
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<CompilerWarning> warnings = new List<CompilerWarning>();
|
||
public List<CompilerWarning> Warnings
|
||
{
|
||
get
|
||
{
|
||
return warnings;
|
||
}
|
||
}
|
||
|
||
public Dictionary<Tuple<string, string>, Tuple<string, int>> SourceFileNamesDictionary { get; } = new Dictionary<Tuple<string, string>, Tuple<string, int>>();
|
||
|
||
public Dictionary<Tuple<string, string>, Tuple<string, int>> PCUFileNamesDictionary { get; } = new Dictionary<Tuple<string, string>, Tuple<string, int>>();
|
||
|
||
public Dictionary<Tuple<string, string>, string> GetUnitFileNameCache { get; } = new Dictionary<Tuple<string, string>, string>();
|
||
|
||
public void AddWarnings(List<CompilerWarning> 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<Errors.Error> errorsList = new List<Errors.Error>();
|
||
public List<Errors.Error> 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<string, List<compiler_directive>> GetCompilerDirectives(List<CompilationUnit> Units)
|
||
{
|
||
Dictionary<string, List<compiler_directive>> directives = new Dictionary<string, List<compiler_directive>>(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<compiler_directive>());
|
||
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));
|
||
}
|
||
|
||
/// <summary>
|
||
/// преобразует в директивы семантического уровня
|
||
/// </summary>
|
||
private List<compiler_directive> GetDirectivesAsSemanticNodes(List<SyntaxTree.compiler_directive> compilerDirectives, string unitFileName)
|
||
{
|
||
List<compiler_directive> list = new List<compiler_directive>();
|
||
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<string> modules = new List<string>();
|
||
public List<string> addit_imports = new List<string>();
|
||
public List<string> addit_project_files = new List<string>();
|
||
}
|
||
|
||
private void add_import_info(ProgInfo info, List<string> 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<string> mods = new List<string>();
|
||
List<int> inds = new List<int>();
|
||
for (int i=0; i<info.modules.Count; i++)
|
||
{
|
||
switch (info.modules[i])
|
||
{
|
||
case "GraphABCHelper" : inds.Add(0); break;
|
||
case "GraphABC" : inds.Add(1); break;
|
||
case "ABCObjects" : inds.Add(2); break;
|
||
case "ABCHouse" : inds.Add(3); break;
|
||
case "ABCSprites" : inds.Add(3); break;
|
||
case "ABCButtons" : inds.Add(3); break;
|
||
case "DMCollect" : inds.Add(0); break;
|
||
case "DrawManField" : inds.Add(2); break;
|
||
case "DMZadan" : inds.Add(4); break;
|
||
case "DMTaskMaker" : inds.Add(3); break;
|
||
case "RobotField" : inds.Add(2); break;
|
||
case "RobotTaskMaker" : inds.Add(3); break;
|
||
case "RobotZadan" : inds.Add(4); break;
|
||
case "Robot" : inds.Add(5); break;
|
||
}
|
||
}*/
|
||
|
||
}
|
||
|
||
private int find_pos(string s, int line, int col, bool search_main)
|
||
{
|
||
int ind_ln = 1;
|
||
int ind_col = 1;
|
||
int pos = 0;
|
||
for (int i = 0; i < s.Length; i++)
|
||
{
|
||
if (ind_col == col && ind_ln == line)
|
||
{
|
||
if (search_main)
|
||
{
|
||
pos += 3;
|
||
while (s[pos] != 'M' && s[pos] != 'm')
|
||
pos++;
|
||
}
|
||
return pos;
|
||
}
|
||
if (s[i] == '\n')
|
||
{
|
||
ind_col = 1;
|
||
ind_ln++;
|
||
}
|
||
else
|
||
{
|
||
ind_col++;
|
||
}
|
||
pos++;
|
||
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
private ProgInfo get_programm_info(ICSharpCode.NRefactory.Ast.CompilationUnit cu, string source)
|
||
{
|
||
ProgInfo info = new ProgInfo();
|
||
List<string> usings = new List<string>();
|
||
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<string, string>();
|
||
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<string> sources = new List<string>();
|
||
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<SyntaxTree.unit_or_namespace> 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<compiler_directive> compilerDirectivesList = new List<compiler_directive>();
|
||
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<compiler_directive>();
|
||
|
||
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<unit_node, CompilationUnit>(),
|
||
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));
|
||
}
|
||
|
||
OnChangeCompilerState(this, CompilerState.CompilationFinished, CompilerOptions.SourceFileName); // compilation finished state
|
||
|
||
if (ClearAfterCompilation)
|
||
ClearAll();
|
||
|
||
// на случай ошибки в самом .pcu формате | теоретически, здесь могут быть не только pcu errors EVA
|
||
bool recompilationNeeded = CheckForInternalErrors();
|
||
|
||
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<string> 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<string, object> config_dict = new Dictionary<string, object>();
|
||
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 CheckForInternalErrors()
|
||
{
|
||
bool anyExternalErrors = false;
|
||
|
||
if (ErrorsList.Count > 0)
|
||
{
|
||
// rtl - та самая dll со всей паскалевской системой (PABCSystem)
|
||
if (CompilerOptions.UseDllForSystemUnits && !HasOnlySyntaxErrors(ErrorsList) && CompilerOptions.IgnoreRtlErrors)
|
||
{
|
||
CompilerOptions.UseDllForSystemUnits = false;
|
||
ErrorsList.Clear();
|
||
|
||
anyExternalErrors = true;
|
||
|
||
}
|
||
}
|
||
|
||
return anyExternalErrors;
|
||
}
|
||
|
||
private void GenerateILCode(program_node programNode, NETGenerator.CompilerOptions compilerOptions, List<string> 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<string> GetResourceFilesFromCompilerDirectives()
|
||
{
|
||
List<string> ResourceFiles = null;
|
||
if (compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.compiler_directive_resource))
|
||
{
|
||
ResourceFiles = new List<string>();
|
||
List<compiler_directive> 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<Error> 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();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Бросает ошибку если находит дупликаты в секции uses
|
||
/// </summary>
|
||
void CheckForDuplicatesInUsesSection(List<SyntaxTree.unit_or_namespace> usesList)
|
||
{
|
||
if (usesList == null)
|
||
return;
|
||
List<string> names = new List<string>();
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Возвращает список зависимостей из интерфейсной части модуля (или основной программы)
|
||
/// </summary>
|
||
public List<SyntaxTree.unit_or_namespace> GetInterfaceUsesSection(SyntaxTree.compilation_unit unitSyntaxTree)
|
||
{
|
||
List<SyntaxTree.unit_or_namespace> 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<SyntaxTree.unit_or_namespace> GetImplementationUsesSection(SyntaxTree.compilation_unit unitSyntaxTree)
|
||
{
|
||
|
||
List<SyntaxTree.unit_or_namespace> 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<CompilationUnit, string>();
|
||
var done = new HashSet<CompilationUnit>();
|
||
|
||
var res_path = default(string);
|
||
Func<CompilationUnit, string, bool> 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<CompilationUnit, string>();
|
||
|
||
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<SyntaxTree.unit_or_namespace> 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<string, SyntaxTree.syntax_namespace_node> PrepareUserNamespacesUsedInTheCurrentUnit(CompilationUnit compilationUnit)
|
||
{
|
||
var directives = GetDirectivesAsSemanticNodes(compilationUnit.SyntaxTree.compiler_directives, compilationUnit.SyntaxTree.file_name);
|
||
|
||
List<string> files = GetIncludedFilesFromDirectives(compilationUnit, directives);
|
||
|
||
Dictionary<string, SyntaxTree.syntax_namespace_node> namespaces = new Dictionary<string, SyntaxTree.syntax_namespace_node>(StringComparer.OrdinalIgnoreCase);
|
||
|
||
List<SyntaxTree.unit_or_namespace> namespaceModules = new List<SyntaxTree.unit_or_namespace>();
|
||
|
||
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<SyntaxTree.unit_or_namespace> 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<string> set = new HashSet<string>();
|
||
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<SyntaxTree.unit_or_namespace> 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<string> GetIncludedFilesFromDirectives(CompilationUnit compilationUnit, List<compiler_directive> directives)
|
||
{
|
||
List<string> files = new List<string>();
|
||
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<string> definesList = new List<string> { "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<compiler_directive> 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<compiler_directive>();
|
||
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<compiler_directive> 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", "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, "."));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Формирует узел семантического дерева, соответствующий пространству имен (.NET или пользовательскому)
|
||
/// </summary>
|
||
/// <exception cref="UnitNotFound"></exception>
|
||
/// <exception cref="TreeConverter.NamespaceNotFound"></exception>
|
||
private using_namespace GetNamespace(using_namespace_list usingList, string fullNamespaceName, SyntaxTree.unit_or_namespace name_space, bool mightBeUnit, Dictionary<string, SyntaxTree.syntax_namespace_node> 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<SyntaxTree.unit_or_namespace> possibleNamespaces, bool mightContainUnits, Dictionary<string, SyntaxTree.syntax_namespace_node> 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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// получение списка using - legacy code !!!
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// получение списка using - legacy code !!!
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// получение списка using - legacy code !!!
|
||
/// </summary>
|
||
public string GetSourceFileText(string FileName)
|
||
{
|
||
return (string)SourceFilesProvider(FileName, SourceFileOperation.GetText);
|
||
}
|
||
|
||
|
||
public SyntaxTree.compilation_unit ParseText(string fileName, string text, List<Error> errorList, List<CompilerWarning> 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<Error> errorList, List<CompilerWarning> warnings, List<string> 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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Проверяет, является ли модуль dll по соответствующей директиве
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Проверяет, является ли модуль dll по соответствующей директиве и возвращает эту директиву выходным параметром
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Компилирует основную программу и все используемые ей юниты рекурсивно
|
||
/// </summary>
|
||
/// <param name="unitsFromUsesSection"> Вспомогательная переменная для заполнения CompilationUnit.interfaceUsedUnits и
|
||
/// CompilationUnit.implementationUsedUnits (здесь могут содержаться юниты и dll) </param>
|
||
///
|
||
/// <param name="directUnitsFromUsesSection">Вспомогательная переменная для заполнения CompilationUnit.interfaceUsedDirectUnits и
|
||
/// CompilationUnit.implementationUsedDirectUnits</param>
|
||
///
|
||
/// <param name="currentUnitNode">Синтаксический узел текущего модуля (или пространства имен)</param>
|
||
/// <param name="previousPath">Директория родительского модуля</param>
|
||
/// <returns>Скомпилированный юнит</returns>
|
||
public CompilationUnit CompileUnit(unit_node_list unitsFromUsesSection, Dictionary<unit_node, CompilationUnit> 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<SyntaxTree.syntax_tree_node, string> 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<SyntaxTree.unit_or_namespace> 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<SyntaxTree.unit_or_namespace> interfaceUsesList,
|
||
out unit_node_list references, out Dictionary<string, SyntaxTree.syntax_namespace_node> 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<unit_node, CompilationUnit> 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<SyntaxTree.syntax_tree_node, string> 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();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Компилирует модули из секции uses текущего модуля реализации рекурсивно
|
||
/// </summary>
|
||
private void CompileImplementationDependencies(string currentPath, CompilationUnit currentUnit, List<SyntaxTree.unit_or_namespace> implementationUsesList,
|
||
Dictionary<string, SyntaxTree.syntax_namespace_node> 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<SyntaxTree.syntax_tree_node, string> 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();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Компилирует модули из секции uses интерфейса текущего модуля рекурсивно
|
||
/// </summary>
|
||
/// <exception cref="CycleUnitReference"></exception>
|
||
private void CompileInterfaceDependencies(unit_node_list unitsFromUsesSection, Dictionary<unit_node, CompilationUnit> directUnitsFromUsesSection, SyntaxTree.unit_or_namespace currentUnitNode,
|
||
string unitFileName, string currentPath, CompilationUnit currentUnit, List<SyntaxTree.unit_or_namespace> interfaceUsesList, unit_node_list references,
|
||
Dictionary<string, SyntaxTree.syntax_namespace_node> 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);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Если в программе в секции uses есть не про-во имен и не стандартный модуль, то использование PABCRtl.dll отменяется
|
||
/// </summary>
|
||
private void SetUseDLLForSystemUnits(string currentDirectory, List<SyntaxTree.unit_or_namespace> 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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получение исходного кода модуля, заполнение документации,
|
||
/// генерация синтаксического дерева,
|
||
/// обработка синтаксических ошибок
|
||
/// </summary>
|
||
private void InitializeNewUnit(SyntaxTree.unit_or_namespace currentUnitNode, string UnitFileName, string UnitId, ref CompilationUnit currentUnit, ref Dictionary<SyntaxTree.syntax_tree_node, string> 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;
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Проверка, что директива dll только в Library - требует передачи директивы dll
|
||
/// </summary>
|
||
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<string> DefinesList = new List<string> { "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<SyntaxTree.syntax_tree_node, string> GenUnitDocumentation(CompilationUnit currentUnit, string SourceText)
|
||
{
|
||
Dictionary<SyntaxTree.syntax_tree_node, string> 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<unit_node, CompilationUnit> 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<SyntaxTree.syntax_tree_node, string> AddDocumentationToNodes(SyntaxTree.compilation_unit unitSyntaxTree, string text)
|
||
{
|
||
List<Error> errors = new List<Error>();
|
||
|
||
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<CompilerWarning>(), 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<string, string> standart_assembly_dict = new Dictionary<string, string>();
|
||
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()
|
||
{
|
||
}
|
||
}
|
||
}
|