Esempio n. 1
0
        public void Init(
            int?streamOfProviderIfApplicable,
            EnumMethodEnum enumMethodEnum,
            String enumMethodUsedName,
            EPType typeInfo,
            IList <ExprNode> parameters,
            ExprValidationContext validationContext)
        {
            var eventTypeColl           = EPTypeHelper.GetEventTypeMultiValued(typeInfo);
            var eventTypeBean           = EPTypeHelper.GetEventTypeSingleValued(typeInfo);
            var collectionComponentType = EPTypeHelper.GetClassMultiValued(typeInfo);

            _enumMethodEnum      = enumMethodEnum;
            _enumMethodUsedName  = enumMethodUsedName;
            _streamCountIncoming = validationContext.StreamTypeService.EventTypes.Length;

            if (eventTypeColl == null && collectionComponentType == null && eventTypeBean == null)
            {
                throw new ExprValidationException(
                          "Invalid input for built-in enumeration method '" + enumMethodUsedName +
                          "', expecting collection of event-type or scalar values as input, received " +
                          EPTypeHelper.ToTypeDescriptive(typeInfo));
            }

            // compile parameter abstract for validation against available footprints
            var footprintProvided = DotMethodUtil.GetProvidedFootprint(parameters);

            // validate parameters
            DotMethodInputTypeMatcher inputTypeMatcher = new ProxyDotMethodInputTypeMatcher
            {
                ProcMatches = fp =>
                {
                    if (fp.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeBean == null && eventTypeColl == null)
                    {
                        return(false);
                    }
                    if (fp.Input == DotMethodFPInputEnum.SCALAR_ANY && collectionComponentType == null)
                    {
                        return(false);
                    }
                    return(true);
                }
            };

            var footprint = DotMethodUtil.ValidateParametersDetermineFootprint(
                enumMethodEnum.GetFootprints(), DotMethodTypeEnum.ENUM, enumMethodUsedName, footprintProvided,
                inputTypeMatcher);

            // validate input criteria met for this footprint
            if (footprint.Input != DotMethodFPInputEnum.ANY)
            {
                var message = "Invalid input for built-in enumeration method '" + enumMethodUsedName + "' and " +
                              footprint.Parameters.Length + "-parameter footprint, expecting collection of ";
                var received = " as input, received " + EPTypeHelper.ToTypeDescriptive(typeInfo);
                if (footprint.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeColl == null)
                {
                    throw new ExprValidationException(message + "events" + received);
                }
                if (footprint.Input.IsScalar() && collectionComponentType == null)
                {
                    throw new ExprValidationException(message + "values (typically scalar values)" + received);
                }
                if (footprint.Input == DotMethodFPInputEnum.SCALAR_NUMERIC && !collectionComponentType.IsNumeric())
                {
                    throw new ExprValidationException(message + "numeric values" + received);
                }
            }

            // manage context of this lambda-expression in regards to outer lambda-expression that may call this one.
            ExpressionResultCacheForEnumerationMethod enumerationMethodCache = validationContext.ExprEvaluatorContext.ExpressionResultCacheService.AllocateEnumerationMethod;

            enumerationMethodCache.PushStack(this);

            var bodiesAndParameters = new List <ExprDotEvalParam>();
            var count          = 0;
            var inputEventType = eventTypeBean ?? eventTypeColl;

            foreach (var node in parameters)
            {
                var bodyAndParameter = GetBodyAndParameter(
                    enumMethodUsedName, count++, node, inputEventType, collectionComponentType, validationContext,
                    bodiesAndParameters, footprint);
                bodiesAndParameters.Add(bodyAndParameter);
            }

            _enumEval = GetEnumEval(
                validationContext.EngineImportService, validationContext.EventAdapterService,
                validationContext.StreamTypeService, validationContext.StatementId, enumMethodUsedName,
                bodiesAndParameters, inputEventType, collectionComponentType, _streamCountIncoming,
                validationContext.IsDisablePropertyExpressionEventCollCache);
            _enumEvalNumRequiredEvents = _enumEval.StreamNumSize;

            // determine the stream ids of event properties asked for in the Evaluator(s)
            var streamsRequired = new HashSet <int>();
            var visitor         = new ExprNodeIdentifierCollectVisitor();

            foreach (var desc in bodiesAndParameters)
            {
                desc.Body.Accept(visitor);
                foreach (var ident in visitor.ExprProperties)
                {
                    streamsRequired.Add(ident.StreamId);
                }
            }
            if (streamOfProviderIfApplicable != null)
            {
                streamsRequired.Add(streamOfProviderIfApplicable.Value);
            }

            // We turn on caching if the stack is not empty (we are an inner lambda) and the dependency does not include the stream.
            var isInner = !enumerationMethodCache.PopLambda();

            if (isInner)
            {
                // If none of the properties that the current lambda uses comes from the ultimate Parent(s) or subsequent streams, then cache.
                var parents = enumerationMethodCache.GetStack();
                var found   = false;
                foreach (var req in streamsRequired)
                {
                    var first          = (ExprDotEvalEnumMethodBase)parents.First;
                    var parentIncoming = first._streamCountIncoming - 1;
                    var selfAdded      = _streamCountIncoming; // the one we use ourselfs
                    if (req > parentIncoming && req < selfAdded)
                    {
                        found = true;
                    }
                }
                _cache = !found;
            }
        }
Esempio n. 2
0
        private ExprDotEvalParam GetBodyAndParameter(
            String enumMethodUsedName,
            int parameterNum,
            ExprNode parameterNode,
            EventType inputEventType,
            Type collectionComponentType,
            ExprValidationContext validationContext,
            IList <ExprDotEvalParam> priorParameters,
            DotMethodFP footprint)
        {
            // handle an expression that is a constant or other (not =>)
            if (!(parameterNode is ExprLambdaGoesNode))
            {
                // no node subtree validation is required here, the chain parameter validation has taken place in ExprDotNode.validate
                // validation of parameter types has taken place in footprint matching
                return(new ExprDotEvalParamExpr(parameterNum, parameterNode, parameterNode.ExprEvaluator));
            }

            var goesNode = (ExprLambdaGoesNode)parameterNode;

            // Get secondary
            var additionalTypes = GetAddStreamTypes(
                enumMethodUsedName, goesNode.GoesToNames, inputEventType, collectionComponentType, priorParameters, validationContext.EventAdapterService);
            var additionalStreamNames = goesNode.GoesToNames.ToArray();

            ValidateDuplicateStreamNames(validationContext.StreamTypeService.StreamNames, additionalStreamNames);

            // add name and type to list of known types
            var addTypes =
                (EventType[])
                CollectionUtil.ArrayExpandAddElements(
                    validationContext.StreamTypeService.EventTypes, additionalTypes);
            var addNames =
                (String[])
                CollectionUtil.ArrayExpandAddElements(
                    validationContext.StreamTypeService.StreamNames, additionalStreamNames);

            var types = new StreamTypeServiceImpl(
                addTypes, addNames, new bool[addTypes.Length], null, false);

            // validate expression body
            var filter = goesNode.ChildNodes[0];

            try
            {
                var filterValidationContext = new ExprValidationContext(types, validationContext);
                filter = ExprNodeUtility.GetValidatedSubtree(ExprNodeOrigin.DECLAREDEXPRBODY, filter, filterValidationContext);
            }
            catch (ExprValidationException ex)
            {
                throw new ExprValidationException(
                          "Error validating enumeration method '" + enumMethodUsedName + "' parameter " + parameterNum + ": " +
                          ex.Message, ex);
            }

            var filterEvaluator = filter.ExprEvaluator;
            var expectedType    = footprint.Parameters[parameterNum].ParamType;

            // Lambda-methods don't use a specific expected return-type, so passing null for type is fine.
            DotMethodUtil.ValidateSpecificType(
                enumMethodUsedName, DotMethodTypeEnum.ENUM, expectedType, null, filterEvaluator.ReturnType, parameterNum,
                filter);

            var numStreamsIncoming = validationContext.StreamTypeService.EventTypes.Length;

            return(new ExprDotEvalParamLambda(
                       parameterNum, filter, filterEvaluator,
                       numStreamsIncoming, goesNode.GoesToNames, additionalTypes));
        }
Esempio n. 3
0
        public static ExprDotEvalDTMethodDesc ValidateMake(
            StreamTypeService streamTypeService,
            Deque <ExprChainedSpec> chainSpecStack,
            DatetimeMethodEnum dtMethod,
            String dtMethodName,
            EPType inputType,
            IList <ExprNode> parameters,
            ExprDotNodeFilterAnalyzerInput inputDesc,
            TimeZoneInfo timeZone)
        {
            // verify input
            String message = "Date-time enumeration method '" + dtMethodName +
                             "' requires either a DateTime or long value as input or events of an event type that declares a timestamp property";

            if (inputType is EventEPType)
            {
                if (((EventEPType)inputType).EventType.StartTimestampPropertyName == null)
                {
                    throw new ExprValidationException(message);
                }
            }
            else
            {
                if (!(inputType is ClassEPType || inputType is NullEPType))
                {
                    throw new ExprValidationException(message + " but received " + EPTypeHelper.ToTypeDescriptive(inputType));
                }
                if (inputType is ClassEPType)
                {
                    ClassEPType classEPType = (ClassEPType)inputType;
                    if (!TypeHelper.IsDateTime(classEPType.Clazz))
                    {
                        throw new ExprValidationException(
                                  message + " but received " + classEPType.Clazz.GetTypeNameFullyQualPretty());
                    }
                }
            }

            IList <CalendarOp> calendarOps       = new List <CalendarOp>();
            ReformatOp         reformatOp        = null;
            IntervalOp         intervalOp        = null;
            DatetimeMethodEnum currentMethod     = dtMethod;
            IList <ExprNode>   currentParameters = parameters;
            String             currentMethodName = dtMethodName;

            // drain all calendar ops
            ExprDotNodeFilterAnalyzerDesc filterAnalyzerDesc = null;

            while (true)
            {
                // handle the first one only if its a calendar op
                var evaluators = GetEvaluators(currentParameters);
                var opFactory  = currentMethod.MetaData().OpFactory;

                // compile parameter abstract for validation against available footprints
                var footprintProvided = DotMethodUtil.GetProvidedFootprint(currentParameters);

                // validate parameters
                DotMethodUtil.ValidateParametersDetermineFootprint(
                    currentMethod.Footprints(),
                    DotMethodTypeEnum.DATETIME,
                    currentMethodName, footprintProvided,
                    DotMethodInputTypeMatcherImpl.DEFAULT_ALL);

                if (opFactory is CalendarOpFactory)
                {
                    CalendarOp calendarOp = ((CalendarOpFactory)opFactory).GetOp(currentMethod, currentMethodName, currentParameters, evaluators);
                    calendarOps.Add(calendarOp);
                }
                else if (opFactory is ReformatOpFactory)
                {
                    reformatOp = ((ReformatOpFactory)opFactory).GetOp(timeZone, currentMethod, currentMethodName, currentParameters);

                    // compile filter analyzer information if there are no calendar ops in the chain
                    if (calendarOps.IsEmpty())
                    {
                        filterAnalyzerDesc = reformatOp.GetFilterDesc(streamTypeService.EventTypes, currentMethod, currentParameters, inputDesc);
                    }
                    else
                    {
                        filterAnalyzerDesc = null;
                    }
                }
                else if (opFactory is IntervalOpFactory)
                {
                    intervalOp = ((IntervalOpFactory)opFactory).GetOp(streamTypeService, currentMethod, currentMethodName, currentParameters, evaluators);

                    // compile filter analyzer information if there are no calendar ops in the chain
                    if (calendarOps.IsEmpty())
                    {
                        filterAnalyzerDesc = intervalOp.GetFilterDesc(streamTypeService.EventTypes, currentMethod, currentParameters, inputDesc);
                    }
                    else
                    {
                        filterAnalyzerDesc = null;
                    }
                }
                else
                {
                    throw new IllegalStateException("Invalid op factory class " + opFactory);
                }

                // see if there is more
                if (chainSpecStack.IsEmpty() || !DatetimeMethodEnumExtensions.IsDateTimeMethod(chainSpecStack.First.Name))
                {
                    break;
                }

                // pull next
                var next = chainSpecStack.RemoveFirst();
                currentMethod     = DatetimeMethodEnumExtensions.FromName(next.Name);
                currentParameters = next.Parameters;
                currentMethodName = next.Name;

                if ((reformatOp != null || intervalOp != null))
                {
                    throw new ExprValidationException("Invalid input for date-time method '" + next.Name + "'");
                }
            }

            ExprDotEval dotEval;
            EPType      returnType;

            dotEval    = new ExprDotEvalDT(calendarOps, timeZone, reformatOp, intervalOp, EPTypeHelper.GetClassSingleValued(inputType), EPTypeHelper.GetEventTypeSingleValued(inputType));
            returnType = dotEval.TypeInfo;
            return(new ExprDotEvalDTMethodDesc(dotEval, returnType, filterAnalyzerDesc));
        }
Esempio n. 4
0
        public void Init(
            int? streamOfProviderIfApplicable,
            EnumMethodDesc enumMethodDesc,
            string enumMethodUsedName,
            EPType typeInfo,
            IList<ExprNode> parameters,
            ExprValidationContext validationContext)
        {
            var eventTypeColl = typeInfo.GetEventTypeMultiValued();
            var eventTypeBean = typeInfo.GetEventTypeSingleValued();
            var collectionComponentType = typeInfo.GetClassMultiValued();

            _enumMethodDesc = enumMethodDesc;
            _enumMethodUsedName = enumMethodUsedName;
            _streamCountIncoming = validationContext.StreamTypeService.EventTypes.Length;

            if (eventTypeColl == null && collectionComponentType == null && eventTypeBean == null) {
                throw new ExprValidationException(
                    "Invalid input for built-in enumeration method '" +
                    enumMethodUsedName +
                    "', expecting collection of event-type or scalar values as input, received " +
                    typeInfo.ToTypeDescriptive());
            }

            // compile parameter abstract for validation against available footprints
            var footprintProvided = DotMethodUtil.GetProvidedFootprint(parameters);

            // validate parameters
            DotMethodInputTypeMatcher inputTypeMatcher = new ProxyDotMethodInputTypeMatcher {
                ProcMatches = footprint => {
                    if (footprint.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeBean == null && eventTypeColl == null) {
                        return false;
                    }

                    if (footprint.Input == DotMethodFPInputEnum.SCALAR_ANY && collectionComponentType == null) {
                        return false;
                    }

                    return true;
                },
            };
            var footprint = DotMethodUtil.ValidateParametersDetermineFootprint(
                enumMethodDesc.Footprints,
                DotMethodTypeEnum.ENUM,
                enumMethodUsedName,
                footprintProvided,
                inputTypeMatcher);

            // validate input criteria met for this footprint
            if (footprint.Input != DotMethodFPInputEnum.ANY) {
                var message = "Invalid input for built-in enumeration method '" +
                              enumMethodUsedName +
                              "' and " +
                              footprint.Parameters.Length +
                              "-parameter footprint, expecting collection of ";
                var received = " as input, received " + typeInfo.ToTypeDescriptive();
                if (footprint.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeColl == null) {
                    throw new ExprValidationException(message + "events" + received);
                }

                if (footprint.Input.IsScalar() && collectionComponentType == null) {
                    throw new ExprValidationException(message + "values (typically scalar values)" + received);
                }

                if (footprint.Input == DotMethodFPInputEnum.SCALAR_NUMERIC && !collectionComponentType.IsNumeric()) {
                    throw new ExprValidationException(message + "numeric values" + received);
                }
            }

            // manage context of this lambda-expression in regards to outer lambda-expression that may call this one.
            var enumCallStackHelper = validationContext.EnumMethodCallStackHelper;
            enumCallStackHelper.PushStack(this);

            try {
                // initialize
                var inputEventType = eventTypeBean ?? eventTypeColl;
                Initialize(
                    footprint,
                    enumMethodDesc.EnumMethod,
                    enumMethodUsedName,
                    inputEventType,
                    collectionComponentType,
                    parameters,
                    validationContext.StreamTypeService,
                    validationContext.StatementRawInfo,
                    validationContext.StatementCompileTimeService);

                // get-forge-desc-factory
                var forgeDescFactory = GetForgeFactory(
                    footprint,
                    parameters,
                    enumMethodDesc.EnumMethod,
                    enumMethodUsedName,
                    inputEventType,
                    collectionComponentType,
                    validationContext);

                // handle body and parameter list
                var bodiesAndParameters = new List<ExprDotEvalParam>();
                var count = 0;
                foreach (var node in parameters) {
                    var bodyAndParameter = GetBodyAndParameter(forgeDescFactory, enumMethodUsedName, count++, node, validationContext, footprint);
                    bodiesAndParameters.Add(bodyAndParameter);
                }

                var forgeDesc = forgeDescFactory.MakeEnumForgeDesc(
                    bodiesAndParameters,
                    _streamCountIncoming,
                    validationContext.StatementCompileTimeService);
                EnumForge = forgeDesc.Forge;
                _typeInfo = forgeDesc.Type;
                EnumEvalNumRequiredEvents = EnumForge.StreamNumSize;

                // determine the stream ids of event properties asked for in the evaluator(s)
                var streamsRequired = new HashSet<int?>();
                var visitor = new ExprNodeIdentifierCollectVisitor();
                foreach (var desc in bodiesAndParameters) {
                    desc.Body.Accept(visitor);
                    foreach (var ident in visitor.ExprProperties) {
                        streamsRequired.Add(ident.StreamId);
                    }
                }

                if (streamOfProviderIfApplicable != null) {
                    streamsRequired.Add(streamOfProviderIfApplicable);
                }

                // We turn on caching if the stack is not empty (we are an inner lambda) and the dependency does not include the stream.
                var isInner = !enumCallStackHelper.PopLambda();
                if (isInner) {
                    // If none of the properties that the current lambda uses comes from the ultimate parent(s) or subsequent streams, then cache.
                    var parents = enumCallStackHelper.GetStack();
                    var found = false;
                    foreach (int req in streamsRequired) {
                        var first = (ExprDotForgeEnumMethodBase) parents.First;
                        var parentIncoming = first._streamCountIncoming - 1;
                        var selfAdded = _streamCountIncoming; // the one we use ourselfs
                        if (req > parentIncoming && req < selfAdded) {
                            found = true;
                        }
                    }

                    IsCache = !found;
                }
            }
            catch (ExprValidationException) {
                enumCallStackHelper.PopLambda();
                throw;
            }
        }
Esempio n. 5
0
        public static ExprDotDTMethodDesc ValidateMake(
            StreamTypeService streamTypeService,
            Deque<Chainable> chainSpecStack,
            DatetimeMethodDesc dtMethod,
            string dtMethodName,
            EPType inputType,
            IList<ExprNode> parameters,
            ExprDotNodeFilterAnalyzerInput inputDesc,
            TimeAbacus timeAbacus,
            TableCompileTimeResolver tableCompileTimeResolver,
            ImportServiceCompileTime importService,
            StatementRawInfo statementRawInfo)
        {
            // verify input
            var message = "Date-time enumeration method '" +
                          dtMethodName +
                          "' requires either a DateTimeEx, DateTimeOffset, DateTime, or long value as input or events of an event type that declares a timestamp property";
            if (inputType is EventEPType eventEpType) {
                if (eventEpType.EventType.StartTimestampPropertyName == null) {
                    throw new ExprValidationException(message);
                }
            }
            else {
                if (!(inputType is ClassEPType || inputType is NullEPType)) {
                    throw new ExprValidationException(
                        message + " but received " + inputType.ToTypeDescriptive());
                }

                if (inputType is ClassEPType classEpType) {
                    if (!TypeHelper.IsDateTime(classEpType.Clazz)) {
                        throw new ExprValidationException(
                            message + " but received " + classEpType.Clazz.CleanName());
                    }
                }
            }

            IList<CalendarForge> calendarForges = new List<CalendarForge>();
            ReformatForge reformatForge = null;
            IntervalForge intervalForge = null;
            var currentMethod = dtMethod;
            var currentParameters = parameters;
            var currentMethodName = dtMethodName;

            // drain all calendar op
            FilterExprAnalyzerAffector filterAnalyzerDesc = null;
            while (true) {
                // handle the first one only if its a calendar op
                var forges = GetForges(currentParameters);
                var opFactory = currentMethod.ForgeFactory;

                // compile parameter abstract for validation against available footprints
                var footprintProvided = DotMethodUtil.GetProvidedFootprint(currentParameters);

                // validate parameters
                var footprintFound = DotMethodUtil.ValidateParametersDetermineFootprint(
                    currentMethod.Footprints,
                    DotMethodTypeEnum.DATETIME,
                    currentMethodName,
                    footprintProvided,
                    DotMethodInputTypeMatcherImpl.DEFAULT_ALL);

                if (opFactory is CalendarForgeFactory calendarForgeFactory) {
                    var calendarForge = calendarForgeFactory.GetOp(
                        currentMethod,
                        currentMethodName,
                        currentParameters,
                        forges);
                    calendarForges.Add(calendarForge);
                }
                else if (opFactory is ReformatForgeFactory reformatForgeFactory) {
                    reformatForge = reformatForgeFactory.GetForge(
                        inputType,
                        timeAbacus,
                        currentMethod,
                        currentMethodName,
                        currentParameters);

                    // compile filter analyzer information if there are no calendar op in the chain
                    if (calendarForges.IsEmpty()) {
                        filterAnalyzerDesc = reformatForge.GetFilterDesc(
                            streamTypeService.EventTypes,
                            currentMethod,
                            currentParameters,
                            inputDesc);
                    }
                    else {
                        filterAnalyzerDesc = null;
                    }
                }
                else if (opFactory is IntervalForgeFactory intervalForgeFactory) {
                    intervalForge = intervalForgeFactory.GetForge(
                        streamTypeService,
                        currentMethod,
                        currentMethodName,
                        currentParameters,
                        timeAbacus,
                        tableCompileTimeResolver);

                    // compile filter analyzer information if there are no calendar op in the chain
                    if (calendarForges.IsEmpty()) {
                        filterAnalyzerDesc = intervalForge.GetFilterDesc(
                            streamTypeService.EventTypes,
                            currentMethod,
                            currentParameters,
                            inputDesc);
                    }
                }
                else if (opFactory is DTMPluginForgeFactory dtmPluginForgeFactory) {
                    var usageDesc = new DateTimeMethodValidateContext(
                        footprintFound,
                        streamTypeService,
                        currentMethod,
                        currentParameters,
                        statementRawInfo);
                    var ops = dtmPluginForgeFactory.Validate(usageDesc);
                    if (ops == null) {
                        throw new ExprValidationException(
                            "Plug-in datetime method provider " + dtmPluginForgeFactory.GetType() + " returned a null-value for the operations");
                    }

                    var input = EPTypeHelper.GetClassSingleValued(inputType);
                    if (ops is DateTimeMethodOpsModify dateTimeMethodOpsModify) {
                        calendarForges.Add(new DTMPluginValueChangeForge(input, dateTimeMethodOpsModify, usageDesc.CurrentParameters));
                    }
                    else if (ops is DateTimeMethodOpsReformat dateTimeMethodOpsReformat) {
                        reformatForge = new DTMPluginReformatForge(input, dateTimeMethodOpsReformat, usageDesc.CurrentParameters);
                    }
                    else {
                        throw new ExprValidationException("Plug-in datetime method ops " + ops.GetType() + " is not recognized");
                    }

                    // no action
                }
                else {
                    throw new IllegalStateException("Invalid op factory class " + opFactory);
                }

                // see if there is more
                if (chainSpecStack.IsEmpty() || !DatetimeMethodResolver.IsDateTimeMethod(chainSpecStack.First.GetRootNameOrEmptyString(), importService)) {
                    break;
                }

                // pull next
                var next = chainSpecStack.RemoveFirst();
                currentMethodName = next.GetRootNameOrEmptyString();
                currentMethod = DatetimeMethodResolver.FromName(currentMethodName, importService);
                currentParameters = next.GetParametersOrEmpty();

                if (reformatForge != null || intervalForge != null) {
                    throw new ExprValidationException("Invalid input for date-time method '" + currentMethodName + "'");
                }
            }

            var dotForge = new ExprDotDTForge(
                calendarForges,
                timeAbacus,
                reformatForge,
                intervalForge,
                inputType.GetClassSingleValued(),
                inputType.GetEventTypeSingleValued());
            var returnType = dotForge.TypeInfo;
            return new ExprDotDTMethodDesc(dotForge, returnType, filterAnalyzerDesc);
        }
Esempio n. 6
0
        public static ExprDotDTMethodDesc ValidateMake(
            StreamTypeService streamTypeService,
            Deque<ExprChainedSpec> chainSpecStack,
            DateTimeMethodEnum dtMethod,
            string dtMethodName,
            EPType inputType,
            IList<ExprNode> parameters,
            ExprDotNodeFilterAnalyzerInput inputDesc,
            TimeAbacus timeAbacus,
            ExprEvaluatorContext exprEvaluatorContext,
            TableCompileTimeResolver tableCompileTimeResolver)
        {
            // verify input
            var message = "Date-time enumeration method '" +
                          dtMethodName +
                          "' requires either a DateTimeEx, DateTimeOffset, DateTime, or long value as input or events of an event type that declares a timestamp property";
            if (inputType is EventEPType) {
                if (((EventEPType) inputType).EventType.StartTimestampPropertyName == null) {
                    throw new ExprValidationException(message);
                }
            }
            else {
                if (!(inputType is ClassEPType || inputType is NullEPType)) {
                    throw new ExprValidationException(
                        message + " but received " + inputType.ToTypeDescriptive());
                }

                if (inputType is ClassEPType) {
                    var classEPType = (ClassEPType) inputType;
                    if (!TypeHelper.IsDateTime(classEPType.Clazz)) {
                        throw new ExprValidationException(
                            message + " but received " + classEPType.Clazz.CleanName());
                    }
                }
            }

            IList<CalendarForge> calendarForges = new List<CalendarForge>();
            ReformatForge reformatForge = null;
            IntervalForge intervalForge = null;
            var currentMethod = dtMethod;
            var currentParameters = parameters;
            var currentMethodName = dtMethodName;

            // drain all calendar op
            FilterExprAnalyzerAffector filterAnalyzerDesc = null;
            while (true) {
                // handle the first one only if its a calendar op
                var forges = GetForges(currentParameters);
                var opFactory = currentMethod.GetForgeFactory();

                // compile parameter abstract for validation against available footprints
                DotMethodFPProvided footprintProvided = DotMethodUtil.GetProvidedFootprint(currentParameters);

                // validate parameters
                DotMethodUtil.ValidateParametersDetermineFootprint(
                    currentMethod.GetFootprints(),
                    DotMethodTypeEnum.DATETIME,
                    currentMethodName,
                    footprintProvided,
                    DotMethodInputTypeMatcherImpl.DEFAULT_ALL);

                if (opFactory is CalendarForgeFactory) {
                    var calendarForge = ((CalendarForgeFactory) currentMethod.GetForgeFactory()).GetOp(
                        currentMethod,
                        currentMethodName,
                        currentParameters,
                        forges);
                    calendarForges.Add(calendarForge);
                }
                else if (opFactory is ReformatForgeFactory) {
                    reformatForge = ((ReformatForgeFactory) opFactory).GetForge(
                        inputType,
                        timeAbacus,
                        currentMethod,
                        currentMethodName,
                        currentParameters,
                        exprEvaluatorContext);

                    // compile filter analyzer information if there are no calendar op in the chain
                    if (calendarForges.IsEmpty()) {
                        filterAnalyzerDesc = reformatForge.GetFilterDesc(
                            streamTypeService.EventTypes,
                            currentMethod,
                            currentParameters,
                            inputDesc);
                    }
                    else {
                        filterAnalyzerDesc = null;
                    }
                }
                else if (opFactory is IntervalForgeFactory) {
                    intervalForge = ((IntervalForgeFactory) opFactory).GetForge(
                        streamTypeService,
                        currentMethod,
                        currentMethodName,
                        currentParameters,
                        timeAbacus,
                        tableCompileTimeResolver);

                    // compile filter analyzer information if there are no calendar op in the chain
                    if (calendarForges.IsEmpty()) {
                        filterAnalyzerDesc = intervalForge.GetFilterDesc(
                            streamTypeService.EventTypes,
                            currentMethod,
                            currentParameters,
                            inputDesc);
                    }
                    else {
                        filterAnalyzerDesc = null;
                    }
                }
                else {
                    throw new IllegalStateException("Invalid op factory class " + opFactory);
                }

                // see if there is more
                if (chainSpecStack.IsEmpty() || !DatetimeMethodEnumHelper.IsDateTimeMethod(chainSpecStack.First.Name)) {
                    break;
                }

                // pull next
                var next = chainSpecStack.RemoveFirst();
                currentMethod = DatetimeMethodEnumHelper.FromName(next.Name);
                currentParameters = next.Parameters;
                currentMethodName = next.Name;

                if (reformatForge != null || intervalForge != null) {
                    throw new ExprValidationException("Invalid input for date-time method '" + next.Name + "'");
                }
            }

            ExprDotForge dotForge;
            EPType returnType;

            dotForge = new ExprDotDTForge(
                calendarForges,
                timeAbacus,
                reformatForge,
                intervalForge,
                inputType.GetClassSingleValued(),
                inputType.GetEventTypeSingleValued());
            returnType = dotForge.TypeInfo;
            return new ExprDotDTMethodDesc(dotForge, returnType, filterAnalyzerDesc);
        }