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.context;
018
019 import com.google.dart.compiler.backend.js.ast.*;
020 import com.intellij.psi.PsiElement;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
024 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
025 import org.jetbrains.jet.lang.descriptors.Named;
026 import org.jetbrains.jet.lang.psi.JetExpression;
027 import org.jetbrains.jet.lang.resolve.BindingContext;
028 import org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator;
029 import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
030
031 import java.util.HashMap;
032 import java.util.Map;
033
034 import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForElement;
035
036 /**
037 * All the info about the state of the translation process.
038 */
039 public class TranslationContext {
040 @NotNull
041 private final DynamicContext dynamicContext;
042 @NotNull
043 private final StaticContext staticContext;
044 @NotNull
045 private final AliasingContext aliasingContext;
046
047 @NotNull
048 public static TranslationContext rootContext(@NotNull StaticContext staticContext) {
049 JsProgram program = staticContext.getProgram();
050 JsBlock globalBlock = program.getGlobalBlock();
051 DynamicContext rootDynamicContext = DynamicContext.rootContext(staticContext.getRootScope(), globalBlock);
052 AliasingContext rootAliasingContext = AliasingContext.getCleanContext();
053 return new TranslationContext(staticContext,
054 rootDynamicContext, rootAliasingContext);
055 }
056
057 private final HashMap<JsExpression, TemporaryConstVariable> expressionToTempConstVariableCache = new HashMap<JsExpression, TemporaryConstVariable>();
058
059 public boolean isEcma5() {
060 return staticContext.isEcma5();
061 }
062
063 private TranslationContext(@NotNull StaticContext staticContext,
064 @NotNull DynamicContext dynamicContext,
065 @NotNull AliasingContext aliasingContext) {
066 this.dynamicContext = dynamicContext;
067 this.staticContext = staticContext;
068 this.aliasingContext = aliasingContext;
069 }
070
071 private TranslationContext(@NotNull TranslationContext parent, @NotNull AliasingContext aliasingContext) {
072 dynamicContext = parent.dynamicContext;
073 staticContext = parent.staticContext;
074 this.aliasingContext = aliasingContext;
075 }
076
077 public DynamicContext dynamicContext() {
078 return dynamicContext;
079 }
080
081 @NotNull
082 private TranslationContext contextWithScope(@NotNull JsScope newScope, @NotNull JsBlock block) {
083 return contextWithScope(newScope, block, aliasingContext);
084 }
085
086 @NotNull
087 public TranslationContext contextWithScope(@NotNull JsFunction fun) {
088 return contextWithScope(fun, aliasingContext);
089 }
090
091 @NotNull
092 protected TranslationContext contextWithScope(@NotNull JsScope newScope, @NotNull JsBlock block, @NotNull AliasingContext aliasingContext) {
093 return new TranslationContext(staticContext, DynamicContext.newContext(newScope, block), aliasingContext);
094 }
095
096 @NotNull
097 public TranslationContext contextWithScope(@NotNull JsFunction fun, @NotNull AliasingContext aliasingContext) {
098 return contextWithScope(fun.getScope(), fun.getBody(), aliasingContext);
099 }
100
101 @NotNull
102 public TranslationContext innerBlock(@NotNull JsBlock block) {
103 return new TranslationContext(staticContext, dynamicContext.innerBlock(block), aliasingContext);
104 }
105
106 @NotNull
107 public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor) {
108 return contextWithScope(getScopeForDescriptor(descriptor), getBlockForDescriptor(descriptor));
109 }
110
111 @NotNull
112 public TranslationContext innerContextWithThisAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsName alias) {
113 return new TranslationContext(this, aliasingContext.inner(correspondingDescriptor, alias));
114 }
115
116 @NotNull
117 public TranslationContext innerContextWithAliasesForExpressions(@NotNull Map<JetExpression, JsName> aliases) {
118 return new TranslationContext(this, aliasingContext.withAliasesForExpressions(aliases));
119 }
120
121 @NotNull
122 public TranslationContext innerContextWithDescriptorsAliased(@NotNull Map<DeclarationDescriptor, JsName> aliases) {
123 return new TranslationContext(this, aliasingContext.withDescriptorsAliased(aliases));
124 }
125
126 @NotNull
127 public JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) {
128 if (descriptor instanceof CallableDescriptor) {
129 return getFunctionObject((CallableDescriptor)descriptor).getBody();
130 }
131 else {
132 return new JsBlock();
133 }
134 }
135
136 @NotNull
137 public TranslationContext newDeclaration(@NotNull PsiElement element) {
138 return newDeclaration(getDescriptorForElement(bindingContext(), element));
139 }
140
141 @NotNull
142 public BindingContext bindingContext() {
143 return staticContext.getBindingContext();
144 }
145
146 @NotNull
147 public JsScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) {
148 return staticContext.getScopeForDescriptor(descriptor);
149 }
150
151 @NotNull
152 public JsName getNameForElement(@NotNull PsiElement element) {
153 DeclarationDescriptor descriptor = getDescriptorForElement(bindingContext(), element);
154 return getNameForDescriptor(descriptor);
155 }
156
157 @NotNull
158 public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
159 JsName alias = aliasingContext.getAliasForDescriptor(descriptor);
160 if (alias != null) {
161 return alias;
162 }
163 return staticContext.getNameForDescriptor(descriptor);
164 }
165
166 //TODO: util
167 @NotNull
168 public JsStringLiteral nameToLiteral(@NotNull Named named) {
169 return program().getStringLiteral(named.getName().asString());
170 }
171
172 @Nullable
173 public JsNameRef getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) {
174 return staticContext.getQualifierForDescriptor(descriptor);
175 }
176
177 //TODO: review all invocation with notnull parameters
178 @NotNull
179 public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) {
180 return dynamicContext.declareTemporary(initExpression);
181 }
182
183 @NotNull
184 public TemporaryConstVariable getOrDeclareTemporaryConstVariable(@NotNull JsExpression expression) {
185 TemporaryConstVariable tempVar = expressionToTempConstVariableCache.get(expression);
186
187 if (tempVar == null) {
188 TemporaryVariable tmpVar = declareTemporary(expression);
189
190 tempVar = new TemporaryConstVariable(tmpVar.name(), tmpVar.assignmentExpression());
191
192 expressionToTempConstVariableCache.put(expression, tempVar);
193 expressionToTempConstVariableCache.put(tmpVar.assignmentExpression(), tempVar);
194 }
195
196 return tempVar;
197 }
198
199 public void associateExpressionToLazyValue(JsExpression expression, TemporaryConstVariable temporaryConstVariable) {
200 assert expression == temporaryConstVariable.assignmentExpression();
201 expressionToTempConstVariableCache.put(expression, temporaryConstVariable);
202 }
203
204 @NotNull
205 public Namer namer() {
206 return staticContext.getNamer();
207 }
208
209 @NotNull
210 public Intrinsics intrinsics() {
211 return staticContext.getIntrinsics();
212 }
213
214 @NotNull
215 public JsProgram program() {
216 return staticContext.getProgram();
217 }
218
219 @NotNull
220 public JsScope scope() {
221 return dynamicContext.getScope();
222 }
223
224 @NotNull
225 public AliasingContext aliasingContext() {
226 return aliasingContext;
227 }
228
229 @NotNull
230 public LiteralFunctionTranslator literalFunctionTranslator() {
231 return staticContext.getLiteralFunctionTranslator();
232 }
233
234 @NotNull
235 public JsFunction getFunctionObject(@NotNull CallableDescriptor descriptor) {
236 return staticContext.getFunctionWithScope(descriptor);
237 }
238
239 public void addStatementToCurrentBlock(@NotNull JsStatement statement) {
240 dynamicContext.jsBlock().getStatements().add(statement);
241 }
242
243 @NotNull
244 public AliasingContext.ThisAliasProvider thisAliasProvider() {
245 return aliasingContext().thisAliasProvider;
246 }
247
248 @NotNull
249 public JsExpression getThisObject(@NotNull DeclarationDescriptor descriptor) {
250 JsNameRef ref = thisAliasProvider().get(descriptor);
251 return ref == null ? JsLiteral.THIS : ref;
252 }
253 }