diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs
index 32b5ffe53..bbcb6a0fd 100644
--- a/Configuration/GlobalAssemblyInfo.cs
+++ b/Configuration/GlobalAssemblyInfo.cs
@@ -15,7 +15,7 @@ internal static class RevisionClass
public const string Major = "3";
public const string Minor = "5";
public const string Build = "0";
- public const string Revision = "2157";
+ public const string Revision = "2165";
public const string MainVersion = Major + "." + Minor;
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;
diff --git a/Configuration/Version.defs b/Configuration/Version.defs
index 1294e9e0e..398f7125a 100644
--- a/Configuration/Version.defs
+++ b/Configuration/Version.defs
@@ -1,4 +1,4 @@
%MINOR%=5
-%REVISION%=2157
+%REVISION%=2165
%COREVERSION%=0
%MAJOR%=3
diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh
index b48c6d068..f816349fa 100644
--- a/ReleaseGenerators/PascalABCNET_version.nsh
+++ b/ReleaseGenerators/PascalABCNET_version.nsh
@@ -1 +1 @@
-!define VERSION '3.5.0.2157'
+!define VERSION '3.5.0.2165'
diff --git a/SyntaxTreeConverters/StandardSyntaxConverter.cs b/SyntaxTreeConverters/StandardSyntaxConverter.cs
index 455b0adbc..494f68eea 100644
--- a/SyntaxTreeConverters/StandardSyntaxConverter.cs
+++ b/SyntaxTreeConverters/StandardSyntaxConverter.cs
@@ -22,7 +22,7 @@ namespace PascalABCCompiler.SyntaxTreeConverters
// Выносим выражения с лямбдами из заголовка foreach
StandOutExprWithLambdaInForeachSequenceVisitor.New.ProcessNode(root);
VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer.New.ProcessNode(root); // SSM bug fix #1147
-
+ FindOnExceptVarsAndApplyRenameVisitor.New.ProcessNode(root);
#if DEBUG
//new SimplePrettyPrinterVisitor("E:/projs/out.txt").ProcessNode(root);
#endif
diff --git a/SyntaxVisitors/SyntaxVisitors.csproj b/SyntaxVisitors/SyntaxVisitors.csproj
index 00b7ce314..f99127c0e 100644
--- a/SyntaxVisitors/SyntaxVisitors.csproj
+++ b/SyntaxVisitors/SyntaxVisitors.csproj
@@ -59,6 +59,7 @@
+
diff --git a/SyntaxVisitors/VisitorsForLambdas/RenameOnExceptVarsVisitor.cs b/SyntaxVisitors/VisitorsForLambdas/RenameOnExceptVarsVisitor.cs
new file mode 100644
index 000000000..e3d0fe9ae
--- /dev/null
+++ b/SyntaxVisitors/VisitorsForLambdas/RenameOnExceptVarsVisitor.cs
@@ -0,0 +1,90 @@
+// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (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.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using PascalABCCompiler;
+using PascalABCCompiler.SyntaxTree;
+
+namespace SyntaxVisitors
+{
+ // Проба будущего визитора или не будущего
+ public class RenameOnExceptVarsVisitor : BaseChangeVisitor
+ {
+ public string NameForRename = null;
+ public string NewName = null;
+ public RenameOnExceptVarsVisitor()
+ {
+ }
+
+ public void Rename(exception_handler eh)
+ {
+ NameForRename = eh.variable?.name?.ToLower();
+ if (NameForRename != null)
+ {
+ NewName = GetNewVariableName(NameForRename);
+ ProcessNode(eh.statements);
+ }
+ }
+
+ public override void visit(ident id)
+ {
+ var idl = id.name.ToLower();
+ if (NameForRename == idl)
+ {
+ id.name = NewName;
+ }
+ }
+
+ public override void visit(dot_node dn)
+ {
+ ProcessNode(dn.left);
+ if (dn.right.GetType() != typeof(ident))
+ ProcessNode(dn.right);
+ }
+
+ private static int num = 0;
+ private static string GetNewVariableName(string name)
+ {
+ num++;
+ return "$Rename_"+name+num.ToString();
+ }
+ }
+
+ public class FindOnExceptVarsAndApplyRenameVisitor : BaseChangeVisitor
+ {
+ public static FindOnExceptVarsAndApplyRenameVisitor New
+ {
+ get { return new FindOnExceptVarsAndApplyRenameVisitor(); }
+ }
+ public override void visit(exception_handler eh)
+ {
+ if (eh.variable != null)
+ {
+ // Вначале переименовать везде кроме как в заголовке, потом добавить в блок операторов переприсваивание
+ var vis = new RenameOnExceptVarsVisitor();
+ vis.Rename(eh);
+
+ var vs = new var_statement(new ident(vis.NewName/*, eh.statements.source_context*/), new ident(vis.NameForRename, eh.variable.source_context)/*, eh.statements.source_context*/);
+ var stl = new List();
+ stl.Add(vs);
+ if (eh.statements != null)
+ {
+ stl.Add(eh.statements);
+ ReplaceStatementUsingParent(eh.statements, stl);
+ }
+ else
+ {
+ var s = new statement_list(stl);
+ s.Parent = eh;
+ s.source_context = eh.source_context;
+ eh.statements = s;
+ }
+ }
+ base.visit(eh);
+ }
+ }
+}
diff --git a/SyntaxVisitors/YieldVisitors/RenameSameVarNamesVisitor.cs b/SyntaxVisitors/YieldVisitors/RenameSameVarNamesVisitor.cs
new file mode 100644
index 000000000..0eef1ac24
--- /dev/null
+++ b/SyntaxVisitors/YieldVisitors/RenameSameVarNamesVisitor.cs
@@ -0,0 +1,181 @@
+// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (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.Collections.Generic;
+using System.Linq;
+using PascalABCCompiler.SyntaxTree;
+
+namespace PascalABCCompiler.SyntaxTreeConverters
+{
+
+ // Первое предназначение - вынести последовательность из заголовка в foreach до foreach как отдельное присваивание
+ // Второе предназначение - переименовать все переменные, совпадающие по имени с типом T обобщенного класса, в котором находится метод, содержащий лямбду
+ public class VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer: CollectLightSymInfoVisitor
+ {
+ ///
+ /// Надо приводить к нижнему регистру
+ ///
+ //public List NamesForReplace = new List();
+
+ private int LambdaNestedLevel = 0;
+
+ Dictionary d = new Dictionary(); // словарь скоупов для каждого имени
+ // При входе в обобщенный класс или запись мы в словарь добавляем все его обобщенные параметры со значением nil
+ // При выходе из класса мы очищаем словарь
+ // При встрече описания переменной с именем, совпадающим с одним из ключей в словаре, мы заменяем значение null на пространство имен, в котором мы находимся
+ // Описание переменной в словарь добавляется только если она описана в методе, но вне лямбды, поскольку в лямбде конфликтов имен нет
+ // При выходе из пространства имен мы проверяем, есть ли в словаре такое значение, и если да, очищаем его, присваивая null
+ // Переименовывать будем все имена name если ключ name есть в словаре и d[name] != null
+ public static new VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer New
+ {
+ get => new VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer();
+ }
+ public override void AddSymbol(ident name, SymKind kind, type_definition td = null, Attributes attr = 0)
+ {
+ if (name == null || name.name == null)
+ {
+ return;
+ }
+ var n = name.name.ToLower();
+ //if (LambdaNestedLevel > 0) // т.е. впервые встретилось переопределение именно в лямбде, тогда пропускать эту лямбду
+ // return;
+ if (d.ContainsKey(n) && d[n] == null && (kind == SymKind.var || kind == SymKind.param)) // Добавляем не все, а только разыскиваемые и только если это - переменная
+ {
+ d[n] = this.Current;
+ base.AddSymbol(name, kind, td, attr);
+ }
+ }
+ public override void Enter(syntax_tree_node st)
+ {
+ base.Enter(st);
+ if (st is function_lambda_definition)
+ LambdaNestedLevel += 1;
+ else if (st is class_definition cl)
+ {
+ var td = cl.Parent as type_declaration;
+ if (td?.type_name is template_type_name ttn)
+ {
+ foreach (var id in ttn.template_args.idents)
+ {
+ d[id.name.ToLower()] = null;
+ }
+ }
+ }
+ else if (st is procedure_definition pd)
+ {
+ var cn = pd.proc_header.name?.class_name;
+ if (cn is template_type_name ttn)
+ {
+ foreach (var id in ttn.template_args.idents)
+ {
+ d[id.name.ToLower()] = null;
+ }
+ }
+ }
+ }
+ public override void PreExitScope(syntax_tree_node st)
+ {
+ var l = d.Keys.Where(k => d[k] == Current).ToList();
+ // Обходим все словари и смотрим у них вершину стеков
+ foreach (var k in l)
+ {
+ d[k] = null; // т.е. в этом пространстве имен мы захватили одноименное описание переменной - освобождаем его
+ }
+ }
+ public override void Exit(syntax_tree_node st)
+ {
+ if (st is function_lambda_definition)
+ LambdaNestedLevel -= 1;
+ else if (st is class_definition) // то мы не ищем переопределение имен, поскольку мы вышли из класса
+ {
+ d.Clear();
+ }
+ else if (st is procedure_definition pd) // мы вышли из метода вида t1.p
+ {
+ var cn = pd.proc_header.name?.class_name;
+ if (cn is template_type_name ttn)
+ d.Clear();
+ }
+ base.Exit(st);
+ }
+
+ public override void visit(template_type_name tn)
+ {
+ // игнорировать чтобы там ничего не переименовывалось
+ }
+ public override void visit(ident id)
+ {
+ ReplaceNameOrNot(id);
+ }
+ public override void visit(dot_node dn)
+ {
+ if (dn.left is ident id)
+ ReplaceNameOrNot(id);
+ else ProcessNode(dn.left);
+ }
+
+ public static int ReplaceNum = 0;
+ public void ReplaceNameOrNot(ident id)
+ {
+ var n = id.name.ToLower();
+ if (d.ContainsKey(n) && d[n] != null) // Переименовываем без страха
+ {
+ id.name = id.name + "$Replace$" + ReplaceNum; // имя такое чтобы при выдаче сообщения об ошибке в нем можно было бы обрезать конец
+ }
+ }
+ }
+
+ // Может, переименовать все T? Всё равно алгоритм переименовывания будет один
+ // Искать описания с T. Как нашли - с этого места переименовывать
+ // Сделать визитор LocalRenamer и переименовывать с места описания
+
+ /*public class LocalRenamer : BaseChangeVisitor
+ {
+
+ public static void RenameFrom(var_def_statement vd, string Name, string NewName)
+ {
+ var lr = new LocalRenamer();
+ lr.ProcessNode(vd);
+ }
+ }*/
+
+
+ // Поиск всех захваченных переменных в лямбде
+ // Это сложно
+ /*public class LambdaCapturedNamesSearcher : BaseChangeVisitor
+ {
+ List idents = new List();
+ public static LambdaCapturedNamesSearcher New
+ {
+ get
+ {
+ return new LambdaCapturedNamesSearcher();
+ }
+ }
+ public override void visit(ident id)
+ {
+ // хорошо бы всё здесь захватить! Но вдруг это - описание...
+ }
+ public override void visit(dot_node dn)
+ {
+ // это точно надо захватывать
+ }
+
+ public override void visit(var_def_statement vds)
+ {
+ // имена обойти отдельно, инициализатор - отдельно
+ foreach (var id in vds.vars.idents)
+ {
+ // Надо проверять совпадение имен с именами в параметрах обобщения
+ // если не совпадают, то просто пропускаем
+ // если совпадают, то исключаем это имя из списка проверки! Всё - имя уже переопределено! И это произошло в лямбде, что можно
+ }
+ visit(vds.inital_value);
+ }
+ public override void visit(function_lambda_definition ld)
+ {
+ // параметры обойти отдельно, тело отдельно
+ // проблема, что могут быть вложенные лямбды. Т.е это - основная, а в ней - ещё.
+ }
+ }*/
+}
diff --git a/TestSuite/lambda_OnExcept.pas b/TestSuite/lambda_OnExcept.pas
new file mode 100644
index 000000000..bba0fdb7f
--- /dev/null
+++ b/TestSuite/lambda_OnExcept.pas
@@ -0,0 +1,37 @@
+type MyException = class(Exception) end;
+
+procedure p1;
+begin
+
+ var i := 8;
+ var p: procedure := ()->
+ begin
+ i := 3;
+ end;
+
+ try
+ raise new MyException;
+ except
+ on e: Exception do
+ begin
+ var q: procedure := ()->
+ begin
+ Print(e);
+ end;
+ //q;
+ end;
+ on e: MyException do
+ begin
+ var q: procedure := ()->
+ begin
+ Print(e);
+ end;
+ //q;
+ end;
+ end;
+
+end;
+
+begin
+ p1;
+end.
\ No newline at end of file
diff --git a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs
index d473dcd03..0982684f8 100644
--- a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs
+++ b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs
@@ -144,16 +144,23 @@ namespace TreeConverter.LambdaExpressions.Closure
public override void visit(exception_handler eh)
{
- //_visitor.context.enter_code_block_without_bind();
- //visitor.context.add_var_definition(eh.variable.name, _visitor.get_location(eh.variable), _visitor.convert_strong(eh.type_name), PascalABCCompiler.SemanticTree.polymorphic_state.ps_common, true);
+ // Отдельным визитором переменные в on присвою локальным переменным и переименую везде внутри блока
+ statements_list sl = new statements_list(_visitor.get_location(eh.statements));
+ _visitor.convertion_data_and_alghoritms.statement_list_stack_push(sl);
+
+ _visitor.context.enter_code_block_without_bind();
+
+ _visitor.context.add_var_definition(eh.variable.name, _visitor.get_location(eh.variable), _visitor.convert_strong(eh.type_name), PascalABCCompiler.SemanticTree.polymorphic_state.ps_common, true);
//SymbolInfo si = _visitor.context.find_first(eh.variable.name);
//var csi = new CapturedVariablesTreeNode.CapturedSymbolInfo(eh, si);
- // Нужно своё ПИ для обработчиков исключений в захвате !!! Или - переименовывать все переменные
- // _currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(eh, si));
+ //_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(eh, si));
//_pendingCapturedSymbols.Add(csi);
+ ProcessNode(eh.variable);
+
ProcessNode(eh.statements);
+ _visitor.context.leave_code_block();
+ _visitor.convertion_data_and_alghoritms.statement_list_stack_pop();
//_pendingCapturedSymbols.Remove(csi);
- //_visitor.context.leave_code_block();
}
public override void visit(ident id)