예제 #1
0
 public ExprMathNodeForgeEval(
     ExprMathNodeForge forge,
     ExprEvaluator evaluatorLeft,
     ExprEvaluator evaluatorRight)
 {
     this.forge = forge;
     this.evaluatorLeft = evaluatorLeft;
     this.evaluatorRight = evaluatorRight;
 }
예제 #2
0
        public static CodegenMethod Codegen(
            ExprMathNodeForge forge,
            CodegenMethodScope codegenMethodScope,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope,
            ExprNode lhs,
            ExprNode rhs)
        {
            var methodNode = codegenMethodScope.MakeChild(
                forge.EvaluationType,
                typeof(ExprMathNodeForgeEval),
                codegenClassScope);
            var lhsType = lhs.Forge.EvaluationType;
            var rhsType = rhs.Forge.EvaluationType;
            var block = methodNode.Block
                .DeclareVar(
                    lhsType,
                    "left",
                    lhs.Forge.EvaluateCodegen(lhsType, methodNode, exprSymbol, codegenClassScope));
            if (lhsType.CanBeNull()) {
                block.IfRefNullReturnNull("left");
            }

            block.DeclareVar(
                rhsType,
                "right",
                rhs.Forge.EvaluateCodegen(rhsType, methodNode, exprSymbol, codegenClassScope));
            if (rhsType.CanBeNull()) {
                block.IfRefNullReturnNull("right");
            }

            block.MethodReturn(
                CodegenLegoCast.CastSafeFromObjectType(
                    forge.EvaluationType,
                    forge.ArithTypeEnumComputer.Codegen(
                        methodNode,
                        codegenClassScope,
                        Ref("left"),
                        Ref("right"),
                        lhsType,
                        rhsType)));
            return methodNode;
        }
예제 #3
0
        public override ExprNode Validate(ExprValidationContext validationContext)
        {
            if (ChildNodes.Length != 2) {
                throw new ExprValidationException("Arithmatic node must have 2 parameters");
            }

            foreach (var child in ChildNodes) {
                var childType = child.Forge.EvaluationType;
                if (!childType.IsNumeric()) {
                    throw new ExprValidationException(
                        "Implicit conversion from datatype '" +
                        childType.CleanName() +
                        "' to numeric is not allowed");
                }
            }

            // Determine result type, set up compute function
            var lhs = ChildNodes[0];
            var rhs = ChildNodes[1];
            var lhsType = lhs.Forge.EvaluationType;
            var rhsType = rhs.Forge.EvaluationType;

            Type resultType;

            // If both sides are unboxed, then the result is also unboxed
            if (!lhsType.IsNullable() && !rhsType.IsNullable()) {
                if ((lhsType == typeof(short)) && (rhsType == typeof(short))) {
                    resultType = typeof(int);
                } else if (lhsType == typeof(byte) && (rhsType == typeof(byte))) {
                    resultType = typeof(int);
                } else if (lhsType == rhsType) {
                    resultType = rhsType;
                }
                else {
                    resultType = lhsType
                        .GetArithmaticCoercionType(rhsType)
                        .GetUnboxedType();
                }
            }
            else if ((lhsType == typeof(short) || lhsType == typeof(short?)) &&
                     (rhsType == typeof(short) || rhsType == typeof(short?))) {
                resultType = typeof(int?);
            }
            else if ((lhsType == typeof(byte) || lhsType == typeof(byte?)) &&
                     (rhsType == typeof(byte) || rhsType == typeof(byte?))) {
                resultType = typeof(int?);
            }
            else if (lhsType == rhsType) {
                resultType = rhsType.GetBoxedType();
            }
            else {
                resultType = lhsType.GetArithmaticCoercionType(rhsType);
            }

            if (MathArithTypeEnum == MathArithTypeEnum.DIVIDE && !_isIntegerDivision) {
                if (!resultType.IsDecimal()) {
                    resultType = typeof(double?);
                }
            }

            // If ths isDivisionByZeroReturnsNull is set, it requires promotion to boxed types
            // to support passing back null.
            if (_isDivisionByZeroReturnsNull) {
                resultType = resultType.GetBoxedType();
            }
            
            var arithTypeEnumComputer = MathArithType.GetComputer(
                MathArithTypeEnum,
                resultType,
                lhsType,
                rhsType,
                _isIntegerDivision,
                _isDivisionByZeroReturnsNull,
                validationContext.ImportService.DefaultMathContext);
            _forge = new ExprMathNodeForge(this, arithTypeEnumComputer, resultType);
            return null;
        }