2017-02-19 16:29:24 +03:00
|
|
|
|
// 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;
|
2016-07-18 13:07:08 +03:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
|
|
using PascalABCCompiler;
|
|
|
|
|
|
using PascalABCCompiler.SyntaxTree;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SyntaxVisitors
|
|
|
|
|
|
{
|
|
|
|
|
|
public class RenameSameBlockLocalVarsVisitor : BaseChangeVisitor
|
|
|
|
|
|
{
|
|
|
|
|
|
// Надо хранить принадлежность имени конкретному ПИ на определенном уровне вложенности
|
|
|
|
|
|
// И отображение этого имени в новое
|
|
|
|
|
|
|
|
|
|
|
|
// Map :: CurrentLevel -> { BlockName -> NewBlockName }
|
|
|
|
|
|
private List<Dictionary<string, string>> BlockNamesStack { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
private Dictionary<string, int> BlockNamesCounter { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private int CurrentLevel = -1;
|
|
|
|
|
|
|
|
|
|
|
|
public RenameSameBlockLocalVarsVisitor()
|
|
|
|
|
|
{
|
|
|
|
|
|
this.BlockNamesStack = new List<Dictionary<string, string>>();
|
|
|
|
|
|
this.BlockNamesCounter = new Dictionary<string, int>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static RenameSameBlockLocalVarsVisitor New
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return new RenameSameBlockLocalVarsVisitor(); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void Accept(procedure_definition pd)
|
|
|
|
|
|
{
|
|
|
|
|
|
New.ProcessNode(pd);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(declarations decls)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Для обхода в правильном порядке сверху вниз
|
|
|
|
|
|
var vd_s = decls.defs.OfType<variable_definitions>().ToArray();
|
|
|
|
|
|
for (int i = 0; i < vd_s.Count(); ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProcessNode(vd_s[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-01 18:40:49 +03:00
|
|
|
|
public override void visit(procedure_header proc_header)
|
2016-07-18 13:07:08 +03:00
|
|
|
|
{
|
2016-08-01 18:40:49 +03:00
|
|
|
|
// DO THIS THING!
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-01 18:40:49 +03:00
|
|
|
|
private bool first_time_visit_function_header = true;
|
2016-07-18 13:07:08 +03:00
|
|
|
|
public override void visit(function_header fh)
|
|
|
|
|
|
{
|
2016-08-01 18:40:49 +03:00
|
|
|
|
if (first_time_visit_function_header)
|
|
|
|
|
|
{
|
|
|
|
|
|
DefaultVisit(fh);
|
|
|
|
|
|
first_time_visit_function_header = false;
|
|
|
|
|
|
}
|
2016-07-18 13:07:08 +03:00
|
|
|
|
// DO NOTHING
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(formal_parameters fp)
|
|
|
|
|
|
{
|
2016-08-01 18:40:49 +03:00
|
|
|
|
if (!first_time_visit_function_header) // чтобы в лямбдах не заходить в формальные параметры. Во вложенных тоже не зайдёт
|
|
|
|
|
|
return;
|
2016-08-06 15:23:20 +03:00
|
|
|
|
// SSM переименование формальных параметров (нужно если мы их изменяем внутри)
|
2016-08-01 18:40:49 +03:00
|
|
|
|
++CurrentLevel;
|
|
|
|
|
|
BlockNamesStack.Add(new Dictionary<string, string>());
|
|
|
|
|
|
if (fp != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var fpids = fp.params_list.SelectMany(tp => tp.idents.idents);
|
|
|
|
|
|
foreach (var v in fpids)
|
|
|
|
|
|
{
|
2017-05-01 17:08:26 +03:00
|
|
|
|
var low = v.name/*.ToLower()*/;
|
|
|
|
|
|
//BlockNamesStack[CurrentLevel].Add(low, "$fp_"+ low);
|
|
|
|
|
|
BlockNamesStack[CurrentLevel][low] = "$fp_" + low;
|
2016-08-01 18:40:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-07-18 13:07:08 +03:00
|
|
|
|
// DO NOTHING
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(statement_list stlist)
|
|
|
|
|
|
{
|
|
|
|
|
|
++CurrentLevel;
|
|
|
|
|
|
|
|
|
|
|
|
if (BlockNamesStack.Count <= CurrentLevel)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Создаем отображение для имен текущего уровня вложенности мини-пространства имен
|
|
|
|
|
|
BlockNamesStack.Add(new Dictionary<string, string>());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//base.visit(stlist);
|
|
|
|
|
|
for (var i = 0; i < stlist.list.Count; ++i)
|
|
|
|
|
|
ProcessNode(stlist.list[i]);
|
|
|
|
|
|
|
|
|
|
|
|
BlockNamesStack.RemoveAt(BlockNamesStack.Count - 1);
|
|
|
|
|
|
|
|
|
|
|
|
--CurrentLevel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-08 00:24:28 +03:00
|
|
|
|
public override void visit(var_def_statement var_def)
|
2016-07-18 13:07:08 +03:00
|
|
|
|
{
|
2018-11-08 00:24:28 +03:00
|
|
|
|
if (var_def.vars.idents.Any(id => id.name.StartsWith("$")))
|
2016-07-18 13:07:08 +03:00
|
|
|
|
{
|
2018-11-08 00:24:28 +03:00
|
|
|
|
base.visit(var_def); // SSM 17/07/16 исправление ошибки - не обходилось выражение-инициализатор
|
2016-07-18 13:07:08 +03:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-08 00:24:28 +03:00
|
|
|
|
var newLocalNames = var_def.vars.idents.Select(id =>
|
2016-07-18 13:07:08 +03:00
|
|
|
|
{
|
2018-11-08 00:24:28 +03:00
|
|
|
|
var low = id.name
|
|
|
|
|
|
//.ToLower()
|
|
|
|
|
|
;
|
2017-05-01 17:08:26 +03:00
|
|
|
|
|
|
|
|
|
|
var newName = this.CreateNewVariableName(low);
|
|
|
|
|
|
//BlockNamesStack[CurrentLevel].Add(low, newName);
|
|
|
|
|
|
BlockNamesStack[CurrentLevel][low] = newName;
|
2016-07-18 13:07:08 +03:00
|
|
|
|
return new ident(newName, id.source_context);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2018-11-08 00:24:28 +03:00
|
|
|
|
var newVS = new var_def_statement(new ident_list(newLocalNames.ToArray()),
|
|
|
|
|
|
var_def.vars_type,
|
|
|
|
|
|
var_def.inital_value);
|
|
|
|
|
|
|
|
|
|
|
|
Replace(var_def, newVS);
|
|
|
|
|
|
listNodes[listNodes.Count - 1] = newVS; //SSM 8.11.18
|
|
|
|
|
|
base.visit(newVS);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*public override void visit(var_statement vs)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (vs.var_def.vars.idents.Any(id => id.name.StartsWith("$")))
|
|
|
|
|
|
{
|
|
|
|
|
|
base.visit(vs); // SSM 17/07/16 исправление ошибки - не обходилось выражение-инициализатор
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var newLocalNames = vs.var_def.vars.idents.Select(id =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var low = id.name
|
|
|
|
|
|
//.ToLower()
|
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
var newName = this.CreateNewVariableName(low);
|
|
|
|
|
|
//BlockNamesStack[CurrentLevel].Add(low, newName);
|
|
|
|
|
|
BlockNamesStack[CurrentLevel][low] = newName;
|
|
|
|
|
|
return new ident(newName, id.source_context);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2016-07-18 13:07:08 +03:00
|
|
|
|
var newVS = new var_statement(new var_def_statement(new ident_list(newLocalNames.ToArray()),
|
|
|
|
|
|
vs.var_def.vars_type,
|
|
|
|
|
|
vs.var_def.inital_value));
|
|
|
|
|
|
|
|
|
|
|
|
Replace(vs, newVS);
|
|
|
|
|
|
|
|
|
|
|
|
base.visit(newVS);
|
2018-11-08 00:24:28 +03:00
|
|
|
|
}/* */
|
2016-07-18 13:07:08 +03:00
|
|
|
|
|
|
|
|
|
|
public override void visit(variable_definitions vd)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (vd.var_definitions.Any(vds => vds.vars.idents.Any(id => id.name.StartsWith("$"))))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
++CurrentLevel;
|
|
|
|
|
|
|
|
|
|
|
|
if (BlockNamesStack.Count <= CurrentLevel)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Создаем отображение для имен текущего уровня вложенности мини-пространства имен
|
|
|
|
|
|
BlockNamesStack.Add(new Dictionary<string, string>());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var newVD = new variable_definitions(
|
|
|
|
|
|
vd.var_definitions.Select(vds =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var newLocalNames = vds.vars.idents.Select(id =>
|
|
|
|
|
|
{
|
2017-05-01 17:08:26 +03:00
|
|
|
|
var low = id.name/*.ToLower()*/;
|
|
|
|
|
|
|
|
|
|
|
|
var newName = this.CreateNewVariableName(low);
|
|
|
|
|
|
//BlockNamesStack[CurrentLevel].Add(low, newName);
|
|
|
|
|
|
BlockNamesStack[CurrentLevel][low] = newName;
|
2016-07-18 13:07:08 +03:00
|
|
|
|
return new ident(newName, id.source_context);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return new var_def_statement(new ident_list(newLocalNames.ToArray()), vds.vars_type, vds.inital_value);
|
|
|
|
|
|
}).ToList(),
|
|
|
|
|
|
vd.source_context);
|
|
|
|
|
|
|
|
|
|
|
|
Replace(vd, newVD);
|
|
|
|
|
|
base.visit(newVD);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(ident id)
|
|
|
|
|
|
{
|
2017-05-01 17:08:26 +03:00
|
|
|
|
var newName = this.GetNewVariableName(id.name/*.ToLower()*/);
|
|
|
|
|
|
if (newName != null)
|
2016-07-18 13:07:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
Replace(id, new ident(newName, id.source_context));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(dot_node dn)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProcessNode(dn.left);
|
|
|
|
|
|
if (dn.right.GetType() != typeof(ident))
|
|
|
|
|
|
ProcessNode(dn.right);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string CreateNewVariableName(string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (BlockNamesCounter.ContainsKey(name))
|
|
|
|
|
|
{
|
|
|
|
|
|
++BlockNamesCounter[name];
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
BlockNamesCounter.Add(name, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
return "$" + name + "__" + BlockNamesCounter[name];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string GetNewVariableName(string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = CurrentLevel; i >= 0; --i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (BlockNamesStack[i].ContainsKey(name))
|
|
|
|
|
|
{
|
|
|
|
|
|
return BlockNamesStack[i][name];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|