XPathParser.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System.Runtime;
  7. using System.Xml;
  8. using System.Xml.XPath;
  9. using System.Xml.Xsl;
  10. class XPathParser
  11. {
  12. IFunctionLibrary[] functionLibraries;
  13. XPathLexer lexer;
  14. XmlNamespaceManager namespaces;
  15. XPathToken readToken;
  16. XsltContext context;
  17. internal XPathParser(string xpath, XmlNamespaceManager namespaces, IFunctionLibrary[] functionLibraries)
  18. {
  19. Fx.Assert(null != xpath, "");
  20. this.functionLibraries = functionLibraries;
  21. this.namespaces = namespaces;
  22. this.lexer = new XPathLexer(xpath);
  23. this.context = namespaces as XsltContext;
  24. }
  25. XPathExpr EnsureReturnsNodeSet(XPathExpr expr)
  26. {
  27. if (expr.ReturnType != ValueDataType.Sequence)
  28. {
  29. this.ThrowError(QueryCompileError.InvalidFunction);
  30. }
  31. return expr;
  32. }
  33. XPathToken NextToken()
  34. {
  35. if (null != this.readToken)
  36. {
  37. XPathToken nextToken = this.readToken;
  38. this.readToken = null;
  39. return nextToken;
  40. }
  41. while (this.lexer.MoveNext())
  42. {
  43. if (XPathTokenID.Whitespace != this.lexer.Token.TokenID)
  44. {
  45. return this.lexer.Token;
  46. }
  47. }
  48. return null;
  49. }
  50. XPathToken NextToken(XPathTokenID id)
  51. {
  52. XPathToken token = this.NextToken();
  53. if (null != token)
  54. {
  55. if (id == token.TokenID)
  56. {
  57. return token;
  58. }
  59. this.readToken = token;
  60. }
  61. return null;
  62. }
  63. XPathToken NextToken(XPathTokenID id, QueryCompileError error)
  64. {
  65. XPathToken token = this.NextToken(id);
  66. if (null == token)
  67. {
  68. this.ThrowError(error);
  69. }
  70. return token;
  71. }
  72. XPathToken NextTokenClass(XPathTokenID tokenClass)
  73. {
  74. XPathToken token = this.NextToken();
  75. if (null != token)
  76. {
  77. if (0 != (token.TokenID & tokenClass))
  78. {
  79. return token;
  80. }
  81. this.readToken = token;
  82. }
  83. return null;
  84. }
  85. NodeQName QualifyName(string prefix, string name)
  86. {
  87. if (null != this.namespaces && null != prefix && prefix.Length > 0)
  88. {
  89. prefix = this.namespaces.NameTable.Add(prefix);
  90. string ns = this.namespaces.LookupNamespace(prefix);
  91. if (null == ns)
  92. {
  93. this.ThrowError(QueryCompileError.NoNamespaceForPrefix);
  94. }
  95. return new NodeQName(name, ns);
  96. }
  97. return new NodeQName(name);
  98. }
  99. internal XPathExpr Parse()
  100. {
  101. XPathExpr expr = this.ParseExpression();
  102. if (null == expr)
  103. {
  104. this.ThrowError(QueryCompileError.InvalidExpression);
  105. }
  106. // If we stopped before the entire xpath was lexed, we hit something we could not tokenize
  107. XPathToken lastToken = this.NextToken();
  108. if (null != lastToken)
  109. {
  110. this.ThrowError(QueryCompileError.UnexpectedToken);
  111. }
  112. return expr;
  113. }
  114. XPathExprList ParseAbsolutePath()
  115. {
  116. XPathExprList path = null;
  117. XPathToken token = this.NextToken();
  118. if (null != token)
  119. {
  120. switch (token.TokenID)
  121. {
  122. default:
  123. this.PushToken(token);
  124. break;
  125. case XPathTokenID.Slash:
  126. path = new XPathExprList();
  127. path.Add(new XPathStepExpr(new NodeSelectCriteria(QueryAxisType.Child, NodeQName.Empty, QueryNodeType.Root)));
  128. break;
  129. case XPathTokenID.DblSlash:
  130. // '//' is special. If found at the start of an absolute path, it implies that the descendant-or-self axis
  131. // is applied to the ROOT
  132. path = new XPathExprList();
  133. path.Add(new XPathStepExpr(new NodeSelectCriteria(QueryAxisType.Child, NodeQName.Empty, QueryNodeType.Root)));
  134. path.Add(new XPathStepExpr(new NodeSelectCriteria(QueryAxisType.DescendantOrSelf, NodeQName.Empty, QueryNodeType.All)));
  135. break;
  136. }
  137. }
  138. if (null != path)
  139. {
  140. this.ParseRelativePath(path);
  141. }
  142. return path;
  143. }
  144. XPathExpr ParseAdditiveExpression()
  145. {
  146. XPathExpr leftExpr = this.ParseMultiplicativeExpression();
  147. if (null != leftExpr)
  148. {
  149. MathOperator op;
  150. do
  151. {
  152. op = MathOperator.None;
  153. XPathToken token = this.NextToken();
  154. if (null != token)
  155. {
  156. switch (token.TokenID)
  157. {
  158. default:
  159. this.PushToken(token);
  160. break;
  161. case XPathTokenID.Plus:
  162. op = MathOperator.Plus;
  163. break;
  164. case XPathTokenID.Minus:
  165. op = MathOperator.Minus;
  166. break;
  167. }
  168. if (MathOperator.None != op)
  169. {
  170. XPathExpr rightExpr = this.ParseMultiplicativeExpression();
  171. if (null == rightExpr)
  172. {
  173. this.ThrowError(QueryCompileError.InvalidExpression);
  174. }
  175. leftExpr = new XPathMathExpr(op, leftExpr, rightExpr);
  176. }
  177. }
  178. } while (MathOperator.None != op);
  179. }
  180. return leftExpr;
  181. }
  182. XPathExpr ParseAndExpression()
  183. {
  184. XPathExpr eqExpr = this.ParseEqualityExpression();
  185. if (null != eqExpr && null != this.NextToken(XPathTokenID.And))
  186. {
  187. XPathExpr andExpr = new XPathExpr(XPathExprType.And, ValueDataType.Boolean);
  188. andExpr.AddBooleanExpression(XPathExprType.And, eqExpr);
  189. do
  190. {
  191. eqExpr = this.ParseEqualityExpression();
  192. if (eqExpr == null)
  193. this.ThrowError(QueryCompileError.InvalidExpression);
  194. andExpr.AddBooleanExpression(XPathExprType.And, eqExpr);
  195. } while (null != this.NextToken(XPathTokenID.And));
  196. return andExpr;
  197. }
  198. return eqExpr;
  199. }
  200. QueryAxisType ParseAxisSpecifier()
  201. {
  202. if (null != this.NextToken(XPathTokenID.AtSign))
  203. {
  204. return QueryAxisType.Attribute;
  205. }
  206. QueryAxisType axisType = QueryAxisType.None;
  207. XPathToken token;
  208. if (null != (token = this.NextTokenClass(XPathTokenID.Axis)))
  209. {
  210. switch (token.TokenID)
  211. {
  212. default:
  213. this.ThrowError(QueryCompileError.UnsupportedAxis);
  214. break;
  215. case XPathTokenID.Attribute:
  216. axisType = QueryAxisType.Attribute;
  217. break;
  218. case XPathTokenID.Child:
  219. axisType = QueryAxisType.Child;
  220. break;
  221. case XPathTokenID.Descendant:
  222. axisType = QueryAxisType.Descendant;
  223. break;
  224. case XPathTokenID.DescendantOrSelf:
  225. axisType = QueryAxisType.DescendantOrSelf;
  226. break;
  227. case XPathTokenID.Self:
  228. axisType = QueryAxisType.Self;
  229. break;
  230. }
  231. // axis specifiers must be followed by a '::'
  232. this.NextToken(XPathTokenID.DblColon, QueryCompileError.InvalidAxisSpecifier);
  233. }
  234. return axisType;
  235. }
  236. XPathExpr ParseEqualityExpression()
  237. {
  238. XPathExpr leftExpr = this.ParseRelationalExpression();
  239. if (null != leftExpr)
  240. {
  241. RelationOperator op;
  242. do
  243. {
  244. op = RelationOperator.None;
  245. XPathToken token = this.NextToken();
  246. if (null != token)
  247. {
  248. switch (token.TokenID)
  249. {
  250. default:
  251. this.PushToken(token);
  252. break;
  253. case XPathTokenID.Eq:
  254. op = RelationOperator.Eq;
  255. break;
  256. case XPathTokenID.Neq:
  257. op = RelationOperator.Ne;
  258. break;
  259. }
  260. if (RelationOperator.None != op)
  261. {
  262. XPathExpr rightExpr = this.ParseRelationalExpression();
  263. if (null == rightExpr)
  264. {
  265. this.ThrowError(QueryCompileError.InvalidExpression);
  266. }
  267. leftExpr = new XPathRelationExpr(op, leftExpr, rightExpr);
  268. }
  269. }
  270. } while (RelationOperator.None != op);
  271. }
  272. return leftExpr;
  273. }
  274. XPathExpr ParseExpression()
  275. {
  276. return this.ParseOrExpression();
  277. }
  278. XPathExpr ParseFilterExpression()
  279. {
  280. XPathExpr primaryExpr = this.ParsePrimaryExpression();
  281. if (null == primaryExpr)
  282. {
  283. return null;
  284. }
  285. XPathExpr filterExpr = new XPathExpr(XPathExprType.Filter, primaryExpr.ReturnType);
  286. filterExpr.Add(primaryExpr);
  287. XPathExpr predicate = this.ParsePredicateExpression();
  288. if (null != predicate)
  289. {
  290. EnsureReturnsNodeSet(primaryExpr);
  291. //XPathExpr filterExpr = new XPathExpr(XPathExprType.Filter, ValueDataType.Sequence);
  292. //filterExpr.Add(primaryExpr);
  293. filterExpr.Add(predicate);
  294. // Read in any additional predicates
  295. while (null != (predicate = this.ParsePredicateExpression()))
  296. {
  297. filterExpr.Add(predicate);
  298. }
  299. return filterExpr;
  300. }
  301. return primaryExpr;
  302. }
  303. XPathExpr ParseFunctionExpression()
  304. {
  305. XPathToken functionToken = this.NextToken(XPathTokenID.Function);
  306. if (null == functionToken)
  307. {
  308. return null;
  309. }
  310. NodeQName functionName = this.QualifyName(functionToken.Prefix, functionToken.Name);
  311. this.NextToken(XPathTokenID.LParen, QueryCompileError.InvalidFunction);
  312. XPathExprList args = new XPathExprList();
  313. // Read in arguments
  314. XPathExpr arg;
  315. while (null != (arg = this.ParseExpression()))
  316. {
  317. args.Add(arg);
  318. if (null == this.NextToken(XPathTokenID.Comma))
  319. {
  320. break;
  321. }
  322. }
  323. // Bind to the function
  324. // Try each library until we can bind the function
  325. XPathExpr functionImpl = null;
  326. if (null != this.functionLibraries)
  327. {
  328. QueryFunction fun = null;
  329. for (int i = 0; i < this.functionLibraries.Length; ++i)
  330. {
  331. if (null != (fun = this.functionLibraries[i].Bind(functionName.Name, functionName.Namespace, args)))
  332. {
  333. functionImpl = new XPathFunctionExpr(fun, args);
  334. break;
  335. }
  336. }
  337. }
  338. // Try to bind using the XsltContext
  339. if (null == functionImpl && this.context != null)
  340. {
  341. XPathResultType[] argTypes = new XPathResultType[args.Count];
  342. for (int i = 0; i < args.Count; ++i)
  343. {
  344. argTypes[i] = XPathXsltFunctionExpr.ConvertTypeToXslt(args[i].ReturnType);
  345. }
  346. string prefix = this.context.LookupPrefix(functionName.Namespace);
  347. IXsltContextFunction xsltFun = this.context.ResolveFunction(prefix, functionName.Name, argTypes);
  348. if (xsltFun != null)
  349. {
  350. functionImpl = new XPathXsltFunctionExpr(this.context, xsltFun, args);
  351. }
  352. }
  353. if (null == functionImpl)
  354. {
  355. this.ThrowError(QueryCompileError.UnsupportedFunction);
  356. }
  357. this.NextToken(XPathTokenID.RParen, QueryCompileError.InvalidFunction);
  358. return functionImpl;
  359. }
  360. internal XPathExpr ParseLocationPath()
  361. {
  362. XPathExprList path = this.ParseAbsolutePath();
  363. if (null == path)
  364. {
  365. path = this.ParseRelativePath();
  366. }
  367. if (null != path)
  368. {
  369. return new XPathExpr(XPathExprType.LocationPath, ValueDataType.Sequence, path);
  370. }
  371. return null;
  372. }
  373. XPathExpr ParseLiteralExpression()
  374. {
  375. XPathToken literal;
  376. if (null != (literal = this.NextToken(XPathTokenID.Literal)))
  377. {
  378. return new XPathStringExpr(literal.Name);
  379. }
  380. return null;
  381. }
  382. XPathExpr ParseMultiplicativeExpression()
  383. {
  384. XPathExpr leftExpr = this.ParseUnaryExpression();
  385. if (null != leftExpr)
  386. {
  387. MathOperator op;
  388. do
  389. {
  390. op = MathOperator.None;
  391. XPathToken token = this.NextToken();
  392. if (null != token)
  393. {
  394. switch (token.TokenID)
  395. {
  396. default:
  397. this.PushToken(token);
  398. break;
  399. case XPathTokenID.Multiply:
  400. op = MathOperator.Multiply;
  401. break;
  402. case XPathTokenID.Div:
  403. op = MathOperator.Div;
  404. break;
  405. case XPathTokenID.Mod:
  406. op = MathOperator.Mod;
  407. break;
  408. }
  409. if (MathOperator.None != op)
  410. {
  411. XPathExpr rightExpr = this.ParseUnaryExpression();
  412. if (null == rightExpr)
  413. {
  414. this.ThrowError(QueryCompileError.InvalidExpression);
  415. }
  416. leftExpr = new XPathMathExpr(op, leftExpr, rightExpr);
  417. }
  418. }
  419. } while (MathOperator.None != op);
  420. }
  421. return leftExpr;
  422. }
  423. NodeSelectCriteria ParseNodeTest(QueryAxisType axisType)
  424. {
  425. Fx.Assert(QueryAxisType.None != axisType, "");
  426. QueryAxis axis = QueryDataModel.GetAxis(axisType);
  427. XPathToken token;
  428. NodeQName qname = NodeQName.Empty;
  429. if (null != (token = this.NextTokenClass(XPathTokenID.NameTest)))
  430. {
  431. switch (token.TokenID)
  432. {
  433. default:
  434. this.ThrowError(QueryCompileError.UnexpectedToken);
  435. break;
  436. case XPathTokenID.Wildcard:
  437. qname = new NodeQName(QueryDataModel.Wildcard, QueryDataModel.Wildcard);
  438. break;
  439. case XPathTokenID.NameTest:
  440. qname = this.QualifyName(token.Prefix, token.Name);
  441. break;
  442. case XPathTokenID.NameWildcard:
  443. qname = this.QualifyName(token.Prefix, QueryDataModel.Wildcard);
  444. break;
  445. }
  446. }
  447. QueryNodeType nodeType = QueryNodeType.Any;
  448. if (qname.IsEmpty)
  449. {
  450. // Check for nodeTests
  451. if (null == (token = this.NextTokenClass(XPathTokenID.NodeType)))
  452. {
  453. // Not a NodeTest either.
  454. return null;
  455. }
  456. switch (token.TokenID)
  457. {
  458. default:
  459. this.ThrowError(QueryCompileError.UnsupportedNodeTest);
  460. break;
  461. case XPathTokenID.Comment:
  462. nodeType = QueryNodeType.Comment;
  463. break;
  464. case XPathTokenID.Text:
  465. nodeType = QueryNodeType.Text;
  466. break;
  467. case XPathTokenID.Processing:
  468. nodeType = QueryNodeType.Processing;
  469. break;
  470. case XPathTokenID.Node:
  471. nodeType = QueryNodeType.All;
  472. break;
  473. }
  474. // Make sure the nodes being selected CAN actually be selected from this axis
  475. if (0 == (axis.ValidNodeTypes & nodeType))
  476. {
  477. this.ThrowError(QueryCompileError.InvalidNodeType);
  478. }
  479. // Eat ()
  480. this.NextToken(XPathTokenID.LParen, QueryCompileError.InvalidNodeTest);
  481. this.NextToken(XPathTokenID.RParen, QueryCompileError.InvalidNodeTest);
  482. }
  483. else
  484. {
  485. nodeType = axis.PrincipalNodeType;
  486. }
  487. return new NodeSelectCriteria(axisType, qname, nodeType);
  488. }
  489. XPathExpr ParseNumberExpression()
  490. {
  491. XPathToken number;
  492. if (null != (number = this.NextTokenClass(XPathTokenID.Number)))
  493. {
  494. return new XPathNumberExpr(number.Number);
  495. }
  496. return null;
  497. }
  498. XPathExpr ParseOrExpression()
  499. {
  500. XPathExpr andExpr = this.ParseAndExpression();
  501. if (null != andExpr && null != this.NextToken(XPathTokenID.Or))
  502. {
  503. XPathExpr orExpr = new XPathExpr(XPathExprType.Or, ValueDataType.Boolean);
  504. orExpr.AddBooleanExpression(XPathExprType.Or, andExpr);
  505. do
  506. {
  507. andExpr = this.ParseAndExpression();
  508. if (andExpr == null)
  509. this.ThrowError(QueryCompileError.InvalidExpression);
  510. orExpr.AddBooleanExpression(XPathExprType.Or, andExpr);
  511. } while (null != this.NextToken(XPathTokenID.Or));
  512. return orExpr;
  513. }
  514. return andExpr;
  515. }
  516. XPathExpr ParsePathExpression()
  517. {
  518. XPathExpr pathExpr = this.ParseLocationPath();
  519. if (null != pathExpr)
  520. {
  521. return pathExpr;
  522. }
  523. // Perhaps we have a filter expression
  524. XPathExpr filterExpr = this.ParseFilterExpression();
  525. if (null != filterExpr)
  526. {
  527. if (null != this.NextToken(XPathTokenID.Slash))
  528. {
  529. EnsureReturnsNodeSet(filterExpr);
  530. // Is this a complex filter expression.. i.e. followed by further selections..
  531. XPathExprList relPath = this.ParseRelativePath();
  532. if (null == relPath)
  533. {
  534. this.ThrowError(QueryCompileError.InvalidLocationPath);
  535. }
  536. XPathExpr relPathExpr = new XPathExpr(XPathExprType.RelativePath, ValueDataType.Sequence, relPath);
  537. pathExpr = new XPathExpr(XPathExprType.Path, ValueDataType.Sequence);
  538. pathExpr.Add(filterExpr);
  539. pathExpr.Add(relPathExpr);
  540. }
  541. else if (null != this.NextToken(XPathTokenID.DblSlash))
  542. {
  543. EnsureReturnsNodeSet(filterExpr);
  544. XPathExprList relPath = this.ParseRelativePath();
  545. if (null == relPath)
  546. {
  547. this.ThrowError(QueryCompileError.InvalidLocationPath);
  548. }
  549. XPathExpr relPathExpr = new XPathExpr(XPathExprType.RelativePath, ValueDataType.Sequence, relPath);
  550. pathExpr = new XPathExpr(XPathExprType.Path, ValueDataType.Sequence);
  551. pathExpr.Add(filterExpr);
  552. pathExpr.Add(new XPathStepExpr(new NodeSelectCriteria(QueryAxisType.DescendantOrSelf, NodeQName.Empty, QueryNodeType.All)));
  553. pathExpr.Add(relPathExpr);
  554. }
  555. else
  556. {
  557. pathExpr = filterExpr;
  558. }
  559. }
  560. return pathExpr;
  561. }
  562. XPathExprList ParsePredicates()
  563. {
  564. XPathExprList predicates = null;
  565. XPathExpr predicate = this.ParsePredicateExpression();
  566. if (null != predicate)
  567. {
  568. predicates = new XPathExprList();
  569. predicates.Add(predicate);
  570. while (null != (predicate = this.ParsePredicateExpression()))
  571. {
  572. predicates.Add(predicate);
  573. }
  574. }
  575. return predicates;
  576. }
  577. XPathExpr ParsePredicateExpression()
  578. {
  579. XPathExpr predicate = null;
  580. if (null != this.NextToken(XPathTokenID.LBracket))
  581. {
  582. predicate = this.ParseExpression();
  583. if (null == predicate)
  584. {
  585. this.ThrowError(QueryCompileError.InvalidPredicate);
  586. }
  587. this.NextToken(XPathTokenID.RBracket, QueryCompileError.InvalidPredicate);
  588. }
  589. return predicate;
  590. }
  591. XPathExpr ParsePrimaryExpression()
  592. {
  593. XPathExpr expr = this.ParseVariableExpression();
  594. if (null == expr)
  595. {
  596. if (null != this.NextToken(XPathTokenID.LParen))
  597. {
  598. expr = this.ParseExpression();
  599. if (null == expr || null == this.NextToken(XPathTokenID.RParen))
  600. {
  601. this.ThrowError(QueryCompileError.InvalidExpression);
  602. }
  603. }
  604. }
  605. if (null == expr)
  606. {
  607. expr = this.ParseLiteralExpression();
  608. }
  609. if (null == expr)
  610. {
  611. expr = this.ParseNumberExpression();
  612. }
  613. if (null == expr)
  614. {
  615. expr = this.ParseFunctionExpression();
  616. }
  617. return expr;
  618. }
  619. XPathExprList ParseRelativePath()
  620. {
  621. XPathExprList path = new XPathExprList();
  622. if (this.ParseRelativePath(path))
  623. {
  624. return path;
  625. }
  626. return null;
  627. }
  628. bool ParseRelativePath(XPathExprList path)
  629. {
  630. Fx.Assert(null != path, "");
  631. XPathStepExpr step = this.ParseStep();
  632. if (null == step)
  633. {
  634. return false;
  635. }
  636. path.Add(step);
  637. while (true)
  638. {
  639. if (null != this.NextToken(XPathTokenID.Slash))
  640. {
  641. step = this.ParseStep();
  642. }
  643. else if (null != this.NextToken(XPathTokenID.DblSlash))
  644. {
  645. step = new XPathStepExpr(new NodeSelectCriteria(QueryAxisType.DescendantOrSelf, NodeQName.Empty, QueryNodeType.All));
  646. path.Add(step);
  647. step = this.ParseStep();
  648. }
  649. else
  650. {
  651. break;
  652. }
  653. if (null == step)
  654. {
  655. this.ThrowError(QueryCompileError.InvalidLocationPath);
  656. }
  657. path.Add(step);
  658. }
  659. return true;
  660. }
  661. XPathExpr ParseRelationalExpression()
  662. {
  663. XPathExpr leftExpr = this.ParseAdditiveExpression();
  664. if (null != leftExpr)
  665. {
  666. RelationOperator op;
  667. do
  668. {
  669. op = RelationOperator.None;
  670. XPathToken token = this.NextToken();
  671. if (null != token)
  672. {
  673. switch (token.TokenID)
  674. {
  675. default:
  676. this.PushToken(token);
  677. break;
  678. case XPathTokenID.Lt:
  679. op = RelationOperator.Lt;
  680. break;
  681. case XPathTokenID.Lte:
  682. op = RelationOperator.Le;
  683. break;
  684. case XPathTokenID.Gt:
  685. op = RelationOperator.Gt;
  686. break;
  687. case XPathTokenID.Gte:
  688. op = RelationOperator.Ge;
  689. break;
  690. }
  691. if (RelationOperator.None != op)
  692. {
  693. XPathExpr rightExpr = this.ParseAdditiveExpression();
  694. if (null == rightExpr)
  695. {
  696. this.ThrowError(QueryCompileError.InvalidExpression);
  697. }
  698. leftExpr = new XPathRelationExpr(op, leftExpr, rightExpr);
  699. }
  700. }
  701. } while (RelationOperator.None != op);
  702. }
  703. return leftExpr;
  704. }
  705. XPathStepExpr ParseStep()
  706. {
  707. QueryAxisType axis = this.ParseAxisSpecifier();
  708. NodeSelectCriteria selectDesc = null;
  709. bool abbreviatedStep = false;
  710. if (QueryAxisType.None != axis)
  711. {
  712. // Valid axis specifier - must be followed by a nodeTest
  713. selectDesc = this.ParseNodeTest(axis);
  714. }
  715. else
  716. {
  717. // No axis specifier. This could be an abbreviated step - shortcuts for 'self' or 'parent'
  718. if (null != this.NextToken(XPathTokenID.Period))
  719. {
  720. selectDesc = new NodeSelectCriteria(QueryAxisType.Self, NodeQName.Empty, QueryNodeType.All);
  721. abbreviatedStep = true;
  722. }
  723. else if (null != this.NextToken(XPathTokenID.DblPeriod))
  724. {
  725. // A shortcut for parent
  726. selectDesc = new NodeSelectCriteria(QueryAxisType.Parent, NodeQName.Empty, QueryNodeType.Ancestor);
  727. abbreviatedStep = true;
  728. }
  729. else
  730. {
  731. // No axis specifier provided. Assume child
  732. if (null == (selectDesc = this.ParseNodeTest(QueryAxisType.Child)))
  733. {
  734. // No nodeTest either.. clearly not a Step
  735. return null;
  736. }
  737. }
  738. }
  739. if (null == selectDesc)
  740. {
  741. this.ThrowError(QueryCompileError.InvalidLocationStep);
  742. }
  743. XPathExprList predicates = null;
  744. if (!abbreviatedStep)
  745. {
  746. // Abbreviated steps are not permitted predicates
  747. predicates = this.ParsePredicates();
  748. }
  749. return new XPathStepExpr(selectDesc, predicates);
  750. }
  751. XPathExpr ParseUnaryExpression()
  752. {
  753. bool negate = false, anyNegate = false;
  754. for (; null != this.NextToken(XPathTokenID.Minus); anyNegate = true, negate = !negate);
  755. XPathExpr expr = ParseUnionExpression();
  756. if (expr != null)
  757. {
  758. // If there were any negations at all, the type gets converted to a number
  759. if (anyNegate && expr.ReturnType != ValueDataType.Double)
  760. {
  761. expr.ReturnType = ValueDataType.Double;
  762. expr.TypecastRequired = true;
  763. }
  764. expr.Negate = negate;
  765. }
  766. return expr;
  767. }
  768. internal XPathExpr ParseUnionExpression()
  769. {
  770. XPathExpr leftExpr = this.ParsePathExpression();
  771. if (null != leftExpr)
  772. {
  773. if (null != this.NextToken(XPathTokenID.Pipe))
  774. {
  775. EnsureReturnsNodeSet(leftExpr);
  776. XPathExpr rightExpr = this.ParseUnionExpression();
  777. if (rightExpr == null)
  778. {
  779. ThrowError(QueryCompileError.CouldNotParseExpression);
  780. }
  781. EnsureReturnsNodeSet(rightExpr);
  782. return new XPathConjunctExpr(XPathExprType.Union, ValueDataType.Sequence, leftExpr, rightExpr);
  783. }
  784. }
  785. return leftExpr;
  786. }
  787. internal XPathExpr ParseVariableExpression()
  788. {
  789. XPathExpr expr = null;
  790. if (this.context != null)
  791. {
  792. XPathToken varTok = this.NextToken(XPathTokenID.Variable);
  793. if (varTok != null)
  794. {
  795. NodeQName varName = this.QualifyName(varTok.Prefix, varTok.Name);
  796. string prefix = this.context.LookupPrefix(varName.Namespace);
  797. IXsltContextVariable var = this.context.ResolveVariable(prefix, varName.Name);
  798. if (var != null)
  799. {
  800. expr = new XPathXsltVariableExpr(this.context, var);
  801. }
  802. }
  803. }
  804. return expr;
  805. }
  806. void PushToken(XPathToken token)
  807. {
  808. Fx.Assert(null == this.readToken, "");
  809. this.readToken = token;
  810. }
  811. internal void ThrowError(QueryCompileError error)
  812. {
  813. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(error, this.lexer.ConsumedSubstring()));
  814. }
  815. internal struct QName
  816. {
  817. string prefix;
  818. string name;
  819. internal QName(string prefix, string name)
  820. {
  821. Fx.Assert(null != prefix, "");
  822. this.prefix = prefix;
  823. this.name = name;
  824. }
  825. internal string Prefix
  826. {
  827. get
  828. {
  829. return this.prefix;
  830. }
  831. }
  832. internal string Name
  833. {
  834. get
  835. {
  836. return this.name;
  837. }
  838. }
  839. }
  840. }
  841. }