public ExprMathNodeForgeEval( ExprMathNodeForge forge, ExprEvaluator evaluatorLeft, ExprEvaluator evaluatorRight) { this.forge = forge; this.evaluatorLeft = evaluatorLeft; this.evaluatorRight = evaluatorRight; }
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; }
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; }