From 6de1848ec9610a77d1df6740aebe03797903a419 Mon Sep 17 00:00:00 2001 From: Kalsash <75901974+Kalsash@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:14:38 +0300 Subject: [PATCH] Async await fix (#3146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Добавил комментарии для async/await * source_context fix * ReplaceVarNames fix * Parametrs fix * async_defs fix --------- Co-authored-by: Aleksandr Kalinin --- SyntaxVisitors/Async/AsyncBuilder.cs | 96 +- SyntaxVisitors/Async/AsyncVisitor.cs | 72 +- SyntaxVisitors/Async/AwaitBuilder.cs | 1106 ++++++++--------- SyntaxVisitors/Async/MainVisitor.cs | 12 +- .../Async/ReplaceVarNamesVisitor.cs | 11 - SyntaxVisitors/Async/VarsHelper.cs | 35 +- TestSuite/CompilationSamples/ABCObjects.pas | 1 - TestSuite/CompilationSamples/CRT.pas | 1 - TestSuite/CompilationSamples/GraphABC.pas | 1 - TestSuite/CompilationSamples/PABCSystem.pas | 2 - TestSuite/exe/eto.exe.config | 11 + 11 files changed, 674 insertions(+), 674 deletions(-) create mode 100644 TestSuite/exe/eto.exe.config diff --git a/SyntaxVisitors/Async/AsyncBuilder.cs b/SyntaxVisitors/Async/AsyncBuilder.cs index 663e66a31..90178d4e7 100644 --- a/SyntaxVisitors/Async/AsyncBuilder.cs +++ b/SyntaxVisitors/Async/AsyncBuilder.cs @@ -1,29 +1,26 @@ using PascalABCCompiler.SyntaxTree; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SyntaxVisitors.Async { + // Билдер для построения StateMachine для каждого асинхронного метода internal class AsyncBuilder { // корень дерева private program_module program_Module { get; set; } + // нужен для перестановки defs, содержащихся в блоке program block + public List declarationsList = new List(); + // список всех асинхронных методов + public List pdList = new List(); - public List declarations = new List(); - - public List pdList = new List(); - - public HashSet VarsList = new HashSet(); - + // Словарик переменных, которые нужно будет переименовать public Dictionary RepVarsDict = new Dictionary(); - int k = 0; + int LabelNameCounter = 0; private int StateCounter = 1; - private declarations Decls = new declarations(); + // копирует блоки построенной StateMachine и передает их в declarationsList + private declarations Decls = new declarations(); public AsyncBuilder(program_module program_Module) { @@ -82,10 +79,6 @@ namespace SyntaxVisitors.Async var cd = new class_definition(ntr, classbodylist, defs.source_context); var td = new type_declaration(new ident("StateMachine"), cd, program_Module.source_context); - //block bl = listNodes.FindLast(x => x is block) as block; - //var ld = new label_definitions("tbuilder"); - //bl.defs.Add(ld); - var pd = new procedure_definition(); pd.proc_header = ph2; var a = new assign(new ident("tbuilder"), new dot_node(new ident("AsyncVoidMethodBuilder"), new ident("Create")), Operators.Assignment, defs.source_context); @@ -125,10 +118,6 @@ namespace SyntaxVisitors.Async Decls.Add(new type_declarations(td, defs.source_context), defs.source_context); Decls.Add(pd, defs.source_context); Decls.Add(pd2, defs.source_context); - - //program_Module.program_block.defs.AddFirst(pd2); - //program_Module.program_block.defs.AddFirst(pd); - //program_Module.program_block.defs.AddFirst(td); } @@ -139,7 +128,6 @@ namespace SyntaxVisitors.Async BuildStateMachine(); var name = NewStateMachine(); - //async_pm.program_block.defs var t_name = Decls.list[0] as type_declarations; t_name.types_decl[0].type_name = name; @@ -182,16 +170,16 @@ namespace SyntaxVisitors.Async dc.Add(Decls.list[2], defs.source_context); dc.Add(p, defs.source_context); - declarations.Add(dc); + declarationsList.Add(dc); Decls.list.Clear(); } - public void ParseStateMachines() + + // Для каждого асинхронного метода вызываем ParseStateMachine + public void ParseStateMachines() { - //var async_pm = async_root as program_module; var defs = program_Module.program_block.defs; - //pdList.Reverse(); var t = new List(); foreach (var item in pdList) { @@ -204,16 +192,16 @@ namespace SyntaxVisitors.Async { ParseStateMachine(pd); } - declarations.Reverse(); + declarationsList.Reverse(); - foreach (var item in declarations) + foreach (var item in declarationsList) { defs.AddFirst(item.list); } } - + // Переставляем асинхронные методы в нужном порядке public void SortBlocks() { var defs = program_Module.program_block.defs; @@ -266,7 +254,8 @@ namespace SyntaxVisitors.Async { pdList.Add(p); } - public void ChangeBodies() + // Для каждого асинхронного метода вызываем ChangeBody + public void ChangeBodies() { StateCounter = 1; pdList.Reverse(); @@ -282,14 +271,6 @@ namespace SyntaxVisitors.Async { s = s.Substring(s.LastIndexOf('.') + 1); } - - - // AddError нужно вместо SyntaxVisitorError - //if (s.StartsWith("Void") || s.StartsWith("Task")) - //{ - // //BuilderType = "Async" + s + "MethodBuilder"; - //} - //else if (!s.Contains("Task")) throw new SyntaxVisitorError("Возвращаемым типом асинхронного метода должен быть void, Task, Task или аналогичный тип, IAsyncEnumerable или IAsyncEnumerator", item.proc_header.source_context); @@ -306,8 +287,8 @@ namespace SyntaxVisitors.Async } public string newLabelName(string old) { - k++; - return "@awvar@_" + k.ToString() + "_" + old; + LabelNameCounter++; + return "@awvar@_" + LabelNameCounter.ToString() + "_" + old; } // Изменяем тело асинхронной функции, добавляя AsyncBuilder для запуска StateMachine @@ -315,6 +296,7 @@ namespace SyntaxVisitors.Async { var state = "@awst@_"; var block = pd.proc_body as block; + if (pd.proc_header.IsAsync == false) { return; @@ -340,9 +322,14 @@ namespace SyntaxVisitors.Async { var nv = newLabelName(id.name); RepVarsDict.Add(id.name, nv); - //id.name = nv; parsList.Add(new assign(new dot_node(i, id), id, Operators.Assignment), block.source_context); } + else + { + var nv = newLabelName(id.name); + RepVarsDict[id.name] = nv; + parsList.Add(new assign(new dot_node(i, id), id, Operators.Assignment), block.source_context); + } } } } @@ -375,9 +362,32 @@ namespace SyntaxVisitors.Async m.dereferencing_value = new dot_node(new dot_node(i, new ident("tbuilder", block.source_context)), new ident("Start", block.source_context), block.source_context); var p = new procedure_call(m, block.source_context);//st.tbuilder.Start(st); - - - var stl = new statement_list((pd.proc_body as block).program_code, st, a, parsList, a2); + var temp_def = new declarations(); + var defsCount = 0; + if (block.defs != null) + { + foreach (var dl in block.defs.list) + { + if (dl is variable_definitions) + { + defsCount++; + var ddl = dl as variable_definitions; + foreach (var item in ddl.list) + { + (pd.proc_body as block).program_code.AddFirst(new var_statement(item)); + } + } + else + temp_def.Add(dl); + } + } + + if (defsCount > 0) + { + block.defs = temp_def; + } + var stl = new statement_list((pd.proc_body as block).program_code, st, a, parsList, a2); + var class_name = pd.proc_header.name.class_name; if (class_name != null) diff --git a/SyntaxVisitors/Async/AsyncVisitor.cs b/SyntaxVisitors/Async/AsyncVisitor.cs index 1aa1382be..f39de750b 100644 --- a/SyntaxVisitors/Async/AsyncVisitor.cs +++ b/SyntaxVisitors/Async/AsyncVisitor.cs @@ -1,18 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using PascalABCCompiler.Errors; -using PascalABCCompiler; +using System.Collections.Generic; using PascalABCCompiler.SyntaxTree; using SyntaxVisitors.Async; -using PascalABCCompiler.Parsers; -using PascalABCCompiler.ParserTools; -using PascalABCCompiler.SyntaxTreeConverters; -using System.IO; -using System.Collections; namespace SyntaxVisitors { @@ -20,10 +8,14 @@ namespace SyntaxVisitors { private program_module program_Module { get; set; } + // текущий асинхронный метод, для которого будет построена StateMachine private procedure_definition proc_def { get; set; } - + + // список всех асинхронных методов private List proc_def_List = new List(); + // Тип билдера, который нужно менять в зависимости от возвращаемого + // типа асинхронного типа private string BuilderType = "AsyncVoidMethodBuilder"; private int AwaiterCounter = 1; @@ -35,23 +27,25 @@ namespace SyntaxVisitors private bool IsFirstAwait = true; private bool IsFirstAsync = true; - - private int ChangeBuilderCounter = 0; + + // Нужен, чтобы понимать с какой машиной + // состояний мы сейчас работаем + private int StateMachineNumber = 0; public static AsyncVisitor New { - get { return new AsyncVisitor(); } } public override void visit(procedure_definition pd) { - if (pd.proc_header.IsAsync) + // Собираем все асинхронные методы в proc_def_List + if (pd.proc_header.IsAsync) { - MainVisitor.flag = false; + MainVisitor.HasAwait = false; MainVisitor.Accept(pd); - if (!MainVisitor.flag) + if (!MainVisitor.HasAwait) { var b = pd.proc_body as block; if (b != null) @@ -77,7 +71,6 @@ namespace SyntaxVisitors } LoweringAsyncVisitor.Accept(pd); AsyncBuilder.GetMethods(pd); - // DefaultVisit(pd); } else { @@ -88,15 +81,16 @@ namespace SyntaxVisitors { if (procedure_code.list[i] is await_node_statement) { - throw new SyntaxVisitorError("Ключевое слово 'await' может быть использовано только в асинхронных методах ", procedure_code.list[i].source_context); + throw new SyntaxVisitorError("Ключевое слово 'await' может быть использовано " + + "только в асинхронных методах ", procedure_code.list[i].source_context); } if (procedure_code.list[i] is var_statement) { var pp = procedure_code.list[i] as var_statement; if (pp.var_def.inital_value is await_node) { - // AddError нужно вместо SyntaxVisitorError - throw new SyntaxVisitorError("Ключевое слово 'await' может быть использовано только в асинхронных методах ", pp.var_def.inital_value.source_context); + throw new SyntaxVisitorError("Ключевое слово 'await' может быть использовано " + + "только в асинхронных методах ", pp.var_def.inital_value.source_context); } } } @@ -117,29 +111,31 @@ namespace SyntaxVisitors AwaitBuilder = new AwaitBuilder(program_Module, proc_def); AwaitBuilder.VarsHelper.RepVarsDict = AsyncBuilder.RepVarsDict; AwaitBuilder.GetCode(); - AwaitBuilder.AddAwaiter("TaskAwaiter", true, a.ex, ChangeBuilderCounter); - AwaitBuilder.ChangeBuilder(BuilderType, ChangeBuilderCounter); + AwaitBuilder.AddAwaiter(true, a.ex, StateMachineNumber); + AwaitBuilder.ChangeBuilder(BuilderType, StateMachineNumber); } else { - AwaitBuilder.ChangeBuilder(BuilderType, ChangeBuilderCounter); - AwaitBuilder.AddAwaiter("TaskAwaiter", false, a.ex, ChangeBuilderCounter); + AwaitBuilder.ChangeBuilder(BuilderType, StateMachineNumber); + AwaitBuilder.AddAwaiter(false, a.ex, StateMachineNumber); } if (AwaitBuilder.AwaiterCounter == AwaiterCounter - 1) { - AwaitBuilder.GenAwait(ChangeBuilderCounter + 2, a.ex); + AwaitBuilder.GenAwait(StateMachineNumber + 2); AwaitBuilder.DeleteBody(); } } public void GenMain(program_module pm) { - if (MainVisitor.flag) + if (MainVisitor.HasAwait) { var d = pm.program_block.defs; var p = new procedure_definition(); - p.proc_header = new function_header(new template_type_reference(new named_type_reference(new ident("Task", d.source_context), d.source_context), - new template_param_list(new named_type_reference(new ident("integer", d.source_context), d.source_context), d.source_context), d.source_context), d.source_context); + p.proc_header = new function_header(new template_type_reference(new named_type_reference(new ident("Task", + d.source_context), d.source_context), + new template_param_list(new named_type_reference(new ident("integer", d.source_context), + d.source_context), d.source_context), d.source_context), d.source_context); p.proc_header.name = new method_name(); p.proc_header.name.meth_name = new ident("@AsyncMain", d.source_context); p.proc_header.IsAsync = true; @@ -151,7 +147,6 @@ namespace SyntaxVisitors foreach (var item in pm.program_block.program_code.list) { b.program_code.list.Add(item); - } p.proc_body = b; pm.program_block.program_code.list.Clear(); @@ -159,8 +154,10 @@ namespace SyntaxVisitors var mc = new method_call(); mc.dereferencing_value = new ident("@AsyncMain"); mc.source_context = d.source_context; - var vst = new var_statement(new var_def_statement(new ident("@aw_main", d.source_context), mc, d.source_context), d.source_context); - var pc = new procedure_call(new dot_node(new dot_node(new ident("@aw_main", d.source_context), new ident("GetAwaiter")), new ident("GetResult"), d.source_context), d.source_context); + var vst = new var_statement(new var_def_statement(new ident("@aw_main", + d.source_context), mc, d.source_context), d.source_context); + var pc = new procedure_call(new dot_node(new dot_node(new ident("@aw_main", d.source_context), + new ident("GetAwaiter")), new ident("GetResult"), d.source_context), d.source_context); pm.program_block.program_code.list.Add(vst); pm.program_block.program_code.list.Add(pc); @@ -169,11 +166,10 @@ namespace SyntaxVisitors public override void visit(program_module pm) { program_Module = pm; - MainVisitor.flag = false; + MainVisitor.HasAwait = false; MainVisitor.Accept(pm.program_block.program_code); GenMain(pm); - DefaultVisit(pm); if (proc_def_List.Count > 0) { @@ -211,7 +207,7 @@ namespace SyntaxVisitors } DefaultVisit(p); - ChangeBuilderCounter += 4; + StateMachineNumber += 4; } AsyncBuilder.SortBlocks(); diff --git a/SyntaxVisitors/Async/AwaitBuilder.cs b/SyntaxVisitors/Async/AwaitBuilder.cs index 21c0e2177..5084c753c 100644 --- a/SyntaxVisitors/Async/AwaitBuilder.cs +++ b/SyntaxVisitors/Async/AwaitBuilder.cs @@ -1,224 +1,218 @@ using PascalABCCompiler.SyntaxTree; -using QUT.Gppg; -using SyntaxVisitors.SugarVisitors; -using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; + namespace SyntaxVisitors.Async { - internal class AwaitBuilder - { - // корень дерева - private program_module program_Module { get; set; } + internal class AwaitBuilder + { + // корень дерева + private program_module program_Module { get; set; } - // тело асинхронной функции - public procedure_definition proc_def { get; set; } + // текущий асинхронный метод + public procedure_definition proc_def { get; set; } - private Dictionary Awaiters = new Dictionary(); - int lbnum = 0; + int lbnum = 0; - private statement_list code_list = new statement_list(); + // тело асинхронного метода + private statement_list code_list = new statement_list(); - public expression_list TaskList = new expression_list(); + // Список Taskов, принадлежащих к какому-нибудь await + public expression_list TaskList = new expression_list(); - public int AwaiterCounter = 0; + // Счетчик awaitов + public int AwaiterCounter = 0; - public int NewAwaiterCounter = 1; - public int TempTaskCounter = 1; - - public int GenAwCounter = 2; - - public VarsHelper VarsHelper; - - public string ResultType = ""; - public expression ResultVal = new expression(); + // Счетчик временных переменных для Task + public int TempTaskCounter = 1; + public VarsHelper VarsHelper; + // Возвращаемый тип асинхронного метода + public string ResultType = ""; + // Результат работы асинхронного метода + public expression ResultVal = new expression(); //ctor public AwaitBuilder(program_module pm, procedure_definition pd) - { - program_Module = pm; - proc_def = pd; - VarsHelper = new VarsHelper(); + { + program_Module = pm; + proc_def = pd; + VarsHelper = new VarsHelper(); - } + } + public int NewAwaiterCounter = 1; + public string NewAwaiter() + { + return "@aw@_" + NewAwaiterCounter++; + } + public string NewTempTask() + { + return "@tt@_" + TempTaskCounter++; + } + // для каждого await добавляем awaiter + public void AddAwaiter(bool IsFirstTime, expression ex, int c) + { - public string NewAwaiter() - { - return "@aw@_" + NewAwaiterCounter++; - } - public string NewTempTask() - { - return "@tt@_" + TempTaskCounter++; - } - // для каждого await добавляем awaiter - public void AddAwaiter(string a_type, bool IsFirstTime, expression ex, int c) - { + var a_name = NewAwaiter(); + TaskList.AddFirst(ex); + var tdecl = program_Module.program_block.defs.list[c] as type_declarations; + var tdef = tdecl.types_decl[0]; + var cd = tdef.type_def as class_definition; + var bd = cd.body; + var tn = NewTempTask(); + var vds = new var_def_statement(new ident(a_name, bd.source_context), new named_type_reference(new ident("string", bd.source_context)), bd.source_context); + var class_name = proc_def.proc_header.name.class_name; + if (IsFirstTime) + { + List members = new List { vds }; + if (class_name != null) + { + members.Add(new var_statement(new var_def_statement(new ident("@awclass", bd.source_context), new named_type_reference(class_name), bd.source_context), bd.source_context)); - var a_name = NewAwaiter(); - Awaiters.Add(a_name, a_type); - TaskList.AddFirst(ex); - var tdecl = program_Module.program_block.defs.list[c] as type_declarations; - var tdef = tdecl.types_decl[0]; - var cd = tdef.type_def as class_definition; - var bd = cd.body; - var tn = NewTempTask(); - var vds = new var_def_statement(new ident(a_name,bd.source_context), new named_type_reference(new ident("string",bd.source_context)),bd.source_context); - var class_name = proc_def.proc_header.name.class_name; - if (IsFirstTime) - { - List members = new List { vds }; - if (class_name != null) - { - members.Add(new var_statement(new var_def_statement(new ident("@awclass",bd.source_context), new named_type_reference(class_name),bd.source_context),bd.source_context)); + } + var cm = new class_members(members, new access_modifer_node(access_modifer.private_modifer), bd.source_context); + bd.AddFirst(cm); - } - var cm = new class_members(members, new access_modifer_node(access_modifer.private_modifer), bd.source_context); - bd.AddFirst(cm); + } + else + { + var cm2 = bd.class_def_blocks[0]; + cm2.members.Add(vds); + } + } + // Меняем тип AsyncBuilder + public void ChangeBuilder(string Type, int ChangeBuilderCounter) + { + var tdecl = program_Module.program_block.defs.list[ChangeBuilderCounter] as type_declarations; + var tdef = tdecl.types_decl[0]; + var cd = tdef.type_def as class_definition; + var bd = cd.body; + var cm = bd[1] as class_members; + var vdf = cm[2] as var_def_statement; + var pd = program_Module.program_block.defs.list[ChangeBuilderCounter + 1] as procedure_definition; + var pb = pd.proc_body as block; + var st = pb.program_code; + var a = st.list[0] as assign; + var mc = new method_call(); + mc.source_context = st.source_context; - } - else - { - var cm2 = bd.class_def_blocks[0]; - cm2.members.Add(vds); - } - } - // Меняем тип AsyncBuilder - public void ChangeBuilder(string Type, int ChangeBuilderCounter) - { - var tdecl = program_Module.program_block.defs.list[ChangeBuilderCounter] as type_declarations; - var tdef = tdecl.types_decl[0]; - var cd = tdef.type_def as class_definition; - var bd = cd.body; - var cm = bd[1] as class_members; - var vdf = cm[2] as var_def_statement; - var pd = program_Module.program_block.defs.list[ChangeBuilderCounter + 1] as procedure_definition; - var pb = pd.proc_body as block; - var st = pb.program_code; - var a = st.list[0] as assign; - var mc = new method_call(); - mc.source_context = st.source_context; + if (Type.StartsWith("AsyncVoidMethodBuilder") || Type == "AsyncTaskMethodBuilder") + { - if (Type.StartsWith("AsyncVoidMethodBuilder") || Type == "AsyncTaskMethodBuilder") - { + vdf.vars_type = new named_type_reference(Type, vdf.source_context); + mc.dereferencing_value = new dot_node(new ident(Type, vdf.source_context), new ident("Create")); + } + else + { + var tt = Type.Substring(23); + tt = tt.Replace(">", ""); + ResultType = tt; + var tpl = new template_param_list(); + tpl.source_context = vdf.source_context; + tpl.params_list.Add(new named_type_reference(new ident(tt, vdf.source_context))); + vdf.vars_type = new template_type_reference("AsyncTaskMethodBuilder", tpl); + mc.dereferencing_value = new dot_node(new ident_with_templateparams(new ident("AsyncTaskMethodBuilder", vdf.source_context), + tpl, vdf.source_context), new ident("Create", vdf.source_context), vdf.source_context); + } - vdf.vars_type = new named_type_reference(Type, vdf.source_context); - mc.dereferencing_value = new dot_node(new ident(Type, vdf.source_context), new ident("Create")); - } - else - { - var tt = Type.Substring(23); - tt = tt.Replace(">", ""); - ResultType = tt; - var tpl = new template_param_list(); - tpl.source_context = vdf.source_context; - tpl.params_list.Add(new named_type_reference(new ident(tt, vdf.source_context))); - vdf.vars_type = new template_type_reference("AsyncTaskMethodBuilder", tpl); - mc.dereferencing_value = new dot_node(new ident_with_templateparams(new ident("AsyncTaskMethodBuilder", vdf.source_context), - tpl, vdf.source_context), new ident("Create", vdf.source_context),vdf.source_context); - } + a.from = mc; + } - a.from = mc; - } + public string newLabelName() + { + lbnum++; + return "@awlb@_" + lbnum.ToString(); + } - public string newLabelName() - { - lbnum++; - return "@awlb@_" + lbnum.ToString(); - } - public void GetCode() - { - var class_name = proc_def.proc_header.name.class_name; - if (class_name != null) - { - foreach (var item in program_Module.program_block.defs.list) - { - if (item is type_declarations) - { - var tds = item as type_declarations; - foreach (var tdef in tds.types_decl) - { - if (tdef.type_name.name == class_name.name) - { - var cd = tdef.type_def as class_definition; - var bd = cd.body; - for (int i = 0; i < bd.Count; i++) - { - if (bd[i] is class_members) - { - var cm = bd[i] as class_members; - foreach (var mem in cm.members) - { - if (mem is var_def_statement) - { - var vm = mem as var_def_statement; - if (vm.var_attr != definition_attribute.Static) - { - foreach (var vms in vm.vars.list) - { - VarsHelper.ClassIdentSet.Add(vms.name); - } - } - else - { - foreach (var vms in vm.vars.list) - { - VarsHelper.ClassStaticSet.Add(vms.name); - } + // Обрабатываем тело асинхронного метода + public void GetCode() + { + var class_name = proc_def.proc_header.name.class_name; + if (class_name != null) + { + foreach (var item in program_Module.program_block.defs.list) + { + if (item is type_declarations) + { + var tds = item as type_declarations; + foreach (var tdef in tds.types_decl) + { + if (tdef.type_name.name == class_name.name) + { + var cd = tdef.type_def as class_definition; + var bd = cd.body; + for (int i = 0; i < bd.Count; i++) + { + if (bd[i] is class_members) + { + var cm = bd[i] as class_members; + foreach (var mem in cm.members) + { + if (mem is var_def_statement) + { + var vm = mem as var_def_statement; + if (vm.var_attr != definition_attribute.Static) + { + foreach (var vms in vm.vars.list) + { + VarsHelper.ClassIdentSet.Add(vms.name); + } + } + else + { + foreach (var vms in vm.vars.list) + { + VarsHelper.ClassStaticSet.Add(vms.name); + } - } + } - } - } - } + } + } + } - } - } - } - } - } - } + } + } + } + } + } + } - var b = proc_def.proc_header is function_header; - var procedure_code = (proc_def.proc_body as block).program_code.list[0] as statement_list; - var temp_list = new statement_list(); + var b = proc_def.proc_header is function_header; + var procedure_code = (proc_def.proc_body as block).program_code.list[0] as statement_list; + var temp_list = new statement_list(); var r_list = new statement_list(); if (proc_def.proc_header.parameters != null) - { - var par = proc_def.proc_header.parameters; - foreach (var p in par.params_list) - { - if (p.param_kind is parametr_kind.var_parametr) - { - throw new SyntaxVisitorError("var-параметры нельзя использовать в асинхронных методах ", p.source_context); - } - foreach (var id in p.idents.list) - { - var v = new var_statement(new var_def_statement(id, p.vars_type, p.source_context), p.source_context); - VarsHelper.VarsList.Add(v); - VarsHelper.Parametrs.Add(id.name); - //VarsHelper.TasksHash.Add(v); - } - } - } + { + var par = proc_def.proc_header.parameters; + foreach (var p in par.params_list) + { + if (p.param_kind is parametr_kind.var_parametr) + { + throw new SyntaxVisitorError("var-параметры нельзя использовать в асинхронных методах ", p.source_context); + } + foreach (var id in p.idents.list) + { + var v = new var_statement(new var_def_statement(id, p.vars_type, p.source_context), p.source_context); + VarsHelper.VarsList.Add(v); + VarsHelper.Parametrs.Add(id.name); + } + } + } - var await_counter = 0; - bool flag = true; - for (int i = 0; i < procedure_code.list.Count; i++) - { - if (procedure_code.list[i] is await_node_statement) - { - var pp = procedure_code.list[i] as await_node_statement; + var await_counter = 0; + bool flag = true; + for (int i = 0; i < procedure_code.list.Count; i++) + { + if (procedure_code.list[i] is await_node_statement) + { + var pp = procedure_code.list[i] as await_node_statement; await_counter++; flag = false; var a = pp.aw; @@ -233,343 +227,345 @@ namespace SyntaxVisitors.Async } } - if (procedure_code.list[i] is var_statement) - { - var pp = procedure_code.list[i] as var_statement; - if (pp.var_def.inital_value is await_node) - { + if (procedure_code.list[i] is var_statement) + { + var pp = procedure_code.list[i] as var_statement; + if (pp.var_def.inital_value is await_node) + { var a = pp.var_def.inital_value as await_node; - VarsHelper.VarsList.Add(pp); - foreach (var v in pp.var_def.vars.list) - { - var mmc = new method_call(); - mmc.source_context = v.source_context; + VarsHelper.VarsList.Add(pp); + foreach (var v in pp.var_def.vars.list) + { + var mmc = new method_call(); + mmc.source_context = v.source_context; if (a.ex is method_call) - mmc.dereferencing_value = new dot_node(new dot_node(a.ex as method_call, new ident("GetAwaiter", v.source_context)), - new ident("GetResult", v.source_context), v.source_context); - else - mmc.dereferencing_value = new dot_node(new dot_node(new ident(a.ex.ToString(), v.source_context), - new ident("GetAwaiter"), v.source_context), new ident("GetResult", v.source_context), v.source_context); + mmc.dereferencing_value = new dot_node(new dot_node(a.ex as method_call, new ident("GetAwaiter", v.source_context)), + new ident("GetResult"), v.source_context); + else + mmc.dereferencing_value = new dot_node(new dot_node(new ident(a.ex.ToString(), v.source_context), + new ident("GetAwaiter"), v.source_context), new ident("GetResult"), v.source_context); var ass = new assign(v, mmc, Operators.Assignment, v.source_context); - ass.first_assignment_defines_type = true; - //temp_list.Add(ass); - r_list.Add(ass); - } - await_counter++; - flag = false; - - if (a.ex is ident) - { - VarsHelper.ExprHash.Add(a.ex.ToString()); - if (!VarsHelper.TaskIdents.ContainsKey(a.ex.ToString())) - { - VarsHelper.TaskIdents.Add(a.ex.ToString(), await_counter.ToString()); - } + ass.first_assignment_defines_type = true; + //temp_list.Add(ass); + r_list.Add(ass); + } + await_counter++; + flag = false; - } - } - else - { - VarsHelper.VarsList.Add(pp); - if (pp.var_def.inital_value != null) - { - foreach (var item in pp.var_def.vars.list) - { - var ass = new assign(item, pp.var_def.inital_value, Operators.Assignment,item.source_context); - ass.first_assignment_defines_type = true; - temp_list.Add(ass); - } - } - continue; - } - } + if (a.ex is ident) + { + VarsHelper.ExprHash.Add(a.ex.ToString()); + if (!VarsHelper.TaskIdents.ContainsKey(a.ex.ToString())) + { + VarsHelper.TaskIdents.Add(a.ex.ToString(), await_counter.ToString()); + } - if (procedure_code.list[i] is assign && b) - { - var pa = procedure_code.list[i] as assign; - if (pa.to is ident) - { - var pat = pa.to as ident; - if (pat.name == "Result") - { - ResultVal = pa.from; - //continue; - } - } - } - if (flag) - temp_list.Add(procedure_code.list[i]); - else - { - flag = true; - code_list.Add(temp_list); - temp_list = r_list; + } + } + else + { + VarsHelper.VarsList.Add(pp); + if (pp.var_def.inital_value != null) + { + foreach (var item in pp.var_def.vars.list) + { + var ass = new assign(item, pp.var_def.inital_value, Operators.Assignment, item.source_context); + ass.first_assignment_defines_type = true; + temp_list.Add(ass); + } + } + continue; + } + } + + if (procedure_code.list[i] is assign && b) + { + var pa = procedure_code.list[i] as assign; + if (pa.to is ident) + { + var pat = pa.to as ident; + if (pat.name == "Result") + { + ResultVal = pa.from; + } + } + } + if (flag) + temp_list.Add(procedure_code.list[i]); + else + { + flag = true; + code_list.Add(temp_list); + temp_list = r_list; r_list = new statement_list(); } - } - VarsHelper.MarkVars(); - AwaiterCounter = await_counter; - code_list.Add(temp_list); - code_list.source_context = procedure_code.source_context; + } + VarsHelper.MarkVars(); + AwaiterCounter = await_counter; + code_list.Add(temp_list); + code_list.source_context = procedure_code.source_context; - } + } - // Изменяем метод MoveNext в зависимости от количества await - public void GenAwait(int c, expression exx) - { - var pd = program_Module.program_block.defs.list[c] as procedure_definition; - var bl = pd.proc_body as block; + // Изменяем метод MoveNext в зависимости от количества await + public void GenAwait(int c) + { + var pd = program_Module.program_block.defs.list[c] as procedure_definition; + var bl = pd.proc_body as block; - var class_name = proc_def.proc_header.name.class_name; - var awaiter = "@aw@_"; - var aw_temp = "@awtemp@_"; - var extp = "awextemp@_"; + var class_name = proc_def.proc_header.name.class_name; + var awaiter = "@aw@_"; + var aw_temp = "@awtemp@_"; + var extp = "awextemp@_"; - // используется если await внутри цикла - if ((proc_def.proc_body as block).defs != null) - { + // используется если await внутри цикла + if ((proc_def.proc_body as block).defs != null) + { var loopLabelsList = (proc_def.proc_body as block).defs.list; - if (loopLabelsList != null) - foreach (var b in loopLabelsList) + if (loopLabelsList != null) + foreach (var b in loopLabelsList) + { + bl.defs.Add(b); + } + } + + var lb1 = newLabelName(); + bl.defs.Add(new label_definitions(new ident(lb1, bl.source_context)), bl.source_context); + var ts = bl.program_code.list[0] as try_stmt; + var g1 = new goto_statement(lb1, ts.source_context); + var ls = new labeled_statement(lb1); + ls.source_context = ts.source_context; + (code_list.list[1] as statement_list).source_context = ts.source_context; + + ts.stmt_list.Remove(ts.stmt_list.Last()); + + + // если метод возвращает значение + if (ResultType != "") + { + var r_pc = new procedure_call(new method_call(new dot_node(new ident("tbuilder", ts.source_context), + new ident("SetResult", ts.source_context)), + new expression_list(new ident("@aw_res", ts.source_context), ts.source_context), ts.source_context), ts.source_context); + bl.program_code.list[2] = r_pc; + } + + ////// if (state == 1) + + var ifnode = new if_node(); + ifnode.source_context = ts.source_context; + ifnode.condition = new bin_expr(new dot_node(new ident("self"), new ident("state")), new int32_const(1), Operators.Equal, ts.source_context); + + var extemp = new var_statement(new var_def_statement(new ident(extp, TaskList[0].source_context), + TaskList[0] as expression, TaskList[0].source_context), TaskList[0].source_context); + (code_list.list[0] as statement_list).Add(extemp); + + var mcс = new method_call(); + mcс.dereferencing_value = new dot_node(new ident(extp, TaskList[0].source_context), new ident("GetAwaiter", TaskList[0].source_context)); + mcс.source_context = TaskList[0].source_context; + + // Убираем лишние присваивания для Task + if (VarsHelper.TaskIdents.Count != 0) + { + if (VarsHelper.TaskIdents.First().Value == "1") { - bl.defs.Add(b); + mcс.dereferencing_value = new dot_node(new ident(VarsHelper.TaskIdents.First().Key, TaskList[0].source_context), + new ident("GetAwaiter", TaskList[0].source_context), TaskList[0].source_context); + (code_list.list[0] as statement_list).Remove(extemp); } } - var lb1 = newLabelName(); - bl.defs.Add(new label_definitions(new ident(lb1,bl.source_context)),bl.source_context); - var ts = bl.program_code.list[0] as try_stmt; - var g1 = new goto_statement(lb1,ts.source_context); - var ls = new labeled_statement(lb1); - ls.source_context = ts.source_context; - (code_list.list[1] as statement_list).source_context = ts.source_context; - ts.stmt_list.Remove(ts.stmt_list.Last()); + var assign_ = new assign(new ident("@aw@_" + "1", ts.source_context), mcс, Operators.Assignment, ts.source_context); + assign_.first_assignment_defines_type = true; - // если метод возвращает значение - if (ResultType != "") - { - var r_pc = new procedure_call(new method_call(new dot_node(new ident("tbuilder",ts.source_context), - new ident("SetResult", ts.source_context)), - new expression_list(new ident("@aw_res", ts.source_context), ts.source_context), ts.source_context), ts.source_context); - bl.program_code.list[2] = r_pc; - } + var if2 = new if_node(); + if2.source_context = ts.source_context; + if2.condition = new bin_expr(new dot_node(new ident("@aw@_" + "1", ts.source_context), new ident("IsCompleted", ts.source_context), ts.source_context), + new ident("False", ts.source_context), Operators.Equal, ts.source_context); - ////// if (state == 1) + var a1 = new assign(new dot_node(new ident("self", if2.source_context), new ident("state", ts.source_context), if2.source_context), new int32_const(2, ts.source_context), Operators.Assignment, ts.source_context); - var ifnode = new if_node(); - ifnode.source_context = ts.source_context; - ifnode.condition = new bin_expr(new dot_node(new ident("self"), new ident("state")), new int32_const(1), Operators.Equal,ts.source_context); + var temp = new var_statement(new var_def_statement(new ident(aw_temp, ts.source_context), new ident("self", ts.source_context)), ts.source_context); + var dt = new dot_node(new dot_node(new ident("self", ts.source_context), new ident("tbuilder", ts.source_context)), + new ident("AwaitUnsafeOnCompleted", ts.source_context), ts.source_context); + var ex = new expression_list(new ident("@aw@_" + "1", ts.source_context), ts.source_context); + ex.Add(new ident(aw_temp)); + var mc = new method_call(dt, ex, ts.source_context); + var pc = new procedure_call(mc, ts.source_context); + var ifnode_body2 = new statement_list(a1, temp, pc, new procedure_call(new ident("exit"), ts.source_context), new empty_statement()); + ifnode_body2.left_logical_bracket = new token_info("begin"); + ifnode_body2.right_logical_bracket = new token_info("end"); + if2.then_body = ifnode_body2; + if2.then_body.source_context = ts.source_context; - var extemp = new var_statement(new var_def_statement(new ident(extp,ts.source_context), TaskList[0] as expression,ts.source_context),ts.source_context); - (code_list.list[0] as statement_list).Add(extemp); + (code_list.list[0] as statement_list).Add(assign_, ts.source_context); + (code_list.list[0] as statement_list).Add(if2, ts.source_context); + (code_list.list[0] as statement_list).Add(new empty_statement(), ts.source_context); + var ifnode_body1 = new statement_list(code_list.list[0], ts.source_context); - var mcс = new method_call(); - mcс.dereferencing_value = new dot_node(new ident(extp, ifnode.source_context), new ident("GetAwaiter",ifnode.source_context)); - mcс.source_context = ifnode.source_context; - //if (class_name is null) - //{ + ifnode_body1.Add(g1, ts.source_context); - //} - // Убираем лишние присваивания для Task - if (VarsHelper.TaskIdents.Count != 0) - { - if (VarsHelper.TaskIdents.First().Value == "1") - { - mcс.dereferencing_value = new dot_node(new ident(VarsHelper.TaskIdents.First().Key, ifnode.source_context), - new ident("GetAwaiter", ts.source_context), ifnode.source_context); - (code_list.list[0] as statement_list).Remove(extemp); - } - } + ifnode_body1.left_logical_bracket = new token_info("begin"); + ifnode_body1.right_logical_bracket = new token_info("end"); + ifnode.then_body = ifnode_body1; + ifnode.source_context = ts.source_context; + FillTypedVars(c - 2); + + ts.stmt_list.Add(ifnode, ts.source_context); + ////// if (state == 1) - var assign_ = new assign(new ident("@aw@_" + "1",ts.source_context), mcс, Operators.Assignment, ts.source_context); - assign_.first_assignment_defines_type = true; + // Добавляем метки для переходов по состояниям + var awCount = AwaiterCounter; + while (awCount > 1) + { + awCount--; + lb1 = newLabelName(); + bl.defs.Add(new label_definitions(new ident(lb1, ts.source_context)), ts.source_context); + } + lbnum = 0; + awCount = AwaiterCounter; - var if2 = new if_node(); - if2.source_context= ts.source_context; - if2.condition = new bin_expr(new dot_node(new ident("@aw@_" + "1", ts.source_context), new ident("IsCompleted", ts.source_context), ts.source_context), - new ident("False", ts.source_context), Operators.Equal, ts.source_context); + // Когда Task уже завершен + while (awCount != 0) + { + awCount--; - var a1 = new assign(new dot_node(new ident("self",if2.source_context), new ident("state", ts.source_context),if2.source_context), new int32_const(2, ts.source_context), Operators.Assignment, ts.source_context); - - var temp = new var_statement(new var_def_statement(new ident(aw_temp, ts.source_context), new ident("self", ts.source_context)), ts.source_context); - var dt = new dot_node(new dot_node(new ident("self", ts.source_context), new ident("tbuilder", ts.source_context)), - new ident("AwaitUnsafeOnCompleted", ts.source_context), ts.source_context); - var ex = new expression_list(new ident("@aw@_" + "1", ts.source_context),ts.source_context); - ex.Add(new ident(aw_temp)); - var mc = new method_call(dt, ex, ts.source_context); - var pc = new procedure_call(mc, ts.source_context); - var ifnode_body2 = new statement_list(a1, temp, pc, new procedure_call(new ident("exit"),ts.source_context), new empty_statement()); - ifnode_body2.left_logical_bracket = new token_info("begin"); - ifnode_body2.right_logical_bracket = new token_info("end"); - if2.then_body = ifnode_body2; - if2.then_body.source_context = ts.source_context; - - (code_list.list[0] as statement_list).Add(assign_,ts.source_context); - (code_list.list[0] as statement_list).Add(if2,ts.source_context); - (code_list.list[0] as statement_list).Add(new empty_statement(),ts.source_context); - var ifnode_body1 = new statement_list(code_list.list[0],ts.source_context); - - ifnode_body1.Add(g1,ts.source_context); - - ifnode_body1.left_logical_bracket = new token_info("begin"); - ifnode_body1.right_logical_bracket = new token_info("end"); - ifnode.then_body = ifnode_body1; - ifnode.source_context = ts.source_context; - FillTypedVars(c - 2); - - ts.stmt_list.Add(ifnode, ts.source_context); - ////// if (state == 1) - - - // Добавляем метки для переходов по состояниям - var awCount = AwaiterCounter; - while (awCount > 1) - { - awCount--; - lb1 = newLabelName(); - bl.defs.Add(new label_definitions(new ident(lb1, ts.source_context)), ts.source_context); - } - - lbnum = 0; - awCount = AwaiterCounter; - - // Когда Task уже завершен - while (awCount != 0) - { - awCount--; - - ///if (state == 2,3,4 ...) - var ifnode2 = new if_node(); - ifnode2.condition = new bin_expr(new dot_node(new ident("self", ts.source_context), new ident("state", ts.source_context)), - new int32_const(lbnum + 2, ts.source_context), Operators.Equal, ts.source_context); - ///state = -1; - var a5 = new assign(new dot_node(new ident("self", ts.source_context), - new ident("state", ts.source_context)), new un_expr(new int32_const(1, ts.source_context), - Operators.Minus, ts.source_context), Operators.Assignment, ts.source_context); - ///goto label; - var stlist3 = new statement_list(a5, new goto_statement(newLabelName(), ts.source_context), new empty_statement()); - stlist3.left_logical_bracket = new token_info("begin"); - stlist3.right_logical_bracket = new token_info("end"); - ifnode2.then_body = stlist3; + ///if (state == 2,3,4 ...) + var ifnode2 = new if_node(); + ifnode2.condition = new bin_expr(new dot_node(new ident("self", ts.source_context), new ident("state", ts.source_context)), + new int32_const(lbnum + 2, ts.source_context), Operators.Equal, ts.source_context); + ///state = -1; + var a5 = new assign(new dot_node(new ident("self", ts.source_context), + new ident("state", ts.source_context)), new un_expr(new int32_const(1, ts.source_context), + Operators.Minus, ts.source_context), Operators.Assignment, ts.source_context); + ///goto label; + var stlist3 = new statement_list(a5, new goto_statement(newLabelName(), ts.source_context), new empty_statement()); + stlist3.left_logical_bracket = new token_info("begin"); + stlist3.right_logical_bracket = new token_info("end"); + ifnode2.then_body = stlist3; ifnode2.then_body.source_context = ts.source_context; ifnode2.source_context = ts.source_context; ts.stmt_list.Add(ifnode2, ts.source_context); - } + } - lbnum = 1; - awCount = AwaiterCounter; - ts.stmt_list.Add(ls, ts.source_context); - var mc2 = new method_call(); - mc2.source_context = ts.source_context; + lbnum = 1; + awCount = AwaiterCounter; + ts.stmt_list.Add(ls, ts.source_context); + var mc2 = new method_call(); + mc2.source_context = ts.source_context; // начиная со второго встреченного await while (awCount > 1) - { - awCount--; - var lb2 = newLabelName(); - var g2 = new goto_statement(lb2, ts.source_context); - var ls2 = new labeled_statement(lb2); - ls2.source_context = ts.source_context; + { + awCount--; + var lb2 = newLabelName(); + var g2 = new goto_statement(lb2, ts.source_context); + var ls2 = new labeled_statement(lb2); + ls2.source_context = ts.source_context; mc2 = new method_call(); - mc2.source_context= ts.source_context; - mc2.dereferencing_value = new dot_node(new ident(awaiter + (lbnum - 1).ToString(), ts.source_context), - new ident("GetResult", ts.source_context), ts.source_context); - ts.stmt_list.Add(new procedure_call(mc2, ts.source_context), ts.source_context); - var tt = code_list.list[lbnum - 1] as statement_list; - var fg = true; - foreach (var stat in tt.list) - { - if (stat is assign && fg) - { - var asstat = stat as assign; - if (asstat.from.ToString().Contains("GetResult")) - { - asstat.from = mc2; + mc2.source_context = ts.source_context; + + mc2.dereferencing_value = new dot_node(new ident(awaiter + (lbnum - 1).ToString(), ts.source_context), + new ident("GetResult"), ts.source_context); + + + ts.stmt_list.Add(new procedure_call(mc2, ts.source_context), ts.source_context); + var tt = code_list.list[lbnum - 1] as statement_list; + var fg = true; + + + foreach (var stat in tt.list) + { + if (stat is assign && fg) + { + var asstat = stat as assign; + if (asstat.from.ToString().Contains("GetResult")) + { + asstat.from = mc2; } } - fg = false; - ts.stmt_list.Add(stat, stat.source_context); - } - - extemp = new var_statement(new var_def_statement(new ident(extp + lbnum.ToString(), ts.source_context), - TaskList[lbnum - 1] as expression, ts.source_context), ts.source_context); - extemp.source_context = ts.source_context; - ts.stmt_list.Add(extemp, ts.source_context); - var mccc = new method_call(); - mccc.dereferencing_value = new dot_node(new ident(extp + lbnum.ToString(), ts.source_context), - new ident("GetAwaiter", ts.source_context), ts.source_context); - mccc.source_context = ts.source_context; + fg = false; + ts.stmt_list.Add(stat, stat.source_context); + } + extemp = new var_statement(new var_def_statement(new ident(extp + lbnum.ToString(), TaskList[lbnum - 1].source_context), + TaskList[lbnum - 1] as expression, TaskList[lbnum - 1].source_context), TaskList[lbnum - 1].source_context); + extemp.source_context = TaskList[lbnum - 1].source_context; + ts.stmt_list.Add(extemp, TaskList[lbnum - 1].source_context); + var mccc = new method_call(); + mccc.dereferencing_value = new dot_node(new ident(extp + lbnum.ToString(), TaskList[lbnum - 1].source_context), + new ident("GetAwaiter", TaskList[lbnum - 1].source_context), TaskList[lbnum - 1].source_context); + mccc.source_context = TaskList[lbnum - 1].source_context; // Убираем лишние присваивания для Task foreach (var kv in VarsHelper.TaskIdents) - { - if (kv.Value == lbnum.ToString()) - { - mccc.dereferencing_value = new dot_node(new ident(kv.Key, ts.source_context), - new ident("GetAwaiter", ts.source_context), ts.source_context); - ts.stmt_list.Remove(extemp); - break; - } - } + { + if (kv.Value == lbnum.ToString()) + { + mccc.dereferencing_value = new dot_node(new ident(kv.Key, TaskList[lbnum - 1].source_context), + new ident("GetAwaiter", TaskList[lbnum - 1].source_context), TaskList[lbnum - 1].source_context); + ts.stmt_list.Remove(extemp); + break; + } + } - var assign22_ = new assign(new ident(awaiter + lbnum.ToString(), ts.source_context), mccc, Operators.Assignment, ts.source_context); - assign22_.source_context = ts.source_context; - assign22_.first_assignment_defines_type = true; + var assign22_ = new assign(new ident(awaiter + lbnum.ToString(), ts.source_context), mccc, Operators.Assignment, ts.source_context); + assign22_.source_context = ts.source_context; + assign22_.first_assignment_defines_type = true; - ts.stmt_list.Add(assign22_,ts.source_context); + ts.stmt_list.Add(assign22_, ts.source_context); - var if3 = new if_node(); - if3.source_context = ts.source_context; - if3.condition = new bin_expr(new dot_node(new ident(awaiter + lbnum.ToString(), ts.source_context), - new ident("IsCompleted", ts.source_context)), - new ident("False", ts.source_context), Operators.Equal, ts.source_context); + var if3 = new if_node(); + if3.source_context = ts.source_context; + if3.condition = new bin_expr(new dot_node(new ident(awaiter + lbnum.ToString(), ts.source_context), + new ident("IsCompleted", ts.source_context)), + new ident("False", ts.source_context), Operators.Equal, ts.source_context); - var a11 = new assign(new dot_node(new ident("self", ts.source_context), new ident("state", ts.source_context)), - new int32_const(lbnum + 1), Operators.Assignment, ts.source_context); - var temp2 = new var_statement(new var_def_statement - (new ident(aw_temp, ts.source_context), - new ident("self", ts.source_context), ts.source_context), ts.source_context); - var dt1 = new dot_node(new dot_node(new ident("self", ts.source_context), - new ident("tbuilder", ts.source_context), ts.source_context), - new ident("AwaitUnsafeOnCompleted", ts.source_context), ts.source_context); + var a11 = new assign(new dot_node(new ident("self", ts.source_context), new ident("state", ts.source_context)), + new int32_const(lbnum + 1), Operators.Assignment, ts.source_context); + var temp2 = new var_statement(new var_def_statement + (new ident(aw_temp, ts.source_context), + new ident("self", ts.source_context), ts.source_context), ts.source_context); + var dt1 = new dot_node(new dot_node(new ident("self", ts.source_context), + new ident("tbuilder", ts.source_context), ts.source_context), + new ident("AwaitUnsafeOnCompleted", ts.source_context), ts.source_context); - var ex1 = new expression_list(new ident(awaiter + lbnum.ToString(), ts.source_context), ts.source_context); - ex1.Add(new ident(aw_temp, ts.source_context), ts.source_context); - var mc11 = new method_call(dt1, ex1, ts.source_context); - var pc11 = new procedure_call(mc11, ts.source_context); - var stlist4 = new statement_list(a11, temp2, pc11, new procedure_call(new ident("exit")), new empty_statement()); - stlist4.source_context = ts.source_context; - stlist4.left_logical_bracket = new token_info("begin"); - stlist4.right_logical_bracket = new token_info("end"); - if3.then_body = stlist4; - ts.stmt_list.Add(if3, ts.source_context); - ts.stmt_list.Add(g2, ts.source_context); - ts.stmt_list.Add(ls2, ts.source_context); - } + var ex1 = new expression_list(new ident(awaiter + lbnum.ToString(), ts.source_context), ts.source_context); + ex1.Add(new ident(aw_temp, ts.source_context), ts.source_context); + var mc11 = new method_call(dt1, ex1, ts.source_context); + var pc11 = new procedure_call(mc11, ts.source_context); + var stlist4 = new statement_list(a11, temp2, pc11, new procedure_call(new ident("exit")), new empty_statement()); + stlist4.source_context = ts.source_context; + stlist4.left_logical_bracket = new token_info("begin"); + stlist4.right_logical_bracket = new token_info("end"); + if3.then_body = stlist4; + ts.stmt_list.Add(if3, ts.source_context); + ts.stmt_list.Add(g2, ts.source_context); + ts.stmt_list.Add(ls2, ts.source_context); + + } - // Когда await закончились и пора выводить результат - mc2 = new method_call(); - mc2.source_context = ts.source_context; - mc2.dereferencing_value = new dot_node(new ident(awaiter + lbnum.ToString(), ts.source_context), - new ident("GetResult", ts.source_context), ts.source_context); + // Когда await закончились и пора выводить результат + mc2 = new method_call(); + mc2.source_context = ts.source_context; + mc2.dereferencing_value = new dot_node(new ident(awaiter + lbnum.ToString(), ts.source_context), + new ident("GetResult"), ts.source_context); ts.stmt_list.Add(new procedure_call(mc2, ts.source_context), ts.source_context); - var tt2 = code_list.list.Last() as statement_list; + var tt2 = code_list.list.Last() as statement_list; var fg2 = true; foreach (var stat in tt2.list) { @@ -585,38 +581,36 @@ namespace SyntaxVisitors.Async fg2 = false; ts.stmt_list.Add(stat, stat.source_context); } - // ts.stmt_list.Add(code_list.list.Last(), ts.source_context); - // Переименование всех локальных переменных - foreach (var cis in VarsHelper.ClassIdentSet) - { - var replacerVis = new ReplaceVarNamesVisitor(cis, "@awclass." + cis); + // Переименование всех переменных класса, находящихся в теле асинхронного метода + foreach (var cis in VarsHelper.ClassIdentSet) + { + var replacerVis = new ReplaceVarNamesVisitor(cis, "@awclass." + cis); ts.visit(replacerVis); - if (replacerVis.counter != 0 && proc_def.proc_header.class_keyword) - { + if (replacerVis.counter != 0 && proc_def.proc_header.class_keyword) + { throw new SyntaxVisitorError("Для нестатического поля, метода или свойства требуется ссылка на объект", ts.source_context); } - - } - foreach (var cis in VarsHelper.ClassStaticSet) - { - var replacerVis = new ReplaceVarNamesVisitor(cis, class_name + "." + cis); - ts.visit(replacerVis); - } - foreach (var d in VarsHelper.RepVarsDict) - { - if (VarsHelper.Parametrs.Contains(d.Key)) - { - continue; - } - var replacerVis = new ReplaceVarNamesVisitor(d.Key, d.Value); - ts.visit(replacerVis); - } + // Переименование всех статических переменных класса, находящихся в теле асинхронного метода + foreach (var cis in VarsHelper.ClassStaticSet) + { + var replacerVis = new ReplaceVarNamesVisitor(cis, class_name + "." + cis); + ts.visit(replacerVis); + } + //foreach (var d in VarsHelper.RepVarsDict) + //{ + // if (VarsHelper.Parametrs.Contains(d.Key)) + // { + // continue; + // } + // var replacerVis = new ReplaceVarNamesVisitor(d.Key, d.Value); + // ts.visit(replacerVis); + //} var MethodsSet = new HashSet(); if (class_name != null) - { + { foreach (var dec in program_Module.program_block.defs.list) { if (dec is type_declarations) @@ -642,19 +636,19 @@ namespace SyntaxVisitors.Async { if (item is procedure_header) { - + var pph = item as procedure_header; - if (!pph.class_keyword) - { + if (!pph.class_keyword) + { MethodsSet.Add(pph.name.meth_name.name); } } if (item is function_header) { var fh = item as function_header; - if (!fh.class_keyword) + if (!fh.class_keyword) MethodsSet.Add(fh.name.meth_name.name); - + } } } @@ -668,83 +662,83 @@ namespace SyntaxVisitors.Async } } } - - foreach (var item in MethodsSet) - { - var replacerVis = new ReplaceVarNamesVisitor(item, "@awclass."+item); + + foreach (var item in MethodsSet) + { + var replacerVis = new ReplaceVarNamesVisitor(item, "@awclass." + item); ts.visit(replacerVis); } // Сохранение результата асинхронного метода if (ResultType != "") - { - if (ResultVal.Parent == null && ResultVal.Parent == null) - { - ts.stmt_list.Add(new assign(new ident("@aw_res", ts.source_context), - new default_operator(new named_type_reference(ResultType, ts.source_context), - ts.source_context), ts.source_context), ts.source_context); - } - else - { + { + if (ResultVal.Parent == null && ResultVal.Parent == null) + { + ts.stmt_list.Add(new assign(new ident("@aw_res", ts.source_context), + new default_operator(new named_type_reference(ResultType, ts.source_context), + ts.source_context), ts.source_context), ts.source_context); + } + else + { var replacerVis = new ReplaceVarNamesVisitor("Result", "@aw_res"); ts.visit(replacerVis); - //ts.stmt_list.Add(new assign(new ident("@aw_res"), ResultVal)); } - - } - } + } - public void FillTypedVars(int c) - { - var tdecl = program_Module.program_block.defs.list[c] as type_declarations; - var tdef = tdecl.types_decl[0]; - var cd = tdef.type_def as class_definition; - var bd = cd.body; - var cm = bd[1] as class_members; - if (ResultType != "") - { - var r_vds = new var_def_statement(new ident("@aw_res", cm.source_context), - new named_type_reference(new ident(ResultType, cm.source_context),cm.source_context),cm.source_context); - cm.Add(r_vds); - } - foreach (var vt in VarsHelper.TasksHash) - { - var vd = new var_def_statement(new ident_list(), new named_type_reference("string", vt.source_context)); - foreach (var w in vt.var_def.vars.list) - { - vd.vars.Add(w,w.source_context); - } - cm.members.Add(vd); - } - foreach (var v in VarsHelper.VarsList) - { - if (VarsHelper.TasksHash.Contains(v)) - { - continue; - } - if (VarsHelper.NoneTypedVarsList.Contains(v)) - { - var vv = new var_statement(); - vv.source_context = v.source_context; - vv.var_def = new var_def_statement(v.var_def.vars, - new named_type_reference(new ident("string",v.source_context),v.source_context),v.source_context); - VarsHelper.AddNewRep(vv); - cm.members.Add(vv.var_def); - continue; - } - VarsHelper.AddNewRep(v); - cm.members.Add(v.var_def); - } - } + } - // Удаляем тело асинхронной функции - public void DeleteBody() - { - var b = proc_def.proc_body as block; - var st = b.program_code; - st.list.Remove(st.list.First()); - } - } + // Объявляем локальные переменные полями класса StateMachine + public void FillTypedVars(int c) + { + var tdecl = program_Module.program_block.defs.list[c] as type_declarations; + var tdef = tdecl.types_decl[0]; + var cd = tdef.type_def as class_definition; + var bd = cd.body; + var cm = bd[1] as class_members; + if (ResultType != "") + { + var r_vds = new var_def_statement(new ident("@aw_res", cm.source_context), + new named_type_reference(new ident(ResultType, cm.source_context), cm.source_context), cm.source_context); + cm.Add(r_vds); + } + foreach (var vt in VarsHelper.TasksHash) + { + var vd = new var_def_statement(new ident_list(), new named_type_reference("string", vt.source_context)); + foreach (var w in vt.var_def.vars.list) + { + vd.vars.Add(w, w.source_context); + } + cm.members.Add(vd); + } + foreach (var v in VarsHelper.VarsList) + { + if (VarsHelper.TasksHash.Contains(v)) + { + continue; + } + if (VarsHelper.NoneTypedVarsList.Contains(v)) + { + var vv = new var_statement(); + vv.source_context = v.source_context; + vv.var_def = new var_def_statement(v.var_def.vars, + new named_type_reference(new ident("string", v.source_context), v.source_context), v.source_context); + //VarsHelper.AddNewRep(vv); + cm.members.Add(vv.var_def); + continue; + } + //VarsHelper.AddNewRep(v); + cm.members.Add(v.var_def); + } + } + + // Удаляем тело асинхронной функции + public void DeleteBody() + { + var b = proc_def.proc_body as block; + var st = b.program_code; + st.list.Remove(st.list.First()); + } + } } diff --git a/SyntaxVisitors/Async/MainVisitor.cs b/SyntaxVisitors/Async/MainVisitor.cs index 01230e1f2..37a9c7e9e 100644 --- a/SyntaxVisitors/Async/MainVisitor.cs +++ b/SyntaxVisitors/Async/MainVisitor.cs @@ -1,14 +1,12 @@ using PascalABCCompiler.SyntaxTree; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace SyntaxVisitors.Async { internal class MainVisitor :BaseChangeVisitor { - public static bool flag = false; + // Визитор, который проверяет, есть ли хоть + // один await в асинхронном методе + public static bool HasAwait = false; public static MainVisitor New { get { return new MainVisitor(); } @@ -23,11 +21,11 @@ namespace SyntaxVisitors.Async } public override void visit(await_node_statement ans) { - flag = true; + HasAwait = true; } public override void visit(await_node aw) { - flag = true; + HasAwait = true; } } } diff --git a/SyntaxVisitors/Async/ReplaceVarNamesVisitor.cs b/SyntaxVisitors/Async/ReplaceVarNamesVisitor.cs index 0fcbb62c6..4e65e79b0 100644 --- a/SyntaxVisitors/Async/ReplaceVarNamesVisitor.cs +++ b/SyntaxVisitors/Async/ReplaceVarNamesVisitor.cs @@ -1,9 +1,4 @@ using PascalABCCompiler.SyntaxTree; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SyntaxVisitors.Async { @@ -22,12 +17,6 @@ namespace SyntaxVisitors.Async public override void visit(ident id) { - //if (id.name != _oldName) - //{ - // return; - //} - //id.name = _newName; - if (id.name == _oldName) { id.name = _newName; diff --git a/SyntaxVisitors/Async/VarsHelper.cs b/SyntaxVisitors/Async/VarsHelper.cs index c503e31b9..bb45efa29 100644 --- a/SyntaxVisitors/Async/VarsHelper.cs +++ b/SyntaxVisitors/Async/VarsHelper.cs @@ -7,39 +7,46 @@ using System.Threading.Tasks; namespace SyntaxVisitors.Async { + // Класс для работы с переменными public class VarsHelper { + // Множество всех переменных, находящихся в данном асинхронном методе public HashSet VarsList = new HashSet(); + // Множество всех явно типизированных переменных public HashSet TypedVarsList = new HashSet(); + // Множество всех неявно типизированных переменных public HashSet NoneTypedVarsList = new HashSet(); - public HashSet Parametrs = new HashSet(); + // Множество всех параметров асинхронного метода + public HashSet Parametrs = new HashSet(); - public HashSet ExprHash = new HashSet(); + // Множество переменных, находящихся внутри await + public HashSet ExprHash = new HashSet(); + // Множество переменных, являющихся Task public HashSet TasksHash = new HashSet(); + // Словарик переменных, которые нужно переименовать public Dictionary RepVarsDict = new Dictionary(); + // Список переменных класса public HashSet ClassIdentSet = new HashSet(); - public HashSet ClassStaticSet = new HashSet(); + // Список статических переменных класса + public HashSet ClassStaticSet = new HashSet(); + + // Словарик переменных, являющихся Task public Dictionary TaskIdents = new Dictionary(); - int k = 0; - public VarsHelper() - { - - } - + int LabelNameCounter = 0; public string newLabelName(string old) { - k++; - return "@awvar@_" + k.ToString() +"_" + old; + LabelNameCounter++; + return "@awvar@_" + LabelNameCounter.ToString() +"_" + old; } - + // Добавляем новую переменную, которую нужно будет переименовать public void AddNewRep(var_statement var_Statement) { foreach (var v in var_Statement.var_def.vars.list) @@ -47,7 +54,6 @@ namespace SyntaxVisitors.Async { if (v.name.StartsWith("@")) { - //RepVarsDict.Add(v.name, v.name); continue; } var nv = newLabelName(v.name); @@ -56,7 +62,8 @@ namespace SyntaxVisitors.Async v.name = nv; } } - + // Помечаем какими являются переменные, чтобы знать + // что делать с ними дальше public void MarkVars() { foreach (var var in VarsList) diff --git a/TestSuite/CompilationSamples/ABCObjects.pas b/TestSuite/CompilationSamples/ABCObjects.pas index ef2d4971a..708b732b5 100644 --- a/TestSuite/CompilationSamples/ABCObjects.pas +++ b/TestSuite/CompilationSamples/ABCObjects.pas @@ -10,7 +10,6 @@ unit ABCObjects; //{$apptype windows} {$reference '%GAC%\System.Windows.Forms.dll'} {$reference '%GAC%\System.Drawing.dll'} -{$gendoc true} interface diff --git a/TestSuite/CompilationSamples/CRT.pas b/TestSuite/CompilationSamples/CRT.pas index e934f1d11..d2c161d6d 100644 --- a/TestSuite/CompilationSamples/CRT.pas +++ b/TestSuite/CompilationSamples/CRT.pas @@ -7,7 +7,6 @@ unit CRT; {$apptype console} -{$gendoc true} interface diff --git a/TestSuite/CompilationSamples/GraphABC.pas b/TestSuite/CompilationSamples/GraphABC.pas index 970f5802e..5dbbe0e22 100644 --- a/TestSuite/CompilationSamples/GraphABC.pas +++ b/TestSuite/CompilationSamples/GraphABC.pas @@ -8,7 +8,6 @@ unit GraphABC; {$apptype windows} {$reference '%GAC%\System.Windows.Forms.dll'} {$reference '%GAC%\System.Drawing.dll'} -{$gendoc true} interface diff --git a/TestSuite/CompilationSamples/PABCSystem.pas b/TestSuite/CompilationSamples/PABCSystem.pas index fbdee0e67..9b503384c 100644 --- a/TestSuite/CompilationSamples/PABCSystem.pas +++ b/TestSuite/CompilationSamples/PABCSystem.pas @@ -7,8 +7,6 @@ unit PABCSystem; {$zerobasedstrings off} -{$gendoc true} - // Default Application type {$apptype console} diff --git a/TestSuite/exe/eto.exe.config b/TestSuite/exe/eto.exe.config new file mode 100644 index 000000000..20fb4d115 --- /dev/null +++ b/TestSuite/exe/eto.exe.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file