// 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; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using PascalABCCompiler; using PascalABCCompiler.SyntaxTree; namespace SyntaxVisitors { public class DeleteLocalDefs : BaseChangeVisitor { public List LocalDeletedIds = new List(); public List BlockDeletedIds = new List(); public HashSet idsToDelete; public HashSet deletedIdsToDeleteInLocalScope = new HashSet(); // одно множество и на Local и на Block public DeleteLocalDefs(HashSet ids) // надо запускать этот визитор начиная с корня подпрограммы { idsToDelete = ids; } public override void visit(var_statement vs) { var idents = vs.var_def.vars.idents; var IdentsToDeleteInVarDef = idents.FindAll(id => idsToDelete.Contains(id.name)); // найти в операторе все идентификаторы для удаления if (IdentsToDeleteInVarDef.Count != 0) { deletedIdsToDeleteInLocalScope.UnionWith(IdentsToDeleteInVarDef.Select(id => id.name)); // добавить те идентификаторы, которые мы удаляем из данного описания LocalDeletedIds.Add(new var_def_statement(new ident_list(IdentsToDeleteInVarDef), vs.var_def.vars_type, vs.var_def.inital_value)); // добавить описание из удаленных в данном разделе описаний идентификаторов idents.RemoveAll(id => idsToDelete.Contains(id.name)); // удалить в операторе все идентификаторы для удаления idsToDelete.ExceptWith(deletedIdsToDeleteInLocalScope); if (idents.Count == 0) // то и весь var_statement надо убить this.DeleteInStatementList(vs); } // Здесь мы не обрабатываем вложенный var_def_statement, поэтому когда мы будем обрабатывать его в другом visit, то это будут переменные до beginа подпрограммы или основной программы } public override void visit(var_def_statement vd) { var idents = vd.vars.idents; var IdentsToDeleteInVarDef = idents.FindAll(id => idsToDelete.Contains(id.name)); // найти в операторе все идентификаторы для удаления if (IdentsToDeleteInVarDef.Count != 0) { deletedIdsToDeleteInLocalScope.UnionWith(IdentsToDeleteInVarDef.Select(id => id.name)); // добавить те идентификаторы, которые мы удаляем из данного описания BlockDeletedIds.Add(new var_def_statement(new ident_list(IdentsToDeleteInVarDef), vd.vars_type, vd.inital_value)); // добавить описание из удаленных в данном разделе описаний идентификаторов idents.RemoveAll(id => idsToDelete.Contains(id.name)); // удалить в операторе все идентификаторы для удаления if (idents.Count == 0) { // Выше - variable_definitions, еще выше - declarations var uvdsl = UpperNodeAs(); uvdsl.var_definitions.Remove(vd); if (uvdsl.var_definitions.Count == 0) { var d = UpperNodeAs(2); d.defs.Remove(uvdsl); } } } } public void AfterProcTraverse() { idsToDelete.ExceptWith(deletedIdsToDeleteInLocalScope); // исключаем из множества удаляемых идентификаторов те, которые мы нашли и удалили в секции var_statement. Это надо делать не для каждого описания, а в конце подпрограммы после удаления из всех секций var_statement } } }