@Override
    public Object visitJoin_stream(@NotNull SiddhiQLParser.Join_streamContext ctx) {

//        join_stream
//        :left_source=join_source join right_source=join_source right_unidirectional=UNIDIRECTIONAL (ON expression)?
// 
//        |left_source=join_source join right_source=join_source (ON expression)? 
//        |left_source=join_source left_unidirectional=UNIDIRECTIONAL join right_source=join_source (ON expression)?
// 
//        ;

        SingleInputStream leftStream = (SingleInputStream) visit(ctx.left_source);
        SingleInputStream rightStream = (SingleInputStream) visit(ctx.right_source);
        JoinInputStream.Type joinType = (JoinInputStream.Type) visit(ctx.join());
        JoinInputStream.EventTrigger eventTrigger = null;
        Expression onCondition = null;
        Within within = null;
        Expression per = null;

        if (ctx.within_time_range() != null) {
            within = (Within) visit(ctx.within_time_range());
        }

        if (ctx.per() != null) {
            per = (Expression) visit(ctx.per());
        }

        if (ctx.expression() != null) {
            onCondition = (Expression) visit(ctx.expression());
        }

        if (ctx.right_unidirectional != null) {
            eventTrigger = JoinInputStream.EventTrigger.RIGHT;
        } else if (ctx.left_unidirectional != null) {
            eventTrigger = JoinInputStream.EventTrigger.LEFT;
        } else {
            eventTrigger = JoinInputStream.EventTrigger.ALL;
        }

        InputStream inputStream = InputStream.joinStream(leftStream, joinType, rightStream, onCondition,
                eventTrigger, within, per);
        populateQueryContext(inputStream, ctx);
        return inputStream;

    }
{@inheritDoc}
<p>The default implementation returns the result of calling
{@link #visitChildren} on {@code ctx}.</p>

@param ctx
modules/siddhi-query-compiler/src/main/java/io/siddhi/query/compiler/internal/SiddhiQLBaseVisitorImpl.java