001 /* 002 * Copyright 2010-2015 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.kotlin.js.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.kotlin.descriptors.CallableDescriptor; 024 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; 025 import org.jetbrains.kotlin.descriptors.MemberDescriptor; 026 import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor; 027 import org.jetbrains.kotlin.diagnostics.DiagnosticSink; 028 import org.jetbrains.kotlin.js.config.Config; 029 import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics; 030 import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; 031 import org.jetbrains.kotlin.name.FqName; 032 import org.jetbrains.kotlin.psi.JetExpression; 033 import org.jetbrains.kotlin.resolve.BindingContext; 034 import org.jetbrains.kotlin.resolve.BindingTrace; 035 import org.jetbrains.kotlin.types.reflect.ReflectionTypes; 036 037 import java.util.HashMap; 038 import java.util.Map; 039 040 import static org.jetbrains.kotlin.js.translate.context.ContextPackage.getNameForCapturedDescriptor; 041 import static org.jetbrains.kotlin.js.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 BindingTrace bindingTrace() { 170 return staticContext.getBindingTrace(); 171 } 172 173 @NotNull 174 public JsScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) { 175 return staticContext.getScopeForDescriptor(descriptor); 176 } 177 178 @NotNull 179 public JsName getNameForElement(@NotNull PsiElement element) { 180 DeclarationDescriptor descriptor = getDescriptorForElement(bindingContext(), element); 181 return getNameForDescriptor(descriptor); 182 } 183 184 @NotNull 185 public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) { 186 return staticContext.getNameForDescriptor(descriptor); 187 } 188 189 @NotNull 190 public JsName getNameForPackage(@NotNull FqName fqName) { 191 return staticContext.getNameForPackage(fqName); 192 } 193 194 @NotNull 195 public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name, boolean fresh) { 196 return staticContext.declarePropertyOrPropertyAccessorName(descriptor, name, fresh); 197 } 198 199 @NotNull 200 public JsNameRef getQualifiedReference(@NotNull DeclarationDescriptor descriptor) { 201 return staticContext.getQualifiedReference(descriptor); 202 } 203 204 @NotNull 205 public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) { 206 return staticContext.getQualifiedReference(packageFqName); 207 } 208 209 @Nullable 210 public JsExpression getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) { 211 return staticContext.getQualifierForDescriptor(descriptor); 212 } 213 214 @NotNull 215 public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) { 216 return dynamicContext.declareTemporary(initExpression); 217 } 218 219 @NotNull 220 public TemporaryConstVariable getOrDeclareTemporaryConstVariable(@NotNull JsExpression expression) { 221 TemporaryConstVariable tempVar = expressionToTempConstVariableCache.get(expression); 222 223 if (tempVar == null) { 224 TemporaryVariable tmpVar = declareTemporary(expression); 225 226 tempVar = new TemporaryConstVariable(tmpVar.name(), tmpVar.assignmentExpression()); 227 228 expressionToTempConstVariableCache.put(expression, tempVar); 229 expressionToTempConstVariableCache.put(tmpVar.assignmentExpression(), tempVar); 230 } 231 232 return tempVar; 233 } 234 235 public void associateExpressionToLazyValue(JsExpression expression, TemporaryConstVariable temporaryConstVariable) { 236 assert expression == temporaryConstVariable.assignmentExpression(); 237 expressionToTempConstVariableCache.put(expression, temporaryConstVariable); 238 } 239 240 @NotNull 241 public Namer namer() { 242 return staticContext.getNamer(); 243 } 244 245 @NotNull 246 public Intrinsics intrinsics() { 247 return staticContext.getIntrinsics(); 248 } 249 250 @NotNull 251 public ReflectionTypes getReflectionTypes() { 252 return staticContext.getReflectionTypes(); 253 } 254 255 @NotNull 256 public JsProgram program() { 257 return staticContext.getProgram(); 258 } 259 260 @NotNull 261 public Config getConfig() { 262 return staticContext.getConfig(); 263 } 264 265 @NotNull 266 public JsScope scope() { 267 return dynamicContext.getScope(); 268 } 269 270 @NotNull 271 public AliasingContext aliasingContext() { 272 return aliasingContext; 273 } 274 275 @NotNull 276 public JsFunction getFunctionObject(@NotNull CallableDescriptor descriptor) { 277 return staticContext.getFunctionWithScope(descriptor); 278 } 279 280 public void addStatementToCurrentBlock(@NotNull JsStatement statement) { 281 dynamicContext.jsBlock().getStatements().add(statement); 282 } 283 284 public void addStatementsToCurrentBlockFrom(@NotNull TranslationContext context) { 285 addStatementsToCurrentBlockFrom(context.dynamicContext().jsBlock()); 286 } 287 288 public void addStatementsToCurrentBlockFrom(@NotNull JsBlock block) { 289 dynamicContext.jsBlock().getStatements().addAll(block.getStatements()); 290 } 291 292 public boolean currentBlockIsEmpty() { 293 return dynamicContext.jsBlock().isEmpty(); 294 } 295 296 public void moveVarsFrom(@NotNull TranslationContext context) { 297 dynamicContext.moveVarsFrom(context.dynamicContext()); 298 } 299 300 @NotNull 301 public JsBlock getCurrentBlock() { 302 return dynamicContext.jsBlock(); 303 } 304 305 @NotNull 306 public JsEmpty getEmptyStatement() { 307 return program().getEmptyStatement(); 308 } 309 310 @NotNull 311 public JsExpression getEmptyExpression() { 312 return program().getEmptyExpression(); 313 } 314 315 @Nullable 316 public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { 317 JsNameRef nameRef = captureIfNeedAndGetCapturedName(descriptor); 318 if (nameRef != null) { 319 return nameRef; 320 } 321 322 return aliasingContext.getAliasForDescriptor(descriptor); 323 } 324 325 @NotNull 326 public JsExpression getDispatchReceiver(@NotNull ReceiverParameterDescriptor descriptor) { 327 JsExpression alias = getAliasForDescriptor(descriptor); 328 return alias == null ? JsLiteral.THIS : alias; 329 } 330 331 @NotNull 332 private DefinitionPlace getDefinitionPlace() { 333 if (definitionPlace != null) return definitionPlace; 334 if (parent != null) return parent.getDefinitionPlace(); 335 336 throw new AssertionError("Can not find definition place from rootContext(definitionPlace and parent is null)"); 337 } 338 339 @NotNull 340 public JsNameRef define(DeclarationDescriptor descriptor, JsExpression expression) { 341 String suggestedName = TranslationUtils.getSuggestedNameForInnerDeclaration(this, descriptor); 342 return getDefinitionPlace().define(suggestedName, expression); 343 } 344 345 @Nullable 346 private JsNameRef captureIfNeedAndGetCapturedName(DeclarationDescriptor descriptor) { 347 if (usageTracker != null && descriptor instanceof CallableDescriptor) { 348 CallableDescriptor callableDescriptor = (CallableDescriptor) descriptor; 349 350 usageTracker.used(callableDescriptor); 351 352 JsName name = getNameForCapturedDescriptor(usageTracker, callableDescriptor); 353 if (name != null) return name.makeRef(); 354 } 355 356 return null; 357 } 358 }