2
0

XPathLexer.cs 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System.Collections;
  7. using System.Runtime;
  8. internal static class XPathCharTypes
  9. {
  10. static byte[] charProperties;
  11. // Types of characters identified by this class
  12. private const byte None = 0x00;
  13. private const byte Letter = 0x01;
  14. private const byte Combining = 0x02;
  15. private const byte Digit = 0x04;
  16. private const byte Extender = 0x08;
  17. private const byte Whitespace = 0x10;
  18. private const byte NCName = 0x20;
  19. private const byte NCNameStart = 0x40;
  20. #region Data Tables
  21. // The character tables below hold unicode characters that are paired to represent character ranges.
  22. // The first is the first character in the range, the second is the last character in the range.
  23. // The definition of NCName is taken from "Namespaces in XML" (http://www.w3.org/TR/REC-xml-names/) Section 2
  24. // The definition of Whitespace is taken from: "XML 1.0 (Second Edition)" (http://www.w3.org/TR/REC-xml) Section 2.3
  25. // All classes of characters contain references to their definitions
  26. // BaseChars
  27. // Taken from: "XML 1.0 (Second Edition)" (http://www.w3.org/TR/REC-xml) Appendix B
  28. // [#x0041-#x005A] | [#x0061-#x007A] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x00FF] | [#x0100-#x0131] | [#x0134-#x013E] | [#x0141-#x0148] | [#x014A-#x017E] | [#x0180-#x01C3] | [#x01CD-#x01F0] | [#x01F4-#x01F5] | [#x01FA-#x0217] | [#x0250-#x02A8] | [#x02BB-#x02C1] | #x0386 | [#x0388-#x038A] | #x038C | [#x038E-#x03A1] | [#x03A3-#x03CE] | [#x03D0-#x03D6] | #x03DA | #x03DC | #x03DE | #x03E0 | [#x03E2-#x03F3] | [#x0401-#x040C] | [#x040E-#x044F] | [#x0451-#x045C] | [#x045E-#x0481] | [#x0490-#x04C4] | [#x04C7-#x04C8] | [#x04CB-#x04CC] | [#x04D0-#x04EB] | [#x04EE-#x04F5] | [#x04F8-#x04F9] | [#x0531-#x0556] | #x0559 | [#x0561-#x0586] | [#x05D0-#x05EA] | [#x05F0-#x05F2] | [#x0621-#x063A] | [#x0641-#x064A] | [#x0671-#x06B7] | [#x06BA-#x06BE] | [#x06C0-#x06CE] | [#x06D0-#x06D3] | #x06D5 | [#x06E5-#x06E6] | [#x0905-#x0939] | #x093D | [#x0958-#x0961] | [#x0985-#x098C] | [#x098F-#x0990] | [#x0993-#x09A8] | [#x09AA-#x09B0] | #x09B2 | [#x09B6-#x09B9] | [#x09DC-#x09DD] | [#x09DF-#x09E1] | [#x09F0-#x09F1] | [#x0A05-#x0A0A] | [#x0A0F-#x0A10] | [#x0A13-#x0A28] | [#x0A2A-#x0A30] | [#x0A32-#x0A33] | [#x0A35-#x0A36] | [#x0A38-#x0A39] | [#x0A59-#x0A5C] | #x0A5E | [#x0A72-#x0A74] | [#x0A85-#x0A8B] | #x0A8D | [#x0A8F-#x0A91] | [#x0A93-#x0AA8] | [#x0AAA-#x0AB0] | [#x0AB2-#x0AB3] | [#x0AB5-#x0AB9] | #x0ABD | #x0AE0 | [#x0B05-#x0B0C] | [#x0B0F-#x0B10] | [#x0B13-#x0B28] | [#x0B2A-#x0B30] | [#x0B32-#x0B33] | [#x0B36-#x0B39] | #x0B3D | [#x0B5C-#x0B5D] | [#x0B5F-#x0B61] | [#x0B85-#x0B8A] | [#x0B8E-#x0B90] | [#x0B92-#x0B95] | [#x0B99-#x0B9A] | #x0B9C | [#x0B9E-#x0B9F] | [#x0BA3-#x0BA4] | [#x0BA8-#x0BAA] | [#x0BAE-#x0BB5] | [#x0BB7-#x0BB9] | [#x0C05-#x0C0C] | [#x0C0E-#x0C10] | [#x0C12-#x0C28] | [#x0C2A-#x0C33] | [#x0C35-#x0C39] | [#x0C60-#x0C61] | [#x0C85-#x0C8C] | [#x0C8E-#x0C90] | [#x0C92-#x0CA8] | [#x0CAA-#x0CB3] | [#x0CB5-#x0CB9] | #x0CDE | [#x0CE0-#x0CE1] | [#x0D05-#x0D0C] | [#x0D0E-#x0D10] | [#x0D12-#x0D28] | [#x0D2A-#x0D39] | [#x0D60-#x0D61] | [#x0E01-#x0E2E] | #x0E30 | [#x0E32-#x0E33] | [#x0E40-#x0E45] |
  29. // [#x0E81-#x0E82] | #x0E84 | [#x0E87-#x0E88] | #x0E8A | #x0E8D | [#x0E94-#x0E97] | [#x0E99-#x0E9F] | [#x0EA1-#x0EA3] | #x0EA5 | #x0EA7 | [#x0EAA-#x0EAB] | [#x0EAD-#x0EAE] | #x0EB0 | [#x0EB2-#x0EB3] | #x0EBD | [#x0EC0-#x0EC4] | [#x0F40-#x0F47] | [#x0F49-#x0F69] | [#x10A0-#x10C5] | [#x10D0-#x10F6] | #x1100 | [#x1102-#x1103] | [#x1105-#x1107] | #x1109 | [#x110B-#x110C] | [#x110E-#x1112] | #x113C | #x113E | #x1140 | #x114C | #x114E | #x1150 | [#x1154-#x1155] | #x1159 | [#x115F-#x1161] | #x1163 | #x1165 | #x1167 | #x1169 | [#x116D-#x116E] | [#x1172-#x1173] | #x1175 | #x119E | #x11A8 | #x11AB | [#x11AE-#x11AF] | [#x11B7-#x11B8] | #x11BA | [#x11BC-#x11C2] | #x11EB | #x11F0 | #x11F9 | [#x1E00-#x1E9B] | [#x1EA0-#x1EF9] | [#x1F00-#x1F15] | [#x1F18-#x1F1D] | [#x1F20-#x1F45] | [#x1F48-#x1F4D] | [#x1F50-#x1F57] | #x1F59 | #x1F5B | #x1F5D | [#x1F5F-#x1F7D] | [#x1F80-#x1FB4] | [#x1FB6-#x1FBC] | #x1FBE | [#x1FC2-#x1FC4] | [#x1FC6-#x1FCC] | [#x1FD0-#x1FD3] | [#x1FD6-#x1FDB] | [#x1FE0-#x1FEC] | [#x1FF2-#x1FF4] | [#x1FF6-#x1FFC] | #x2126 | [#x212A-#x212B] | #x212E | [#x2180-#x2182] | [#x3041-#x3094] | [#x30A1-#x30FA] | [#x3105-#x312C] | [#xAC00-#xD7A3]
  30. const string BaseChars =
  31. "\u0041\u005A\u0061\u007A\u00C0\u00D6\u00D8\u00F6" +
  32. "\u00F8\u00FF\u0100\u0131\u0134\u013E\u0141\u0148" +
  33. "\u014A\u017E\u0180\u01C3\u01CD\u01F0\u01F4\u01F5" +
  34. "\u01FA\u0217\u0250\u02A8\u02BB\u02C1\u0386\u0386" +
  35. "\u0388\u038A\u038C\u038C\u038E\u03A1\u03A3\u03CE" +
  36. "\u03D0\u03D6\u03DA\u03DA\u03DC\u03DC\u03DE\u03DE" +
  37. "\u03E0\u03E0\u03E2\u03F3\u0401\u040C\u040E\u044F" +
  38. "\u0451\u045C\u045E\u0481\u0490\u04C4\u04C7\u04C8" +
  39. "\u04CB\u04CC\u04D0\u04EB\u04EE\u04F5\u04F8\u04F9" +
  40. "\u0531\u0556\u0559\u0559\u0561\u0586\u05D0\u05EA" +
  41. "\u05F0\u05F2\u0621\u063A\u0641\u064A\u0671\u06B7" +
  42. "\u06BA\u06BE\u06C0\u06CE\u06D0\u06D3\u06D5\u06D5" +
  43. "\u06E5\u06E6\u0905\u0939\u093D\u093D\u0958\u0961" +
  44. "\u0985\u098C\u098F\u0990\u0993\u09A8\u09AA\u09B0" +
  45. "\u09B2\u09B2\u09B6\u09B9\u09DC\u09DD\u09DF\u09E1" +
  46. "\u09F0\u09F1\u0A05\u0A0A\u0A0F\u0A10\u0A13\u0A28" +
  47. "\u0A2A\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39" +
  48. "\u0A59\u0A5C\u0A5E\u0A5E\u0A72\u0A74\u0A85\u0A8B" +
  49. "\u0A8D\u0A8D\u0A8F\u0A91\u0A93\u0AA8\u0AAA\u0AB0" +
  50. "\u0AB2\u0AB3\u0AB5\u0AB9\u0ABD\u0ABD\u0AE0\u0AE0" +
  51. "\u0B05\u0B0C\u0B0F\u0B10\u0B13\u0B28\u0B2A\u0B30" +
  52. "\u0B32\u0B33\u0B36\u0B39\u0B3D\u0B3D\u0B5C\u0B5D" +
  53. "\u0B5F\u0B61\u0B85\u0B8A\u0B8E\u0B90\u0B92\u0B95" +
  54. "\u0B99\u0B9A\u0B9C\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4" +
  55. "\u0BA8\u0BAA\u0BAE\u0BB5\u0BB7\u0BB9\u0C05\u0C0C" +
  56. "\u0C0E\u0C10\u0C12\u0C28\u0C2A\u0C33\u0C35\u0C39" +
  57. "\u0C60\u0C61\u0C85\u0C8C\u0C8E\u0C90\u0C92\u0CA8" +
  58. "\u0CAA\u0CB3\u0CB5\u0CB9\u0CDE\u0CDE\u0CE0\u0CE1" +
  59. "\u0D05\u0D0C\u0D0E\u0D10\u0D12\u0D28\u0D2A\u0D39" +
  60. "\u0D60\u0D61\u0E01\u0E2E\u0E30\u0E30\u0E32\u0E33" +
  61. "\u0E40\u0E45\u0E81\u0E82\u0E84\u0E84\u0E87\u0E88" +
  62. "\u0E8A\u0E8A\u0E8D\u0E8D\u0E94\u0E97\u0E99\u0E9F" +
  63. "\u0EA1\u0EA3\u0EA5\u0EA5\u0EA7\u0EA7\u0EAA\u0EAB" +
  64. "\u0EAD\u0EAE\u0EB0\u0EB0\u0EB2\u0EB3\u0EBD\u0EBD" +
  65. "\u0EC0\u0EC4\u0F40\u0F47\u0F49\u0F69\u10A0\u10C5" +
  66. "\u10D0\u10F6\u1100\u1100\u1102\u1103\u1105\u1107" +
  67. "\u1109\u1109\u110B\u110C\u110E\u1112\u113C\u113C" +
  68. "\u113E\u113E\u1140\u1140\u114C\u114C\u114E\u114E" +
  69. "\u1150\u1150\u1154\u1155\u1159\u1159\u115F\u1161" +
  70. "\u1163\u1163\u1165\u1165\u1167\u1167\u1169\u1169" +
  71. "\u116D\u116E\u1172\u1173\u1175\u1175\u119E\u119E" +
  72. "\u11A8\u11A8\u11AB\u11AB\u11AE\u11AF\u11B7\u11B8" +
  73. "\u11BA\u11BA\u11BC\u11C2\u11EB\u11EB\u11F0\u11F0" +
  74. "\u11F9\u11F9\u1E00\u1E9B\u1EA0\u1EF9\u1F00\u1F15" +
  75. "\u1F18\u1F1D\u1F20\u1F45\u1F48\u1F4D\u1F50\u1F57" +
  76. "\u1F59\u1F59\u1F5B\u1F5B\u1F5D\u1F5D\u1F5F\u1F7D" +
  77. "\u1F80\u1FB4\u1FB6\u1FBC\u1FBE\u1FBE\u1FC2\u1FC4" +
  78. "\u1FC6\u1FCC\u1FD0\u1FD3\u1FD6\u1FDB\u1FE0\u1FEC" +
  79. "\u1FF2\u1FF4\u1FF6\u1FFC\u2126\u2126\u212A\u212B" +
  80. "\u212E\u212E\u2180\u2182\u3041\u3094\u30A1\u30FA" +
  81. "\u3105\u312C\uAC00\uD7A3";
  82. // IdeogramicChars
  83. // Taken from: "XML 1.0 (Second Edition)" (http://www.w3.org/TR/REC-xml) Appendix B
  84. // [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]
  85. const string IdeogramicChars =
  86. "\u4E00\u9FA5\u3007\u3007\u3021\u3029";
  87. // CombiningChars
  88. // Taken from: "XML 1.0 (Second Edition)" (http://www.w3.org/TR/REC-xml) Appendix B
  89. // [#x0300-#x0345] | [#x0360-#x0361] | [#x0483-#x0486] | [#x0591-#x05A1] | [#x05A3-#x05B9] | [#x05BB-#x05BD] | #x05BF | [#x05C1-#x05C2] | #x05C4 | [#x064B-#x0652] | #x0670 | [#x06D6-#x06DC] | [#x06DD-#x06DF] | [#x06E0-#x06E4] | [#x06E7-#x06E8] | [#x06EA-#x06ED] | [#x0901-#x0903] | #x093C | [#x093E-#x094C] | #x094D | [#x0951-#x0954] | [#x0962-#x0963] | [#x0981-#x0983] | #x09BC | #x09BE | #x09BF | [#x09C0-#x09C4] | [#x09C7-#x09C8] | [#x09CB-#x09CD] | #x09D7 | [#x09E2-#x09E3] | #x0A02 | #x0A3C | #x0A3E | #x0A3F | [#x0A40-#x0A42] | [#x0A47-#x0A48] | [#x0A4B-#x0A4D] | [#x0A70-#x0A71] | [#x0A81-#x0A83] | #x0ABC | [#x0ABE-#x0AC5] | [#x0AC7-#x0AC9] | [#x0ACB-#x0ACD] | [#x0B01-#x0B03] | #x0B3C | [#x0B3E-#x0B43] | [#x0B47-#x0B48] | [#x0B4B-#x0B4D] | [#x0B56-#x0B57] | [#x0B82-#x0B83] | [#x0BBE-#x0BC2] | [#x0BC6-#x0BC8] | [#x0BCA-#x0BCD] | #x0BD7 | [#x0C01-#x0C03] | [#x0C3E-#x0C44] | [#x0C46-#x0C48] | [#x0C4A-#x0C4D] | [#x0C55-#x0C56] | [#x0C82-#x0C83] | [#x0CBE-#x0CC4] | [#x0CC6-#x0CC8] | [#x0CCA-#x0CCD] | [#x0CD5-#x0CD6] | [#x0D02-#x0D03] | [#x0D3E-#x0D43] | [#x0D46-#x0D48] | [#x0D4A-#x0D4D] | #x0D57 | #x0E31 | [#x0E34-#x0E3A] | [#x0E47-#x0E4E] | #x0EB1 | [#x0EB4-#x0EB9] | [#x0EBB-#x0EBC] | [#x0EC8-#x0ECD] | [#x0F18-#x0F19] | #x0F35 | #x0F37 | #x0F39 | #x0F3E | #x0F3F | [#x0F71-#x0F84] | [#x0F86-#x0F8B] | [#x0F90-#x0F95] | #x0F97 | [#x0F99-#x0FAD] | [#x0FB1-#x0FB7] | #x0FB9 | [#x20D0-#x20DC] | #x20E1 | [#x302A-#x302F] | #x3099 | #x309A
  90. const string CombiningChars =
  91. "\u0300\u0345\u0360\u0361\u0483\u0486\u0591\u05A1" +
  92. "\u05A3\u05B9\u05BB\u05BD\u05BF\u05BF\u05C1\u05C2" +
  93. "\u05C4\u05C4\u064B\u0652\u0670\u0670\u06D6\u06DC" +
  94. "\u06DD\u06DF\u06E0\u06E4\u06E7\u06E8\u06EA\u06ED" +
  95. "\u0901\u0903\u093C\u093C\u093E\u094C\u094D\u094D" +
  96. "\u0951\u0954\u0962\u0963\u0981\u0983\u09BC\u09BC" +
  97. "\u09BE\u09BE\u09BF\u09BF\u09C0\u09C4\u09C7\u09C8" +
  98. "\u09CB\u09CD\u09D7\u09D7\u09E2\u09E3\u0A02\u0A02" +
  99. "\u0A3C\u0A3C\u0A3E\u0A3E\u0A3F\u0A3F\u0A40\u0A42" +
  100. "\u0A47\u0A48\u0A4B\u0A4D\u0A70\u0A71\u0A81\u0A83" +
  101. "\u0ABC\u0ABC\u0ABE\u0AC5\u0AC7\u0AC9\u0ACB\u0ACD" +
  102. "\u0B01\u0B03\u0B3C\u0B3C\u0B3E\u0B43\u0B47\u0B48" +
  103. "\u0B4B\u0B4D\u0B56\u0B57\u0B82\u0B83\u0BBE\u0BC2" +
  104. "\u0BC6\u0BC8\u0BCA\u0BCD\u0BD7\u0BD7\u0C01\u0C03" +
  105. "\u0C3E\u0C44\u0C46\u0C48\u0C4A\u0C4D\u0C55\u0C56" +
  106. "\u0C82\u0C83\u0CBE\u0CC4\u0CC6\u0CC8\u0CCA\u0CCD" +
  107. "\u0CD5\u0CD6\u0D02\u0D03\u0D3E\u0D43\u0D46\u0D48" +
  108. "\u0D4A\u0D4D\u0D57\u0D57\u0E31\u0E31\u0E34\u0E3A" +
  109. "\u0E47\u0E4E\u0EB1\u0EB1\u0EB4\u0EB9\u0EBB\u0EBC" +
  110. "\u0EC8\u0ECD\u0F18\u0F19\u0F35\u0F35\u0F37\u0F37" +
  111. "\u0F39\u0F39\u0F3E\u0F3E\u0F3F\u0F3F\u0F71\u0F84" +
  112. "\u0F86\u0F8B\u0F90\u0F95\u0F97\u0F97\u0F99\u0FAD" +
  113. "\u0FB1\u0FB7\u0FB9\u0FB9\u20D0\u20DC\u20E1\u20E1" +
  114. "\u302A\u302F\u3099\u3099\u309A\u309A";
  115. // DigitChars
  116. // Taken from: "XML 1.0 (Second Edition)" (http://www.w3.org/TR/REC-xml) Appendix B
  117. // [#x0030-#x0039] | [#x0660-#x0669] | [#x06F0-#x06F9] | [#x0966-#x096F] | [#x09E6-#x09EF] | [#x0A66-#x0A6F] | [#x0AE6-#x0AEF] | [#x0B66-#x0B6F] | [#x0BE7-#x0BEF] | [#x0C66-#x0C6F] | [#x0CE6-#x0CEF] | [#x0D66-#x0D6F] | [#x0E50-#x0E59] | [#x0ED0-#x0ED9] | [#x0F20-#x0F29]
  118. const string DigitChars =
  119. "\u0030\u0039\u0660\u0669\u06F0\u06F9\u0966\u096F" +
  120. "\u09E6\u09EF\u0A66\u0A6F\u0AE6\u0AEF\u0B66\u0B6F" +
  121. "\u0BE7\u0BEF\u0C66\u0C6F\u0CE6\u0CEF\u0D66\u0D6F" +
  122. "\u0E50\u0E59\u0ED0\u0ED9\u0F20\u0F29";
  123. // ExtenderChars
  124. // Taken from: "XML 1.0 (Second Edition)" (http://www.w3.org/TR/REC-xml) Appendix B
  125. // #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] | [#x309D-#x309E] | [#x30FC-#x30FE]
  126. const string ExtenderChars =
  127. "\u00B7\u00B7\u02D0\u02D0\u02D1\u02D1\u0387\u0387" +
  128. "\u0640\u0640\u0E46\u0E46\u0EC6\u0EC6\u3005\u3005" +
  129. "\u3031\u3035\u309D\u309E\u30FC\u30FE";
  130. // WhitespaceChars
  131. // Taken from: "XML 1.0 (Second Edition)" (http://www.w3.org/TR/REC-xml) Section 2.3
  132. // #x0020 | #x0009 | #x000D | #x000A
  133. const string WhitespaceChars =
  134. "\u0020\u0020\u0009\u0009\u000D\u000D\u000A\u000A";
  135. // Other NCName start chars
  136. // Taken from: "Namespaces in XML" (http://www.w3.org/TR/REC-xml-names/) Section 2
  137. const string OtherNCNameStartChars =
  138. "__";
  139. // Other NCName chars
  140. // Taken from: "Namespaces in XML" (http://www.w3.org/TR/REC-xml-names/) Section 2
  141. const string OtherNCNameChars =
  142. "..--__";
  143. #endregion
  144. // Static Constructor
  145. // Initializes the table of unicode -> type mappings
  146. static XPathCharTypes()
  147. {
  148. if (charProperties != null)
  149. {
  150. return;
  151. }
  152. charProperties = new byte[char.MaxValue];
  153. // PERF: precompute the classes of each character set so SetProperties only needs to be run once per set.
  154. // Letter = BaseChar + Ideogramic
  155. SetProperties(BaseChars, Letter);
  156. SetProperties(IdeogramicChars, Letter);
  157. // Combining
  158. SetProperties(CombiningChars, Combining);
  159. // Digit
  160. SetProperties(DigitChars, Digit);
  161. // Extender
  162. SetProperties(ExtenderChars, Extender);
  163. // Whitespace
  164. SetProperties(WhitespaceChars, Whitespace);
  165. // NCNameStart = Base + Ideogramic + Other
  166. SetProperties(BaseChars, NCNameStart);
  167. SetProperties(IdeogramicChars, NCNameStart);
  168. SetProperties(OtherNCNameStartChars, NCNameStart);
  169. // NCName = NCNameStart + Combining + Extender
  170. SetProperties(BaseChars, NCName);
  171. SetProperties(IdeogramicChars, NCName);
  172. SetProperties(DigitChars, NCName);
  173. SetProperties(CombiningChars, NCName);
  174. SetProperties(ExtenderChars, NCName);
  175. SetProperties(OtherNCNameChars, NCName);
  176. }
  177. // Identify all described characters as belonging to a particular type
  178. private static void SetProperties(string ranges, byte value)
  179. {
  180. // Iterate over all characters in the table
  181. for (int p = 0; p < ranges.Length; p += 2)
  182. {
  183. // Iterate over all characters in a range
  184. for (int i = ranges[p], last = ranges[p + 1]; i <= last; i++)
  185. {
  186. // Add the code to the character
  187. charProperties[i] |= value;
  188. }
  189. }
  190. }
  191. // Get a character's code
  192. // This is done as a separate function for clarity and flexability
  193. // The compiler should just inline it
  194. private static byte GetCode(char c)
  195. {
  196. return charProperties[c];
  197. }
  198. #region Classifying functions
  199. // These are functions that simply test whether a character is of a particular type
  200. #if NO
  201. internal static bool IsLetter(char c)
  202. {
  203. return ((GetCode(c) & Letter) != 0);
  204. }
  205. internal static bool IsCombining(char c)
  206. {
  207. return ((GetCode(c) & Combining) != 0);
  208. }
  209. #endif
  210. internal static bool IsDigit(char c)
  211. {
  212. return ((GetCode(c) & Digit) != 0);
  213. }
  214. #if NO
  215. internal static bool IsExtender(char c)
  216. {
  217. return ((GetCode(c) & Extender) != 0);
  218. }
  219. #endif
  220. internal static bool IsWhitespace(char c)
  221. {
  222. return ((GetCode(c) & Whitespace) != 0);
  223. }
  224. internal static bool IsNCName(char c)
  225. {
  226. return ((GetCode(c) & NCName) != 0);
  227. }
  228. internal static bool IsNCNameStart(char c)
  229. {
  230. return ((GetCode(c) & NCNameStart) != 0);
  231. }
  232. #endregion
  233. }
  234. internal enum XPathTokenID
  235. {
  236. Unknown = 0x00000000,
  237. Terminal = 0x10000000,
  238. NameTest = 0x20000000,
  239. NodeType = 0x40000000,
  240. Operator = 0x01000000,
  241. NamedOperator = 0x02000000,
  242. Function = 0x04000000,
  243. Axis = 0x08000000,
  244. Literal = 0x00100000,
  245. Number = 0x00200000,
  246. Variable = 0x00400000,
  247. TypeMask = 0x7f400000,
  248. // terminals
  249. LParen = 0x00000001 | XPathTokenID.Terminal,
  250. RParen = 0x00000002 | XPathTokenID.Terminal,
  251. LBracket = 0x00000003 | XPathTokenID.Terminal,
  252. RBracket = 0x00000004 | XPathTokenID.Terminal,
  253. Period = 0x00000005 | XPathTokenID.Terminal,
  254. DblPeriod = 0x00000006 | XPathTokenID.Terminal,
  255. AtSign = 0x00000007 | XPathTokenID.Terminal,
  256. Comma = 0x00000008 | XPathTokenID.Terminal,
  257. DblColon = 0x00000009 | XPathTokenID.Terminal,
  258. Whitespace = 0x0000000A | XPathTokenID.Terminal,
  259. // operators
  260. Eq = 0x0000000B | XPathTokenID.Operator,
  261. Neq = 0x0000000C | XPathTokenID.Operator,
  262. Gt = 0x0000000D | XPathTokenID.Operator,
  263. Gte = 0x0000000E | XPathTokenID.Operator,
  264. Lt = 0x0000000F | XPathTokenID.Operator,
  265. Lte = 0x00000010 | XPathTokenID.Operator,
  266. Plus = 0x00000012 | XPathTokenID.Operator,
  267. Minus = 0x00000013 | XPathTokenID.Operator,
  268. Slash = 0x00000014 | XPathTokenID.Operator,
  269. Multiply = 0x00000015 | XPathTokenID.Operator,
  270. Pipe = 0x00000016 | XPathTokenID.Operator,
  271. DblSlash = 0x00000017 | XPathTokenID.Operator,
  272. Mod = 0x00000018 | XPathTokenID.NamedOperator,
  273. And = 0x00000019 | XPathTokenID.NamedOperator,
  274. Or = 0x0000001A | XPathTokenID.NamedOperator,
  275. Div = 0x0000001B | XPathTokenID.NamedOperator,
  276. // Literals
  277. Integer = 0x0000001C | XPathTokenID.Number,
  278. Decimal = 0x0000001D | XPathTokenID.Number,
  279. String = 0x0000001E | XPathTokenID.Literal,
  280. //
  281. Comment = 0x0000001F | XPathTokenID.NodeType,
  282. Text = 0x00000020 | XPathTokenID.NodeType,
  283. Processing = 0x00000021 | XPathTokenID.NodeType,
  284. Node = 0x00000022 | XPathTokenID.NodeType,
  285. Wildcard = 0x00000023 | XPathTokenID.NameTest,
  286. NameWildcard = 0x00000024 | XPathTokenID.NameTest,
  287. //QName = 0x00000025 | XPathTokenID.NameTest,
  288. // Keywords
  289. Ancestor = 0x00000027 | XPathTokenID.Axis,
  290. AncestorOrSelf = 0x00000028 | XPathTokenID.Axis,
  291. Attribute = 0x00000029 | XPathTokenID.Axis,
  292. Child = 0x0000002A | XPathTokenID.Axis,
  293. Descendant = 0x0000002B | XPathTokenID.Axis,
  294. DescendantOrSelf = 0x0000002C | XPathTokenID.Axis,
  295. Following = 0x0000002D | XPathTokenID.Axis,
  296. FollowingSibling = 0x0000002E | XPathTokenID.Axis,
  297. Namespace = 0x0000002F | XPathTokenID.Axis,
  298. Parent = 0x00000030 | XPathTokenID.Axis,
  299. Preceding = 0x00000031 | XPathTokenID.Axis,
  300. PrecedingSibling = 0x00000032 | XPathTokenID.Axis,
  301. Self = 0x00000033 | XPathTokenID.Axis
  302. }
  303. // Represents a single token of an XPath expression
  304. internal class XPathToken
  305. {
  306. string name;
  307. double number;
  308. string prefix;
  309. XPathTokenID tokenID;
  310. internal XPathToken()
  311. {
  312. this.tokenID = XPathTokenID.Unknown;
  313. }
  314. internal string Name
  315. {
  316. get
  317. {
  318. return this.name;
  319. }
  320. }
  321. internal double Number
  322. {
  323. get
  324. {
  325. return this.number;
  326. }
  327. }
  328. internal string Prefix
  329. {
  330. get
  331. {
  332. return this.prefix;
  333. }
  334. }
  335. internal XPathTokenID TokenID
  336. {
  337. get
  338. {
  339. return this.tokenID;
  340. }
  341. }
  342. internal void Clear()
  343. {
  344. this.number = double.NaN;
  345. this.prefix = string.Empty;
  346. this.name = string.Empty;
  347. this.tokenID = XPathTokenID.Unknown;
  348. }
  349. internal void Set(XPathTokenID id)
  350. {
  351. this.Clear();
  352. this.tokenID = id;
  353. }
  354. internal void Set(XPathTokenID id, double number)
  355. {
  356. this.Set(id);
  357. this.number = number;
  358. }
  359. internal void Set(XPathTokenID id, string name)
  360. {
  361. Fx.Assert(null != name, "");
  362. this.Clear();
  363. this.tokenID = id;
  364. this.name = name;
  365. }
  366. internal void Set(XPathTokenID id, XPathParser.QName qname)
  367. {
  368. this.Set(id, qname.Name);
  369. this.prefix = qname.Prefix;
  370. }
  371. }
  372. internal class XPathLexer
  373. {
  374. static Hashtable namedTypes; // Mapping from named types to token IDs
  375. XPathTokenID previousID;
  376. string xpath;
  377. int tokenStart;
  378. int currChar;
  379. int xpathLength;
  380. char ch;
  381. XPathToken token;
  382. bool resolveKeywords;
  383. // Static Constructor
  384. // Set up the mapping of named types
  385. static XPathLexer()
  386. {
  387. namedTypes = new Hashtable();
  388. // Named operators
  389. namedTypes.Add("and", XPathTokenID.And);
  390. namedTypes.Add("or", XPathTokenID.Or);
  391. namedTypes.Add("mod", XPathTokenID.Mod);
  392. namedTypes.Add("div", XPathTokenID.Div);
  393. // Axes
  394. namedTypes.Add("ancestor", XPathTokenID.Ancestor);
  395. namedTypes.Add("ancestor-or-self", XPathTokenID.AncestorOrSelf);
  396. namedTypes.Add("attribute", XPathTokenID.Attribute);
  397. namedTypes.Add("child", XPathTokenID.Child);
  398. namedTypes.Add("descendant", XPathTokenID.Descendant);
  399. namedTypes.Add("descendant-or-self", XPathTokenID.DescendantOrSelf);
  400. namedTypes.Add("following", XPathTokenID.Following);
  401. namedTypes.Add("following-sibling", XPathTokenID.FollowingSibling);
  402. namedTypes.Add("namespace", XPathTokenID.Namespace);
  403. namedTypes.Add("parent", XPathTokenID.Parent);
  404. namedTypes.Add("preceding", XPathTokenID.Preceding);
  405. namedTypes.Add("preceding-sibling", XPathTokenID.PrecedingSibling);
  406. namedTypes.Add("self", XPathTokenID.Self);
  407. // Node types
  408. namedTypes.Add("comment", XPathTokenID.Comment);
  409. namedTypes.Add("text", XPathTokenID.Text);
  410. namedTypes.Add("processing-instruction", XPathTokenID.Processing);
  411. namedTypes.Add("node", XPathTokenID.Node);
  412. }
  413. internal XPathLexer(string xpath)
  414. : this(xpath, true)
  415. {
  416. }
  417. internal XPathLexer(string xpath, bool resolveKeywords)
  418. {
  419. this.resolveKeywords = resolveKeywords;
  420. // Hold on to a copy of the string so it can't be changed out from under us
  421. this.xpath = string.Copy(xpath);
  422. this.xpathLength = this.xpath.Length;
  423. // Start at the beginning
  424. this.tokenStart = 0;
  425. this.currChar = 0;
  426. this.ch = char.MinValue;
  427. this.previousID = XPathTokenID.Unknown;
  428. // We will not create new tokens, we will simply change the old one.
  429. // This will be the only XPathToken instance created by the lexer
  430. // The 'next token' data can be more quickly communicated to the parser if they both hold a reference to the data.
  431. this.token = new XPathToken();
  432. // Strip leading whitespace
  433. ConsumeWhitespace();
  434. }
  435. internal int FirstTokenChar
  436. {
  437. get
  438. {
  439. return this.tokenStart;
  440. }
  441. }
  442. internal XPathToken Token
  443. {
  444. get
  445. {
  446. // Return the lexer's token instance.
  447. return this.token;
  448. }
  449. }
  450. // Try to advance to the next character in the xpath string
  451. private bool AdvanceChar()
  452. {
  453. if (this.currChar < this.xpathLength)
  454. {
  455. // Advance to the next character
  456. this.ch = this.xpath[this.currChar];
  457. this.currChar++;
  458. return true;
  459. }
  460. else if (this.currChar == this.xpathLength)
  461. {
  462. // Signal that we're at the end of the string
  463. this.currChar++;
  464. this.ch = char.MinValue;
  465. }
  466. return false;
  467. }
  468. // Advance the 'start of token' marker to the current location in the string
  469. private void ConsumeToken()
  470. {
  471. this.tokenStart = this.currChar;
  472. }
  473. // Query for the portion of the xpath expression already consumed.
  474. internal string ConsumedSubstring()
  475. {
  476. return this.xpath.Substring(0, this.tokenStart);
  477. }
  478. // Query for the portion of the xpath expression currently being consumed as a token.
  479. private string CurrentSubstring()
  480. {
  481. return this.xpath.Substring(this.tokenStart, this.currChar - this.tokenStart);
  482. }
  483. private char PeekChar()
  484. {
  485. return PeekChar(1);
  486. }
  487. private char PeekChar(int offset)
  488. {
  489. int peekChar = this.currChar + offset - 1;
  490. if (peekChar < this.xpathLength)
  491. {
  492. return this.xpath[peekChar];
  493. }
  494. return char.MinValue;
  495. }
  496. private void PutbackChar()
  497. {
  498. if (this.currChar > this.tokenStart)
  499. {
  500. --this.currChar;
  501. }
  502. }
  503. // Move to the next token
  504. // This updates the values in the token instance and returns true if successful.
  505. internal bool MoveNext()
  506. {
  507. // Hold onto the ID of the last token.
  508. // It will be needed by some of the special cases.
  509. this.previousID = this.token.TokenID;
  510. // If there are no more characters, we can't get another token.
  511. if (!AdvanceChar())
  512. {
  513. return false;
  514. }
  515. if (XPathCharTypes.IsNCNameStart(this.ch))
  516. {
  517. // Extract a QName if we've got the start of an NCName
  518. TokenizeQName();
  519. }
  520. else if (XPathCharTypes.IsDigit(this.ch))
  521. {
  522. // Extract a number
  523. TokenizeNumber();
  524. }
  525. else
  526. {
  527. // Everything else is a single/double character token, or a variable.
  528. switch (this.ch)
  529. {
  530. case '(':
  531. token.Set(XPathTokenID.LParen);
  532. break;
  533. case ')':
  534. token.Set(XPathTokenID.RParen);
  535. break;
  536. case '[':
  537. token.Set(XPathTokenID.LBracket);
  538. break;
  539. case ']':
  540. token.Set(XPathTokenID.RBracket);
  541. break;
  542. case '.':
  543. // Watch for a double period
  544. if (PeekChar() == '.')
  545. {
  546. AdvanceChar();
  547. token.Set(XPathTokenID.DblPeriod);
  548. }
  549. else
  550. {
  551. // Check if the period is the start of a number
  552. if (XPathCharTypes.IsDigit(PeekChar()))
  553. {
  554. TokenizeNumber();
  555. }
  556. else
  557. {
  558. token.Set(XPathTokenID.Period);
  559. }
  560. }
  561. break;
  562. case '@':
  563. token.Set(XPathTokenID.AtSign);
  564. break;
  565. case ',':
  566. token.Set(XPathTokenID.Comma);
  567. break;
  568. case ':':
  569. // Only a double colon is permitted.
  570. // The single colon part of the QName is consumed in TokenizeQName if it is valid
  571. if (PeekChar() == ':')
  572. {
  573. AdvanceChar();
  574. token.Set(XPathTokenID.DblColon);
  575. }
  576. else
  577. {
  578. ThrowError(QueryCompileError.UnexpectedToken, CurrentSubstring());
  579. }
  580. break;
  581. case '/':
  582. // Check for a double slash
  583. if (PeekChar() == '/')
  584. {
  585. AdvanceChar();
  586. token.Set(XPathTokenID.DblSlash);
  587. }
  588. else
  589. {
  590. token.Set(XPathTokenID.Slash);
  591. }
  592. break;
  593. case '|':
  594. token.Set(XPathTokenID.Pipe);
  595. break;
  596. case '+':
  597. token.Set(XPathTokenID.Plus);
  598. break;
  599. case '-':
  600. token.Set(XPathTokenID.Minus);
  601. break;
  602. case '=':
  603. token.Set(XPathTokenID.Eq);
  604. break;
  605. case '!':
  606. // This can only be the start of a '!='
  607. // 'not' is a negation in XPath
  608. if (PeekChar() == '=')
  609. {
  610. AdvanceChar();
  611. token.Set(XPathTokenID.Neq);
  612. }
  613. else
  614. {
  615. ThrowError(QueryCompileError.UnsupportedOperator, CurrentSubstring());
  616. }
  617. break;
  618. case '<':
  619. // Watch for '<='
  620. if (PeekChar() == '=')
  621. {
  622. AdvanceChar();
  623. token.Set(XPathTokenID.Lte);
  624. }
  625. else
  626. {
  627. token.Set(XPathTokenID.Lt);
  628. }
  629. break;
  630. case '>':
  631. // Watch for '>='
  632. if (PeekChar() == '=')
  633. {
  634. AdvanceChar();
  635. token.Set(XPathTokenID.Gte);
  636. }
  637. else
  638. {
  639. token.Set(XPathTokenID.Gt);
  640. }
  641. break;
  642. case '*':
  643. // Check if we're supposed to parse a '*' as a multiply
  644. if (IsSpecialPrev())
  645. {
  646. token.Set(XPathTokenID.Multiply);
  647. }
  648. else
  649. {
  650. token.Set(XPathTokenID.Wildcard, new XPathParser.QName(string.Empty, QueryDataModel.Wildcard));
  651. }
  652. break;
  653. case '$':
  654. // Make sure '$' was followed by something that counts as a variable name
  655. XPathParser.QName qname = GetQName();
  656. if (qname.Prefix.Length == 0 && qname.Name.Length == 0)
  657. {
  658. AdvanceChar();
  659. ThrowError(QueryCompileError.InvalidVariable, this.ch == char.MinValue ? string.Empty : CurrentSubstring());
  660. }
  661. token.Set(XPathTokenID.Variable, qname);
  662. break;
  663. case '\"':
  664. TokenizeLiteral('\"');
  665. break;
  666. case '\'':
  667. TokenizeLiteral('\'');
  668. break;
  669. default:
  670. // Unrecognized character
  671. token.Set(XPathTokenID.Unknown);
  672. break;
  673. }
  674. }
  675. // Whitespace can mark the end of a token, but is not part of the XPath syntax
  676. ConsumeWhitespace();
  677. return true;
  678. }
  679. private void ConsumeWhitespace()
  680. {
  681. // Advance over all whitespace characters and consume the all recently read characters
  682. for (; XPathCharTypes.IsWhitespace(PeekChar()); AdvanceChar());
  683. ConsumeToken();
  684. }
  685. private void TokenizeQName()
  686. {
  687. for (; XPathCharTypes.IsNCName(PeekChar()); AdvanceChar());
  688. string name1 = this.CurrentSubstring();
  689. XPathTokenID id = XPathTokenID.Unknown;
  690. XPathParser.QName qname = new XPathParser.QName("", "");
  691. if (PeekChar() == ':' && PeekChar(2) != ':')
  692. {
  693. AdvanceChar();
  694. ConsumeToken();
  695. AdvanceChar();
  696. if (XPathCharTypes.IsNCNameStart(this.ch))
  697. {
  698. // It's a full QName
  699. for (; XPathCharTypes.IsNCName(PeekChar()); AdvanceChar());
  700. id = XPathTokenID.NameTest;
  701. qname = new XPathParser.QName(name1, this.CurrentSubstring());
  702. }
  703. else if (this.ch == '*')
  704. {
  705. // We've got a wildcard
  706. id = XPathTokenID.NameWildcard;
  707. qname = new XPathParser.QName(name1, QueryDataModel.Wildcard);
  708. }
  709. else
  710. {
  711. ThrowError(QueryCompileError.InvalidNCName, this.ch == char.MinValue ? "" : CurrentSubstring());
  712. }
  713. }
  714. else
  715. {
  716. // It's a name test without a prefix
  717. id = XPathTokenID.NameTest;
  718. qname = new XPathParser.QName(string.Empty, name1);
  719. }
  720. // Handle special cases
  721. ConsumeWhitespace();
  722. if (IsSpecialPrev())
  723. {
  724. // If we're in the the first special case of the lexer, a qname MUST
  725. // be a NamedOperator
  726. token.Set(GetNamedOperator(qname));
  727. return;
  728. }
  729. else if (qname.Prefix.Length == 0)
  730. {
  731. if (this.PeekChar() == '(')
  732. {
  733. // An NCName followed by a '(' MUST be eiter a node type or function name
  734. id = GetNodeTypeOrFunction(qname);
  735. if (id != XPathTokenID.Function)
  736. {
  737. token.Set(id);
  738. }
  739. else
  740. {
  741. token.Set(id, qname);
  742. }
  743. }
  744. else if (this.PeekChar() == ':' && this.PeekChar(2) == ':')
  745. {
  746. // An NCName followed by a '::' MUST be an axis
  747. token.Set(GetAxisName(qname));
  748. }
  749. else
  750. {
  751. token.Set(id, qname);
  752. }
  753. }
  754. else
  755. {
  756. if (this.PeekChar() == '(')
  757. {
  758. id = XPathTokenID.Function;
  759. }
  760. token.Set(id, qname);
  761. }
  762. }
  763. private XPathParser.QName GetQName()
  764. {
  765. string name1 = GetNCName();
  766. // Return an empty QName if we can't read one
  767. if (name1 == null)
  768. {
  769. return new XPathParser.QName(string.Empty, string.Empty);
  770. }
  771. // Pull the '$' off a variable
  772. if (name1[0] == '$')
  773. {
  774. name1 = name1.Substring(1);
  775. }
  776. // See if there's a second part to the QName
  777. if (PeekChar() == ':' && XPathCharTypes.IsNCNameStart(PeekChar(2)))
  778. {
  779. AdvanceChar();
  780. ConsumeToken();
  781. return new XPathParser.QName(name1, GetNCName());
  782. }
  783. else
  784. {
  785. return new XPathParser.QName(string.Empty, name1);
  786. }
  787. }
  788. private string GetNCName()
  789. {
  790. // Make sure we're starting an NCName
  791. if (XPathCharTypes.IsNCNameStart(PeekChar()))
  792. {
  793. AdvanceChar();
  794. // Read all the NCName characters
  795. for (; XPathCharTypes.IsNCName(PeekChar()); AdvanceChar());
  796. // Extract, consume, and return the NCName
  797. string name = CurrentSubstring();
  798. ConsumeToken();
  799. return name;
  800. }
  801. else
  802. {
  803. return null;
  804. }
  805. }
  806. private void TokenizeNumber()
  807. {
  808. XPathTokenID id = XPathTokenID.Integer;
  809. // Read all the digits
  810. for (; XPathCharTypes.IsDigit(this.ch); AdvanceChar());
  811. if (this.ch == '.')
  812. {
  813. AdvanceChar();
  814. if (XPathCharTypes.IsDigit(this.ch))
  815. {
  816. id = XPathTokenID.Decimal;
  817. // Read all the digits after the decimal point
  818. for (; XPathCharTypes.IsDigit(this.ch); AdvanceChar());
  819. }
  820. }
  821. PutbackChar();
  822. // The converted double
  823. double d = QueryValueModel.Double(CurrentSubstring());
  824. // flip the sign if we're negative
  825. token.Set(id, d);
  826. }
  827. private void TokenizeLiteral(char c)
  828. {
  829. // Consume the opening quote
  830. ConsumeToken();
  831. // Advance over all characters that are not the closing quote
  832. AdvanceChar();
  833. while (this.ch != c)
  834. {
  835. // Watch for an unclosed literal
  836. if (this.ch == char.MinValue)
  837. {
  838. PutbackChar();
  839. ThrowError(QueryCompileError.InvalidLiteral, CurrentSubstring());
  840. }
  841. AdvanceChar();
  842. }
  843. // Put back the closing quote
  844. PutbackChar();
  845. // Grab the literal string
  846. token.Set(XPathTokenID.Literal, CurrentSubstring());
  847. // Read the closing quote
  848. AdvanceChar();
  849. }
  850. private bool IsSpecialPrev()
  851. {
  852. // The first lexer special case is when there was a previous token and it
  853. // wasn't '@', '::', '(', '[', ',', an operator, or a named operator
  854. return (this.previousID != XPathTokenID.Unknown) &&
  855. (this.previousID != XPathTokenID.AtSign) &&
  856. (this.previousID != XPathTokenID.DblColon) &&
  857. (this.previousID != XPathTokenID.LParen) &&
  858. (this.previousID != XPathTokenID.LBracket) &&
  859. (this.previousID != XPathTokenID.Comma) &&
  860. (this.previousID & XPathTokenID.Operator) == 0 &&
  861. (this.previousID & XPathTokenID.NamedOperator) == 0;
  862. }
  863. private XPathTokenID GetNamedOperator(XPathParser.QName qname)
  864. {
  865. // Named operators can't have prefixes
  866. if (qname.Prefix.Length != 0)
  867. {
  868. ThrowError(QueryCompileError.InvalidOperatorName, qname.Prefix + ":" + qname.Name);
  869. }
  870. // Make sure the type is 'NamedOperator'
  871. XPathTokenID id = GetNamedType(qname.Name);
  872. if (this.resolveKeywords && (id & XPathTokenID.NamedOperator) == 0)
  873. {
  874. ThrowError(QueryCompileError.UnsupportedOperator, this.previousID.ToString() + "->" + qname.Name);
  875. }
  876. return id;
  877. }
  878. private XPathTokenID GetAxisName(XPathParser.QName qname)
  879. {
  880. // Axes can't have prefixes
  881. if (qname.Prefix.Length != 0)
  882. {
  883. ThrowError(QueryCompileError.InvalidAxisSpecifier, qname.Prefix + ":" + qname.Name);
  884. }
  885. // Make sure the type is 'Axis'
  886. XPathTokenID id = GetNamedType(qname.Name);
  887. if (this.resolveKeywords && (id & XPathTokenID.Axis) == 0)
  888. {
  889. ThrowError(QueryCompileError.UnsupportedAxis, qname.Name);
  890. }
  891. return id;
  892. }
  893. private XPathTokenID GetNodeTypeOrFunction(XPathParser.QName qname)
  894. {
  895. XPathTokenID id = GetNamedType(qname.Name);
  896. // If it's not a node type, it's lexed as a function
  897. if ((id & XPathTokenID.NodeType) == 0)
  898. {
  899. id = XPathTokenID.Function;
  900. }
  901. else if (qname.Prefix.Length > 0)
  902. {
  903. // Node types don't have prefixes
  904. ThrowError(QueryCompileError.InvalidNodeType, qname.Prefix + ":" + qname.Name);
  905. }
  906. return id;
  907. }
  908. private XPathTokenID GetNamedType(string name)
  909. {
  910. // Get the named type if one exists
  911. if (this.resolveKeywords && namedTypes.ContainsKey(name))
  912. {
  913. return (XPathTokenID)namedTypes[name];
  914. }
  915. else
  916. {
  917. return XPathTokenID.Unknown;
  918. }
  919. }
  920. private void ThrowError(QueryCompileError err, string msg)
  921. {
  922. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(err, msg));
  923. }
  924. }
  925. }