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;
 }
示例#2
0
            // 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);
            }
示例#3
0
        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;
        }
示例#4
0
 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;
 }
示例#6
0
        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);
        }
示例#7
0
        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);
        }
 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);
     }
 }
 static XPathQueryMatcher()
 {
     ValueDataType type;
     matchAlwaysFilter = new PushBooleanOpcode(true);
     rootFilter = QueryMatcher.CompileForInternalEngine("/", null, QueryCompilerFlags.None, out type);
     rootFilter.Append(new MatchResultOpcode());
 }
        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;
        }
示例#12
0
        /// <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);
        }
示例#13
0
        // 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;
        }
示例#15
0
            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);
            }
示例#16
0
            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);
            }
 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;
 }
示例#18
0
        /// <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);
        }
            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);
            }
 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);
 }
            // 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);
            }