Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
XPathParser.cs
Go to the documentation of this file.
3
5
6internal sealed class XPathParser<Node>
7{
9
11
12 private readonly Stack<int> _posInfo = new Stack<int>();
13
14 private int _parseRelativePath;
15
16 private int _parseSubExprDepth;
17
18 private static readonly int[] s_XPathOperatorPrecedence = new int[16]
19 {
20 0, 1, 2, 3, 3, 4, 4, 4, 4, 5,
21 5, 6, 6, 6, 7, 8
22 };
23
25 {
26 Node result = default(Node);
30 try
31 {
32 builder.StartBuild();
33 result = ParseExpr();
34 scanner.CheckToken(endLex);
35 }
37 {
38 if (ex.queryString == null)
39 {
40 ex.queryString = scanner.Source;
41 PopPosInfo(out ex.startChar, out ex.endChar);
42 }
43 throw;
44 }
45 finally
46 {
47 result = builder.EndBuild(result);
48 }
49 return result;
50 }
51
52 internal static bool IsStep(LexKind lexKind)
53 {
54 if (lexKind != LexKind.Dot && lexKind != LexKind.DotDot && lexKind != LexKind.At && lexKind != LexKind.Axis && lexKind != LexKind.Star)
55 {
56 return lexKind == LexKind.Name;
57 }
58 return true;
59 }
60
62 {
63 if (_scanner.Kind == LexKind.Slash)
64 {
66 Node val = _builder.Axis(XPathAxis.Root, XPathNodeType.All, null, null);
67 if (IsStep(_scanner.Kind))
68 {
69 val = _builder.JoinStep(val, ParseRelativeLocationPath());
70 }
71 return val;
72 }
73 if (_scanner.Kind == LexKind.SlashSlash)
74 {
76 return _builder.JoinStep(_builder.Axis(XPathAxis.Root, XPathNodeType.All, null, null), _builder.JoinStep(_builder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null), ParseRelativeLocationPath()));
77 }
79 }
80
82 {
84 {
86 }
87 Node val = ParseStep();
88 if (_scanner.Kind == LexKind.Slash)
89 {
91 val = _builder.JoinStep(val, ParseRelativeLocationPath());
92 }
93 else if (_scanner.Kind == LexKind.SlashSlash)
94 {
96 val = _builder.JoinStep(val, _builder.JoinStep(_builder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null), ParseRelativeLocationPath()));
97 }
99 return val;
100 }
101
102 private Node ParseStep()
103 {
104 Node val;
105 if (LexKind.Dot == _scanner.Kind)
106 {
108 val = _builder.Axis(XPathAxis.Self, XPathNodeType.All, null, null);
109 if (LexKind.LBracket == _scanner.Kind)
110 {
112 }
113 }
114 else if (LexKind.DotDot == _scanner.Kind)
115 {
117 val = _builder.Axis(XPathAxis.Parent, XPathNodeType.All, null, null);
118 if (LexKind.LBracket == _scanner.Kind)
119 {
121 }
122 }
123 else
124 {
126 switch (_scanner.Kind)
127 {
128 case LexKind.Axis:
132 break;
133 case LexKind.At:
134 axis = XPathAxis.Attribute;
136 break;
137 case LexKind.Name:
138 case LexKind.Star:
139 axis = XPathAxis.Child;
140 break;
141 default:
143 }
144 val = ParseNodeTest(axis);
145 while (LexKind.LBracket == _scanner.Kind)
146 {
147 val = _builder.Predicate(val, ParsePredicate(), IsReverseAxis(axis));
148 }
149 }
150 return val;
151 }
152
153 private static bool IsReverseAxis(XPathAxis axis)
154 {
155 if (axis != XPathAxis.Ancestor && axis != XPathAxis.Preceding && axis != XPathAxis.AncestorOrSelf)
156 {
157 return axis == XPathAxis.PrecedingSibling;
158 }
159 return true;
160 }
161
163 {
167 Node result = _builder.Axis(axis, nodeType, nodePrefix, nodeName);
168 PopPosInfo();
169 return result;
170 }
171
172 private static bool IsNodeType(XPathScanner scanner)
173 {
174 if (scanner.Prefix.Length == 0)
175 {
176 if (!(scanner.Name == "node") && !(scanner.Name == "text") && !(scanner.Name == "processing-instruction"))
177 {
178 return scanner.Name == "comment";
179 }
180 return true;
181 }
182 return false;
183 }
184
186 {
187 return axis switch
188 {
191 _ => XPathNodeType.Element,
192 };
193 }
194
196 {
197 switch (scanner.Kind)
198 {
199 case LexKind.Name:
200 if (scanner.CanBeFunction && IsNodeType(scanner))
201 {
202 nodePrefix = null;
203 nodeName = null;
204 switch (scanner.Name)
205 {
206 case "comment":
207 nodeType = XPathNodeType.Comment;
208 break;
209 case "text":
210 nodeType = XPathNodeType.Text;
211 break;
212 case "node":
213 nodeType = XPathNodeType.All;
214 break;
215 default:
216 nodeType = XPathNodeType.ProcessingInstruction;
217 break;
218 }
219 scanner.NextLex();
220 scanner.PassToken(LexKind.LParens);
221 if (nodeType == XPathNodeType.ProcessingInstruction && scanner.Kind != LexKind.RParens)
222 {
223 scanner.CheckToken(LexKind.String);
224 nodePrefix = string.Empty;
225 nodeName = scanner.StringValue;
226 scanner.NextLex();
227 }
228 scanner.PassToken(LexKind.RParens);
229 }
230 else
231 {
232 nodePrefix = scanner.Prefix;
233 nodeName = scanner.Name;
234 nodeType = PrincipalNodeType(axis);
235 scanner.NextLex();
236 if (nodeName == "*")
237 {
238 nodeName = null;
239 }
240 }
241 break;
242 case LexKind.Star:
243 nodePrefix = null;
244 nodeName = null;
245 nodeType = PrincipalNodeType(axis);
246 scanner.NextLex();
247 break;
248 default:
249 throw scanner.CreateException(System.SR.XPath_NodeTestExpected, scanner.RawValue);
250 }
251 }
252
254 {
255 _scanner.PassToken(LexKind.LBracket);
256 Node result = ParseExpr();
257 _scanner.PassToken(LexKind.RBracket);
258 return result;
259 }
260
261 private Node ParseExpr()
262 {
263 return ParseSubExpr(0);
264 }
265
267 {
269 {
271 }
272 Node val;
273 if (_scanner.Kind == LexKind.Minus)
274 {
278 val = _builder.Operator(xPathOperator, ParseSubExpr(callerPrec2), default(Node));
279 }
280 else
281 {
282 val = ParseUnionExpr();
283 }
284 while (true)
285 {
288 if (num <= callerPrec)
289 {
290 break;
291 }
293 val = _builder.Operator(xPathOperator, val, ParseSubExpr(num));
294 }
296 return val;
297 }
298
300 {
302 Node val = ParsePathExpr();
303 if (_scanner.Kind == LexKind.Union)
304 {
306 val = _builder.Operator(XPathOperator.Union, default(Node), val);
307 PopPosInfo();
308 while (_scanner.Kind == LexKind.Union)
309 {
312 Node right = ParsePathExpr();
314 val = _builder.Operator(XPathOperator.Union, val, right);
315 PopPosInfo();
316 }
317 }
318 return val;
319 }
320
322 {
323 if (IsPrimaryExpr())
324 {
326 Node val = ParseFilterExpr();
328 if (_scanner.Kind == LexKind.Slash)
329 {
332 val = _builder.JoinStep(val, ParseRelativeLocationPath());
333 PopPosInfo();
334 }
335 else if (_scanner.Kind == LexKind.SlashSlash)
336 {
339 val = _builder.JoinStep(val, _builder.JoinStep(_builder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null), ParseRelativeLocationPath()));
340 PopPosInfo();
341 }
342 return val;
343 }
344 return ParseLocationPath();
345 }
346
348 {
350 Node val = ParsePrimaryExpr();
352 while (_scanner.Kind == LexKind.LBracket)
353 {
355 val = _builder.Predicate(val, ParsePredicate(), reverseStep: false);
356 PopPosInfo();
357 }
358 return val;
359 }
360
361 private bool IsPrimaryExpr()
362 {
363 if (_scanner.Kind != LexKind.String && _scanner.Kind != LexKind.Number && _scanner.Kind != LexKind.Dollar && _scanner.Kind != LexKind.LParens)
364 {
366 {
367 return !IsNodeType(_scanner);
368 }
369 return false;
370 }
371 return true;
372 }
373
375 {
376 Node result;
377 switch (_scanner.Kind)
378 {
379 case LexKind.String:
380 result = _builder.String(_scanner.StringValue);
382 break;
383 case LexKind.Number:
386 break;
387 case LexKind.Dollar:
388 {
393 result = _builder.Variable(_scanner.Prefix, _scanner.Name);
394 PopPosInfo();
396 break;
397 }
398 case LexKind.LParens:
400 result = ParseExpr();
401 _scanner.PassToken(LexKind.RParens);
402 break;
403 default:
404 result = ParseFunctionCall();
405 break;
406 }
407 return result;
408 }
409
411 {
412 List<Node> list = new List<Node>();
413 string name = _scanner.Name;
414 string prefix = _scanner.Prefix;
417 _scanner.PassToken(LexKind.LParens);
418 if (_scanner.Kind != LexKind.RParens)
419 {
420 while (true)
421 {
422 list.Add(ParseExpr());
423 if (_scanner.Kind != LexKind.Comma)
424 {
425 break;
426 }
428 }
429 _scanner.CheckToken(LexKind.RParens);
430 }
433 Node result = _builder.Function(prefix, name, list);
434 PopPosInfo();
435 return result;
436 }
437
438 private void PushPosInfo(int startChar, int endChar)
439 {
440 _posInfo.Push(startChar);
441 _posInfo.Push(endChar);
442 }
443
444 private void PopPosInfo()
445 {
446 _posInfo.Pop();
447 _posInfo.Pop();
448 }
449
450 private void PopPosInfo(out int startChar, out int endChar)
451 {
452 endChar = _posInfo.Pop();
453 startChar = _posInfo.Pop();
454 }
455}
void Add(TKey key, TValue value)
static string XPath_PredicateAfterDot
Definition SR.cs:1842
static string XPath_UnexpectedToken
Definition SR.cs:1832
static string Xslt_InputTooComplex
Definition SR.cs:1862
static string XPath_PredicateAfterDotDot
Definition SR.cs:1844
static string XPath_NodeTestExpected
Definition SR.cs:1834
Definition SR.cs:7
static unsafe double StringToDouble(string s)
static readonly int[] s_XPathOperatorPrecedence
static bool IsNodeType(XPathScanner scanner)
Node ParseNodeTest(XPathAxis axis)
IXPathBuilder< Node > _builder
static XPathNodeType PrincipalNodeType(XPathAxis axis)
readonly Stack< int > _posInfo
Node Parse(XPathScanner scanner, IXPathBuilder< Node > builder, LexKind endLex)
static bool IsStep(LexKind lexKind)
void PushPosInfo(int startChar, int endChar)
Node ParseSubExpr(int callerPrec)
void PopPosInfo(out int startChar, out int endChar)
static void InternalParseNodeTest(XPathScanner scanner, XPathAxis axis, out XPathNodeType nodeType, out string nodePrefix, out string nodeName)
static bool IsReverseAxis(XPathAxis axis)
XPathCompileException CreateException(string resId, params string[] args)