async/await

This commit is contained in:
Aleksandr Kalinin 2024-06-03 17:39:57 +03:00
parent bda964c3af
commit 155d0a01ba
25 changed files with 4996 additions and 2476 deletions

View file

@ -15,7 +15,7 @@ internal static class RevisionClass
public const string Major = "3";
public const string Minor = "9";
public const string Build = "0";
public const string Revision = "3488";
public const string Revision = "3489";
public const string MainVersion = Major + "." + Minor;
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;

View file

@ -1,4 +1,4 @@
%COREVERSION%=0
%REVISION%=3488
%MINOR%=9
%REVISION%=3489
%COREVERSION%=0
%MAJOR%=3

View file

@ -1,9 +1,9 @@
//
// This CSharp output file generated by Gardens Point LEX
// Version: 1.1.3.301
// Machine: DESKTOP-V3E9T2U
// DateTime: 25.05.2024 22:13:44
// UserName: alex
// Machine: DESKTOP-IS1MGLS
// DateTime: 01.06.2024 6:59:07
// UserName: LastHero
// GPLEX input file <ABCPascal.lex>
// GPLEX frame file <embedded resource>
//

View file

@ -2761,6 +2761,8 @@ unlabelled_stmt
{ $$ = $1; }
| proc_call
{ $$ = $1; }
| tkAwait expr_l1
{ $$ = new await_node_statement(new await_node($2,@$),@$); }
| goto_stmt
{ $$ = $1; }
| compound_stmt
@ -3374,7 +3376,7 @@ expr_dq
: relop_expr
{ $$ = $1; }
| tkAwait relop_expr
{ $$ = $2; }
{ $$ = new await_node($2 as expression, @$); }
| expr_dq tkDoubleQuestion relop_expr
{ $$ = new double_question_node($1 as expression, $3 as expression, @$);}
;

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -379,5 +379,6 @@ script=

View file

@ -81,6 +81,8 @@ namespace Languages.Pascal.Frontend.Converters
MarkMethodHasYieldAndCheckSomeErrorsVisitor.New.ProcessNode(root);
ProcessYieldCapturedVarsVisitor.New.ProcessNode(root);
AsyncVisitor.New.ProcessNode(root);
CacheFunctionVisitor.New.ProcessNode(root);
// При наличии файла lightpt.dat подключает модули LightPT и Tasks

View file

@ -1 +1 @@
3.9.0.3488
3.9.0.3489

View file

@ -1 +1 @@
!define VERSION '3.9.0.3488'
!define VERSION '3.9.0.3489'

View file

@ -1317,6 +1317,16 @@ namespace PascalABCCompiler.SyntaxTree
{
DefaultVisit(_let_var_expr);
}
public virtual void visit(await_node _await_node)
{
DefaultVisit(_await_node);
}
public virtual void visit(await_node_statement _await_node_statement)
{
DefaultVisit(_await_node_statement);
}
}

View file

@ -2101,6 +2101,22 @@ namespace PascalABCCompiler.SyntaxTree
{
}
public virtual void pre_do_visit(await_node _await_node)
{
}
public virtual void post_do_visit(await_node _await_node)
{
}
public virtual void pre_do_visit(await_node_statement _await_node_statement)
{
}
public virtual void post_do_visit(await_node_statement _await_node_statement)
{
}
public override void visit(expression _expression)
{
DefaultVisit(_expression);
@ -4342,6 +4358,22 @@ namespace PascalABCCompiler.SyntaxTree
visit(let_var_expr.ex);
post_do_visit(_let_var_expr);
}
public override void visit(await_node _await_node)
{
DefaultVisit(_await_node);
pre_do_visit(_await_node);
visit(await_node.ex);
post_do_visit(_await_node);
}
public override void visit(await_node_statement _await_node_statement)
{
DefaultVisit(_await_node_statement);
pre_do_visit(_await_node_statement);
visit(await_node_statement.aw);
post_do_visit(_await_node_statement);
}
}

View file

@ -544,6 +544,10 @@ namespace PascalABCCompiler.SyntaxTree
return new ref_var_def_statement();
case 261:
return new let_var_expr();
case 262:
return new await_node();
case 263:
return new await_node_statement();
}
return null;
}
@ -4569,6 +4573,30 @@ namespace PascalABCCompiler.SyntaxTree
_let_var_expr.ex = _read_node() as expression;
}
public void visit(await_node _await_node)
{
read_await_node(_await_node);
}
public void read_await_node(await_node _await_node)
{
read_expression(_await_node);
_await_node.ex = _read_node() as expression;
}
public void visit(await_node_statement _await_node_statement)
{
read_await_node_statement(_await_node_statement);
}
public void read_await_node_statement(await_node_statement _await_node_statement)
{
read_statement(_await_node_statement);
_await_node_statement.aw = _read_node() as await_node;
}
}

View file

@ -7181,6 +7181,48 @@ namespace PascalABCCompiler.SyntaxTree
}
}
public void visit(await_node _await_node)
{
bw.Write((Int16)262);
write_await_node(_await_node);
}
public void write_await_node(await_node _await_node)
{
write_expression(_await_node);
if (_await_node.ex == null)
{
bw.Write((byte)0);
}
else
{
bw.Write((byte)1);
_await_node.ex.visit(this);
}
}
public void visit(await_node_statement _await_node_statement)
{
bw.Write((Int16)263);
write_await_node_statement(_await_node_statement);
}
public void write_await_node_statement(await_node_statement _await_node_statement)
{
write_statement(_await_node_statement);
if (_await_node_statement.aw == null)
{
bw.Write((byte)0);
}
else
{
bw.Write((byte)1);
_await_node_statement.aw.visit(this);
}
}
}

View file

@ -55897,6 +55897,320 @@ namespace PascalABCCompiler.SyntaxTree
}
///<summary>
///
///</summary>
[Serializable]
public partial class await_node : expression
{
///<summary>
///Конструктор без параметров.
///</summary>
public await_node()
{
}
///<summary>
///Конструктор с параметрами.
///</summary>
public await_node(expression _ex)
{
this._ex=_ex;
FillParentsInDirectChilds();
}
///<summary>
///Конструктор с параметрами.
///</summary>
public await_node(expression _ex,SourceContext sc)
{
this._ex=_ex;
source_context = sc;
FillParentsInDirectChilds();
}
protected expression _ex;
///<summary>
///
///</summary>
public expression ex
{
get
{
return _ex;
}
set
{
_ex=value;
if (_ex != null)
_ex.Parent = this;
}
}
/// <summary> Создает копию узла </summary>
public override syntax_tree_node Clone()
{
await_node copy = new await_node();
copy.Parent = this.Parent;
if (source_context != null)
copy.source_context = new SourceContext(source_context);
if (attributes != null)
{
copy.attributes = (attribute_list)attributes.Clone();
copy.attributes.Parent = copy;
}
if (ex != null)
{
copy.ex = (expression)ex.Clone();
copy.ex.Parent = copy;
}
return copy;
}
/// <summary> Получает копию данного узла корректного типа </summary>
public new await_node TypedClone()
{
return Clone() as await_node;
}
///<summary> Заполняет поля Parent в непосредственных дочерних узлах </summary>
public override void FillParentsInDirectChilds()
{
if (attributes != null)
attributes.Parent = this;
if (ex != null)
ex.Parent = this;
}
///<summary> Заполняет поля Parent во всем поддереве </summary>
public override void FillParentsInAllChilds()
{
FillParentsInDirectChilds();
attributes?.FillParentsInAllChilds();
ex?.FillParentsInAllChilds();
}
///<summary>
///Свойство для получения количества всех подузлов без элементов поля типа List
///</summary>
public override Int32 subnodes_without_list_elements_count
{
get
{
return 1;
}
}
///<summary>
///Свойство для получения количества всех подузлов. Подузлом также считается каждый элемент поля типа List
///</summary>
public override Int32 subnodes_count
{
get
{
return 1;
}
}
///<summary>
///Индексатор для получения всех подузлов
///</summary>
public override syntax_tree_node this[Int32 ind]
{
get
{
if(subnodes_count == 0 || ind < 0 || ind > subnodes_count-1)
throw new IndexOutOfRangeException();
switch(ind)
{
case 0:
return ex;
}
return null;
}
set
{
if(subnodes_count == 0 || ind < 0 || ind > subnodes_count-1)
throw new IndexOutOfRangeException();
switch(ind)
{
case 0:
ex = (expression)value;
break;
}
}
}
///<summary>
///Метод для обхода дерева посетителем
///</summary>
///<param name="visitor">Объект-посетитель.</param>
///<returns>Return value is void</returns>
public override void visit(IVisitor visitor)
{
visitor.visit(this);
}
}
///<summary>
///
///</summary>
[Serializable]
public partial class await_node_statement : statement
{
///<summary>
///Конструктор без параметров.
///</summary>
public await_node_statement()
{
}
///<summary>
///Конструктор с параметрами.
///</summary>
public await_node_statement(await_node _aw)
{
this._aw=_aw;
FillParentsInDirectChilds();
}
///<summary>
///Конструктор с параметрами.
///</summary>
public await_node_statement(await_node _aw,SourceContext sc)
{
this._aw=_aw;
source_context = sc;
FillParentsInDirectChilds();
}
protected await_node _aw;
///<summary>
///
///</summary>
public await_node aw
{
get
{
return _aw;
}
set
{
_aw=value;
if (_aw != null)
_aw.Parent = this;
}
}
/// <summary> Создает копию узла </summary>
public override syntax_tree_node Clone()
{
await_node_statement copy = new await_node_statement();
copy.Parent = this.Parent;
if (source_context != null)
copy.source_context = new SourceContext(source_context);
if (attributes != null)
{
copy.attributes = (attribute_list)attributes.Clone();
copy.attributes.Parent = copy;
}
if (aw != null)
{
copy.aw = (await_node)aw.Clone();
copy.aw.Parent = copy;
}
return copy;
}
/// <summary> Получает копию данного узла корректного типа </summary>
public new await_node_statement TypedClone()
{
return Clone() as await_node_statement;
}
///<summary> Заполняет поля Parent в непосредственных дочерних узлах </summary>
public override void FillParentsInDirectChilds()
{
if (attributes != null)
attributes.Parent = this;
if (aw != null)
aw.Parent = this;
}
///<summary> Заполняет поля Parent во всем поддереве </summary>
public override void FillParentsInAllChilds()
{
FillParentsInDirectChilds();
attributes?.FillParentsInAllChilds();
aw?.FillParentsInAllChilds();
}
///<summary>
///Свойство для получения количества всех подузлов без элементов поля типа List
///</summary>
public override Int32 subnodes_without_list_elements_count
{
get
{
return 1;
}
}
///<summary>
///Свойство для получения количества всех подузлов. Подузлом также считается каждый элемент поля типа List
///</summary>
public override Int32 subnodes_count
{
get
{
return 1;
}
}
///<summary>
///Индексатор для получения всех подузлов
///</summary>
public override syntax_tree_node this[Int32 ind]
{
get
{
if(subnodes_count == 0 || ind < 0 || ind > subnodes_count-1)
throw new IndexOutOfRangeException();
switch(ind)
{
case 0:
return aw;
}
return null;
}
set
{
if(subnodes_count == 0 || ind < 0 || ind > subnodes_count-1)
throw new IndexOutOfRangeException();
switch(ind)
{
case 0:
aw = (await_node)value;
break;
}
}
}
///<summary>
///Метод для обхода дерева посетителем
///</summary>
///<param name="visitor">Объект-посетитель.</param>
///<returns>Return value is void</returns>
public override void visit(IVisitor visitor)
{
visitor.visit(this);
}
}
}

View file

@ -1576,6 +1576,18 @@ namespace PascalABCCompiler.SyntaxTree
///<param name="_let_var_expr">Node to visit</param>
///<returns> Return value is void </returns>
void visit(let_var_expr _let_var_expr);
///<summary>
///Method to visit await_node.
///</summary>
///<param name="_await_node">Node to visit</param>
///<returns> Return value is void </returns>
void visit(await_node _await_node);
///<summary>
///Method to visit await_node_statement.
///</summary>
///<param name="_await_node_statement">Node to visit</param>
///<returns> Return value is void </returns>
void visit(await_node_statement _await_node_statement);
}

View file

@ -3368,6 +3368,26 @@
<TagIndices />
</Tags>
</SyntaxNode>
<SyntaxNode Name="await_node" BaseName="expression">
<Fields>
<SyntaxField Name="ex" SyntaxType="expression" />
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
</Tags>
</SyntaxNode>
<SyntaxNode Name="await_node_statement" BaseName="statement">
<Fields>
<SyntaxField Name="aw" SyntaxType="await_node" />
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
</Tags>
</SyntaxNode>
</SyntaxNodes>
<Settings>
<FileName>Tree.cs</FileName>
@ -3414,6 +3434,7 @@
<HelpData Key=".aloneparam" Value="" />
<HelpData Key=".attr" Value="" />
<HelpData Key=".attributes" Value="" />
<HelpData Key=".aw" Value="" />
<HelpData Key=".body" Value="" />
<HelpData Key=".cconst" Value="Значение константы." />
<HelpData Key=".char_num" Value="Номер символа." />
@ -3572,6 +3593,10 @@
<HelpData Key="attribute_list.attributes" Value="" />
<HelpData Key="attribute_list.void Add(simple_attribute_list sal, SourceContext sc)" Value="" />
<HelpData Key="attribute_list.w" Value="" />
<HelpData Key="await_node" Value="" />
<HelpData Key="await_node.ex" Value="" />
<HelpData Key="await_node_statement" Value="" />
<HelpData Key="await_node_statement.aw" Value="" />
<HelpData Key="bigint_const" Value="" />
<HelpData Key="bigint_const.val" Value="" />
<HelpData Key="bin_expr" Value="Бинарное выражение" />

View file

@ -0,0 +1,401 @@
using PascalABCCompiler.SyntaxTree;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SyntaxVisitors.Async
{
internal class AsyncBuilder
{
// корень дерева
private program_module program_Module { get; set; }
public List<declarations> declarations = new List<declarations>();
public List<procedure_definition> pdList = new List<procedure_definition>();
public HashSet<var_statement> VarsList = new HashSet<var_statement>();
public Dictionary<string, string> RepVarsDict = new Dictionary<string, string>();
int k = 0;
private int StateCounter = 1;
private declarations Decls = new declarations();
public AsyncBuilder(program_module program_Module)
{
this.program_Module = program_Module;
}
// Подключаем необходимые модули
public void AddUsesCompilerServices()
{
if (program_Module.used_units != null)
{
program_Module.used_units.Add(new unit_or_namespace(new ident_list(new ident("System"),
new ident("Runtime"), new ident("CompilerServices"))), program_Module.used_units.source_context);
}
else
{
program_Module.used_units = new uses_list(new unit_or_namespace(new ident_list(new ident("System"),
new ident("Runtime"), new ident("CompilerServices"))), program_Module.source_context);
}
}
public string NewStateMachine()
{
return "@StateMachine@_" + StateCounter++;
}
// Создаем StateMachine вручную
public void BuildStateMachine()
{
var defs = program_Module.program_block.defs;
var vds = new var_def_statement(new ident("state"), new named_type_reference(new ident("integer")), defs.source_context);
var vds2 = new var_def_statement(new ident("tbuilder"), new named_type_reference(new ident("AsyncVoidMethodBuilder")), defs.source_context);
var ph = new procedure_header();
ph.name = new method_name();
ph.name.meth_name = new ident("MoveNext");
ph.proc_attributes = new procedure_attributes_list();
ph.source_context = defs.source_context;
var ph2 = new procedure_header();
ph2.name = new method_name();
ph2.name.meth_name = new ident("SetStateMachine");
ph2.source_context = defs.source_context;
var namedtr = new named_type_reference(new ident("System"), defs.source_context);
namedtr.Add(new ident("Runtime"));
namedtr.Add(new ident("CompilerServices"));
namedtr.Add(new ident("IAsyncStateMachine"));
var tp = new typed_parameters(new ident("stateMachine"), namedtr, defs.source_context);
ph2.parameters = new formal_parameters(tp);
ph2.proc_attributes = new procedure_attributes_list();
List<declaration> members = new List<declaration>{ vds, vds2, ph, ph2 };
var cm = new class_members(members, new access_modifer_node(access_modifer.public_modifer), defs.source_context);
var classbodylist = new class_body_list(cm, defs.source_context);
var ntr = new named_type_reference_list(new named_type_reference(new ident("IAsyncStateMachine")), defs.source_context);
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);
var p = new procedure_call(new method_call(new dot_node(new ident("tbuilder"), new ident("SetStateMachine")), new expression_list(new ident("stateMachine"))), defs.source_context);
var subnodes = new List<statement> { a, p };
var stlist = new statement_list(subnodes, new token_info("begin"), new token_info("end"), false, defs.source_context);
pd.proc_body = new block(new declarations(), stlist, defs.source_context);
pd.source_context = defs.source_context;
var pd2 = new procedure_definition();
pd2.proc_header = ph;
pd2.source_context = defs.source_context;
stlist = new statement_list(new empty_statement(), defs.source_context);
stlist.left_logical_bracket = new token_info("try", defs.source_context);
a = new assign(new ident("state"), new un_expr(new int32_const(2), Operators.Minus), Operators.Assignment, defs.source_context);
var e = new new_expr(new named_type_reference(new ident("Exception")), new expression_list(new string_const("MoveNextException")), defs.source_context);
p = new procedure_call(new method_call(new dot_node(new ident("tbuilder"), new ident("SetException")), new expression_list(e)), defs.source_context);
var exception_block = new exception_block();
exception_block.stmt_list = new statement_list(a, p, new procedure_call(new ident("exit")), new empty_statement());
exception_block.source_context = defs.source_context;
exception_block.stmt_list.source_context = defs.source_context;
var try_handler = new try_handler_except(exception_block, defs.source_context);
var tr = new try_stmt(stlist, try_handler, defs.source_context);
var mc = new method_call();
mc.source_context = defs.source_context;
mc.dereferencing_value = new dot_node(new ident("tbuilder"), new ident("SetResult"), defs.source_context);
p = new procedure_call(mc, defs.source_context);
subnodes = new List<statement> { tr, a, p, new empty_statement() };
stlist = new statement_list(subnodes, new token_info("begin"), new token_info("end"), false);
stlist.source_context = defs.source_context;
pd2.proc_body = new block(new declarations(), stlist, defs.source_context);
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);
}
// Генерируем StateMachine
public void ParseStateMachine(procedure_definition p)
{
var defs = program_Module.program_block.defs;
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;
var tdef2 = t_name.types_decl[0];
var cd2 = tdef2.type_def as class_definition;
var bd2 = cd2.body;
var cm2 = bd2[0] as class_members;
var ph = new procedure_header();
ph.name = new method_name();
ph.name.meth_name = new ident("MoveNext");
ph.proc_attributes = new procedure_attributes_list();
ph.source_context = defs.source_context;
var ph2 = new procedure_header();
ph2.name = new method_name();
ph2.name.meth_name = new ident("SetStateMachine", defs.source_context);
ph2.source_context = defs.source_context;
var namedtr = new named_type_reference(new ident("System"), defs.source_context);
namedtr.Add(new ident("Runtime"));
namedtr.Add(new ident("CompilerServices"));
namedtr.Add(new ident("IAsyncStateMachine"));
var tp = new typed_parameters(new ident("stateMachine"), namedtr, defs.source_context);
ph2.parameters = new formal_parameters(tp, defs.source_context);
ph2.proc_attributes = new procedure_attributes_list();
ph2.source_context = defs.source_context;
cm2.members[2] = ph;
cm2.members[3] = ph2;
var pd1 = Decls.list[1] as procedure_definition;
pd1.proc_header.name.class_name = name;
var pd2 = Decls.list[2] as procedure_definition;
pd2.proc_header.name.class_name = name;
var dc = new declarations();
dc.Add(Decls.list[0], defs.source_context);
dc.Add(Decls.list[1], defs.source_context);
dc.Add(Decls.list[2], defs.source_context);
dc.Add(p, defs.source_context);
declarations.Add(dc);
Decls.list.Clear();
}
public void ParseStateMachines()
{
//var async_pm = async_root as program_module;
var defs = program_Module.program_block.defs;
//pdList.Reverse();
var t = new List<procedure_definition>();
foreach (var item in pdList)
{
t.Add(item);
defs.Remove(item);
}
t.Reverse();
foreach (var pd in t)
{
ParseStateMachine(pd);
}
declarations.Reverse();
foreach (var item in declarations)
{
defs.AddFirst(item.list);
}
}
public void SortBlocks()
{
var defs = program_Module.program_block.defs;
var ind = pdList.Count * 4;
int k = 0;
for (int i = ind; i < defs.list.Count; i++)
{
if (defs.list[i] is procedure_definition)
{
var p = defs.list[i] as procedure_definition;
if (p.proc_header.IsAsync)
continue;
var d = defs.list[i];
defs.list.Remove(d);
defs.AddFirst(d);
k++;
}
}
var sortedNumbers = new List<declaration>();
for (int i = k - 1; i >= 0; i--)
{
sortedNumbers.Add(defs.list[i]);
}
for (int i = k; i < defs.list.Count; i++)
{
sortedNumbers.Add(defs.list[i]);
}
defs.list.Clear();
foreach (var item in sortedNumbers)
{
defs.list.Add(item);
}
for (int i = 0; i < defs.list.Count; i++)
{
if (defs.list[i] is variable_definitions || defs.list[i] is type_declarations)
{
var d = defs.list[i];
defs.list.Remove(d);
defs.AddFirst(d);
}
}
}
public void GetMethods(procedure_definition p)
{
pdList.Add(p);
}
public void ChangeBodies()
{
StateCounter = 1;
pdList.Reverse();
foreach (var item in pdList)
{
var b = item.proc_header is function_header;
var s = "Void";
if (b)
{
var fh = item.proc_header as function_header;
s = fh.return_type.ToString();
// AddError нужно вместо SyntaxVisitorError
if (s.StartsWith("Void") || s.StartsWith("Task"))
{
//BuilderType = "Async" + s + "MethodBuilder";
}
else
throw new SyntaxVisitorError("Возвращаемым типом асинхронного метода должен быть void, Task, Task<T> или аналогичный тип, IAsyncEnumerable<T> или IAsyncEnumerator<T>",
item.proc_header.source_context);
}
if (s == "Void" || s == "Task")
{
ChangeBody(item, b, "Async" + s + "MethodBuilder");
}
else
{
ChangeBody(item, b, "AsyncTaskMethodBuilder" + s.Substring(4));
}
}
}
public string newLabelName(string old)
{
k++;
return "@awvar@_" + k.ToString() + "_" + old;
}
// Изменяем тело асинхронной функции, добавляя AsyncBuilder для запуска StateMachine
public void ChangeBody(procedure_definition pd, bool IsFunc, string Type)
{
var state = "@awst@_";
var block = pd.proc_body as block;
if (pd.proc_header.IsAsync == false)
{
return;
}
var i = new ident(state, block.source_context);
var v = new var_def_statement(i, new new_expr(NewStateMachine()), block.source_context); // st:= new StateMachine();
var st = new var_statement(v, block.source_context); // st:= new StateMachine();
var d = new dot_node(i, new ident("state"), block.source_context);
var a = new assign(d, new int32_const(1), Operators.Assignment, block.source_context);//st.state := 1;
var parsList = new statement_list();
parsList.source_context = block.source_context;
if (pd.proc_header.parameters != null)
{
var par = pd.proc_header.parameters;
foreach (var pp in par.params_list)
{
foreach (var id in pp.idents.list)
{
if (!RepVarsDict.ContainsKey(id.name))
{
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);
}
}
}
}
parsList.source_context = block.source_context;
var fr2 = new method_call();
fr2.source_context = block.source_context;
if (Type.StartsWith("AsyncVoidMethodBuilder") || Type == "AsyncTaskMethodBuilder")
{
fr2.dereferencing_value = new dot_node(new ident(Type), new ident("Create"), block.source_context);
}
else
{
var ttt = Type.Substring(23);
ttt = ttt.Replace(">", "");
var tpl = new template_param_list();
tpl.source_context = block.source_context;
tpl.params_list.Add(new named_type_reference(new ident(ttt, block.source_context)));
fr2.dereferencing_value = new dot_node(new ident_with_templateparams(new ident("AsyncTaskMethodBuilder", block.source_context), tpl, block.source_context), new ident("Create", block.source_context), block.source_context);
}
var a2 = new assign(new dot_node(i, new ident("tbuilder", block.source_context)), fr2, Operators.Assignment, block.source_context);//st.tbuilder := AsyncTaskMethodBuilder.Create();
var m = new method_call(new expression_list(i), block.source_context);
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 class_name = pd.proc_header.name.class_name;
if (class_name != null)
{
if (!pd.proc_header.class_keyword)
{
var ascl = new assign(new dot_node(i, "@awclass", pd.source_context), new ident("self", pd.source_context), pd.source_context); // st:= new StateMachine();
stl.Add(ascl);
}
}
stl.Add(p);
if (IsFunc)
{
var a3 = new assign(new ident("Result", pd.source_context), new dot_node(new dot_node(new ident(state, block.source_context), new ident("tbuilder", block.source_context)), new ident("Task", block.source_context)), Operators.Assignment, pd.source_context);
stl.Add(a3);
}
stl.source_context = pd.source_context;
pd.proc_body = new block(stl);
var tt = pd.proc_body as block;
tt.defs = block.defs;
}
}
}

View file

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PascalABCCompiler.Errors;
using PascalABCCompiler;
using PascalABCCompiler.SyntaxTree;
using SyntaxVisitors.Async;
using PascalABCCompiler.Parsers;
using PascalABCCompiler.ParserTools;
using PascalABCCompiler.SyntaxTreeConverters;
using System.IO;
using System.Collections;
namespace SyntaxVisitors
{
public class AsyncVisitor : BaseChangeVisitor
{
private program_module program_Module { get; set; }
private procedure_definition proc_def { get; set; }
private List<procedure_definition> proc_def_List = new List<procedure_definition>();
private string BuilderType = "AsyncVoidMethodBuilder";
private bool IsAsync = false;
private int AwaiterCounter = 1;
private AwaitBuilder AwaitBuilder;
private AsyncBuilder AsyncBuilder;
private bool IsFirstAwait = true;
private bool IsFirstAsync = true;
private int ChangeBuilderCounter = 0;
public static AsyncVisitor New
{
get { return new AsyncVisitor(); }
}
public override void visit(procedure_definition pd)
{
if (pd.proc_header.IsAsync)
{
IsAsync = true;
proc_def = pd;
proc_def_List.Add(pd);
if (IsFirstAsync)
{
IsFirstAsync = false;
AsyncBuilder = new AsyncBuilder(program_Module);
AsyncBuilder.AddUsesCompilerServices();
}
LoweringAsyncVisitor.Accept(pd);
AsyncBuilder.GetMethods(pd);
// DefaultVisit(pd);
}
else
{
if (pd.proc_body is block)
{
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)
{
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);
}
}
}
}
}
}
public override void visit(await_node_statement astat)
{
ProcessNode(astat.aw);
// DefaultVisit(astat.aw);
}
public override void visit(await_node a)
{
if (!IsAsync)
{
throw new SyntaxVisitorError("'await' can only be used in an async method ", a.source_context);
}
AwaiterCounter++;
if (IsFirstAwait)
{
IsFirstAwait = false;
AwaitBuilder = new AwaitBuilder(program_Module, proc_def);
AwaitBuilder.VarsHelper.RepVarsDict = AsyncBuilder.RepVarsDict;
//AwaitBuilder.RemoveRedundantAwait();
AwaitBuilder.GetCode();
AwaitBuilder.AddAwaiter("TaskAwaiter", true, a.ex, ChangeBuilderCounter);
AwaitBuilder.ChangeBuilder(BuilderType, ChangeBuilderCounter);
}
else
{
AwaitBuilder.ChangeBuilder(BuilderType, ChangeBuilderCounter);
AwaitBuilder.AddAwaiter("TaskAwaiter", false, a.ex, ChangeBuilderCounter);
}
if (AwaitBuilder.AwaiterCounter == AwaiterCounter - 1)
{
AwaitBuilder.GenAwait(ChangeBuilderCounter + 2, a.ex);
AwaitBuilder.DeleteBody();
}
}
public void GenMain(program_module pm)
{
if (MainVisitor.flag)
{
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 n = p.proc_header.name;
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);
}
//b.program_code = pm.program_block.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);
pm.program_block.program_code.list.Add(pc);
}
}
public override void visit(program_module pm)
{
program_Module = pm;
MainVisitor.flag = false;
MainVisitor.Accept(pm.program_block.program_code);
GenMain(pm);
DefaultVisit(pm);
if (IsAsync)
{
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)
{
IsAsync = true;
if (p.proc_header is function_header)
{
var fh = p.proc_header as function_header;
var s = fh.return_type.ToString();
if (s.StartsWith("Task<"))
{
BuilderType = "AsyncTaskMethodBuilder" + s.Substring(4);
}
else
BuilderType = "Async" + fh.return_type.ToString() + "MethodBuilder";
}
else
{
BuilderType = "AsyncVoidMethodBuilder";
}
}
else
IsAsync = false;
DefaultVisit(p);
ChangeBuilderCounter += 4;
}
AsyncBuilder.SortBlocks();
}
}
}
}

View file

@ -0,0 +1,750 @@
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; }
// тело асинхронной функции
public procedure_definition proc_def { get; set; }
private Dictionary<string, string> Awaiters = new Dictionary<string, string>();
int lbnum = 0;
private statement_list code_list = new statement_list();
public expression_list TaskList = new expression_list();
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();
//ctor
public AwaitBuilder(program_module pm, procedure_definition pd)
{
program_Module = pm;
proc_def = pd;
VarsHelper = new VarsHelper();
}
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();
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<declaration> members = new List<declaration> { 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);
}
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")
{
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;
}
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);
}
}
}
}
}
}
}
}
}
}
}
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 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;
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 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;
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);
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());
}
}
}
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;
//continue;
}
}
}
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;
}
// Изменяем метод 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;
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)
{
var loopLabelsList = (proc_def.proc_body as block).defs.list;
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,ts.source_context), TaskList[0] as expression,ts.source_context),ts.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, ifnode.source_context), new ident("GetAwaiter",ifnode.source_context));
mcс.source_context = ifnode.source_context;
//if (class_name is null)
//{
//}
// Убираем лишние присваивания для 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);
}
}
var assign_ = new assign(new ident("@aw@_" + "1",ts.source_context), mcс, Operators.Assignment, ts.source_context);
assign_.first_assignment_defines_type = true;
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);
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;
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;
// начиная со второго встреченного 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;
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;
}
}
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;
// Убираем лишние присваивания для 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;
}
}
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);
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 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);
ts.stmt_list.Add(new procedure_call(mc2, ts.source_context), ts.source_context);
var tt2 = code_list.list.Last() as statement_list;
var fg2 = true;
foreach (var stat in tt2.list)
{
if (stat is assign && fg2)
{
var asstat = stat as assign;
if (asstat.from.ToString().Contains("GetResult"))
{
asstat.from = mc2;
}
}
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);
ts.visit(replacerVis);
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);
}
var MethodsSet = new HashSet<string>();
if (class_name != null)
{
foreach (var dec in program_Module.program_block.defs.list)
{
if (dec is type_declarations)
{
var td = (type_declarations)dec;
foreach (var tdeff in td.types_decl)
{
if (tdeff.type_name.name != class_name.name)
{
continue;
}
if (tdeff.type_def is class_definition)
{
var cd = tdeff.type_def as class_definition;
var bd = cd.body;
for (int j = 0; j < bd.Count; j++)
{
if (bd[j] is class_members)
{
var cm = bd[j] as class_members;
foreach (var item in cm.members)
{
if (item is procedure_header)
{
var pph = item as procedure_header;
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)
MethodsSet.Add(fh.name.meth_name.name);
}
}
}
}
}
}
}
}
}
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
{
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());
}
}
}

View file

@ -0,0 +1,522 @@
using PascalABCCompiler.SyntaxTree;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SyntaxVisitors.Async
{
public class VarNames
{
public string VarName { get; set; }
public string VarEndName { get; set; }
public VarNames()
{
}
public VarNames(string varName, string varEndName)
{
VarName = varName;
VarEndName = varEndName;
}
}
public class LoweringAsyncVisitor : BaseChangeVisitor
{
public static LoweringAsyncVisitor New
{
get { return new LoweringAsyncVisitor(); }
}
private int _varnum = 0;
private int _foreachCollectionNum = 0;
private int _enumeratorNum = 0;
private VarNames NewVarNames(ident name)
{
_varnum++;
return new VarNames()
{
VarName = "$" + name.name + _varnum,
VarEndName = "<>varLV" + _varnum
};
}
private ident NewEnumeratorName()
{
++_enumeratorNum;
return "$enumerator$" + _enumeratorNum;
}
private ident NewForeachCollectionName()
{
++_foreachCollectionNum;
return "$coll$" + _foreachCollectionNum;
}
public static void Accept(procedure_definition pd)
{
New.ProcessNode(pd);
}
public override void Enter(syntax_tree_node st)
{
base.Enter(st);
if (!(st is procedure_definition || st is block || st is statement_list
|| st.GetType() == typeof(case_node) || st.GetType() == typeof(for_node) || st.GetType() == typeof(foreach_stmt)
|| st.GetType() == typeof(if_node)
|| st.GetType() == typeof(repeat_node) || st.GetType() == typeof(while_node)
|| st.GetType() == typeof(with_statement) || st is try_stmt || st.GetType() == typeof(lock_stmt)))
{
//visitNode = false;
}
}
public override void visit(yield_unknown_foreach_type _unk)
{
// DO NOTHING
}
// frninja 21/05/16
public override void visit(foreach_stmt frch)
{
// Полный код Loweringа c yield_unknown_foreach_type = integer
// var a: System.Collections.Generic.IEnumerable<integer>;
// a := l;
// var en := a.GetEnumerator();
// while en.MoveNext do
// begin
// var curr := en.Current; // var не нужно ставить если curr была описана раньше
// Print(curr);
// end;
///
// var a: System.Collections.Generic.IEnumerable<yield_unknown_foreach_type> := l;
var foreachCollIdent = this.NewForeachCollectionName();
var foreachCollType = new template_type_reference(new named_type_reference("System.Collections.Generic.IEnumerable"),
new template_param_list(new yield_unknown_foreach_type(frch)));
var foreachCollVarDef = new var_statement(foreachCollIdent, foreachCollType);
var ass = new assign(foreachCollIdent, frch.in_what);
// var en := a.GetEnumerator();
var enumeratorIdent = this.NewEnumeratorName();
var enumeratorVarDef = new var_statement(enumeratorIdent, new method_call(new dot_node(foreachCollIdent, new ident("GetEnumerator")), new expression_list()));
//var curr := en.Current;
// Переменная цикла foreach. Есть три варианта:
// 1. foreach x in l do -> curr := en.Current;
// 2. foreach var x in l do -> var curr := en.Current;
// 3. foreach var x: T in l do -> var curr: T := en.Current;
var currentIdent = frch.identifier;
statement st = null;
var curExpr = new dot_node(enumeratorIdent, "Current");
// С типом
if (frch.type_name == null) // 1. foreach x in l do -> curr := en.Current;
{
st = new assign(currentIdent, curExpr);
}
else if (frch.type_name is no_type_foreach) // 2. foreach var x in l do -> var curr := en.Current;
{
// Получаем служебное имя с $ и заменяем его в теле цикла
currentIdent = this.NewVarNames(frch.identifier).VarName;
var replacerVis = new ReplaceVariableNameVisitor(frch.identifier, currentIdent);
frch.visit(replacerVis);
st = new var_statement(currentIdent, curExpr);
}
else // 3. foreach var x: T in l do -> var curr: T := en.Current;
{
// Получаем служебное имя с $ и заменяем его в теле цикла
currentIdent = this.NewVarNames(frch.identifier).VarName;
var replacerVis = new ReplaceVariableNameVisitor(frch.identifier, currentIdent);
frch.visit(replacerVis);
st = new var_statement(currentIdent, frch.type_name, curExpr);
}
// Добавляем тело цикла в stl
var stl = new statement_list(st);
ProcessNode(frch.stmt); // для обработки вложенных конструкций
stl.Add(frch.stmt);
var whileNode = new while_node(new method_call(new dot_node(enumeratorIdent, "MoveNext"), new expression_list()),
stl,
WhileCycleType.While);
var sq = SeqStatements(foreachCollVarDef, ass, enumeratorVarDef, whileNode);
ReplaceStatement(frch, sq);
visit(whileNode); // Lowering оставшегося whileNode
}
private expression CreateConditionFromCaseVariant(expression param, expression_list list)
{
var res = list.expressions.Aggregate(new bool_const(false) as expression, (acc, expr) =>
{
bin_expr currentExpr = null;
diapason_expr diap = expr as diapason_expr;
if (diap != null)
{
currentExpr = new bin_expr(new bin_expr(param, diap.left, Operators.GreaterEqual),
new bin_expr(param, diap.right, Operators.LessEqual),
Operators.LogicalAND);
}
else
{
currentExpr = new bin_expr(param, expr, Operators.Equal);
}
return new bin_expr(acc, currentExpr, Operators.LogicalOR);
});
return res;
}
// frninja 30/05/16
public override void visit(case_node csn)
{
//var b = HasStatementVisitor<yield_node>.Has(csn);
//if (!b)
// return;
/*
*
* case i of
* cv1: bla1;
* cv2: bla2;
* ..
* cvN: blaN;
* else: bla_else;
*
* --->
*
* if i satisfy cv1
* then bla1
* else if i satisfy cv2
* then bla2
* ..
* else if i satisfy cvN
* then blaN
* else bla_else
*
*/
if_node currentIfNode = null;
statement currentIfElseClause = (csn.else_statement != null) ? csn.else_statement : new statement_list(new empty_statement()); ;
for (int i = csn.conditions.variants.Count - 1; i >= 0; --i)
{
case_variant cv = csn.conditions.variants[i];
ProcessNode(cv.exec_if_true);
var ifCondition = this.CreateConditionFromCaseVariant(csn.param, cv.conditions);
currentIfNode = new if_node(ifCondition, new statement_list(cv.exec_if_true), new statement_list(currentIfElseClause));
currentIfElseClause = currentIfNode;
}
if_node finalIfNode = currentIfNode;
if (finalIfNode == null) // SSM - значит, в цикл мы не заходили и у case отсутствуют все ветви кроме else - поскольку yieldы в case есть
{
ReplaceStatement(csn, csn.else_statement);
}
else
ReplaceStatement(csn, finalIfNode);
if (finalIfNode != null)
visit(finalIfNode);
}
public override void visit(if_node ifn)
{
ProcessNode(ifn.then_body);
ProcessNode(ifn.else_body);
//var b = HasStatementVisitor<yield_node>.Has(ifn);
//if (!b)
// return;
var gtAfter = goto_statement.New;
var lbAfter = new labeled_statement(gtAfter.label);
if ((object)ifn.else_body == null)
{
var if0 = new if_node(un_expr.Not(ifn.condition), gtAfter);
//Replace(ifn, SeqStatements(gotoStartIfCondition, ifn.then_body, lbAfter));
ReplaceStatement(ifn, SeqStatements(if0, ifn.then_body, lbAfter));
// в declarations ближайшего блока добавить описание labels
block bl = listNodes.FindLast(x => x is block) as block;
if (bl.defs is null)
bl.defs = new declarations();
bl.defs.Add(new label_definitions(gtAfter.label));
}
else
{
var gtAlt = goto_statement.New;
var lbAlt = new labeled_statement(gtAlt.label, ifn.else_body);
var if0 = new if_node(un_expr.Not(ifn.condition), gtAlt);
ReplaceStatement(ifn, SeqStatements(if0, ifn.then_body, gtAfter, lbAlt, lbAfter));
// в declarations ближайшего блока добавить описание labels
block bl = listNodes.FindLast(x => x is block) as block;
if (bl.defs is null)
bl.defs = new declarations();
bl.defs.Add(new label_definitions(gtAfter.label, gtAlt.label));
}
}
public override void visit(repeat_node rn)
{
//var b = HasStatementVisitor<yield_node>.Has(rn);
//if (!b)
// return;
var gotoContinue = goto_statement.New;
var gotoBreak = goto_statement.New;
ReplaceBreakContinueWithGotoLabelVisitor replaceBreakContinueVis = new ReplaceBreakContinueWithGotoLabelVisitor(gotoContinue, gotoBreak);
rn.statements.visit(replaceBreakContinueVis);
ProcessNode(rn.statements);
var gotoContinueIfNotCondition = new if_node(un_expr.Not(rn.expr), gotoContinue);
var continueLabeledStatement = new labeled_statement(gotoContinue.label, new statement_list(rn.statements, gotoContinueIfNotCondition));
var breakLabeledStatement = new labeled_statement(gotoBreak.label);
ReplaceStatement(rn, SeqStatements(gotoContinue, continueLabeledStatement, breakLabeledStatement));
// в declarations ближайшего блока добавить описание labels
block bl = listNodes.FindLast(x => x is block) as block;
if (bl.defs == null)
bl.defs = new declarations();
bl.defs.Add(new label_definitions(gotoContinue.label, gotoBreak.label));
}
public override void visit(while_node wn)
{
//var b = HasStatementVisitor<yield_node>.Has(wn);
//if (!b)
// return;
var gotoBreak = goto_statement.New;
var gotoContinue = goto_statement.New;
ReplaceBreakContinueWithGotoLabelVisitor replaceBreakContinueVis = new ReplaceBreakContinueWithGotoLabelVisitor(gotoContinue, gotoBreak);
wn.statements.visit(replaceBreakContinueVis);
ProcessNode(wn.statements);
statement if0;
//if (wn.expr is ident && (wn.expr as ident).name.ToLower() == "true")
// if0 = gotoBreak;
//else
if0 = new if_node(un_expr.Not(wn.expr), gotoBreak);
var lb2 = new labeled_statement(gotoContinue.label, if0); // continue
var lb1 = new labeled_statement(gotoBreak.label); // break
ReplaceStatement(wn, SeqStatements(lb2, wn.statements, gotoContinue, lb1));
// в declarations ближайшего блока добавить описание labels
block bl = listNodes.FindLast(x => x is block) as block;
if (bl.defs == null)
bl.defs = new declarations();
bl.defs.Add(new label_definitions(gotoBreak.label, gotoContinue.label));
}
public override void visit(function_lambda_definition fld)
{
// Нельзя Lowerить содержимое лямбды !!! Баг #1641!
}
public override void visit(for_node fn)
{
//var b = HasStatementVisitor<yield_node>.Has(fn);
//if (!b)
// return;
var gotoContinue = goto_statement.New;
var gotoBreak = goto_statement.New;
var gotoStart = goto_statement.New;
ReplaceBreakContinueWithGotoLabelVisitor replaceBreakContinueVis = new ReplaceBreakContinueWithGotoLabelVisitor(gotoContinue, gotoBreak);
fn.statements.visit(replaceBreakContinueVis);
ProcessNode(fn.statements);
var newNames = this.NewVarNames(fn.loop_variable);
var newLoopVar = fn.create_loop_variable ? new ident(newNames.VarName) : fn.loop_variable;
// Нужно заменить fn.loop_variable -> newLoopVar в теле цикла
var replacerVis = new ReplaceVariableNameVisitor(fn.loop_variable, newLoopVar);
fn.visit(replacerVis);
fn.loop_variable = newLoopVar;
var endtemp = new ident(newNames.VarEndName); //new ident(newVarName());
//var ass1 = new var_statement(fn.loop_variable, fn.type_name, fn.initial_value);
//var ass1 = new var_statement(fn.loop_variable, fn.type_name, fn.initial_value);
//var ass2 = new var_statement(endtemp, fn.type_name, fn.finish_value);
// Исправления в связи с #1254 (новый алгоритм)
// цикл for i:=a to b do
// i := a
// if i > b then goto break
//Start: stmts
// if i >= b then goto break
//Continue: Inc(i)
// goto Start
//Break:
// цикл for i:=a downto b do
// i := a
// if i < b then goto break
//Start: stmts
// if i <= b then goto break
//Continue: Dec(i)
// goto Start
//Break:
// frninja 05/06/16 - фиксим для !fn.create_variable
var ass1 = fn.create_loop_variable
? new var_statement(fn.loop_variable, fn.type_name, fn.initial_value) as statement
: new assign(fn.loop_variable, fn.initial_value) as statement;
var if0 = new if_node((fn.cycle_type == for_cycle_type.to) ?
bin_expr.Greater(fn.loop_variable, fn.finish_value) :
bin_expr.Less(fn.loop_variable, fn.finish_value), gotoBreak);
var if1 = new if_node((fn.cycle_type == for_cycle_type.to) ?
bin_expr.GreaterEqual(fn.loop_variable, fn.finish_value) :
bin_expr.LessEqual(fn.loop_variable, fn.finish_value), gotoBreak);
var lb1 = new labeled_statement(gotoStart.label);
var lb2 = new labeled_statement(gotoBreak.label); // пустой оператор
var Inc = new procedure_call(new method_call((fn.cycle_type == for_cycle_type.to) ?
new ident("Inc") :
new ident("Dec"), new expression_list(fn.loop_variable)));
var lbInc = new labeled_statement(gotoContinue.label, Inc);
ReplaceStatement(fn, SeqStatements(ass1, if0, lb1, fn.statements, if1, lbInc, gotoStart, lb2));
/*var if0 = new if_node((fn.cycle_type == for_cycle_type.to) ?
bin_expr.Greater(fn.loop_variable, fn.finish_value) :
bin_expr.Less(fn.loop_variable, fn.finish_value), gotoBreak);
var lb2 = new labeled_statement(gotoStart.label, if0);
var lb1 = new labeled_statement(gotoBreak.label); // пустой оператор
var Inc = new procedure_call(new method_call((fn.cycle_type == for_cycle_type.to) ?
new ident("Inc") :
new ident("Dec"), new expression_list(fn.loop_variable)));
var lbInc = new labeled_statement(gotoContinue.label, Inc);
ReplaceStatement(fn, SeqStatements(ass1, lb2, fn.statements, lbInc, gotoStart, lb1));*/
// в declarations ближайшего блока добавить описание labels
block bl = listNodes.FindLast(x => x is block) as block;
if (bl.defs == null)
bl.defs = new declarations();
bl.defs.Add(new label_definitions(gotoContinue.label, gotoBreak.label, gotoStart.label));
}
/*
public override void visit(for_node fn)
{
* initializer;
* goto end;
* start:
* body;
* continue:
* increment;
* end:
* GotoIfTrue condition start;
* break:
var b = HasStatementVisitor<yield_node>.Has(fn);
if (!b)
return;
var gotoStart = goto_statement.New;
var gotoEnd = goto_statement.New;
var gotoStart = goto_statement.New;
var gotoBreak = goto_statement.New;
ReplaceBreakContinueWithGotoLabelVisitor replaceBreakContinueVis = new ReplaceBreakContinueWithGotoLabelVisitor(gotoStart, gotoBreak);
fn.statements.visit(replaceBreakContinueVis);
ProcessNode(fn.statements);
var newNames = this.NewVarNames(fn.loop_variable);
var newLoopVar = fn.create_loop_variable ? new ident(newNames.VarName) : fn.loop_variable;
// Нужно заменить fn.loop_variable -> newLoopVar в теле цикла
var replacerVis = new ReplaceVariableNameVisitor(fn.loop_variable, newLoopVar);
fn.visit(replacerVis);
fn.loop_variable = newLoopVar;
var endtemp = new ident(newNames.VarEndName); //new ident(newVarName());
//var initializer = new var_statement(fn.loop_variable, fn.type_name, fn.initial_value);
//var initializer = new var_statement(fn.loop_variable, fn.type_name, fn.initial_value);
//var ass2 = new var_statement(endtemp, fn.type_name, fn.finish_value);
// frninja 05/06/16 - фиксим для !fn.create_variable
var initializer = fn.create_loop_variable
? new var_statement(fn.loop_variable, fn.type_name, fn.initial_value) as statement
: new assign(fn.loop_variable, fn.initial_value) as statement;
var gotoStartIfCondition = new if_node((fn.cycle_type == for_cycle_type.to) ?
new bin_expr(fn.loop_variable, fn.finish_value, Operators.LessEqual) :
new bin_expr(fn.loop_variable, fn.finish_value, Operators.GreaterEqual), gotoStart);
var endLabeledStatement = new labeled_statement(gotoEnd.label, gotoStartIfCondition);
var startLabeledStatement = new labeled_statement(gotoStart.label, fn.statements);
var Inc = new procedure_call(new method_call((fn.cycle_type == for_cycle_type.to) ?
new ident("Inc") :
new ident("Dec"), new expression_list(fn.loop_variable)));
var continueLabeledStatement = new labeled_statement(gotoStart.label, Inc);
var breakLabeledStatement = new labeled_statement(gotoBreak.label);
ReplaceStatement(fn, SeqStatements(initializer, gotoEnd, startLabeledStatement, continueLabeledStatement, endLabeledStatement, breakLabeledStatement));
// в declarations ближайшего блока добавить описание labels
block bl = listNodes.FindLast(x => x is block) as block;
bl.defs.Add(new label_definitions(gotoStart.label, gotoEnd.label, gotoStart.label, gotoBreak.label));
}*/
}
}

View file

@ -0,0 +1,29 @@
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;
public static MainVisitor New
{
get { return new MainVisitor(); }
}
public static void Accept(statement_list st)
{
New.ProcessNode(st);
}
public override void visit(await_node_statement ans)
{
flag = true;
}
public override void visit(await_node aw)
{
flag = true;
}
}
}

View file

@ -0,0 +1,43 @@
using PascalABCCompiler.SyntaxTree;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SyntaxVisitors.Async
{
public class ReplaceVarNamesVisitor: BaseChangeVisitor
{
private string _oldName;
private string _newName;
public int counter = 0;
public ReplaceVarNamesVisitor(ident oldName, ident newName)
{
_oldName = oldName.name;
_newName = newName.name;
counter = 0;
}
public override void visit(ident id)
{
//if (id.name != _oldName)
//{
// return;
//}
//id.name = _newName;
if (id.name == _oldName)
{
id.name = _newName;
counter++;
}
}
public override void visit(try_stmt tr)
{
ProcessNode(tr.stmt_list);
}
}
}

View file

@ -0,0 +1,78 @@
using PascalABCCompiler.SyntaxTree;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SyntaxVisitors.Async
{
public class VarsHelper
{
public HashSet<var_statement> VarsList = new HashSet<var_statement>();
public HashSet<var_statement> TypedVarsList = new HashSet<var_statement>();
public HashSet<var_statement> NoneTypedVarsList = new HashSet<var_statement>();
public HashSet<string> Parametrs = new HashSet<string>();
public HashSet<string> ExprHash = new HashSet<string>();
public HashSet<var_statement> TasksHash = new HashSet<var_statement>();
public Dictionary<string,string> RepVarsDict = new Dictionary<string,string>();
public HashSet<string> ClassIdentSet = new HashSet<string>();
public HashSet<string> ClassStaticSet = new HashSet<string>();
public Dictionary<string, string> TaskIdents = new Dictionary<string, string>();
int k = 0;
public VarsHelper()
{
}
public string newLabelName(string old)
{
k++;
return "@awvar@_" + k.ToString() +"_" + old;
}
public void AddNewRep(var_statement var_Statement)
{
foreach (var v in var_Statement.var_def.vars.list)
if (!RepVarsDict.ContainsKey(v.name))
{
if (v.name.StartsWith("@"))
{
//RepVarsDict.Add(v.name, v.name);
continue;
}
var nv = newLabelName(v.name);
RepVarsDict.Add(v.name, nv);
v.name = nv;
}
}
public void MarkVars()
{
foreach (var var in VarsList)
{
var v = var.var_def;
if (v.vars_type != null)
TypedVarsList.Add(var);
else
NoneTypedVarsList.Add(var);
var vd = var.var_def;
if (ExprHash.Contains(vd.vars.list[0].name))
{
TasksHash.Add(var);
}
}
}
}
}

View file

@ -43,6 +43,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AllVarsInProcYieldsProba.cs" />
<Compile Include="Async\AsyncBuilder.cs" />
<Compile Include="Async\AsyncVisitor.cs" />
<Compile Include="Async\AwaitBuilder.cs" />
<Compile Include="Async\LoweringAsyncVisitor.cs" />
<Compile Include="Async\MainVisitor.cs" />
<Compile Include="Async\ReplaceVarNamesVisitor.cs" />
<Compile Include="Async\VarsHelper.cs" />
<Compile Include="BaseSyntaxTreeConverter.cs" />
<Compile Include="BaseVisitors\CollectNamespaces.cs" />
<Compile Include="BaseVisitors\HasStatementVisitor.cs" />