// Лучше запретить yield в вложенных функциях и в функциях со вложенными!
        // Запретить-запретить-запретить
        public override void visit(procedure_definition pd)
        {
            // var u = UpperNode(3);
            // В случае отсутствия формальных параметров
            if ((object)pd.proc_header.parameters == null)
            {
                base.visit(pd.proc_body);
                return;
            }

            formalParametersStack.Add(new Dictionary<string, string>());
            int currentLevel = formalParametersStack.Count - 1;

            foreach (var plist in pd.proc_header.parameters.params_list)
            {
                foreach (var id in plist.idents.idents)
                {
                    var paramName = id.name;
                    var hoistedParamName = CapturedNamesHelper.MakeCapturedFormalParameterName(id.name);

                    formalParametersStack[currentLevel].Add(paramName, hoistedParamName);

                    // Захват
                    CollectedFormalParameters.Add(hoistedParamName, plist.vars_type);
                }
            }

            base.visit(pd.proc_body);

            formalParametersStack.RemoveAt(currentLevel);
        }
        public override void visit(procedure_definition p)
        {
            if (PrintInfo)
                Console.WriteLine(" " + p.proc_header.name.meth_name);

            var ld = new FindLocalDefsVisitor(); 
            p.visit(ld);

            base.visit(p);
        }
        public override void visit(procedure_definition pd)
        {
            // frninja

            // Classification
            ISet<string> CollectedLocalsNames = new HashSet<string>();
            ISet<string> CollectedFormalParamsNames = new HashSet<string>();
            ISet<string> CollectedClassFieldsNames = new HashSet<string>();
            ISet<string> CollectedUnitGlobalsNames = new HashSet<string>();

            ISet<var_def_statement> CollectedLocals = new HashSet<var_def_statement>();
            ISet<var_def_statement> CollectedFormalParams = new HashSet<var_def_statement>();

            // Map from ident idName -> captured ident idName
            IDictionary<string, string> CapturedLocalsNamesMap = new Dictionary<string, string>();
            IDictionary<string, string> CapturedFormalParamsNamesMap = new Dictionary<string, string>();

            var dld = new DeleteAllLocalDefs(); // mids.vars - все захваченные переменные
            pd.visit(dld); // Удалить в локальных и блочных описаниях этой процедуры все переменные и вынести их в отдельный список var_def_statement

            // frninja 08/12/15
            bool isInClassMethod;

            // Collect locals
            CollectedLocals.UnionWith(dld.LocalDeletedDefs);
            CollectedLocalsNames.UnionWith(dld.LocalDeletedDefs.SelectMany(vds => vds.vars.idents).Select(id => id.name));
            // Collect formal params
            CollectFormalParams(pd, CollectedFormalParams);
            CollectFormalParamsNames(pd, CollectedFormalParamsNames);
            // Collect class fields
            CollectClassFieldsNames(pd, CollectedClassFieldsNames, out isInClassMethod);

            // Collect unit globals
            CollectUnitGlobalsNames(pd, CollectedUnitGlobalsNames);

            // Create maps :: idName -> captureName
            CreateCapturedLocalsNamesMap(CollectedLocalsNames, CapturedLocalsNamesMap);
            CreateCapturedFormalParamsNamesMap(CollectedFormalParamsNames, CapturedFormalParamsNamesMap);

            // AHAHA test!
            ReplaceCapturedVariablesVisitor rcapVis = new ReplaceCapturedVariablesVisitor(
                CollectedLocalsNames,
                CollectedFormalParamsNames,
                CollectedClassFieldsNames,
                new HashSet<string>(),
                new HashSet<string>(),
                CollectedUnitGlobalsNames,
                CapturedLocalsNamesMap,
                CapturedFormalParamsNamesMap,
                isInClassMethod
                );
            // Replace
            (pd.proc_body as block).program_code.visit(rcapVis);
        }
        public override void visit(procedure_definition pd)
        {
            //this.CurrentMethod = pd;

            MethodsStack.Push(pd);

            HasYields = false;

            base.visit(pd);
            pd.has_yield = HasYields;

            if (pd.has_yield) // SSM bug fix #219
            {
                var ee = pd.proc_body as block;
                if (ee != null)
                {
                    var FirstTypeDeclaration = ee.defs.DescendantNodes().OfType<type_declarations>();
                    if (FirstTypeDeclaration.Count() > 0)
                    {
                        throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_LOCAL_TYPE_DEFINITIONS", FirstTypeDeclaration.First().source_context);
                    }
                }
            }

            var innerPds = pd.DescendantNodes().OfType<procedure_definition>();

            if (pd.has_yield && innerPds.Count() > 0
                || innerPds.Where(npd => npd.has_yield).Count() > 0)
            {
                // Есть yield и вложенные - плохо
                // Или нет yield но есть вложенные с yield
                throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_NESTED_SUBROUTINES", pd.source_context);
            }

            if (pd.has_yield && pd.DescendantNodes().OfType<try_stmt>().Count() > 0)
            {
                throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_TRY_EXCEPT_FINALLY", pd.source_context);
            }

            if (pd.has_yield && pd.DescendantNodes().OfType<lock_stmt>().Count() > 0)
            {
                throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_LOCK", pd.source_context);
            }

            HasYields = false;

            MethodsStack.Pop();

            //this.CurrentMethod = null;
        }
        private void CollectClassFieldsNames(procedure_definition pd, ISet<string> collectedFields, out bool isInClassMethod)
        {
            isInClassMethod = false;

            ident className = null;
            if ((object)pd.proc_header.name.class_name != null)
            {
                // Объявление вне класса его метода
                className = pd.proc_header.name.class_name;
            }
            else
            {
                // Объявление функции в классе?
                var classDef = UpperNode(3) as class_definition;
                if ((object)(UpperNode(3) as class_definition) != null)
                {
                    var td = UpperNode(4) as type_declaration;
                    if ((object)td != null)
                    {
                        className = td.type_name;
                    }
                }
            }

            if ((object)className != null)
            {
                isInClassMethod = true;

                CollectClassFieldsVisitor fieldsVis = new CollectClassFieldsVisitor(className);
                var cu = UpperTo<compilation_unit>();
                if ((object)cu != null)
                {
                    cu.visit(fieldsVis);
                    // Collect
                    collectedFields.UnionWith(fieldsVis.CollectedFields.Select(id => id.name));
                }
            }
        }
        private ident GetClassName(procedure_definition pd)
        {
            if ((object)pd.proc_header.name.class_name != null)
            {
                // Объявление вне класса его метода
                return pd.proc_header.name.class_name;
            }
            else
            {
                // Объявление функции в классе?
                var classDef = UpperNode(3) as class_definition;
                if ((object)(UpperNode(3) as class_definition) != null)
                {
                    var td = UpperNode(4) as type_declaration;
                    if ((object)td != null)
                    {
                        return td.type_name;
                    }
                }
            }

            return null;
        }
 private void CollectUnitGlobalsNames(procedure_definition pd, ISet<string> collectedUnitGlobalsName)
 {
     var cu = UpperTo<compilation_unit>();
     if ((object)cu != null)
     {
         var ugVis = new CollectUnitGlobalsVisitor();
         cu.visit(ugVis);
         // Collect
         collectedUnitGlobalsName.UnionWith(ugVis.CollectedGlobals.Select(id => id.name));
     }
 }
 private void CollectFormalParams(procedure_definition pd, ISet<var_def_statement> collectedFormalParams)
 {
     if ((object)pd.proc_header.parameters != null)
         collectedFormalParams.UnionWith(pd.proc_header.parameters.params_list.Select(tp => new var_def_statement(tp.idents, tp.vars_type)));
 }
        public override void visit(procedure_definition pd)
        {
            // frninja
            // DEBUG for test
            // SORRY

            // Classification
            ISet<string> CollectedLocalsNames = new HashSet<string>();
            ISet<string> CollectedFormalParamsNames = new HashSet<string>();
            ISet<string> CollectedClassFieldsNames = new HashSet<string>();
            ISet<string> CollectedClassMethodsNames = new HashSet<string>();
            ISet<string> CollectedClassPropertiesNames = new HashSet<string>();
            ISet<string> CollectedUnitGlobalsNames = new HashSet<string>();

            ISet<var_def_statement> CollectedLocals = new HashSet<var_def_statement>();
            ISet<var_def_statement> CollectedFormalParams = new HashSet<var_def_statement>();

            // Map from ident idName -> captured ident idName
            IDictionary<string, string> CapturedLocalsNamesMap = new Dictionary<string, string>();
            IDictionary<string, string> CapturedFormalParamsNamesMap = new Dictionary<string, string>();

            hasYields = false;
            if (pd.proc_header is function_header)
                mids = new FindMainIdentsVisitor();

            base.visit(pd);

            if (!hasYields) // т.е. мы разобрали функцию и уже выходим. Это значит, что пока yield будет обрабатываться только в функциях. Так это и надо.
                return;

            LoweringVisitor.Accept(pd);

            // frninja 16/11/15: перенес ниже чтобы работал захват для lowered for

            var dld = new DeleteAllLocalDefs(); // mids.vars - все захваченные переменные
            pd.visit(dld); // Удалить в локальных и блочных описаниях этой процедуры все переменные и вынести их в отдельный список var_def_statement

            // frninja 08/12/15
            bool isClassMethod = IsClassMethod(pd);

            // Collect locals
            CollectedLocals.UnionWith(dld.LocalDeletedDefs);
            CollectedLocalsNames.UnionWith(dld.LocalDeletedDefs.SelectMany(vds => vds.vars.idents).Select(id => id.name));
            // Collect formal params
            CollectFormalParams(pd, CollectedFormalParams);
            CollectFormalParamsNames(pd, CollectedFormalParamsNames);
            // Collect class fields
            CollectClassFieldsNames(pd, CollectedClassFieldsNames);
            // Collect class methods
            CollectClassMethodsNames(pd, CollectedClassMethodsNames);
            // Collect class properties
            CollectClassPropertiesNames(pd, CollectedClassPropertiesNames);
            // Collect unit globals
            CollectUnitGlobalsNames(pd, CollectedUnitGlobalsNames);

            // Create maps :: idName -> captureName
            CreateCapturedLocalsNamesMap(CollectedLocalsNames, CapturedLocalsNamesMap);
            CreateCapturedFormalParamsNamesMap(CollectedFormalParamsNames, CapturedFormalParamsNamesMap);

            // AHAHA test!
            ReplaceCapturedVariablesVisitor rcapVis = new ReplaceCapturedVariablesVisitor(
                CollectedLocalsNames,
                CollectedFormalParamsNames,
                CollectedClassFieldsNames,
                CollectedClassMethodsNames,
                CollectedClassPropertiesNames,
                CollectedUnitGlobalsNames,
                CapturedLocalsNamesMap,
                CapturedFormalParamsNamesMap,
                isClassMethod
                );
            // Replace
            (pd.proc_body as block).program_code.visit(rcapVis);

            mids.vars.Except(dld.LocalDeletedDefsNames); // параметры остались. Их тоже надо исключать - они и так будут обработаны
            // В результате работы в mids.vars что-то осталось. Это не локальные переменные и с ними непонятно что делать

            // Обработать параметры!
            // Как? Ищем в mids formal_parametrs, но надо выделить именно обращение к параметрам - не полям класса, не глобальным переменным

            var cfa = new ConstructFiniteAutomata((pd.proc_body as block).program_code);
            cfa.Transform();
            (pd.proc_body as block).program_code = cfa.res;

            // Конструируем определение класса
            var cct = GenClassesForYield(pd, dld.LocalDeletedDefs, CapturedLocalsNamesMap, CapturedFormalParamsNamesMap); // все удаленные описания переменных делаем описанием класса

            //UpperNodeAs<declarations>().InsertBefore(pd, cct);
            if (isClassMethod)
            {
                var cd = UpperTo<class_definition>();
                if ((object)cd != null)
                {
                    var td = UpperTo<type_declarations>();
                    // Insert class predefenition!
                    var iteratorClassPredef = new type_declaration(GetClassName(pd), new class_definition(null));
                    td.types_decl.Insert(0, iteratorClassPredef);

                    foreach (var helperName in cct.types_decl.Select(ttd => ttd.type_name))
                    {
                        var helperPredef = new type_declaration(helperName, new class_definition());
                        td.types_decl.Insert(0, helperPredef);
                    }

                    foreach (var helper in cct.types_decl)
                    {
                        td.types_decl.Add(helper);
                    }

                    //UpperTo<declarations>().InsertAfter(td, cct);
                }
            }
            else
            {
                UpperTo<declarations>().InsertBefore(pd, cct);
            }

            mids = null; // вдруг мы выйдем из процедуры, не зайдем в другую, а там - оператор! Такого конечно не может быть
        }
		public void visit(procedure_definition _procedure_definition)
		{
			bw.Write((Int16)43);
			write_procedure_definition(_procedure_definition);
		}
Exemple #11
0
        public static type_declaration BuildClassWithOneMethod(string class_name, List<ident> names, List<type_definition> types, procedure_definition pd)
        {
            var formnames = names.Select(x => new ident("form"+x.name)).ToList();

            var cm1 = BuildClassFieldsSection(names, types);
            var cm2 = BuildSimpleConstructorSection(names, formnames, types);
            var cm3 = BuildOneMemberSection(pd);

            return new type_declaration(class_name, BuildClassOrRecordDefinition(true, cm1, cm2, cm3), BuildGenSC);
        }
        // frninja 31/05/16
        /// <summary>
        /// Вставляет метод-хелпер
        /// </summary>
        /// <param name="pd">Метод-итератор</param>
        /// <param name="helper">Метод-хелпер</param>
        private void InsertHelperMethod(procedure_definition pd, procedure_definition helper)
        {
            helper.proc_header.is_yield_helper = true;

            if (IsClassMethod(pd))
            {
                var cd = UpperTo<class_definition>();
                if (cd != null)
                {
                    // Метод класса описан в классе
                    var classMembers = UpperTo<class_members>();
                    classMembers.Add(helper);
                }
                else
                {
                    // Метод класса описан вне класса

                    var decls = UpperTo<declarations>();
                    var classMembers = decls.list
                        .Select(decl => decl as type_declarations)
                        .Where(tdecls => tdecls != null)
                        .SelectMany(tdecls => tdecls.types_decl)
                        .Where(td => td.type_name.name == GetClassName(pd).name)
                        .Select(td => td.type_def as class_definition)
                        .Where(_cd => _cd != null)
                        .SelectMany(_cd => _cd.body.class_def_blocks);


                    // Вставляем предописание метода-хелпера 
                    var helperPredefHeader = ObjectCopier.Clone(helper.proc_header);
                    helperPredefHeader.name.class_name = null;
                    classMembers.First().members.Insert(0, helperPredefHeader);

                    // Вставляем тело метода-хелпера
                    UpperTo<declarations>().InsertBefore(pd, helper);
                }
            }
            else
            {
                UpperTo<declarations>().InsertBefore(pd, helper);
            }
        }
        private void CollectClassMethodsNames(procedure_definition pd, ISet<string> collectedMethods)
        {
            ident className = GetClassName(pd);

            if (className != null)
            {
                CollectClassMethodsVisitor methodsVis = new CollectClassMethodsVisitor(className);
                var cu = UpperTo<compilation_unit>();
                if (cu != null)
                {
                    cu.visit(methodsVis);
                    // Collect
                    collectedMethods.UnionWith(methodsVis.CollectedMethods.Select(id => id.name));
                }
            }
        }
        private where_definition_list GetMethodWhereSection(procedure_definition pd)
        {
            if (!IsClassMethod(pd))
            {
                if (pd.proc_header.where_defs != null)
                {
                    return ObjectCopier.Clone(pd.proc_header.where_defs);
                }
                else
                {
                    var pdPredefs = UpperTo<declarations>().defs
                        .OfType<procedure_definition>()
                        .Where(lpd => lpd.proc_body == null
                                && lpd.proc_header.name.meth_name.name == pd.proc_header.name.meth_name.name
                                && lpd.proc_header.proc_attributes.proc_attributes.FindIndex(attr => attr.attribute_type == proc_attribute.attr_forward) != -1);
                    if (pdPredefs.Count() > 0)
                    {
                        return ObjectCopier.Clone(pdPredefs.First().proc_header.where_defs);
                    }
                }
            }
            else
            {
                class_definition cd = GetMethodClassDefinition(pd);
                if (cd != null)
                {
                    return ObjectCopier.Clone(cd.where_section);
                }
            }

            return null;
        }
        private class_definition GetMethodClassDefinition(procedure_definition pd)
        {
            if (!IsClassMethod(pd))
            {
                return null;
            }

            var cd = UpperTo<class_definition>();
            if (cd != null)
            {
                // Метод класса описан в классе
                return cd;
            }
            else
            {
                // Метод класса описан вне класса

                return UpperTo<declarations>().list
                    .OfType<type_declarations>()
                    .SelectMany(tdecls => tdecls.types_decl)
                    .Where(td => td.type_name.name == GetClassName(pd).name)
                    .Select(td => td.type_def as class_definition)
                    .Where(_cd => _cd != null)
                    .DefaultIfEmpty()
                    .First();
            }
        }
        private void CheckInnerMethodsWithYield(procedure_definition pd)
        {
            var pdWithYields = pd.DescendantNodes(includeSelf: true)
                .OfType<procedure_definition>()
                .Where(npd => npd.has_yield);

            var pddds = pdWithYields.Count();
        }
        public override void visit(procedure_definition pd)
        {
            // frninja 14/06/16 - проверяем наличие yield у вложенных методов (и запрещаем )
            CheckInnerMethodsWithYield(pd);

            if (!pd.has_yield)
                return;

            // frninja 05/06/16 - вставляем предописание если метод-итератор описан не в классе (обычная функция) чтоб работали рекурсивные вызовы
            // Нужен также для верной работы <yield_error> функции, проверяющей разные ошибки на этапе семантики
            // Как только уберу <yield_error>-функцию, от этого тоже можно избавиться
            bool methodPredefCreated = InsertGlobalIteratorMethodPredefinition(pd);

            // frninja 24/05/16 - оборачиваем одиночные операторы в begin..end
            AddBeginEndsVisitor.Accept(pd);

            /*
            // Проверяем проблемы имен для for
            CheckVariablesRedefenitionVisitor checkVarRedefVisitor = new CheckVariablesRedefenitionVisitor(
                new HashSet<string>(
                    pd.proc_header.parameters != null
                    ?
                    pd.proc_header.parameters.params_list.SelectMany(fp => fp.idents.idents.Select(id => id.name))
                    :
                    Enumerable.Empty<string>()));
            pd.visit(checkVarRedefVisitor);
            */

            // Выносим выражение из yield в отдельную переменную
            ReplaceYieldExprByVarVisitor.Accept(pd);

            // Раскрываем операторы yield sequence. На семантике они не существуют
            LoweringYieldSequenceVisitor.Accept(pd);

            // frninja 31/05/16 - добавляем метод-хелпер, возьмет на себя проверку разных ошибок уже существующим бэкендом
            CreateErrorCheckerHelper(pd); // SSM 14/07/16 - переставил до переименования переменных чтобы отлавливались ошибки одинаковых имен в разных пространствах имен
            // SSM - можно сделать спец визитор, который бы отлавливал дубли имен - тогда этого не надо

            // Переименовываем одинаковые имена в мини-ПИ: begin var a := 1 end; begin var a := 1 end; 
            RenameSameBlockLocalVarsVisitor.Accept(pd);

            // SSM 01/08/16 - надо захватить и переименовать еще все формальные параметры. 
            // Это решит проблему их изменения в pd при следующем вызове запроса.
            var bb = pd.proc_body as block;
            if (pd.proc_header.parameters != null)
            {
                var fpids = pd.proc_header.parameters.params_list.SelectMany(tp => tp.idents.idents);
                foreach (var v in fpids)
                {
                    var vds = new var_statement(new ident("$fp_"+v.name, v.source_context), v);
                    bb.program_code.AddFirst(vds);
                }
            }

            // Теперь lowering
            LoweringVisitor.Accept(pd);

            // frninja 13/04/16 - убираем лишние begin..end
            DeleteRedundantBeginEnds.Accept(pd);

            // Обработка метода для корректного захвата локальных переменных и их типов
            // - это уже не надо - иногда можно включать чтобы посмотреть, что собой представляет функция после Loweringа
            //IEnumerable<var_def_statement> localsClonesCollection;
            //CreateLocalVariablesTypeProxies(pd, out localsClonesCollection);         

            // frninja 16/11/15: перенес ниже чтобы работал захват для lowered for

            var dld = MoveAllLocalDefsToLists.Accept(pd); // Удалить в локальных и блочных описаниях этой процедуры все переменные и вынести их в отдельный список var_def_statement

            // Строим отображение из локальных переменных клона оригинального метода в локальные переменные основного метода
            //Dictionary<var_def_statement, var_def_statement> localsCloneMap = CreateLocalsClonesMap(dld.LocalDeletedDefs, localsClonesCollection);

            // frninja 08/12/15

            // Выполняем захват имён
            IDictionary<string, string> CapturedLocalsNamesMap;
            IDictionary<string, string> CapturedFormalParamsNamesMap;
            ReplaceCapturedVariables(pd, dld.LocalDeletedDefs, out CapturedLocalsNamesMap, out CapturedFormalParamsNamesMap);

            //mids.vars.Except(dld.LocalDeletedDefsNames); // параметры остались. Их тоже надо исключать - они и так будут обработаны
            // В результате работы в mids.vars что-то осталось. Это не локальные переменные и с ними непонятно что делать

            // Обработать параметры! 
            // Как? Ищем в mids formal_parametrs, но надо выделить именно обращение к параметрам - не полям класса, не глобальным переменным

            var cfa = new ConstructFiniteAutomata(pd.proc_body as block);
            cfa.Transform();

            (pd.proc_body as block).program_code = cfa.res;

            // Конструируем определение класса
            var cct = GenClassesForYield(pd, dld.LocalDeletedDefs, CapturedLocalsNamesMap, CapturedFormalParamsNamesMap/*, localsCloneMap*/); // все удаленные описания переменных делаем описанием класса

            // Вставляем классы-хелперы
            InsertYieldHelpers(pd, cct);

            // frninja 20/05/16 - фикс для повторного обхода
            pd.has_yield = false;

            // frninja 05/06/16 - убираем where-секцию у описания метода. Они уже скопированы куда надо
            /*if (methodPredefCreated)
            {
                pd.proc_header.where_defs = null;
            }*/

            //mids = null; // вдруг мы выйдем из процедуры, не зайдем в другую, а там - оператор! Такого конечно не может быть
        }
        // frninja 31/05/16
        /// <summary>
        /// Вставляет клон метода-итератора для того, чтобы проверить ошибки существующим бэкендом (пересечение диапазонов case, повторные объявления переменных)
        /// </summary>
        /// <param name="pd"></param>
        private void CreateErrorCheckerHelper(procedure_definition pd)
        {
            // Клонируем исходный метод для проверок ошибок бэкендом
            var pdCloned = ObjectCopier.Clone(pd);

            pdCloned.has_yield = false;


            // Добавляем в класс метод с обертками для локальных переменных
            pdCloned.proc_header.name.meth_name = new ident(YieldConsts.YieldHelperMethodPrefix + "_error_checkerr>" + pd.proc_header.name.meth_name.name,
                // frninja 05/06/16 - фиксим source_context
                pd.proc_header.name.meth_name.source_context); // = new method_name("<yield_helper_locals_type_detector>" + pd.proc_header.className.meth_name.className);
            //pdCloned.is_yield_helper = true;

            InsertHelperMethod(pd, pdCloned);
        }
 public static void Accept(procedure_definition pd)
 {
     New.ProcessNode(pd);
 }
        /// <summary>
        /// Обработка локальных переменных метода и их типов для корректного захвата
        /// </summary>
        /// <param className="pd">Объявление метода</param>
        /// <returns>Коллекция посещенных локальных переменных</returns>
        // SSM - Эта функция уже не нужна - я иногда использую ее чтобы посмотреть как выглядит функция после Loweringа
        private void CreateLocalVariablesTypeProxies(procedure_definition pd, out IEnumerable<var_def_statement> localsClonesCollection)
        {
            // Выполняем определение типов локальных переменных с автовыводом типов

            // Клонируем исходный метод для вставки оберток-хелперов для локальных переменных и дальнейшей обработки на семантике
            var pdCloned = ObjectCopier.Clone(pd);
            //var pdCloned = pd;

            pdCloned.has_yield = false;

            // Заменяем локальные переменные с неизвестным типом на обертки-хелперы (откладываем до семантики)
            var localsTypeDetectorHelperVisitor = new LocalVariablesTypeDetectorHelperVisior();
            pdCloned.visit(localsTypeDetectorHelperVisitor);

            // frninja 16/03/16 - строим список локальных переменных в правильном порядке
            localsTypeDetectorHelperVisitor.LocalDeletedDefs.AddRange(localsTypeDetectorHelperVisitor.LocalDeletedVS);
            localsTypeDetectorHelperVisitor.LocalDeletedVS.Clear();

            localsClonesCollection = localsTypeDetectorHelperVisitor.LocalDeletedDefs.ToArray();

            // Добавляем в класс метод с обертками для локальных переменных
            pdCloned.proc_header.name.meth_name = new ident(YieldConsts.YieldHelperMethodPrefix+ "_locals_type_detector>" + pd.proc_header.name.meth_name.name,
                // frninja 05/06/16 - фиксим source_context
                pd.proc_header.name.meth_name.source_context); // = new method_name("<yield_helper_locals_type_detector>" + pd.proc_header.className.meth_name.className);

            InsertHelperMethod(pd, pdCloned); // SSM 13.07.16 - вызов этого метода можно не добавлять
        }
		public void write_procedure_definition(procedure_definition _procedure_definition)
		{
			write_declaration(_procedure_definition);
			if (_procedure_definition.proc_header == null)
			{
				bw.Write((byte)0);
			}
			else
			{
				bw.Write((byte)1);
				_procedure_definition.proc_header.visit(this);
			}
			if (_procedure_definition.proc_body == null)
			{
				bw.Write((byte)0);
			}
			else
			{
				bw.Write((byte)1);
				_procedure_definition.proc_body.visit(this);
			}
			bw.Write(_procedure_definition.is_short_definition);
		}
        /// <summary>
        /// Отображение локальных в клонированные локальные
        /// </summary>
        /// <param className="from">Откуда</param>
        /// <param className="to">Куда</param>
        /// <returns>Отображение</returns>
        /*private Dictionary<var_def_statement, var_def_statement> CreateLocalsClonesMap(IEnumerable<var_def_statement> from, IEnumerable<var_def_statement> to)
        {
            // Нужно тк клонировали метод для создания хелпера-определителя типов локальных переменных - Eq не будет работать

            // Строим отображение из локальных переменных клона оригинального метода в локальные переменные основного метода
            Dictionary<var_def_statement, var_def_statement> localsClonesMap = new Dictionary<var_def_statement, var_def_statement>();

            var localsArr = from.ToArray();
            var localsClonesArr = to.ToArray();

            // Create map :: locals -> cloned locals
            for (int i = 0; i < localsArr.Length; ++i)
            {
                localsClonesMap.Add(localsArr[i], localsClonesArr[i]);
            }

            return localsClonesMap;
        }*/

        

        /// <summary>
        /// Вставляем описание классов-хелперов для yield перед методом-итератором в зависимости от его описания
        /// </summary>
        /// <param className="pd">Метод-итератор</param>
        /// <param className="cct">Описание классов-хелперов для yield</param>
        private void InsertYieldHelpers(procedure_definition pd, type_declarations cct)
        {
            if (IsClassMethod(pd))
            {
                var cd = UpperTo<class_definition>();
                if (cd != null)
                {
                    // Если метод класса описан в классе
                    var td = UpperTo<type_declarations>();

                    // frninja 20/04/16 - выпилено 

                    //foreach (var helperName in cct.types_decl.Select(ttd => ttd.type_name))
                    //{
                    //    var helperPredef = new type_declaration(helperName, new class_definition());
                        //td.types_decl.Insert(0, helperPredef);
                    //}

                    // Insert class predefenition!
                    //var iteratorClassPredef = new type_declaration(GetClassName(pd), new class_definition(null));
                    //td.types_decl.Insert(0, iteratorClassPredef);

                    foreach (var helper in cct.types_decl)
                    {
                        td.types_decl.Add(helper);
                    }

                }
                else
                {
                    // Метод класса описан вне класса
                    UpperTo<declarations>().InsertBefore(pd, cct);
                }
            }
            else
            {
                UpperTo<declarations>().InsertBefore(pd, cct);
            }
        }
        private void CollectClassPropertiesNames(procedure_definition pd, ISet<string> collectedProperties)
        {
            ident className = GetClassName(pd);

            if ((object)className != null)
            {
                CollectClassPropertiesVisitor propertiesVis = new CollectClassPropertiesVisitor(className);
                var cu = UpperTo<compilation_unit>();
                if ((object)cu != null)
                {
                    cu.visit(propertiesVis);
                    // Collect
                    collectedProperties.UnionWith(propertiesVis.CollectedProperties.Select(id => id.name));
                }
            }
        }
        /// <summary>
        /// Захватываем имена в методе
        /// </summary>
        /// <param className="pd">Метод-итератор</param>
        /// <param className="deletedLocals">Коллекция удаленных локальных переменных</param>
        /// <param className="capturedLocalsNamesMap">Построенное отображение имен локальных переменных в захваченные имена</param>
        /// <param className="capturedFormalParamsNamesMap">Построенное отображение имен формальных параметров в захваченные имена</param>
        private void ReplaceCapturedVariables(procedure_definition pd,
            IEnumerable<var_def_statement> deletedLocals,
            out IDictionary<string, string> capturedLocalsNamesMap,
            out IDictionary<string, string> capturedFormalParamsNamesMap)
        {
            // Структуры данных под классификацию имен в методе

            // Classification
            ISet<string> CollectedLocalsNames = new HashSet<string>();
            ISet<string> CollectedFormalParamsNames = new HashSet<string>();
            ISet<string> CollectedClassFieldsNames = new HashSet<string>();
            ISet<string> CollectedClassMethodsNames = new HashSet<string>();
            ISet<string> CollectedClassPropertiesNames = new HashSet<string>();
            ISet<string> CollectedUnitGlobalsNames = new HashSet<string>();

            ISet<var_def_statement> CollectedLocals = new HashSet<var_def_statement>();
            ISet<var_def_statement> CollectedFormalParams = new HashSet<var_def_statement>();

            // Map from ident idName -> captured ident idName
            capturedLocalsNamesMap = new Dictionary<string, string>();
            capturedFormalParamsNamesMap = new Dictionary<string, string>();

            // Собираем инфу о именах

            // Collect locals
            CollectedLocals.UnionWith(deletedLocals);
            CollectedLocalsNames.UnionWith(deletedLocals.SelectMany(vds => vds.vars.idents).Select(id => id.name));
            // Collect formal params
            CollectFormalParams(pd, CollectedFormalParams);
            CollectFormalParamsNames(pd, CollectedFormalParamsNames);

            // Collect class fields
            CollectClassFieldsNames(pd, CollectedClassFieldsNames);
            // Collect class methods
            CollectClassMethodsNames(pd, CollectedClassMethodsNames);
            // Collect class properties
            CollectClassPropertiesNames(pd, CollectedClassPropertiesNames);
            // Collect unit globals
            CollectUnitGlobalsNames(pd, CollectedUnitGlobalsNames);

            // Строим отображения для имён захваченных локальных переменных и формальных параметров

            // Create maps :: idName -> captureName
            CreateCapturedLocalsNamesMap(CollectedLocalsNames, capturedLocalsNamesMap);
            CreateCapturedFormalParamsNamesMap(CollectedFormalParamsNames, capturedFormalParamsNamesMap);

            // Выполняем замену захват имён в теле метода
            // AHAHA test!
            ReplaceCapturedVariablesVisitor rcapVis = new ReplaceCapturedVariablesVisitor(
                CollectedLocalsNames,
                CollectedFormalParamsNames,
                CollectedClassFieldsNames,
                CollectedClassMethodsNames,
                CollectedClassPropertiesNames,
                CollectedUnitGlobalsNames,
                capturedLocalsNamesMap,
                capturedFormalParamsNamesMap,
                IsClassMethod(pd),
                pd.proc_header.class_keyword,
                GetClassName(pd)
                );
            // Replace
            (pd.proc_body as block).program_code.visit(rcapVis);
        }
 private void CollectFormalParamsNames(procedure_definition pd, ISet<string> collectedFormalParamsNames)
 {
     if ((object)pd.proc_header.parameters != null)
         collectedFormalParamsNames.UnionWith(pd.proc_header.parameters.params_list.SelectMany(tp => tp.idents.idents).Select(id => id.name));
 }
        private bool IsExtensionMethod(procedure_definition pd)
        {
            var tdecls = UpperTo<declarations>().defs.OfType<type_declarations>().SelectMany(tds => tds.types_decl);

            var isExtension = pd.proc_header.proc_attributes.proc_attributes.Any(attr => attr.name == "extensionmethod");

            if (isExtension)
            {
                // Метод объявлен как extensionmethod
                
                // !!!!!!!! TODO: Проверить что имя класса не находится в этом модуле.

                // Убираем за ненадобностью имя класса ибо оно указано как тип обязательного параметра self
                
                pd.proc_header.name.class_name = null;
                return true;
            }
            else
            {
                // Если не похоже на метод-расширение или объявление вне класса
                if (pd.proc_header.name.class_name == null)
                    return false;

                
                // Разрешаем только имена типов из этого модуля (не расширения)
                if (!tdecls.Any(td => td.type_name.name == pd.proc_header.name.class_name.name))
                {
                    // Имя в модуле не найдено -> метод расширение описанный без extensionmethod. Ругаемся!!!
                    throw new SyntaxVisitorError("Possible extension-method definintion without extensionmethod keyword. Please use extensionmethod syntax",
                        pd.proc_header.source_context);
                }
                
            }
            
            return false;
        }
        /*public override void visit(class_members cm)
        {
            foreach (var decl in cm.members)
            {
                if (decl is procedure_header || decl is procedure_definition)
                    decl.visit(this);
            }
            base.visit(cm);
        }*/
        type_declarations GenClassesForYield(procedure_definition pd, IEnumerable<var_def_statement> fields,
            IDictionary<string, string> localsMap,
            IDictionary<string, string> formalParamsMap)
        {
            var fh = (pd.proc_header as function_header);
            if (fh == null)
                throw new SyntaxError("Only functions can contain yields", "", pd.proc_header.source_context, pd.proc_header);
            var seqt = fh.return_type as sequence_type;
            if (seqt == null)
                throw new SyntaxError("Functions with yields must return sequences", "", fh.return_type.source_context, fh.return_type);

            // Теперь на месте функции генерируем класс

            // Захваченные переменные
            var cm = class_members.Public;
            var capturedFields = fields.Select(vds =>
                                    {
                                        ident_list ids = new ident_list(vds.vars.idents.Select(id => new ident(localsMap[id.name])).ToArray());
                                        return new var_def_statement(ids, vds.vars_type, vds.inital_value);
                                    });

            foreach (var m in capturedFields)
                cm.Add(m);

            // Параметры функции
            List<ident> lid = new List<ident>();
            var pars = fh.parameters;
            if (pars != null)
                foreach (var ps in pars.params_list)
                {
                    if (ps.param_kind != parametr_kind.none)
                        throw new SyntaxError("Parameters of functions with yields must not have 'var', 'const' or 'params' modifier", "", pars.source_context, pars);
                    if (ps.inital_value != null)
                        throw new SyntaxError("Parameters of functions with yields must not have initial values", "", pars.source_context, pars);
                    //var_def_statement vds = new var_def_statement(ps.idents, ps.vars_type);
                    ident_list ids = new ident_list(ps.idents.list.Select(id => new ident(formalParamsMap[id.name])).ToArray());
                    var_def_statement vds = new var_def_statement(ids, ps.vars_type);
                    cm.Add(vds); // все параметры функции делаем полями класса
                    //lid.AddRange(vds.vars.idents);
                    lid.AddRange(ps.idents.list);
                }

            var stels = seqt.elements_type;

            // frninja 08/18/15 - Для захвата self
            if ((object)GetClassName(pd) != null)
                cm.Add(new var_def_statement(Consts.Self, GetClassName(pd).name));

            // Системные поля и методы для реализации интерфейса IEnumerable
            cm.Add(new var_def_statement(Consts.State, "integer"),
                new var_def_statement(Consts.Current, stels),
                procedure_definition.EmptyDefaultConstructor,
                new procedure_definition("Reset"),
                new procedure_definition("MoveNext", "boolean", pd.proc_body),
                new procedure_definition("get_Current", "object", new assign("Result", Consts.Current)),
                new procedure_definition("GetEnumerator", "System.Collections.IEnumerator", new assign("Result", "Self"))
                );

            var className = newClassName();
            var classNameHelper = className + "Helper";

            var interfaces = new named_type_reference_list("System.Collections.IEnumerator", "System.Collections.IEnumerable");
            var td = new type_declaration(classNameHelper, SyntaxTreeBuilder.BuildClassDefinition(interfaces, cm));

            // Изменение тела процедуры

            var stl = new statement_list(new var_statement("res", new new_expr(className)));
            //stl.AddMany(lid.Select(id => new assign(new dot_node("res", id), id)));
            stl.AddMany(lid.Select(id => new assign(new dot_node("res", new ident(formalParamsMap[id.name])), id)));

            // frninja 08/12/15 - захват self
            if ((object)GetClassName(pd) != null)
                stl.Add(new assign(new dot_node("res", Consts.Self), new ident("self")));

            stl.Add(new assign("Result", "res"));

            // New body
            pd.proc_body = new block(stl);

            if ((object)GetClassName(pd) != null)
            {
                // frninja 10/12/15 - заменить на function_header и перенести описание тела в declarations
                Replace(pd, fh);
                var decls = UpperTo<declarations>();
                if ((object)decls != null)
                {
                    function_header nfh = new function_header();
                    nfh.name = new method_name(fh.name.meth_name.name);
                    // Set name
                    nfh.name.class_name = GetClassName(pd);
                    nfh.parameters = fh.parameters;
                    nfh.proc_attributes = fh.proc_attributes;

                    procedure_definition npd = new procedure_definition(nfh, new block(stl));

                    // Update header
                    //pd.proc_header.name.class_name = GetClassName(pd);
                    // Add to decls
                    decls.Add(npd);
                }
            }

            // Второй класс

            var tpl = new template_param_list(stels);

            var IEnumeratorT = new template_type_reference("System.Collections.Generic.IEnumerator", tpl);

            var cm1 = class_members.Public.Add(
                procedure_definition.EmptyDefaultConstructor,
                new procedure_definition(new function_header("get_Current", stels), new assign("Result", Consts.Current)),
                new procedure_definition(new function_header("GetEnumerator", IEnumeratorT), new assign("Result", "Self")),
                new procedure_definition("Dispose")
            );

            var interfaces1 = new named_type_reference_list(classNameHelper);
            var IEnumerableT = new template_type_reference("System.Collections.Generic.IEnumerable", tpl);

            interfaces1.Add(IEnumerableT).Add(IEnumeratorT);

            var td1 = new type_declaration(className, SyntaxTreeBuilder.BuildClassDefinition(interfaces1, cm1));

            var cct = new type_declarations(td);
            cct.Add(td1);

            return cct;
        }
        /*public override void Enter(syntax_tree_node st)
        {
            base.Enter(st);
            countNodesVisited++;

            // сокращение обходимых узлов. Как сделать фильтр по тем узлам, которые необходимо обходить? Например, все операторы (без выражений и описаний), все описания (без операторов)
            if (st.GetType()==typeof(assign) || st.GetType()==typeof(var_def_statement) || st is procedure_call || st is procedure_header || st is expression)
            {
                visitNode = false; // фильтр - куда не заходить 
            }
        }*/

        /*public override void visit(class_members cm)
        {
            foreach (var decl in cm.members)
            {
                if (decl is procedure_header || decl is procedure_definition)
                    decl.visit(this);
            }
            base.visit(cm);
        }*/

        type_declarations GenClassesForYield(procedure_definition pd,
            IEnumerable<var_def_statement> fields, // локальные переменные
            IDictionary<string, string> localsMap, // отображение для захваченных имен локальных переменных
            IDictionary<string, string> formalParamsMap//, // отображение для захваченных имен формальных параметров
            //IDictionary<var_def_statement, var_def_statement> localsCloneMap // отображение для оберток локальных переменных 
            ) 
        {
            var fh = (pd.proc_header as function_header);
            if (fh == null)
                throw new SyntaxError("Only functions can contain yields", "", pd.proc_header.source_context, pd.proc_header);
            var seqt = fh.return_type as sequence_type;
            if (seqt == null)
                throw new SyntaxError("Functions with yields must return sequences", "", fh.return_type.source_context, fh.return_type);

            // Теперь на месте функции генерируем класс

            // Захваченные локальные переменные
            var cm = class_members.Public;
            var capturedFields = fields.Select(vds =>
                                    {
                                        ident_list ids = new ident_list(vds.vars.idents.Select(id => new ident(localsMap[id.name])).ToArray());
                                        if (vds.vars_type == null) //&& vds.inital_value != null)
                                        {
                                            if (vds.inital_value != null)
                                            {
                                                //return new var_def_statement(ids, new yield_unknown_expression_type(localsCloneMap[vds], varsTypeDetectorHelper), null);
                                                return new var_def_statement(ids, new yield_unknown_expression_type(vds), null); // SSM - убрал localsCloneMap[vds] - заменил на vds - не знаю, зачем вообще это отображение делалось - всё равно оно было тождественным!!!
                                            }
                                            else
                                            {
                                                throw new SyntaxVisitorError("Variable defenition without type and value!",vds.source_context); // SSM - быть такого не может - грамматика не пропустит
                                            }
                                        }
                                        else
                                        {
                                            return new var_def_statement(ids, vds.vars_type, null);
                                        }
                                        
                                        //return new var_def_statement(ids, vds.vars_type, vds.inital_value);
                                    });

            foreach (var m in capturedFields)
                cm.Add(m);

            // Параметры функции
            List<ident> lid = new List<ident>();
            var pars = fh.parameters;
            if (pars != null)
                foreach (var ps in pars.params_list)
                {
                    if (ps.param_kind != parametr_kind.none)
                        throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_VAR_CONST_PARAMS_MODIFIERS", pars.source_context);
                    if (ps.inital_value != null)
                        throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_DEFAULT_PARAMETERS", pars.source_context);
                    //var_def_statement vds = new var_def_statement(ps.idents, ps.vars_type);
                    ident_list ids = new ident_list(ps.idents.list.Select(id => new ident(formalParamsMap[id.name])).ToArray());
                    var_def_statement vds = new var_def_statement(ids, ps.vars_type);
                    cm.Add(vds); // все параметры функции делаем полями класса
                    //lid.AddRange(vds.vars.idents);
                    lid.AddRange(ps.idents.list);
                }

            var stels = seqt.elements_type;

            var iteratorClassName = GetClassName(pd);

            // frninja 08/18/15 - Для захвата self
            if (iteratorClassName != null)
            {
                // frninja 20/04/16 - поддержка шаблонных классов
                var iteratorClassRef = CreateClassReference(iteratorClassName);

                cm.Add(new var_def_statement(YieldConsts.Self, iteratorClassRef));
            }

            var GetEnumeratorBody = new statement_list();

            // Системные поля и методы для реализации интерфейса IEnumerable
            cm.Add(new var_def_statement(YieldConsts.State, "integer"),
                new var_def_statement(YieldConsts.Current, stels),
                procedure_definition.EmptyDefaultConstructor,
                new procedure_definition("Reset"),
                new procedure_definition("MoveNext", "boolean", pd.proc_body),
                new procedure_definition("System.Collections.IEnumerator.get_Current", "object", new assign("Result", YieldConsts.Current)),
                //new procedure_definition("System.Collections.IEnumerable.GetEnumerator", "System.Collections.IEnumerator", new assign("Result", "Self"))
                new procedure_definition("System.Collections.IEnumerable.GetEnumerator", "System.Collections.IEnumerator", GetEnumeratorBody)
                );

            // frninja 20/04/16 - поддержка шаблонных классов
            var yieldClassName = NewYieldClassName();
            var yieldClassHelperName = yieldClassName + "Helper";

            var className = this.CreateHelperClassName(yieldClassName, iteratorClassName, pd);
            var classNameHelper = this.CreateHelperClassName(yieldClassHelperName, iteratorClassName, pd);
            

            var interfaces = new named_type_reference_list("System.Collections.IEnumerator", "System.Collections.IEnumerable");

            // frninja 24/04/16 - поддержка шаблонных классов
            //var td = new type_declaration(classNameHelper, this.CreateHelperClassDefinition(classNameHelper, pd, interfaces, cm));
                //SyntaxTreeBuilder.BuildClassDefinition(interfaces, cm));

            // Изменение тела процедуры
            

            // frninja 20/04/16 - поддержка шаблонных классов
            var stl = new statement_list(new var_statement("$res", new new_expr(this.CreateClassReference(className), new expression_list())));
            

            //stl.AddMany(lid.Select(id => new assign(new dot_node("$res", id), id)));
            stl.AddMany(lid.Select(id => new assign(new dot_node("$res", new ident(formalParamsMap[id.name])), id)));

            // frninja 08/12/15 - захват self
            if (iteratorClassName != null && !pd.proc_header.class_keyword)
            {
                stl.Add(new assign(new dot_node("$res", YieldConsts.Self), new ident("self")));
            }

            stl.Add(new assign("Result", "$res"));

            // New body
            pd.proc_body = new block(stl);

            if (iteratorClassName != null)
            {
                var cd = UpperTo<class_definition>();
                if (cd != null)
                {
                    // Если метод описан в классе 
                    // frninja 10/12/15 - заменить на function_header и перенести описание тела в declarations
                    Replace(pd, fh);
                    var decls = UpperTo<declarations>();
                    if (decls != null)
                    {
                        // frninja 12/05/16 - забыли копировать return
                        function_header nfh = ObjectCopier.Clone(fh);
                        //function_header nfh = new function_header();
                        //nfh.name = new method_name(fh.name.meth_name.name);

                        // Set className
                        nfh.name.class_name = iteratorClassName;
                        //nfh.parameters = fh.parameters;
                        //nfh.proc_attributes = fh.proc_attributes;
                        //nfh.return_type = fh.return_type;

                        procedure_definition npd = new procedure_definition(nfh, new block(stl));

                        // Update header
                        //pd.proc_header.className.class_name = GetClassName(pd);
                        // Add to decls
                        decls.Add(npd);
                    }
                }
            }

            // Второй класс

            var tpl = new template_param_list(stels);

            var IEnumeratorT = new template_type_reference("System.Collections.Generic.IEnumerator", tpl);

            var cm1 = cm.Add( //class_members.Public.Add(
                //procedure_definition.EmptyDefaultConstructor,
                new procedure_definition(new function_header("get_Current", stels), new assign("Result", YieldConsts.Current)),
                new procedure_definition(new function_header("GetEnumerator", IEnumeratorT), GetEnumeratorBody),
                new procedure_definition("Dispose")
            );


            // frninja 20/04/16 - поддержка шаблонных классов
            var interfaces1 = new named_type_reference_list(/*this.CreateClassReference(classNameHelper) as named_type_reference*/);
            var IEnumerableT = new template_type_reference("System.Collections.Generic.IEnumerable", tpl);

            interfaces1.Add(IEnumerableT).Add(IEnumeratorT);

            // frninja 24/04/16 - поддержка шаблонных классов

            // frninja 05/06/16 - фикс. Поддержка where секции
            var helperClassDefinition = this.CreateHelperClassDefinition(className, pd, interfaces1, cm1);
            helperClassDefinition.where_section = this.GetMethodWhereSection(pd);

            var td1 = new type_declaration(className, helperClassDefinition);
            //SyntaxTreeBuilder.BuildClassDefinition(interfaces1, cm1));


            var stl1 = new statement_list(new var_statement("$res", new new_expr(this.CreateClassReference(className), new expression_list())));
            

            stl1.AddMany(lid.Select(id => new assign(new dot_node("$res", new ident(formalParamsMap[id.name])), new ident(formalParamsMap[id.name]))));

            // Переприсваивание self 
            if (iteratorClassName != null && !pd.proc_header.class_keyword)
            {
                stl1.Add(new assign(new dot_node("$res", YieldConsts.Self), new ident(YieldConsts.Self)));
            }

            stl1.Add(new assign("Result", "$res"));


            GetEnumeratorBody.Add(new if_node(new bin_expr(new ident(YieldConsts.State), new int32_const(0), Operators.Equal),
                new assign("Result", "Self"),
                stl1));

            var cct = new type_declarations(/*td*/);
            cct.Add(td1);

            return cct;
        }
 private bool IsClassMethod(procedure_definition pd)
 {
     return (object)GetClassName(pd) != null;
 }
        /// <summary>
        /// Вставляет предописание метода-итератора для рекурсивных вызовов, если метод описан вне класса
        /// </summary>
        private bool InsertGlobalIteratorMethodPredefinition(procedure_definition pd)
        {
            if (IsExtensionMethod(pd))  // SSM 17.07.16 - нельзя генерировать предописания для extension-методов!
            {
                return false;
            }

            if (IsClassMethod(pd))
            {
                return false;
            }

            // SSM 20/08/16 и еще нельзя генерировать если это функция, описанная в interface и implementation модуля
            var un = UpperNode(2) as implementation_node;
            if (un != null)
            {
                var cu = UpperNode(3) as unit_module;
                if (cu != null) // а это всегда так
                {
                    var fhh = cu.interface_part.interface_definitions.defs.OfType<function_header>().Where(fh => fh.name.meth_name.name.ToLower()==pd.proc_header.name.meth_name.name.ToLower());
                    if (fhh.Any()) // если еcть в разделе интерфейса такие же имена, то не генерировать предописание 
                        return false;
                    // вообще-то надо сравнивать заголовки - не только имена - но даже так устраняется основная масса ошибок
                }
            }

            var pdPredefs = UpperTo<declarations>().defs
                .OfType<procedure_definition>()
                .Where(lpd => lpd.proc_body == null
                        && lpd.proc_header.name.meth_name.name == pd.proc_header.name.meth_name.name
                        && lpd.proc_header.proc_attributes.proc_attributes.FindIndex(attr => attr.attribute_type == proc_attribute.attr_forward) != -1);


            bool isPredefined = pdPredefs.Count() > 0;

            if (!isPredefined)
            {

                var fh = ObjectCopier.Clone(pd.proc_header as function_header);
                fh.proc_attributes.Add(new procedure_attribute(proc_attribute.attr_forward));

                procedure_definition predef = new procedure_definition() { proc_header = fh };
                // frninja 05/06/16 - для шаблонов с where
                predef.proc_header.where_defs = ObjectCopier.Clone(pd.proc_header.where_defs);

                UpperTo<declarations>().InsertBefore(pd, predef);

                return true;
            }

            return false;
        }