pascalabcnet/AdditionalLanguages/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/StandardSyntaxTreeConverter.cs
Александр Земляк 1f4b44c2c0
Исправление ошибок при перекомпиляции pcu файлов (#3398)
* Move yield string constants to StringConstants class

* Add GeneratedNamesManager class to store all generated names during unit compilation

* Make GeneratedNamesManager class non static

* Add Utils project to installer files

* Add GeneratedNamesManager usage in CapturedVariablesSubstitutionsManager

* Move GeneratedNamesManager initialization in CompilationUnit constructor

* More GeneratedNamesManager usage

* QuestionPointDesugarVisitor fix
2026-03-08 18:30:33 +03:00

155 lines
8.4 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.

using Languages.Pascal.Frontend.Converters;
using PascalABCCompiler;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.SyntaxTreeConverters;
using SyntaxVisitors;
using SyntaxVisitors.SugarVisitors;
using System;
using PascalABCCompiler.CoreUtils;
namespace Languages.SPython.Frontend.Converters
{
public class StandardSyntaxTreeConverter : BaseSyntaxTreeConverter
{
public override string Name { get; } = "Standard";
protected override syntax_tree_node ApplyConversions(syntax_tree_node root, bool forIntellisense)
{
var generatedNamesManager = new GeneratedNamesManager();
// кидает ошибки за использование
// неподдерживаемых конструкций языка
if (!forIntellisense)
new UnsupportedConstructsVisitor().ProcessNode(root);
// добавление всех import ..., from ... import ...
// как uses в начале программы для сбора имён из этих модулей
if (!forIntellisense)
new ImportToUsesVisitor().ProcessNode(root);
// замена
// name bin_bit_op= expr
// на
// name = name bin_bit_op (expr)
new TryCatchDecorator(new BitwiseAssignmentDesugarVisitor(), forIntellisense).ProcessNode(root);
// замена return; на { exit(); }
// замена return expr; на { result := expr; exit(); }
new TryCatchDecorator(new ReturnDesugarVisitor(), forIntellisense).ProcessNode(root);
// замена вызова функции map(func, sequence)
// на func(element) for element in sequence
new TryCatchDecorator(new MapDesugarVisitor(), forIntellisense).ProcessNode(root);
// замена генерации последовательностей на Select.Where
// (не работает из-за лямбд (скорее всего), если переместить в ConvertAfterUsedModulesCompilation)
new TryCatchDecorator(new GeneratorObjectDesugarVisitor(root, generatedNamesManager), forIntellisense).ProcessNode(root);
// Выносим выражения с лямбдами из заголовка foreach + считаем максимум 10 вложенных лямбд
// украл из паскаля
new TryCatchDecorator(StandOutExprWithLambdaInForeachSequenceAndNestedLambdasVisitor.Create(generatedNamesManager), forIntellisense).ProcessNode(root);
new TryCatchDecorator(new VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer(root as compilation_unit), forIntellisense).ProcessNode(root);
new TryCatchDecorator(FindOnExceptVarsAndApplyRenameVisitor.Create(generatedNamesManager), forIntellisense).ProcessNode(root);
// дешугаризация составных сравнительных операций (e.g. a == b == c)
new TryCatchDecorator(new CompoundComparisonDesugarVisitor(generatedNamesManager), forIntellisense).ProcessNode(root);
return root;
}
protected override syntax_tree_node ApplyConversionsAfterUsedModulesCompilation(syntax_tree_node root, bool forIntellisense, in CompilationArtifactsUsedBySyntaxConverters compilationArtifacts)
{
var generatedNamesManager = new GeneratedNamesManager();
// украл из паскаля, нужны для работы 'for i1, i2 in expr' (работает с кортежными присваиваниями)
var binder = new BindCollectLightSymInfo(root as compilation_unit);
new TryCatchDecorator(binder, forIntellisense).ProcessNode(root);
new TryCatchDecorator(new NewAssignTuplesDesugarVisitor(binder, generatedNamesManager), forIntellisense).ProcessNode(root);
// Заменяет
// variable_name = single_length_string
// на
// variable_name = str(single_length_string)
// чтобы при выведении типа правильно вывел str, а не char
new TryCatchDecorator(new AssignmentCharAsStringVisitor(), forIntellisense).ProcessNode(root);
// Сохраняет множество имён функций, которые объявлены в программе для NameCorrectVisitor
var ffv = new FindFunctionsNamesVisitor();
new TryCatchDecorator(ffv, forIntellisense).ProcessNode(root);
// проверка корректности имён, разрешение неоднозначности
// сохранение множества переменных, использующихся как глобальные в ncv.variablesUsedAsGlobal
var ncv = new NameCorrectVisitor(System.IO.Path.GetFileNameWithoutExtension(((compilation_unit)root).file_name), forIntellisense,
compilationArtifacts.NamesFromUsedUnits, ffv.definedFunctionsNames);
new TryCatchDecorator(ncv, forIntellisense).ProcessNode(root);
// замена типов из SPython на типы из PascalABC.NET
if (!forIntellisense)
new TypeCorrectVisitor().ProcessNode(root);
// вынос forward объявлений для всех функций в начало
new TryCatchDecorator(new AddForwardDeclarationsVisitor(), forIntellisense).ProcessNode(root);
// выполняет генерацию кода для функций с kwarg-аргументами
new TryCatchDecorator(new KwargsFunctionDesugarVisitor(), forIntellisense).ProcessNode(root);
// замена вызова функций с kwarg-аргументами на вызов метода класса
new TryCatchDecorator(new FunctionsWithNamedParametersDesugarVisitor(), forIntellisense).ProcessNode(root);
// выносит объявлений переменных из ncv.variablesUsedAsGlobal на глобальный уровень
// (в модулях все переменные, объявленные на глобальном уровне являются глобальными)
new TryCatchDecorator(new RetainUsedGlobalVariablesVisitor(ncv.variablesUsedAsGlobal), forIntellisense).ProcessNode(root);
// удаление специфичных синтаксических узлов Spython'a перед конвертацией в семантическое дерево
if (!forIntellisense)
new EraseSpythonOnlyNodesVisitor().ProcessNode(root);
// перестроение структуры дерева, для последующих этапов компиляции
// итоговое представление:
// 1) forward объявления функций
// 2) объявления глобальных переменных (без присваиваний)
// 3) объявление функции %%MAIN%%, содержащей компилируемую программу
// 4) объявления функций, объявленных в программе
// 5) begin %%MAIN%%() end.
new TryCatchDecorator(new TreeNodesRearrangementVisitor(), forIntellisense).ProcessNode(root);
return root;
}
private class TryCatchDecorator
{
private WalkingVisitorNew internalVisitor;
private bool forIntellisense;
public TryCatchDecorator(WalkingVisitorNew internalVisitor, bool forIntellisense)
{
this.internalVisitor = internalVisitor;
this.forIntellisense = forIntellisense;
}
public bool ProcessNode(syntax_tree_node root)
{
if (forIntellisense)
{
try
{
internalVisitor.ProcessNode(root);
}
catch (Exception)
{
return false;
}
}
else
{
internalVisitor.ProcessNode(root);
}
return true;
}
}
}
}