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.MemberDescriptor; 026 import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; 027 import org.jetbrains.jet.lang.diagnostics.DiagnosticSink; 028 import org.jetbrains.jet.lang.psi.JetExpression; 029 import org.jetbrains.jet.lang.reflect.ReflectionTypes; 030 import org.jetbrains.jet.lang.resolve.BindingContext; 031 import org.jetbrains.jet.lang.resolve.BindingTraceContext; 032 import org.jetbrains.jet.lang.resolve.name.FqName; 033 import org.jetbrains.k2js.config.Config; 034 import org.jetbrains.k2js.translate.intrinsic.Intrinsics; 035 import org.jetbrains.k2js.translate.utils.TranslationUtils; 036 037 import java.util.HashMap; 038 import java.util.Map; 039 040 import static org.jetbrains.k2js.translate.context.ContextPackage.getNameForCapturedDescriptor; 041 import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForElement; 042 043 /** 044 * All the info about the state of the translation process. 045 */ 046 public class TranslationContext { 047 @NotNull 048 private final DynamicContext dynamicContext; 049 @NotNull 050 private final StaticContext staticContext; 051 @NotNull 052 private final AliasingContext aliasingContext; 053 @Nullable 054 private final UsageTracker usageTracker; 055 @Nullable 056 private final TranslationContext parent; 057 @Nullable 058 private final DefinitionPlace definitionPlace; 059 060 @NotNull 061 public static TranslationContext rootContext(@NotNull StaticContext staticContext, JsFunction rootFunction) { 062 DynamicContext rootDynamicContext = DynamicContext.rootContext(rootFunction.getScope(), rootFunction.getBody()); 063 AliasingContext rootAliasingContext = AliasingContext.getCleanContext(); 064 return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null); 065 } 066 067 private final Map<JsExpression, TemporaryConstVariable> expressionToTempConstVariableCache = new HashMap<JsExpression, TemporaryConstVariable>(); 068 069 private TranslationContext( 070 @Nullable TranslationContext parent, 071 @NotNull StaticContext staticContext, 072 @NotNull DynamicContext dynamicContext, 073 @NotNull AliasingContext aliasingContext, 074 @Nullable UsageTracker usageTracker, 075 @Nullable DefinitionPlace definitionPlace 076 ) { 077 this.parent = parent; 078 this.dynamicContext = dynamicContext; 079 this.staticContext = staticContext; 080 this.aliasingContext = aliasingContext; 081 this.usageTracker = usageTracker; 082 this.definitionPlace = definitionPlace; 083 } 084 085 @Nullable 086 public UsageTracker usageTracker() { 087 return usageTracker; 088 } 089 090 @NotNull 091 public DynamicContext dynamicContext() { 092 return dynamicContext; 093 } 094 095 @NotNull 096 public TranslationContext contextWithScope(@NotNull JsFunction fun) { 097 return this.newFunctionBody(fun, aliasingContext); 098 } 099 100 @NotNull 101 public TranslationContext newFunctionBody(@NotNull JsFunction fun, @Nullable AliasingContext aliasingContext) { 102 DynamicContext dynamicContext = DynamicContext.newContext(fun.getScope(), fun.getBody()); 103 if (aliasingContext == null) { 104 aliasingContext = this.aliasingContext.inner(); 105 } 106 107 return new TranslationContext(this, this.staticContext, dynamicContext, aliasingContext, this.usageTracker, null); 108 } 109 110 @NotNull 111 public TranslationContext newFunctionBodyWithUsageTracker(@NotNull JsFunction fun, @NotNull MemberDescriptor descriptor) { 112 DynamicContext dynamicContext = DynamicContext.newContext(fun.getScope(), fun.getBody()); 113 UsageTracker usageTracker = new UsageTracker(this.usageTracker, descriptor, fun.getScope()); 114 return new TranslationContext(this, this.staticContext, dynamicContext, this.aliasingContext.inner(), usageTracker, this.definitionPlace); 115 } 116 117 @NotNull 118 public TranslationContext innerBlock(@NotNull JsBlock block) { 119 return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null); 120 } 121 122 @NotNull 123 public TranslationContext innerBlock() { 124 return innerBlock(new JsBlock()); 125 } 126 127 @NotNull 128 public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor, @Nullable DefinitionPlace place) { 129 DynamicContext dynamicContext = DynamicContext.newContext(getScopeForDescriptor(descriptor), getBlockForDescriptor(descriptor)); 130 return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, place); 131 } 132 133 @NotNull 134 private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) { 135 return new TranslationContext(this, this.staticContext, this.dynamicContext, aliasingContext, this.usageTracker, null); 136 } 137 138 @NotNull 139 public TranslationContext innerContextWithAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsExpression alias) { 140 return this.innerWithAliasingContext(aliasingContext.inner(correspondingDescriptor, alias)); 141 } 142 143 @NotNull 144 public TranslationContext innerContextWithAliasesForExpressions(@NotNull Map<JetExpression, JsExpression> aliases) { 145 return this.innerWithAliasingContext(aliasingContext.withExpressionsAliased(aliases)); 146 } 147 148 @NotNull 149 public TranslationContext innerContextWithDescriptorsAliased(@NotNull Map<DeclarationDescriptor, JsExpression> aliases) { 150 return this.innerWithAliasingContext(aliasingContext.withDescriptorsAliased(aliases)); 151 } 152 153 @NotNull 154 public JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) { 155 if (descriptor instanceof CallableDescriptor) { 156 return getFunctionObject((CallableDescriptor) descriptor).getBody(); 157 } 158 else { 159 return new JsBlock(); 160 } 161 } 162 163 @NotNull 164 public BindingContext bindingContext() { 165 return staticContext.getBindingContext(); 166 } 167 168 @NotNull 169 public DiagnosticSink getTrace() { return staticContext.getConfig().getTrace(); } 170 171 @NotNull 172 public JsScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) { 173 return staticContext.getScopeForDescriptor(descriptor); 174 } 175 176 @NotNull 177 public JsName getNameForElement(@NotNull PsiElement element) { 178 DeclarationDescriptor descriptor = getDescriptorForElement(bindingContext(), element); 179 return getNameForDescriptor(descriptor); 180 } 181 182 @NotNull 183 public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) { 184 return staticContext.getNameForDescriptor(descriptor); 185 } 186 187 @NotNull 188 public JsName getNameForPackage(@NotNull FqName fqName) { 189 return staticContext.getNameForPackage(fqName); 190 } 191 192 @NotNull 193 public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name, boolean fresh) { 194 return staticContext.declarePropertyOrPropertyAccessorName(descriptor, name, fresh); 195 } 196 197 @NotNull 198 public JsNameRef getQualifiedReference(@NotNull DeclarationDescriptor descriptor) { 199 return staticContext.getQualifiedReference(descriptor); 200 } 201 202 @NotNull 203 public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) { 204 return staticContext.getQualifiedReference(packageFqName); 205 } 206 207 @Nullable 208 public JsExpression getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) { 209 return staticContext.getQualifierForDescriptor(descriptor); 210 } 211 212 @NotNull 213 public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) { 214 return dynamicContext.declareTemporary(initExpression); 215 } 216 217 @NotNull 218 public TemporaryConstVariable getOrDeclareTemporaryConstVariable(@NotNull JsExpression expression) { 219 TemporaryConstVariable tempVar = expressionToTempConstVariableCache.get(expression); 220 221 if (tempVar == null) { 222 TemporaryVariable tmpVar = declareTemporary(expression); 223 224 tempVar = new TemporaryConstVariable(tmpVar.name(), tmpVar.assignmentExpression()); 225 226 expressionToTempConstVariableCache.put(expression, tempVar); 227 expressionToTempConstVariableCache.put(tmpVar.assignmentExpression(), tempVar); 228 } 229 230 return tempVar; 231 } 232 233 public void associateExpressionToLazyValue(JsExpression expression, TemporaryConstVariable temporaryConstVariable) { 234 assert expression == temporaryConstVariable.assignmentExpression(); 235 expressionToTempConstVariableCache.put(expression, temporaryConstVariable); 236 } 237 238 @NotNull 239 public Namer namer() { 240 return staticContext.getNamer(); 241 } 242 243 @NotNull 244 public Intrinsics intrinsics() { 245 return staticContext.getIntrinsics(); 246 } 247 248 @NotNull 249 public ReflectionTypes getReflectionTypes() { 250 return staticContext.getReflectionTypes(); 251 } 252 253 @NotNull 254 public JsProgram program() { 255 return staticContext.getProgram(); 256 } 257 258 @NotNull 259 public Config getConfig() { 260 return staticContext.getConfig(); 261 } 262 263 @NotNull 264 public JsScope scope() { 265 return dynamicContext.getScope(); 266 } 267 268 @NotNull 269 public AliasingContext aliasingContext() { 270 return aliasingContext; 271 } 272 273 @NotNull 274 public JsFunction getFunctionObject(@NotNull CallableDescriptor descriptor) { 275 return staticContext.getFunctionWithScope(descriptor); 276 } 277 278 public void addStatementToCurrentBlock(@NotNull JsStatement statement) { 279 dynamicContext.jsBlock().getStatements().add(statement); 280 } 281 282 public void addStatementsToCurrentBlockFrom(@NotNull TranslationContext context) { 283 addStatementsToCurrentBlockFrom(context.dynamicContext().jsBlock()); 284 } 285 286 public void addStatementsToCurrentBlockFrom(@NotNull JsBlock block) { 287 dynamicContext.jsBlock().getStatements().addAll(block.getStatements()); 288 } 289 290 public boolean currentBlockIsEmpty() { 291 return dynamicContext.jsBlock().isEmpty(); 292 } 293 294 public void moveVarsFrom(@NotNull TranslationContext context) { 295 dynamicContext.moveVarsFrom(context.dynamicContext()); 296 } 297 298 @NotNull 299 public JsBlock getCurrentBlock() { 300 return dynamicContext.jsBlock(); 301 } 302 303 @NotNull 304 public JsEmpty getEmptyStatement() { 305 return program().getEmptyStatement(); 306 } 307 308 @NotNull 309 public JsExpression getEmptyExpression() { 310 return program().getEmptyExpression(); 311 } 312 313 @Nullable 314 public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { 315 JsNameRef nameRef = captureIfNeedAndGetCapturedName(descriptor); 316 if (nameRef != null) { 317 return nameRef; 318 } 319 320 return aliasingContext.getAliasForDescriptor(descriptor); 321 } 322 323 @NotNull 324 public JsExpression getDispatchReceiver(@NotNull ReceiverParameterDescriptor descriptor) { 325 JsExpression alias = getAliasForDescriptor(descriptor); 326 return alias == null ? JsLiteral.THIS : alias; 327 } 328 329 @NotNull 330 private DefinitionPlace getDefinitionPlace() { 331 if (definitionPlace != null) return definitionPlace; 332 if (parent != null) return parent.getDefinitionPlace(); 333 334 throw new AssertionError("Can not find definition place from rootContext(definitionPlace and parent is null)"); 335 } 336 337 @NotNull 338 public JsNameRef define(DeclarationDescriptor descriptor, JsExpression expression) { 339 String suggestedName = TranslationUtils.getSuggestedNameForInnerDeclaration(this, descriptor); 340 return getDefinitionPlace().define(suggestedName, expression); 341 } 342 343 @Nullable 344 private JsNameRef captureIfNeedAndGetCapturedName(DeclarationDescriptor descriptor) { 345 if (usageTracker != null && descriptor instanceof CallableDescriptor) { 346 CallableDescriptor callableDescriptor = (CallableDescriptor) descriptor; 347 348 usageTracker.used(callableDescriptor); 349 350 JsName name = getNameForCapturedDescriptor(usageTracker, callableDescriptor); 351 if (name != null) return name.makeRef(); 352 } 353 354 return null; 355 } 356 }