001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.k2js.translate.utils.dangerous;
018    
019    import com.google.common.collect.Maps;
020    import com.intellij.psi.PsiElement;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.jet.lang.psi.*;
023    
024    import java.util.Map;
025    
026    import static org.jetbrains.k2js.translate.utils.PsiUtils.getBaseExpression;
027    
028    //TODO: refactor
029    public final class FindPreviousVisitor extends JetTreeVisitor<DangerousData> {
030    
031        @NotNull
032        private final Map<JetElement, Void> hasDangerous = Maps.newHashMap();
033    
034        public FindPreviousVisitor(@NotNull DangerousData data) {
035            JetElement node = data.getDangerousNode();
036            PsiElement last = data.getRootNode().getParent();
037            while (node != last) {
038                hasDangerous.put(node, null);
039                PsiElement parent = node.getParent();
040                assert parent instanceof JetElement;
041                node = (JetElement)parent;
042            }
043        }
044    
045        @Override
046        public Void visitJetElement(JetElement element, DangerousData data) {
047            if (data.getDangerousNode() == element) {
048                return null;
049            }
050            if (!hasDangerous(element)) {
051                addElement(element, data);
052            }
053            else {
054                acceptChildrenThatAreBeforeTheDangerousNode(element, data);
055            }
056            return null;
057        }
058    
059        //TODO: return value not used, wtf?
060        private static boolean addElement(@NotNull JetElement element, @NotNull DangerousData data) {
061            if (element instanceof JetExpression) {
062                data.getNodesToBeGeneratedBefore().add((JetExpression)element);
063                return true;
064            }
065            return false;
066        }
067    
068        private void acceptChildrenThatAreBeforeTheDangerousNode(@NotNull JetElement element, @NotNull DangerousData data) {
069            PsiElement current = element.getFirstChild();
070            while (current != null) {
071                if (current instanceof JetElement) {
072                    ((JetElement)current).accept(this, data);
073                    if (hasDangerous(element)) {
074                        break;
075                    }
076                }
077                current = current.getNextSibling();
078            }
079        }
080    
081        @Override
082        public Void visitPrefixExpression(@NotNull JetPrefixExpression expression, @NotNull DangerousData data) {
083            if (data.getDangerousNode() == expression) {
084                return null;
085            }
086            if (!hasDangerous(expression)) {
087                addElement(expression, data);
088                return null;
089            }
090            else {
091                if (hasDangerous(getBaseExpression(expression))) {
092                    return null;
093                }
094                else {
095                    //TODO:
096                    throw new IllegalStateException();
097                }
098            }
099        }
100    
101        @Override
102        public Void visitCallExpression(@NotNull JetCallExpression expression, @NotNull DangerousData data) {
103            if (data.getDangerousNode() == expression) {
104                return null;
105            }
106            if (!hasDangerous(expression)) {
107                data.getNodesToBeGeneratedBefore().add(expression);
108            }
109            else {
110                acceptArgumentsThatAreBeforeDangerousNode(expression, data);
111            }
112            return null;
113        }
114    
115        private void acceptArgumentsThatAreBeforeDangerousNode(@NotNull JetCallExpression expression, @NotNull DangerousData data) {
116            for (ValueArgument argument : expression.getValueArguments()) {
117                JetExpression argumentExpression = argument.getArgumentExpression();
118                assert argumentExpression != null;
119                argumentExpression.accept(this, data);
120                if (hasDangerous(argumentExpression)) {
121                    break;
122                }
123            }
124        }
125    
126        private boolean hasDangerous(@NotNull JetElement element) {
127            return hasDangerous.containsKey(element);
128        }
129    }