/*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, // отображение для оберток локальных переменных yield_locals_type_map_helper localTypeMapHelper) // вспомогательный узел для типов локальных переменных { 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(localsCloneMap[vds], localTypeMapHelper), null); } else { throw new Exception("Variable defenition without type and value!"); } } 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 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; 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)); } // Системные поля и методы для реализации интерфейса 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")) ); // 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) { 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), new assign("Result", "Self")), 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 - поддержка шаблонных классов var td1 = new type_declaration(className, this.CreateHelperClassDefinition(className, pd, interfaces1, cm1)); //SyntaxTreeBuilder.BuildClassDefinition(interfaces1, cm1)); var cct = new type_declarations(/*td*/); cct.Add(td1); return cct; }
public LocalVariablesTypeDetectorHelperVisior(yield_locals_type_map_helper varTypeMap) { this.VarTypeMap = varTypeMap; }
/// <summary> /// Обработка локальных переменных метода и их типов для корректного захвата /// </summary> /// <param className="pd">Объявление метода</param> /// <returns>Коллекция посещенных локальных переменных</returns> private void CreateLocalVariablesTypeProxies(procedure_definition pd, out IEnumerable<var_def_statement> localsClonesCollection, out yield_locals_type_map_helper localsTypeMapHelper) { // Выполняем определение типов локальных переменных с автовыводом типов // Клонируем исходный метод для вставки оберток-хелперов для локальных переменных и дальнейшей обработки на семантике var pdCloned = ObjectCopier.Clone(pd); // Заменяем локальные переменные с неизвестным типом на обертки-хелперы (откладываем до семантики) localsTypeMapHelper = new yield_locals_type_map_helper(); LocalVariablesTypeDetectorHelperVisior localsTypeDetectorHelperVisitor = new LocalVariablesTypeDetectorHelperVisior(localsTypeMapHelper); 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); // = new method_name("<yield_helper_locals_type_detector>" + pd.proc_header.className.meth_name.className); if (IsClassMethod(pd)) { var cd = UpperTo<class_definition>(); if (cd != null) { // Метод класса описан в классе var classMembers = UpperTo<class_members>(); classMembers.Add(pdCloned); } 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(pdCloned.proc_header); helperPredefHeader.name.class_name = null; classMembers.First().members.Insert(0, helperPredefHeader); // Вставляем тело метода-хелпера UpperTo<declarations>().InsertBefore(pd, pdCloned); } } else { UpperTo<declarations>().InsertBefore(pd, pdCloned); } }