pascalabcnet/AdditionalLanguages/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/StandardSyntaxTreeConverter.cs
2026-04-09 09:47:15 +03:00

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

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 BitwiseAssignmentDesugarVisitor().ProcessNode(root);
// замена return; на { exit(); }
// замена return expr; на { result := expr; exit(); }
new ReturnDesugarVisitor().ProcessNode(root);
// замена вызова функции map(func, sequence)
// на func(element) for element in sequence
new MapDesugarVisitor().ProcessNode(root);
// замена генерации последовательностей на Select.Where
// (не работает из-за лямбд (скорее всего), если переместить в ApplyConversionsAfterUsedModulesCompilation)
new GeneratorObjectDesugarVisitor(root, generatedNamesManager).ProcessNode(root);
// Выносим выражения с лямбдами из заголовка foreach + считаем максимум 10 вложенных лямбд
// украл из паскаля
new TryCatchDecorator(StandOutExprWithLambdaInForeachSequenceAndNestedLambdasVisitor.Create(generatedNamesManager), forIntellisense).ProcessNode(root);
new VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer(root as compilation_unit).ProcessNode(root);
FindOnExceptVarsAndApplyRenameVisitor.Create(generatedNamesManager).ProcessNode(root);
// дешугаризация составных сравнительных операций (e.g. a == b == c)
new CompoundComparisonDesugarVisitor(generatedNamesManager).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);
binder.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 AssignmentCharAsStringVisitor().ProcessNode(root);
// Сохраняет множество имён функций, которые объявлены в программе для NameCorrectVisitor
var ffv = new FindFunctionsNamesVisitor();
ffv.ProcessNode(root);
// проверка корректности имён, разрешение неоднозначности
// сохранение множества переменных, использующихся как глобальные в ncv.variablesUsedAsGlobal
var ncv = new NameCorrectVisitor(System.IO.Path.GetFileNameWithoutExtension(((compilation_unit)root).file_name), forIntellisense,
compilationArtifacts.NamesFromUsedUnits, ffv.definedFunctionsNames);
ncv.ProcessNode(root);
// замена типов из SPython на типы из PascalABC.NET
if (!forIntellisense)
new TypeCorrectVisitor().ProcessNode(root);
// вынос forward объявлений для всех функций в начало
new AddForwardDeclarationsVisitor().ProcessNode(root);
// выполняет генерацию кода для функций с kwarg-аргументами
new TryCatchDecorator(new KwargsFunctionDesugarVisitor(), forIntellisense).ProcessNode(root);
// замена вызова функций с kwarg-аргументами на вызов метода класса
new TryCatchDecorator(new FunctionsWithNamedParametersDesugarVisitor(), forIntellisense).ProcessNode(root);
// выносит объявлений переменных из ncv.variablesUsedAsGlobal на глобальный уровень
// (в модулях все переменные, объявленные на глобальном уровне являются глобальными)
new RetainUsedGlobalVariablesVisitor(ncv.variablesUsedAsGlobal).ProcessNode(root);
// удаление специфичных синтаксических узлов Spython'a перед конвертацией в семантическое дерево
if (!forIntellisense)
new EraseSpythonOnlyNodesVisitor().ProcessNode(root);
// перестроение структуры дерева, для последующих этапов компиляции
// итоговое представление:
// 1) forward объявления функций
// 2) объявления глобальных переменных (без присваиваний)
// 3) объявление функции %%MAIN%%, содержащей компилируемую программу
// 4) объявления функций, объявленных в программе
// 5) begin %%MAIN%%() end.
new TreeNodesRearrangementVisitor().ProcessNode(root);
return root;
}
private class TryCatchDecorator
{
private readonly WalkingVisitorNew internalVisitor;
private readonly 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;
}
}
}
}