예제 #1
0
 public ExprEqualsAllAnyNodeForgeEvalAllNoColl(
     ExprEqualsAllAnyNodeForge forge,
     ExprEvaluator[] evaluators)
 {
     this.forge = forge;
     this.evaluators = evaluators;
 }
        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);
        }
예제 #3
0
        public override ExprNode Validate(ExprValidationContext validationContext)
        {
            // Must have 2 child nodes
            if (ChildNodes.Length < 1) {
                throw new IllegalStateException("Equals group node does not have 1 or more parameters");
            }

            // Must be the same boxed type returned by expressions under this
            Type typeOne = ChildNodes[0].Forge.EvaluationType.GetBoxedType();

            // collections, array or map not supported
            if (typeOne.IsArray || typeOne.IsGenericCollection() || typeOne.IsGenericStringDictionary()) {
                throw new ExprValidationException(
                    "Collection or array comparison is not allowed for the IN, ANY, SOME or ALL keywords");
            }

            IList<Type> comparedTypes = new List<Type>();
            comparedTypes.Add(typeOne);
            var hasCollectionOrArray = false;
            for (var i = 0; i < ChildNodes.Length - 1; i++) {
                var propType = ChildNodes[i + 1].Forge.EvaluationType;
                if (propType == null) {
                    // no action
                }
                else if (propType.IsArray) {
                    hasCollectionOrArray = true;
                    if (propType.GetElementType() != typeof(object)) {
                        comparedTypes.Add(propType.GetElementType());
                    }
                }
                else if (propType.IsGenericCollection()) {
                    hasCollectionOrArray = true;
                }
                else if (propType.IsGenericStringDictionary()) {
                    hasCollectionOrArray = true;
                }
                else {
                    comparedTypes.Add(propType);
                }
            }

            // Determine common denominator type
            Type coercionTypeBoxed;
            try {
                coercionTypeBoxed = TypeHelper.GetCommonCoercionType(comparedTypes.ToArray());
            }
            catch (CoercionException ex) {
                throw new ExprValidationException("Implicit conversion not allowed: " + ex.Message);
            }

            // Check if we need to coerce
            var mustCoerce = false;
            Coercer coercer = null;
            if (coercionTypeBoxed.IsNumeric()) {
                foreach (var compareType in comparedTypes) {
                    if (coercionTypeBoxed != compareType.GetBoxedType()) {
                        mustCoerce = true;
                    }
                }

                if (mustCoerce) {
                    coercer = SimpleNumberCoercerFactory.GetCoercer(null, coercionTypeBoxed.GetBoxedType());
                }
            }

            _forge = new ExprEqualsAllAnyNodeForge(this, mustCoerce, coercer, coercionTypeBoxed, hasCollectionOrArray);
            return null;
        }