Exemplo n.º 1
0
        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);
        }