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 017package org.jetbrains.k2js.translate.utils.dangerous; 018 019import com.google.common.collect.Lists; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.psi.JetBlockExpression; 023import org.jetbrains.jet.lang.psi.JetElement; 024import org.jetbrains.jet.lang.psi.JetExpression; 025import org.jetbrains.k2js.translate.context.TranslationContext; 026 027import java.util.List; 028 029/** 030 * This module uses a methaphor for naming. 031 * <p/> 032 * Dangerous are the nodes that can be expressions in Kotlin but can't be expressions in JavaScript. 033 * These are: when, if, inlined functions. 034 * The issue with them is that we have to translate them to a list of statements. And also all the expressions which must be computed before 035 * the dangerous expressions. 036 * RootNode is a node which contains such an expression. For example, it may be a statement expression belongs to. 037 */ 038public class DangerousData { 039 @NotNull 040 private final List<JetExpression> nodesToBeGeneratedBefore = Lists.newArrayList(); 041 042 043 @NotNull 044 public static DangerousData collect(@NotNull JetExpression expression, @NotNull TranslationContext context) { 045 if (cantContainDangerousElements(expression)) { 046 return emptyData(); 047 } 048 return doCollectData(expression, context); 049 } 050 051 private static boolean cantContainDangerousElements(@NotNull JetElement element) { 052 return element instanceof JetBlockExpression; 053 } 054 055 @NotNull 056 private static DangerousData doCollectData(@NotNull JetExpression expression, 057 @NotNull TranslationContext context) { 058 DangerousData data = new DangerousData(); 059 FindDangerousVisitor visitor = new FindDangerousVisitor(context); 060 expression.accept(visitor, data); 061 if (!data.exists()) { 062 return emptyData(); 063 } 064 data.setRootNode(expression); 065 FindPreviousVisitor findPreviousVisitor = new FindPreviousVisitor(data); 066 expression.accept(findPreviousVisitor, data); 067 return data; 068 } 069 070 private static final DangerousData EMPTY = new DangerousData() { 071 @Override 072 public boolean exists() { 073 return false; 074 } 075 076 @Override 077 public boolean shouldBeTranslated() { 078 return false; 079 } 080 }; 081 082 @NotNull 083 public static DangerousData emptyData() { 084 return EMPTY; 085 } 086 087 @Nullable 088 private JetExpression dangerousNode = null; 089 090 @Nullable 091 private JetExpression rootNode = null; 092 093 public void setDangerousNode(@NotNull JetExpression dangerousNode) { 094 assert this.dangerousNode == null : "Should be assigned only once"; 095 this.dangerousNode = dangerousNode; 096 } 097 098 @NotNull 099 public List<JetExpression> getNodesToBeGeneratedBefore() { 100 return nodesToBeGeneratedBefore; 101 } 102 103 public boolean exists() { 104 return dangerousNode != null; 105 } 106 107 public boolean shouldBeTranslated() { 108 return exists() && !nodesToBeGeneratedBefore.isEmpty(); 109 } 110 111 @NotNull 112 public JetExpression getDangerousNode() { 113 assert dangerousNode != null; 114 return dangerousNode; 115 } 116 117 @NotNull 118 public JetExpression getRootNode() { 119 assert rootNode != null; 120 return rootNode; 121 } 122 123 @SuppressWarnings("NullableProblems") 124 public void setRootNode(@NotNull JetExpression rootNode) { 125 this.rootNode = rootNode; 126 } 127}