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