forked from pasztorpisti/vs-window-title-changer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ExpressionCompilerThread.cs
170 lines (148 loc) · 4.22 KB
/
ExpressionCompilerThread.cs
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using VSWindowTitleChanger.ExpressionEvaluator;
namespace VSWindowTitleChanger
{
// A simple job executor thread. Its queue can be cleared anytime and it can be
// stopped without processing all jobs in the queue.
class ExpressionCompilerThread : IDisposable
{
Thread m_Thread;
AutoResetEvent m_WakeUpEvent = new AutoResetEvent(false);
LinkedList<IJob> m_Jobs = new LinkedList<IJob>();
bool m_StopRequest;
public ExpressionCompilerThread()
{
m_Thread = new Thread(new ThreadStart(Run));
m_Thread.Start();
}
public virtual void Dispose()
{
lock (this)
{
m_StopRequest = true;
m_WakeUpEvent.Set();
}
m_Thread.Join();
}
public void AddJob(IJob job)
{
lock (this)
{
m_Jobs.AddLast(job);
m_WakeUpEvent.Set();
}
}
public void RemoveAllJobs()
{
lock (this)
{
m_Jobs.Clear();
}
}
void Run()
{
for (;;)
{
m_WakeUpEvent.WaitOne();
// FIXME: BUG: After waiting for the event we should
// remove jobs in a loop until m_Jobs is empty.
IJob job;
lock (this)
{
if (m_StopRequest)
break;
job = m_Jobs.First.Value;
m_Jobs.RemoveFirst();
}
// FIXME: some people experience NullPointerException somewhere
// in this Run method. It might be job or something inside Execute.
job.Execute();
}
}
public interface IJob
{
void Execute();
}
}
class ExpressionCompilerJob : ExpressionCompilerThread.IJob
{
Parser m_Parser;
IEvalContext m_EvalContext;
bool m_CollectUnresolvedVariables;
CompiledExpressionCache m_Cache;
// The variable_value_resolver is used only to find the unused variables, the variable values aren't used.
// variable_value_resolver can be null, in that case unused variables aren't explored.
// cache can be null.
public ExpressionCompilerJob(Parser parser, IEvalContext eval_ctx, bool collect_unresolved_variables, CompiledExpressionCache cache)
{
m_Parser = parser;
m_EvalContext = eval_ctx;
m_CollectUnresolvedVariables = collect_unresolved_variables;
m_Cache = cache;
}
public delegate void CompileFinishedHandler(ExpressionCompilerJob job);
public event CompileFinishedHandler OnCompileFinished;
IntPtr m_UserData;
public IntPtr UserData { get { return m_UserData; } set { m_UserData = value; } }
Exception m_Error;
Expression m_Expression;
Value m_EvalResult;
List<Variable> m_SortedUnresolvedVariables;
bool m_ContainsExec;
public Exception Error { get { return m_Error; } }
// Only if there is no error:
public Expression Expession { get { return m_Expression; } }
public Value EvalResult { get { return m_EvalResult; } }
public bool ContainsExec { get { return m_ContainsExec; } }
public List<Variable> SortedUnresolvedVariables { get { return m_SortedUnresolvedVariables; } }
class VariablePosComparer : IComparer<Variable>
{
public virtual int Compare(Variable a, Variable b)
{
return a.Position - b.Position;
}
}
public virtual void Execute()
{
Debug.Assert(m_Error == null && m_Expression == null);
try
{
if (m_Cache != null)
{
CompiledExpression compiled_expression = m_Cache.GetEntry(m_Parser.Text);
m_Expression = compiled_expression.expression;
m_Error = compiled_expression.compile_error;
m_ContainsExec = compiled_expression.contains_exec;
}
else
{
m_Expression = m_Parser.Parse();
m_ContainsExec = m_Parser.ContainsExec;
}
if (m_Expression != null && m_EvalContext != null)
{
m_EvalResult = m_Expression.Evaluate(new SafeEvalContext(m_EvalContext));
if (m_CollectUnresolvedVariables)
{
m_SortedUnresolvedVariables = m_Expression.CollectUnresolvedVariables(m_EvalContext);
m_SortedUnresolvedVariables.Sort(new VariablePosComparer());
}
}
}
catch (Exception ex)
{
m_Error = ex;
}
PackageGlobals.BeginInvokeOnUIThread(delegate()
{
if (OnCompileFinished != null)
{
OnCompileFinished(this);
}
});
}
}
}