2024-06-12 16:14:38 +03:00
|
|
|
|
using System.Collections.Generic;
|
2024-06-03 17:39:57 +03:00
|
|
|
|
using PascalABCCompiler.SyntaxTree;
|
|
|
|
|
|
using SyntaxVisitors.Async;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SyntaxVisitors
|
|
|
|
|
|
{
|
2024-06-24 09:40:54 +03:00
|
|
|
|
public class AsyncVisitor : BaseChangeVisitor
|
|
|
|
|
|
{
|
|
|
|
|
|
private program_module program_Module { get; set; }
|
2024-06-03 17:39:57 +03:00
|
|
|
|
|
2024-06-24 09:40:54 +03:00
|
|
|
|
// текущий асинхронный метод, для которого будет построена StateMachine
|
|
|
|
|
|
private procedure_definition proc_def { get; set; }
|
2024-06-03 17:39:57 +03:00
|
|
|
|
|
2024-06-24 09:40:54 +03:00
|
|
|
|
// список всех асинхронных методов
|
|
|
|
|
|
private List<procedure_definition> proc_def_List = new List<procedure_definition>();
|
2024-06-03 17:39:57 +03:00
|
|
|
|
|
2024-06-24 09:40:54 +03:00
|
|
|
|
// Тип билдера, который нужно менять в зависимости от возвращаемого
|
|
|
|
|
|
// типа асинхронного типа
|
|
|
|
|
|
private string BuilderType = "AsyncVoidMethodBuilder";
|
2024-06-03 17:39:57 +03:00
|
|
|
|
|
2024-06-24 09:40:54 +03:00
|
|
|
|
private int AwaiterCounter = 1;
|
2024-06-03 17:39:57 +03:00
|
|
|
|
|
2024-06-24 09:40:54 +03:00
|
|
|
|
private AwaitBuilder AwaitBuilder;
|
2024-06-03 17:39:57 +03:00
|
|
|
|
|
2024-06-24 09:40:54 +03:00
|
|
|
|
private AsyncBuilder AsyncBuilder;
|
2024-06-03 17:39:57 +03:00
|
|
|
|
|
2024-06-24 09:40:54 +03:00
|
|
|
|
private bool IsFirstAwait = true;
|
|
|
|
|
|
|
|
|
|
|
|
private bool IsFirstAsync = true;
|
|
|
|
|
|
|
|
|
|
|
|
// Нужен, чтобы понимать с какой машиной
|
|
|
|
|
|
// состояний мы сейчас работаем
|
|
|
|
|
|
private int StateMachineNumber = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Множество всех процедур
|
|
|
|
|
|
public static HashSet<string> ProcedureSet = new HashSet<string>();
|
|
|
|
|
|
|
|
|
|
|
|
// Множество всех функций
|
|
|
|
|
|
public static HashSet<string> FunctionSet = new HashSet<string>();
|
2024-06-03 17:39:57 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static AsyncVisitor New
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return new AsyncVisitor(); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(procedure_definition pd)
|
2024-06-24 09:40:54 +03:00
|
|
|
|
{
|
|
|
|
|
|
if (pd.proc_header is function_header)
|
|
|
|
|
|
{
|
|
|
|
|
|
var ph = pd.proc_header as function_header;
|
|
|
|
|
|
if (ph.name != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
FunctionSet.Add(ph.name.meth_name.name);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var ph = pd.proc_header;
|
|
|
|
|
|
if (ph.name != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProcedureSet.Add(ph.name.meth_name.name);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-06-12 16:14:38 +03:00
|
|
|
|
// Собираем все асинхронные методы в proc_def_List
|
|
|
|
|
|
if (pd.proc_header.IsAsync)
|
2024-06-24 09:40:54 +03:00
|
|
|
|
{
|
|
|
|
|
|
MainVisitor.HasAwait = false;
|
|
|
|
|
|
MainVisitor.Accept(pd);
|
|
|
|
|
|
if (!MainVisitor.HasAwait)
|
|
|
|
|
|
{
|
|
|
|
|
|
var b = pd.proc_body as block;
|
|
|
|
|
|
if (b != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var await = new await_node_statement();
|
|
|
|
|
|
await.source_context = b.source_context;
|
|
|
|
|
|
await.aw = new await_node();
|
|
|
|
|
|
await.aw.source_context = b.source_context;
|
|
|
|
|
|
var mc = new method_call();
|
|
|
|
|
|
mc.dereferencing_value = new dot_node(new dot_node(new dot_node(new dot_node(new ident("System"),
|
|
|
|
|
|
new ident("Threading")), new ident("Tasks")), new ident("Task")), new ident("Delay"));
|
|
|
|
|
|
mc.parameters = new expression_list(new int32_const(0));
|
|
|
|
|
|
mc.source_context = b.source_context;
|
2024-06-05 20:35:46 +03:00
|
|
|
|
|
|
|
|
|
|
await.aw.ex = mc;
|
2024-06-24 09:40:54 +03:00
|
|
|
|
b.program_code.list.Add(await);
|
2024-07-12 21:06:00 +03:00
|
|
|
|
await.Parent = b.program_code;
|
2024-06-24 09:40:54 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
proc_def = pd;
|
|
|
|
|
|
proc_def_List.Add(pd);
|
|
|
|
|
|
if (IsFirstAsync)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
IsFirstAsync = false;
|
|
|
|
|
|
AsyncBuilder = new AsyncBuilder(program_Module);
|
|
|
|
|
|
AsyncBuilder.AddUsesCompilerServices();
|
|
|
|
|
|
}
|
2024-06-03 17:39:57 +03:00
|
|
|
|
LoweringAsyncVisitor.Accept(pd);
|
|
|
|
|
|
AsyncBuilder.GetMethods(pd);
|
2024-06-24 09:40:54 +03:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (pd.proc_body is block)
|
|
|
|
|
|
{
|
2024-06-03 17:39:57 +03:00
|
|
|
|
var procedure_code = (pd.proc_body as block).program_code;
|
|
|
|
|
|
for (int i = 0; i < procedure_code.list.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (procedure_code.list[i] is await_node_statement)
|
|
|
|
|
|
{
|
2024-06-12 16:14:38 +03:00
|
|
|
|
throw new SyntaxVisitorError("Ключевое слово 'await' может быть использовано " +
|
2024-06-24 09:40:54 +03:00
|
|
|
|
"только в асинхронных методах ", procedure_code.list[i].source_context);
|
2024-06-03 17:39:57 +03:00
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
2024-06-12 16:14:38 +03:00
|
|
|
|
throw new SyntaxVisitorError("Ключевое слово 'await' может быть использовано " +
|
2024-06-24 09:40:54 +03:00
|
|
|
|
"только в асинхронных методах ", pp.var_def.inital_value.source_context);
|
2024-06-03 17:39:57 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-06-24 09:40:54 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public override void visit(await_node_statement astat)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProcessNode(astat.aw);
|
2024-06-03 17:39:57 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(await_node a)
|
2024-06-24 09:40:54 +03:00
|
|
|
|
{
|
2024-07-05 19:26:19 +03:00
|
|
|
|
// сразу обернуть в sugared_addressed_value
|
2024-07-07 21:02:25 +03:00
|
|
|
|
//var sug = new sugared_expression(a, a.ex, a.ex.source_context);
|
|
|
|
|
|
//ReplaceUsingParent(a, sug);
|
2024-06-24 09:40:54 +03:00
|
|
|
|
AwaiterCounter++;
|
|
|
|
|
|
if (IsFirstAwait)
|
|
|
|
|
|
{
|
|
|
|
|
|
IsFirstAwait = false;
|
|
|
|
|
|
AwaitBuilder = new AwaitBuilder(program_Module, proc_def);
|
|
|
|
|
|
AwaitBuilder.VarsHelper.RepVarsDict = AsyncBuilder.RepVarsDict;
|
|
|
|
|
|
AwaitBuilder.GetCode();
|
|
|
|
|
|
AwaitBuilder.AddAwaiter(true, a.ex, StateMachineNumber);
|
|
|
|
|
|
AwaitBuilder.ChangeBuilder(BuilderType, StateMachineNumber);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
AwaitBuilder.ChangeBuilder(BuilderType, StateMachineNumber);
|
|
|
|
|
|
AwaitBuilder.AddAwaiter(false, a.ex, StateMachineNumber);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (AwaitBuilder.AwaiterCounter == AwaiterCounter - 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
AwaitBuilder.GenAwait(StateMachineNumber + 2);
|
|
|
|
|
|
AwaitBuilder.DeleteBody();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public void GenMain(program_module pm)
|
|
|
|
|
|
{
|
|
|
|
|
|
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.name = new method_name();
|
|
|
|
|
|
p.proc_header.name.meth_name = new ident("@AsyncMain", d.source_context);
|
|
|
|
|
|
p.proc_header.IsAsync = true;
|
|
|
|
|
|
p.source_context = d.source_context;
|
|
|
|
|
|
var b = new block();
|
|
|
|
|
|
b.source_context = d.source_context;
|
|
|
|
|
|
b.program_code = new statement_list();
|
|
|
|
|
|
b.program_code.source_context = d.source_context;
|
|
|
|
|
|
foreach (var item in pm.program_block.program_code.list)
|
|
|
|
|
|
{
|
|
|
|
|
|
b.program_code.list.Add(item);
|
|
|
|
|
|
item.Parent = b.program_code;
|
|
|
|
|
|
}
|
|
|
|
|
|
p.proc_body = b;
|
|
|
|
|
|
pm.program_block.program_code.list.Clear();
|
|
|
|
|
|
d.Add(p);
|
|
|
|
|
|
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);
|
|
|
|
|
|
pm.program_block.program_code.list.Add(vst);
|
2024-07-12 21:06:00 +03:00
|
|
|
|
vst.Parent = pm.program_block.program_code;
|
2024-06-24 09:40:54 +03:00
|
|
|
|
pm.program_block.program_code.list.Add(pc);
|
2024-07-12 21:06:00 +03:00
|
|
|
|
pc.Parent = pm.program_block.program_code;
|
2024-06-24 09:40:54 +03:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public override void visit(program_module pm)
|
|
|
|
|
|
{
|
|
|
|
|
|
program_Module = pm;
|
2024-06-12 16:14:38 +03:00
|
|
|
|
MainVisitor.HasAwait = false;
|
2024-06-03 17:39:57 +03:00
|
|
|
|
MainVisitor.Accept(pm.program_block.program_code);
|
|
|
|
|
|
GenMain(pm);
|
2024-06-24 09:40:54 +03:00
|
|
|
|
|
2024-06-03 17:39:57 +03:00
|
|
|
|
DefaultVisit(pm);
|
2024-06-24 09:40:54 +03:00
|
|
|
|
if (proc_def_List.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
AsyncBuilder.ParseStateMachines();
|
|
|
|
|
|
AsyncBuilder.ChangeBodies();
|
|
|
|
|
|
proc_def_List.Reverse();
|
|
|
|
|
|
foreach (var p in proc_def_List)
|
|
|
|
|
|
{
|
|
|
|
|
|
AwaiterCounter = 1;
|
|
|
|
|
|
IsFirstAwait = true;
|
|
|
|
|
|
proc_def = p;
|
|
|
|
|
|
if (p.proc_header.IsAsync)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (p.proc_header is function_header)
|
|
|
|
|
|
{
|
|
|
|
|
|
var fh = p.proc_header as function_header;
|
|
|
|
|
|
var s = fh.return_type.ToString();
|
2024-06-04 19:34:39 +03:00
|
|
|
|
if (s.Contains("."))
|
|
|
|
|
|
{
|
|
|
|
|
|
s = s.Substring(s.LastIndexOf('.') + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (s.StartsWith("Task"))
|
2024-06-24 09:40:54 +03:00
|
|
|
|
{
|
|
|
|
|
|
BuilderType = "AsyncTaskMethodBuilder" + s.Substring(4);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
BuilderType = "Async" + fh.return_type.ToString() + "MethodBuilder";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
BuilderType = "AsyncVoidMethodBuilder";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DefaultVisit(p);
|
|
|
|
|
|
StateMachineNumber += 4;
|
|
|
|
|
|
}
|
|
|
|
|
|
AsyncBuilder.SortBlocks();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-06-03 17:39:57 +03:00
|
|
|
|
}
|