//----------------------------------------------- // If-then-else branching //----------------------------------------------- /// <summary> /// Setup a branching context. All nested iterators compiled in this context must evaluate /// to a single boolean value. However, these expressions must not push the result as a boolean /// onto the stack. Instead, if brctxt is BranchType.True, then the expression should /// jump to lblBranch if it evaluates to true. If brctxt is BranchType.False, then the /// branch should happen if the evaluation result is false. /// </summary> public void SetBranching(BranchingContext brctxt, Label lblBranch) { Debug.Assert(brctxt != BranchingContext.None); this.brctxt = brctxt; this.lblBranch = lblBranch; }
//----------------------------------------------- // If-then-else branching //----------------------------------------------- /// <summary> /// Setup a branching context. All nested iterators compiled in this context must evaluate /// to a single boolean value. However, these expressions must not push the result as a boolean /// onto the stack. Instead, if brctxt is BranchType.True, then the expression should /// jump to lblBranch if it evaluates to true. If brctxt is BranchType.False, then the /// branch should happen if the evaluation result is false. /// </summary> public void SetBranching(BranchingContext brctxt, Label lblBranch) { Debug.Assert(brctxt != BranchingContext.None); _brctxt = brctxt; _lblBranch = lblBranch; }
/// <summary> /// Anchor any remaining labels. /// </summary> private void EndConjunctiveTests(BranchingContext brctxt, Label lblBranch, Label lblOnFalse) { switch (brctxt) { case BranchingContext.OnTrue: // Anchor false label _helper.MarkLabel(lblOnFalse); goto case BranchingContext.OnFalse; case BranchingContext.OnFalse: _iterCurr.Storage = StorageDescriptor.None(); break; case BranchingContext.None: // Convert branch targets into push of true/false _helper.ConvBranchToBool(lblOnFalse, false); _iterCurr.Storage = StorageDescriptor.Stack(typeof(bool), false); break; } }
/// <summary> /// Fixup branching context for the last test in a conjunctive (Logical And) expression. /// </summary> private void StartLastConjunctiveTest(BranchingContext brctxt, Label lblBranch, Label lblOnFalse) { switch (brctxt) { case BranchingContext.OnTrue: // If last condition evaluates to true, branch to true label _iterCurr.SetBranching(BranchingContext.OnTrue, lblBranch); break; default: // If last condition evalutes to false, branch to false label // Else fall through to true code path _iterCurr.SetBranching(BranchingContext.OnFalse, lblOnFalse); break; } }
/// <summary> /// Fixup branching context for all but the last test in a conjunctive (Logical And) expression. /// Return a temporary label which will be passed to StartLastAndBranch() and EndAndBranch(). /// </summary> private Label StartConjunctiveTests(BranchingContext brctxt, Label lblBranch) { Label lblOnFalse; switch (brctxt) { case BranchingContext.OnFalse: // If condition evaluates to false, branch to false label _iterCurr.SetBranching(BranchingContext.OnFalse, lblBranch); return lblBranch; default: // If condition evaluates to false: // 1. Jump to new false label that will be fixed just beyond the second condition // 2. Or, jump to code that pushes "false" lblOnFalse = _helper.DefineLabel(); _iterCurr.SetBranching(BranchingContext.OnFalse, lblOnFalse); return lblOnFalse; } }
/// <summary> /// Start a nested iterator in a branching context and recursively generate code for the specified QilExpression node. /// </summary> private void NestedVisitWithBranch(QilNode nd, BranchingContext brctxt, Label lblBranch) { Debug.Assert(nd.XmlType.IsSingleton && !XmlILConstructInfo.Read(nd).PushToWriterLast); StartNestedIterator(nd); _iterCurr.SetBranching(brctxt, lblBranch); Visit(nd); EndNestedIterator(nd); _iterCurr.Storage = StorageDescriptor.None(); }