diff --git a/Languages/Pascal/SyntaxTreeConverters/SyntaxTreeConverters/StandardSyntaxConverter.cs b/Languages/Pascal/SyntaxTreeConverters/SyntaxTreeConverters/StandardSyntaxConverter.cs index 88631da96..263b6d359 100644 --- a/Languages/Pascal/SyntaxTreeConverters/SyntaxTreeConverters/StandardSyntaxConverter.cs +++ b/Languages/Pascal/SyntaxTreeConverters/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/PascalABCNET.sln b/PascalABCNET.sln index c1f52f38b..3d7567d26 100644 --- a/PascalABCNET.sln +++ b/PascalABCNET.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.8.34309.116 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.34301.259 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VisualPascalABCNET", "VisualPascalABCNET", "{26843C5D-9D7E-4C2C-AC14-2D227FA5592E}" EndProject 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/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..681946505 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/NewAssignTuplesDesugarVisitor.cs @@ -0,0 +1,61 @@ +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); + } + } +} 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..e633526cd --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/GraphUtils.cs @@ -0,0 +1,512 @@ +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(); + + 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; + } + } + + //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--) + { + //delete 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); + } + // if repeated assigns or pointers -> 2n + else 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]); + } + + + 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); + 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 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..2ab9bdfb2 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AssignTuplesDesugarVisitor/desugarAlgoritm/Symbol.cs @@ -0,0 +1,129 @@ +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 + } + 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 + { + 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..3e9fdfee4 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() { @@ -85,54 +88,57 @@ namespace SyntaxVisitors.SugarVisitors 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 (!optimize_tuple_assign) { - 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 (asstup.expr is tuple_node tn && 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 (asstup.expr is tuple_node tn1 && !tn1.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 > tn1.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 sl = new List(); + for (var i = 0; i < n; i++) + { + 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); + } + + //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 { - 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); + DefaultVisit(asstup); } - - ReplaceStatementUsingParent(asstup, sl); - } - else - { - DefaultVisit(asstup); } } diff --git a/SyntaxVisitors/SyntaxVisitors.csproj b/SyntaxVisitors/SyntaxVisitors.csproj index c241e422c..1bc6a61ad 100644 --- a/SyntaxVisitors/SyntaxVisitors.csproj +++ b/SyntaxVisitors/SyntaxVisitors.csproj @@ -52,6 +52,14 @@ + + + + + + + + @@ -61,11 +69,12 @@ + - + diff --git a/bin/AssignTupleOptimizer.dll b/bin/AssignTupleOptimizer.dll new file mode 100644 index 000000000..34f741394 Binary files /dev/null and b/bin/AssignTupleOptimizer.dll differ