ReplaceNamesInIsVarVisitor.cs

This commit is contained in:
Mikhalkovich Stanislav 2020-07-20 20:45:00 +03:00
parent 459d3b4e27
commit ccc7feaee6

View file

@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PascalABCCompiler.SyntaxTree;
// SSM 13/07/20
// Нигде не используется поскольку не решает проблему конфликта is_var и yield.
// Хотя видимо все другие проблемы может решать
namespace SyntaxVisitors.PatternsVisitors
{
class CollectNamesInIsVarVisitor : WalkingVisitorNew
{
public HashSet<string> NamesInIsVars = new HashSet<string>();
public static CollectNamesInIsVarVisitor New => new CollectNamesInIsVarVisitor();
public override void visit(is_pattern_expr isPatternExpr)
{
var pp = isPatternExpr.right?.parameters;
if (pp != null)
{
foreach (var p in pp)
{
if (p is var_deconstructor_parameter vdp)
{
NamesInIsVars.Add(vdp.identifier.name.ToLower());
}
}
}
}
public static HashSet<string> NamesToRename(procedure_definition pd)
{
var v = new CollectNamesInIsVarVisitor();
v.ProcessNode(pd);
return v.NamesInIsVars;
}
}
struct PairNames
{
public ident Name;
public string NewName;
public PairNames(ident Name, string NewName)
{
this.Name = Name;
this.NewName = NewName;
}
}
// Этот визитор запускать только с procedure_definition: ReplaceNamesInIsVarVisitor.New.ProcessNode(pd)
class ReplaceNamesInIsVarVisitor : WalkingVisitorNew
{
HashSet<string> NamesToRename = null;
// Список (стек) пространств имен
List<syntax_tree_node> nsp = new List<syntax_tree_node>();
// Словарь имён
Dictionary<syntax_tree_node, List<PairNames>> dict = new Dictionary<syntax_tree_node, List<PairNames>>();
private int num = 0;
public string GenerateNewName(string name)
{
num += 1;
return "#GenIsVar" + num + "#" + name;
}
public static ReplaceNamesInIsVarVisitor New => new ReplaceNamesInIsVarVisitor();
public syntax_tree_node CurrentNamespace() => nsp[nsp.Count - 1];
public void PushNamespace(syntax_tree_node stn)
{
dict[stn] = new List<PairNames>();
nsp.Add(stn);
}
public void PopNamespace()
{
// удалить соответствующий элемент словаря - если он есть
dict.Remove(CurrentNamespace());
nsp.RemoveAt(nsp.Count - 1);
}
public void AddNameNewName(ident name, string newname)
{
if (!NamesToRename.Contains(name.name.ToLower())) // Если имя - не из нашего внимания, то не добавляем
return;
// Ошибка возникает когда это имя есть в каком-то namespace выше и оно - не через границу function_lambda_definition
// Начинаем проверять с текущего и выше до f_l_d включительно или до p_d включительно. Если есть совпадение, то ошибка
var i = nsp.Count - 1;
while (true)
{
var curns = nsp[i];
// проверить, есть ли в dict[curns] такое имя
if (dict[curns].Select(n=>n.Name.name.ToLower()).Contains(name.name.ToLower()))
throw new SyntaxVisitorError("Повторное объявление", name.source_context);
if (curns is procedure_definition || curns is function_lambda_definition)
break;
i--;
}
dict[CurrentNamespace()].Add(new PairNames(name, newname));
}
public override void visit(procedure_definition pd) // три вида ПИ, которые надо учитывать
{
NamesToRename = CollectNamesInIsVarVisitor.NamesToRename(pd); // Это - акцент внимания
if (NamesToRename.Count == 0)
return; // nothing top do
PushNamespace(pd);
if (pd.proc_header.parameters != null)
{
var allnames = pd.proc_header.parameters.params_list.SelectMany(tp => tp.idents.idents);
foreach (var name in allnames)
AddNameNewName(name, null); // null означает, что переименовывать не надо
}
base.visit(pd);
PopNamespace();
NamesToRename = null;
}
public override void visit(function_lambda_definition fd)
{
PushNamespace(fd);
if (fd.formal_parameters != null)
{
var allnames = fd.formal_parameters.params_list.SelectMany(tp => tp.idents.idents);
foreach (var name in allnames)
AddNameNewName(name, null); // null означает, что переименовывать не надо
}
base.visit(fd);
PopNamespace();
}
public override void visit(statement_list stl)
{
PushNamespace(stl);
base.visit(stl);
PopNamespace();
}
public override void visit(is_pattern_expr isPatternExpr)
{
var pp = isPatternExpr.right?.parameters;
if (pp != null)
{
foreach (var p in pp)
{
if (p is var_deconstructor_parameter vdp)
{
var newname = GenerateNewName(vdp.identifier.name);
AddNameNewName(vdp.identifier.TypedClone(), newname);
vdp.identifier.name = newname;
}
}
}
}
// попытаться переименовать
public void TryToRename(ident id)
{
if (!NamesToRename.Contains(id.name.ToLower()))
return;
// Начинаем искать по ПИ это имя с именем для переименования
for (var i = nsp.Count - 1; i >= 0; i--)
{
var curns = nsp[i];
// проверить, есть ли в dict[curns] такое имя
var ind = dict[curns].FindIndex(pn => pn.Name.name.ToLower() == id.name.ToLower());
if (ind != -1)
{
var newname = dict[curns][ind].NewName;
if (newname != null)
{
id.name = newname;
return; //переименовали - миссия выполнена!
}
}
if (curns is procedure_definition || curns is function_lambda_definition)
break;
}
}
// Собственно переименование
public override void visit(ident id)
{
TryToRename(id);
}
public override void visit(dot_node dn)
{
if (dn.left is ident id)
TryToRename(id);
else ProcessNode(dn.left);
ProcessNode(dn.right);
}
}
}