parent
8d59eafce2
commit
1327baaa48
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%COREVERSION%=0
|
||||
%REVISION%=2102
|
||||
%REVISION%=2106
|
||||
%MINOR%=5
|
||||
%MAJOR%=3
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
!define VERSION '3.5.0.2102'
|
||||
!define VERSION '3.5.0.2106'
|
||||
|
|
|
|||
|
|
@ -47,77 +47,117 @@ namespace PascalABCCompiler.SyntaxTreeConverters
|
|||
}
|
||||
|
||||
|
||||
public class GivenNamesReplacer: CollectLightSymInfoVisitor
|
||||
public class VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer: CollectLightSymInfoVisitor
|
||||
{
|
||||
/// <summary>
|
||||
/// Надо приводить к нижнему регистру
|
||||
/// </summary>
|
||||
public List<string> NamesForReplace { get; }
|
||||
//public List<string> NamesForReplace = new List<string>();
|
||||
|
||||
private int LambdaNestedLevel = 0;
|
||||
|
||||
Dictionary<string, Stack<ScopeSyntax>> d = new Dictionary<string, Stack<ScopeSyntax>>(); // словарь скоупов для каждого имени
|
||||
// При добавлении символа мы в словарь добавляем его ПИ (символ может быть правильно вложенным только если вначале идет локальная переменная,
|
||||
// потом - параметр лямбды, потом - локальная переменная вложенной лямбды и т.д.
|
||||
public static new GivenNamesReplacer New
|
||||
Dictionary<string, ScopeSyntax> d = new Dictionary<string, ScopeSyntax>(); // словарь скоупов для каждого имени
|
||||
// При входе в обобщенный класс или запись мы в словарь добавляем все его обобщенные параметры со значением 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<t>.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; // имя такое чтобы при выдаче сообщения об ошибке в нем можно было бы обрезать конец
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<T>(m, n: integer; x: T): array [,] of T;
|
||||
/// Возвращает двумерный массив размера m x n, заполненный элементами x
|
||||
/// Возвращает двумерный массив размера m x n, заполненный элементами gen(i,j)
|
||||
function MatrGen<T>(m, n: integer; gen: (integer,integer)->T): array [,] of T;
|
||||
/// Транспонирует двумерный массив
|
||||
function Transpose<T>(a: array [,] of T): array [,] of T;
|
||||
|
|
|
|||
|
|
@ -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'}
|
||||
|
|
|
|||
Loading…
Reference in a new issue