Ejemplo n.º 1
0
        public static CodegenExpression Codegen(
            ExprCaseNodeForge forge,
            CodegenMethodScope codegenMethodScope,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope)
        {
            Type evaluationType = forge.EvaluationType == null
                ? typeof(IDictionary<object, object>)
                : forge.EvaluationType;
            CodegenMethod methodNode = codegenMethodScope.MakeChild(
                evaluationType,
                typeof(ExprCaseNodeForgeEvalSyntax1),
                codegenClassScope);

            CodegenBlock block = methodNode.Block.DeclareVar<bool?>("when", ConstantFalse());

            foreach (UniformPair<ExprNode> pair in forge.WhenThenNodeList) {
                block.AssignRef(
                    "when",
                    pair.First.Forge.EvaluateCodegen(typeof(bool?), methodNode, exprSymbol, codegenClassScope));
                block.IfCondition(And(NotEqualsNull(Ref("when")), ExprDotName(Ref("when"), "Value")))
                    .BlockReturn(CodegenToType(forge, pair.Second, methodNode, exprSymbol, codegenClassScope));
            }

            if (forge.OptionalElseExprNode != null) {
                block.MethodReturn(
                    CodegenToType(forge, forge.OptionalElseExprNode, methodNode, exprSymbol, codegenClassScope));
            }
            else {
                block.MethodReturn(ConstantNull());
            }

            return LocalMethod(methodNode);
        }
Ejemplo n.º 2
0
        public static CodegenExpression Codegen(
            ExprCaseNodeForge forge,
            CodegenMethodScope codegenMethodScope,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope)
        {
            var evaluationType = forge.EvaluationType == null
                ? typeof(IDictionary<object, object>)
                : forge.EvaluationType;
            var compareType = forge.OptionalCompareExprNode.Forge.EvaluationType;
            var methodNode = codegenMethodScope.MakeChild(
                evaluationType,
                typeof(ExprCaseNodeForgeEvalSyntax2),
                codegenClassScope);

            var checkResultType = compareType == null ? typeof(object) : compareType;
            var block = methodNode.Block
                .DeclareVar(
                    checkResultType,
                    "checkResult",
                    forge.OptionalCompareExprNode.Forge.EvaluateCodegen(
                        checkResultType,
                        methodNode,
                        exprSymbol,
                        codegenClassScope));
            var num = 0;
            foreach (var pair in forge.WhenThenNodeList) {
                var refname = "r" + num;
                var lhsType = pair.First.Forge.EvaluationType;
                var lhsDeclaredType = lhsType == null ? typeof(object) : lhsType;
                block.DeclareVar(
                    lhsDeclaredType,
                    refname,
                    pair.First.Forge.EvaluateCodegen(lhsDeclaredType, methodNode, exprSymbol, codegenClassScope));
                var compareExpression = CodegenCompare(
                    Ref("checkResult"),
                    compareType,
                    Ref(refname),
                    pair.First.Forge.EvaluationType,
                    forge,
                    methodNode,
                    codegenClassScope);
                block.IfCondition(compareExpression)
                    .BlockReturn(CodegenToType(forge, pair.Second, methodNode, exprSymbol, codegenClassScope));
                num++;
            }

            if (forge.OptionalElseExprNode != null) {
                block.MethodReturn(
                    CodegenToType(forge, forge.OptionalElseExprNode, methodNode, exprSymbol, codegenClassScope));
            }
            else {
                block.MethodReturn(ConstantNull());
            }

            return LocalMethod(methodNode);
        }
Ejemplo n.º 3
0
 public ExprCaseNodeForgeEvalSyntax1(
     ExprCaseNodeForge forge,
     IList<UniformPair<ExprEvaluator>> whenThenNodeList,
     ExprEvaluator optionalElseExprNode)
 {
     this.forge = forge;
     this.whenThenNodeList = whenThenNodeList;
     this.optionalElseExprNode = optionalElseExprNode;
 }
Ejemplo n.º 4
0
        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();
        }
Ejemplo n.º 5
0
 internal ExprCaseNodeForgeEvalSyntax2(
     ExprCaseNodeForge forge,
     IList<UniformPair<ExprEvaluator>> whenThenNodeList,
     ExprEvaluator compareExprNode,
     ExprEvaluator optionalElseExprNode)
 {
     this.forge = forge;
     this.whenThenNodeList = whenThenNodeList;
     this.compareExprNode = compareExprNode;
     this.optionalElseExprNode = optionalElseExprNode;
 }
Ejemplo n.º 6
0
        protected internal static CodegenExpression CodegenToType(
            ExprCaseNodeForge forge,
            ExprNode node,
            CodegenMethod methodNode,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope)
        {
            Type nodeEvaluationType = node.Forge.EvaluationType;
            if (nodeEvaluationType == forge.EvaluationType || !forge.IsNumericResult) {
                return node.Forge.EvaluateCodegen(nodeEvaluationType, methodNode, exprSymbol, codegenClassScope);
            }

            if (nodeEvaluationType == null) {
                return ConstantNull();
            }

            return TypeHelper.CoerceNumberToBoxedCodegen(
                node.Forge.EvaluateCodegen(nodeEvaluationType, methodNode, exprSymbol, codegenClassScope),
                nodeEvaluationType,
                forge.EvaluationType);
        }
Ejemplo n.º 7
0
        public static CodegenExpression CodegenTypeableSingle(
            ExprCaseNodeForge forge,
            CodegenMethodScope codegenMethodScope,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope)
        {
            CodegenMethod methodNode = codegenMethodScope.MakeChild(
                typeof(object[]),
                typeof(ExprCaseNodeForgeEvalTypable),
                codegenClassScope);


            CodegenBlock block = methodNode.Block
                .DeclareVar<IDictionary<object, object>>(
                    "map",
                    StaticMethod(
                        typeof(CompatExtensions),
                        "UnwrapDictionary",
                        forge.EvaluateCodegen(
                            typeof(IDictionary<object, object>),
                            methodNode,
                            exprSymbol,
                            codegenClassScope)))
                .DeclareVar<object[]>(
                    "row",
                    NewArrayByLength(typeof(object), ExprDotName(Ref("map"), "Count")));
            int index = -1;
            foreach (KeyValuePair<string, object> entry in forge.mapResultType) {
                index++;
                block.AssignArrayElement(
                    Ref("row"),
                    Constant(index),
                    ExprDotMethod(Ref("map"), "Get", Constant(entry.Key)));
            }

            block.MethodReturn(Ref("row"));
            return LocalMethod(methodNode);
        }
Ejemplo n.º 8
0
        public override ExprNode Validate(ExprValidationContext validationContext)
        {
            var analysis = AnalyzeCase();

            foreach (var pair in analysis.WhenThenNodeList) {
                if (!IsCase2) {
                    var returnType = pair.First.Forge.EvaluationType;
                    if (returnType != typeof(bool) && returnType != typeof(bool?)) {
                        throw new ExprValidationException("Case node 'when' expressions must return a boolean value");
                    }
                }
            }

            var mustCoerce = false;
            Coercer coercer = null;
            if (IsCase2) {
                // validate we can compare result types
                var comparedTypes = new List<Type>();
                comparedTypes.Add(analysis.OptionalCompareExprNode.Forge.EvaluationType);
                foreach (var pair in analysis.WhenThenNodeList) {
                    comparedTypes.Add(pair.First.Forge.EvaluationType);
                }

                // Determine common denominator type
                try {
                    var coercionType = TypeHelper.GetCommonCoercionType(comparedTypes.ToArray());

                    // Determine if we need to coerce numbers when one type doesn't match any other type
                    if (coercionType.IsNumeric()) {
                        mustCoerce = false;
                        foreach (var comparedType in comparedTypes) {
                            if (comparedType != coercionType) {
                                mustCoerce = true;
                            }
                        }

                        if (mustCoerce) {
                            coercer = SimpleNumberCoercerFactory.GetCoercer(null, coercionType);
                        }
                    }
                }
                catch (CoercionException ex) {
                    throw new ExprValidationException("Implicit conversion not allowed: " + ex.Message);
                }
            }

            // Determine type of each result (then-node and else node) child node expression
            IList<Type> childTypes = new List<Type>();
            IList<IDictionary<string, object>> childMapTypes = new List<IDictionary<string, object>>();
            foreach (var pair in analysis.WhenThenNodeList) {
                if (pair.Second.Forge is ExprTypableReturnForge) {
                    var typableReturn = (ExprTypableReturnForge) pair.Second.Forge;
                    var rowProps = typableReturn.RowProperties;
                    if (rowProps != null) {
                        childMapTypes.Add(rowProps);
                        continue;
                    }
                }

                childTypes.Add(pair.Second.Forge.EvaluationType);
            }

            if (analysis.OptionalElseExprNode != null) {
                if (analysis.OptionalElseExprNode.Forge is ExprTypableReturnForge) {
                    var typableReturn = (ExprTypableReturnForge) analysis.OptionalElseExprNode.Forge;
                    var rowProps = typableReturn.RowProperties;
                    if (rowProps != null) {
                        childMapTypes.Add(rowProps);
                    }
                    else {
                        childTypes.Add(analysis.OptionalElseExprNode.Forge.EvaluationType);
                    }
                }
                else {
                    childTypes.Add(analysis.OptionalElseExprNode.Forge.EvaluationType);
                }
            }

            if (!childMapTypes.IsEmpty() && !childTypes.IsEmpty()) {
                var message =
                    "Case node 'when' expressions require that all results either return a single value or a Map-type (new-operator) value";
                string check;
                var count = -1;
                foreach (var pair in analysis.WhenThenNodeList) {
                    count++;
                    if (pair.Second.Forge.EvaluationType != null &&
                        pair.Second.Forge.EvaluationType.IsNotGenericDictionary()) {
                        check = ", check when-condition number " + count;
                        throw new ExprValidationException(message + check);
                    }
                }

                if (analysis.OptionalElseExprNode != null) {
                    if (analysis.OptionalElseExprNode.Forge.EvaluationType != null &&
                        analysis.OptionalElseExprNode.Forge.EvaluationType.IsNotGenericDictionary()) {
                        check = ", check the else-condition";
                        throw new ExprValidationException(message + check);
                    }
                }

                throw new ExprValidationException(message);
            }

            IDictionary<string, object> mapResultType = null;
            Type resultType = null;
            var isNumericResult = false;
            if (childMapTypes.IsEmpty()) {
                // Determine common denominator type
                try {
                    resultType = TypeHelper
                        .GetCommonCoercionType(childTypes.ToArray())
                        .GetBoxedType();
                    if (resultType.IsNumeric()) {
                        isNumericResult = true;
                    }
                }
                catch (CoercionException ex) {
                    throw new ExprValidationException("Implicit conversion not allowed: " + ex.Message);
                }
            }
            else {
                resultType = typeof(IDictionary<string, object>);
                mapResultType = childMapTypes[0];
                for (var i = 1; i < childMapTypes.Count; i++) {
                    var other = childMapTypes[i];
                    var messageEquals = BaseNestableEventType.IsDeepEqualsProperties(
                        "Case-when number " + i,
                        mapResultType,
                        other);
                    if (messageEquals != null) {
                        throw new ExprValidationException(
                            "Incompatible case-when return types by new-operator in case-when number " +
                            i +
                            ": " +
                            messageEquals.Message,
                            messageEquals);
                    }
                }
            }

            forge = new ExprCaseNodeForge(
                this,
                resultType,
                mapResultType,
                isNumericResult,
                mustCoerce,
                coercer,
                analysis.WhenThenNodeList,
                analysis.OptionalCompareExprNode,
                analysis.OptionalElseExprNode);
            return null;
        }
Ejemplo n.º 9
0
 public ExprCaseNodeForgeEvalTypable(ExprCaseNodeForge forge)
 {
     this.forge = forge;
     this.evaluator = forge.ExprEvaluator;
 }