// Лучше запретить 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); }
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; }