/// <summary> /// Visit the nodes of the tree (right then left) and populate some data structures /// </summary> /// <param name="info"></param> private void PopulateData(ShortCircuitInfo info) { // Is our right child a leaf or another And/Or expression? AndOrElement andOrChild = MyRightChild as AndOrElement; if (andOrChild == null) { // Leaf so push it on the stack info.Operands.Push(MyRightChild); } else { // Another And/Or expression so recurse andOrChild.PopulateData(info); } // Add ourselves as an operator info.Operators.Push(this); // Do the same thing for the left child andOrChild = MyLeftChild as AndOrElement; if (andOrChild == null) { info.Operands.Push(MyLeftChild); } else { andOrChild.PopulateData(info); } }
/// <summary> /// Emit a short/long branch for an And/Or element /// </summary> /// <param name="op"></param> /// <param name="longBranch"></param> /// <returns></returns> private static OpCode GetBranchOpcode(AndOrElement op, bool longBranch) { if (op._myOperation == AndOrOperation.And) { if (longBranch == true) { return(OpCodes.Brfalse); } else { return(OpCodes.Brfalse_S); } } else { if (longBranch == true) { return(OpCodes.Brtrue); } else { return(OpCodes.Brtrue_S); } } }
/// <summary> /// Recursively pop operators and operands /// </summary> /// <param name="operands"></param> /// <param name="operators"></param> private void Pop(Stack operands, Stack operators) { operators.Pop(); AndOrElement andOrChild = MyLeftChild as AndOrElement; if (andOrChild == null) { operands.Pop(); } else { andOrChild.Pop(operands, operators); } andOrChild = (AndOrElement)MyRightChild; if (andOrChild == null) { operands.Pop(); } else { andOrChild.Pop(operands, operators); } }
private static void EmitBranch(AndOrElement op, FleeILGenerator ilg, Label target, ShortCircuitInfo info) { // Get the branch opcode if (op._myOperation == AndOrOperation.And) { ilg.EmitBranchFalse(target); } else { ilg.EmitBranchTrue(target); } }
private void PopRightChild(Stack operands, Stack operators) { AndOrElement andOrChild = MyRightChild as AndOrElement; // What kind of child do we have? if ((andOrChild != null)) { // Another and/or expression so recurse andOrChild.Pop(operands, operators); } else { // A terminal so pop it off the operands stack operands.Pop(); } }
/// <summary> /// Emit a sequence of and/or expressions with short-circuiting /// </summary> /// <param name="ilg"></param> /// <param name="info"></param> /// <param name="services"></param> private static void EmitLogicalShortCircuit(FleeILGenerator ilg, ShortCircuitInfo info, IServiceProvider services) { while (info.Operators.Count != 0) { // Get the operator AndOrElement op = (AndOrElement)info.Operators.Pop(); // Get the left operand ExpressionElement leftOperand = (ExpressionElement)info.Operands.Pop(); // Emit the left EmitOperand(leftOperand, info, ilg, services); // Get the label for the short-circuit case Label l = GetShortCircuitLabel(op, info, ilg); // Emit the branch EmitBranch(op, ilg, l, info); } }
/// <summary> /// Get the label for a short-circuit /// </summary> /// <param name="current"></param> /// <param name="info"></param> /// <param name="ilg"></param> /// <returns></returns> private static Label GetShortCircuitLabel(AndOrElement current, ShortCircuitInfo info, FleeILGenerator ilg) { // We modify the given stacks so we need to clone them Stack cloneOperands = (Stack)info.Operands.Clone(); Stack cloneOperators = (Stack)info.Operators.Clone(); // Pop all siblings current.PopRightChild(cloneOperands, cloneOperators); // Go until we run out of operators while (cloneOperators.Count > 0) { // Get the top operator AndOrElement top = (AndOrElement)cloneOperators.Pop(); // Is is a different operation? if (top._myOperation != current._myOperation) { // Yes, so return a label to its right operand object nextOperand = cloneOperands.Pop(); return(GetLabel(nextOperand, ilg, info)); } else { // No, so keep going up the stack top.PopRightChild(cloneOperands, cloneOperators); } } // We've reached the end of the stack so return the label for the appropriate true/false terminal if (current._myOperation == AndOrOperation.And) { return(GetLabel(OurFalseTerminalKey, ilg, info)); } else { return(GetLabel(OurTrueTerminalKey, ilg, info)); } }
private static void EmitBranch(AndOrElement op, FleeILGenerator ilg, Label target, ShortCircuitInfo info) { if (ilg.IsTemp == true) { info.Branches.AddBranch(ilg, target); // Temp mode; just emit a short branch and return OpCode shortBranch = GetBranchOpcode(op, false); ilg.Emit(shortBranch, target); return; } // Emit the proper branch opcode // Determine if it is a long branch bool longBranch = info.Branches.IsLongBranch(ilg, target); // Get the branch opcode OpCode brOpcode = GetBranchOpcode(op, longBranch); // Emit the branch ilg.Emit(brOpcode, target); }