public static ExprDotNodeRealizedChain GetChainEvaluators( int? streamOfProviderIfApplicable, EPType inputType, IList<ExprChainedSpec> chainSpec, ExprValidationContext validationContext, bool isDuckTyping, ExprDotNodeFilterAnalyzerInput inputDesc) { IList<ExprDotForge> methodForges = new List<ExprDotForge>(); var currentInputType = inputType; EnumMethodEnum? lastLambdaFunc = null; var lastElement = chainSpec.IsEmpty() ? null : chainSpec[chainSpec.Count - 1]; FilterExprAnalyzerAffector filterAnalyzerDesc = null; Deque<ExprChainedSpec> chainSpecStack = new ArrayDeque<ExprChainedSpec>(chainSpec); while (!chainSpecStack.IsEmpty()) { var chainElement = chainSpecStack.RemoveFirst(); lastLambdaFunc = null; // reset // compile parameters for chain element var paramForges = new ExprForge[chainElement.Parameters.Count]; var paramTypes = new Type[chainElement.Parameters.Count]; for (var i = 0; i < chainElement.Parameters.Count; i++) { paramForges[i] = chainElement.Parameters[i].Forge; paramTypes[i] = paramForges[i].EvaluationType; } // check if special 'size' method if (currentInputType is ClassMultiValuedEPType) { var type = (ClassMultiValuedEPType) currentInputType; if (chainElement.Name.Equals("size", StringComparison.InvariantCultureIgnoreCase) && paramTypes.Length == 0 && lastElement == chainElement) { var sizeExpr = new ExprDotForgeArraySize(); methodForges.Add(sizeExpr); currentInputType = sizeExpr.TypeInfo; continue; } if (chainElement.Name.Equals("get", StringComparison.InvariantCultureIgnoreCase) && paramTypes.Length == 1 && Boxing.GetBoxedType(paramTypes[0]) == typeof(int?)) { var componentType = Boxing.GetBoxedType(type.Component); var get = new ExprDotForgeArrayGet(paramForges[0], componentType); methodForges.Add(get); currentInputType = get.TypeInfo; continue; } } // determine if there is a matching method var matchingMethod = false; var methodTarget = GetMethodTarget(currentInputType); if (methodTarget != null) { try { GetValidateMethodDescriptor( methodTarget, chainElement.Name, chainElement.Parameters, validationContext); matchingMethod = true; } catch (ExprValidationException) { // expected } } if (EnumMethodEnumExtensions.IsEnumerationMethod(chainElement.Name) && (!matchingMethod || methodTarget.IsArray || methodTarget.IsGenericCollection())) { var enumerationMethod = EnumMethodEnumExtensions.FromName(chainElement.Name); if (enumerationMethod == null) { throw new EPException("unable to determine enumeration method from name"); } var eval = TypeHelper.Instantiate<ExprDotForgeEnumMethod>( enumerationMethod.Value.GetImplementation()); eval.Init( streamOfProviderIfApplicable, enumerationMethod.Value, chainElement.Name, currentInputType, chainElement.Parameters, validationContext); currentInputType = eval.TypeInfo; if (currentInputType == null) { throw new IllegalStateException( "Enumeration method '" + chainElement.Name + "' has not returned type information"); } methodForges.Add(eval); lastLambdaFunc = enumerationMethod; continue; } // resolve datetime if (DatetimeMethodEnumHelper.IsDateTimeMethod(chainElement.Name) && (!matchingMethod || methodTarget == typeof(DateTimeEx) || methodTarget == typeof(DateTimeOffset) || methodTarget == typeof(DateTime))) { var dateTimeMethod = DatetimeMethodEnumHelper.FromName(chainElement.Name); var datetimeImpl = ExprDotDTFactory.ValidateMake( validationContext.StreamTypeService, chainSpecStack, dateTimeMethod, chainElement.Name, currentInputType, chainElement.Parameters, inputDesc, validationContext.ImportService.TimeAbacus, null, validationContext.TableCompileTimeResolver); currentInputType = datetimeImpl.ReturnType; if (currentInputType == null) { throw new IllegalStateException( "Date-time method '" + chainElement.Name + "' has not returned type information"); } methodForges.Add(datetimeImpl.Forge); filterAnalyzerDesc = datetimeImpl.IntervalFilterDesc; continue; } // try to resolve as property if the last method returned a type if (currentInputType is EventEPType) { var inputEventType = (EventTypeSPI) ((EventEPType) currentInputType).EventType; var type = inputEventType.GetPropertyType(chainElement.Name); var getter = inputEventType.GetGetterSPI(chainElement.Name); if (type != null && getter != null) { var noduck = new ExprDotForgeProperty( getter, EPTypeHelper.SingleValue(Boxing.GetBoxedType(type))); methodForges.Add(noduck); currentInputType = EPTypeHelper.SingleValue(EPTypeHelper.GetClassSingleValued(noduck.TypeInfo)); continue; } } // Finally try to resolve the method if (methodTarget != null) { try { // find descriptor again, allow for duck typing var desc = GetValidateMethodDescriptor( methodTarget, chainElement.Name, chainElement.Parameters, validationContext); paramForges = desc.ChildForges; ExprDotForge forge; if (currentInputType is ClassEPType) { // if followed by an enumeration method, convert array to collection if (desc.ReflectionMethod.ReturnType.IsArray && !chainSpecStack.IsEmpty() && EnumMethodEnumExtensions.IsEnumerationMethod(chainSpecStack.First.Name)) { forge = new ExprDotMethodForgeNoDuck( validationContext.StatementName, desc.ReflectionMethod, paramForges, ExprDotMethodForgeNoDuck.DuckType.WRAPARRAY); } else { forge = new ExprDotMethodForgeNoDuck( validationContext.StatementName, desc.ReflectionMethod, paramForges, ExprDotMethodForgeNoDuck.DuckType.PLAIN); } } else { forge = new ExprDotMethodForgeNoDuck( validationContext.StatementName, desc.ReflectionMethod, paramForges, ExprDotMethodForgeNoDuck.DuckType.UNDERLYING); } methodForges.Add(forge); currentInputType = forge.TypeInfo; } catch (Exception e) { if (!isDuckTyping) { throw new ExprValidationException(e.Message, e); } var duck = new ExprDotMethodForgeDuck( validationContext.StatementName, validationContext.ImportService, chainElement.Name, paramTypes, paramForges); methodForges.Add(duck); currentInputType = duck.TypeInfo; } continue; } var message = "Could not find event property, enumeration method or instance method named '" + chainElement.Name + "' in " + EPTypeHelper.ToTypeDescriptive(currentInputType); throw new ExprValidationException(message); } var intermediateEvals = methodForges.ToArray(); if (lastLambdaFunc != null) { ExprDotForge finalEval = null; if (currentInputType is EventMultiValuedEPType) { var mvType = (EventMultiValuedEPType) currentInputType; var tableMetadata = validationContext.TableCompileTimeResolver.ResolveTableFromEventType(mvType.Component); if (tableMetadata != null) { finalEval = new ExprDotForgeUnpackCollEventBeanTable(mvType.Component, tableMetadata); } else { finalEval = new ExprDotForgeUnpackCollEventBean(mvType.Component); } } else if (currentInputType is EventEPType) { var epType = (EventEPType) currentInputType; var tableMetadata = validationContext.TableCompileTimeResolver.ResolveTableFromEventType(epType.EventType); if (tableMetadata != null) { finalEval = new ExprDotForgeUnpackBeanTable(epType.EventType, tableMetadata); } else { finalEval = new ExprDotForgeUnpackBean(epType.EventType); } } if (finalEval != null) { methodForges.Add(finalEval); } } var unpackingForges = methodForges.ToArray(); return new ExprDotNodeRealizedChain(intermediateEvals, unpackingForges, filterAnalyzerDesc); }
public static CodegenExpression Codegen( EnumOrderByAscDescScalarLambdaForge forge, EnumForgeCodegenParams args, CodegenMethodScope codegenMethodScope, CodegenClassScope codegenClassScope) { var resultTypeMember = codegenClassScope.AddDefaultFieldUnshared( true, typeof(ObjectArrayEventType), Cast( typeof(ObjectArrayEventType), EventTypeUtility.ResolveTypeCodegen(forge.resultEventType, EPStatementInitServicesConstants.REF))); var innerBoxedType = Boxing.GetBoxedType(forge.InnerExpression.EvaluationType); var paramTypes = EnumForgeCodegenNames.PARAMS; var scope = new ExprForgeCodegenSymbol(false, null); var methodNode = codegenMethodScope.MakeChildWithScope( typeof(FlexCollection), typeof(EnumOrderByAscDescScalarLambdaForgeEval), scope, codegenClassScope) .AddParam(paramTypes); var block = methodNode.Block .DeclareVar<OrderedDictionary<object, object>>( "sort", NewInstance(typeof(OrderedDictionary<object, object>))) .DeclareVar<bool>("hasColl", ConstantFalse()) .DeclareVar<ObjectArrayEventBean>( "resultEvent", NewInstance<ObjectArrayEventBean>(NewArrayByLength(typeof(object), Constant(1)), resultTypeMember)) .AssignArrayElement(EnumForgeCodegenNames.REF_EPS, Constant(forge.StreamNumLambda), Ref("resultEvent")) .DeclareVar<object[]>("props", ExprDotName(Ref("resultEvent"), "Properties")); block.ForEach(typeof(object), "next", EnumForgeCodegenNames.REF_ENUMCOLL) .AssignArrayElement("props", Constant(0), Ref("next")) .DeclareVar( innerBoxedType, "value", forge.InnerExpression.EvaluateCodegen(innerBoxedType, methodNode, scope, codegenClassScope)) .DeclareVar<object>("entry", ExprDotMethod(Ref("sort"), "Get", Ref("value"))) .IfCondition(EqualsNull(Ref("entry"))) .Expression(ExprDotMethod(Ref("sort"), "Put", Ref("value"), Ref("next"))) .BlockContinue() .IfCondition(InstanceOf(Ref("entry"), typeof(ICollection<object>))) .ExprDotMethod(Cast(typeof(ICollection<object>), Ref("entry")), "Add", Ref("next")) .BlockContinue() .DeclareVar<Deque<object>>("coll", NewInstance<ArrayDeque<object>>(Constant(2))) .ExprDotMethod(Ref("coll"), "Add", Ref("entry")) .ExprDotMethod(Ref("coll"), "Add", Ref("next")) .ExprDotMethod(Ref("sort"), "Put", Ref("value"), Ref("coll")) .AssignRef("hasColl", ConstantTrue()) .BlockEnd(); block.MethodReturn( FlexWrap( StaticMethod( typeof(EnumOrderByAscDescEventsForgeEval), "EnumOrderBySortEval", Ref("sort"), Ref("hasColl"), Constant(forge.descending)))); return LocalMethod(methodNode, args.Eps, args.Enumcoll, args.IsNewData, args.ExprCtx); }