Exemple #1
0
        public override void visit(procedure_definition pd)
        {
            hasYields = false;
            if (pd.proc_header is function_header)
            {
                mids = new FindMainIdentsVisitor();
            }

            base.visit(pd);

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

            var dld = new DeleteAllLocalDefs();          // mids.vars - все захваченные переменные

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

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

            LoweringVisitor.Accept(pd);

            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); // все удаленные описания переменных делаем описанием класса

            UpperNodeAs <declarations>().InsertBefore(pd, cct);

            mids = null; // вдруг мы выйдем из процедуры, не зайдем в другую, а там - оператор! Такого конечно не может быть
        }
        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 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; // вдруг мы выйдем из процедуры, не зайдем в другую, а там - оператор! Такого конечно не может быть
        }
        public override void visit(procedure_definition pd)
        {
            if (pd.proc_header.name.meth_name.name.StartsWith(YieldConsts.YieldHelperMethodPrefix))
                return;

            //var isExtension = IsExtensionMethod(pd);

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

            base.visit(pd);

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

            // Проверяем проблемы имен для 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);

            // Переименовываем одинаковые имена в мини-ПИ
            RenameSameBlockLocalVarsVisitor renameLocalsVisitor = new RenameSameBlockLocalVarsVisitor();
            pd.visit(renameLocalsVisitor);

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

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

            // Обработка метода для корректного захвата локальных переменных и их типов
            yield_locals_type_map_helper localsTypeMapHelper;
            IEnumerable<var_def_statement> localsClonesCollection;
            CreateLocalVariablesTypeProxies(pd, out localsClonesCollection, out localsTypeMapHelper);
            

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

            var dld = new DeleteAllLocalDefs(); // mids.vars - все захваченные переменные
            pd.visit(dld); // Удалить в локальных и блочных описаниях этой процедуры все переменные и вынести их в отдельный список 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).program_code);
            cfa.Transform();

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

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

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

            

            mids = null; // вдруг мы выйдем из процедуры, не зайдем в другую, а там - оператор! Такого конечно не может быть
        }
        public override void visit(procedure_definition pd)
        {
            hasYields = false;
            if (pd.proc_header is function_header)
                mids = new FindMainIdentsVisitor();

            base.visit(pd);

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

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

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

            LoweringVisitor.Accept(pd);

            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); // все удаленные описания переменных делаем описанием класса

            UpperNodeAs<declarations>().InsertBefore(pd, cct);

            mids = null; // вдруг мы выйдем из процедуры, не зайдем в другую, а там - оператор! Такого конечно не может быть
        }