From 1327baaa480f4955397c3c5e07a56571b20fc9b9 Mon Sep 17 00:00:00 2001 From: Mikhalkovich Stanislav Date: Sat, 15 Jun 2019 13:25:44 +0300 Subject: [PATCH] =?UTF-8?q?fix=20#1147=20=D0=9C=D0=BD=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=BE=20=D0=BA=D0=BE=D0=B4=D0=B0=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BC=D0=B0=D0=BB=D0=B5=D0=BD=D1=8C=D0=BA=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D1=84=D0=B8=D0=BA=D1=81=D0=B0=20))?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Configuration/GlobalAssemblyInfo.cs | 2 +- Configuration/Version.defs | 2 +- Optimizer/Optimizer.cs | 24 +++-- ReleaseGenerators/PascalABCNET_version.nsh | 2 +- ...tExprWithLambdaInForeachSequenceVisitor.cs | 94 +++++++++++++------ .../StandardSyntaxConverter.cs | 1 + .../LightSymInfoVisitors/SymInfoCollect1.cs | 22 +++-- TestSuite/CompilationSamples/PABCSystem.pas | 2 +- .../CompilationSamples/__RedirectIOMode.pas | 4 +- 9 files changed, 104 insertions(+), 49 deletions(-) diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs index 6c8205478..e79a49feb 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 = "2102"; + public const string Revision = "2106"; 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 468c6c37a..3304c8ca3 100644 --- a/Configuration/Version.defs +++ b/Configuration/Version.defs @@ -1,4 +1,4 @@ %COREVERSION%=0 -%REVISION%=2102 +%REVISION%=2106 %MINOR%=5 %MAJOR%=3 diff --git a/Optimizer/Optimizer.cs b/Optimizer/Optimizer.cs index 3fbc67d75..c64fb4195 100644 --- a/Optimizer/Optimizer.cs +++ b/Optimizer/Optimizer.cs @@ -54,6 +54,12 @@ namespace PascalABCCompiler { warns.Add(new GenericWarning(message, loc)); } + private void AddWarningAssignWithoutUsing(string name, location loc) + { + if (name.Contains("$")) + return; + warns.Add(new AssignWithoutUsing(name,loc)); + } private void AddHint(string message, location loc) { @@ -91,7 +97,7 @@ namespace PascalABCCompiler namespace_variable vdn = vdn2 as namespace_variable; VarInfo vi = helper.GetVariable(vdn); if (isUnused(vi, vdn)) warns.Add(new UnusedVariable(vdn.name, vdn.loc)); - if (vi.num_ass > 0 && vi.act_num_use == 0) warns.Add(new AssignWithoutUsing(vdn.name, vi.last_ass_loc)); + if (vi.num_ass > 0 && vi.act_num_use == 0) AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc); //if (vi.num_ass == 0 && vi.act_num_use > 0) helper.AddRealWarning(vdn, warns); } else if (vdn2 is local_block_variable) @@ -99,7 +105,7 @@ namespace PascalABCCompiler local_block_variable vdn = vdn2 as local_block_variable; VarInfo vi = helper.GetVariable(vdn); if (isUnused(vi, vdn)) warns.Add(new UnusedVariable(vdn.name, vdn.loc)); - if (vi.num_ass > 0 && vi.act_num_use == 0) warns.Add(new AssignWithoutUsing(vdn.name, vi.last_ass_loc)); + if (vi.num_ass > 0 && vi.act_num_use == 0) AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc); } } foreach (common_type_node ctn in cnn.types) @@ -285,7 +291,7 @@ namespace PascalABCCompiler !helper.IsExternal(cnfn)) warns.Add(new UndefinedReturnValue(cnfn.name, cnfn.function_code.location)); if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name) - warns.Add(new AssignWithoutUsing(vdn.name, vi.last_ass_loc)); + AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc); } else if (vdn2 is local_block_variable) { @@ -303,7 +309,7 @@ namespace PascalABCCompiler !helper.IsExternal(cnfn)) warns.Add(new UndefinedReturnValue(cnfn.name, cnfn.function_code.location)); if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name) - warns.Add(new AssignWithoutUsing(vdn.name, vi.last_ass_loc)); + AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc); } if (vdn2.inital_value != null) VisitExpression(vdn2.inital_value); @@ -354,14 +360,14 @@ namespace PascalABCCompiler !helper.IsExternal(cnfn)) warns.Add(new UndefinedReturnValue(cnfn.name, cnfn.function_code.location)); if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name) - warns.Add(new AssignWithoutUsing(vdn.name, vi.last_ass_loc)); + AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc); } else if (vdn2 is local_block_variable) { local_block_variable vdn = vdn2 as local_block_variable; VarInfo vi = helper.GetVariable(vdn); if (isUnused(vi, vdn)) - warns.Add(new UnusedVariable(vdn.name, vdn.loc)); + AddWarningAssignWithoutUsing(vdn.name, vdn.loc); else if (vi.num_ass == 0 && vdn.is_ret_value && !cnfn.name.StartsWith("<") && @@ -371,7 +377,7 @@ namespace PascalABCCompiler !helper.IsExternal(cnfn)) warns.Add(new UndefinedReturnValue(cnfn.name, cnfn.function_code.location)); if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name) - warns.Add(new AssignWithoutUsing(vdn.name, vi.last_ass_loc)); + AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc); } if (vdn2.inital_value != null) VisitExpression(vdn2.inital_value); @@ -579,8 +585,8 @@ namespace PascalABCCompiler if (isUnused(vi, vdn)) warns.Add(new UnusedVariable(vdn.name, vdn.loc)); - if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name) - warns.Add(new AssignWithoutUsing(vdn.name, vi.last_ass_loc)); + if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name) + AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc); } } diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh index 97d5bacf9..acf761028 100644 --- a/ReleaseGenerators/PascalABCNET_version.nsh +++ b/ReleaseGenerators/PascalABCNET_version.nsh @@ -1 +1 @@ -!define VERSION '3.5.0.2102' +!define VERSION '3.5.0.2106' diff --git a/SyntaxTreeConverters/StandOutExprWithLambdaInForeachSequenceVisitor.cs b/SyntaxTreeConverters/StandOutExprWithLambdaInForeachSequenceVisitor.cs index 87b05ae09..6a6d387c5 100644 --- a/SyntaxTreeConverters/StandOutExprWithLambdaInForeachSequenceVisitor.cs +++ b/SyntaxTreeConverters/StandOutExprWithLambdaInForeachSequenceVisitor.cs @@ -47,77 +47,117 @@ namespace PascalABCCompiler.SyntaxTreeConverters } - public class GivenNamesReplacer: CollectLightSymInfoVisitor + public class VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer: CollectLightSymInfoVisitor { /// /// Надо приводить к нижнему регистру /// - public List NamesForReplace { get; } + //public List NamesForReplace = new List(); private int LambdaNestedLevel = 0; - Dictionary> d = new Dictionary>(); // словарь скоупов для каждого имени - // При добавлении символа мы в словарь добавляем его ПИ (символ может быть правильно вложенным только если вначале идет локальная переменная, - // потом - параметр лямбды, потом - локальная переменная вложенной лямбды и т.д. - public static new GivenNamesReplacer New + Dictionary d = new Dictionary(); // словарь скоупов для каждого имени + // При входе в обобщенный класс или запись мы в словарь добавляем все его обобщенные параметры со значением nil + // При выходе из класса мы очищаем словарь + // При встрече описания переменной с именем, совпадающим с одним из ключей в словаре, мы заменяем значение null на пространство имен, в котором мы находимся + // Описание переменной в словарь добавляется только если она описана в методе, но вне лямбды, поскольку в лямбде конфликтов имен нет + // При выходе из пространства имен мы проверяем, есть ли в словаре такое значение, и если да, очищаем его, присваивая null + // Переименовывать будем все имена name если ключ name есть в словаре и d[name] != null + public static new VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer New { - get => new GivenNamesReplacer(); + get => new VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer(); } public override void AddSymbol(ident name, SymKind kind, type_definition td = null, Attributes attr = 0) { - var n = name.name.ToLower(); - if (LambdaNestedLevel > 0 && d[n].Count() == 0) // т.е. впервые встретилось переопределение именно в лямбде, тогда пропускать эту лямбду - return; - if (NamesForReplace.Contains(n) && (kind == SymKind.var || kind == SymKind.param)) // Добавляем не все, а только разыскиваемые и только если это - переменная + if (name == null || name.name == null) { - d[n].Push(this.Current); + 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; // т.е. в этом пространстве имен мы захватили одноименное описание переменной - освобождаем его } - base.Enter(st); } public override void Exit(syntax_tree_node st) { - // Обходим все словари и смотрим у них вершину стеков - foreach (var k in d.Keys) - { - var stack = d[k]; - if (stack.Count() > 0 && stack.Peek() == Current) - { - stack.Pop(); - } - } 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) { - Process(id); + ReplaceNameOrNot(id); } public override void visit(dot_node dn) { if (dn.left is ident id) - Process(id); + ReplaceNameOrNot(id); else ProcessNode(dn.left); } public static int ReplaceNum = 0; - public void Process(ident id) + public void ReplaceNameOrNot(ident id) { var n = id.name.ToLower(); - if (NamesForReplace.Contains(n) && d[n].Count() == 1) // Проблема такая - первый раз T будет описано именно в лямбде. + if (d.ContainsKey(n) && d[n] != null) // Переименовываем без страха { - id.name = "$" + id.name + ReplaceNum; + id.name = id.name + "$Replace$" + ReplaceNum; // имя такое чтобы при выдаче сообщения об ошибке в нем можно было бы обрезать конец } } } diff --git a/SyntaxTreeConverters/StandardSyntaxConverter.cs b/SyntaxTreeConverters/StandardSyntaxConverter.cs index db2d06f82..455b0adbc 100644 --- a/SyntaxTreeConverters/StandardSyntaxConverter.cs +++ b/SyntaxTreeConverters/StandardSyntaxConverter.cs @@ -21,6 +21,7 @@ namespace PascalABCCompiler.SyntaxTreeConverters root.FillParentsInAllChilds(); // Выносим выражения с лямбдами из заголовка foreach StandOutExprWithLambdaInForeachSequenceVisitor.New.ProcessNode(root); + VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer.New.ProcessNode(root); // SSM bug fix #1147 #if DEBUG //new SimplePrettyPrinterVisitor("E:/projs/out.txt").ProcessNode(root); diff --git a/SyntaxVisitors/LightSymInfoVisitors/SymInfoCollect1.cs b/SyntaxVisitors/LightSymInfoVisitors/SymInfoCollect1.cs index 4fe5d5bcc..c8789e599 100644 --- a/SyntaxVisitors/LightSymInfoVisitors/SymInfoCollect1.cs +++ b/SyntaxVisitors/LightSymInfoVisitors/SymInfoCollect1.cs @@ -41,15 +41,18 @@ namespace PascalABCCompiler.SyntaxTree break; case procedure_definition p: var name = p.proc_header?.name?.meth_name; + if (name == null) + name = "create"; var attr = p.proc_header.class_keyword ? Attributes.class_attr : 0; - if (p.proc_header is function_header && name != null) - AddSymbol(name, SymKind.funcname,null, attr); - else AddSymbol(name, SymKind.procname, null, attr); + if (name != null) + if (p.proc_header is function_header) + AddSymbol(name, SymKind.funcname,null, attr); + else AddSymbol(name, SymKind.procname, null, attr); t = new ProcScopeSyntax(name); break; - case formal_parameters p: - t = new ParamsScopeSyntax(); - break; + //case formal_parameters p:// Это неправильный Scope - он закрывался при выходе из секции формальных параметров, что неправильно + // t = new ParamsScopeSyntax(); + // break; case statement_list p: t = new StatListScopeSyntax(); break; @@ -102,6 +105,10 @@ namespace PascalABCCompiler.SyntaxTree } } } + } + public virtual void PreExitScope(syntax_tree_node st) + { + } public override void Exit(syntax_tree_node st) { @@ -109,7 +116,7 @@ namespace PascalABCCompiler.SyntaxTree { case program_module p: case procedure_definition pd: - case formal_parameters fp: + //case formal_parameters fp: case statement_list stl: case for_node f: case foreach_stmt fe: @@ -118,6 +125,7 @@ namespace PascalABCCompiler.SyntaxTree case function_lambda_definition fld: //case repeat_node rep: case case_node cas: + PreExitScope(st); Current = Current.Parent; break; } diff --git a/TestSuite/CompilationSamples/PABCSystem.pas b/TestSuite/CompilationSamples/PABCSystem.pas index 3d0127f1f..da4b5f374 100644 --- a/TestSuite/CompilationSamples/PABCSystem.pas +++ b/TestSuite/CompilationSamples/PABCSystem.pas @@ -1922,7 +1922,7 @@ function MatrRandomInteger(m: integer := 5; n: integer := 5; a: integer := 0; b: function MatrRandomReal(m: integer := 5; n: integer := 5; a: real := 0; b: real := 10): array [,] of real; /// Возвращает двумерный массив размера m x n, заполненный элементами x function MatrFill(m, n: integer; x: T): array [,] of T; -/// Возвращает двумерный массив размера m x n, заполненный элементами x +/// Возвращает двумерный массив размера m x n, заполненный элементами gen(i,j) function MatrGen(m, n: integer; gen: (integer,integer)->T): array [,] of T; /// Транспонирует двумерный массив function Transpose(a: array [,] of T): array [,] of T; diff --git a/TestSuite/CompilationSamples/__RedirectIOMode.pas b/TestSuite/CompilationSamples/__RedirectIOMode.pas index 191f57f20..1f1b86bb6 100644 --- a/TestSuite/CompilationSamples/__RedirectIOMode.pas +++ b/TestSuite/CompilationSamples/__RedirectIOMode.pas @@ -9,9 +9,9 @@ unit __RedirectIOMode; // Функции: // 1. Посылка в поток ErrorStream сигнала [READLNSIGNAL] // 2. Перехват исключений по AppDomain.CurrentDomain.UnhandledException и -// пердача их в поток ErrorStream +// передача их в поток ErrorStream // 3. Перехват исключений по Application.ThreadException и -// пердача их в поток ErrorStream +// передача их в поток ErrorStream //------------------------------------------------------------------------------ {$reference 'System.Windows.Forms.dll'}