internal void CompileForInternal(string xpath, XmlNamespaceManager names) { base.query = null; xpath = xpath.Trim(); if (xpath.Length == 0) { base.query = matchAlwaysFilter; this.flags |= XPathFilterFlags.AlwaysMatch; } else if ((1 == xpath.Length) && ('/' == xpath[0])) { base.query = rootFilter.First; this.flags |= XPathFilterFlags.AlwaysMatch; } else { ValueDataType type; OpcodeBlock block = QueryMatcher.CompileForInternalEngine(xpath, names, QueryCompilerFlags.None, out type); if (this.match) { block.Append(new MatchResultOpcode()); } else { block.Append(new QueryResultOpcode()); } base.query = block.First; } this.flags &= ~XPathFilterFlags.IsFxFilter; }
// Compiles expressions at nesting level == 1 -> boolean expressions that can be processed // with less complex opcodes because they will never track multiple sequences simultaneously void CompileBasicBoolean(XPathExpr expr, bool testValue) { // Boolean expressions must always have at least 2 sub expressions Fx.Assert(expr.SubExprCount > 1, ""); Fx.Assert(this.compiler.nestingLevel == 1, ""); OpcodeBlock boolBlock = new OpcodeBlock(); // struct Opcode blockEnd = new BlockEndOpcode(); XPathExprList subExprList = expr.SubExpr; // Compile sub-expressions for (int i = 0; i < subExprList.Count; ++i) { XPathExpr subExpr = subExprList[i]; boolBlock.Append(this.CompileBlock(subExpr)); // Make sure each sub-expression can produce a boolean result if (subExpr.ReturnType != ValueDataType.Boolean) { boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean)); } if (i < (subExprList.Count - 1)) { // No point jumping if this is the last expression boolBlock.Append(new JumpIfOpcode(blockEnd, testValue)); } } boolBlock.Append(blockEnd); this.codeBlock.Append(boolBlock); }
internal void Add(string expression, XmlNamespaceManager names, object item, bool forceExternal) { Fx.Assert(null != item, ""); // Compile the new filter bool compiled = false; OpcodeBlock codeBlock = new OpcodeBlock(); codeBlock.Append(new NoOpOpcode(OpcodeID.QueryTree)); if (!forceExternal) { try { ValueDataType returnType = ValueDataType.None; // Try to compile and merge the compiled query into the query tree codeBlock.Append(QueryMatcher.CompileForInternalEngine(expression, names, QueryCompilerFlags.InverseQuery, out returnType)); MultipleResultOpcode opcode; if (!this.match) { opcode = new QueryMultipleResultOpcode(); } else { opcode = new MatchMultipleResultOpcode(); } opcode.AddItem(item); codeBlock.Append(opcode); compiled = true; // Perform SubExpression Elimination codeBlock = new OpcodeBlock(this.elim.Add(item, codeBlock.First)); this.subExprVars = this.elim.VariableCount; } catch (QueryCompileException) { // If the filter couldn't be compiled, we drop down to the framework engine } } if (!compiled) { codeBlock.Append(QueryMatcher.CompileForExternalEngine(expression, names, item, this.match)); } // Merge the compiled query into the query tree QueryTreeBuilder builder = new QueryTreeBuilder(); this.query = builder.Build(this.query, codeBlock); // To de-merge this filter from the tree, we'll have to walk backwards up the tree... so we // have to remember the last opcode that is executed on behalf of this filter this.lastLookup[item] = builder.LastOpcode; }
private void CompileBoolean(XPathExpr expr, bool testValue) { if (this.compiler.nestingLevel == 1) { this.CompileBasicBoolean(expr, testValue); } else { OpcodeBlock block = new OpcodeBlock(); Opcode jump = new BlockEndOpcode(); block.Append(new PushBooleanOpcode(testValue)); XPathExprList subExpr = expr.SubExpr; XPathExpr expr2 = subExpr[0]; block.Append(this.CompileBlock(expr2)); if (expr2.ReturnType != ValueDataType.Boolean) { block.Append(new TypecastOpcode(ValueDataType.Boolean)); } block.Append(new ApplyBooleanOpcode(jump, testValue)); for (int i = 1; i < subExpr.Count; i++) { expr2 = subExpr[i]; block.Append(new StartBooleanOpcode(testValue)); block.Append(this.CompileBlock(expr2)); if (expr2.ReturnType != ValueDataType.Boolean) { block.Append(new TypecastOpcode(ValueDataType.Boolean)); } block.Append(new EndBooleanOpcode(jump, testValue)); } block.Append(jump); this.codeBlock.Append(block); } }
internal virtual OpcodeBlock Compile(XPathExpr expr) { this.nestingLevel = 1; this.pushInitialContext = false; OpcodeBlock block = new XPathExprCompiler(this).Compile(expr); if (this.pushInitialContext) { OpcodeBlock block2 = new OpcodeBlock(); block2.Append(new PushContextNodeOpcode()); block2.Append(block); block2.Append(new PopContextNodes()); return block2; } return block; }
internal virtual OpcodeBlock Compile(XPathExpr expr) { this.nestingLevel = 1; this.pushInitialContext = false; OpcodeBlock block = new XPathExprCompiler(this).Compile(expr); if (this.pushInitialContext) { OpcodeBlock block2 = new OpcodeBlock(); block2.Append(new PushContextNodeOpcode()); block2.Append(block); block2.Append(new PopContextNodes()); return(block2); } return(block); }
internal static OpcodeBlock CompileForInternalEngine(string xpath, XmlNamespaceManager nsManager, QueryCompilerFlags flags, IFunctionLibrary[] functionLibs, out ValueDataType returnType) { OpcodeBlock codeBlock; returnType = ValueDataType.None; if (0 == xpath.Length) { // 0 length XPaths always match codeBlock = new OpcodeBlock(); codeBlock.Append(new PushBooleanOpcode(true)); // Always match by pushing true on the eval stack } else { // Try to parse the xpath. Bind to default function libraries // The parser returns an expression tree XPathParser parser = new XPathParser(xpath, nsManager, functionLibs); XPathExpr parseTree = parser.Parse(); if (null == parseTree) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.CouldNotParseExpression)); } returnType = parseTree.ReturnType; // Compile the expression tree XPathCompiler compiler = new XPathCompiler(flags); codeBlock = compiler.Compile(parseTree); } return(codeBlock); }
static XPathQueryMatcher() { ValueDataType type; matchAlwaysFilter = new PushBooleanOpcode(true); rootFilter = QueryMatcher.CompileForInternalEngine("/", null, QueryCompilerFlags.None, out type); rootFilter.Append(new MatchResultOpcode()); }
// Compiles top level expressions internal virtual OpcodeBlock Compile(XPathExpr expr) { Fx.Assert(null != expr, ""); this.nestingLevel = 1; this.pushInitialContext = false; XPathExprCompiler exprCompiler = new XPathExprCompiler(this); OpcodeBlock mainBlock = exprCompiler.Compile(expr); if (this.pushInitialContext) { OpcodeBlock expandedBlock = new OpcodeBlock(); expandedBlock.Append(new PushContextNodeOpcode()); expandedBlock.Append(mainBlock); expandedBlock.Append(new PopContextNodes()); return expandedBlock; } return mainBlock; }
/// <summary> /// Compile the given filter to run on an external (fx) xpath engine /// </summary> internal static OpcodeBlock CompileForExternalEngine(string expression, XmlNamespaceManager namespaces, object item, bool match) { // Compile... XPathExpression xpathExpr = QueryMatcher.fxCompiler.Compile(expression); // Fx will bind prefixes and functions here. if (namespaces != null) { // There's a bug in System.Xml.XPath. If we pass an XsltContext to SetContext it won't throw if there's // an undefined prefix. if (namespaces is XsltContext) { // Lex the xpath to find all prefixes used XPathLexer lexer = new XPathLexer(expression, false); while (lexer.MoveNext()) { string prefix = lexer.Token.Prefix; if (prefix.Length > 0 && namespaces.LookupNamespace(prefix) == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XsltException(SR.GetString(SR.FilterUndefinedPrefix, prefix))); } } } xpathExpr.SetContext(namespaces); } // // FORCE the function to COMPILE - they won't bind namespaces unless we check the return type // if (XPathResultType.Error == xpathExpr.ReturnType) { // This should never be reached. The above property should throw if there's an error throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XPathException(SR.GetString(SR.FilterCouldNotCompile, expression))); } OpcodeBlock codeBlock = new OpcodeBlock(); SingleFxEngineResultOpcode op; if (!match) { op = new QuerySingleFxEngineResultOpcode(); } else { op = new MatchSingleFxEngineResultOpcode(); } op.XPath = xpathExpr; op.Item = item; codeBlock.Append(op); return(codeBlock); }
// Compiles top level expressions internal virtual OpcodeBlock Compile(XPathExpr expr) { Fx.Assert(null != expr, ""); this.nestingLevel = 1; this.pushInitialContext = false; XPathExprCompiler exprCompiler = new XPathExprCompiler(this); OpcodeBlock mainBlock = exprCompiler.Compile(expr); if (this.pushInitialContext) { OpcodeBlock expandedBlock = new OpcodeBlock(); expandedBlock.Append(new PushContextNodeOpcode()); expandedBlock.Append(mainBlock); expandedBlock.Append(new PopContextNodes()); return(expandedBlock); } return(mainBlock); }
internal void Add(string expression, XmlNamespaceManager names, object item, bool forceExternal) { bool flag = false; OpcodeBlock newBlock = new OpcodeBlock(); newBlock.Append(new NoOpOpcode(OpcodeID.QueryTree)); if (!forceExternal) { try { MultipleResultOpcode opcode; ValueDataType none = ValueDataType.None; newBlock.Append(QueryMatcher.CompileForInternalEngine(expression, names, QueryCompilerFlags.InverseQuery, out none)); if (!this.match) { opcode = new QueryMultipleResultOpcode(); } else { opcode = new MatchMultipleResultOpcode(); } opcode.AddItem(item); newBlock.Append(opcode); flag = true; newBlock = new OpcodeBlock(this.elim.Add(item, newBlock.First)); base.subExprVars = this.elim.VariableCount; } catch (QueryCompileException) { } } if (!flag) { newBlock.Append(QueryMatcher.CompileForExternalEngine(expression, names, item, this.match)); } QueryTreeBuilder builder = new QueryTreeBuilder(); base.query = builder.Build(base.query, newBlock); this.lastLookup[item] = builder.LastOpcode; }
private void CompileBasicBoolean(XPathExpr expr, bool testValue) { OpcodeBlock block = new OpcodeBlock(); Opcode jump = new BlockEndOpcode(); XPathExprList subExpr = expr.SubExpr; for (int i = 0; i < subExpr.Count; i++) { XPathExpr expr2 = subExpr[i]; block.Append(this.CompileBlock(expr2)); if (expr2.ReturnType != ValueDataType.Boolean) { block.Append(new TypecastOpcode(ValueDataType.Boolean)); } if (i < (subExpr.Count - 1)) { block.Append(new JumpIfOpcode(jump, testValue)); } } block.Append(jump); this.codeBlock.Append(block); }
void CompileBoolean(XPathExpr expr, bool testValue) { // Boolean expressions must always have at least 2 sub expressions Fx.Assert(expr.SubExprCount > 1, ""); if (this.compiler.nestingLevel == 1) { this.CompileBasicBoolean(expr, testValue); return; } OpcodeBlock boolBlock = new OpcodeBlock(); // struct Opcode blockEnd = new BlockEndOpcode(); // Set up the result mask boolBlock.Append(new PushBooleanOpcode(testValue)); XPathExprList subExprList = expr.SubExpr; XPathExpr subExpr; // the first expression needs the least work.. subExpr = subExprList[0]; boolBlock.Append(this.CompileBlock(subExpr)); if (subExpr.ReturnType != ValueDataType.Boolean) { boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean)); } boolBlock.Append(new ApplyBooleanOpcode(blockEnd, testValue)); // Compile remaining sub-expressions for (int i = 1; i < subExprList.Count; ++i) { subExpr = subExprList[i]; boolBlock.Append(new StartBooleanOpcode(testValue)); boolBlock.Append(this.CompileBlock(subExpr)); // Make sure each sub-expression can produce a boolean result if (subExpr.ReturnType != ValueDataType.Boolean) { boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean)); } boolBlock.Append(new EndBooleanOpcode(blockEnd, testValue)); } boolBlock.Append(blockEnd); this.codeBlock.Append(boolBlock); }
/// <summary> /// Compile for the internal engine with default flags /// By defalt, we compile an xpath to run stand alone, with standard optimizations /// </summary> internal void CompileForInternal(string xpath, XmlNamespaceManager names) { this.query = null; xpath = xpath.Trim(); if (0 == xpath.Length) { // Empty xpaths always match. Same for xpaths that refer to the root only // We will evaluate such filters with minimal overhead. However, we // don't want a null value for this.query, so we stick a dummy value in there this.query = XPathQueryMatcher.matchAlwaysFilter; this.flags |= (XPathFilterFlags.AlwaysMatch); } else if (1 == xpath.Length && '/' == xpath[0]) { this.query = XPathQueryMatcher.rootFilter.First; this.flags |= (XPathFilterFlags.AlwaysMatch); } else { ValueDataType returnType; OpcodeBlock codeBlock = QueryMatcher.CompileForInternalEngine(xpath, names, QueryCompilerFlags.None, out returnType); // Inject a final opcode that will place the query result on the query context // This query is now ready for execution STAND ALONE if (this.match) { codeBlock.Append(new MatchResultOpcode()); } else { codeBlock.Append(new QueryResultOpcode()); } this.query = codeBlock.First; } this.flags &= ~XPathFilterFlags.IsFxFilter; }
internal static OpcodeBlock CompileForInternalEngine(string xpath, XmlNamespaceManager nsManager, QueryCompilerFlags flags, IFunctionLibrary[] functionLibs, out ValueDataType returnType) { returnType = ValueDataType.None; if (xpath.Length == 0) { OpcodeBlock block = new OpcodeBlock(); block.Append(new PushBooleanOpcode(true)); return(block); } XPathExpr expr = new XPathParser(xpath, nsManager, functionLibs).Parse(); if (expr == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.CouldNotParseExpression)); } returnType = expr.ReturnType; XPathCompiler compiler = new XPathCompiler(flags); return(compiler.Compile(expr)); }
internal static OpcodeBlock CompileForExternalEngine(string expression, XmlNamespaceManager namespaces, object item, bool match) { SingleFxEngineResultOpcode opcode; XPathExpression expression2 = fxCompiler.Compile(expression); if (namespaces != null) { if (namespaces is XsltContext) { XPathLexer lexer = new XPathLexer(expression, false); while (lexer.MoveNext()) { string prefix = lexer.Token.Prefix; if ((prefix.Length > 0) && (namespaces.LookupNamespace(prefix) == null)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XsltException(System.ServiceModel.SR.GetString("FilterUndefinedPrefix", new object[] { prefix }))); } } } expression2.SetContext(namespaces); } if (XPathResultType.Error == expression2.ReturnType) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XPathException(System.ServiceModel.SR.GetString("FilterCouldNotCompile", new object[] { expression }))); } OpcodeBlock block = new OpcodeBlock(); if (!match) { opcode = new QuerySingleFxEngineResultOpcode(); } else { opcode = new MatchSingleFxEngineResultOpcode(); } opcode.XPath = expression2; opcode.Item = item; block.Append(opcode); return(block); }