-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIntroduceVariableDeclarations.cs
More file actions
94 lines (80 loc) · 3.53 KB
/
Copy pathIntroduceVariableDeclarations.cs
File metadata and controls
94 lines (80 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.ILAst;
using JSIL.Ast;
using JSIL.Internal;
namespace JSIL.Transforms {
public class IntroduceVariableDeclarations : JSAstVisitor {
public readonly HashSet<JSVariable> ToDeclare = new HashSet<JSVariable>();
public readonly List<KeyValuePair<JSNode, JSNode>> ToReplace = new List<KeyValuePair<JSNode, JSNode>>();
public readonly HashSet<JSVariable> SeenAlready = new HashSet<JSVariable>();
public readonly HashSet<JSVariable> CouldntDeclare = new HashSet<JSVariable>();
public readonly IDictionary<string, JSVariable> Variables;
public readonly ITypeInfoSource TypeInfo;
public IntroduceVariableDeclarations (IDictionary<string, JSVariable> variables, ITypeInfoSource typeInfo) {
Variables = variables;
TypeInfo = typeInfo;
}
public void VisitNode (JSFunctionExpression fn) {
var existingDeclarations = new HashSet<string>(
fn.AllChildrenRecursive.OfType<JSVariableDeclarationStatement>()
.SelectMany(
(vds) =>
from vd in vds.Declarations
select ((JSVariable)vd.Left).Identifier
).Union(
from tcb in fn.AllChildrenRecursive.OfType<JSTryCatchBlock>()
where tcb.CatchVariable != null
select tcb.CatchVariable.Identifier
)
);
foreach (var v_ in from v in Variables.Values
where !v.IsParameter &&
!existingDeclarations.Contains(v.Identifier)
select v)
{
ToDeclare.Add(v_);
}
VisitChildren(fn);
foreach (var kvp in ToReplace)
fn.ReplaceChildRecursive(kvp.Key, kvp.Value);
if (ToDeclare.Count > 0)
fn.Body.Statements.Insert(
0, new JSVariableDeclarationStatement(
(from v in ToDeclare
select new JSBinaryOperatorExpression(
JSOperator.Assignment, v,
v.DefaultValue,
v.IdentifierType
)).ToArray()
)
);
}
public void VisitNode (JSVariable v) {
SeenAlready.Add(v);
VisitChildren(v);
}
public void VisitNode (JSBinaryOperatorExpression boe) {
var isAssignment = boe.Operator == JSOperator.Assignment;
var leftVar = boe.Left as JSVariable;
if (
(leftVar != null) && isAssignment && !leftVar.IsParameter
) {
if (ToDeclare.Contains(leftVar) && !CouldntDeclare.Contains(leftVar) && !SeenAlready.Contains(leftVar)) {
var superParent = Stack.Skip(2).FirstOrDefault();
if ((superParent != null) && (ParentNode is JSStatement)) {
ToDeclare.Remove(leftVar);
ToReplace.Add(new KeyValuePair<JSNode, JSNode>(ParentNode, new JSVariableDeclarationStatement(boe)));
VisitChildren(boe);
return;
} else {
CouldntDeclare.Add(leftVar);
}
}
}
VisitChildren(boe);
}
}
}