async/await
This commit is contained in:
parent
bda964c3af
commit
155d0a01ba
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%COREVERSION%=0
|
||||
%REVISION%=3488
|
||||
%MINOR%=9
|
||||
%REVISION%=3489
|
||||
%COREVERSION%=0
|
||||
%MAJOR%=3
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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
BIN
Languages/Pascal/PascalABCParserNewSaushkin/PABC.back
Normal file
BIN
Languages/Pascal/PascalABCParserNewSaushkin/PABC.back
Normal file
Binary file not shown.
|
|
@ -379,5 +379,6 @@ script=
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.9.0.3488
|
||||
3.9.0.3489
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
!define VERSION '3.9.0.3488'
|
||||
!define VERSION '3.9.0.3489'
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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="Бинарное выражение" />
|
||||
|
|
|
|||
401
SyntaxVisitors/Async/AsyncBuilder.cs
Normal file
401
SyntaxVisitors/Async/AsyncBuilder.cs
Normal 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;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
216
SyntaxVisitors/Async/AsyncVisitor.cs
Normal file
216
SyntaxVisitors/Async/AsyncVisitor.cs
Normal 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();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
750
SyntaxVisitors/Async/AwaitBuilder.cs
Normal file
750
SyntaxVisitors/Async/AwaitBuilder.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
522
SyntaxVisitors/Async/LoweringAsyncVisitor.cs
Normal file
522
SyntaxVisitors/Async/LoweringAsyncVisitor.cs
Normal 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));
|
||||
}*/
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
29
SyntaxVisitors/Async/MainVisitor.cs
Normal file
29
SyntaxVisitors/Async/MainVisitor.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
SyntaxVisitors/Async/ReplaceVarNamesVisitor.cs
Normal file
43
SyntaxVisitors/Async/ReplaceVarNamesVisitor.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
SyntaxVisitors/Async/VarsHelper.cs
Normal file
78
SyntaxVisitors/Async/VarsHelper.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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" />
|
||||
|
|
|
|||
Loading…
Reference in a new issue