org.elasticsearch.plan.a.Adapter.java Source code

Java tutorial

Introduction

Here is the source code for org.elasticsearch.plan.a.Adapter.java

Source

package org.elasticsearch.plan.a;

/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import static org.elasticsearch.plan.a.Caster.*;
import static org.elasticsearch.plan.a.Default.*;
import static org.elasticsearch.plan.a.Definition.*;
import static org.elasticsearch.plan.a.PlanAParser.*;

class Adapter {
    static class Variable {
        final String name;
        final Type type;
        final int slot;

        private Variable(final String name, final Type type, final int slot) {
            this.name = name;
            this.type = type;
            this.slot = slot;
        }
    }

    static class StatementMetadata {
        final ParserRuleContext source;

        boolean allExit;
        boolean allReturn;
        boolean anyReturn;
        boolean allBreak;
        boolean anyBreak;
        boolean allContinue;
        boolean anyContinue;

        private StatementMetadata(final ParserRuleContext source) {
            this.source = source;

            allExit = false;
            allReturn = false;
            anyReturn = false;
            allBreak = false;
            anyBreak = false;
            allContinue = false;
            anyContinue = false;
        }
    }

    static class ExpressionMetadata {
        final ParserRuleContext source;

        boolean statement;

        Object preConst;
        Object postConst;
        boolean isNull;

        Type to;
        Type from;
        Promotion promotion;
        boolean explicit;

        Cast cast;

        private ExpressionMetadata(final ParserRuleContext source) {
            this.source = source;

            statement = false;

            preConst = null;
            postConst = null;
            isNull = false;

            to = null;
            from = null;
            promotion = null;
            explicit = false;

            cast = null;
        }
    }

    static class Branch {
        final ParserRuleContext source;

        Label begin;
        Label end;
        Label tru;
        Label fals;

        private Branch(final ParserRuleContext source) {
            this.source = source;

            begin = null;
            end = null;
            tru = null;
            fals = null;
        }
    }

    static String error(final ParserRuleContext ctx) {
        return "Error [" + ctx.getStart().getLine() + ":" + ctx.getStart().getCharPositionInLine() + "]: ";
    }

    final Definition definition;
    final Standard standard;
    final Caster caster;
    final String source;
    final ParserRuleContext root;

    private final Deque<Integer> scopes;
    private final Deque<Variable> variables;

    private final Map<ParserRuleContext, StatementMetadata> statementMetadata;
    private final Map<ParserRuleContext, ExpressionMetadata> expressionMetadata;
    private final Map<ParserRuleContext, External> externals;

    private final Map<ParserRuleContext, Branch> branches;
    private final Deque<Branch> jumps;
    private final Set<ParserRuleContext> strings;

    Adapter(final Definition definition, final Standard standard, final Caster caster, final String source,
            final ParserRuleContext root) {
        this.definition = definition;
        this.standard = standard;
        this.caster = caster;
        this.source = source;
        this.root = root;

        scopes = new ArrayDeque<>();
        variables = new ArrayDeque<>();

        statementMetadata = new HashMap<>();
        expressionMetadata = new HashMap<>();
        externals = new HashMap<>();

        branches = new HashMap<>();
        jumps = new ArrayDeque<>();
        strings = new HashSet<>();
    }

    void incrementScope() {
        scopes.push(0);
    }

    void decrementScope() {
        int remove = scopes.pop();

        while (remove > 0) {
            variables.pop();
            --remove;
        }
    }

    Variable getVariable(final String name) {
        final Iterator<Variable> itr = variables.iterator();

        while (itr.hasNext()) {
            final Variable variable = itr.next();

            if (variable.name.equals(name)) {
                return variable;
            }
        }

        return null;
    }

    Variable addVariable(final ParserRuleContext source, final String name, final Type type) {
        if (getVariable(name) != null) {
            if (source == null) {
                throw new IllegalArgumentException(
                        "Argument name [" + name + "] already defined within the scope.");
            } else {
                throw new IllegalArgumentException(
                        error(source) + "Variable name [" + name + "] already defined within the scope.");
            }
        }

        final Variable previous = variables.peekFirst();
        int slot = 0;

        if (previous != null) {
            slot += previous.slot + previous.type.metadata.size;
        }

        final Variable variable = new Variable(name, type, slot);
        variables.push(variable);

        final int update = scopes.pop() + 1;
        scopes.push(update);

        return variable;
    }

    StatementMetadata createStatementMetadata(final ParserRuleContext source) {
        final StatementMetadata sourcesmd = new StatementMetadata(source);
        statementMetadata.put(source, sourcesmd);

        return sourcesmd;
    }

    StatementMetadata getStatementMetadata(final ParserRuleContext source) {
        final StatementMetadata sourcesmd = statementMetadata.get(source);

        if (sourcesmd == null) {
            throw new IllegalStateException(error(source) + "Statement metadata does not exist at"
                    + " the parse node with text [" + source.getText() + "].");
        }

        return sourcesmd;
    }

    ExpressionContext getExpressionContext(ExpressionContext source) {
        if (source instanceof PrecedenceContext) {
            final ParserRuleContext parent = source.getParent();
            int index = 0;

            for (final ParseTree child : parent.children) {
                if (child == source) {
                    break;
                }

                ++index;
            }

            while (source instanceof PrecedenceContext) {
                source = ((PrecedenceContext) source).expression();
            }

            parent.children.set(index, source);
        }

        return source;
    }

    ExpressionMetadata createExpressionMetadata(ParserRuleContext source) {
        final ExpressionMetadata sourceemd = new ExpressionMetadata(source);
        expressionMetadata.put(source, sourceemd);

        return sourceemd;
    }

    ExpressionMetadata getExpressionMetadata(final ParserRuleContext source) {
        final ExpressionMetadata sourceemd = expressionMetadata.get(source);

        if (sourceemd == null) {
            throw new IllegalStateException(error(source) + "Expression metadata does not exist at"
                    + " the parse node with text [" + source.getText() + "].");
        }

        return sourceemd;
    }

    void putExternal(final ParserRuleContext source, final External external) {
        externals.put(source, external);
    }

    External getExternal(final ParserRuleContext source) {
        final External external = externals.get(source);

        if (external == null) {
            throw new IllegalStateException(error(source) + "External data does not exist at"
                    + " the parse node with text [" + source.getText() + "].");
        }

        return external;
    }

    Branch markBranch(final ParserRuleContext source, final ParserRuleContext... nodes) {
        final Branch branch = new Branch(source);

        for (final ParserRuleContext node : nodes) {
            branches.put(node, branch);
        }

        return branch;
    }

    Branch getBranch(final ParserRuleContext source) {
        return branches.get(source);
    }

    void checkWriteBranch(final MethodVisitor visitor, final ParserRuleContext source) {
        final Branch branch = getBranch(source);

        if (branch != null) {
            if (branch.tru != null) {
                visitor.visitJumpInsn(Opcodes.IFNE, branch.tru);
            } else if (branch.fals != null) {
                visitor.visitJumpInsn(Opcodes.IFEQ, branch.fals);
            }
        }
    }

    void pushJump(final Branch branch) {
        jumps.push(branch);
    }

    Branch peekJump() {
        return jumps.peek();
    }

    void popJump() {
        jumps.pop();
    }

    void markStrings(final ParserRuleContext node) {
        strings.add(node);
    }

    void unmarkStrings(final ParserRuleContext node) {
        strings.remove(node);
    }

    boolean getStrings(final ParserRuleContext node) {
        return strings.contains(node);
    }
}