Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
XPathParser.cs
Go to the documentation of this file.
1using System;
4
6
7internal struct XPathParser
8{
9 private sealed class ParamInfo
10 {
11 private readonly Function.FunctionType _ftype;
12
13 private readonly int _minargs;
14
15 private readonly int _maxargs;
16
17 private readonly XPathResultType[] _argTypes;
18
20
21 public int Minargs => _minargs;
22
23 public int Maxargs => _maxargs;
24
26
28 {
29 _ftype = ftype;
32 _argTypes = argTypes;
33 }
34 }
35
37
38 private int _parseDepth;
39
40 private static readonly XPathResultType[] s_temparray1 = Array.Empty<XPathResultType>();
41
42 private static readonly XPathResultType[] s_temparray2 = new XPathResultType[1] { XPathResultType.NodeSet };
43
44 private static readonly XPathResultType[] s_temparray3 = new XPathResultType[1] { XPathResultType.Any };
45
46 private static readonly XPathResultType[] s_temparray4 = new XPathResultType[1] { XPathResultType.String };
47
48 private static readonly XPathResultType[] s_temparray5 = new XPathResultType[2]
49 {
50 XPathResultType.String,
51 XPathResultType.String
52 };
53
54 private static readonly XPathResultType[] s_temparray6 = new XPathResultType[3]
55 {
56 XPathResultType.String,
57 XPathResultType.Number,
58 XPathResultType.Number
59 };
60
61 private static readonly XPathResultType[] s_temparray7 = new XPathResultType[3]
62 {
63 XPathResultType.String,
64 XPathResultType.String,
65 XPathResultType.String
66 };
67
68 private static readonly XPathResultType[] s_temparray8 = new XPathResultType[1] { XPathResultType.Boolean };
69
70 private static readonly XPathResultType[] s_temparray9 = new XPathResultType[1];
71
73
75
76 private bool IsNodeType
77 {
78 get
79 {
80 if (_scanner.Prefix.Length == 0)
81 {
82 if (!(_scanner.Name == "node") && !(_scanner.Name == "text") && !(_scanner.Name == "processing-instruction"))
83 {
84 return _scanner.Name == "comment";
85 }
86 return true;
87 }
88 return false;
89 }
90 }
91
92 private bool IsPrimaryExpr
93 {
94 get
95 {
97 {
99 {
100 return !IsNodeType;
101 }
102 return false;
103 }
104 return true;
105 }
106 }
107
108 private XPathParser(string xpathExpr)
109 {
111 _parseDepth = 0;
112 }
113
115 {
117 AstNode result = xPathParser.ParseExpression(null);
118 if (xPathParser._scanner.Kind != XPathScanner.LexKind.Eof)
119 {
120 throw XPathException.Create(System.SR.Xp_InvalidToken, xPathParser._scanner.SourceText);
121 }
122 return result;
123 }
124
126 {
128 AstNode result = xPathParser.ParsePattern();
129 if (xPathParser._scanner.Kind != XPathScanner.LexKind.Eof)
130 {
131 throw XPathException.Create(System.SR.Xp_InvalidToken, xPathParser._scanner.SourceText);
132 }
133 return result;
134 }
135
137 {
138 if (++_parseDepth > 200)
139 {
141 }
142 AstNode result = ParseOrExpr(qyInput);
143 _parseDepth--;
144 return result;
145 }
146
147 private AstNode ParseOrExpr(AstNode qyInput)
148 {
149 AstNode astNode = ParseAndExpr(qyInput);
150 while (TestOp("or"))
151 {
152 NextLex();
153 astNode = new Operator(Operator.Op.OR, astNode, ParseAndExpr(qyInput));
154 }
155 return astNode;
156 }
157
158 private AstNode ParseAndExpr(AstNode qyInput)
159 {
161 while (TestOp("and"))
162 {
163 NextLex();
164 astNode = new Operator(Operator.Op.AND, astNode, ParseEqualityExpr(qyInput));
165 }
166 return astNode;
167 }
168
170 {
172 while (true)
173 {
174 Operator.Op op = ((_scanner.Kind == XPathScanner.LexKind.Eq) ? Operator.Op.EQ : ((_scanner.Kind == XPathScanner.LexKind.Ne) ? Operator.Op.NE : Operator.Op.INVALID));
175 if (op == Operator.Op.INVALID)
176 {
177 break;
178 }
179 NextLex();
181 }
182 return astNode;
183 }
184
186 {
188 while (true)
189 {
190 Operator.Op op = ((_scanner.Kind == XPathScanner.LexKind.Lt) ? Operator.Op.LT : ((_scanner.Kind == XPathScanner.LexKind.Le) ? Operator.Op.LE : ((_scanner.Kind == XPathScanner.LexKind.Gt) ? Operator.Op.GT : ((_scanner.Kind == XPathScanner.LexKind.Ge) ? Operator.Op.GE : Operator.Op.INVALID))));
191 if (op == Operator.Op.INVALID)
192 {
193 break;
194 }
195 NextLex();
196 astNode = new Operator(op, astNode, ParseAdditiveExpr(qyInput));
197 }
198 return astNode;
199 }
200
202 {
204 while (true)
205 {
206 Operator.Op op = ((_scanner.Kind == XPathScanner.LexKind.Plus) ? Operator.Op.PLUS : ((_scanner.Kind == XPathScanner.LexKind.Minus) ? Operator.Op.MINUS : Operator.Op.INVALID));
207 if (op == Operator.Op.INVALID)
208 {
209 break;
210 }
211 NextLex();
213 }
214 return astNode;
215 }
216
218 {
219 AstNode astNode = ParseUnaryExpr(qyInput);
220 while (true)
221 {
222 Operator.Op op = ((_scanner.Kind == XPathScanner.LexKind.Star) ? Operator.Op.MUL : (TestOp("div") ? Operator.Op.DIV : (TestOp("mod") ? Operator.Op.MOD : Operator.Op.INVALID)));
223 if (op == Operator.Op.INVALID)
224 {
225 break;
226 }
227 NextLex();
228 astNode = new Operator(op, astNode, ParseUnaryExpr(qyInput));
229 }
230 return astNode;
231 }
232
234 {
235 bool flag = false;
236 while (_scanner.Kind == XPathScanner.LexKind.Minus)
237 {
238 NextLex();
239 flag = !flag;
240 }
241 if (flag)
242 {
243 return new Operator(Operator.Op.MUL, ParseUnionExpr(qyInput), new Operand(-1.0));
244 }
245 return ParseUnionExpr(qyInput);
246 }
247
249 {
250 AstNode astNode = ParsePathExpr(qyInput);
251 while (_scanner.Kind == XPathScanner.LexKind.Union)
252 {
253 NextLex();
254 AstNode astNode2 = ParsePathExpr(qyInput);
255 CheckNodeSet(astNode.ReturnType);
256 CheckNodeSet(astNode2.ReturnType);
258 }
259 return astNode;
260 }
261
263 {
265 if (IsPrimaryExpr)
266 {
267 astNode = ParseFilterExpr(qyInput);
268 if (_scanner.Kind == XPathScanner.LexKind.Slash)
269 {
270 NextLex();
272 }
273 else if (_scanner.Kind == XPathScanner.LexKind.SlashSlash)
274 {
275 NextLex();
276 astNode = ParseRelativeLocationPath(new Axis(Axis.AxisType.DescendantOrSelf, astNode));
277 }
278 }
279 else
280 {
282 }
283 return astNode;
284 }
285
287 {
289 while (_scanner.Kind == XPathScanner.LexKind.LBracket)
290 {
292 }
293 return astNode;
294 }
295
297 {
298 CheckNodeSet(qyInput.ReturnType);
300 AstNode result = ParseExpression(qyInput);
302 return result;
303 }
304
306 {
307 if (_scanner.Kind == XPathScanner.LexKind.Slash)
308 {
309 NextLex();
310 AstNode astNode = new Root();
311 if (IsStep(_scanner.Kind))
312 {
314 }
315 return astNode;
316 }
317 if (_scanner.Kind == XPathScanner.LexKind.SlashSlash)
318 {
319 NextLex();
320 return ParseRelativeLocationPath(new Axis(Axis.AxisType.DescendantOrSelf, new Root()));
321 }
322 return ParseRelativeLocationPath(qyInput);
323 }
324
326 {
327 AstNode astNode = qyInput;
328 while (true)
329 {
331 if (XPathScanner.LexKind.SlashSlash == _scanner.Kind)
332 {
333 NextLex();
334 astNode = new Axis(Axis.AxisType.DescendantOrSelf, astNode);
335 continue;
336 }
337 if (XPathScanner.LexKind.Slash != _scanner.Kind)
338 {
339 break;
340 }
341 NextLex();
342 }
343 return astNode;
344 }
345
346 private static bool IsStep(XPathScanner.LexKind lexKind)
347 {
349 {
350 return lexKind == XPathScanner.LexKind.Name;
351 }
352 return true;
353 }
354
355 private AstNode ParseStep(AstNode qyInput)
356 {
359 {
360 NextLex();
361 astNode = new Axis(Axis.AxisType.Self, qyInput);
362 }
363 else if (XPathScanner.LexKind.DotDot == _scanner.Kind)
364 {
365 NextLex();
366 astNode = new Axis(Axis.AxisType.Parent, qyInput);
367 }
368 else
369 {
371 switch (_scanner.Kind)
372 {
373 case XPathScanner.LexKind.At:
374 axisType = Axis.AxisType.Attribute;
375 NextLex();
376 break;
377 case XPathScanner.LexKind.Axe:
378 axisType = GetAxis();
379 NextLex();
380 break;
381 }
382 XPathNodeType nodeType = ((axisType != Axis.AxisType.Attribute) ? XPathNodeType.Element : XPathNodeType.Attribute);
383 astNode = ParseNodeTest(qyInput, axisType, nodeType);
384 while (XPathScanner.LexKind.LBracket == _scanner.Kind)
385 {
387 }
388 }
389 return astNode;
390 }
391
393 {
394 string prefix;
395 string text;
396 switch (_scanner.Kind)
397 {
398 case XPathScanner.LexKind.Name:
400 {
401 prefix = string.Empty;
402 text = string.Empty;
403 nodeType = ((_scanner.Name == "comment") ? XPathNodeType.Comment : ((_scanner.Name == "text") ? XPathNodeType.Text : ((_scanner.Name == "node") ? XPathNodeType.All : ((_scanner.Name == "processing-instruction") ? XPathNodeType.ProcessingInstruction : XPathNodeType.Root))));
404 NextLex();
406 if (nodeType == XPathNodeType.ProcessingInstruction && _scanner.Kind != XPathScanner.LexKind.RParens)
407 {
410 NextLex();
411 }
413 }
414 else
415 {
418 NextLex();
419 if (text == "*")
420 {
421 text = string.Empty;
422 }
423 }
424 break;
425 case XPathScanner.LexKind.Star:
426 prefix = string.Empty;
427 text = string.Empty;
428 NextLex();
429 break;
430 default:
432 }
433 return new Axis(axisType, qyInput, prefix, text, nodeType);
434 }
435
437 {
438 AstNode astNode = null;
439 switch (_scanner.Kind)
440 {
441 case XPathScanner.LexKind.String:
443 NextLex();
444 break;
445 case XPathScanner.LexKind.Number:
447 NextLex();
448 break;
449 case XPathScanner.LexKind.Dollar:
450 NextLex();
453 NextLex();
454 break;
455 case XPathScanner.LexKind.LParens:
456 NextLex();
457 astNode = ParseExpression(qyInput);
458 if (astNode.Type != AstNode.AstType.ConstantOperand)
459 {
460 astNode = new Group(astNode);
461 }
463 break;
464 case XPathScanner.LexKind.Name:
466 {
467 astNode = ParseMethod(null);
468 }
469 break;
470 }
471 return astNode;
472 }
473
474 private AstNode ParseMethod(AstNode qyInput)
475 {
477 string name = _scanner.Name;
478 string prefix = _scanner.Prefix;
481 if (_scanner.Kind != XPathScanner.LexKind.RParens)
482 {
483 while (true)
484 {
485 list.Add(ParseExpression(qyInput));
486 if (_scanner.Kind == XPathScanner.LexKind.RParens)
487 {
488 break;
489 }
491 }
492 }
494 if (prefix.Length == 0 && s_functionTable.TryGetValue(name, out var value))
495 {
496 int num = list.Count;
497 if (num < value.Minargs)
498 {
500 }
501 if (value.FType == Function.FunctionType.FuncConcat)
502 {
503 for (int i = 0; i < num; i++)
504 {
505 AstNode astNode = list[i];
506 if (astNode.ReturnType != XPathResultType.String)
507 {
508 astNode = new Function(Function.FunctionType.FuncString, astNode);
509 }
510 list[i] = astNode;
511 }
512 }
513 else
514 {
515 if (value.Maxargs < num)
516 {
518 }
519 if (value.ArgTypes.Length < num)
520 {
521 num = value.ArgTypes.Length;
522 }
523 for (int j = 0; j < num; j++)
524 {
526 if (value.ArgTypes[j] == XPathResultType.Any || value.ArgTypes[j] == astNode2.ReturnType)
527 {
528 continue;
529 }
530 switch (value.ArgTypes[j])
531 {
532 case XPathResultType.NodeSet:
533 if (!(astNode2 is Variable) && (!(astNode2 is Function) || astNode2.ReturnType != XPathResultType.Any))
534 {
536 }
537 break;
538 case XPathResultType.String:
540 break;
541 case XPathResultType.Number:
543 break;
544 case XPathResultType.Boolean:
545 astNode2 = new Function(Function.FunctionType.FuncBoolean, astNode2);
546 break;
547 }
548 list[j] = astNode2;
549 }
550 }
551 return new Function(value.FType, list);
552 }
553 return new Function(prefix, name, list);
554 }
555
557 {
559 while (_scanner.Kind == XPathScanner.LexKind.Union)
560 {
561 NextLex();
563 }
564 return astNode;
565 }
566
568 {
569 AstNode astNode = null;
570 switch (_scanner.Kind)
571 {
572 case XPathScanner.LexKind.Slash:
573 NextLex();
574 astNode = new Root();
576 {
577 return astNode;
578 }
579 break;
580 case XPathScanner.LexKind.SlashSlash:
581 NextLex();
582 astNode = new Axis(Axis.AxisType.DescendantOrSelf, new Root());
583 break;
584 case XPathScanner.LexKind.Name:
586 {
587 break;
588 }
590 if (astNode != null)
591 {
592 switch (_scanner.Kind)
593 {
594 case XPathScanner.LexKind.Slash:
595 NextLex();
596 break;
597 case XPathScanner.LexKind.SlashSlash:
598 NextLex();
599 astNode = new Axis(Axis.AxisType.DescendantOrSelf, astNode);
600 break;
601 default:
602 return astNode;
603 }
604 }
605 break;
606 }
608 }
609
611 {
613 if (_scanner.Prefix.Length == 0)
614 {
615 if (_scanner.Name == "id")
616 {
618 NextLex();
622 NextLex();
624 return new Function(paramInfo.FType, list);
625 }
626 if (_scanner.Name == "key")
627 {
628 NextLex();
632 NextLex();
636 NextLex();
638 return new Function("", "key", list);
639 }
640 }
641 return null;
642 }
643
645 {
647 if (XPathScanner.LexKind.SlashSlash == _scanner.Kind)
648 {
649 NextLex();
650 astNode = ParseRelativePathPattern(new Axis(Axis.AxisType.DescendantOrSelf, astNode));
651 }
652 else if (XPathScanner.LexKind.Slash == _scanner.Kind)
653 {
654 NextLex();
656 }
657 return astNode;
658 }
659
661 {
663 switch (_scanner.Kind)
664 {
665 case XPathScanner.LexKind.At:
666 axisType = Axis.AxisType.Attribute;
667 NextLex();
668 break;
669 case XPathScanner.LexKind.Axe:
670 axisType = GetAxis();
671 if (axisType != Axis.AxisType.Child && axisType != Axis.AxisType.Attribute)
672 {
674 }
675 NextLex();
676 break;
677 }
678 XPathNodeType nodeType = ((axisType != Axis.AxisType.Attribute) ? XPathNodeType.Element : XPathNodeType.Attribute);
679 AstNode astNode = ParseNodeTest(qyInput, axisType, nodeType);
680 while (XPathScanner.LexKind.LBracket == _scanner.Kind)
681 {
683 }
684 return astNode;
685 }
686
688 {
689 if (_scanner.Kind != t)
690 {
692 }
693 }
694
696 {
697 CheckToken(t);
698 NextLex();
699 }
700
701 private void NextLex()
702 {
704 }
705
706 private bool TestOp(string op)
707 {
708 if (_scanner.Kind == XPathScanner.LexKind.Name && _scanner.Prefix.Length == 0)
709 {
710 return _scanner.Name.Equals(op);
711 }
712 return false;
713 }
714
716 {
717 if (t != XPathResultType.NodeSet && t != XPathResultType.Any)
718 {
720 }
721 }
722
724 {
726 dictionary.Add("last", new ParamInfo(Function.FunctionType.FuncLast, 0, 0, s_temparray1));
727 dictionary.Add("position", new ParamInfo(Function.FunctionType.FuncPosition, 0, 0, s_temparray1));
728 dictionary.Add("name", new ParamInfo(Function.FunctionType.FuncName, 0, 1, s_temparray2));
729 dictionary.Add("namespace-uri", new ParamInfo(Function.FunctionType.FuncNameSpaceUri, 0, 1, s_temparray2));
730 dictionary.Add("local-name", new ParamInfo(Function.FunctionType.FuncLocalName, 0, 1, s_temparray2));
731 dictionary.Add("count", new ParamInfo(Function.FunctionType.FuncCount, 1, 1, s_temparray2));
732 dictionary.Add("id", new ParamInfo(Function.FunctionType.FuncID, 1, 1, s_temparray3));
733 dictionary.Add("string", new ParamInfo(Function.FunctionType.FuncString, 0, 1, s_temparray3));
734 dictionary.Add("concat", new ParamInfo(Function.FunctionType.FuncConcat, 2, 100, s_temparray4));
735 dictionary.Add("starts-with", new ParamInfo(Function.FunctionType.FuncStartsWith, 2, 2, s_temparray5));
736 dictionary.Add("contains", new ParamInfo(Function.FunctionType.FuncContains, 2, 2, s_temparray5));
737 dictionary.Add("substring-before", new ParamInfo(Function.FunctionType.FuncSubstringBefore, 2, 2, s_temparray5));
738 dictionary.Add("substring-after", new ParamInfo(Function.FunctionType.FuncSubstringAfter, 2, 2, s_temparray5));
739 dictionary.Add("substring", new ParamInfo(Function.FunctionType.FuncSubstring, 2, 3, s_temparray6));
740 dictionary.Add("string-length", new ParamInfo(Function.FunctionType.FuncStringLength, 0, 1, s_temparray4));
741 dictionary.Add("normalize-space", new ParamInfo(Function.FunctionType.FuncNormalize, 0, 1, s_temparray4));
742 dictionary.Add("translate", new ParamInfo(Function.FunctionType.FuncTranslate, 3, 3, s_temparray7));
743 dictionary.Add("boolean", new ParamInfo(Function.FunctionType.FuncBoolean, 1, 1, s_temparray3));
744 dictionary.Add("not", new ParamInfo(Function.FunctionType.FuncNot, 1, 1, s_temparray8));
745 dictionary.Add("true", new ParamInfo(Function.FunctionType.FuncTrue, 0, 0, s_temparray8));
746 dictionary.Add("false", new ParamInfo(Function.FunctionType.FuncFalse, 0, 0, s_temparray8));
747 dictionary.Add("lang", new ParamInfo(Function.FunctionType.FuncLang, 1, 1, s_temparray4));
748 dictionary.Add("number", new ParamInfo(Function.FunctionType.FuncNumber, 0, 1, s_temparray3));
749 dictionary.Add("sum", new ParamInfo(Function.FunctionType.FuncSum, 1, 1, s_temparray2));
750 dictionary.Add("floor", new ParamInfo(Function.FunctionType.FuncFloor, 1, 1, s_temparray9));
751 dictionary.Add("ceiling", new ParamInfo(Function.FunctionType.FuncCeiling, 1, 1, s_temparray9));
752 dictionary.Add("round", new ParamInfo(Function.FunctionType.FuncRound, 1, 1, s_temparray9));
753 return dictionary;
754 }
755
757 {
759 dictionary.Add("ancestor", Axis.AxisType.Ancestor);
760 dictionary.Add("ancestor-or-self", Axis.AxisType.AncestorOrSelf);
761 dictionary.Add("attribute", Axis.AxisType.Attribute);
762 dictionary.Add("child", Axis.AxisType.Child);
763 dictionary.Add("descendant", Axis.AxisType.Descendant);
764 dictionary.Add("descendant-or-self", Axis.AxisType.DescendantOrSelf);
765 dictionary.Add("following", Axis.AxisType.Following);
766 dictionary.Add("following-sibling", Axis.AxisType.FollowingSibling);
767 dictionary.Add("namespace", Axis.AxisType.Namespace);
768 dictionary.Add("parent", Axis.AxisType.Parent);
769 dictionary.Add("preceding", Axis.AxisType.Preceding);
770 dictionary.Add("preceding-sibling", Axis.AxisType.PrecedingSibling);
771 dictionary.Add("self", Axis.AxisType.Self);
772 return dictionary;
773 }
774
776 {
777 if (!s_AxesTable.TryGetValue(_scanner.Name, out var value))
778 {
780 }
781 return value;
782 }
783}
XPathResultType ReturnType
Definition AstNode.cs:22
readonly Function.FunctionType _ftype
ParamInfo(Function.FunctionType ftype, int minargs, int maxargs, XPathResultType[] argTypes)
readonly XPathResultType[] _argTypes
static string Xp_InvalidNumArgs
Definition SR.cs:1238
static string Xp_QueryTooComplex
Definition SR.cs:1266
static string Xp_NodeSetExpected
Definition SR.cs:1244
static string Xp_InvalidArgumentType
Definition SR.cs:1236
static string Xp_InvalidToken
Definition SR.cs:1242
Definition SR.cs:7
static XPathException Create(string res)
AstNode ParseOrExpr(AstNode qyInput)
AstNode ParseFilterExpr(AstNode qyInput)
static readonly XPathResultType[] s_temparray1
static readonly XPathResultType[] s_temparray4
AstNode ParseUnaryExpr(AstNode qyInput)
static readonly Dictionary< string, ParamInfo > s_functionTable
static readonly Dictionary< string, Axis.AxisType > s_AxesTable
void CheckNodeSet(XPathResultType t)
static readonly XPathResultType[] s_temparray3
AstNode ParseEqualityExpr(AstNode qyInput)
AstNode ParseStepPattern(AstNode qyInput)
static readonly XPathResultType[] s_temparray6
AstNode ParseUnionExpr(AstNode qyInput)
AstNode ParseLocationPath(AstNode qyInput)
static readonly XPathResultType[] s_temparray2
void PassToken(XPathScanner.LexKind t)
static readonly XPathResultType[] s_temparray9
static Dictionary< string, ParamInfo > CreateFunctionTable()
AstNode ParseNodeTest(AstNode qyInput, Axis.AxisType axisType, XPathNodeType nodeType)
static Dictionary< string, Axis.AxisType > CreateAxesTable()
AstNode ParseAndExpr(AstNode qyInput)
AstNode ParseMethod(AstNode qyInput)
AstNode ParsePrimaryExpr(AstNode qyInput)
static readonly XPathResultType[] s_temparray8
AstNode ParsePredicate(AstNode qyInput)
AstNode ParseStep(AstNode qyInput)
AstNode ParseExpression(AstNode qyInput)
static AstNode ParseXPathExpression(string xpathExpression)
static bool IsStep(XPathScanner.LexKind lexKind)
AstNode ParseRelativeLocationPath(AstNode qyInput)
AstNode ParseRelativePathPattern(AstNode qyInput)
AstNode ParseRelationalExpr(AstNode qyInput)
AstNode ParseAdditiveExpr(AstNode qyInput)
AstNode ParseMultiplicativeExpr(AstNode qyInput)
AstNode ParsePathExpr(AstNode qyInput)
static readonly XPathResultType[] s_temparray5
static readonly XPathResultType[] s_temparray7
void CheckToken(XPathScanner.LexKind t)
static AstNode ParseXPathPattern(string xpathPattern)