public static CodegenExpression Codegen( ExprInNodeForge forge, CodegenMethodScope codegenMethodScope, ExprForgeCodegenSymbol exprSymbol, CodegenClassScope codegenClassScope) { var forges = ExprNodeUtilityQuery.GetForges(forge.ForgeRenderable.ChildNodes); var isNot = forge.ForgeRenderable.IsNotIn; var methodNode = codegenMethodScope.MakeChild( typeof(bool?), typeof(ExprInNodeForgeEvalWColl), codegenClassScope); var block = methodNode.Block .DeclareVar<bool>("hasNullRow", ConstantFalse()); var leftTypeUncoerced = forges[0].EvaluationType.GetBoxedType(); var leftTypeCoerced = forge.CoercionType.GetBoxedType(); block.DeclareVar( leftTypeUncoerced, "left", forges[0].EvaluateCodegen(leftTypeUncoerced, methodNode, exprSymbol, codegenClassScope)); block.DeclareVar( forge.CoercionType, "leftCoerced", !forge.IsMustCoerce ? Ref("left") : forge.Coercer.CoerceCodegenMayNullBoxed( Ref("left"), leftTypeUncoerced, methodNode, codegenClassScope)); for (var i = 1; i < forges.Length; i++) { var reftype = forges[i].EvaluationType.GetBoxedType(); var refforge = forges[i]; var refname = "r" + i; if (reftype == null) { block.AssignRef("hasNullRow", ConstantTrue()); continue; } block.DeclareVar( reftype, refname, refforge.EvaluateCodegen(reftype, methodNode, exprSymbol, codegenClassScope)); if (reftype.IsArray) { var ifRightNotNull = block.IfCondition(NotEqualsNull(Ref(refname))); { if (leftTypeUncoerced.CanBeNull()) { ifRightNotNull.IfCondition( And( Relational(ArrayLength(Ref(refname)), GT, Constant(0)), EqualsNull(Ref("left")))) .BlockReturn(ConstantNull()); } var forLoop = ifRightNotNull.ForLoopIntSimple("index", ArrayLength(Ref(refname))); { forLoop.DeclareVar( reftype.GetElementType(), "item", ArrayAtIndex(Ref(refname), Ref("index"))); forLoop.DeclareVar<bool>( "itemNull", reftype.GetElementType().CanNotBeNull() ? ConstantFalse() : EqualsNull(Ref("item"))); var itemNotNull = forLoop.IfCondition(Ref("itemNull")) .AssignRef("hasNullRow", ConstantTrue()) .IfElse(); { if (!forge.IsMustCoerce) { itemNotNull.IfCondition( CodegenLegoCompareEquals.CodegenEqualsNonNullNoCoerce( Ref("leftCoerced"), leftTypeCoerced, Ref("item"), reftype.GetElementType())) .BlockReturn(!isNot ? ConstantTrue() : ConstantFalse()); } else { if (TypeHelper.IsNumeric(reftype.GetElementType())) { itemNotNull.IfCondition( CodegenLegoCompareEquals.CodegenEqualsNonNullNoCoerce( Ref("leftCoerced"), leftTypeCoerced, forge.Coercer.CoerceCodegen(Ref("item"), reftype.GetElementType()), forge.CoercionType)) .BlockReturn(!isNot ? ConstantTrue() : ConstantFalse()); } } } } } } else if (reftype.IsGenericDictionary()) { var ifRightNotNull = block.IfCondition(NotEqualsNull(Ref(refname))); { if (leftTypeUncoerced.CanBeNull()) { ifRightNotNull.IfRefNullReturnNull("left"); } var leftWithBoxing = ExprEqualsAllAnyNodeForgeHelper.ItemToCollectionUnboxing( Ref("left"), leftTypeUncoerced, reftype.GetDictionaryKeyType()); ifRightNotNull.IfCondition(ExprDotMethod(Ref(refname), "CheckedContainsKey", leftWithBoxing)) .BlockReturn(!isNot ? ConstantTrue() : ConstantFalse()); } } else if (reftype.IsGenericCollection()) { var ifRightNotNull = block.IfCondition(NotEqualsNull(Ref(refname))); { if (leftTypeUncoerced.CanBeNull()) { ifRightNotNull.IfRefNullReturnNull("left"); } var leftWithBoxing = ExprEqualsAllAnyNodeForgeHelper.ItemToCollectionUnboxing( Ref("left"), leftTypeUncoerced, reftype.GetCollectionItemType()); ifRightNotNull .IfCondition(StaticMethod(typeof(Collections), "CheckedContains", Ref(refname), leftWithBoxing)) .BlockReturn(!isNot ? ConstantTrue() : ConstantFalse()); } } else { var ifRightNotNull = reftype.CanNotBeNull() ? block : block.IfRefNotNull(refname); { if (leftTypeUncoerced.CanBeNull()) { ifRightNotNull.IfRefNullReturnNull("left"); } if (!forge.IsMustCoerce) { ifRightNotNull .IfCondition( CodegenLegoCompareEquals.CodegenEqualsNonNullNoCoerce( Ref("leftCoerced"), leftTypeCoerced, Ref(refname), reftype)) .BlockReturn(!isNot ? ConstantTrue() : ConstantFalse()); } else { ifRightNotNull .IfCondition( CodegenLegoCompareEquals.CodegenEqualsNonNullNoCoerce( Ref("leftCoerced"), leftTypeCoerced, forge.Coercer.CoerceCodegen(Ref(refname), reftype), forge.CoercionType)) .BlockReturn(!isNot ? ConstantTrue() : ConstantFalse()); } } if (reftype.CanBeNull()) { block.IfRefNull(refname).AssignRef("hasNullRow", ConstantTrue()); } } } block.IfCondition(Ref("hasNullRow")).BlockReturn(ConstantNull()); block.MethodReturn(isNot ? ConstantTrue() : ConstantFalse()); return LocalMethod(methodNode); }
public static CodegenExpression Codegen( ExprEqualsAllAnyNodeForge forge, CodegenMethodScope codegenMethodScope, ExprForgeCodegenSymbol exprSymbol, CodegenClassScope codegenClassScope) { var forges = ExprNodeUtilityQuery.GetForges(forge.ForgeRenderable.ChildNodes); var isNot = forge.ForgeRenderable.IsNot; var methodNode = codegenMethodScope.MakeChild( typeof(bool?), typeof(ExprEqualsAllAnyNodeForgeEvalAllWColl), codegenClassScope); var block = methodNode.Block; var leftTypeUncoerced = forges[0].EvaluationType; block.DeclareVar( leftTypeUncoerced, "left", forges[0].EvaluateCodegen(leftTypeUncoerced, methodNode, exprSymbol, codegenClassScope)); block.DeclareVar( forge.CoercionTypeBoxed, "leftCoerced", !forge.IsMustCoerce ? Ref("left") : forge.Coercer.CoerceCodegenMayNullBoxed( Ref("left"), leftTypeUncoerced, methodNode, codegenClassScope)); block.DeclareVar<bool>("hasNonNullRow", ConstantFalse()); block.DeclareVar<bool>("hasNullRow", ConstantFalse()); for (var i = 1; i < forges.Length; i++) { var refforge = forges[i]; var refname = "r" + i; var reftype = forges[i].EvaluationType; if (reftype.IsArray) { var arrayBlock = block.IfRefNullReturnNull("left") .DeclareVar( reftype, refname, refforge.EvaluateCodegen(reftype, methodNode, exprSymbol, codegenClassScope)) .IfCondition(EqualsNull(Ref(refname))) .AssignRef("hasNullRow", ConstantTrue()) .IfElse(); var forLoop = arrayBlock.ForLoopIntSimple("i", ArrayLength(Ref(refname))); var arrayAtIndex = ArrayAtIndex(Ref(refname), Ref("i")); forLoop.DeclareVar( forge.CoercionTypeBoxed, "item", forge.Coercer == null ? arrayAtIndex : forge.Coercer.CoerceCodegenMayNullBoxed( arrayAtIndex, reftype.GetElementType(), methodNode, codegenClassScope)); var forLoopElse = forLoop.IfCondition(EqualsNull(Ref("item"))) .AssignRef("hasNullRow", ConstantTrue()) .IfElse(); forLoopElse.AssignRef("hasNonNullRow", ConstantTrue()); forLoopElse.IfCondition( NotOptional(!isNot, StaticMethod<object>("Equals", Ref("leftCoerced"), Ref("item")))) .BlockReturn(ConstantFalse()); } else if (reftype.IsGenericDictionary()) { var dictionaryType = typeof(IDictionary<,>) .MakeGenericType( reftype.GetGenericArguments()[0], reftype.GetGenericArguments()[1]); var leftWithBoxing = ExprEqualsAllAnyNodeForgeHelper.ItemToCollectionUnboxing( Ref("left"), leftTypeUncoerced, reftype.GetDictionaryKeyType()); block.IfRefNullReturnNull("left") .DeclareVar( dictionaryType, refname, refforge.EvaluateCodegen( dictionaryType, methodNode, exprSymbol, codegenClassScope)) .IfCondition(EqualsNull(Ref(refname))) .AssignRef("hasNullRow", ConstantTrue()) .IfElse() .AssignRef("hasNonNullRow", ConstantTrue()) .IfCondition(NotOptional(!isNot, ExprDotMethod(Ref(refname), "CheckedContainsKey", leftWithBoxing))) .BlockReturn(ConstantFalse()); } else if (reftype.IsGenericCollection()) { var collectionType = typeof(ICollection<>) .MakeGenericType(reftype.GetGenericArguments()[0]); var leftWithBoxing = ExprEqualsAllAnyNodeForgeHelper.ItemToCollectionUnboxing( Ref("left"), leftTypeUncoerced, reftype.GetCollectionItemType()); block.IfRefNullReturnNull("left") .DeclareVar( collectionType, refname, refforge.EvaluateCodegen( collectionType, methodNode, exprSymbol, codegenClassScope)) .IfCondition(EqualsNull(Ref(refname))) .AssignRef("hasNullRow", ConstantTrue()) .IfElse() .AssignRef("hasNonNullRow", ConstantTrue()) .IfCondition(NotOptional(!isNot, ExprDotMethod(Ref(refname), "CheckedContains", leftWithBoxing))) .BlockReturn(ConstantFalse()); } else { block.IfRefNullReturnNull("leftCoerced"); block.DeclareVar( forge.CoercionTypeBoxed, refname, forge.Coercer == null ? refforge.EvaluateCodegen( forge.CoercionTypeBoxed, methodNode, exprSymbol, codegenClassScope) : forge.Coercer.CoerceCodegenMayNullBoxed( refforge.EvaluateCodegen( forge.CoercionTypeBoxed, methodNode, exprSymbol, codegenClassScope), reftype, methodNode, codegenClassScope)); var ifRightNotNull = block.IfRefNotNull(refname); { ifRightNotNull.AssignRef("hasNonNullRow", ConstantTrue()); ifRightNotNull .IfCondition(NotOptional(!isNot, StaticMethod<object>("Equals", Ref("leftCoerced"), Ref(refname)))) .BlockReturn(ConstantFalse()); } ifRightNotNull.IfElse() .AssignRef("hasNullRow", ConstantTrue()); } } block.IfCondition(Or(Not(Ref("hasNonNullRow")), Ref("hasNullRow"))).BlockReturn(ConstantNull()); block.MethodReturn(ConstantTrue()); return LocalMethod(methodNode); }