Assign tuple optimizer (#3162)

* 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 <miks@math.sfedu.ru>
Co-authored-by: Артём Филонов <afilono@sfedu.ru>
Co-authored-by: Sun Serega <sunserega2@gmail.com>
This commit is contained in:
nevermind322 2024-07-08 20:35:57 +03:00 committed by GitHub
parent b086568133
commit f680461234
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 1247 additions and 82 deletions

View file

@ -15,7 +15,9 @@ namespace Languages.Pascal.Frontend.Converters
protected override syntax_tree_node ApplyConcreteConversions(syntax_tree_node root) protected override syntax_tree_node ApplyConcreteConversions(syntax_tree_node root)
{ {
root.FillParentsInAllChilds();
var binder = new BindCollectLightSymInfo(root as compilation_unit);
#if DEBUG #if DEBUG
// var stat = new ABCStatisticsVisitor(); // var stat = new ABCStatisticsVisitor();
// stat.ProcessNode(root); // stat.ProcessNode(root);
@ -42,9 +44,9 @@ namespace Languages.Pascal.Frontend.Converters
#if DEBUG #if DEBUG
//new SimplePrettyPrinterVisitor("D:/out.txt").ProcessNode(root); //new SimplePrettyPrinterVisitor("D:/out.txt").ProcessNode(root);
#endif #endif
bool optimize_tuple_assign = true;
// tuple_node // tuple_node
TupleVisitor.New.ProcessNode(root); TupleVisitor.Create(optimize_tuple_assign).ProcessNode(root);
// index // index
IndexVisitor.New.ProcessNode(root); 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]); // теперь коллизия с (a[1:6], a[6:11]):= (a[6:11], a[1:6]);
// assign_tuple и assign_var_tuple // 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 // question_point_desugar_visitor
QuestionPointDesugarVisitor.New.ProcessNode(root); QuestionPointDesugarVisitor.New.ProcessNode(root);

View file

@ -1,4 +1,5 @@
 using System.Collections.Generic;
using System.Linq;
namespace PascalABCCompiler.SyntaxTree namespace PascalABCCompiler.SyntaxTree
{ {
@ -12,22 +13,23 @@ namespace PascalABCCompiler.SyntaxTree
{ {
Current = Root; Current = Root;
visit(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; syntax_tree_node cur_node = node;
var path = new Queue<ScopeSyntax>();
while (cur_node != null) while (cur_node != null)
{ {
// Console.WriteLine("cur_node: " + cur_node.ToString());
if (AbstractScopeCreator.IsScopeCreator(cur_node)) if (AbstractScopeCreator.IsScopeCreator(cur_node))
{ {
//Console.WriteLine("checking scope" + cur_node.ToString())
var cur_scope = scopeCreator.GetScope(cur_node); var cur_scope = scopeCreator.GetScope(cur_node);
//Console.WriteLine(cur_scope.ToString() + ": " + cur_scope.Symbols.Count); path.Enqueue(cur_scope);
var prev_scope = Current; var prev_scope = Current;
if (prev_scope != null) if (prev_scope != null)
@ -36,11 +38,10 @@ namespace PascalABCCompiler.SyntaxTree
Current = cur_scope; Current = cur_scope;
if (cur_scope.Parent == null && !(Current is GlobalScopeSyntax)) if (cur_scope.Parent == null && !(Current is GlobalScopeSyntax))
{ {
//Console.WriteLine("visiting " + cur_node.ToString());
cur_node.visit(this); cur_node.visit(this);
} }
var res = Current.bind(node); var res = Current.bind(node);
if (res != null) return res; if (res != null) return new BindResult(res, path.ToList());
} }
cur_node = cur_node.Parent; cur_node = cur_node.Parent;
} }

View file

@ -38,6 +38,20 @@ namespace PascalABCCompiler.SyntaxTree
AddSymbols(vd.vars.list, SymKind.var, vd.vars_type, attr); AddSymbols(vd.vars.list, SymKind.var, vd.vars_type, attr);
base.visit(vd); 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) public override void visit(formal_parameters fp)
{ {
foreach (var pg in fp.params_list) foreach (var pg in fp.params_list)

View file

@ -22,7 +22,7 @@ namespace PascalABCCompiler.SyntaxTree
recordname, interfacename, template_param, type_alias, const_var, property }; recordname, interfacename, template_param, type_alias, const_var, property };
[Flags] [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 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 abstract class ScopeSyntax
{ {
public syntax_tree_node node; public syntax_tree_node node;

View file

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

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,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<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>();
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 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<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);
//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<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,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<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> /// </summary>
public class TupleVisitor : BaseChangeVisitor 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; private int num = 0;
public string UniqueName() public string UniqueName()
{ {
@ -59,81 +62,97 @@ namespace SyntaxVisitors.SugarVisitors
// Остальное раскрывается в AssignTuplesDesugarVisitor // Остальное раскрывается в AssignTuplesDesugarVisitor
public override void visit(assign_var_tuple assvartup) 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 (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
if (n > tn.el.Count)
throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", assvartup.idents[0]);
// Оптимизация, т.к. все - константы
var sl = new List<statement>();
for (var i = 0; i < n; i++)
{ {
var a = new var_statement( var n = assvartup.idents.idents.Count();
assvartup.idents.idents[i], if (n > tn.el.Count)
tn.el.expressions[i], throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", assvartup.idents[0]);
assvartup.idents.idents[i].source_context);
sl.Add(a); // Оптимизация, т.к. все - константы
var sl = new List<statement>();
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 else
{ {
DefaultVisit(assvartup); DefaultVisit(assvartup);
} }
} }
public override void visit(assign_tuple asstup) 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 (tn.el.expressions.All(ex => ex is const_node) && !tn.el.expressions.Any(ex => ex is nil_const))
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 a = new assign(asstup.vars.variables[i], var n = asstup.vars.variables.Count();
tn.el.expressions[i], if (n > tn.el.Count)
Operators.Assignment, throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]);
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 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 (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 n = asstup.vars.variables.Count();
var var_def = new var_def_statement(temp_id, tn1.el.expressions[i], tn1.el.expressions[i].source_context); if (n > tn.el.Count)
var a = new var_statement(var_def, tn1.el.expressions[i].source_context); throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", asstup.vars.variables[0]);
sl.Add(a);
}
//for (var i = 0; i < n; i++) var sl = new List<statement>();
for (var i = n-1; i >= 0; i--) for (var i = 0; i < n; i++)
{ {
var a = new assign(asstup.vars.variables[i], var temp_id = new ident(UniqueName(), tn.el.expressions[i].source_context);
(sl[i] as var_statement).var_def.vars.idents[0], var var_def = new var_def_statement(temp_id, tn.el.expressions[i], tn.el.expressions[i].source_context);
Operators.Assignment, var a = new var_statement(var_def, tn.el.expressions[i].source_context);
asstup.vars.variables[i].source_context); sl.Add(a);
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 else
{ {
DefaultVisit(asstup); DefaultVisit(asstup);
} }
} }
public void ReplaceVarTupleDefStatementUsingParent(var_tuple_def_statement from, IEnumerable<var_def_statement> to) public void ReplaceVarTupleDefStatementUsingParent(var_tuple_def_statement from, IEnumerable<var_def_statement> to)
@ -150,27 +169,34 @@ namespace SyntaxVisitors.SugarVisitors
// А это по идее до begin - там немного другие узлы и внешний контекст // А это по идее до begin - там немного другие узлы и внешний контекст
public override void visit(var_tuple_def_statement vtd) 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)) 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 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<var_def_statement>();
for (var i = 0; i < n; i++)
{ {
var a = new var_def_statement(vtd.vars.idents[i], var n = vtd.vars.idents.Count();
tn.el.expressions[i], if (n > tn.el.Count)
vtd.vars.idents[i].source_context); throw new SyntaxVisitorError("TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT", vtd.vars.idents[0]);
vd.Add(a);
var vd = new List<var_def_statement>();
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); else if (optimize_tuple_assign)
visit(vtd.inital_value); return;
else
DefaultVisit(vtd);
} }
else else
{ {
DefaultVisit(vtd); DefaultVisit(vtd);
} }
} }
public override void visit(tuple_node tup) public override void visit(tuple_node tup)

View file

@ -52,6 +52,14 @@
<Compile Include="LightSymInfoVisitors\CollectLightSymInfoVisitor.cs" /> <Compile Include="LightSymInfoVisitors\CollectLightSymInfoVisitor.cs" />
<Compile Include="LightSymInfoVisitors\LightScopeCreator.cs" /> <Compile Include="LightSymInfoVisitors\LightScopeCreator.cs" />
<Compile Include="LightSymInfoVisitors\LightScopeHelperClasses.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\CacheFunctionVisitor.cs" />
<Compile Include="SugarVisitors\LetExprVisitor.cs" /> <Compile Include="SugarVisitors\LetExprVisitor.cs" />
<Compile Include="SugarVisitors\TestAssignIsDefVisitor.cs" /> <Compile Include="SugarVisitors\TestAssignIsDefVisitor.cs" />
@ -65,7 +73,7 @@
<Compile Include="PatternsVisitors\PatternsDesugaringVisitor.cs" /> <Compile Include="PatternsVisitors\PatternsDesugaringVisitor.cs" />
<Compile Include="PatternsVisitors\ReplaceNamesInIsVarVisitor.cs" /> <Compile Include="PatternsVisitors\ReplaceNamesInIsVarVisitor.cs" />
<Compile Include="PatternsVisitors\SingleDeconstructChecker.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\DoubleQuestionDesugarVisitor.cs" />
<Compile Include="SugarVisitors\IndexVisitor.cs" /> <Compile Include="SugarVisitors\IndexVisitor.cs" />
<Compile Include="SugarVisitors\LoopDesugarVisitor.cs" /> <Compile Include="SugarVisitors\LoopDesugarVisitor.cs" />