private static ExpressionExecutor parseVariable(Variable variable, MetaComplexEvent metaEvent,
                                                    int currentState,
                                                    List<VariableExpressionExecutor> executorList,
                                                    int defaultStreamEventIndex,
                                                    SiddhiQueryContext siddhiQueryContext) {
        String attributeName = variable.getAttributeName();
        int[] eventPosition = new int[2];
        if (variable.getStreamIndex() != null) {
            if (variable.getStreamIndex() <= SiddhiConstants.LAST) {
                eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN] = variable.getStreamIndex() + 1;
            } else {
                eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN] = variable.getStreamIndex();
            }
        } else {
            eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN] = defaultStreamEventIndex;
        }
        eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = SiddhiConstants.UNKNOWN_STATE;
        if (metaEvent instanceof MetaStreamEvent) {
            MetaStreamEvent metaStreamEvent = (MetaStreamEvent) metaEvent;
            AbstractDefinition abstractDefinition;
            Attribute.Type type;
            if (currentState == SiddhiConstants.HAVING_STATE) {
                abstractDefinition = metaStreamEvent.getOutputStreamDefinition();
                type = abstractDefinition.getAttributeType(attributeName);
                eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = SiddhiConstants.HAVING_STATE;
            } else {
                abstractDefinition = metaStreamEvent.getLastInputDefinition();
                type = abstractDefinition.getAttributeType(attributeName);
                ((MetaStreamEvent) metaEvent).addData(new Attribute(attributeName, type));
            }
            if (variable.getStreamId() != null && !variable.getStreamId().equals(abstractDefinition.getId())) {
                throw new SiddhiAppCreationException("Id '" + variable.getStreamId() + "' not defined within the " +
                        "current scope", variable, siddhiQueryContext.getSiddhiAppContext());
            }
            VariableExpressionExecutor variableExpressionExecutor = new VariableExpressionExecutor(
                    new Attribute(attributeName, type), eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX],
                    eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN]);
            if (((MetaStreamEvent) metaEvent).getEventType() != MetaStreamEvent.EventType.DEFAULT) {
                variableExpressionExecutor.getPosition()[SiddhiConstants.STREAM_ATTRIBUTE_TYPE_INDEX] =
                        SiddhiConstants.OUTPUT_DATA_INDEX;
                variableExpressionExecutor.getPosition()[SiddhiConstants.STREAM_ATTRIBUTE_INDEX_IN_TYPE] =
                        abstractDefinition
                                .getAttributePosition(variableExpressionExecutor.getAttribute().getName());
            }
            if (executorList != null) {
                executorList.add(variableExpressionExecutor);
            }
            return variableExpressionExecutor;
        } else {
            MetaStateEvent metaStateEvent = (MetaStateEvent) metaEvent;
            Attribute.Type type = null;
            AbstractDefinition definition = null;
            String firstInput = null;
            boolean multiValue = false;
            if (variable.getStreamId() == null) {
                MetaStreamEvent[] metaStreamEvents = metaStateEvent.getMetaStreamEvents();
                if (currentState == SiddhiConstants.HAVING_STATE) {
                    definition = metaStateEvent.getOutputStreamDefinition();
                    try {
                        type = definition.getAttributeType(attributeName);
                        eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = SiddhiConstants.HAVING_STATE;
                    } catch (AttributeNotExistException e) {
                        currentState = SiddhiConstants.UNKNOWN_STATE;
                    }
                }
                if (currentState == SiddhiConstants.UNKNOWN_STATE) {
                    for (int i = 0; i < metaStreamEvents.length; i++) {
                        MetaStreamEvent metaStreamEvent = metaStreamEvents[i];
                        definition = metaStreamEvent.getLastInputDefinition();
                        if (type == null) {
                            try {
                                type = definition.getAttributeType(attributeName);
                                firstInput = "Input Stream: " + definition.getId() + " with " + "reference: "
                                        + metaStreamEvent.getInputReferenceId();
                                eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = i;
                            } catch (AttributeNotExistException e) {
                                // do nothing
                            }
                        } else {
                            try {
                                definition.getAttributeType(attributeName);
                                throw new SiddhiAppValidationException(firstInput + " and Input Stream: "
                                        + definition.getId() + " with " + "reference: "
                                        + metaStreamEvent.getInputReferenceId() + " contains attribute " + "with same"
                                        + " name '" + attributeName + "'");
                            } catch (AttributeNotExistException e) {
                                // do nothing as its expected
                            }
                        }
                    }
                } else if (currentState >= 0) {
                    MetaStreamEvent metaStreamEvent = metaStreamEvents[currentState];
                    definition = metaStreamEvent.getLastInputDefinition();
                    try {
                        type = definition.getAttributeType(attributeName);
                        eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = currentState;
                    } catch (AttributeNotExistException e) {
                        ExpressionExecutor functionExecutor = constructEventExpressionExecutor(variable, currentState,
                                siddhiQueryContext, eventPosition, metaStateEvent);
                        if (functionExecutor != null) {
                            return functionExecutor;
                        }
                        throw new SiddhiAppValidationException(e.getMessageWithOutContext() + " Input stream '" +
                                definition.getId() + "' with reference '" +
                                metaStreamEvent.getInputReferenceId() + "' for attribute '" +
                                variable.getAttributeName() + "'", e,
                                e.getQueryContextStartIndex(), e.getQueryContextEndIndex());
                    }
                }
            } else {
                MetaStreamEvent[] metaStreamEvents = metaStateEvent.getMetaStreamEvents();
                for (int i = 0, metaStreamEventsLength = metaStreamEvents.length; i < metaStreamEventsLength; i++) {
                    MetaStreamEvent metaStreamEvent = metaStreamEvents[i];
                    definition = metaStreamEvent.getLastInputDefinition();
                    if (metaStreamEvent.getInputReferenceId() == null) {
                        if (definition.getId().equals(variable.getStreamId())) {
                            type = definition.getAttributeType(attributeName);
                            eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = i;
                            break;
                        }
                    } else {
                        if (metaStreamEvent.getInputReferenceId().equals(variable.getStreamId())) {
                            type = definition.getAttributeType(attributeName);
                            eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] = i;
                            if (currentState > -1 && metaStreamEvents[currentState].getInputReferenceId() != null
                                    && variable.getStreamIndex() != null
                                    && variable.getStreamIndex() <= SiddhiConstants.LAST) {
                                if (variable.getStreamId()
                                        .equals(metaStreamEvents[currentState].getInputReferenceId())) {
                                    eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN] =
                                            variable.getStreamIndex();
                                }
                            } else if (currentState == SiddhiConstants.UNKNOWN_STATE &&
                                    variable.getStreamIndex() == null) {
                                multiValue = metaStreamEvent.isMultiValue();
                            }
                            break;
                        }
                    }
                }
            }
            if (eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] == SiddhiConstants.UNKNOWN_STATE) {
                if (variable.getStreamId() == null) {
                    ExpressionExecutor functionExecutor = constructEventExpressionExecutor(variable, currentState, siddhiQueryContext, eventPosition, metaStateEvent);
                    if (functionExecutor != null) {
                        return functionExecutor;
                    }
                    throw new SiddhiAppValidationException(
                            "No matching stream reference found for attribute '" + variable.getAttributeName() + "'");
                } else {
                    throw new SiddhiAppValidationException(
                            "Stream with reference '" + variable.getStreamId() + "' not found for attribute '" +
                                    variable.getAttributeName() + "'");
                }
            }
            VariableExpressionExecutor variableExpressionExecutor = new VariableExpressionExecutor(
                    new Attribute(attributeName, type), eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX],
                    eventPosition[SiddhiConstants.STREAM_EVENT_INDEX_IN_CHAIN]);
            if (eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX] != SiddhiConstants.HAVING_STATE) {
                MetaStreamEvent metaStreamEvent = ((MetaStateEvent) metaEvent)
                        .getMetaStreamEvent(eventPosition[SiddhiConstants.STREAM_EVENT_CHAIN_INDEX]);
                if (metaStreamEvent.getEventType() != MetaStreamEvent.EventType.DEFAULT) {
                    variableExpressionExecutor.getPosition()[SiddhiConstants.STREAM_ATTRIBUTE_TYPE_INDEX] =
                            SiddhiConstants.OUTPUT_DATA_INDEX;
                    variableExpressionExecutor.getPosition()[SiddhiConstants.STREAM_ATTRIBUTE_INDEX_IN_TYPE] =
                            metaStreamEvent.getLastInputDefinition()
                                    .getAttributePosition(variableExpressionExecutor.getAttribute().getName());
                    for (Attribute attribute : metaStreamEvent.getLastInputDefinition().getAttributeList()) {
                        metaStreamEvent.addOutputData(new Attribute(attribute.getName(), attribute.getType()));
                    }
                }
                metaStreamEvent.addData(new Attribute(attributeName, type));
            }
            if (executorList != null) {
                executorList.add(variableExpressionExecutor);
            }
            if (multiValue) {
                FunctionExecutor functionExecutor = new MultiValueVariableFunctionExecutor();
                ExpressionExecutor[] innerExpressionExecutors = new ExpressionExecutor[]{variableExpressionExecutor};
                functionExecutor.initExecutor(innerExpressionExecutors,
                        ProcessingMode.BATCH, null, false, siddhiQueryContext);
                return functionExecutor;
            }
            return variableExpressionExecutor;
        }
    }
Parse and validate the given Siddhi variable and return a VariableExpressionExecutor

@param variable           Variable to be parsed
@param metaEvent          Meta event used to collect execution info of stream associated with query
@param currentState       Current State Number
@param executorList       List to hold VariableExpressionExecutors to update after query parsing @return
@param siddhiQueryContext Siddhi Query Context
@return VariableExpressionExecutor representing given variable
modules/siddhi-core/src/main/java/io/siddhi/core/util/parser/ExpressionParser.java