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.context; 018 019import com.google.dart.compiler.backend.js.ast.*; 020import com.intellij.psi.PsiElement; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.descriptors.CallableDescriptor; 024import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 025import org.jetbrains.jet.lang.descriptors.Named; 026import org.jetbrains.jet.lang.psi.JetExpression; 027import org.jetbrains.jet.lang.resolve.BindingContext; 028import org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator; 029import org.jetbrains.k2js.translate.intrinsic.Intrinsics; 030 031import java.util.HashMap; 032import java.util.Map; 033 034import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForElement; 035 036/** 037 * All the info about the state of the translation process. 038 */ 039public 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}