public static ExprDotNodeRealizedChain GetChainEvaluators( int?streamOfProviderIfApplicable, EPType inputType, IList <ExprChainedSpec> chainSpec, ExprValidationContext validationContext, bool isDuckTyping, ExprDotNodeFilterAnalyzerInput inputDesc) { var methodEvals = new List <ExprDotEval>(); var currentInputType = inputType; EnumMethodEnum?lastLambdaFunc = null; var lastElement = chainSpec.IsEmpty() ? null : chainSpec[chainSpec.Count - 1]; ExprDotNodeFilterAnalyzerDesc filterAnalyzerDesc = null; var chainSpecStack = new ArrayDeque <ExprChainedSpec>(chainSpec); while (!chainSpecStack.IsEmpty()) { var chainElement = chainSpecStack.RemoveFirst(); lastLambdaFunc = null; // reset // compile parameters for chain element var paramEvals = new ExprEvaluator[chainElement.Parameters.Count]; var paramTypes = new Type[chainElement.Parameters.Count]; for (var i = 0; i < chainElement.Parameters.Count; i++) { paramEvals[i] = chainElement.Parameters[i].ExprEvaluator; paramTypes[i] = paramEvals[i].ReturnType; } // check if special 'size' method if (currentInputType is ClassMultiValuedEPType) { var type = (ClassMultiValuedEPType)currentInputType; if ((chainElement.Name.ToLower() == "size") && paramTypes.Length == 0 && Equals(lastElement, chainElement)) { var sizeExpr = new ExprDotEvalArraySize(); methodEvals.Add(sizeExpr); currentInputType = sizeExpr.TypeInfo; continue; } if ((chainElement.Name.ToLower() == "get") && paramTypes.Length == 1 && paramTypes[0].GetBoxedType() == typeof(int?)) { var componentType = type.Component; var get = new ExprDotEvalArrayGet(paramEvals[0], componentType); methodEvals.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 } } // resolve lambda if (chainElement.Name.IsEnumerationMethod() && (!matchingMethod || methodTarget.IsArray || methodTarget.IsImplementsInterface(typeof(ICollection <object>)))) { var enumerationMethod = EnumMethodEnumExtensions.FromName(chainElement.Name); var eval = TypeHelper.Instantiate <ExprDotEvalEnumMethod>(enumerationMethod.GetImplementation()); eval.Init(streamOfProviderIfApplicable, enumerationMethod, chainElement.Name, currentInputType, chainElement.Parameters, validationContext); currentInputType = eval.TypeInfo; if (currentInputType == null) { throw new IllegalStateException("Enumeration method '" + chainElement.Name + "' has not returned type information"); } methodEvals.Add(eval); lastLambdaFunc = enumerationMethod; continue; } // resolve datetime if (chainElement.Name.IsDateTimeMethod() && (!matchingMethod || methodTarget == typeof(DateTimeOffset?))) { var datetimeMethod = DatetimeMethodEnumExtensions.FromName(chainElement.Name); var datetimeImpl = ExprDotEvalDTFactory.ValidateMake( validationContext.StreamTypeService, chainSpecStack, datetimeMethod, chainElement.Name, currentInputType, chainElement.Parameters, inputDesc, validationContext.EngineImportService.TimeZone, validationContext.EngineImportService.TimeAbacus); currentInputType = datetimeImpl.ReturnType; if (currentInputType == null) { throw new IllegalStateException("Date-time method '" + chainElement.Name + "' has not returned type information"); } methodEvals.Add(datetimeImpl.Eval); filterAnalyzerDesc = datetimeImpl.IntervalFilterDesc; continue; } // try to resolve as property if the last method returned a type if (currentInputType is EventEPType) { var inputEventType = ((EventEPType)currentInputType).EventType; var type = inputEventType.GetPropertyType(chainElement.Name); var getter = inputEventType.GetGetter(chainElement.Name); if (type != null && getter != null) { var noduck = new ExprDotEvalProperty(getter, EPTypeHelper.SingleValue(type.GetBoxedType())); methodEvals.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); var fastMethod = desc.FastMethod; paramEvals = desc.ChildEvals; ExprDotEval eval; if (currentInputType is ClassEPType) { // if followed by an enumeration method, convert array to collection if (fastMethod.ReturnType.IsArray && !chainSpecStack.IsEmpty() && chainSpecStack.First.Name.IsEnumerationMethod()) { eval = new ExprDotMethodEvalNoDuckWrapArray(validationContext.StatementName, fastMethod, paramEvals); } else { eval = new ExprDotMethodEvalNoDuck(validationContext.StatementName, fastMethod, paramEvals); } } else { eval = new ExprDotMethodEvalNoDuckUnderlying(validationContext.StatementName, fastMethod, paramEvals); } methodEvals.Add(eval); currentInputType = eval.TypeInfo; } catch (Exception e) { if (!isDuckTyping) { throw new ExprValidationException(e.Message, e); } else { var duck = new ExprDotMethodEvalDuck(validationContext.StatementName, validationContext.EngineImportService, chainElement.Name, paramTypes, paramEvals); methodEvals.Add(duck); currentInputType = duck.TypeInfo; } } continue; } var message = "Could not find event property, enumeration method or instance method named '" + chainElement.Name + "' in " + currentInputType.ToTypeDescriptive(); throw new ExprValidationException(message); } var intermediateEvals = methodEvals.ToArray(); if (lastLambdaFunc != null) { ExprDotEval finalEval = null; if (currentInputType is EventMultiValuedEPType) { var mvType = (EventMultiValuedEPType)currentInputType; var tableMetadata = validationContext.TableService.GetTableMetadataFromEventType(mvType.Component); if (tableMetadata != null) { finalEval = new ExprDotEvalUnpackCollEventBeanTable(mvType.Component, tableMetadata); } else { finalEval = new ExprDotEvalUnpackCollEventBean(mvType.Component); } } else if (currentInputType is EventEPType) { var epType = (EventEPType)currentInputType; var tableMetadata = validationContext.TableService.GetTableMetadataFromEventType(epType.EventType); if (tableMetadata != null) { finalEval = new ExprDotEvalUnpackBeanTable(epType.EventType, tableMetadata); } else { finalEval = new ExprDotEvalUnpackBean(epType.EventType); } } if (finalEval != null) { methodEvals.Add(finalEval); } } var unpackingEvals = methodEvals.ToArray(); return(new ExprDotNodeRealizedChain(intermediateEvals, unpackingEvals, filterAnalyzerDesc)); }
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); }