Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
QueryBuilder.cs
Go to the documentation of this file.
1using System;
4
6
7internal sealed class QueryBuilder
8{
9 private enum Flags
10 {
11 None = 0,
12 SmartDesc = 1,
13 PosFilter = 2,
14 Filter = 4
15 }
16
17 private enum Props
18 {
19 None = 0,
20 PosFilter = 1,
21 HasPosition = 2,
22 HasLast = 4,
23 NonFlat = 8
24 }
25
26 private string _query;
27
28 private bool _allowVar;
29
30 private bool _allowKey;
31
32 private bool _allowCurrent;
33
34 private bool _needContext;
35
37
38 private int _parseDepth;
39
40 private void Reset()
41 {
42 _parseDepth = 0;
43 _needContext = false;
44 }
45
46 private Query ProcessAxis(Axis root, Flags flags, out Props props)
47 {
48 Query query = null;
49 if (root.Prefix.Length > 0)
50 {
51 _needContext = true;
52 }
53 _firstInput = null;
55 if (root.Input != null)
56 {
57 Flags flags2 = Flags.None;
58 if ((flags & Flags.PosFilter) == 0)
59 {
60 if (root.Input is Axis axis && root.TypeOfAxis == Axis.AxisType.Child && axis.TypeOfAxis == Axis.AxisType.DescendantOrSelf && axis.NodeType == XPathNodeType.All)
61 {
63 if (axis.Input != null)
64 {
65 qyParent = ProcessNode(axis.Input, Flags.SmartDesc, out props);
66 }
67 else
68 {
69 qyParent = new ContextQuery();
70 props = Props.None;
71 }
72 query = new DescendantQuery(qyParent, root.Name, root.Prefix, root.NodeType, matchSelf: false, axis.AbbrAxis);
73 if ((props & Props.NonFlat) != 0)
74 {
76 }
77 props |= Props.NonFlat;
78 return query;
79 }
80 if (root.TypeOfAxis == Axis.AxisType.Descendant || root.TypeOfAxis == Axis.AxisType.DescendantOrSelf)
81 {
82 flags2 |= Flags.SmartDesc;
83 }
84 }
86 }
87 else
88 {
89 query2 = new ContextQuery();
90 props = Props.None;
91 }
92 switch (root.TypeOfAxis)
93 {
94 case Axis.AxisType.Ancestor:
95 query = new XPathAncestorQuery(query2, root.Name, root.Prefix, root.NodeType, matchSelf: false);
96 props |= Props.NonFlat;
97 break;
98 case Axis.AxisType.AncestorOrSelf:
99 query = new XPathAncestorQuery(query2, root.Name, root.Prefix, root.NodeType, matchSelf: true);
100 props |= Props.NonFlat;
101 break;
102 case Axis.AxisType.Child:
103 query = (((props & Props.NonFlat) == 0) ? new ChildrenQuery(query2, root.Name, root.Prefix, root.NodeType) : new CacheChildrenQuery(query2, root.Name, root.Prefix, root.NodeType));
104 break;
105 case Axis.AxisType.Parent:
106 query = new ParentQuery(query2, root.Name, root.Prefix, root.NodeType);
107 break;
108 case Axis.AxisType.Descendant:
109 if ((flags & Flags.SmartDesc) != 0)
110 {
111 query = new DescendantOverDescendantQuery(query2, matchSelf: false, root.Name, root.Prefix, root.NodeType, abbrAxis: false);
112 }
113 else
114 {
115 query = new DescendantQuery(query2, root.Name, root.Prefix, root.NodeType, matchSelf: false, abbrAxis: false);
116 if ((props & Props.NonFlat) != 0)
117 {
119 }
120 }
121 props |= Props.NonFlat;
122 break;
123 case Axis.AxisType.DescendantOrSelf:
124 if ((flags & Flags.SmartDesc) != 0)
125 {
126 query = new DescendantOverDescendantQuery(query2, matchSelf: true, root.Name, root.Prefix, root.NodeType, root.AbbrAxis);
127 }
128 else
129 {
130 query = new DescendantQuery(query2, root.Name, root.Prefix, root.NodeType, matchSelf: true, root.AbbrAxis);
131 if ((props & Props.NonFlat) != 0)
132 {
134 }
135 }
136 props |= Props.NonFlat;
137 break;
138 case Axis.AxisType.Preceding:
139 query = new PrecedingQuery(query2, root.Name, root.Prefix, root.NodeType);
140 props |= Props.NonFlat;
141 break;
142 case Axis.AxisType.Following:
143 query = new FollowingQuery(query2, root.Name, root.Prefix, root.NodeType);
144 props |= Props.NonFlat;
145 break;
146 case Axis.AxisType.FollowingSibling:
147 query = new FollSiblingQuery(query2, root.Name, root.Prefix, root.NodeType);
148 if ((props & Props.NonFlat) != 0)
149 {
151 }
152 break;
153 case Axis.AxisType.PrecedingSibling:
154 query = new PreSiblingQuery(query2, root.Name, root.Prefix, root.NodeType);
155 break;
156 case Axis.AxisType.Attribute:
157 query = new AttributeQuery(query2, root.Name, root.Prefix, root.NodeType);
158 break;
159 case Axis.AxisType.Self:
160 query = new XPathSelfQuery(query2, root.Name, root.Prefix, root.NodeType);
161 break;
162 case Axis.AxisType.Namespace:
163 query = (((root.NodeType != XPathNodeType.All && root.NodeType != XPathNodeType.Element && root.NodeType != XPathNodeType.Attribute) || root.Prefix.Length != 0) ? ((Query)new EmptyQuery()) : ((Query)new NamespaceQuery(query2, root.Name, root.Prefix, root.NodeType)));
164 break;
165 default:
167 }
168 return query;
169 }
170
171 private static bool CanBeNumber(Query q)
172 {
173 if (q.StaticType != XPathResultType.Any)
174 {
175 return q.StaticType == XPathResultType.Number;
176 }
177 return true;
178 }
179
181 {
182 bool flag = (flags & Flags.Filter) == 0;
185 if (CanBeNumber(query) || (props2 & (Props)6) != 0)
186 {
187 props2 |= Props.HasPosition;
188 flags |= Flags.PosFilter;
189 }
190 flags &= (Flags)(-2);
191 Query query2 = ProcessNode(root.Input, flags | Flags.Filter, out props);
192 if (root.Input.Type != AstNode.AstType.Filter)
193 {
194 props &= (Props)(-2);
195 }
196 if ((props2 & Props.HasPosition) != 0)
197 {
198 props |= Props.PosFilter;
199 }
200 if (query2 is FilterQuery filterQuery && (props2 & Props.HasPosition) == 0 && filterQuery.Condition.StaticType != XPathResultType.Any)
201 {
202 Query query3 = filterQuery.Condition;
203 if (query3.StaticType == XPathResultType.Number)
204 {
205 query3 = new LogicalExpr(Operator.Op.EQ, new NodeFunctions(Function.FunctionType.FuncPosition, null), query3);
206 }
208 query2 = filterQuery.qyInput;
209 }
210 if ((props & Props.PosFilter) != 0 && query2 is DocumentOrderQuery)
211 {
213 }
214 if (_firstInput == null)
215 {
217 }
218 bool flag2 = (query2.Properties & QueryProps.Merge) != 0;
219 bool flag3 = (query2.Properties & QueryProps.Reverse) != 0;
220 if ((props2 & Props.HasPosition) != 0)
221 {
222 if (flag3)
223 {
225 }
226 else if ((props2 & Props.HasLast) != 0)
227 {
229 }
230 }
231 if (flag && _firstInput != null)
232 {
233 if (flag2 && (props & Props.PosFilter) != 0)
234 {
235 query2 = new FilterQuery(query2, query, noPosition: false);
236 Query qyInput = _firstInput.qyInput;
237 if (!(qyInput is ContextQuery))
238 {
239 _firstInput.qyInput = new ContextQuery();
240 _firstInput = null;
241 return new MergeFilterQuery(qyInput, query2);
242 }
243 _firstInput = null;
244 return query2;
245 }
246 _firstInput = null;
247 }
248 return new FilterQuery(query2, query, (props2 & Props.HasPosition) == 0);
249 }
250
252 {
257 props = props2 | props3;
258 switch (root.OperatorType)
259 {
260 case Operator.Op.PLUS:
261 case Operator.Op.MINUS:
262 case Operator.Op.MUL:
263 case Operator.Op.DIV:
264 case Operator.Op.MOD:
265 return new NumericExpr(root.OperatorType, query, query2);
266 case Operator.Op.EQ:
267 case Operator.Op.NE:
268 case Operator.Op.LT:
269 case Operator.Op.LE:
270 case Operator.Op.GT:
271 case Operator.Op.GE:
272 return new LogicalExpr(root.OperatorType, query, query2);
273 case Operator.Op.OR:
274 case Operator.Op.AND:
275 return new BooleanExpr(root.OperatorType, query, query2);
276 case Operator.Op.UNION:
277 props |= Props.NonFlat;
278 return new UnionExpr(query, query2);
279 default:
280 return null;
281 }
282 }
283
285 {
286 _needContext = true;
287 if (!_allowVar)
288 {
290 }
291 return new VariableQuery(root.Localname, root.Prefix);
292 }
293
295 {
296 props = Props.None;
297 Query query = null;
298 switch (root.TypeOfFunction)
299 {
300 case Function.FunctionType.FuncLast:
301 query = new NodeFunctions(root.TypeOfFunction, null);
302 props |= Props.HasLast;
303 return query;
304 case Function.FunctionType.FuncPosition:
305 query = new NodeFunctions(root.TypeOfFunction, null);
306 props |= Props.HasPosition;
307 return query;
308 case Function.FunctionType.FuncCount:
309 return new NodeFunctions(Function.FunctionType.FuncCount, ProcessNode(root.ArgumentList[0], Flags.None, out props));
310 case Function.FunctionType.FuncID:
311 query = new IDQuery(ProcessNode(root.ArgumentList[0], Flags.None, out props));
312 props |= Props.NonFlat;
313 return query;
314 case Function.FunctionType.FuncLocalName:
315 case Function.FunctionType.FuncNameSpaceUri:
316 case Function.FunctionType.FuncName:
317 if (root.ArgumentList != null && root.ArgumentList.Count > 0)
318 {
319 return new NodeFunctions(root.TypeOfFunction, ProcessNode(root.ArgumentList[0], Flags.None, out props));
320 }
321 return new NodeFunctions(root.TypeOfFunction, null);
322 case Function.FunctionType.FuncString:
323 case Function.FunctionType.FuncConcat:
324 case Function.FunctionType.FuncStartsWith:
325 case Function.FunctionType.FuncContains:
326 case Function.FunctionType.FuncSubstringBefore:
327 case Function.FunctionType.FuncSubstringAfter:
328 case Function.FunctionType.FuncSubstring:
329 case Function.FunctionType.FuncStringLength:
330 case Function.FunctionType.FuncNormalize:
331 case Function.FunctionType.FuncTranslate:
333 case Function.FunctionType.FuncNumber:
334 case Function.FunctionType.FuncSum:
335 case Function.FunctionType.FuncFloor:
336 case Function.FunctionType.FuncCeiling:
337 case Function.FunctionType.FuncRound:
338 if (root.ArgumentList != null && root.ArgumentList.Count > 0)
339 {
340 return new NumberFunctions(root.TypeOfFunction, ProcessNode(root.ArgumentList[0], Flags.None, out props));
341 }
342 return new NumberFunctions(Function.FunctionType.FuncNumber, null);
343 case Function.FunctionType.FuncTrue:
344 case Function.FunctionType.FuncFalse:
345 return new BooleanFunctions(root.TypeOfFunction, null);
346 case Function.FunctionType.FuncBoolean:
347 case Function.FunctionType.FuncNot:
348 case Function.FunctionType.FuncLang:
349 return new BooleanFunctions(root.TypeOfFunction, ProcessNode(root.ArgumentList[0], Flags.None, out props));
350 case Function.FunctionType.FuncUserDefined:
351 _needContext = true;
352 if (!_allowCurrent && root.Name == "current" && root.Prefix.Length == 0)
353 {
355 }
356 if (!_allowKey && root.Name == "key" && root.Prefix.Length == 0)
357 {
359 }
361 props |= Props.NonFlat;
362 return query;
363 default:
365 }
366 }
367
369 {
370 int count = args.Count;
372 props = Props.None;
373 for (int i = 0; i < count; i++)
374 {
376 props |= props2;
377 }
378 return list;
379 }
380
382 {
383 if (++_parseDepth > 1024)
384 {
386 }
387 Query result = null;
388 props = Props.None;
389 switch (root.Type)
390 {
391 case AstNode.AstType.Axis:
392 result = ProcessAxis((Axis)root, flags, out props);
393 break;
394 case AstNode.AstType.Operator:
395 result = ProcessOperator((Operator)root, out props);
396 break;
397 case AstNode.AstType.Filter:
398 result = ProcessFilter((Filter)root, flags, out props);
399 break;
400 case AstNode.AstType.ConstantOperand:
401 result = new OperandQuery(((Operand)root).OperandValue);
402 break;
403 case AstNode.AstType.Variable:
404 result = ProcessVariable((Variable)root);
405 break;
406 case AstNode.AstType.Function:
407 result = ProcessFunction((Function)root, out props);
408 break;
409 case AstNode.AstType.Group:
410 result = new GroupQuery(ProcessNode(((Group)root).GroupNode, Flags.None, out props));
411 break;
412 case AstNode.AstType.Root:
413 result = new AbsoluteQuery();
414 break;
415 }
416 _parseDepth--;
417 return result;
418 }
419
420 private Query Build(AstNode root, string query)
421 {
422 Reset();
423 _query = query;
424 Props props;
425 return ProcessNode(root, Flags.None, out props);
426 }
427
428 internal Query Build(string query, bool allowVar, bool allowKey)
429 {
432 _allowCurrent = true;
434 }
435
436 internal Query Build(string query, out bool needContext)
437 {
438 Query result = Build(query, allowVar: true, allowKey: true);
440 return result;
441 }
442
443 internal Query BuildPatternQuery(string query, bool allowVar, bool allowKey)
444 {
447 _allowCurrent = false;
449 }
450
452 {
453 Query result = BuildPatternQuery(query, allowVar: true, allowKey: true);
455 return result;
456 }
457}
XPathNodeType NodeType
Definition Axis.cs:59
List< AstNode > ArgumentList
Definition Function.cs:86
Query BuildPatternQuery(string query, out bool needContext)
List< Query > ProcessArguments(List< AstNode > args, out Props props)
Query ProcessVariable(Variable root)
Query ProcessAxis(Axis root, Flags flags, out Props props)
Query ProcessOperator(Operator root, out Props props)
Query Build(string query, bool allowVar, bool allowKey)
Query Build(AstNode root, string query)
Query ProcessFunction(Function root, out Props props)
Query ProcessNode(AstNode root, Flags flags, out Props props)
Query Build(string query, out bool needContext)
Query BuildPatternQuery(string query, bool allowVar, bool allowKey)
Query ProcessFilter(Filter root, Flags flags, out Props props)
XPathResultType StaticType
Definition Query.cs:34
void Add(TKey key, TValue value)
static string Xp_QueryTooComplex
Definition SR.cs:1266
static string Xp_CurrentNotAllowed
Definition SR.cs:1264
static string Xp_InvalidKeyPattern
Definition SR.cs:1250
static string Xp_NotSupported
Definition SR.cs:1246
Definition SR.cs:7
static XPathException Create(string res)
static AstNode ParseXPathExpression(string xpathExpression)
static AstNode ParseXPathPattern(string xpathPattern)