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; } } } }