1
2
3
4
5
6 using System;
7 using System.Collections;
8 using System.Xml;
9
10 namespace System.XPath
11 {
12 public enum Operator
13 {
14 or_, and_, equal, notEqual, less, greater, lessOrEqual, greaterOrEqual, plus, minus, mul, div, mod, union, slash, slashSlash, parens
15 }
16
17 public string OperatorStr(Operator op)
18 {
19 switch (op)
20 {
21 case Operator.or_: return "or";
22 case Operator.and_: return "and";
23 case Operator.equal: return "equal";
24 case Operator.notEqual: return "not-equal";
25 case Operator.less: return "less";
26 case Operator.greater: return "greater";
27 case Operator.lessOrEqual: return "less-or-equal";
28 case Operator.greaterOrEqual: return "greater-or-equal";
29 case Operator.plus: return "plus";
30 case Operator.minus: return "minus";
31 case Operator.mul: return "mul";
32 case Operator.div: return "div";
33 case Operator.mod: return "mod";
34 case Operator.union: return "union";
35 case Operator.slash: return "slash";
36 case Operator.slashSlash: return "slash-slash";
37 case Operator.parens: return "parens";
38 }
39 return "<unknown operator>";
40 }
41
42 public enum ExprKind
43 {
44 unaryExpr, binaryExpr, root, filterExpr, locationStepExpr, variableReference, literal, numberExpr, functionCall
45 }
46
47 public string ExprKindStr(ExprKind kind)
48 {
49 switch (kind)
50 {
51 case ExprKind.unaryExpr: return "unary-expr";
52 case ExprKind.binaryExpr: return "binary-expr";
53 case ExprKind.root: return "root";
54 case ExprKind.filterExpr: return "filter";
55 case ExprKind.locationStepExpr: return "location-step";
56 case ExprKind.variableReference: return "variable-reference";
57 case ExprKind.literal: return "literal";
58 case ExprKind.numberExpr: return "number";
59 case ExprKind.functionCall: return "function-call";
60 }
61 return "<unknown expression>";
62 }
63
64 public abstract class Expr
65 {
66 public Expr(ExprKind kind_) : kind(kind_)
67 {
68 }
69 public virtual default ~Expr();
70 public inline ExprKind Kind() const
71 {
72 return kind;
73 }
74 public inline const string& GetString() const
75 {
76 return str;
77 }
78 public void SetString(const string& str_)
79 {
80 str = str_;
81 }
82 public abstract Result<UniquePtr<Object>> Evaluate(Context& context);
83 public virtual System.Xml.Element* ToXmlElement() const
84 {
85 System.Xml.Element* element = System.Xml.MakeElement("expr");
86 element->SetAttribute("kind", ExprKindStr(kind));
87 return element;
88 }
89 private ExprKind kind;
90 private string str;
91 }
92
93 public class UnaryExpr : Expr
94 {
95 public UnaryExpr(Operator op_, Expr* operand_) : base(ExprKind.unaryExpr), op(op_), operand(operand_)
96 {
97 }
98 public inline Operator Op() const
99 {
100 return op;
101 }
102 public inline Expr* Operand() const
103 {
104 return operand.Get();
105 }
106 [nodiscard]
107 public override Result<UniquePtr<Object>> Evaluate(Context& context)
108 {
109 switch (op)
110 {
111 case Operator.minus:
112 {
113 return EvaluateUnaryMinusExpr(operand.Get(), context);
114 }
115 case Operator.parens:
116 {
117 return EvaluateParenExpr(operand.Get(), context);
118 }
119 }
120 int errorId = AllocateError("unary minus or parenthesis operator expected");
121 return Result<UniquePtr<Object>>(ErrorId(errorId));
122 }
123 public override System.Xml.Element* ToXmlElement() const
124 {
125 System.Xml.Element* element = base->ToXmlElement();
126 element->SetAttribute("operator", OperatorStr(op));
127 System.Xml.Element* child = operand->ToXmlElement();
128 element->AppendChild(child);
129 return element;
130 }
131 private Operator op;
132 private UniquePtr<Expr> operand;
133 }
134
135 public class BinaryExpr : Expr
136 {
137 public BinaryExpr(Operator op_, Expr* left_, Expr* right_) : base(ExprKind.binaryExpr), op(op_), left(left_), right(right_)
138 {
139 }
140 public inline Operator Op() const
141 {
142 return op;
143 }
144 public inline Expr* Left() const
145 {
146 return left.Get();
147 }
148 public inline Expr* Right() const
149 {
150 return right.Get();
151 }
152 [nodiscard]
153 public override Result<UniquePtr<Object>> Evaluate(Context& context)
154 {
155 switch (op)
156 {
157 case Operator.or_:
158 {
159 return EvaluateOrExpr(left.Get(), right.Get(), context);
160 }
161 case Operator.and_:
162 {
163 return EvaluateAndExpr(left.Get(), right.Get(), context);
164 }
165 case Operator.equal:
166 case Operator.notEqual:
167 case Operator.less:
168 case Operator.greater:
169 case Operator.lessOrEqual:
170 case Operator.greaterOrEqual:
171 {
172 return Compare(left.Get(), right.Get(), op, context);
173 }
174 case Operator.plus:
175 case Operator.minus:
176 case Operator.mul:
177 case Operator.div:
178 case Operator.mod:
179 {
180 return EvaluateArithmeticOp(left.Get(), right.Get(), op, context);
181 }
182 case Operator.union:
183 {
184 return EvaluateUnionExpr(left.Get(), right.Get(), context);
185 }
186 case Operator.slash:
187 {
188 return EvaluateCombineStepExpr(left.Get(), right.Get(), context);
189 }
190 }
191 int errorId = AllocateError("binary operator expected");
192 return Result<UniquePtr<Object>>(ErrorId(errorId));
193 }
194 public override System.Xml.Element* ToXmlElement() const
195 {
196 System.Xml.Element* element = base->ToXmlElement();
197 element->SetAttribute("operator", OperatorStr(op));
198 System.Xml.Element* leftElement = left->ToXmlElement();
199 element->AppendChild(leftElement);
200 System.Xml.Element* rightElement = right->ToXmlElement();
201 element->AppendChild(rightElement);
202 return element;
203 }
204 private Operator op;
205 private UniquePtr<Expr> left;
206 private UniquePtr<Expr> right;
207 }
208
209 public class Root : Expr
210 {
211 public Root() : base(ExprKind.root)
212 {
213 }
214 [nodiscard]
215 public override Result<UniquePtr<Object>> Evaluate(Context& context) const
216 {
217 UniquePtr<NodeSet> nodeSet = new NodeSet();
218 if (context.Node()->IsDocumentNode())
219 {
220 nodeSet->Add(context.Node());
221 }
222 else if (context.Node()->OwnerDocument() != null)
223 {
224 nodeSet->Add(context.Node()->OwnerDocument());
225 }
226 return Result<UniquePtr<Object>>(UniquePtr<Object>(nodeSet.Release()));
227 }
228 }
229
230 public class FilterExpr : Expr
231 {
232 public FilterExpr(Expr* subject_, Expr* predicate_) : base(ExprKind.filterExpr), subject(subject_), predicate(predicate_)
233 {
234 }
235 public inline Expr* Subject() const
236 {
237 return subject.Get();
238 }
239 public inline Expr* Predicate() const
240 {
241 return predicate.Get();
242 }
243 [nodiscard]
244 public override Result<UniquePtr<Object>> Evaluate(Context& context) const
245 {
246 auto subjectResult = subject->Evaluate(context);
247 if (subjectResult.Error())
248 {
249 return subjectResult;
250 }
251 UniquePtr<Object> subjectObject = Rvalue(subjectResult.Value());
252 if (subjectObject->IsNodeSet())
253 {
254 UniquePtr<NodeSet> nodeSet = cast<NodeSet*>(subjectObject.Release());
255 UniquePtr<NodeSet> filteredNodeSet = new NodeSet();
256 int n = nodeSet->Count();
257 for (int i = 0; i < n; ++i;)
258 {
259 System.Xml.Node* node = nodeSet->GetNode(i);
260 Context filterContext(node, i + 1, n);
261 auto result = predicate->Evaluate(filterContext);
262 if (result.Error())
263 {
264 return result;
265 }
266 Object* resultObject = result.Value().Get();
267 bool include = false;
268 if (resultObject->IsNumber())
269 {
270 Number* number = cast<Number*>(resultObject);
271 if (number->Value() == filterContext.Pos())
272 {
273 include = true;
274 }
275 }
276 else
277 {
278 auto booleanResult = ToBoolean(resultObject, filterContext);
279 if (booleanResult.Error())
280 {
281 return booleanResult;
282 }
283 auto booleanCastResult = BooleanCast(booleanResult.Value().Get());
284 if (booleanCastResult.Error())
285 {
286 return Result<UniquePtr<Object>>(ErrorId(booleanCastResult.GetErrorId()));
287 }
288 Boolean* boolean = booleanCastResult.Value();
289 include = boolean->Value();
290 }
291 if (include)
292 {
293 filteredNodeSet->Add(node);
294 }
295 }
296 Swap(nodeSet, filteredNodeSet);
297 return Result<UniquePtr<Object>>(UniquePtr<Object>(nodeSet.Release()));
298 }
299 else
300 {
301 int errorId = AllocateError("node-set expected");
302 return Result<UniquePtr<Object>>(ErrorId(errorId));
303 }
304 }
305 public override System.Xml.Element* ToXmlElement() const
306 {
307 System.Xml.Element* element = base->ToXmlElement();
308 System.Xml.Element* subjectElement = subject->ToXmlElement();
309 element->AppendChild(subjectElement);
310 System.Xml.Element* predicateElement = predicate->ToXmlElement();
311 element->AppendChild(predicateElement);
312 return element;
313 }
314 private UniquePtr<Expr> subject;
315 private UniquePtr<Expr> predicate;
316 }
317
318 public class LocationStepExpr : Expr
319 {
320 public LocationStepExpr(System.Xml.Axis axis_, NodeTest* nodeTest_) : base(ExprKind.locationStepExpr), axis(axis_), nodeTest(nodeTest_)
321 {
322 }
323 public inline NodeTest* GetNodeTest() const
324 {
325 return nodeTest.Get();
326 }
327 public void AddPredicate(Expr* predicate)
328 {
329 predicates.Add(UniquePtr<Expr>(predicate));
330 }
331 public inline const List<UniquePtr<Expr>>& Predicates() const
332 {
333 return predicates;
334 }
335 [nodiscard]
336 public override Result<UniquePtr<Object>> Evaluate(Context& context) const
337 {
338 UniquePtr<NodeSet> nodeSet(new NodeSet());
339 NodeSelectionOperation selectNodes(nodeTest.Get(), *nodeSet, axis);
340 context.Node()->Walk(selectNodes, axis);
341 for (const auto& predicate : predicates)
342 {
343 UniquePtr<NodeSet> filteredNodeSet(new NodeSet());
344 int n = nodeSet->Count();
345 for (int i = 0; i < n; ++i;)
346 {
347 System.Xml.Node* node = nodeSet->GetNode(i);
348 Context filterContext(node, i + 1, n);
349 auto predicateEvaluationResult = predicate->Evaluate(filterContext);
350 if (predicateEvaluationResult.Error())
351 {
352 return Result<UniquePtr<Object>>(ErrorId(predicateEvaluationResult.GetErrorId()));
353 }
354 bool include = false;
355 Object* predicateResult = predicateEvaluationResult.Value().Get();
356 if (predicateResult->IsNumber())
357 {
358 Number* number = cast<Number*>(predicateResult);
359 if (number->Value() == filterContext.Pos())
360 {
361 include = true;
362 }
363 }
364 else
365 {
366 auto booleanResult = ToBoolean(predicateResult, filterContext);
367 if (booleanResult.Error())
368 {
369 return booleanResult;
370 }
371 auto booleanCastResult = BooleanCast(booleanResult.Value().Get());
372 if (booleanCastResult.Error())
373 {
374 return Result<UniquePtr<Object>>(ErrorId(booleanCastResult.GetErrorId()));
375 }
376 Boolean* boolean = booleanCastResult.Value();
377 include = boolean->Value();
378 }
379 if (include)
380 {
381 filteredNodeSet->Add(node);
382 }
383 }
384 Swap(nodeSet, filteredNodeSet);
385 }
386 return Result<UniquePtr<Object>>(UniquePtr<Object>(nodeSet.Release()));
387 }
388 public override System.Xml.Element* ToXmlElement() const
389 {
390 System.Xml.Element* element = base->ToXmlElement();
391 element->SetAttribute("axis", System.Xml.AxisName(axis));
392 element->AppendChild(nodeTest->ToXmlElement());
393 System.Xml.Element* predicatesElement = System.Xml.MakeElement("predicates");
394 for (const auto& predicate : predicates)
395 {
396 predicatesElement->AppendChild(predicate->ToXmlElement());
397 }
398 element->AppendChild(predicatesElement);
399 return element;
400 }
401 private System.Xml.Axis axis;
402 private UniquePtr<NodeTest> nodeTest;
403 private List<UniquePtr<Expr>> predicates;
404 }
405
406 public class VariableReference : Expr
407 {
408 public VariableReference(const string& variableName_) : base(ExprKind.variableReference), variableName(variableName_)
409 {
410 }
411 public inline const string& VariableName() const
412 {
413 return variableName;
414 }
415 [nodiscard]
416 public override Result<UniquePtr<Object>> Evaluate(Context& context) const
417 {
418 #assert(false);
419 return Result<UniquePtr<Object>>();
420 }
421 public override System.Xml.Element* ToXmlElement() const
422 {
423 System.Xml.Element* element = base->ToXmlElement();
424 element->SetAttribute("variable-name", variableName);
425 return element;
426 }
427 private string variableName;
428 }
429
430 public class Literal : Expr
431 {
432 public Literal(const string& value_) : base(ExprKind.literal), value(value_)
433 {
434 }
435 public inline const string& Value() const
436 {
437 return value;
438 }
439 [nodiscard]
440 public override Result<UniquePtr<Object>> Evaluate(Context& context) const
441 {
442 return Result<UniquePtr<Object>>(UniquePtr<Object>(new Str(value)));
443 }
444 public override System.Xml.Element* ToXmlElement() const
445 {
446 System.Xml.Element* element = base->ToXmlElement();
447 element->SetAttribute("value", value);
448 return element;
449 }
450 private string value;
451 }
452
453 public class NumberExpr : Expr
454 {
455 public NumberExpr(double value_) : base(ExprKind.numberExpr), value(value_)
456 {
457 }
458 [nodiscard]
459 public override Result<UniquePtr<Object>> Evaluate(Context& context) const
460 {
461 return Result<UniquePtr<Object>>(UniquePtr<Object>(new Number(value)));
462 }
463 public override System.Xml.Element* ToXmlElement() const
464 {
465 System.Xml.Element* element = base->ToXmlElement();
466 element->SetAttribute("value", ToString(value));
467 return element;
468 }
469 private double value;
470 }
471
472 public class FunctionCall : Expr
473 {
474 public FunctionCall(const string& functionName_) : base(ExprKind.functionCall), functionName(functionName_)
475 {
476 }
477 public inline const string& FunctionName() const
478 {
479 return functionName;
480 }
481 public void AddArgument(Expr* argument)
482 {
483 arguments.Add(UniquePtr<Expr>(argument));
484 }
485 [nodiscard]
486 public override Result<UniquePtr<Object>> Evaluate(Context& context) const
487 {
488 auto functionResult = GetFunction(functionName);
489 if (functionResult.Error())
490 {
491 return Result<UniquePtr<Object>>(ErrorId(functionResult.GetErrorId()));
492 }
493 Function* function = functionResult.Value();
494 List<UniquePtr<Object>> ownedArgs;
495 List<Object*> args;
496 for (const auto& arg : arguments)
497 {
498 auto argResult = arg->Evaluate(context);
499 if (argResult.Error())
500 {
501 return Result<UniquePtr<Object>>(ErrorId(argResult.GetErrorId()));
502 }
503 UniquePtr<Object> ownedArg = Rvalue(argResult.Value());
504 args.Add(ownedArg.Get());
505 ownedArgs.Add(Rvalue(ownedArg));
506 }
507 return function->Evaluate(context, args);
508 }
509 public override System.Xml.Element* ToXmlElement() const
510 {
511 System.Xml.Element* element = base->ToXmlElement();
512 element->SetAttribute("function-name", functionName);
513 System.Xml.Element* argumentsElement = System.Xml.MakeElement("arguments");
514 for (const auto& arg : arguments)
515 {
516 argumentsElement->AppendChild(arg->ToXmlElement());
517 }
518 element->AppendChild(argumentsElement);
519 return element;
520 }
521 private string functionName;
522 private List<UniquePtr<Expr>> arguments;
523 }
524
525 public Expr* MakeSlashSlashExpr(Expr* left, Expr* right)
526 {
527 return new BinaryExpr(Operator.slash, left,
528 new BinaryExpr(Operator.slash,
529 new LocationStepExpr(System.Xml.Axis.descendantOrSelf, new NodeTest(NodeTestKind.anyNodeTest)),
530 right));
531 }