private void EmitConditional(YaleIlGenerator ilg, ExpressionContext context, BranchManager branchManager) { var falseLabel = branchManager.FindLabel("falseLabel"); var endLabel = branchManager.FindLabel("endLabel"); // Emit the condition condition.Emit(ilg, context); // On false go to the false operand if (ilg.IsTemp) { branchManager.AddBranch(ilg, falseLabel); ilg.Emit(OpCodes.Brfalse_S, falseLabel); } else if (branchManager.IsLongBranch(ilg, falseLabel) == false) { ilg.Emit(OpCodes.Brfalse_S, falseLabel); } else { ilg.Emit(OpCodes.Brfalse, falseLabel); } // Emit the true operand whenTrue.Emit(ilg, context); ImplicitConverter.EmitImplicitConvert(whenTrue.ResultType, resultType, ilg); // Jump to end if (ilg.IsTemp) { branchManager.AddBranch(ilg, endLabel); ilg.Emit(OpCodes.Br_S, endLabel); } else if (branchManager.IsLongBranch(ilg, endLabel) == false) { ilg.Emit(OpCodes.Br_S, endLabel); } else { ilg.Emit(OpCodes.Br, endLabel); } branchManager.MarkLabel(ilg, falseLabel); ilg.MarkLabel(falseLabel); // Emit the false operand whenFalse.Emit(ilg, context); ImplicitConverter.EmitImplicitConvert(whenFalse.ResultType, resultType, ilg); // Fall through to end branchManager.MarkLabel(ilg, endLabel); ilg.MarkLabel(endLabel); }
/// <summary> /// Emit a short-circuited logical operation sequence /// The idea: Store all the leaf operands in a stack with the leftmost at the top and rightmost at the bottom. /// For each operand, emit it and try to find an end point for when it short-circuits. This means we go up through /// the stack of operators (ignoring siblings) until we find a different operation (then emit a branch to its right operand) /// or we reach the root (emit a branch to a true/false). /// Repeat the process for all operands and then emit the true/false/last operand end cases. /// </summary> private void EmitLogical(YaleIlGenerator ilg, ShortCircuitInfo info, ExpressionContext context) { // We always have an end label info.Branches.GetLabel(OurEndLabelKey, ilg); // Populate our data structures PopulateData(info); // Emit the sequence EmitLogicalShortCircuit(ilg, info, context); // Get the last operand var terminalOperand = (BaseExpressionElement)info.Operands.Pop(); // Emit it EmitOperand(terminalOperand, info, ilg, context); // And jump to the end var endLabel = info.Branches.FindLabel(OurEndLabelKey); ilg.Emit(OpCodes.Br_S, endLabel); // Emit our true/false terminals EmitTerminals(info, ilg, endLabel); // Mark the end ilg.MarkLabel(endLabel); }
private void EmitListIn(YaleIlGenerator ilg, ExpressionContext context, BranchManager branchManager) { var compareElement = new CompareElement(); var endLabel = branchManager.FindLabel("endLabel"); var trueTerminal = branchManager.FindLabel("trueTerminal"); // Cache the operand since we will be comparing against it a lot var lb = ilg.DeclareLocal(operand.ResultType); var targetIndex = lb.LocalIndex; operand.Emit(ilg, context); Utility.EmitStoreLocal(ilg, targetIndex); // Wrap our operand in a local shim var targetShim = new LocalBasedElement(operand, targetIndex); // Emit the compares foreach (var argumentElement in arguments) { compareElement.Initialize(targetShim, argumentElement, LogicalCompareOperation.Equal); compareElement.Emit(ilg, context); EmitBranchToTrueTerminal(ilg, trueTerminal, branchManager); } ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Br_S, endLabel); branchManager.MarkLabel(ilg, trueTerminal); ilg.MarkLabel(trueTerminal); ilg.Emit(OpCodes.Ldc_I4_1); branchManager.MarkLabel(ilg, endLabel); ilg.MarkLabel(endLabel); }