From 76f4020256b1c2080c619c3baafe272be9091951 Mon Sep 17 00:00:00 2001 From: Mikhalkovich Stanislav Date: Wed, 12 Jun 2019 11:30:07 +0300 Subject: [PATCH] =?UTF-8?q?bug=20fix=20#891=20-=20=D0=BF=D0=BE=D0=BF=D1=8B?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=BD=D0=BE=D0=BC=D0=B5=D1=80=20=D0=B4?= =?UTF-8?q?=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Configuration/GlobalAssemblyInfo.cs | 2 +- Configuration/Version.defs | 2 +- ReleaseGenerators/PascalABCNET_version.nsh | 2 +- ...tExprWithLambdaInForeachSequenceVisitor.cs | 91 +++++++++++++++++++ ...capture_local_and_proc_noparams_call-1.pas | 31 +++++++ ...re_local_and_proc_noparams_call_static.pas | 32 +++++++ ...l_and_proc_noparams_call_static_inside.pas | 21 +++++ TestSuite/lambda_capture_static_methods.pas | 10 ++ .../Closure/CapturedVariablesTreeBuilder.cs | 44 ++++++++- bin/PascalABCNET.exe.config | 19 ---- 10 files changed, 231 insertions(+), 23 deletions(-) create mode 100644 TestSuite/lambda_capture_local_and_proc_noparams_call-1.pas create mode 100644 TestSuite/lambda_capture_local_and_proc_noparams_call_static.pas create mode 100644 TestSuite/lambda_capture_local_and_proc_noparams_call_static_inside.pas create mode 100644 TestSuite/lambda_capture_static_methods.pas delete mode 100644 bin/PascalABCNET.exe.config diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs index f0adbcd00..6c8205478 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 = "2098"; + public const string Revision = "2102"; 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 0c8ea0189..468c6c37a 100644 --- a/Configuration/Version.defs +++ b/Configuration/Version.defs @@ -1,4 +1,4 @@ %COREVERSION%=0 -%REVISION%=2098 +%REVISION%=2102 %MINOR%=5 %MAJOR%=3 diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh index c3ce90365..97d5bacf9 100644 --- a/ReleaseGenerators/PascalABCNET_version.nsh +++ b/ReleaseGenerators/PascalABCNET_version.nsh @@ -1 +1 @@ -!define VERSION '3.5.0.2098' +!define VERSION '3.5.0.2102' diff --git a/SyntaxTreeConverters/StandOutExprWithLambdaInForeachSequenceVisitor.cs b/SyntaxTreeConverters/StandOutExprWithLambdaInForeachSequenceVisitor.cs index 558cc17a3..4d5dc28f7 100644 --- a/SyntaxTreeConverters/StandOutExprWithLambdaInForeachSequenceVisitor.cs +++ b/SyntaxTreeConverters/StandOutExprWithLambdaInForeachSequenceVisitor.cs @@ -7,6 +7,9 @@ using PascalABCCompiler.SyntaxTree; namespace PascalABCCompiler.SyntaxTreeConverters { + + // Первое предназначение - вынести последовательность из заголовка в foreach до foreach как отдельное присваивание + // Второе предназначение - переименовать все переменные, совпадающие по имени с типом T обобщенного класса, в котором находится метод, содержащий лямбду public class StandOutExprWithLambdaInForeachSequenceVisitor : BaseChangeVisitor { public static StandOutExprWithLambdaInForeachSequenceVisitor New @@ -18,12 +21,46 @@ namespace PascalABCCompiler.SyntaxTreeConverters } private int GenIdNum = 0; + //private int GenRenameIdNum = 0; + + //private ident_list ClassTemplateArgsOrNull = null; // если мы - в обобщенном классе, то это - его обобщенные параметры + // надо бы еще то же сделать если метод описывается отдельно public ident GenIdentName() { GenIdNum++; return new ident("$GenContFE" + GenIdNum.ToString()); } +/* public string RenameIdentName(string name) + { + GenRenameIdNum++; + return "$GenRenameLocalInLambda" + GenRenameIdNum.ToString(); + } + public override void Enter(syntax_tree_node st) + { + if (st is class_definition cd) + { + var a = cd.Parent as type_declaration; + ClassTemplateArgsOrNull = (a?.type_name as template_type_name)?.template_args; + } + + } + + public override void Exit(syntax_tree_node st) + { + if (st is class_definition) + ClassTemplateArgsOrNull = null; + } + + public override void visit(procedure_definition pd) + { + if (ClassTemplateArgsOrNull == null) + return; + var lfds = pd.DescendantNodes().OfType(); + if (lfds.Count() == 0) + return; + }*/ + public override void visit(foreach_stmt fe) { //if (fe.DescendantNodes().OfType().Count() > 0) // из-за #1984 убрал вообще условие. Пусть будет всегда @@ -40,4 +77,58 @@ namespace PascalABCCompiler.SyntaxTreeConverters base.visit(fe); } } + + // Может, переименовать все 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_capture_local_and_proc_noparams_call-1.pas b/TestSuite/lambda_capture_local_and_proc_noparams_call-1.pas new file mode 100644 index 000000000..892574ceb --- /dev/null +++ b/TestSuite/lambda_capture_local_and_proc_noparams_call-1.pas @@ -0,0 +1,31 @@ +type + t1 = class + public procedure p0 := exit; + public i: integer := 2; + + public procedure p1; + {begin + var v := 0; + var p: procedure := ()->begin + v := v; + Assert(i=2); + p0; + end; + p; + end;} + end; + +procedure t1.p1; +begin + var v := 0; + var p: procedure := ()->begin + v := v; + Assert(i=2); + p0; + end; + p; +end; + +begin + t1.Create.p1; +end. \ No newline at end of file diff --git a/TestSuite/lambda_capture_local_and_proc_noparams_call_static.pas b/TestSuite/lambda_capture_local_and_proc_noparams_call_static.pas new file mode 100644 index 000000000..24d4bd817 --- /dev/null +++ b/TestSuite/lambda_capture_local_and_proc_noparams_call_static.pas @@ -0,0 +1,32 @@ +type + t1 = class + public static procedure p0 := Print(111); + public static i: integer := 2; + + public static function p1: integer; + {begin + var v := 0; + var p: procedure := ()->begin + v := v; + Assert(i=2); + p0; + end; + p; + end;} + end; + + static function t1.p1: integer; + begin + var v := 0; + var p: procedure := ()->begin + v := v; + Assert(i=2); + p0; + end; + p; + end; + + +begin + t1&.p1; +end. \ No newline at end of file diff --git a/TestSuite/lambda_capture_local_and_proc_noparams_call_static_inside.pas b/TestSuite/lambda_capture_local_and_proc_noparams_call_static_inside.pas new file mode 100644 index 000000000..af84d9e32 --- /dev/null +++ b/TestSuite/lambda_capture_local_and_proc_noparams_call_static_inside.pas @@ -0,0 +1,21 @@ +type + t1 = class + public static procedure p0 := Print(111); + public static i: integer := 2; + + public static function p1: integer; + begin + var v := 0; + var p: procedure := ()->begin + v := v; + Assert(i=2); + p0; + end; + p; + end; + end; + + +begin + t1&.p1; +end. \ No newline at end of file diff --git a/TestSuite/lambda_capture_static_methods.pas b/TestSuite/lambda_capture_static_methods.pas new file mode 100644 index 000000000..817dac8fc --- /dev/null +++ b/TestSuite/lambda_capture_static_methods.pas @@ -0,0 +1,10 @@ +type + T = class + public static procedure p1(a: integer) := exit; + + public static procedure P := &Array.ForEach(Arr(0), x -> p1(x)); // В данной версии компилятора не поддерживается замыкание данного типа символов + end; + +begin + Assert(1=1) +end. \ No newline at end of file diff --git a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs index f512a9ba1..220fcd526 100644 --- a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs +++ b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs @@ -164,7 +164,7 @@ namespace TreeConverter.LambdaExpressions.Closure si.sym_info.semantic_node_type == semantic_node_type.common_namespace_function_node || si.sym_info.semantic_node_type == semantic_node_type.namespace_constant_definition || si.sym_info.semantic_node_type == semantic_node_type.compiled_function_node || - //si.sym_info.semantic_node_type == semantic_node_type.common_method_node || // SSM bug fix #167 - SSM 30.05.19 эта строчка не влияет на #167 и я её закомментировал + //si.sym_info.semantic_node_type == semantic_node_type.common_method_node || // SSM bug fix #1991 11.06.19 конкурирует с #891 si.sym_info.semantic_node_type == semantic_node_type.compiled_namespace_node || si.sym_info.semantic_node_type == semantic_node_type.compiled_variable_definition || si.sym_info.semantic_node_type == semantic_node_type.common_type_node || @@ -212,6 +212,48 @@ namespace TreeConverter.LambdaExpressions.Closure return; } } + + if (si.sym_info.semantic_node_type == semantic_node_type.common_method_node && (si.sym_info as common_method_node).IsStatic) + { + // надо дописывать к идентификатору имя типа. Подниматься по синтаксическому дереву конечно долго )) + syntax_tree_node sn = id; + ident cname = null; + while (!(sn is procedure_definition) && sn != null) // Это если метод класса определен вне интерфейса класса + sn = sn.Parent; + if (sn != null) + { + var pd = sn as procedure_definition; + var ph = pd.proc_header; + if (ph.name.class_name != null) + { + cname = ph.name.class_name; + addressed_value id1 = null; + if (cname is template_type_name ttn) + { + var tpl = new template_param_list(ttn.template_args.idents.Select(l => SyntaxTreeBuilder.BuildSimpleType(l.name)).ToList(), ttn.template_args.source_context); + id1 = new ident_with_templateparams(new ident(ttn.name, ttn.source_context), tpl,ttn.source_context); + } + else id1 = new ident(cname.name, cname.source_context); + dot_node dn = new dot_node(id1, new ident(id.name, id.source_context), id.source_context); + id.Parent.ReplaceDescendantUnsafe(id, dn); + ProcessNode(id.Parent); + return; + } + } + while (!(sn is class_definition) && sn != null) + sn = sn.Parent; + if (sn != null) + { + var cd = sn as class_definition; + cname = (cd.Parent as type_declaration).type_name; + dot_node dn = new dot_node(new ident(cname.name, cname.source_context), new ident(id.name, id.source_context), id.source_context); + id.Parent.ReplaceDescendantUnsafe(id, dn); + ProcessNode(id.Parent); + } + return; + } + + if (!(acceptableVarType) && InLambdaContext) { _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id))); diff --git a/bin/PascalABCNET.exe.config b/bin/PascalABCNET.exe.config deleted file mode 100644 index c59f59fe9..000000000 --- a/bin/PascalABCNET.exe.config +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - -