Example #1
0
        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);
        }
Example #2
0
        public static ExprDotNodeRealizedChain GetChainEvaluators(
            int?streamOfProviderIfApplicable,
            EPType inputType,
            IList <Chainable> chainSpec,
            ExprValidationContext validationContext,
            bool isDuckTyping,
            ExprDotNodeFilterAnalyzerInput inputDesc)
        {
            var                        methodForges       = new List <ExprDotForge>();
            var                        currentInputType   = inputType;
            EnumMethodDesc             lastLambdaFunc     = null;
            var                        lastElement        = chainSpec.IsEmpty() ? null : chainSpec[chainSpec.Count - 1];
            FilterExprAnalyzerAffector filterAnalyzerDesc = null;

            Deque <Chainable> chainSpecStack = new ArrayDeque <Chainable>(chainSpec);

            while (!chainSpecStack.IsEmpty())
            {
                var chainElement     = chainSpecStack.RemoveFirst();
                var parameters       = chainElement.GetParametersOrEmpty();
                var chainElementName = chainElement.GetRootNameOrEmptyString();
                var last             = chainSpecStack.IsEmpty();
                lastLambdaFunc = null;                 // reset

                // compile parameters for chain element
                var paramForges = new ExprForge[parameters.Count];
                var paramTypes  = new Type[parameters.Count];
                for (var i = 0; i < parameters.Count; i++)
                {
                    paramForges[i] = parameters[i].Forge;
                    paramTypes[i]  = paramForges[i].EvaluationType;
                }

                // check if special 'size' method
                if (currentInputType is ClassMultiValuedEPType)
                {
                    var type = (ClassMultiValuedEPType)currentInputType;
                    if (string.Equals(chainElementName, "size", StringComparison.InvariantCultureIgnoreCase) &&
                        paramTypes.Length == 0 &&
                        lastElement == chainElement)
                    {
                        ExprDotForge size;
                        var          containerType = ((ClassMultiValuedEPType)currentInputType).Container;
                        if (containerType.IsArray)
                        {
                            size = new ExprDotForgeSizeArray();
                        }
                        else
                        {
                            size = new ExprDotForgeSizeCollection();
                        }

                        methodForges.Add(size);
                        currentInputType = size.TypeInfo;
                        continue;
                    }

                    if (string.Equals(chainElementName, "get", StringComparison.InvariantCultureIgnoreCase) &&
                        paramTypes.Length == 1 &&
                        paramTypes[0].GetBoxedType() == typeof(int?))
                    {
                        ExprDotForge get;
                        var          componentType = type.Component.GetBoxedType();
                        if (type.Container.IsArray)
                        {
                            get = new ExprDotForgeGetArray(paramForges[0], componentType);
                        }
                        else
                        {
                            get = new ExprDotForgeGetCollection(paramForges[0], componentType);
                        }

                        methodForges.Add(get);
                        currentInputType = get.TypeInfo;
                        continue;
                    }

                    if (chainElement is ChainableArray && type.Container.IsArray)
                    {
                        var array     = (ChainableArray)chainElement;
                        var typeInfo  = currentInputType;
                        var indexExpr = ChainableArray.ValidateSingleIndexExpr(
                            array.Indexes,
                            () => "operation on type " + typeInfo.ToTypeDescriptive());
                        var componentType = type.Component.GetBoxedType();
                        var get           = new ExprDotForgeGetArray(indexExpr.Forge, componentType);
                        methodForges.Add(get);
                        currentInputType = get.TypeInfo;
                        continue;
                    }
                }

                // determine if there is a matching method or property
                var methodTarget   = GetMethodTarget(currentInputType);
                var matchingMethod = false;
                if (methodTarget != null && (!(chainElement is ChainableArray)))
                {
                    try {
                        GetValidateMethodDescriptor(methodTarget, chainElementName, parameters, validationContext);
                        matchingMethod = true;
                    }
                    catch (ExprValidationException) {
                        // expected
                    }
                }

                if (EnumMethodResolver.IsEnumerationMethod(chainElementName, validationContext.ImportService) &&
                    (!matchingMethod || methodTarget.IsArray || methodTarget.IsGenericCollection()))
                {
                    var enumerationMethod = EnumMethodResolver.FromName(chainElementName, validationContext.ImportService);
                    if (enumerationMethod == null)
                    {
                        throw new EPException("unable to determine enumeration method from name");
                    }

                    var eval = enumerationMethod.Factory.Invoke(chainElement.GetParametersOrEmpty().Count);
                    if (currentInputType is ClassEPType classEpType && classEpType.Clazz.IsGenericCollection() && !classEpType.Clazz.IsArray)
                    {
                        currentInputType = EPTypeHelper.CollectionOfSingleValue(typeof(object), null);
                    }

                    eval.Init(streamOfProviderIfApplicable, enumerationMethod, chainElementName, currentInputType, parameters, validationContext);
                    currentInputType = eval.TypeInfo;
                    if (currentInputType == null)
                    {
                        throw new IllegalStateException("Enumeration method '" + chainElementName + "' has not returned type information");
                    }

                    methodForges.Add(eval);
                    lastLambdaFunc = enumerationMethod;
                    continue;
                }

                // resolve datetime
                if (DatetimeMethodResolver.IsDateTimeMethod(chainElementName, validationContext.ImportService) &&
                    (!matchingMethod ||
                     methodTarget == typeof(DateTimeEx) ||
                     methodTarget == typeof(DateTimeOffset) ||
                     methodTarget == typeof(DateTime)))
                {
                    var datetimeMethod = DatetimeMethodResolver.FromName(chainElementName, validationContext.ImportService);
                    var datetimeImpl   = ExprDotDTFactory.ValidateMake(
                        validationContext.StreamTypeService,
                        chainSpecStack,
                        datetimeMethod,
                        chainElementName,
                        currentInputType,
                        parameters,
                        inputDesc,
                        validationContext.ImportService.TimeAbacus,
                        validationContext.TableCompileTimeResolver,
                        validationContext.ImportService,
                        validationContext.StatementRawInfo);
                    currentInputType = datetimeImpl.ReturnType;
                    if (currentInputType == null)
                    {
                        throw new IllegalStateException(
                                  "Date-time method '" + chainElementName + "' 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)
                {
                    if (chainElement is ChainableArray)
                    {
                        throw new ExprValidationException("Could not perform array operation on type " + currentInputType.ToTypeDescriptive());
                    }

                    var          inputEventType = (EventTypeSPI)((EventEPType)currentInputType).EventType;
                    var          type           = inputEventType.GetPropertyType(chainElementName);
                    var          getter         = inputEventType.GetGetterSPI(chainElementName);
                    var          fragmentType   = inputEventType.GetFragmentType(chainElementName);
                    ExprDotForge forge;
                    if (type != null && getter != null)
                    {
                        if (fragmentType == null || last)
                        {
                            forge            = new ExprDotForgeProperty(getter, EPTypeHelper.SingleValue(type.GetBoxedType()));
                            currentInputType = forge.TypeInfo;
                        }
                        else
                        {
                            if (!fragmentType.IsIndexed)
                            {
                                currentInputType = EPTypeHelper.SingleEvent(fragmentType.FragmentType);
                            }
                            else
                            {
                                currentInputType = EPTypeHelper.ArrayOfEvents(fragmentType.FragmentType);
                            }

                            forge = new ExprDotForgePropertyFragment(getter, currentInputType);
                        }

                        methodForges.Add(forge);
                        continue;
                    }
                }

                if (currentInputType is EventMultiValuedEPType eventMultiValuedEpType && chainElement is ChainableArray chainableArray)
                {
                    var inputEventType = (EventTypeSPI)eventMultiValuedEpType.Component;
                    var typeInfo       = currentInputType;
                    var indexExpr      = ChainableArray.ValidateSingleIndexExpr(
                        chainableArray.Indexes,
                        () => "operation on type " + typeInfo.ToTypeDescriptive());
                    currentInputType = EPTypeHelper.SingleEvent(inputEventType);
                    var forge = new ExprDotForgeEventArrayAtIndex(currentInputType, indexExpr);
                    methodForges.Add(forge);
                    continue;
                }

                // Finally try to resolve the method
                if (methodTarget != null && !(chainElement is ChainableArray))
                {
                    try {
                        // find descriptor again, allow for duck typing
                        var desc = GetValidateMethodDescriptor(methodTarget, chainElementName, 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() &&
                                EnumMethodResolver.IsEnumerationMethod(chainSpecStack.First.GetRootNameOrEmptyString(), validationContext.ImportService))
                            {
                                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,
                            chainElementName,
                            paramTypes,
                            paramForges);
                        methodForges.Add(duck);
                        currentInputType = duck.TypeInfo;
                    }

                    continue;
                }

                string message;
                if (!(chainElement is ChainableArray))
                {
                    message = "Could not find event property or method named '" + chainElementName + "' in " + currentInputType.ToTypeDescriptive();
                }
                else
                {
                    message = "Could not perform array operation on type " + currentInputType.ToTypeDescriptive();
                }

                throw new ExprValidationException(message);
            }

            var intermediateEvals = methodForges.ToArray();

            if (lastLambdaFunc != null)
            {
                ExprDotForge finalEval = null;
                if (currentInputType is EventMultiValuedEPType mvType)
                {
                    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 epType)
                {
                    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));
        }