// Six possible causes of exceptions in the builder: // 1. Undefined prefix in a node test. // 2. Undefined prefix in a variable reference, or unknown variable. // 3. Undefined prefix in a function call, or unknown function, or wrong number/types of arguments. // 4. Argument of Union operator is not a node-set. // 5. First argument of Predicate is not a node-set. // 6. Argument of Axis is not a node-set. public Node Parse(string xpathExpr, IXPathBuilder <Node> builder) { Debug.Assert(this.scanner == null && this.builder == null); Debug.Assert(builder != null); Node result = default(Node); this.scanner = new XPathScanner(xpathExpr); this.builder = builder; this.posInfo.Clear(); try { builder.StartBuild(); result = ParseExpr(); scanner.CheckToken(LexKind.Eof); } catch (XPathParserException e) { if (e.queryString == null) { e.queryString = scanner.Source; PopPosInfo(out e.startChar, out e.endChar); } throw; } finally { result = builder.EndBuild(result); #if DEBUG this.builder = null; this.scanner = null; #endif } Debug.Assert(posInfo.Count == 0, "PushPosInfo() and PopPosInfo() calls have been unbalanced"); return(result); }
/* * PrimaryExpr ::= Literal | Number | VariableReference | '(' Expr ')' | FunctionCall */ private Node ParsePrimaryExpr() { Debug.Assert(IsPrimaryExpr()); Node opnd; switch (scanner.Kind) { case LexKind.String: opnd = builder.String(scanner.StringValue); scanner.NextLex(); break; case LexKind.Number: opnd = builder.Number(scanner.RawValue); scanner.NextLex(); break; case LexKind.Dollar: int startChar = scanner.LexStart; scanner.NextLex(); scanner.CheckToken(LexKind.Name); PushPosInfo(startChar, scanner.LexStart + scanner.LexSize); opnd = builder.Variable(scanner.Prefix, scanner.Name); PopPosInfo(); scanner.NextLex(); break; case LexKind.LParens: scanner.NextLex(); opnd = ParseExpr(); scanner.PassToken(LexKind.RParens); break; default: Debug.Assert( scanner.Kind == LexKind.Name && scanner.CanBeFunction && !IsNodeType(scanner), "IsPrimaryExpr() returned true, but the lexeme is not recognized" ); opnd = ParseFunctionCall(); break; } return(opnd); }
private static void InternalParseNodeTest(XPathScanner scanner, XPathAxis axis, out XPathNodeType nodeType, out string nodePrefix, out string nodeName) { switch (scanner.Kind) { case LexKind.Name: if (scanner.CanBeFunction && IsNodeType(scanner)) { nodePrefix = null; nodeName = null; switch (scanner.Name) { case "comment": nodeType = XPathNodeType.Comment; break; case "text": nodeType = XPathNodeType.Text; break; case "node": nodeType = XPathNodeType.All; break; default: Debug.Assert(scanner.Name == "processing-instruction"); nodeType = XPathNodeType.ProcessingInstruction; break; } scanner.NextLex(); scanner.PassToken(LexKind.LParens); if (nodeType == XPathNodeType.ProcessingInstruction) { if (scanner.Kind != LexKind.RParens) // 'processing-instruction' '(' Literal ')' { scanner.CheckToken(LexKind.String); // It is not needed to set nodePrefix here, but for our current implementation // comparing whole QNames is faster than comparing just local names nodePrefix = string.Empty; nodeName = scanner.StringValue; scanner.NextLex(); } } scanner.PassToken(LexKind.RParens); } else { nodePrefix = scanner.Prefix; nodeName = scanner.Name; nodeType = PrincipalNodeType(axis); scanner.NextLex(); if (nodeName == "*") { nodeName = null; } } break; case LexKind.Star: nodePrefix = null; nodeName = null; nodeType = PrincipalNodeType(axis); scanner.NextLex(); break; default: throw scanner.NodeTestExpectedException(scanner.RawValue); } }