protected override QilNode VisitConditional(QilTernary ndCond) {
XmlILConstructInfo info = XmlILConstructInfo.Read(ndCond);
if (info.ConstructMethod == XmlILConstructMethod.Writer) {
Label lblFalse, lblDone;
// Evaluate if test
lblFalse = this.helper.DefineLabel();
NestedVisitWithBranch(ndCond.Left, BranchingContext.OnFalse, lblFalse);
// Generate true branch code
NestedVisit(ndCond.Center);
// Generate false branch code. If false branch is the empty list,
if (ndCond.Right.NodeType == QilNodeType.Sequence && ndCond.Right.Count == 0) {
// Then generate simplified code that doesn't contain a false branch
this.helper.MarkLabel(lblFalse);
NestedVisit(ndCond.Right);
}
else {
// Jump past false branch
lblDone = this.helper.DefineLabel();
this.helper.EmitUnconditionalBranch(OpCodes.Br, lblDone);
// Generate false branch code
this.helper.MarkLabel(lblFalse);
NestedVisit(ndCond.Right);
this.helper.MarkLabel(lblDone);
}
this.iterCurr.Storage = StorageDescriptor.None();
}
else {
IteratorDescriptor iterInfoTrue;
LocalBuilder locBool = null, locCond = null;
Label lblFalse, lblDone, lblNext;
Type itemStorageType = GetItemStorageType(ndCond);
Debug.Assert(info.ConstructMethod == XmlILConstructMethod.Iterator);
// Evaluate conditional test -- save boolean result in boolResult
Debug.Assert(ndCond.Left.XmlType.TypeCode == XmlTypeCode.Boolean);
lblFalse = this.helper.DefineLabel();
if (ndCond.XmlType.IsSingleton) {
// if (!bool-expr) goto LabelFalse;
NestedVisitWithBranch(ndCond.Left, BranchingContext.OnFalse, lblFalse);
}
else {
// CondType itemCond;
// int boolResult = bool-expr;
locCond = this.helper.DeclareLocal("$$$cond", itemStorageType);
locBool = this.helper.DeclareLocal("$$$boolResult", typeof(bool));
NestedVisitEnsureLocal(ndCond.Left, locBool);
// if (!boolResult) goto LabelFalse;
this.helper.Emit(OpCodes.Ldloc, locBool);
this.helper.Emit(OpCodes.Brfalse, lblFalse);
}
// Generate code for true branch
ConditionalBranch(ndCond.Center, itemStorageType, locCond);
iterInfoTrue = this.iterNested;
// goto LabelDone;
lblDone = this.helper.DefineLabel();
this.helper.EmitUnconditionalBranch(OpCodes.Br, lblDone);
// Generate code for false branch
// LabelFalse:
this.helper.MarkLabel(lblFalse);
ConditionalBranch(ndCond.Right, itemStorageType, locCond);
// If conditional is not cardinality one, then need to iterate through all values
if (!ndCond.XmlType.IsSingleton) {
Debug.Assert(!ndCond.Center.XmlType.IsSingleton || !ndCond.Right.XmlType.IsSingleton);
// IL's rules do not allow OpCodes.Br here
// goto LabelDone;
this.helper.EmitUnconditionalBranch(OpCodes.Brtrue, lblDone);
// LabelNext:
lblNext = this.helper.DefineLabel();
this.helper.MarkLabel(lblNext);
// if (boolResult) goto LabelNextTrue else goto LabelNextFalse;
this.helper.Emit(OpCodes.Ldloc, locBool);
this.helper.Emit(OpCodes.Brtrue, iterInfoTrue.GetLabelNext());
this.helper.EmitUnconditionalBranch(OpCodes.Br, this.iterNested.GetLabelNext());
this.iterCurr.SetIterator(lblNext, StorageDescriptor.Local(locCond, itemStorageType, false));
}
// LabelDone:
this.helper.MarkLabel(lblDone);
}
return ndCond;
}