pascalabcnet/ParserTools/ParsersController.cs
AlexanderZemlyak 0ae7595f0d
Implement programming languages integration functionality (#3001)
* Make standardModules Dictionary instead of LanguageId usage

* Create new common string constants for pascal language

* Add LanguagesData class template

* Move some compiler directive string constants to Compiler project

* Extract LanguagesData class to separate file

Also extracted RuntimeServiceModule (IO-modules) management to new functions.

* Fix pabcnetc crashing (KeyNotFoundException)

* Make similar change in pabcnetc_clear

* Return PABCExtensions in DomConverter.cs

* Return compiler string constants to Tree Converter

* Rename MoveSystemUnitForward method

* Rename system unit variable

* Add new parser load error (localized versions)

* Fix pascal language name constant

* Add system units property to parsers

* Add LanguageKits directory with a test file

* Implement language integrator

Был реализован загрузчик комплектов дополнительных языков (всех кроме Pascal). Был пересмотрен подход к реализации ParsersController и этот класс сделан синглтоном. Добавлена загрузка стандартных модулей языков в CompilerOptions.

* Squashed commit of the following:

commit 8f9dc7e5a0
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Mon Mar 11 20:33:13 2024 +0300

    fix #3050

commit 90363ced45
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sun Mar 3 21:37:25 2024 +0300

    Недобитки при сортировке строк

commit c9d7ba7758
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Sat Mar 2 13:32:14 2024 +0300

    Order и OrderDescending для строк с Ordinal

commit 6fbc0200bf
Author: AlexanderZemlyak <92867056+AlexanderZemlyak@users.noreply.github.com>
Date:   Tue Feb 27 23:21:26 2024 +0300

    Fix interface loop dependency check (#3047)

    Tests for problematic case were added

commit e4d63bfef9
Author: bormant <bormant@mail.ru>
Date:   Tue Feb 27 23:18:25 2024 +0300

    Fix typo: C (ru) -> C (en) (#3042)

commit 0d37232d21
Author: Mikhalkovich Stanislav <miks@math.sfedu.ru>
Date:   Tue Feb 27 19:15:08 2024 +0300

    School - исправление пустого диапазона простых и IP-адресов

commit 9fd4c7f338
Merge: 3cca2a89 6027083b
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Wed Feb 21 20:57:10 2024 +0100

    Merge branch 'master' of https://github.com/pascalabcnet/pascalabcnet

commit 3cca2a8949
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Wed Feb 21 20:56:49 2024 +0100

    fix in formatter
2024-03-13 22:16:40 +03:00

231 lines
9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using PascalABCCompiler.Errors;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
namespace PascalABCCompiler.Parsers
{
public class Controller
{
private static readonly Lazy<Controller> lazyInstanceWrapper = new Lazy<Controller>(() => new Controller(), true);
public static Controller Instance { get { return lazyInstanceWrapper.Value; } }
public const char HideParserExtensionPostfixChar = '_';
public event Action<IParser> ParserConnected;
public event Action<string> ParserLoadErrorOccured;
public List<IParser> Parsers = new List<IParser>();
public IParser LastParser;
/// <summary>
/// Загружает стандартные парсеры из папки бин (в частности PascalABCParser.dll)
/// </summary>
public void LoadStandardParsers()
{
string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName);
DirectoryInfo directory = new DirectoryInfo(directoryName);
FileInfo[] dllfiles = directory.GetFiles("*Parser.dll");
foreach (FileInfo parserFile in dllfiles)
{
if (Path.GetFileName(parserFile.FullName) == "VBNETParser.dll" || Path.GetFileName(parserFile.FullName) == "PascalABCPartParser.dll")
continue;
IntegrateParsersFromAssembly(parserFile);
}
}
/// <summary>
/// Загружает все парсеры языков из переданной сборки, используя рефлексию
/// </summary>
public void IntegrateParsersFromAssembly(FileInfo parserFile)
{
Assembly assembly = Assembly.LoadFile(parserFile.FullName);
try
{
Type[] types = assembly.GetTypes();
if (assembly != null)
{
foreach (Type type in types)
{
if (type.Name.IndexOf("LanguageParser") >= 0)
{
object obj = Activator.CreateInstance(type);
if (obj is IParser parser)
{
SaveParser(parser);
}
}
}
}
}
catch (ReflectionTypeLoadException e)
{
#if DEBUG
string errorMessage = e + Environment.NewLine;
errorMessage += "<Loader exceptions>:" + Environment.NewLine;
errorMessage += string.Join(Environment.NewLine, e.LoaderExceptions.Select(error => error.ToString())) + Environment.NewLine;
File.AppendAllText("log.txt", errorMessage);
#endif
string errorLocalized = string.Format(ParserErrorsStringResources.Get("LOAD_ERROR{0}"), Path.GetFileName(parserFile.FullName));
ParserLoadErrorOccured?.Invoke(errorLocalized + Environment.NewLine);
}
catch (Exception e)
{
#if DEBUG
string errorMessage = e + Environment.NewLine;
File.AppendAllText("log.txt", errorMessage);
#endif
string errorLocalized = string.Format(ParserErrorsStringResources.Get("LOAD_ERROR{0}"), Path.GetFileName(parserFile.FullName));
ParserLoadErrorOccured?.Invoke(errorLocalized + Environment.NewLine);
}
}
private Controller()
{
sourceFilesProvider = SourceFilesProviders.DefaultSourceFilesProvider;
}
SourceFilesProviderDelegate sourceFilesProvider = null;
public SourceFilesProviderDelegate SourceFilesProvider
{
get
{
return sourceFilesProvider;
}
set
{
sourceFilesProvider = value;
foreach (IParser parser in Parsers)
{
parser.SourceFilesProvider = value;
}
}
}
/// <summary>
/// Добавляет парсер в общий список парсеров (с вызовом инициализации парсера)
/// </summary>
private void SaveParser(IParser parser)
{
Parsers.Add(parser);
parser.Reset();
parser.SourceFilesProvider = SourceFilesProvider;
ParserConnected?.Invoke(parser);
}
/// <summary>
/// Возвращает подходящий для переданного расширения парсер из имеющихся
/// </summary>
public IParser SelectParser(string extension)
{
foreach (IParser parser in Parsers)
foreach (string parserExtension in parser.FilesExtensions)
if (parserExtension.ToLower() == extension)
return parser;
return null;
}
public bool ParserExists(string ext)
{
return SelectParser(ext) != null;
}
/// <summary>
/// Строит синтаксическое дерево с автоматическим выбором подходящего парсера
/// </summary>
/// <exception cref="ParserBadFileExtension"></exception>
public SyntaxTree.syntax_tree_node SelectParserForUnitAndBuildTree(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings, ParseMode ParseMode, List<string> DefinesList = null)
{
LastParser = SelectParser(Path.GetExtension(FileName).ToLower());
if (LastParser == null)
throw new ParserBadFileExtension(FileName);
LastParser.Errors = Errors;
LastParser.Warnings = Warnings;
return LastParser.BuildTree(FileName, Text, ParseMode, DefinesList);
}
/// <summary>
/// Возвращеает синтаксическое дерево модуля
/// </summary>
public SyntaxTree.compilation_unit GetCompilationUnit(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings, ParseMode parseMode, List<string> DefinesList = null)
{
return GetSyntaxTree<SyntaxTree.compilation_unit>(FileName, Text, Errors, Warnings, parseMode, DefinesList);
}
public SyntaxTree.compilation_unit GetCompilationUnitForFormatter(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings)
{
try // SSM 06.09.18
{
return GetSyntaxTree<SyntaxTree.compilation_unit>(FileName, Text, Errors, Warnings, ParseMode.ForFormatter);
}
catch (ParserBadFileExtension e)
{
Errors.Add(e);
return null;
// Погасить исключение если оно не погашено ранее
}
}
public SyntaxTree.expression GetExpression(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings)
{
try // SSM 06.09.18
{
return GetSyntaxTree<SyntaxTree.expression>(FileName, Text, Errors, Warnings, ParseMode.Expression);
}
catch
{
return null;
}
}
public SyntaxTree.expression GetTypeAsExpression(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings)
{
return GetSyntaxTree<SyntaxTree.expression> (FileName, Text, Errors, Warnings, ParseMode.TypeAsExpression);
}
public SyntaxTree.statement GetStatement(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings)
{
return GetSyntaxTree<SyntaxTree.statement>(FileName, Text, Errors, Warnings, ParseMode.Statement);
}
/// <summary>
/// Обобщенная функция для получения различных синтаксических узлов
/// </summary>
private T GetSyntaxTree<T>(string FileName, string Text, List<Error> Errors, List<CompilerWarning> Warnings, ParseMode parseMode, List<string> DefinesList = null) where T : SyntaxTree.syntax_tree_node
{
SyntaxTree.syntax_tree_node unitNode = SelectParserForUnitAndBuildTree(FileName, Text, Errors, Warnings, parseMode, DefinesList);
if (unitNode == null)
return null;
if (unitNode is T)
return unitNode as T;
Errors.Add(new UnexpectedNodeType(FileName, unitNode.source_context, null));
return null;
}
public void Reset()
{
}
}
}