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
This commit is contained in:
nevermind322 2024-06-06 23:10:38 +03:00 committed by GitHub
parent 9f8f982cc2
commit 133d082e4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 1133 additions and 59 deletions

View file

@ -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);

View file

@ -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

View file

@ -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<ScopeSyntax>();
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;
}

View file

@ -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<ScopeSyntax> path;
public BindResult(SymInfoSyntax s, List<ScopeSyntax> p)
{
symInfo = s;
path = p;
}
}
public abstract class ScopeSyntax
{
public syntax_tree_node node;

View file

@ -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<statement> desugar(tuple_node tn, addressed_value_list vars)
{
var order = Assign.getAssignOrder(tn, vars, binder);
var assigns = new List<statement>();
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);
}
}
}

View file

@ -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<Assign> getAssignOrder(tuple_node tn, addressed_value_list vars, BindCollectLightSymInfo binder)
{
var left = new List<Symbol>();
var right = new List<Symbol>();
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();
}
}
}

View file

@ -0,0 +1,166 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace AssignTupleDesugarAlgorithm
{
internal class AssignGraph : IEnumerable<SymbolNode>
{
public readonly HashSet<SymbolNode> vertexes = new HashSet<SymbolNode>();
public readonly List<Edge> edges = new List<Edge>();
private bool AdjStructuresNeedSync = false;
public List<Edge> assignOrder = new List<Edge>();
public List<Edge> assignLast = new List<Edge>();
public List<Edge> assignFirst = new List<Edge>();
private Dictionary<SymbolNode, List<SymbolNode>> outAdjStructure = null;
public Dictionary<SymbolNode, List<SymbolNode>> OutAdjStructure
{
get
{
if (outAdjStructure == null || AdjStructuresNeedSync)
{
outAdjStructure = createOutAdjStructure();
inAdjStructure = createInAdjStructure();
AdjStructuresNeedSync = false;
}
return outAdjStructure;
}
}
private Dictionary<SymbolNode, List<SymbolNode>> createOutAdjStructure()
{
Dictionary<SymbolNode, List<SymbolNode>> res = new Dictionary<SymbolNode, List<SymbolNode>>();
foreach (var vert in vertexes) res.Add(vert, new List<SymbolNode>());
foreach (Edge edge in edges) res[edge.from].Add(edge.to);
return res;
}
private Dictionary<SymbolNode, List<SymbolNode>> inAdjStructure = null;
public Dictionary<SymbolNode, List<SymbolNode>> InAdjStructure
{
get
{
if (inAdjStructure == null || AdjStructuresNeedSync)
{
outAdjStructure = createOutAdjStructure();
inAdjStructure = createInAdjStructure();
AdjStructuresNeedSync = false;
}
return inAdjStructure;
}
}
private Dictionary<SymbolNode, List<SymbolNode>> createInAdjStructure()
{
Dictionary<SymbolNode, List<SymbolNode>> res = new Dictionary<SymbolNode, List<SymbolNode>>();
foreach (var vert in vertexes) res.Add(vert, new List<SymbolNode>());
foreach (Edge edge in edges) res[edge.to].Add(edge.from);
return res;
}
public List<Edge> GetInEdgesForVertex(SymbolNode v) => edges.FindAll(edge => edge.to == v);
public List<Edge> 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<Edge> GetAssignOrder()
{
List<Edge> assignOrder = new List<Edge>();
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<SymbolNode> 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<Edge> edges, List<SymbolNode> vertexes) : this(edges)
{
foreach (SymbolNode vert in vertexes) this.vertexes.Add(vert);
}
public AssignGraph()
{
}
public AssignGraph(List<Edge> e)
{
edges = e;
foreach (var edge in edges)
{
vertexes.Add(edge.from);
vertexes.Add(edge.to);
}
}
public IEnumerator<SymbolNode> GetEnumerator()
{
return ((IEnumerable<SymbolNode>)vertexes).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)vertexes).GetEnumerator();
}
}
}

View file

@ -0,0 +1,31 @@
using System.Collections.Generic;
namespace AssignTupleDesugarAlgorithm
{
internal class Cycle
{
List<SymbolNode> cycle;
public int Len => cycle.Count;
public Cycle(List<SymbolNode> 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];
}
}
}

View file

@ -0,0 +1,30 @@
using System;
namespace AssignTupleDesugarAlgorithm
{
internal class Edge : IEquatable<Edge>, IComparable<Edge>
{
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;
}
}
}

View file

@ -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<AssignGraph> OnEnterGraph,
Func<AssignGraph, SymbolNode, bool> OnProcessVertex,
Action<AssignGraph, SymbolNode> OnEnterNode,
Func<AssignGraph, SymbolNode, SymbolNode, bool> OnProcessNodeChild,
Action<AssignGraph, SymbolNode> OnLeaveNode,
Action<AssignGraph> OnLeaveGraph,
Func<AssignGraph, SymbolNode, IEnumerable<SymbolNode>> vertexTraversalOrderFunc = null,
IEnumerable<SymbolNode> graphTraversalOrder = null)
{
void dfs(SymbolNode start_node,
Action<AssignGraph, SymbolNode> OnEnter,
Func<AssignGraph, SymbolNode, SymbolNode, bool> OnProcessChild,
Action<AssignGraph, SymbolNode> OnLeave
)
{
OnEnter(graph, start_node);
IEnumerable<SymbolNode> 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<int> left = new HashSet<int>();
public HashSet<int> right = new HashSet<int>();
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<Symbol> left, List<Symbol> right)
{
if (right.Count < left.Count) throw new Exception("AAAA");
List<SymbolNode> v_left = new List<SymbolNode>();
List<SymbolNode> v_right = new List<SymbolNode>();
List<Symbol> left_visited = new List<Symbol>();
List<Edge> assign_first = new List<Edge>();
List<Edge> assign_last = new List<Edge>();
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<string, SynonymsGraph>();
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<Symbol>(left);
var rightSet = new HashSet<Symbol>(right);
var graphs = new List<SynonymsGraph>();
graphs.AddRange(nameToGraph.Values);
graphs.Add(indexerGraph);
var moved_first = new List<Edge>();
var moved_last = new LinkedList<Edge>();
var movedAssigns = new HashSet<int>();
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<string, SymbolNode>();
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<Edge> assigns = new List<Edge>();
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<Edge> make2n(List<Symbol> left, List<Symbol> right)
{
var temps = new List<SymbolNode>();
var res = new List<Edge>();
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<Edge> newEdges = new List<Edge>();
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<List<SymbolNode>> findStronglyConnectedComponets(this AssignGraph g)
{
List<List<SymbolNode>> res = new List<List<SymbolNode>>();
Stack<SymbolNode> route = new Stack<SymbolNode>();
HashSet<SymbolNode> visited = new HashSet<SymbolNode>();
Action<AssignGraph> onEnterGraph = (_) =>
{
route.Clear();
visited.Clear();
};
Action<AssignGraph, SymbolNode> onEnterNode = (graph, node) => { visited.Add(node); };
Action<AssignGraph, SymbolNode> onLeaveNode = (graph, node) => { route.Push(node); };
Func<AssignGraph, SymbolNode, SymbolNode, bool> onProcessChildNode = (graph, parent, childNode) =>
{
if (!visited.Contains(childNode))
{
return true;
}
else return false;
};
Func<AssignGraph, SymbolNode, bool> onProcessVertex = (graph, vert) => { return !visited.Contains(vert); };
g.dfs(OnEnterGraph: onEnterGraph, OnProcessVertex: onProcessVertex,
OnEnterNode: onEnterNode, OnProcessNodeChild: onProcessChildNode,
OnLeaveNode: onLeaveNode,
OnLeaveGraph: (_) => { }
);
Action<AssignGraph> onEnterGraphReversed = (_) => { visited.Clear(); };
Action<AssignGraph, SymbolNode> onEnterNodeReversed = (graph, node) =>
{
visited.Add(node);
res.Last().Add(node);
};
Action<AssignGraph, SymbolNode> onLeaveNodeReversed = (graph, node) => { };
Func<AssignGraph, SymbolNode, SymbolNode, bool> onProcessChildNodeReversed = (graph, parent, childNode) =>
{
if (!visited.Contains(childNode))
{
return true;
}
else return false;
};
Func<AssignGraph, SymbolNode, bool> onProcessVertexReversed = (graph, vert) =>
{
if (visited.Contains(vert)) return false;
else
{
res.Add(new List<SymbolNode>());
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<Cycle> findAllUniqueElementaryCycles(this AssignGraph g)
{
var res = new List<Cycle>();
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<AssignGraph> enterGraph = (graph) => { graph.resetVertexesColor(); };
Func<AssignGraph, SymbolNode, bool> ProcessNode = (graph, node) => node.color != SymbolNode.Color.GREY;
Action<AssignGraph, SymbolNode> EnterNode = (graph, vert) => { vert.color = SymbolNode.Color.GREY; };
Func<AssignGraph, SymbolNode, SymbolNode, bool> 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();
}
}
}

View file

@ -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<string>.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 => "<tup_opt>" + counter++;
public TempSymbol() : base(new ident(getTempPrefix), null)
{
type = Type.LOCAL;
}
}
}

View file

@ -0,0 +1,67 @@
using System;
namespace AssignTupleDesugarAlgorithm
{
internal class SymbolNode : IEquatable<SymbolNode>
{
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)
{
}
}
}

View file

@ -14,11 +14,14 @@ namespace SyntaxVisitors.SugarVisitors
/// </summary>
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<statement>();
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<statement>();
for (var i = 0; i < n; i++)
// Оптимизация, т.к. все - константы
var sl = new List<statement>();
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<statement>();
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);
}
}

View file

@ -52,6 +52,14 @@
<Compile Include="LightSymInfoVisitors\CollectLightSymInfoVisitor.cs" />
<Compile Include="LightSymInfoVisitors\LightScopeCreator.cs" />
<Compile Include="LightSymInfoVisitors\LightScopeHelperClasses.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\Assign.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\AssignGraph.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\Cycle.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\Edge.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\GraphUtils.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\Symbol.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\desugarAlgoritm\SymbolNode.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\NewAssignTuplesDesugarVisitor.cs" />
<Compile Include="SugarVisitors\CacheFunctionVisitor.cs" />
<Compile Include="SugarVisitors\LetExprVisitor.cs" />
<Compile Include="SugarVisitors\TestAssignIsDefVisitor.cs" />
@ -61,11 +69,12 @@
<Compile Include="BaseVisitors\SmallHelperVisitors.cs" />
<Compile Include="ChangeWhileVisitor.cs" />
<Compile Include="CheckingVisitors\UnnamedRecordsCheckErrorsVisitor.cs" />
<Compile Include="LightSymInfoVisitors\LightScopeHelperClasses.cs" />
<Compile Include="PatternsVisitors\ExtendedIsDesugaringVisitor.cs" />
<Compile Include="PatternsVisitors\PatternsDesugaringVisitor.cs" />
<Compile Include="PatternsVisitors\ReplaceNamesInIsVarVisitor.cs" />
<Compile Include="PatternsVisitors\SingleDeconstructChecker.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor.cs" />
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor\AssignTuplesDesugarVisitor.cs" />
<Compile Include="SugarVisitors\DoubleQuestionDesugarVisitor.cs" />
<Compile Include="SugarVisitors\IndexVisitor.cs" />
<Compile Include="SugarVisitors\LoopDesugarVisitor.cs" />

Binary file not shown.