private static CodegenExpression CodegenCompare( CodegenExpressionRef lhs, Type lhsType, CodegenExpressionRef rhs, Type rhsType, ExprCaseNodeForge forge, CodegenMethodScope codegenMethodScope, CodegenClassScope codegenClassScope) { if (lhsType == null) { return EqualsNull(rhs); } if (rhsType == null) { return EqualsNull(lhs); } if (lhsType.CanNotBeNull() && rhsType.CanNotBeNull() && !forge.IsMustCoerce) { return CodegenLegoCompareEquals.CodegenEqualsNonNullNoCoerce(lhs, lhsType, rhs, rhsType); } var block = codegenMethodScope .MakeChild(typeof(bool), typeof(ExprCaseNodeForgeEvalSyntax2), codegenClassScope) .AddParam(lhsType, "leftResult") .AddParam(rhsType, "rightResult") .Block; if (lhsType.CanBeNull()) { var ifBlock = block.IfCondition(EqualsNull(Ref("leftResult"))); if (rhsType.CanNotBeNull()) { ifBlock.BlockReturn(ConstantFalse()); } else { ifBlock.BlockReturn(EqualsNull(Ref("rightResult"))); } } if (rhsType.CanBeNull()) { block.IfCondition(EqualsNull(Ref("rightResult"))).BlockReturn(ConstantFalse()); } CodegenMethod method; if (!forge.IsMustCoerce) { method = block.MethodReturn( CodegenLegoCompareEquals.CodegenEqualsNonNullNoCoerce( Ref("leftResult"), lhsType, Ref("rightResult"), rhsType)); } else { block.DeclareVar<object>("left", forge.Coercer.CoerceCodegen(Ref("leftResult"), lhsType)); block.DeclareVar<object>("right", forge.Coercer.CoerceCodegen(Ref("rightResult"), rhsType)); method = block.MethodReturn(StaticMethod<object>("Equals", Ref("left"), Ref("right"))); } return LocalMethodBuild(method).Pass(lhs).Pass(rhs).Call(); }
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); }