From f680461234fdd473945769fa1c898a5a17b73870 Mon Sep 17 00:00:00 2001 From: nevermind322 <81963698+nevermind322@users.noreply.github.com> Date: Mon, 8 Jul 2024 20:35:57 +0300 Subject: [PATCH] Assign tuple optimizer (#3162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * branch init * add BindCollectLightSymInfo * moved lightsyminfo to syntaxVisitors * LIghtSymInfo fixes * binder 0.1 * Attributes -> SymbolAttributes * AssignTupleOptimizer -> AssignTupleDesugar * moved algorithm classes to AssignTupleDesugarAlgorithm namespace * fixes and refactoring * LightSymInfo rework * add rebuildDebug and build units * enable VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer * remove CollectFullLightSymInfo call * bind now return BindResult * change BindResult path type * path testing * fix Current in BindCollectLightSymInfo * fix Current in BindCollectLightSymInfo * potential symomyms handling without assigns count minimization * assign count minimization * rename AssignTuplesDesugar * move NewAssignTupleDesugar * add optimization switch * delete AssignTupleDesugar project * remove comments * Assign tuple optimizer (#3142) * branch init * add BindCollectLightSymInfo * moved lightsyminfo to syntaxVisitors * LIghtSymInfo fixes * binder 0.1 * Attributes -> SymbolAttributes * AssignTupleOptimizer -> AssignTupleDesugar * moved algorithm classes to AssignTupleDesugarAlgorithm namespace * fixes and refactoring * LightSymInfo rework * add rebuildDebug and build units * enable VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer * remove CollectFullLightSymInfo call * bind now return BindResult * change BindResult path type * path testing * fix Current in BindCollectLightSymInfo * fix Current in BindCollectLightSymInfo * potential symomyms handling without assigns count minimization * assign count minimization * rename AssignTuplesDesugar * move NewAssignTupleDesugar * add optimization switch * delete AssignTupleDesugar project * remove comments * collect symbols from var tuples * optimize var_tuple_def_statement and assign_var_tuple * fix * fix Tuple Visitor * fix CollectLightSymInfo (#3143) * branch init * add BindCollectLightSymInfo * moved lightsyminfo to syntaxVisitors * LIghtSymInfo fixes * binder 0.1 * Attributes -> SymbolAttributes * AssignTupleOptimizer -> AssignTupleDesugar * moved algorithm classes to AssignTupleDesugarAlgorithm namespace * fixes and refactoring * LightSymInfo rework * add rebuildDebug and build units * enable VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer * remove CollectFullLightSymInfo call * bind now return BindResult * change BindResult path type * path testing * fix Current in BindCollectLightSymInfo * fix Current in BindCollectLightSymInfo * potential symomyms handling without assigns count minimization * assign count minimization * rename AssignTuplesDesugar * move NewAssignTupleDesugar * add optimization switch * delete AssignTupleDesugar project * remove comments * collect symbols from var tuples * optimize var_tuple_def_statement and assign_var_tuple * fix * fix Tuple Visitor * 3.9.0.3489 * fix * Assign tuple optimizer (#3147) * branch init * add BindCollectLightSymInfo * moved lightsyminfo to syntaxVisitors * LIghtSymInfo fixes * binder 0.1 * Attributes -> SymbolAttributes * AssignTupleOptimizer -> AssignTupleDesugar * moved algorithm classes to AssignTupleDesugarAlgorithm namespace * fixes and refactoring * LightSymInfo rework * add rebuildDebug and build units * enable VarNamesInMethodsWithSameNameAsClassGenericParamsReplacer * remove CollectFullLightSymInfo call * bind now return BindResult * change BindResult path type * path testing * fix Current in BindCollectLightSymInfo * fix Current in BindCollectLightSymInfo * potential symomyms handling without assigns count minimization * assign count minimization * rename AssignTuplesDesugar * move NewAssignTupleDesugar * add optimization switch * delete AssignTupleDesugar project * remove comments * collect symbols from var tuples * optimize var_tuple_def_statement and assign_var_tuple * fix * fix Tuple Visitor * fix * add const optimization * Удалил лишнее --------- Co-authored-by: Mikhalkovich Stanislav Co-authored-by: Артём Филонов Co-authored-by: Sun Serega --- .../StandardSyntaxConverter.cs | 12 +- .../BindCollectLightSymInfo.cs | 17 +- .../CollectLightSymInfoVisitor.cs | 14 + .../LightScopeHelperClasses.cs | 15 +- .../AssignTuplesDesugarVisitor.cs | 0 .../NewAssignTuplesDesugarVisitor.cs | 102 ++++ .../desugarAlgoritm/Assign.cs | 45 ++ .../desugarAlgoritm/AssignGraph.cs | 166 ++++++ .../desugarAlgoritm/Cycle.cs | 31 ++ .../desugarAlgoritm/Edge.cs | 30 + .../desugarAlgoritm/GraphUtils.cs | 525 ++++++++++++++++++ .../desugarAlgoritm/Symbol.cs | 133 +++++ .../desugarAlgoritm/SymbolNode.cs | 67 +++ SyntaxVisitors/SugarVisitors/TupleVisitor.cs | 162 +++--- SyntaxVisitors/SyntaxVisitors.csproj | 10 +- 15 files changed, 1247 insertions(+), 82 deletions(-) rename SyntaxVisitors/SugarVisitors/{ => AssignTuplesDesugarVisitor}/AssignTuplesDesugarVisitor.cs (100%) create mode 100644 SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/NewAssignTuplesDesugarVisitor.cs create mode 100644 SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Assign.cs create mode 100644 SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/AssignGraph.cs create mode 100644 SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Cycle.cs create mode 100644 SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Edge.cs create mode 100644 SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/GraphUtils.cs create mode 100644 SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Symbol.cs create mode 100644 SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/SymbolNode.cs diff --git a/SyntaxTreeConverters/StandardSyntaxConverter.cs b/SyntaxTreeConverters/StandardSyntaxConverter.cs index 88631da96..263b6d359 100644 --- a/SyntaxTreeConverters/StandardSyntaxConverter.cs +++ b/SyntaxTreeConverters/StandardSyntaxConverter.cs @@ -15,7 +15,9 @@ namespace Languages.Pascal.Frontend.Converters protected override syntax_tree_node ApplyConcreteConversions(syntax_tree_node root) { + root.FillParentsInAllChilds(); + var binder = new BindCollectLightSymInfo(root as compilation_unit); #if DEBUG // var stat = new ABCStatisticsVisitor(); // stat.ProcessNode(root); @@ -42,9 +44,9 @@ namespace Languages.Pascal.Frontend.Converters #if DEBUG //new SimplePrettyPrinterVisitor("D:/out.txt").ProcessNode(root); #endif - + bool optimize_tuple_assign = true; // tuple_node - TupleVisitor.New.ProcessNode(root); + TupleVisitor.Create(optimize_tuple_assign).ProcessNode(root); // index IndexVisitor.New.ProcessNode(root); @@ -55,8 +57,10 @@ namespace Languages.Pascal.Frontend.Converters // теперь коллизия с (a[1:6], a[6:11]):= (a[6:11], a[1:6]); // assign_tuple и assign_var_tuple - AssignTuplesDesugarVisitor.New.ProcessNode(root); // теперь это - на семантике - + if (!optimize_tuple_assign) + AssignTuplesDesugarVisitor.New.ProcessNode(root); // теперь это - на семантике + else + NewAssignTuplesDesugarVisitor.Create(binder).ProcessNode(root); // question_point_desugar_visitor QuestionPointDesugarVisitor.New.ProcessNode(root); diff --git a/SyntaxVisitors/LightSymInfoVisitors/BindCollectLightSymInfo.cs b/SyntaxVisitors/LightSymInfoVisitors/BindCollectLightSymInfo.cs index 4f58774cf..21a0d77b8 100644 --- a/SyntaxVisitors/LightSymInfoVisitors/BindCollectLightSymInfo.cs +++ b/SyntaxVisitors/LightSymInfoVisitors/BindCollectLightSymInfo.cs @@ -1,4 +1,5 @@ - +using System.Collections.Generic; +using System.Linq; namespace PascalABCCompiler.SyntaxTree { @@ -12,22 +13,23 @@ namespace PascalABCCompiler.SyntaxTree { Current = Root; visit(root); + Current = null; } - public SymInfoSyntax bind(ident node) + public BindResult bind(ident node) { - ///Console.WriteLine("searching " + node.ToString()); + + Current = null; syntax_tree_node cur_node = node; + var path = new Queue(); while (cur_node != null) { - // Console.WriteLine("cur_node: " + cur_node.ToString()); if (AbstractScopeCreator.IsScopeCreator(cur_node)) { - //Console.WriteLine("checking scope" + cur_node.ToString()) var cur_scope = scopeCreator.GetScope(cur_node); - //Console.WriteLine(cur_scope.ToString() + ": " + cur_scope.Symbols.Count); + path.Enqueue(cur_scope); var prev_scope = Current; if (prev_scope != null) @@ -36,11 +38,10 @@ namespace PascalABCCompiler.SyntaxTree Current = cur_scope; if (cur_scope.Parent == null && !(Current is GlobalScopeSyntax)) { - //Console.WriteLine("visiting " + cur_node.ToString()); cur_node.visit(this); } var res = Current.bind(node); - if (res != null) return res; + if (res != null) return new BindResult(res, path.ToList()); } cur_node = cur_node.Parent; } diff --git a/SyntaxVisitors/LightSymInfoVisitors/CollectLightSymInfoVisitor.cs b/SyntaxVisitors/LightSymInfoVisitors/CollectLightSymInfoVisitor.cs index 8efc89041..515cdb61c 100644 --- a/SyntaxVisitors/LightSymInfoVisitors/CollectLightSymInfoVisitor.cs +++ b/SyntaxVisitors/LightSymInfoVisitors/CollectLightSymInfoVisitor.cs @@ -38,6 +38,20 @@ namespace PascalABCCompiler.SyntaxTree AddSymbols(vd.vars.list, SymKind.var, vd.vars_type, attr); base.visit(vd); } + + public override void visit(assign_var_tuple node) + { + AddSymbols(node.idents.idents, SymKind.var); + base.visit(node); + } + + public override void visit(var_tuple_def_statement node) + { + var attr = node.var_attr == definition_attribute.Static ? SymbolAttributes.class_attr : 0; + AddSymbols(node.vars.list, SymKind.var, node.vars_type, attr); + base.visit(node); + } + public override void visit(formal_parameters fp) { foreach (var pg in fp.params_list) diff --git a/SyntaxVisitors/LightSymInfoVisitors/LightScopeHelperClasses.cs b/SyntaxVisitors/LightSymInfoVisitors/LightScopeHelperClasses.cs index 6b163c14d..b16d36a03 100644 --- a/SyntaxVisitors/LightSymInfoVisitors/LightScopeHelperClasses.cs +++ b/SyntaxVisitors/LightSymInfoVisitors/LightScopeHelperClasses.cs @@ -22,7 +22,7 @@ namespace PascalABCCompiler.SyntaxTree recordname, interfacename, template_param, type_alias, const_var, property }; [Flags] - public enum SymbolAttributes { class_attr = 1, varparam_attr = 2, private_attr = 4}; + public enum SymbolAttributes { class_attr = 1, varparam_attr = 2, private_attr = 4 }; public class SymInfoSyntax { @@ -53,6 +53,19 @@ namespace PascalABCCompiler.SyntaxTree } } + public class BindResult { + + public SymInfoSyntax symInfo; + public List path; + + public BindResult(SymInfoSyntax s, List p) + { + symInfo = s; + path = p; + } + + } + public abstract class ScopeSyntax { public syntax_tree_node node; diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/AssignTuplesDesugarVisitor.cs similarity index 100% rename from SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor.cs rename to SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/AssignTuplesDesugarVisitor.cs diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/NewAssignTuplesDesugarVisitor.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/NewAssignTuplesDesugarVisitor.cs new file mode 100644 index 000000000..6b806c4a4 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/NewAssignTuplesDesugarVisitor.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; +using System.Linq; +using AssignTupleDesugarAlgorithm; +using PascalABCCompiler.SyntaxTree; + +namespace SyntaxVisitors.SugarVisitors +{ + public class NewAssignTuplesDesugarVisitor : AssignTuplesDesugarVisitor + { + + private BindCollectLightSymInfo binder; + + + public static NewAssignTuplesDesugarVisitor Create(BindCollectLightSymInfo binder) + { + return new NewAssignTuplesDesugarVisitor(binder); + } + + public NewAssignTuplesDesugarVisitor(BindCollectLightSymInfo binder) + { + this.binder = binder; + } + + + List desugar(tuple_node tn, addressed_value_list vars) + { + var order = Assign.getAssignOrder(tn, vars, binder); + var assigns = new List(); + foreach (var a in order) + { + if (a.to is TempSymbol ts) + { + var cur = new var_def_statement(ts.node as ident, a.from.node, tn.Parent.source_context); + assigns.Add(new var_statement(cur, tn.Parent.source_context)); + } + else + { + var cur = new assign(a.to.node as addressed_value, a.from.node, tn.Parent.source_context); + assigns.Add(cur); + } + } + return assigns; + } + + + public override void visit(assign_tuple node) + { + if (node.expr is tuple_node tn) + { + var n = node.vars.variables.Count(); + if (n > tn.el.Count) + throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", node.vars.variables[0]); + + var assigns = desugar(tn, node.vars); + ReplaceStatementUsingParent(node, assigns); + } + else + base.visit(node); + } + + public override void visit(assign_var_tuple node) + { + if (node.expr is tuple_node tn) + { + var n = node.idents.idents.Count(); + if (n > tn.el.Count) + throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", node.idents.idents[0]); + + var assigns = new List(); + for(var i =0; i < n; i++) + { + var cur = new var_def_statement(node.idents.idents[i], tn.el.expressions[i], tn.Parent.source_context); + assigns.Add(new var_statement(cur, node.source_context)); + } + ReplaceStatementUsingParent(node, assigns); + } + else + base.visit(node); + + } + + public override void visit(var_tuple_def_statement node) + { + if (node.inital_value is tuple_node tn) + { + var n = node.vars.idents.Count(); + if (n > tn.el.Count) + throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", node.vars.idents[0]); + var assigns = new List(); + for (var i = 0; i < n; i++) + { + var cur = new var_def_statement(node.vars.idents[i], tn.el.expressions[i], tn.Parent.source_context); + assigns.Add(cur); + } + ReplaceVarTupleDefStatementUsingParent(node, assigns); + } + else + base.visit(node); + + } + } +} diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Assign.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Assign.cs new file mode 100644 index 000000000..9e7bd4213 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Assign.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; +using PascalABCCompiler.SyntaxTree; + +namespace AssignTupleDesugarAlgorithm +{ + public class Assign + { + public Symbol from; + public Symbol to; + public Assign(Symbol to, Symbol from) + { + this.to = to; + this.from = from; + } + + public static List getAssignOrder(tuple_node tn, addressed_value_list vars, BindCollectLightSymInfo binder) + { + var left = new List(); + var right = new List(); + + foreach (var ex in vars.variables) + { + var s = new Symbol(ex, binder); + left.Add(s); + } + + + foreach (var ex in tn.el.expressions) + { + var s = new Symbol(ex, binder); + right.Add(s); + } + + + var graph = GraphUtils.createAssignGraph(left, right); + //graph.drawGraph(); + var order = graph.GetAssignOrder(); + return order.Select(elem => new Assign(to: elem.to.symbol, from: elem.from.symbol)).ToList(); + } + + + + } +} diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/AssignGraph.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/AssignGraph.cs new file mode 100644 index 000000000..eb3cda1ab --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/AssignGraph.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace AssignTupleDesugarAlgorithm +{ + internal class AssignGraph : IEnumerable + { + public readonly HashSet vertexes = new HashSet(); + + public readonly List edges = new List(); + private bool AdjStructuresNeedSync = false; + + public List assignOrder = new List(); + public List assignLast = new List(); + public List assignFirst = new List(); + + private Dictionary> outAdjStructure = null; + + public Dictionary> OutAdjStructure + { + get + { + if (outAdjStructure == null || AdjStructuresNeedSync) + { + outAdjStructure = createOutAdjStructure(); + inAdjStructure = createInAdjStructure(); + AdjStructuresNeedSync = false; + } + + return outAdjStructure; + } + } + + private Dictionary> createOutAdjStructure() + { + Dictionary> res = new Dictionary>(); + + foreach (var vert in vertexes) res.Add(vert, new List()); + + foreach (Edge edge in edges) res[edge.from].Add(edge.to); + + return res; + } + + private Dictionary> inAdjStructure = null; + + public Dictionary> InAdjStructure + { + get + { + if (inAdjStructure == null || AdjStructuresNeedSync) + { + outAdjStructure = createOutAdjStructure(); + inAdjStructure = createInAdjStructure(); + AdjStructuresNeedSync = false; + } + + return inAdjStructure; + } + } + + private Dictionary> createInAdjStructure() + { + Dictionary> res = new Dictionary>(); + + foreach (var vert in vertexes) res.Add(vert, new List()); + + foreach (Edge edge in edges) res[edge.to].Add(edge.from); + + return res; + } + + + public List GetInEdgesForVertex(SymbolNode v) => edges.FindAll(edge => edge.to == v); + public List GetOutEdgesForVertex(SymbolNode v) => edges.FindAll(edge => edge.from == v); + + public void resetVertexesColor() + { + foreach (SymbolNode v in vertexes) v.resetColor(); + } + + public bool EnsureThatEveryVertexHasOneOrZeroInEdge() => + vertexes.All(vert => GetInEdgesForVertex(vert).Count <= 1); + + internal List GetAssignOrder() + { + List assignOrder = new List(); + assignOrder.AddRange(assignFirst); + + if (vertexes.Count == 0) + { + assignOrder.AddRange(assignLast); + this.assignOrder = assignOrder; + return this.assignOrder; + } + + var s = vertexes.First(); + + if (!EnsureThatEveryVertexHasOneOrZeroInEdge()) throw new Exception("Invalid assign graph!"); + + var cycles = this.findAllUniqueElementaryCycles(); + + foreach (var cycle in cycles) + { + SymbolNode cut_place = cycle[0]; + Edge edge_to_cut = GetInEdgesForVertex(cut_place).First(); + + SymbolNode temp_assign_from = edge_to_cut.from; + SymbolNode temp_vertex = new TempSymbolNode(new TempSymbol()); + + assignOrder.Add(new Edge(temp_assign_from, temp_vertex)); + assignLast.Add(new Edge(temp_vertex, cut_place)); + + edges.Remove(edge_to_cut); + AdjStructuresNeedSync = true; + } + + List roots = vertexes.ToList().FindAll(vertex => GetInEdgesForVertex(vertex).Count == 0); + + void treeTraversal(SymbolNode root) + { + foreach (SymbolNode node in OutAdjStructure[root]) treeTraversal(node); + + var inEdges = GetInEdgesForVertex(root); + if (inEdges.Count() > 0) assignOrder.Add(inEdges.First()); + } + + foreach (SymbolNode root in roots) treeTraversal(root); + + assignOrder.AddRange(assignLast); + this.assignOrder = assignOrder; + return this.assignOrder; + } + + public AssignGraph(List edges, List vertexes) : this(edges) + { + foreach (SymbolNode vert in vertexes) this.vertexes.Add(vert); + } + + public AssignGraph() + { + + } + + public AssignGraph(List e) + { + edges = e; + foreach (var edge in edges) + { + vertexes.Add(edge.from); + vertexes.Add(edge.to); + } + } + public IEnumerator GetEnumerator() + { + return ((IEnumerable)vertexes).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)vertexes).GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Cycle.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Cycle.cs new file mode 100644 index 000000000..4935ac742 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Cycle.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; + +namespace AssignTupleDesugarAlgorithm +{ + internal class Cycle + { + List cycle; + + + public int Len => cycle.Count; + + public Cycle(List c) + { + cycle = c; + } + + public SymbolNode this[int i] => cycle[i % Len]; + + + public override string ToString() + { + string res = ""; + foreach (var v in cycle) + { + res += v + "->"; + } + + return res + cycle[0]; + } + } +} \ No newline at end of file diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Edge.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Edge.cs new file mode 100644 index 000000000..c76cc5dc4 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Edge.cs @@ -0,0 +1,30 @@ +using System; + +namespace AssignTupleDesugarAlgorithm +{ + internal class Edge : IEquatable, IComparable + { + public SymbolNode from; + public SymbolNode to; + public int weight; + + public Edge(SymbolNode f, SymbolNode t, int w = 0) + { + if (weight < 0) throw new ArgumentException("weight can't be negative!"); + from = f; + to = t; + weight = w; + } + + public int CompareTo(Edge other) + { + return weight - other.weight; + } + + public bool Equals(Edge other) + { + if (other is null) return false; + return from == other.from && to == other.to; + } + } +} \ No newline at end of file diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/GraphUtils.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/GraphUtils.cs new file mode 100644 index 000000000..a2658f41a --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/GraphUtils.cs @@ -0,0 +1,525 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + + +namespace AssignTupleDesugarAlgorithm +{ + internal static class GraphUtils + { + static private void dfs(this AssignGraph graph, + Action OnEnterGraph, + Func OnProcessVertex, + Action OnEnterNode, + Func OnProcessNodeChild, + Action OnLeaveNode, + Action OnLeaveGraph, + Func> vertexTraversalOrderFunc = null, + IEnumerable graphTraversalOrder = null) + { + void dfs(SymbolNode start_node, + Action OnEnter, + Func OnProcessChild, + Action OnLeave + ) + { + OnEnter(graph, start_node); + IEnumerable vertexTraversalOrder; + if (vertexTraversalOrderFunc == null) vertexTraversalOrder = graph.OutAdjStructure[start_node]; + else vertexTraversalOrder = vertexTraversalOrderFunc(graph, start_node); + foreach (SymbolNode current_node in vertexTraversalOrder) + { + if (OnProcessChild(graph, start_node, current_node)) + dfs(current_node, OnEnter, OnProcessChild, OnLeave); + } + + OnLeave(graph, start_node); + } + + + if (graphTraversalOrder == null) graphTraversalOrder = graph.vertexes; + + OnEnterGraph(graph); + foreach (SymbolNode v in graphTraversalOrder) + { + if (OnProcessVertex(graph, v)) + dfs(v, OnEnter: OnEnterNode, OnProcessChild: OnProcessNodeChild, OnLeave: OnLeaveNode); + } + + OnLeaveGraph(graph); + } + + + private class SynonymsGraph { + + public enum Type { SAME_NAME, INDEXER} + + public HashSet left = new HashSet(); + public HashSet right = new HashSet(); + + public Type type; + + public SynonymsGraph(Type type) + { + this.type = type; + } + + public override string ToString() + { + var res = ""; + if (type == Type.INDEXER) + res += "Indexer"; + else + res += "Same_Name"; + res += "graph(left["; + foreach (var i in left) res += i.ToString() + ","; + res += "], right["; + foreach(var i in right) res += i.ToString() + ","; + res += "])"; + return res; + } + + } + + public static AssignGraph createAssignGraph(List left, List right) + { + if (right.Count < left.Count) throw new Exception("AAAA"); + + + List v_left = new List(); + List v_right = new List(); + List left_visited = new List(); + List assign_first = new List(); + List assign_last = new List(); + + var moved_first = new List(); + var moved_last = new LinkedList(); + var movedAssigns = new HashSet(); + + + void moveAssign(int i, bool toFirst) + { + Edge assign = new Edge(new SymbolNode(right[i]), new SymbolNode(left[i])); + if (toFirst) + moved_first.Add(assign); + else + moved_last.AddFirst(assign); + movedAssigns.Add(i); + } + + void addTemp(int i, bool toFirst) + { + if(toFirst) + { + var temp_symbol = new TempSymbol(); + assign_first.Add(new Edge(new SymbolNode(right[i]), new TempSymbolNode(temp_symbol))); + right[i] = temp_symbol; + } + else + { + var temp_s = new TempSymbol(); + assign_last.Add(new Edge(new TempSymbolNode(temp_s), new SymbolNode(left[i]))); + left[i] = temp_s; + } + } + + // if repeated assigns or pointers -> 2n + for (int i = 0; i < left.Count(); i++) + { + if (left_visited.Find(it => it.StructurallyEquals(left[i])) != null + || right[i].type == Symbol.Type.POINTER + || left[i].type == Symbol.Type.POINTER) + { + var res = new AssignGraph(); + res.assignFirst = make2n(left, right); + return res; + } + else + left_visited.Add(left[i]); + } + + //handle expressions and var params + for (int i = 0; i < left.Count(); i++) + { + if (right[i].type == Symbol.Type.EXPR || right[i].type == Symbol.Type.VAR_PARAM) + { + + addTemp(i, true); + } + if (left[i].type == Symbol.Type.VAR_PARAM) + { + addTemp(i, false); + } + } + + for (int i = left.Count - 1; i > -1; i--) + { + //handle loops + if (left[i].StructurallyEquals(right[i])) + { + var f = new SymbolNode(right[i]); + var t = new SymbolNode(left[i]); + assign_first.Add(new Edge(f, t)); + left.RemoveAt(i); + right.RemoveAt(i); + } + } + + + var indexerGraph = new SynonymsGraph(SynonymsGraph.Type.INDEXER); + var nameToGraph = new Dictionary(); + + + for (int i = 0; i < left.Count; i++) + { + if (left[i].type == Symbol.Type.INDEXER) + indexerGraph.left.Add(i); + else if (left[i].type == Symbol.Type.FROM_OUTER_SCOPE || left[i].type == Symbol.Type.DOT_NODE) + { + var name = left[i].last_name; + if (!nameToGraph.ContainsKey(name)) + nameToGraph.Add(name, new SynonymsGraph(SynonymsGraph.Type.SAME_NAME)); + nameToGraph[name].left.Add(i); + } + if (right[i].type == Symbol.Type.INDEXER) + indexerGraph.right.Add(i); + else if (right[i].type == Symbol.Type.FROM_OUTER_SCOPE || right[i].type == Symbol.Type.DOT_NODE) + { + var name = right[i].last_name; + if (!nameToGraph.ContainsKey(name)) + nameToGraph.Add(name, new SynonymsGraph(SynonymsGraph.Type.SAME_NAME)); + nameToGraph[name].right.Add(i); + } + } + + + var leftSet = new HashSet(left); + var rightSet = new HashSet(right); + var graphs = new List(); + graphs.AddRange(nameToGraph.Values); + graphs.Add(indexerGraph); + + //Handle const + for (int i = 0; i < left.Count; i++) + { + if (right[i].type == Symbol.Type.CONST_EXPR) + { + moveAssign(i, false); + } + } + void resolveGraph(SynonymsGraph sGraph) + { + + foreach (var i in sGraph.left) + { + var type = right[i].type; + if (type == Symbol.Type.LOCAL) + { + if (!leftSet.Contains(right[i])) + moveAssign(i, false); + } + else if (type == Symbol.Type.FROM_OUTER_SCOPE) + { + if (!(leftSet.Contains(right[i]) || nameToGraph[right[i].last_name].left.Count() != 0)) + moveAssign(i, false); + } + else if (type == Symbol.Type.DOT_NODE) + { + if (nameToGraph[right[i].last_name].left.Count() == 0) + moveAssign(i, false); + } + else if (type == Symbol.Type.INDEXER) + { + if (indexerGraph.left.Count() == 0) + moveAssign(i, false); + } + } + + foreach (var i in sGraph.right) + { + var type = left[i].type; + if (type == Symbol.Type.LOCAL) + { + if (!right.Contains(left[i])) + moveAssign(i, true); + } + else if (type == Symbol.Type.FROM_OUTER_SCOPE) + { + if (!(rightSet.Contains(left[i]) || nameToGraph[left[i].last_name].right.Count() != 0)) + moveAssign(i, true); + } + else if (type == Symbol.Type.DOT_NODE) + { + if (nameToGraph[left[i].last_name].right.Count() == 0) + moveAssign(i, true); + } + else if (type == Symbol.Type.INDEXER) + { + if (indexerGraph.right.Count() == 0) + moveAssign(i, true); + } + } + foreach(int i in movedAssigns) + { + sGraph.left.Remove(i); + sGraph.right.Remove(i); + } + + var l_size = sGraph.left.Count; + var r_size = sGraph.right.Count; + if (r_size == 0 || l_size == 0) + return; + + Edge movedFromThisGraph = null; + if (l_size < r_size) + { + foreach (var i in sGraph.left) + { + if (sGraph.right.Contains(i)) + { + if (movedFromThisGraph == null) + { + movedFromThisGraph = new Edge(new SymbolNode(right[i]), new SymbolNode(left[i])); + movedAssigns.Add(i); + } + else + addTemp(i, false); + + } + else + addTemp(i, false); + } + if (movedFromThisGraph != null) + moved_last.AddFirst(movedFromThisGraph); + sGraph.left.Clear(); + } + else + { + foreach (var i in sGraph.right) + { + if (sGraph.left.Contains(i)) + { + + if (movedFromThisGraph == null) + { + movedFromThisGraph = new Edge(new SymbolNode(right[i]), new SymbolNode(left[i])); + movedAssigns.Add(i); + } + else + addTemp(i, true); + } + else + addTemp(i, true); + + } + if (movedFromThisGraph != null) + moved_first.Add(movedFromThisGraph); + sGraph.right.Clear(); + } + } + + + + foreach (var g in graphs) + resolveGraph(g); + + for (int i = left.Count - 1; i >= 0; i--) + { + if (movedAssigns.Contains(i)) + { + left.RemoveAt(i); + right.RemoveAt(i); + movedAssigns.Remove(i); + } + } + + + var symbols = new Dictionary(); + + foreach (Symbol sym in left) + { + if (!symbols.ContainsKey(sym.name)) symbols[sym.name] = new SymbolNode(sym); + v_left.Add(symbols[sym.name]); + } + + foreach (Symbol sym in right) + { + if (!symbols.ContainsKey(sym.name)) symbols[sym.name] = new SymbolNode(sym); + v_right.Add(symbols[sym.name]); + } + + List assigns = new List(); + + for (int i = 0; i < v_left.Count; i++) assigns.Add(new Edge(v_right[i], v_left[i], i)); + + + assign_first.AddRange(moved_first); + foreach(var assign in assign_last) + moved_last.AddLast(assign); + + assign_last = moved_last.ToList(); + + var graph = new AssignGraph(assigns); + graph.assignFirst = assign_first; + graph.assignLast = assign_last; + return graph; + } + + + + + private static List make2n(List left, List right) + { + var temps = new List(); + var res = new List(); + + for(int i = 0; i < right.Count; i++) + { + var to = new SymbolNode(new TempSymbol()); + var from = new SymbolNode(right[i]); + temps.Add(to); + res.Add(new Edge(from, to)); + } + + + for (int i = 0; i < left.Count; i++) + { + var to = new SymbolNode(left[i]); + res.Add(new Edge(temps[i], to)); + } + return res; + } + + private static AssignGraph createReversedGraph(this AssignGraph g) + { + List newEdges = new List(); + foreach (var edge in g.edges) + { + newEdges.Add(new Edge(f: edge.to, t: edge.from)); + } + + return new AssignGraph(newEdges, g.vertexes.ToList()); + } + + public static List> findStronglyConnectedComponets(this AssignGraph g) + { + List> res = new List>(); + + Stack route = new Stack(); + HashSet visited = new HashSet(); + + Action onEnterGraph = (_) => + { + route.Clear(); + visited.Clear(); + }; + + Action onEnterNode = (graph, node) => { visited.Add(node); }; + + Action onLeaveNode = (graph, node) => { route.Push(node); }; + + Func onProcessChildNode = (graph, parent, childNode) => + { + if (!visited.Contains(childNode)) + { + return true; + } + else return false; + }; + + Func onProcessVertex = (graph, vert) => { return !visited.Contains(vert); }; + + g.dfs(OnEnterGraph: onEnterGraph, OnProcessVertex: onProcessVertex, + OnEnterNode: onEnterNode, OnProcessNodeChild: onProcessChildNode, + OnLeaveNode: onLeaveNode, + OnLeaveGraph: (_) => { } + ); + + Action onEnterGraphReversed = (_) => { visited.Clear(); }; + + Action onEnterNodeReversed = (graph, node) => + { + visited.Add(node); + res.Last().Add(node); + }; + + Action onLeaveNodeReversed = (graph, node) => { }; + + Func onProcessChildNodeReversed = (graph, parent, childNode) => + { + if (!visited.Contains(childNode)) + { + return true; + } + else return false; + }; + + Func onProcessVertexReversed = (graph, vert) => + { + if (visited.Contains(vert)) return false; + else + { + res.Add(new List()); + return true; + } + }; + + var graphTraversalOrder = route.ToList(); + + var g_rev = g.createReversedGraph(); + + g_rev.dfs(OnEnterGraph: onEnterGraphReversed, OnProcessVertex: onProcessVertexReversed, + OnEnterNode: onEnterNodeReversed, OnProcessNodeChild: onProcessChildNodeReversed, + OnLeaveNode: onLeaveNodeReversed, + OnLeaveGraph: (_) => { }, + graphTraversalOrder: graphTraversalOrder); + + return res; + } + + public static List findAllUniqueElementaryCycles(this AssignGraph g) + { + var res = new List(); + var components = g.findStronglyConnectedComponets(); + foreach (var component in components) + { + if (component.Count() > 1) res.Add(new Cycle(component)); + } + return res; + } + + public static void LogGraph(this AssignGraph graph) + { + foreach (var vert in graph.vertexes) + { + Console.Write("{0}->[", vert); + graph.OutAdjStructure[vert].ForEach(v => Console.Write("{0}, ", v)); + Console.WriteLine("]"); + } + } + + public static void drawGraph(this AssignGraph g) + { + var writer = File.CreateText("graph.dot"); + writer.WriteLine("digraph _graph {"); + + Action enterGraph = (graph) => { graph.resetVertexesColor(); }; + + Func ProcessNode = (graph, node) => node.color != SymbolNode.Color.GREY; + + Action EnterNode = (graph, vert) => { vert.color = SymbolNode.Color.GREY; }; + + Func ProcessNodeChild = (graph, parent, child) => + { + writer.WriteLine(parent.label + "->" + child.label); + return child.color == SymbolNode.Color.WHITE; + }; + + g.dfs(OnEnterGraph: enterGraph, OnEnterNode: EnterNode, OnProcessNodeChild: ProcessNodeChild, + OnProcessVertex: ProcessNode, OnLeaveGraph: (graph) => { graph.resetVertexesColor(); }, OnLeaveNode: (graph, vertex) => { }); + writer.WriteLine("}"); + writer.Close(); + } + } +} \ No newline at end of file diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Symbol.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Symbol.cs new file mode 100644 index 000000000..966f574d4 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Symbol.cs @@ -0,0 +1,133 @@ +using System.Collections.Generic; +using System.Diagnostics; +using PascalABCCompiler.SyntaxTree; + +namespace AssignTupleDesugarAlgorithm +{ + public class Symbol + { + public enum Type + { + VAR_PARAM, FROM_OUTER_SCOPE, INDEXER, DOT_NODE, LOCAL, EXPR, POINTER, CONST_EXPR + } + public string name; + public string last_name; + + //public bool canBeSynonym = false; + //public bool isIndexer = false; + //public bool isExpr = false; + public expression node; + public Type type; + + public Symbol(expression ex, BindCollectLightSymInfo binder) + { + node = ex; + if (node is indexer ind) + { + name = ind.ToString(); + last_name = name; + type = Type.INDEXER; + } + else if (node is dot_node dn) + { + var last = dn.right; + while (last is dot_node dn1) + last = dn1.right; + + name = node.ToString(); + last_name = last.ToString(); + type = Type.DOT_NODE; + if (last is indexer) + type = Type.INDEXER; + } + else if (node is ident id) + { + name = id.name; + last_name = name; + if (binder != null) + { + var info = binder.bind(id); + if (isVarParam(info)) + { + type = Type.VAR_PARAM; + } + else if (isFromOuterScope(info)) + { + type = Type.FROM_OUTER_SCOPE; + } + else + { + type = Type.LOCAL; + } + } + } + + else if (node is get_address || node is roof_dereference) + { + type = Type.POINTER; + } + else if(node is const_node) + { + type = Type.CONST_EXPR; + } + else + { + type = Type.EXPR; + name = node.ToString(); + last_name = name; + } + } + + public bool StructurallyEquals(Symbol sym) => node.ToString() == sym.node.ToString(); + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (obj.GetType() != GetType()) return false; + return name == (obj as Symbol).name; + } + + public override int GetHashCode() + { + return 363513814 + EqualityComparer.Default.GetHashCode(name); + } + + + static bool isFromOuterScope(BindResult bindRes) + { + var symbol = bindRes.symInfo; + + if (symbol == null) + return true; + + if (symbol.SK == SymKind.var && symbol.Attr.HasFlag(SymbolAttributes.varparam_attr)) + return true; + + if (bindRes.path[bindRes.path.Count - 1] is GlobalScopeSyntax) + return true; + + for (var i = 0; i < bindRes.path.Count - 1; i++) + if (bindRes.path[i] is NamedScopeSyntax) + return true; + + return false; + } + + static bool isVarParam(BindResult res) + { + if (res == null) + return true; + return res.symInfo.Attr.HasFlag(SymbolAttributes.varparam_attr); + } + } + + public class TempSymbol : Symbol + { + private static int counter = 0; + private static string getTempPrefix => "" + counter++; + public TempSymbol() : base(new ident(getTempPrefix), null) + { + type = Type.LOCAL; + } + } +} \ No newline at end of file diff --git a/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/SymbolNode.cs b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/SymbolNode.cs new file mode 100644 index 000000000..e6a34c5f0 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/SymbolNode.cs @@ -0,0 +1,67 @@ +using System; + +namespace AssignTupleDesugarAlgorithm +{ + + internal class SymbolNode : IEquatable + { + public readonly string label; + public int? number = null; + public readonly Symbol symbol; + + public SymbolNode(Symbol s) + { + symbol = s; + label = s.name; + } + + public enum Color + { + WHITE, + GREY, + BLACK + } + + public Color color = Color.WHITE; + public void resetColor() => color = Color.WHITE; + + public bool Equals(SymbolNode other) + { + if (other is null) return false; + + return label == other.label; + } + + public override int GetHashCode() + { + return label.GetHashCode(); + } + + public override bool Equals(object other) + { + if (GetType() != other.GetType()) return false; + return Equals((SymbolNode)other); + } + + + public override string ToString() + { + string n = ""; + if (number != null) + { + n = "(" + number.ToString() + ")"; + } + + return label + n; + } + } + + internal class TempSymbolNode : SymbolNode + { + public TempSymbolNode(TempSymbol s) : base(s) + { + + } + } + +} \ No newline at end of file diff --git a/SyntaxVisitors/SugarVisitors/TupleVisitor.cs b/SyntaxVisitors/SugarVisitors/TupleVisitor.cs index 07276ad3c..6a48dc692 100644 --- a/SyntaxVisitors/SugarVisitors/TupleVisitor.cs +++ b/SyntaxVisitors/SugarVisitors/TupleVisitor.cs @@ -14,11 +14,14 @@ namespace SyntaxVisitors.SugarVisitors /// public class TupleVisitor : BaseChangeVisitor { - public static TupleVisitor New + public bool optimize_tuple_assign; + + public TupleVisitor(bool optimize_tup_opt) { - get { return new TupleVisitor(); } + optimize_tuple_assign = optimize_tup_opt; } + public static TupleVisitor Create(bool optimize_tup_opt) => new TupleVisitor(optimize_tup_opt); private int num = 0; public string UniqueName() { @@ -59,81 +62,97 @@ namespace SyntaxVisitors.SugarVisitors // Остальное раскрывается в AssignTuplesDesugarVisitor public override void visit(assign_var_tuple assvartup) { - if (assvartup.expr is tuple_node tn && tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const)) + if (assvartup.expr is tuple_node tn) { - var n = assvartup.idents.idents.Count(); - if (n > tn.el.Count) - throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", assvartup.idents[0]); - - // Оптимизация, т.к. все - константы - var sl = new List(); - for (var i = 0; i < n; i++) + if (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const)) { - var a = new var_statement( - assvartup.idents.idents[i], - tn.el.expressions[i], - assvartup.idents.idents[i].source_context); - sl.Add(a); + var n = assvartup.idents.idents.Count(); + if (n > tn.el.Count) + throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", assvartup.idents[0]); + + // Оптимизация, т.к. все - константы + var sl = new List(); + for (var i = 0; i < n; i++) + { + var a = new var_statement( + assvartup.idents.idents[i], + tn.el.expressions[i], + assvartup.idents.idents[i].source_context); + sl.Add(a); + } + ReplaceStatementUsingParent(assvartup, sl); } - ReplaceStatementUsingParent(assvartup, sl); + else if (optimize_tuple_assign) + return; + else + DefaultVisit(assvartup); } else { DefaultVisit(assvartup); } + } public override void visit(assign_tuple asstup) { - if (asstup.expr is tuple_node tn && tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const)) + if (asstup.expr is tuple_node tn) { - var n = asstup.vars.variables.Count(); - if (n > tn.el.Count) - throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]); - - // Оптимизация, т.к. все - константы - var sl = new List(); - for (var i = 0; i < n; i++) + if (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const)) { - var a = new assign(asstup.vars.variables[i], - tn.el.expressions[i], - Operators.Assignment, - asstup.vars.variables[i].source_context); - sl.Add(a); - } - ReplaceStatementUsingParent(asstup, sl); - } - else if (asstup.expr is tuple_node tn1 && !tn1.el.expressions.Any(ex => ex is nil_const)) - { - var n = asstup.vars.variables.Count(); - if (n > tn1.el.Count) - throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]); + var n = asstup.vars.variables.Count(); + if (n > tn.el.Count) + throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]); - var sl = new List(); - for (var i = 0; i < n; i++) + // Оптимизация, т.к. все - константы + var sl = new List(); + for (var i = 0; i < n; i++) + { + var a = new assign(asstup.vars.variables[i], + tn.el.expressions[i], + Operators.Assignment, + asstup.vars.variables[i].source_context); + sl.Add(a); + } + ReplaceStatementUsingParent(asstup, sl); + } + else if (optimize_tuple_assign) + return; + else if (!tn.el.expressions.Any(ex => ex is nil_const)) { - var temp_id = new ident(UniqueName(), tn1.el.expressions[i].source_context); - var var_def = new var_def_statement(temp_id, tn1.el.expressions[i], tn1.el.expressions[i].source_context); - var a = new var_statement(var_def, tn1.el.expressions[i].source_context); - sl.Add(a); - } + var n = asstup.vars.variables.Count(); + if (n > tn.el.Count) + throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]); - //for (var i = 0; i < n; i++) - for (var i = n-1; i >= 0; i--) - { - var a = new assign(asstup.vars.variables[i], - (sl[i] as var_statement).var_def.vars.idents[0], - Operators.Assignment, - asstup.vars.variables[i].source_context); - sl.Add(a); - } + var sl = new List(); + for (var i = 0; i < n; i++) + { + var temp_id = new ident(UniqueName(), tn.el.expressions[i].source_context); + var var_def = new var_def_statement(temp_id, tn.el.expressions[i], tn.el.expressions[i].source_context); + var a = new var_statement(var_def, tn.el.expressions[i].source_context); + sl.Add(a); + } - ReplaceStatementUsingParent(asstup, sl); + //for (var i = 0; i < n; i++) + for (var i = n - 1; i >= 0; i--) + { + var a = new assign(asstup.vars.variables[i], + (sl[i] as var_statement).var_def.vars.idents[0], + Operators.Assignment, + asstup.vars.variables[i].source_context); + sl.Add(a); + } + + ReplaceStatementUsingParent(asstup, sl); + } + else + DefaultVisit(asstup); } else { DefaultVisit(asstup); } + } public void ReplaceVarTupleDefStatementUsingParent(var_tuple_def_statement from, IEnumerable to) @@ -150,27 +169,34 @@ namespace SyntaxVisitors.SugarVisitors // А это по идее до begin - там немного другие узлы и внешний контекст public override void visit(var_tuple_def_statement vtd) { - if (vtd.inital_value is tuple_node tn && tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const)) - { - var n = vtd.vars.idents.Count(); - if (n > tn.el.Count) - throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", vtd.vars.idents[0]); - - var vd = new List(); - for (var i = 0; i < n; i++) + if (vtd.inital_value is tuple_node tn) { + if (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const)) { - var a = new var_def_statement(vtd.vars.idents[i], - tn.el.expressions[i], - vtd.vars.idents[i].source_context); - vd.Add(a); + var n = vtd.vars.idents.Count(); + if (n > tn.el.Count) + throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", vtd.vars.idents[0]); + + var vd = new List(); + for (var i = 0; i < n; i++) + { + var a = new var_def_statement(vtd.vars.idents[i], + tn.el.expressions[i], + vtd.vars.idents[i].source_context); + vd.Add(a); + } + ReplaceVarTupleDefStatementUsingParent(vtd, vd); + visit(vtd.inital_value); } - ReplaceVarTupleDefStatementUsingParent(vtd, vd); - visit(vtd.inital_value); + else if (optimize_tuple_assign) + return; + else + DefaultVisit(vtd); } else { DefaultVisit(vtd); } + } public override void visit(tuple_node tup) diff --git a/SyntaxVisitors/SyntaxVisitors.csproj b/SyntaxVisitors/SyntaxVisitors.csproj index c241e422c..cd233a0cd 100644 --- a/SyntaxVisitors/SyntaxVisitors.csproj +++ b/SyntaxVisitors/SyntaxVisitors.csproj @@ -52,6 +52,14 @@ + + + + + + + + @@ -65,7 +73,7 @@ - +