// 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(XPathScanner scanner, IXPathBuilder <Node> builder, LexKind endLex) { Debug.Assert(this.scanner == null && this.builder == null); Debug.Assert(scanner != null && builder != null); Node result = default(Node); this.scanner = scanner; this.builder = builder; this.posInfo.Clear(); try { builder.StartBuild(); result = ParseExpr(); scanner.CheckToken(endLex); } catch (XPathCompileException 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); }
internal static XPathAxis GetAxis(string axisName, XPathScanner scanner) { switch (axisName) { case "ancestor": return(XPathAxis.Ancestor); case "ancestor-or-self": return(XPathAxis.AncestorOrSelf); case "attribute": return(XPathAxis.Attribute); case "child": return(XPathAxis.Child); case "descendant": return(XPathAxis.Descendant); case "descendant-or-self": return(XPathAxis.DescendantOrSelf); case "following": return(XPathAxis.Following); case "following-sibling": return(XPathAxis.FollowingSibling); case "namespace": return(XPathAxis.Namespace); case "parent": return(XPathAxis.Parent); case "preceding": return(XPathAxis.Preceding); case "preceding-sibling": return(XPathAxis.PrecedingSibling); case "self": return(XPathAxis.Self); default: throw scanner.CreateException(Res.XPath_UnknownAxis, axisName); } }
private static bool IsNodeType(XPathScanner scanner) { return(scanner.Prefix.Length == 0 && ( scanner.Name == "node" || scanner.Name == "text" || scanner.Name == "processing-instruction" || scanner.Name == "comment" )); }
internal 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.CreateException(Res.XPath_NodeTestExpected, scanner.RawValue); } }
private QilNode CompileKeyUse(Key key) { string expr = key.Use; XPathScanner scanner; QilNode result; SetEnvironmentFlags(/*allowVariables:*/false, /*allowCurrent:*/true, /*allowKey:*/false); if (expr == null) { result = _f.Error(_f.String(XslLoadException.CreateMessage(key.SourceLine, SR.Xslt_MissingAttribute, "use"))); } else { try { scanner = new XPathScanner(expr); result = _xpathParser.Parse(scanner, _xpathBuilder, LexKind.Eof); } catch (XslLoadException e) { if (_xslVersion != XslVersion.ForwardsCompatible) { ReportErrorInXPath(/*[XT0300]*/e); } result = _f.Error(_f.String(e.Message)); } } if (result is QilIterator) { result = _f.Nop(result); } return result; }
private QilNode CompileKeyMatch(string pttrn) { XPathScanner scanner; QilNode result; if (_keyMatchBuilder == null) { _keyMatchBuilder = new KeyMatchBuilder((IXPathEnvironment)this); } SetEnvironmentFlags(/*allowVariables:*/false, /*allowCurrent:*/false, /*allowKey:*/false); if (pttrn == null) { result = PhantomKeyMatch(); } else { try { scanner = new XPathScanner(pttrn); result = _ptrnParser.Parse(scanner, _keyMatchBuilder); } catch (XslLoadException e) { if (_xslVersion != XslVersion.ForwardsCompatible) { ReportErrorInXPath(/*[XT0340]*/e); } result = _f.Error(_f.String(e.Message)); } } return result; }
private QilNode CompileNumberPattern(string pttrn) { Debug.Assert(pttrn != null); XPathScanner scanner; QilNode result; SetEnvironmentFlags(/*allowVariables:*/true, /*allowCurrent:*/false, /*allowKey:*/true); try { scanner = new XPathScanner(pttrn); result = _ptrnParser.Parse(scanner, _ptrnBuilder); } catch (XslLoadException e) { if (_xslVersion != XslVersion.ForwardsCompatible) { ReportErrorInXPath(/*[XT0340]*/e); } result = _f.Error(_f.String(e.Message)); } return result; }
private QilNode CompileXPathExpressionWithinAvt(string expr, ref int pos) { Debug.Assert(expr != null); XPathScanner scanner; QilNode result; int startPos = pos; SetEnvironmentFlags(/*allowVariables:*/true, /*allowCurrent:*/true, /*allowKey:*/true); try { scanner = new XPathScanner(expr, pos); result = _xpathParser.Parse(scanner, _xpathBuilder, LexKind.RBrace); pos = scanner.LexStart + 1; } catch (XslLoadException e) { if (_xslVersion != XslVersion.ForwardsCompatible) { ReportErrorInXPath(/*[XT0350][XT0360]*/e); } result = _f.Error(_f.String(e.Message)); pos = expr.Length; } if (result is QilIterator) { result = _f.Nop(result); } return result; }
// Calls to CompileXPathExpression() can't be nested in the XSLT. So we can reuse the same instance of xpathBuilder. // The only thing we need to do before its use is adjustment of IXPathEnvironment to have correct context tuple. private QilNode CompileXPathExpression(string expr) { XPathScanner scanner; QilNode result; SetEnvironmentFlags(/*allowVariables:*/true, /*allowCurrent:*/true, /*allowKey:*/true); if (expr == null) { result = PhantomXPathExpression(); } else { try { // Note that the constructor may throw an exception, for example, in case of the expression "'" scanner = new XPathScanner(expr); result = _xpathParser.Parse(scanner, _xpathBuilder, LexKind.Eof); } catch (XslLoadException e) { if (_xslVersion != XslVersion.ForwardsCompatible) { ReportErrorInXPath(/*[XT0300]*/e); } result = _f.Error(_f.String(e.Message)); } } if (result is QilIterator) { result = _f.Nop(result); } return result; }
private QilNode CompileKeyUse(string expr) { XPathScanner scanner; QilNode result; SetEnvironmentFlags(/*allowVariables:*/false, /*allowCurrent:*/true, /*allowKey:*/false); if (expr == null) { result = PhantomXPathExpression(); } else { try { scanner = new XPathScanner(expr); result = xpathParser.Parse(scanner, xpathBuilder, LexKind.Eof); } catch (XslLoadException e) { if (xslVersion != XslVersion.ForwardsCompatible) { ReportErrorInXPath(/*[XT0300]*/e); } result = f.Error(f.String(e.Message)); } } if (result is QilIterator) { result = f.Nop(result); } return result; }