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.JsExpression; 020 import gnu.trove.THashMap; 021 import org.jetbrains.annotations.NotNull; 022 import org.jetbrains.annotations.Nullable; 023 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; 024 import org.jetbrains.kotlin.psi.KtExpression; 025 026 import java.util.Collections; 027 import java.util.Map; 028 029 public class AliasingContext { 030 public static AliasingContext getCleanContext() { 031 return new AliasingContext(null, null, null); 032 } 033 034 @Nullable 035 private Map<DeclarationDescriptor, JsExpression> aliasesForDescriptors; 036 037 @Nullable 038 private final Map<KtExpression, JsExpression> aliasesForExpressions; 039 040 @Nullable 041 private final AliasingContext parent; 042 043 private AliasingContext( 044 @Nullable AliasingContext parent, 045 @Nullable Map<DeclarationDescriptor, JsExpression> aliasesForDescriptors, 046 @Nullable Map<KtExpression, JsExpression> aliasesForExpressions 047 ) { 048 this.parent = parent; 049 this.aliasesForDescriptors = aliasesForDescriptors; 050 this.aliasesForExpressions = aliasesForExpressions; 051 } 052 053 @NotNull 054 public AliasingContext inner() { 055 return new AliasingContext(this, null, null); 056 } 057 058 @NotNull 059 public AliasingContext inner(@NotNull DeclarationDescriptor descriptor, @NotNull JsExpression alias) { 060 return new AliasingContext(this, Collections.singletonMap(descriptor, alias), null); 061 } 062 063 @NotNull 064 public AliasingContext withExpressionsAliased(@NotNull Map<KtExpression, JsExpression> aliasesForExpressions) { 065 return new AliasingContext(this, null, aliasesForExpressions); 066 } 067 068 @NotNull 069 public AliasingContext withDescriptorsAliased(@NotNull Map<DeclarationDescriptor, JsExpression> aliases) { 070 return new AliasingContext(this, aliases, null); 071 } 072 073 074 @Nullable 075 final public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { 076 // these aliases cannot be shared and applicable only in current context 077 return getAliasForDescriptor(descriptor, false); 078 } 079 080 @Nullable 081 protected JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor, boolean fromChild) { 082 JsExpression alias = aliasesForDescriptors == null ? null : aliasesForDescriptors.get(descriptor.getOriginal()); 083 return alias != null || parent == null ? alias : parent.getAliasForDescriptor(descriptor, true); 084 } 085 086 @Nullable 087 public JsExpression getAliasForExpression(@NotNull KtExpression element) { 088 JsExpression alias = aliasesForExpressions == null ? null : aliasesForExpressions.get(element); 089 return alias != null || parent == null ? alias : parent.getAliasForExpression(element); 090 } 091 092 /** 093 * Usages: 094 * 1) Local variable captured in closure. If captured in closure, any modification in closure should affect captured variable. 095 * So, "var count = n" wrapped as "var count = {v: n}". descriptor wil be property descriptor, alias will be JsObjectLiteral 096 * 097 * 2) Local named function. 098 */ 099 public void registerAlias(@NotNull DeclarationDescriptor descriptor, @NotNull JsExpression alias) { 100 if (aliasesForDescriptors == null) { 101 aliasesForDescriptors = Collections.singletonMap(descriptor, alias); 102 } 103 else { 104 if (aliasesForDescriptors.size() == 1) { 105 Map<DeclarationDescriptor, JsExpression> singletonMap = aliasesForDescriptors; 106 aliasesForDescriptors = new THashMap<DeclarationDescriptor, JsExpression>(); 107 aliasesForDescriptors.put(singletonMap.keySet().iterator().next(), singletonMap.values().iterator().next()); 108 } 109 JsExpression prev = aliasesForDescriptors.put(descriptor, alias); 110 assert prev == null : "Alias for descriptor already registered." + 111 " Descriptor: " + descriptor + 112 " prev alias: " + prev + 113 " new alias: " + alias; 114 } 115 } 116 }