All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.js.backend.ast.JsVisitorWithContextImpl Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2008 Google Inc.
 * 
 * Licensed 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.
 */

package org.jetbrains.kotlin.js.backend.ast;

/*
 * Taken from GWT project with modifications.
 * Original:
 *  repository: https://gwt.googlesource.com/gwt
 *  revision: e32bf0a95029165d9e6ab457c7ee7ca8b07b908c
 *  file: dev/core/src/com/google/gwt/dev/js/ast/JsModVisitor.java
 */

import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

/**
 * A visitor for iterating through and modifying an AST.
 */
public class JsVisitorWithContextImpl extends JsVisitorWithContext {

    protected final Stack> statementContexts = new Stack<>();

    public class ListContext extends JsContext {
        private List nodes;
        private int index;

        // Those are reset in every iteration of traverse()
        private final List previous = new SmartList<>();
        private final List next = new SmartList<>();
        private boolean removed = false;

        @Override
        public  void addPrevious(R node) {
            previous.add(node);
        }

        @Override
        public  void addNext(R node) {
            next.add(node);
        }

        @Override
        public void removeMe() {
            removed = true;
        }

        @Override
        public  void replaceMe(R node) {
            checkReplacement(nodes.get(index), node);
            nodes.set(index, node);
            removed = false;
        }
        
        @Nullable
        @Override
        public T getCurrentNode() {
            if (!removed && index < nodes.size()) {
                return nodes.get(index);
            }

            return null;
        }

        public void traverse(List nodes) {
            assert previous.isEmpty(): "addPrevious() was called before traverse()";
            assert next.isEmpty(): "addNext() was called before traverse()";
            this.nodes = nodes;

            for (index = 0; index < nodes.size(); index++) {
                removed = false;
                previous.clear();
                next.clear();
                doTraverse(getCurrentNode(), this);

                if (!previous.isEmpty()) {
                    nodes.addAll(index, previous);
                    index += previous.size();
                }

                if (removed) {
                    nodes.remove(index);
                    index--;
                }

                if (!next.isEmpty()) {
                    nodes.addAll(index + 1, next);
                    index += next.size();
                }
            }

            previous.clear();
            next.clear();
        }
    }

    private class LvalueContext extends NodeContext {
    }

    private class NodeContext extends JsContext {
        protected T node;

        @Override
        public void removeMe() {
            throw new UnsupportedOperationException();
        }

        @Override
        public  void replaceMe(R node) {
            checkReplacement(this.node, node);
            this.node = node;
        }

        @Nullable
        @Override
        public T getCurrentNode() {
            return node;
        }

        protected T traverse(T node) {
            this.node = node;
            doTraverse(node, this);
            return this.node;
        }
    }

    private static void checkReplacement(@SuppressWarnings("UnusedParameters") JsNode origNode, JsNode newNode) {
        if (newNode == null) throw new RuntimeException("Cannot replace with null");
    }

    @Override
    protected  T doAccept(T node) {
        return new NodeContext().traverse(node);
    }

    @Override
    protected JsExpression doAcceptLvalue(JsExpression expr) {
        return new LvalueContext().traverse(expr);
    }

    @Override
    protected  JsStatement doAcceptStatement(T statement) {
        List statements = new SmartList<>(statement);
        doAcceptStatementList(statements);

        if (statements.size() == 1) {
            return statements.get(0);
        }

        return new JsBlock(statements);
    }

    @Override
    protected void doAcceptStatementList(List statements) {
        ListContext context = new ListContext<>();
        statementContexts.push(context);
        context.traverse(statements);
        statementContexts.pop();
    }

    @Override
    protected  void doAcceptList(List collection) {
        new ListContext().traverse(collection);
    }

    @NotNull
    protected JsContext getLastStatementLevelContext() {
        return statementContexts.peek();
    }

    @Override
    protected  void doTraverse(T node, JsContext ctx) {
        node.traverse(this, ctx);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy