public static ExpressionExecutor parseExpression(Expression expression, MetaComplexEvent metaEvent,
                                                     int currentState, Map<String, Table> tableMap,
                                                     List<VariableExpressionExecutor> executorList,
                                                     boolean groupBy,
                                                     int defaultStreamEventIndex,
                                                     ProcessingMode processingMode,
                                                     boolean outputExpectsExpiredEvents, SiddhiQueryContext siddhiQueryContext) {
        try {
            if (expression instanceof And) {
                return new AndConditionExpressionExecutor(
                        parseExpression(((And) expression).getLeftExpression(), metaEvent, currentState, tableMap,
                                executorList, groupBy, defaultStreamEventIndex,
                                processingMode, outputExpectsExpiredEvents, siddhiQueryContext),
                        parseExpression(((And) expression).getRightExpression(), metaEvent, currentState, tableMap,
                                executorList, groupBy, defaultStreamEventIndex,
                                processingMode, outputExpectsExpiredEvents, siddhiQueryContext));
            } else if (expression instanceof Or) {
                return new OrConditionExpressionExecutor(
                        parseExpression(((Or) expression).getLeftExpression(), metaEvent, currentState, tableMap,
                                executorList, groupBy, defaultStreamEventIndex,
                                processingMode, outputExpectsExpiredEvents, siddhiQueryContext),
                        parseExpression(((Or) expression).getRightExpression(), metaEvent, currentState, tableMap,
                                executorList, groupBy, defaultStreamEventIndex,
                                processingMode, outputExpectsExpiredEvents, siddhiQueryContext));
            } else if (expression instanceof Not) {
                return new NotConditionExpressionExecutor(
                        parseExpression(((Not) expression).getExpression(), metaEvent, currentState, tableMap,
                                executorList, groupBy, defaultStreamEventIndex,
                                processingMode, outputExpectsExpiredEvents, siddhiQueryContext));
            } else if (expression instanceof Compare) {
                if (((Compare) expression).getOperator() == Compare.Operator.EQUAL) {
                    Expression leftExpression = ((Compare) expression).getLeftExpression();
                    Expression rightExpression = ((Compare) expression).getRightExpression();
                    ExpressionExecutor leftExpressionExecutor = parseExpression(
                            leftExpression, metaEvent, currentState,
                            tableMap, executorList, groupBy, defaultStreamEventIndex,
                            processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                    ExpressionExecutor rightExpressionExecutor = parseExpression(
                            rightExpression, metaEvent, currentState,
                            tableMap, executorList, groupBy, defaultStreamEventIndex,
                            processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                    return parseEqualCompare(leftExpressionExecutor, rightExpressionExecutor);
                } else if (((Compare) expression).getOperator() == Compare.Operator.NOT_EQUAL) {
                    return parseNotEqualCompare(
                            parseExpression(((Compare) expression).getLeftExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext),
                            parseExpression(((Compare) expression).getRightExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext));
                } else if (((Compare) expression).getOperator() == Compare.Operator.GREATER_THAN) {
                    return parseGreaterThanCompare(
                            parseExpression(((Compare) expression).getLeftExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext),
                            parseExpression(((Compare) expression).getRightExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext));
                } else if (((Compare) expression).getOperator() == Compare.Operator.GREATER_THAN_EQUAL) {
                    return parseGreaterThanEqualCompare(
                            parseExpression(((Compare) expression).getLeftExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext),
                            parseExpression(((Compare) expression).getRightExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext));
                } else if (((Compare) expression).getOperator() == Compare.Operator.LESS_THAN) {
                    return parseLessThanCompare(
                            parseExpression(((Compare) expression).getLeftExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext),
                            parseExpression(((Compare) expression).getRightExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext));
                } else if (((Compare) expression).getOperator() == Compare.Operator.LESS_THAN_EQUAL) {
                    return parseLessThanEqualCompare(
                            parseExpression(((Compare) expression).getLeftExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext),
                            parseExpression(((Compare) expression).getRightExpression(), metaEvent, currentState,
                                    tableMap, executorList, groupBy, defaultStreamEventIndex,
                                    processingMode, outputExpectsExpiredEvents, siddhiQueryContext));
                }

            } else if (expression instanceof Constant) {
                if (expression instanceof BoolConstant) {
                    return new ConstantExpressionExecutor(((BoolConstant) expression).getValue(), Attribute.Type.BOOL);
                } else if (expression instanceof StringConstant) {
                    return new ConstantExpressionExecutor(((StringConstant) expression).getValue(), Attribute.Type.STRING);
                } else if (expression instanceof IntConstant) {
                    return new ConstantExpressionExecutor(((IntConstant) expression).getValue(), Attribute.Type.INT);
                } else if (expression instanceof LongConstant) {
                    return new ConstantExpressionExecutor(((LongConstant) expression).getValue(), Attribute.Type.LONG);
                } else if (expression instanceof FloatConstant) {
                    return new ConstantExpressionExecutor(((FloatConstant) expression).getValue(), Attribute.Type.FLOAT);
                } else if (expression instanceof DoubleConstant) {
                    return new ConstantExpressionExecutor(((DoubleConstant) expression).getValue(), Attribute.Type.DOUBLE);
                }

            } else if (expression instanceof Variable) {
                return parseVariable((Variable) expression, metaEvent, currentState, executorList,
                        defaultStreamEventIndex, siddhiQueryContext);

            } else if (expression instanceof Multiply) {
                ExpressionExecutor left = parseExpression(((Multiply) expression).getLeftValue(), metaEvent,
                        currentState, tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                ExpressionExecutor right = parseExpression(((Multiply) expression).getRightValue(), metaEvent,
                        currentState, tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                Attribute.Type type = parseArithmeticOperationResultType(left, right);
                switch (type) {
                    case INT:
                        return new MultiplyExpressionExecutorInt(left, right);
                    case LONG:
                        return new MultiplyExpressionExecutorLong(left, right);
                    case FLOAT:
                        return new MultiplyExpressionExecutorFloat(left, right);
                    case DOUBLE:
                        return new MultiplyExpressionExecutorDouble(left, right);
                    default: // Will not happen. Handled in parseArithmeticOperationResultType()
                }
            } else if (expression instanceof Add) {
                ExpressionExecutor left = parseExpression(((Add) expression).getLeftValue(), metaEvent, currentState,
                        tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                ExpressionExecutor right = parseExpression(((Add) expression).getRightValue(), metaEvent, currentState,
                        tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                Attribute.Type type = parseArithmeticOperationResultType(left, right);
                switch (type) {
                    case INT:
                        return new AddExpressionExecutorInt(left, right);
                    case LONG:
                        return new AddExpressionExecutorLong(left, right);
                    case FLOAT:
                        return new AddExpressionExecutorFloat(left, right);
                    case DOUBLE:
                        return new AddExpressionExecutorDouble(left, right);
                    default: // Will not happen. Handled in parseArithmeticOperationResultType()
                }
            } else if (expression instanceof Subtract) {
                ExpressionExecutor left = parseExpression(((Subtract) expression).getLeftValue(), metaEvent,
                        currentState, tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                ExpressionExecutor right = parseExpression(((Subtract) expression).getRightValue(), metaEvent,
                        currentState, tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                Attribute.Type type = parseArithmeticOperationResultType(left, right);
                switch (type) {
                    case INT:
                        return new SubtractExpressionExecutorInt(left, right);
                    case LONG:
                        return new SubtractExpressionExecutorLong(left, right);
                    case FLOAT:
                        return new SubtractExpressionExecutorFloat(left, right);
                    case DOUBLE:
                        return new SubtractExpressionExecutorDouble(left, right);
                    default: // Will not happen. Handled in parseArithmeticOperationResultType()
                }
            } else if (expression instanceof Mod) {
                ExpressionExecutor left = parseExpression(((Mod) expression).getLeftValue(), metaEvent, currentState,
                        tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                ExpressionExecutor right = parseExpression(((Mod) expression).getRightValue(), metaEvent, currentState,
                        tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                Attribute.Type type = parseArithmeticOperationResultType(left, right);
                switch (type) {
                    case INT:
                        return new ModExpressionExecutorInt(left, right);
                    case LONG:
                        return new ModExpressionExecutorLong(left, right);
                    case FLOAT:
                        return new ModExpressionExecutorFloat(left, right);
                    case DOUBLE:
                        return new ModExpressionExecutorDouble(left, right);
                    default: // Will not happen. Handled in parseArithmeticOperationResultType()
                }
            } else if (expression instanceof Divide) {
                ExpressionExecutor left = parseExpression(((Divide) expression).getLeftValue(), metaEvent, currentState,
                        tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                ExpressionExecutor right = parseExpression(((Divide) expression).getRightValue(), metaEvent, currentState,
                        tableMap, executorList, groupBy, defaultStreamEventIndex,
                        processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                Attribute.Type type = parseArithmeticOperationResultType(left, right);
                switch (type) {
                    case INT:
                        return new DivideExpressionExecutorInt(left, right);
                    case LONG:
                        return new DivideExpressionExecutorLong(left, right);
                    case FLOAT:
                        return new DivideExpressionExecutorFloat(left, right);
                    case DOUBLE:
                        return new DivideExpressionExecutorDouble(left, right);
                    default: // Will not happen. Handled in parseArithmeticOperationResultType()
                }

            } else if (expression instanceof AttributeFunction) {
                // extensions
                Object executor;
                try {
                    if ((siddhiQueryContext.getSiddhiAppContext().isFunctionExist(
                            ((AttributeFunction) expression).getName()))
                            && (((AttributeFunction) expression).getNamespace()).isEmpty()) {
                        executor = new ScriptFunctionExecutor(((AttributeFunction) expression).getName());
                    } else {
                        executor = SiddhiClassLoader.loadExtensionImplementation((AttributeFunction) expression,
                                FunctionExecutorExtensionHolder.getInstance(siddhiQueryContext.getSiddhiAppContext()));
                    }
                } catch (SiddhiAppCreationException ex) {
                    try {
                        executor = SiddhiClassLoader.loadExtensionImplementation((AttributeFunction) expression,
                                AttributeAggregatorExtensionHolder.getInstance(siddhiQueryContext.getSiddhiAppContext()));
                    } catch (SiddhiAppCreationException e) {
                        throw new ExtensionNotFoundException("'" + ((AttributeFunction) expression).getName() + "' is"
                                + " neither a function extension nor an aggregated attribute extension",
                                expression.getQueryContextStartIndex(), expression.getQueryContextEndIndex());
                    }
                }
                ConfigReader configReader = siddhiQueryContext.getSiddhiContext().getConfigManager().generateConfigReader(
                        ((AttributeFunction) expression).getNamespace(), ((AttributeFunction) expression).getName());
                if (executor instanceof FunctionExecutor) {
                    FunctionExecutor expressionExecutor = (FunctionExecutor) executor;
                    Expression[] innerExpressions = ((AttributeFunction) expression).getParameters();
                    ExpressionExecutor[] innerExpressionExecutors = parseInnerExpression(innerExpressions, metaEvent,
                            currentState, tableMap, executorList, groupBy, defaultStreamEventIndex,
                            processingMode, outputExpectsExpiredEvents, siddhiQueryContext);

                    expressionExecutor.initExecutor(innerExpressionExecutors,
                            processingMode, configReader, groupBy, siddhiQueryContext);
                    if (expressionExecutor.getReturnType() == Attribute.Type.BOOL) {
                        return new BoolConditionExpressionExecutor(expressionExecutor);
                    }
                    return expressionExecutor;
                } else {
                    AttributeAggregatorExecutor attributeAggregatorExecutor = (AttributeAggregatorExecutor) executor;
                    Expression[] innerExpressions = ((AttributeFunction) expression).getParameters();
                    ExpressionExecutor[] innerExpressionExecutors = parseInnerExpression(innerExpressions, metaEvent,
                            currentState, tableMap, executorList, groupBy, defaultStreamEventIndex,
                            processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                    attributeAggregatorExecutor.initAggregator(innerExpressionExecutors, processingMode,
                            outputExpectsExpiredEvents, configReader, groupBy, siddhiQueryContext);
//                    AbstractAggregationAttributeExecutor aggregationAttributeProcessor;
//                    if (groupBy) {
//                        aggregationAttributeProcessor = new GroupByAggregationAttributeExecutor(attributeAggregatorExecutor,
//                                innerExpressionExecutors, configReader, siddhiQueryContext);
//                    } else {
//                        aggregationAttributeProcessor = new AggregationAttributeExecutor(attributeAggregatorExecutor,
//                                innerExpressionExecutors, siddhiQueryContext);
//                    }
                    SelectorParser.getContainsAggregatorThreadLocal().set("true");
                    return attributeAggregatorExecutor;
                }
            } else if (expression instanceof In) {

                Table table = tableMap.get(((In) expression).getSourceId());
                MatchingMetaInfoHolder matchingMetaInfoHolder = MatcherParser.constructMatchingMetaStateHolder(
                        metaEvent, defaultStreamEventIndex, table.getTableDefinition(), defaultStreamEventIndex);
                CompiledCondition compiledCondition = table.compileCondition(((In) expression).getExpression(),
                        matchingMetaInfoHolder, executorList, tableMap, siddhiQueryContext);
                return new InConditionExpressionExecutor(table, compiledCondition,
                        matchingMetaInfoHolder.getMetaStateEvent().getMetaStreamEvents().length,
                        metaEvent instanceof StateEvent, 0);

            } else if (expression instanceof IsNull) {

                IsNull isNull = (IsNull) expression;

                if (isNull.getExpression() != null) {
                    ExpressionExecutor innerExpressionExecutor = parseExpression(isNull.getExpression(), metaEvent,
                            currentState, tableMap, executorList, groupBy, defaultStreamEventIndex,
                            processingMode, outputExpectsExpiredEvents, siddhiQueryContext);
                    return new IsNullConditionExpressionExecutor(innerExpressionExecutor);
                } else {
                    String streamId = isNull.getStreamId();
                    Integer streamIndex = isNull.getStreamIndex();

                    if (metaEvent instanceof MetaStateEvent) {
                        int[] eventPosition = new int[2];
                        if (streamIndex != null) {
                            if (streamIndex <= SiddhiConstants.LAST) {
                                eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN] = streamIndex + 1;
                            } else {
                                eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN] = streamIndex;
                            }
                        } else {
                            eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN] = defaultStreamEventIndex;
                        }
                        eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = SiddhiConstants.UNKNOWN_STATE;

                        MetaStateEvent metaStateEvent = (MetaStateEvent) metaEvent;
                        if (streamId == null) {
                            throw new SiddhiAppCreationException("IsNull does not support streamId being null",
                                    expression.getQueryContextStartIndex(), expression.getQueryContextEndIndex());
                        } else {
                            MetaStreamEvent[] metaStreamEvents = metaStateEvent.getMetaStreamEvents();
                            for (int i = 0, metaStreamEventsLength = metaStreamEvents.length; i < metaStreamEventsLength; i++) {
                                MetaStreamEvent metaStreamEvent = metaStreamEvents[i];
                                AbstractDefinition definition = metaStreamEvent.getLastInputDefinition();
                                if (metaStreamEvent.getInputReferenceId() == null) {
                                    if (definition.getId().equals(streamId)) {
                                        eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = i;
                                        break;
                                    }
                                } else {
                                    if (metaStreamEvent.getInputReferenceId().equals(streamId)) {
                                        eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = i;
                                        if (currentState > -1
                                                && metaStreamEvents[currentState].getInputReferenceId() != null
                                                && streamIndex != null && streamIndex <= SiddhiConstants.LAST) {
                                            if (streamId.equals(metaStreamEvents[currentState].getInputReferenceId())) {
                                                eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN] = streamIndex;
                                            }
                                        }
                                        break;
                                    }
                                }
                            }
                        }
                        return new IsNullStreamConditionExpressionExecutor(eventPosition);
                    } else {
                        return new IsNullStreamConditionExpressionExecutor(null);
                    }

                }
            }
            throw new UnsupportedOperationException(expression.toString() + " not supported!");
        } catch (Throwable t) {
            ExceptionUtil.populateQueryContext(t, expression, siddhiQueryContext.getSiddhiAppContext(),
                    siddhiQueryContext);
            throw t;
        }
    }
Parse the given expression and create the appropriate Executor by recursively traversing the expression

@param expression                 Expression to be parsed
@param metaEvent                  Meta Event
@param currentState               Current state number
@param tableMap                   Event Table Map
@param executorList               List to hold VariableExpressionExecutors to update after query parsing
@param groupBy                    is for groupBy expression
@param defaultStreamEventIndex    Default StreamEvent Index
@param processingMode             processing mode of the query
@param outputExpectsExpiredEvents is expired events sent as output
@param siddhiQueryContext         current siddhi query context
@return ExpressionExecutor
modules/siddhi-core/src/main/java/io/siddhi/core/util/parser/ExpressionParser.java