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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
using Antlr4.Runtime;
using Antlr4.Runtime.Atn;
using Antlr4.Runtime.Misc;
using Antlr4.Runtime.Sharpen;
namespace Antlr4.Runtime.Atn
{
/// <summary>
/// Represents an executor for a sequence of lexer actions which traversed during
/// the matching operation of a lexer rule (token).
/// </summary>
/// <remarks>
/// Represents an executor for a sequence of lexer actions which traversed during
/// the matching operation of a lexer rule (token).
/// <p>The executor tracks position information for position-dependent lexer actions
/// efficiently, ensuring that actions appearing only at the end of the rule do
/// not cause bloating of the
/// <see cref="Antlr4.Runtime.Dfa.DFA"/>
/// created for the lexer.</p>
/// </remarks>
/// <author>Sam Harwell</author>
/// <since>4.2</since>
public class LexerActionExecutor
{
[NotNull]
private readonly ILexerAction[] lexerActions;
/// <summary>
/// Caches the result of
/// <see cref="hashCode"/>
/// since the hash code is an element
/// of the performance-critical
/// <see cref="ATNConfig.GetHashCode()"/>
/// operation.
/// </summary>
private readonly int hashCode;
/// <summary>
/// Constructs an executor for a sequence of
/// <see cref="ILexerAction"/>
/// actions.
/// </summary>
/// <param name="lexerActions">The lexer actions to execute.</param>
public LexerActionExecutor(ILexerAction[] lexerActions)
{
this.lexerActions = lexerActions;
int hash = MurmurHash.Initialize();
foreach (ILexerAction lexerAction in lexerActions)
{
hash = MurmurHash.Update(hash, lexerAction);
}
this.hashCode = MurmurHash.Finish(hash, lexerActions.Length);
}
/// <summary>
/// Creates a
/// <see cref="LexerActionExecutor"/>
/// which executes the actions for
/// the input
/// <paramref name="lexerActionExecutor"/>
/// followed by a specified
/// <paramref name="lexerAction"/>
/// .
/// </summary>
/// <param name="lexerActionExecutor">
/// The executor for actions already traversed by
/// the lexer while matching a token within a particular
/// <see cref="ATNConfig"/>
/// . If this is
/// <see langword="null"/>
/// , the method behaves as though
/// it were an empty executor.
/// </param>
/// <param name="lexerAction">
/// The lexer action to execute after the actions
/// specified in
/// <paramref name="lexerActionExecutor"/>
/// .
/// </param>
/// <returns>
/// A
/// <see cref="LexerActionExecutor"/>
/// for executing the combine actions
/// of
/// <paramref name="lexerActionExecutor"/>
/// and
/// <paramref name="lexerAction"/>
/// .
/// </returns>
[return: NotNull]
public static Antlr4.Runtime.Atn.LexerActionExecutor Append(Antlr4.Runtime.Atn.LexerActionExecutor lexerActionExecutor, ILexerAction lexerAction)
{
if (lexerActionExecutor == null)
{
return new Antlr4.Runtime.Atn.LexerActionExecutor(new ILexerAction[] { lexerAction });
}
ILexerAction[] lexerActions = Arrays.CopyOf(lexerActionExecutor.lexerActions, lexerActionExecutor.lexerActions.Length + 1);
lexerActions[lexerActions.Length - 1] = lexerAction;
return new Antlr4.Runtime.Atn.LexerActionExecutor(lexerActions);
}
/// <summary>
/// Creates a
/// <see cref="LexerActionExecutor"/>
/// which encodes the current offset
/// for position-dependent lexer actions.
/// <p>Normally, when the executor encounters lexer actions where
/// <see cref="ILexerAction.IsPositionDependent()"/>
/// returns
/// <see langword="true"/>
/// , it calls
/// <see cref="Antlr4.Runtime.IIntStream.Seek(int)"/>
/// on the input
/// <see cref="Antlr4.Runtime.ICharStream"/>
/// to set the input
/// position to the <em>end</em> of the current token. This behavior provides
/// for efficient DFA representation of lexer actions which appear at the end
/// of a lexer rule, even when the lexer rule matches a variable number of
/// characters.</p>
/// <p>Prior to traversing a match transition in the ATN, the current offset
/// from the token start index is assigned to all position-dependent lexer
/// actions which have not already been assigned a fixed offset. By storing
/// the offsets relative to the token start index, the DFA representation of
/// lexer actions which appear in the middle of tokens remains efficient due
/// to sharing among tokens of the same length, regardless of their absolute
/// position in the input stream.</p>
/// <p>If the current executor already has offsets assigned to all
/// position-dependent lexer actions, the method returns
/// <c>this</c>
/// .</p>
/// </summary>
/// <param name="offset">
/// The current offset to assign to all position-dependent
/// lexer actions which do not already have offsets assigned.
/// </param>
/// <returns>
/// A
/// <see cref="LexerActionExecutor"/>
/// which stores input stream offsets
/// for all position-dependent lexer actions.
/// </returns>
public virtual Antlr4.Runtime.Atn.LexerActionExecutor FixOffsetBeforeMatch(int offset)
{
ILexerAction[] updatedLexerActions = null;
for (int i = 0; i < lexerActions.Length; i++)
{
if (lexerActions[i].IsPositionDependent && !(lexerActions[i] is LexerIndexedCustomAction))
{
if (updatedLexerActions == null)
{
updatedLexerActions = (ILexerAction[])lexerActions.Clone();
}
updatedLexerActions[i] = new LexerIndexedCustomAction(offset, lexerActions[i]);
}
}
if (updatedLexerActions == null)
{
return this;
}
return new Antlr4.Runtime.Atn.LexerActionExecutor(updatedLexerActions);
}
/// <summary>Gets the lexer actions to be executed by this executor.</summary>
/// <remarks>Gets the lexer actions to be executed by this executor.</remarks>
/// <returns>The lexer actions to be executed by this executor.</returns>
[NotNull]
public virtual ILexerAction[] LexerActions
{
get
{
return lexerActions;
}
}
/// <summary>
/// Execute the actions encapsulated by this executor within the context of a
/// particular
/// <see cref="Antlr4.Runtime.Lexer"/>
/// .
/// <p>This method calls
/// <see cref="Antlr4.Runtime.IIntStream.Seek(int)"/>
/// to set the position of the
/// <paramref name="input"/>
///
/// <see cref="Antlr4.Runtime.ICharStream"/>
/// prior to calling
/// <see cref="ILexerAction.Execute(Antlr4.Runtime.Lexer)"/>
/// on a position-dependent action. Before the
/// method returns, the input position will be restored to the same position
/// it was in when the method was invoked.</p>
/// </summary>
/// <param name="lexer">The lexer instance.</param>
/// <param name="input">
/// The input stream which is the source for the current token.
/// When this method is called, the current
/// <see cref="Antlr4.Runtime.IIntStream.Index()"/>
/// for
/// <paramref name="input"/>
/// should be the start of the following token, i.e. 1
/// character past the end of the current token.
/// </param>
/// <param name="startIndex">
/// The token start index. This value may be passed to
/// <see cref="Antlr4.Runtime.IIntStream.Seek(int)"/>
/// to set the
/// <paramref name="input"/>
/// position to the beginning
/// of the token.
/// </param>
public virtual void Execute(Lexer lexer, ICharStream input, int startIndex)
{
bool requiresSeek = false;
int stopIndex = input.Index;
try
{
foreach (ILexerAction lexerAction in lexerActions)
{
ILexerAction action = lexerAction;
if (action is LexerIndexedCustomAction)
{
int offset = ((LexerIndexedCustomAction)action).Offset;
input.Seek(startIndex + offset);
action = ((LexerIndexedCustomAction)action).Action;
requiresSeek = (startIndex + offset) != stopIndex;
}
else
{
if (action.IsPositionDependent)
{
input.Seek(stopIndex);
requiresSeek = false;
}
}
action.Execute(lexer);
}
}
finally
{
if (requiresSeek)
{
input.Seek(stopIndex);
}
}
}
public override int GetHashCode()
{
return this.hashCode;
}
public override bool Equals(object obj)
{
if (obj == this)
{
return true;
}
else
{
if (!(obj is Antlr4.Runtime.Atn.LexerActionExecutor))
{
return false;
}
}
Antlr4.Runtime.Atn.LexerActionExecutor other = (Antlr4.Runtime.Atn.LexerActionExecutor)obj;
return hashCode == other.hashCode && Arrays.Equals(lexerActions, other.lexerActions);
}
}
}