public override ExprNode Validate(ExprValidationContext validationContext) { var length = ChildNodes.Length; // Can be an empty array with no content if (ChildNodes.Length == 0) { forge = new ExprArrayNodeForge(this, typeof(object), CollectionUtil.OBJECTARRAY_EMPTY); return null; } IList<Type> comparedTypes = new List<Type>(); for (var i = 0; i < length; i++) { comparedTypes.Add(ChildNodes[i].Forge.EvaluationType); } // Determine common denominator type Type arrayReturnType = null; var mustCoerce = false; Coercer coercer = null; try { arrayReturnType = TypeHelper.GetCommonCoercionType(comparedTypes.ToArray()); // Determine if we need to coerce numbers when one type doesn't match any other type if (arrayReturnType.IsNumeric()) { mustCoerce = false; foreach (var comparedType in comparedTypes) { if (comparedType != arrayReturnType) { mustCoerce = true; } } if (mustCoerce) { coercer = SimpleNumberCoercerFactory.GetCoercer(null, arrayReturnType); } } } catch (CoercionException) { // expected, such as mixing String and int values, or types (not boxed) and primitives // use Object[] in such cases } if (arrayReturnType == null) { arrayReturnType = typeof(object); } // Determine if we are dealing with constants only var results = new object[length]; var index = 0; foreach (var child in ChildNodes) { if (!child.Forge.ForgeConstantType.IsCompileTimeConstant) { results = null; // not using a constant result break; } results[index] = ChildNodes[index].Forge.ExprEvaluator.Evaluate(null, false, null); index++; } // Copy constants into array and coerce, if required Array constantResult = null; if (results != null) { constantResult = Array.CreateInstance(arrayReturnType, length); for (var i = 0; i < length; i++) { if (mustCoerce) { var boxed = results[i]; if (boxed != null) { object coercedResult = coercer.CoerceBoxed(boxed); constantResult.SetValue(coercedResult, i); } } else { constantResult.SetValue(results[i], i); } } } forge = new ExprArrayNodeForge(this, arrayReturnType, mustCoerce, coercer, constantResult); return null; }
public override ExprNode Validate(ExprValidationContext validationContext) { // Must have 2 child nodes if (ChildNodes.Length != 2) { throw new ExprValidationException( "Invalid use of equals, expecting left-hand side and right-hand side but received " + ChildNodes.Length + " expressions"); } // Must be the same boxed type returned by expressions under this var lhs = ChildNodes[0]; var rhs = ChildNodes[1]; var typeOne = lhs.Forge.EvaluationType.GetBoxedType(); var typeTwo = rhs.Forge.EvaluationType.GetBoxedType(); // Null constants can be compared for any type if (typeOne == null || typeTwo == null) { forge = new ExprEqualsNodeForgeNC(this); return null; } if (typeOne.Equals(typeTwo) || typeOne.IsAssignableFrom(typeTwo)) { forge = new ExprEqualsNodeForgeNC(this); return null; } // Get the common type such as Bool, String or Double and Long Type coercionType; try { coercionType = typeOne.GetCompareToCoercionType(typeTwo); } catch (CoercionException) { throw new ExprValidationException( "Implicit conversion from datatype '" + typeTwo.CleanName() + "' to '" + typeOne.CleanName() + "' is not allowed"); } // Check if we need to coerce if (coercionType == typeOne.GetBoxedType() && coercionType == typeTwo.GetBoxedType()) { forge = new ExprEqualsNodeForgeNC(this); } else { if (typeOne.IsArray && typeTwo.IsArray) { var typeOneElement = typeOne.GetElementType(); var typeTwoElement = typeTwo.GetElementType(); // Check to see if we have a "boxed" element trying to compare against an unboxed element. We can // coerce this with a custom widener. if (typeOneElement.GetBoxedType() == typeTwoElement.GetBoxedType()) { coercionType = typeOneElement.GetBoxedType().MakeArrayType(); var coercerLhs = ArrayCoercerFactory.GetCoercer(typeOne, coercionType); var coercerRhs = ArrayCoercerFactory.GetCoercer(typeTwo, coercionType); forge = new ExprEqualsNodeForgeCoercion(this, coercerLhs, coercerRhs); return null; } } if (!coercionType.IsNumeric()) { throw new ExprValidationException( "Cannot convert datatype '" + coercionType.CleanName() + "' to a value that fits both type '" + typeOne.CleanName() + "' and type '" + typeTwo.CleanName() + "'"); } var numberCoercerLHS = SimpleNumberCoercerFactory.GetCoercer(typeOne, coercionType); var numberCoercerRHS = SimpleNumberCoercerFactory.GetCoercer(typeTwo, coercionType); forge = new ExprEqualsNodeForgeCoercion(this, numberCoercerLHS, numberCoercerRHS); } return null; }
public static CodegenExpression CodegenEvaluatorMayMultiKeyWCoerce( IList<ExprForge> forges, IList<Type> optCoercionTypes, CodegenMethod method, Type generator, CodegenClassScope classScope) { if (forges.Count == 1) { return CodegenEvaluatorWCoerce( forges[0], optCoercionTypes?[0], method, generator, classScope); } var evaluate = new CodegenExpressionLambda(method.Block).WithParams(PARAMS); var evaluator = NewInstance<ProxyExprEvaluator>(evaluate); //var evaluator = NewAnonymousClass(method.Block, typeof(ExprEvaluator)); //var evaluate = CodegenMethod.MakeParentNode<object>(generator, classScope).AddParam(PARAMS); //evaluator.AddMethod("Evaluate", evaluate); var exprSymbol = new ExprForgeCodegenSymbol(true, null); var exprMethod = method.MakeChildWithScope( typeof(object), typeof(CodegenLegoMethodExpression), exprSymbol, classScope) .AddParam(PARAMS); var exprBlock = exprMethod.Block; var expressions = new CodegenExpression[forges.Count]; for (var i = 0; i < forges.Count; i++) { expressions[i] = forges[i].EvaluateCodegen( forges[i].EvaluationType, exprMethod, exprSymbol, classScope); } exprSymbol.DerivedSymbolsCodegen(exprMethod, exprBlock, classScope); exprBlock.DeclareVar<object[]>( "values", NewArrayByLength(typeof(object), Constant(forges.Count))) .DeclareVar<HashableMultiKey>("valuesMk", NewInstance<HashableMultiKey>(Ref("values"))); for (var i = 0; i < forges.Count; i++) { var result = expressions[i]; if (optCoercionTypes != null && forges[i].EvaluationType.GetBoxedType() != optCoercionTypes[i].GetBoxedType()) { var coercer = SimpleNumberCoercerFactory.GetCoercer( forges[i].EvaluationType, optCoercionTypes[i].GetBoxedType()); var name = "result_" + i; exprBlock.DeclareVar(forges[i].EvaluationType, name, expressions[i]); result = coercer.CoerceCodegen(Ref(name), forges[i].EvaluationType); } exprBlock.AssignArrayElement("values", Constant(i), result); } exprBlock.ReturnMethodOrBlock(Ref("valuesMk")); evaluate.Block.ReturnMethodOrBlock( LocalMethod(exprMethod, REF_EPS, REF_ISNEWDATA, REF_EXPREVALCONTEXT)); return evaluator; }
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; }
public CodegenExpression EventBeanGetCodegen( CodegenExpression beanExpression, CodegenMethodScope parent, CodegenClassScope classScope) { CodegenMethod method = parent.MakeChild(typeof(object), this.GetType(), classScope) .AddParam(typeof(EventBean), "eventBean"); method.Block.DeclareVar<EventBean[]>("events", NewArrayWithInit(typeof(EventBean), Ref("eventBean"))); // method to evaluate expressions and compute hash ExprForgeCodegenSymbol exprSymbol = new ExprForgeCodegenSymbol(true, true); CodegenMethod exprMethod = method .MakeChildWithScope( reflectionMethod.ReturnType, typeof(CodegenLegoMethodExpression), exprSymbol, classScope) .AddParam(ExprForgeCodegenNames.PARAMS); // generate args StaticMethodCodegenArgDesc[] args = AllArgumentExpressions( nodes, reflectionMethod, exprMethod, exprSymbol, classScope); AppendArgExpressions(args, exprMethod.Block); // try block CodegenBlock tryBlock = exprMethod.Block.TryCatch(); CodegenExpression invoke = CodegenInvokeExpression(null, reflectionMethod, args, classScope); tryBlock.BlockReturn(invoke); // exception handling AppendCatch( tryBlock, reflectionMethod, statementName, reflectionMethod.DeclaringType.CleanName(), true, args); exprMethod.Block.MethodReturn(Constant(0)); method.Block.DeclareVar( reflectionMethod.ReturnType, "result", LocalMethod(exprMethod, Ref("events"), ConstantTrue(), ConstantNull())); if (reflectionMethod.ReturnType.CanBeNull()) { method.Block.IfRefNull("result").BlockReturn(Constant(0)); } method.Block.DeclareVar<int>( "value", SimpleNumberCoercerFactory.GetCoercer(reflectionMethod.ReturnType, typeof(int?)) .CoerceCodegen(Ref("result"), reflectionMethod.ReturnType)) .IfCondition(Relational(Ref("value"), CodegenExpressionRelational.CodegenRelational.GE, Constant(0))) .BlockReturn(Op(Ref("value"), "%", Constant(granularity))) .MethodReturn(Op(Op(Ref("value"), "%", Constant(granularity)), "*", Constant(-1))); return LocalMethod(method, beanExpression); }
public static CodegenExpression Codegen( ExprMinMaxRowNodeForge forge, CodegenMethodScope codegenMethodScope, ExprForgeCodegenSymbol exprSymbol, CodegenClassScope codegenClassScope) { var resultType = forge.EvaluationType; var nodes = forge.ForgeRenderable.ChildNodes; CodegenExpression expression; if (resultType.IsBigInteger()) { var convertors = new BigIntegerCoercer[nodes.Length]; for (var i = 0; i < nodes.Length; i++) { convertors[i] = SimpleNumberCoercerFactory.GetCoercerBigInteger(nodes[i].Forge.EvaluationType); } expression = MinMaxType.ComputerBigIntCoerce.Codegen( forge.ForgeRenderable.MinMaxTypeEnum == MinMaxTypeEnum.MAX, codegenMethodScope, exprSymbol, codegenClassScope, nodes, convertors); } else if (resultType.IsDecimal()) { if (forge.ForgeRenderable.MinMaxTypeEnum == MinMaxTypeEnum.MAX) { expression = MinMaxType.MaxComputerDecimalCoerce.Codegen( codegenMethodScope, exprSymbol, codegenClassScope, nodes, resultType); } else { expression = MinMaxType.MinComputerDecimalCoerce.Codegen( codegenMethodScope, exprSymbol, codegenClassScope, nodes, resultType); } } else { if (forge.ForgeRenderable.MinMaxTypeEnum == MinMaxTypeEnum.MAX) { expression = MinMaxType.MaxComputerDoubleCoerce.Codegen( codegenMethodScope, exprSymbol, codegenClassScope, nodes, resultType); } else { expression = MinMaxType.MinComputerDoubleCoerce.Codegen( codegenMethodScope, exprSymbol, codegenClassScope, nodes, resultType); } } return expression; }