Множество правок, связанных с yield.

В частности, изменен алгоритм генерации конечного автомата, поправлен код для GetEnumerator и проч.
This commit is contained in:
miks1965 2016-07-08 23:20:56 +03:00
parent d635ad0d51
commit c6eaba8f94
22 changed files with 508 additions and 74 deletions

View file

@ -470,7 +470,7 @@ namespace CodeCompletion
List<SymInfo> result_names = new List<SymInfo>();
if (elems == null) return null;
for (int i=0; i<elems.Length; i++)
if (pattern != null || pattern != "")
if (pattern != null && pattern != "")
{
if (!elems[i].name.StartsWith("$"))
if (all_names)

View file

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

View file

@ -1,4 +1,4 @@
%MINOR%=1
%REVISION%=1256
%COREVERSION%=0
%REVISION%=1263
%MINOR%=1
%MAJOR%=3

View file

@ -401,6 +401,8 @@ namespace PascalABCCompiler.NETGenerator
private void AddTypeInstanceToFunction(ICommonFunctionNode func, IGenericTypeInstance gti)
{
List<IGenericTypeInstance> instances;
//if (func == null) // SSM 3.07.16 Это решает проблему с оставшимся после перевода в сем. дерево узлом IEnumerable<UnknownType>, но очень грубо - пробую найти ошибку раньше
// return;
bool found = instances_in_functions.TryGetValue(func, out instances);
if (!found)
{

View file

@ -803,6 +803,181 @@
</i>
</OCtx>
</Node>
<Node Name="private Dictionary&lt;Guid, semantic_type_node&gt;">
<FileName>\treeconverter\treeconversion\syntax_tree_visitor.cs</FileName>
<Text>private Dictionary&lt;Guid, semantic_type_node&gt; _yieldForeachTypeMap = new Dictionary&lt;Guid, semantic_type_node&gt;();</Text>
<OCtx>
<i Type="Field">private Dictionary &lt; Guid , semantic_type_node &gt; _yieldForeachTypeMap = new Dictionary &lt; Guid , semantic_type_node &gt; ( )</i>
<i Type="ClassOrNamespace">public class syntax_tree_visitor : SyntaxTree . AbstractVisitor</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeConverter</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="UnknownExprType">
<Items>
<Node Name=" visit(yield_unknown_expression_type">
<FileName>\treeconverter\treeconversion\syntax_tree_visitor.cs</FileName>
<Text>public override void visit(SyntaxTree.yield_unknown_expression_type _unk_expr)</Text>
<OCtx>
<i Type="Method">public override void visit ( SyntaxTree . yield_unknown_expression_type _unk_expr )</i>
<i Type="ClassOrNamespace">public class syntax_tree_visitor : SyntaxTree . AbstractVisitor</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeConverter</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="visit(SyntaxTree.assign">
<FileName>\treeconverter\treeconversion\syntax_tree_visitor.cs</FileName>
<Text>public override void visit(SyntaxTree.assign _assign)</Text>
<OCtx>
<i Type="Method">public override void visit ( SyntaxTree . assign _assign )</i>
<i Type="ClassOrNamespace">public class syntax_tree_visitor : SyntaxTree . AbstractVisitor</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeConverter</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name=" TypeInfo ti = helper.GetTypeReference(value.type);">
<FileName>\netgenerator\netgenerator.cs</FileName>
<Text>TypeInfo ti = helper.GetTypeReference(value.type);</Text>
<OCtx>
<i Type="Method">public override void visit ( SemanticTree . ICommonClassFieldNode value )</i>
<i Type="ClassOrNamespace">public class ILConverter : AbstractVisitor</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . NETGenerator</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
</Items>
</Node>
<Node Name="UnknownForeachType">
<Items>
<Node Name="visit(yield_unknown_foreach_type">
<FileName>\treeconverter\treeconversion\syntax_tree_visitor.cs</FileName>
<Text>public override void visit(SyntaxTree.yield_unknown_foreach_type _unk)</Text>
<OCtx>
<i Type="Method">public override void visit ( SyntaxTree . yield_unknown_foreach_type _unk )</i>
<i Type="ClassOrNamespace">public class syntax_tree_visitor : SyntaxTree . AbstractVisitor</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeConverter</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="stl.Add(new assign(currentIdent">
<FileName>\yield\syntaxvisitors\yieldvisitors\loweringvisitor.cs</FileName>
<Text>stl.Add(new assign(currentIdent, new dot_node(enumeratorIdent, "Current")));</Text>
<OCtx>
<i Type="Method">public override void visit ( foreach_stmt frch )</i>
<i Type="ClassOrNamespace">public class LoweringVisitor : BaseChangeVisitor</i>
<i Type="ClassOrNamespace">namespace SyntaxVisitors</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="visit(SyntaxTree.assign">
<FileName>\TreeConverter\TreeConversion\syntax_tree_visitor.cs</FileName>
<Text>public override void visit(SyntaxTree.assign _assign)</Text>
<OCtx>
<i Type="Method">public override void visit ( SyntaxTree . assign _assign )</i>
<i Type="ClassOrNamespace">public class syntax_tree_visitor : SyntaxTree . AbstractVisitor</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeConverter</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="if (to.type is compiled_type_node)">
<FileName>\TreeConverter\TreeConversion\syntax_tree_visitor.cs</FileName>
<Text>else if (to.type is compiled_type_node)</Text>
<OCtx>
<i Type="Method">public override void visit ( SyntaxTree . assign _assign )</i>
<i Type="ClassOrNamespace">public class syntax_tree_visitor : SyntaxTree . AbstractVisitor</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeConverter</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="FindIEnumerableElementType">
<FileName>\TreeConverter\TreeConversion\syntax_tree_visitor.cs</FileName>
<OCtx>
<i Type="Method">public bool FindIEnumerableElementType ( type_node tn , ref type_node elem_type )</i>
<i Type="ClassOrNamespace">public class syntax_tree_visitor : SyntaxTree . AbstractVisitor</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeConverter</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="generic_convertions.all_type_instances.Add(instance);">
<FileName>\TreeConverter\TreeRealization\generics.cs</FileName>
<Text>generic_convertions.all_type_instances.Add(instance);</Text>
<OCtx>
<i Type="Method">public static void init_generic_instance ( type_node original , generic_instance_type_node instance , List &lt; type_node &gt; param_types )</i>
<i Type="ClassOrNamespace">public static class generic_convertions</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeRealization</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="if (shouldAddToAllTypeInstances)">
<FileName>\TreeConverter\TreeRealization\generics.cs</FileName>
<Text>if (shouldAddToAllTypeInstances) //lroman// Если зашли сюда при выведении типов параметров лямбды, то тип инстанцироваться может с типом lambda_any_type_node. Поэтому, если выводим типы. То данную инстанцию не добавляем</Text>
<OCtx>
<i Type="Method">public static void init_generic_instance ( type_node original , generic_instance_type_node instance , List &lt; type_node &gt; param_types )</i>
<i Type="ClassOrNamespace">public static class generic_convertions</i>
<i Type="ClassOrNamespace">namespace PascalABCCompiler . TreeRealization</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="ConstructFiniteAutomata">
<FileName>\yield\syntaxvisitors\yieldvisitors\processyieldscapturedvars.cs</FileName>
<OCtx>
<i Type="ClassOrNamespace">class ConstructFiniteAutomata</i>
<i Type="ClassOrNamespace">namespace SyntaxVisitors</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
<ICtx>
<i Type="Field">public statement_list res = new statement_list ( )</i>
<i Type="Field">statement_list stl</i>
<i Type="Field">int curState = 0</i>
<i Type="Field">statement_list curStatList</i>
<i Type="Field">statement_list StatListAfterCase = new statement_list ( )</i>
<i Type="Field">case_node cas</i>
<i Type="Field">private labeled_statement OuterLabeledStatement</i>
<i Type="Field">private Dictionary &lt; int , labeled_statement &gt; Dispatches = new Dictionary &lt; int , labeled_statement &gt; ( )</i>
<i Type="Method">public ConstructFiniteAutomata ( statement_list stl )</i>
<i Type="Method">private void AddState ( out int stateNumber , out ident resumeLabel )</i>
</ICtx>
</Node>
</Items>
</Node>
<Node Name="NewConstructFiniteAutomata">
<Items>
<Node Name="ConstructFiniteAutomata1">
<FileName>\yield\syntaxvisitors\yieldvisitors\processyieldscapturedvars.cs</FileName>
<Text>public ConstructFiniteAutomata1(block bl)</Text>
<OCtx>
<i Type="Method">public ConstructFiniteAutomata1 ( block bl )</i>
<i Type="ClassOrNamespace">class ConstructFiniteAutomata1</i>
<i Type="ClassOrNamespace">namespace SyntaxVisitors</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
<Node Name="GenClassesForYield">
<FileName>\yield\syntaxvisitors\yieldvisitors\processyieldscapturedvars.cs</FileName>
<Text>type_declarations GenClassesForYield(procedure_definition pd,</Text>
<OCtx>
<i Type="Method">type_declarations GenClassesForYield ( procedure_definition pd , IEnumerable &lt; var_def_statement &gt; fields , IDictionary &lt; string , string &gt; localsMap , IDictionary &lt; string , string &gt; formalParamsMap , IDictionary &lt; var_def_statement , var_def_statement &gt; localsCloneMap , yield_locals_type_map_helper localTypeMapHelper )</i>
<i Type="ClassOrNamespace">public class ProcessYieldCapturedVarsVisitor : BaseChangeVisitor</i>
<i Type="ClassOrNamespace">namespace SyntaxVisitors</i>
<i Type="CS_TreeNode">
</i>
</OCtx>
</Node>
</Items>
</Node>
</Items>
</Node>
</Items>

View file

@ -1 +1 @@
!define VERSION '3.1.0.1256'
!define VERSION '3.1.0.1263'

View file

@ -708,7 +708,8 @@ namespace PascalABCCompiler.SyntaxTree
sb.Remove(0, 9);
sb.Remove(sb.Length - 1, 1);
sb.Insert(0, "function");
sb.Append(": " + return_type.ToString() + ";");
if (return_type!=null)
sb.Append(": " + return_type.ToString() + ";");
return sb.ToString();
}
}
@ -1445,6 +1446,25 @@ namespace PascalABCCompiler.SyntaxTree
this.vars = vds;
this.map_helper = map_helper;
}
public override string ToString()
{
var sb = new System.Text.StringBuilder();
sb.Append(vars.ToString());
/*if (vars_type != null)
{
sb.Append(": ");
sb.Append(vars_type.ToString());
}
if (inital_value != null)
{
sb.Append(" := ");
sb.Append(inital_value.ToString());
}*/
return sb.ToString();
}
}
public partial class yield_variable_definitions_with_unknown_type : declaration
@ -1579,5 +1599,13 @@ namespace PascalABCCompiler.SyntaxTree
{
}
public partial class array_type
{
public override string ToString()
{
return "array of " + this.elements_type.ToString();
}
}
}

Binary file not shown.

View file

@ -1,10 +0,0 @@
function f: sequence of integer;
begin
var t := Seq(1,3,5);
foreach var k in t do
yield k;
end;
begin
Assert(f.SequenceEqual(Seq(1,3,5)));
end.

View file

@ -416,7 +416,7 @@ namespace TreeConverter.LambdaExpressions.Closure
if (inWhat.type == null)
inWhat = tmp;
_visitor.FindIEnumerableElementType(_foreach_stmt, inWhat.type, ref elemType);
_visitor.FindIEnumerableElementType(/*_foreach_stmt, */inWhat.type, ref elemType);
if (_foreach_stmt.type_name == null)
{

View file

@ -363,6 +363,8 @@ namespace PascalABCCompiler.TreeConverter
public static string record_const_type_name = "RecordConst";
public static string array_const_type_name = "ArrayConst";
public static string auto_type_name = "AutoType"; // SSM 25.06.16 - тип, который определяется на этапе компиляции при первом присваивании
public static string ienumerable_auto_type_name = "IEnumerableAutoType"; // SSM 05.07.16 - тип, который определяется на этапе компиляции при первом присваивании
public static string recort_printable_name_template = "record{0}end";
public static string set_name = "TypedSet";

View file

@ -15725,6 +15725,50 @@ namespace PascalABCCompiler.TreeConverter
else
{
from = convert_strong(_assign.from);
// SSM 26.06.16 - правка в связи с автовыведением типов в yieldах
if (to.type is auto_type)
{
if (to is class_field_reference)
{
var cfr = to as class_field_reference;
cfr.field.type = from.type;
cfr.type = from.type;
}
else if (to is local_block_variable_reference)
{
var lvr = to as local_block_variable_reference;
lvr.var.type = from.type;
lvr.type = from.type;
}
else AddError(to.location, "Не могу вывести тип при наличии yield: "+ to.type.full_name);
//to.type = from.type; // и без всякого real_type!
}
//else if (to.type is compiled_type_node)
//else if (to.type.name.StartsWith("IEnumerable<IEnumerableAutoType>")) // Сделать не сравнением строк!!!
else if (to.type is compiled_generic_instance_type_node && (to.type as compiled_generic_instance_type_node).instance_params[0] is ienumerable_auto_type)
{
var tt = to.type;
type_node elem_type = null;
var b = FindIEnumerableElementType(from.type, ref elem_type);
if (!b)
AddError(null, "FindIEnumerableElementType returns false");
var IEnumType = new template_type_reference(new named_type_reference("System.Collections.Generic.IEnumerable"), new template_param_list(new semantic_type_node(elem_type)));
if (to is class_field_reference)
{
var cfr = to as class_field_reference;
cfr.field.type = convert_strong(IEnumType);
cfr.type = cfr.field.type;
}
else if (to is local_block_variable_reference)
{
var lvr = to as local_block_variable_reference;
lvr.var.type = convert_strong(IEnumType); // замена типа у описания переменной
lvr.type = lvr.var.type; // замена типа у переменной
}
}
}
/// end
@ -16300,7 +16344,7 @@ namespace PascalABCCompiler.TreeConverter
return false;
}
public bool FindIEnumerableElementType(SyntaxTree.foreach_stmt _foreach_stmt, type_node tn, ref type_node elem_type)
public bool FindIEnumerableElementType(/*SyntaxTree.foreach_stmt _foreach_stmt, */type_node tn, ref type_node elem_type)
{
var IEnstring = "System.Collections.IEnumerable";
compiled_type_node ctn = compiled_type_node.get_type_node(NetHelper.NetHelper.FindType(IEnstring));
@ -16465,7 +16509,7 @@ namespace PascalABCCompiler.TreeConverter
in_what = tmp;
//if (in_what.type.find_in_type("GetEnumerator") == null)
if (!FindIEnumerableElementType(_foreach_stmt, in_what.type, ref elem_type))
if (!FindIEnumerableElementType(/*_foreach_stmt, */in_what.type, ref elem_type))
//if (!IsGetEnumerator(in_what.type, ref elem_type))
AddError(in_what.location, "CAN_NOT_EXECUTE_FOREACH_BY_EXPR_OF_TYPE_{0}", in_what.type.name);
@ -19054,13 +19098,17 @@ namespace PascalABCCompiler.TreeConverter
public override void visit(SyntaxTree.yield_unknown_expression_type _unk_expr)
{
_unk_expr.MapHelper.vars_type_map[_unk_expr.Vds].visit(this);
// Отвечает за типизацию всех переменных с автовыведением типа
// Пробую сделать по-другому: перевести в auto_type и потом на присваивании перехватить
// _unk_expr.MapHelper.vars_type_map[_unk_expr.Vds].visit(this);
var t = new semantic_type_node(new auto_type(get_location(_unk_expr)));
t.visit(this);
}
// frninja - заполнение хелпера типов локальных переменных для yield
public override void visit(SyntaxTree.yield_var_def_statement_with_unknown_type _vars)
{
if ((object)_vars.vars.vars_type != null)
/*if ((object)_vars.vars.vars_type != null)
{
// Visit stored vars
_vars.vars.visit(this);
@ -19069,6 +19117,7 @@ namespace PascalABCCompiler.TreeConverter
var t = convert_strong(_vars.vars.inital_value);
_vars.map_helper.vars_type_map[_vars.vars] = new SyntaxTree.semantic_type_node(t.type);
*/
// Visit stored vars
_vars.vars.visit(this);
}
@ -19076,7 +19125,7 @@ namespace PascalABCCompiler.TreeConverter
// frninja - заполнение хелпера типов локальных переменных для yield// frninja - заполнение хелпера типов локальных переменных для yield
public override void visit(SyntaxTree.yield_variable_definitions_with_unknown_type _vars)
{
foreach (var vd in _vars.vars.list)
/*foreach (var vd in _vars.vars.list)
{
if ((object)vd.vars_type != null)
{
@ -19084,7 +19133,7 @@ namespace PascalABCCompiler.TreeConverter
}
var t = convert_strong(vd.inital_value);
_vars.map_helper.vars_type_map[vd] = new SyntaxTree.semantic_type_node(t.type);
}
}*/
// Visit stored vars
_vars.vars.visit(this);
@ -19096,7 +19145,7 @@ namespace PascalABCCompiler.TreeConverter
public override void visit(SyntaxTree.yield_unknown_foreach_type _unk)
{
var _foreach_stmt = _unk.unknown_foreach;
/*var _foreach_stmt = _unk.unknown_foreach;
semantic_type_node t;
@ -19115,8 +19164,10 @@ namespace PascalABCCompiler.TreeConverter
t = new SyntaxTree.semantic_type_node(elem_type);
// Add to map
_yieldForeachTypeMap.Add(_foreach_stmt.Guid, t);
}
}*/
// Visit type
var t = new semantic_type_node(new ienumerable_auto_type(get_location(_unk)));
t.visit(this);
}

View file

@ -344,7 +344,16 @@ namespace PascalABCCompiler.TreeRealization
}
if (shouldAddToAllTypeInstances) //lroman// Если зашли сюда при выведении типов параметров лямбды, то тип инстанцироваться может с типом lambda_any_type_node. Поэтому, если выводим типы. То данную инстанцию не добавляем
generic_convertions.all_type_instances.Add(instance);
{
if (instance.instance_params[0] is ienumerable_auto_type)
{
//instance = instance;
}
else
{
generic_convertions.all_type_instances.Add(instance);
}
}
internal_interface ii = original.get_internal_interface(internal_interface_kind.delegate_interface);
if (ii != null)

View file

@ -4809,4 +4809,22 @@ namespace PascalABCCompiler.TreeRealization
}
}
// тип, который объявляется как auto и определяется при компиляции в момент первого присваивания
// На 04.07.16 нужен только для генерации кода yield
public class auto_type : undefined_type
{
//public type_node real_type = null;
public auto_type(location loc)
: base(compiler_string_consts.auto_type_name, loc) { }
}
// тип, который объявляется как ienumerable_auto и определяется при компиляции в момент первого присваивания
// На 04.07.16 нужен только для генерации кода yield
public class ienumerable_auto_type : undefined_type
{
//public type_node real_type = null;
public ienumerable_auto_type(location loc)
: base(compiler_string_consts.ienumerable_auto_type_name, loc) { }
}
}

View file

@ -208,7 +208,7 @@ namespace VisualPascalABC.Utils
{
return null;
}
return null;
//return null;
}
public string TempBatFile = null;
public void Start(string command, string arguments, bool redirectIO, bool redirectErrors, bool RunWithPause, bool attachDebugger, bool fictive_attach)

View file

@ -378,7 +378,7 @@ namespace Converter
{
if (_word.Contains(specSymbol))
{
_word.Replace(specSymbol, "");
_word = _word.Replace(specSymbol, "");
return getWordValue(_word, specSymbol);
}
else

View file

@ -32,6 +32,8 @@ namespace SyntaxVisitors
OnEnter = Enter;
OnLeave = Exit;
this.filename = filename;
if (filename != null)
System.IO.File.Delete(filename);
}
public void Println(string s)
@ -44,6 +46,7 @@ namespace SyntaxVisitors
}
public void PrintNoOffset(string s)
{
s = s.Replace("PascalABCCompiler.SyntaxTree.", "").Replace("System.Collections.Generic.", "");
if (filename == null)
{
Console.Write(s);
@ -64,6 +67,8 @@ namespace SyntaxVisitors
PrintNoOffset(st.GetType().Name + ": ");
Println(""+st);
}
public virtual void Enter(syntax_tree_node st)
{
if (st is statement_list)
@ -101,10 +106,8 @@ namespace SyntaxVisitors
{
var cd = st as class_definition;
PrintNoOffset("class");
if (cd.class_parents != null && cd.class_parents.types.Count > 0)
{
if (cd.class_parents?.types.Count > 0)
PrintlnNoOffset("(" + cd.class_parents.ToString() + ")");
}
else
PrintlnNoOffset("");
off += 2;
@ -114,23 +117,36 @@ namespace SyntaxVisitors
else if (st is access_modifer_node)
{
var am = st as access_modifer_node;
Println(am.access_level.ToString());
Println(am.access_level.ToString().Replace("_modifier",""));
}
else if (st is variable_definitions)
{
var vds = st as variable_definitions;
Println("var");
Print("var");
off += 2;
}
else if (st is var_def_statement)
{
var vds = st as var_def_statement;
Println(vds.ToString());
Println (vds.ToString());
}
else if (st is empty_statement || st is declarations || st is block || st is class_body || st is class_members || st is case_variants || st is program_module)
else if (st is yield_var_def_statement_with_unknown_type)
{
var vds = st as yield_var_def_statement_with_unknown_type;
Println("var "+vds.ToString());
visitNode = false;
}
else if (st is empty_statement || st is declarations || st is block || st is class_body || st is class_members
|| st is case_variants || st is program_module || st is no_type_foreach || st is template_param_list
|| st is yield_unknown_foreach_type || st is yield_unknown_expression_type
)
{
}
/* else if (st is array_type)
{
var vds = st as array_type;
Println ("array of "+vds.elements_type.ToString());
}*/
else if (st is if_node)
{
var ifn = st as if_node;
@ -156,6 +172,13 @@ namespace SyntaxVisitors
Println("while " + wn.expr.ToString() + " do");
off += 2;
}
else if (st is foreach_stmt)
{
var wn = st as foreach_stmt;
Println("foreach " + wn.identifier.ToString() + " in "+wn.in_what + " do");
off += 2;
}
else if (st is case_node)
{
var cn = st as case_node;
@ -173,7 +196,10 @@ namespace SyntaxVisitors
}
else if (st is var_statement || st is procedure_header)
{
Println(st.ToString());
var s = st.ToString();
s = s.Replace("PascalABCCompiler.SyntaxTree.", "").Replace("System.Collections.Generic.","");
Println(s);
visitNode = false;
}
else if (st is procedure_definition)
@ -193,6 +219,13 @@ namespace SyntaxVisitors
return;
PrintlnNode(st);
}
/*else if (st is named_type_reference)
{
var s = st.ToString();
s = s.Replace("PascalABCCompiler.SyntaxTree.", "").Replace("System.Collections.Generic.","");
PrintlnNoOffset(s);
}*/
else
{
var q = st.GetType().GetMethod("ToString", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);

View file

@ -34,6 +34,7 @@ namespace SyntaxVisitors
}
private int _varnum = 0;
private int _foreachCollectionNum = 0;
private int _enumeratorNum = 0;
private VarNames NewVarNames(ident name)
@ -52,6 +53,12 @@ namespace SyntaxVisitors
return "$enumerator$" + _enumeratorNum;
}
private ident NewForeachCollectionName()
{
++_foreachCollectionNum;
return "$coll$" + _foreachCollectionNum;
}
public static void Accept(procedure_definition pd)
{
New.ProcessNode(pd);
@ -81,63 +88,99 @@ namespace SyntaxVisitors
// 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;
type_definition currentIdentType = null;
statement st = null;
// Новое тело
var stl = new statement_list();
var curExpr = new dot_node(enumeratorIdent, "Current");
// С типом
if (frch.type_name == null)
if (frch.type_name == null) // 1. foreach x in l do -> curr := en.Current;
{
// Внешнее имя, создавать ниче не надо
st = new assign(currentIdent, curExpr);
}
else
else if (frch.type_name is no_type_foreach) // 2. foreach var x in l do -> var curr := en.Current;
{
// var имеет место быть
if (frch.type_name is no_type_foreach)
{
// автовывод
currentIdentType = new yield_unknown_foreach_type(frch);
}
else
{
currentIdentType = frch.type_name;
}
// Получаем служебное имя с $ и заменяем его в теле цикла
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);
// Создаем переменную цикла и добавляем в stl
stl.Add(new var_statement(currentIdent, currentIdentType));
st = new var_statement(currentIdent, frch.type_name, curExpr);
}
// Получаем служебное имя с $ и заменяем его в теле цикла
//currentIdent = this.NewVarNames(frch.identifier).VarName;
//var replacerVis = new ReplaceVariableNameVisitor(frch.identifier, currentIdent);
//frch.visit(replacerVis);
// Создаем переменную цикла и добавляем в stl
//stl.Add(new var_statement(currentIdent, currentIdentType));
// Новое тело
//stl.Add(st);
// SSM вернул всё назад 26.06.16
// Добавляем $current$ = $enumerator$.Current
//stl.Add(new assign(currentIdent, new dot_node(enumeratorIdent, "Current")));
stl.Add(new assign(currentIdent, new method_call(new yield_unknown_foreach_type_ident(frch), new expression_list(new dot_node(enumeratorIdent, "Current")))));
//var curExpr = new dot_node(enumeratorIdent, "Current");
//stl.Add(new assign(currentIdent, new method_call(new yield_unknown_foreach_type_ident(frch), new expression_list(new dot_node(enumeratorIdent, "Current")))));
// Добавляем тело цикла в stl
ProcessNode(frch.stmt);
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);
ReplaceStatement(frch,
/*ReplaceStatement(frch,
SeqStatements(new var_statement(enumeratorIdent,
new named_type_reference("System.Collections.IEnumerator"),
// НЕБЕЗОПАСНО!
new method_call(new dot_node(frch.in_what as addressed_value, new ident("GetEnumerator")), new expression_list())),
whileNode));
*/
ReplaceStatement(frch,
SeqStatements(foreachCollVarDef, ass, enumeratorVarDef, whileNode)
);
}

View file

@ -153,6 +153,8 @@ namespace SyntaxVisitors
cm.Add(new var_def_statement(YieldConsts.Self, iteratorClassRef));
}
var GetEnumeratorBody = new statement_list();
// Системные поля и методы для реализации интерфейса IEnumerable
cm.Add(new var_def_statement(YieldConsts.State, "integer"),
new var_def_statement(YieldConsts.Current, stels),
@ -160,12 +162,10 @@ namespace SyntaxVisitors
new procedure_definition("Reset"),
new procedure_definition("MoveNext", "boolean", pd.proc_body),
new procedure_definition("System.Collections.IEnumerator.get_Current", "object", new assign("Result", YieldConsts.Current)),
new procedure_definition("System.Collections.IEnumerable.GetEnumerator", "System.Collections.IEnumerator", new assign("Result", "Self"))
//new procedure_definition("System.Collections.IEnumerable.GetEnumerator", "System.Collections.IEnumerator", new assign("Result", "Self"))
new procedure_definition("System.Collections.IEnumerable.GetEnumerator", "System.Collections.IEnumerator", GetEnumeratorBody)
);
// frninja 20/04/16 - поддержка шаблонных классов
var yieldClassName = NewYieldClassName();
var yieldClassHelperName = yieldClassName + "Helper";
@ -242,7 +242,7 @@ namespace SyntaxVisitors
var cm1 = cm.Add( //class_members.Public.Add(
//procedure_definition.EmptyDefaultConstructor,
new procedure_definition(new function_header("get_Current", stels), new assign("Result", YieldConsts.Current)),
new procedure_definition(new function_header("GetEnumerator", IEnumeratorT), new assign("Result", "Self")),
new procedure_definition(new function_header("GetEnumerator", IEnumeratorT), GetEnumeratorBody),
new procedure_definition("Dispose")
);
@ -260,10 +260,27 @@ namespace SyntaxVisitors
helperClassDefinition.where_section = this.GetMethodWhereSection(pd);
var td1 = new type_declaration(className, helperClassDefinition);
//SyntaxTreeBuilder.BuildClassDefinition(interfaces1, cm1));
//SyntaxTreeBuilder.BuildClassDefinition(interfaces1, cm1));
var stl1 = new statement_list(new var_statement("res", new new_expr(this.CreateClassReference(className), new expression_list())));
stl1.AddMany(lid.Select(id => new assign(new dot_node("res", new ident(formalParamsMap[id.name])), new ident(formalParamsMap[id.name]))));
// Переприсваивание self
if (iteratorClassName != null && !pd.proc_header.class_keyword)
{
stl1.Add(new assign(new dot_node("res", YieldConsts.Self), new ident(YieldConsts.Self)));
}
stl1.Add(new assign("Result", "res"));
GetEnumeratorBody.Add(new if_node(new bin_expr(new ident(YieldConsts.State), new int32_const(0), Operators.Equal),
new assign("Result", "Self"),
stl1));
var cct = new type_declarations(/*td*/);
cct.Add(td1);
@ -937,7 +954,7 @@ namespace SyntaxVisitors
// Обработать параметры!
// Как? Ищем в mids formal_parametrs, но надо выделить именно обращение к параметрам - не полям класса, не глобальным переменным
var cfa = new ConstructFiniteAutomata((pd.proc_body as block).program_code);
var cfa = new ConstructFiniteAutomata(pd.proc_body as block);
cfa.Transform();
(pd.proc_body as block).program_code = cfa.res;
@ -976,7 +993,7 @@ namespace SyntaxVisitors
}
}
class ConstructFiniteAutomata
/*class ConstructFiniteAutomata1
{
public statement_list res = new statement_list();
statement_list stl;
@ -992,9 +1009,9 @@ namespace SyntaxVisitors
private labeled_statement OuterLabeledStatement;
private Dictionary<int, labeled_statement> Dispatches = new Dictionary<int,labeled_statement>();
public ConstructFiniteAutomata(statement_list stl)
public ConstructFiniteAutomata1(block bl)
{
this.stl = stl;
this.stl = bl.program_code;
}
private void AddState(out int stateNumber, out ident resumeLabel)
@ -1064,6 +1081,69 @@ namespace SyntaxVisitors
//statement_list res = new statement_list(cas);
res = stl;
}
}
}*/
// SSM 07/07/16 - изменен алгоритм генерации конечного автомата на более простой. Вместо case генерируется последовательность if ... goto состояние.
class ConstructFiniteAutomata
{
public statement_list res = new statement_list(); // сюда писать результат
statement_list stl; // это исходные операторы тела функции
declarations defs; // это декларации функции - для добавления меток
int curState = 0;
public ConstructFiniteAutomata(block bl)
{
this.stl = bl.program_code;
defs = bl.defs;
}
public void Process(statement st)
{
if (st is yield_node)
{
var yn = st as yield_node;
curState += 1;
res.AddMany(
new assign(YieldConsts.Current, yn.ex),
new assign(YieldConsts.State, curState),
new assign("Result", true),
new procedure_call("exit"),
new labeled_statement(YieldConsts.LabelStatePrefix+curState.ToString())
);
}
else if (st is labeled_statement)
{
var ls = st as labeled_statement;
res.Add(new labeled_statement(ls.label_name));
Process(ls.to_statement);
}
else
{
res.Add(st);
}
}
public void Transform()
{
res.Add(new labeled_statement(YieldConsts.LabelStatePrefix+curState.ToString()));
foreach (var st in stl.subnodes)
Process(st);
// добавим метки состояний
var idseq = Enumerable.Range(0, curState + 1).Select(i => new ident("lbstate#" + i.ToString()));
var idl = new ident_list(idseq.ToList());
defs.Add(new label_definitions(idl));
statement ifgoto = new goto_statement(YieldConsts.LabelStatePrefix + curState.ToString());
for (var i = curState - 1; i >= 0; i--)
ifgoto = new if_node(new bin_expr(new ident(YieldConsts.State), new int32_const(i), Operators.Equal),
new goto_statement(YieldConsts.LabelStatePrefix + i.ToString()),
ifgoto
);
res.AddFirst(ifgoto);
res.AddFirst(new assign("Result", false));
}
}
}

View file

@ -27,7 +27,9 @@ namespace YieldDesugarSyntaxTreeConverter
root.visit(new MarkMethodHasYieldVisitor());
root.visit(new ProcessYieldCapturedVarsVisitor());
//root.visit(new SimplePrettyPrinterVisitor(@"d:\zzz.txt"));
#if DEBUG
root.visit(new SimplePrettyPrinterVisitor(@"d:\zzz.txt"));
#endif
return root;
}

View file

@ -10,6 +10,7 @@ namespace PascalABCCompiler.YieldHelpers
{
public static string Current = "<>2__current";
public static string State = "<>1__state";
public static string LabelStatePrefix = "lbstate#";
public static string Self = "<>4__self";

Binary file not shown.