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.intrinsic.functions.patterns;
018
019 import com.google.common.collect.Lists;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
022 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
023 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
024 import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
025 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
026 import org.jetbrains.jet.lang.resolve.name.Name;
027 import org.jetbrains.k2js.translate.context.Namer;
028
029 import java.util.Arrays;
030 import java.util.List;
031 import java.util.Set;
032
033 public final class PatternBuilder {
034
035 @NotNull
036 private static final NamePredicate JET = new NamePredicate("jet");
037
038 @NotNull
039 private static final Name KOTLIN_NAME = Name.identifier(Namer.KOTLIN_LOWER_NAME);
040
041 private PatternBuilder() {
042 }
043
044 @NotNull
045 public static DescriptorPredicate pattern(@NotNull NamePredicate checker, @NotNull String stringWithPattern) {
046 List<NamePredicate> checkers = Lists.newArrayList(checker);
047 checkers.addAll(parseStringAsCheckerList(stringWithPattern));
048 return pattern(checkers);
049 }
050
051 @NotNull
052 public static DescriptorPredicate pattern(@NotNull String stringWithPattern, @NotNull NamePredicate checker) {
053 List<NamePredicate> checkers = Lists.newArrayList(parseStringAsCheckerList(stringWithPattern));
054 checkers.add(checker);
055 return pattern(checkers);
056 }
057
058 @NotNull
059 public static DescriptorPredicate pattern(@NotNull String string) {
060 List<NamePredicate> checkers = parseStringAsCheckerList(string);
061 return pattern(checkers);
062 }
063
064 @NotNull
065 private static List<NamePredicate> parseStringAsCheckerList(@NotNull String stringWithPattern) {
066 String[] subPatterns = stringWithPattern.split("\\.");
067 List<NamePredicate> checkers = Lists.newArrayList();
068 for (String subPattern : subPatterns) {
069 String[] validNames = subPattern.split("\\|");
070 checkers.add(new NamePredicate(validNames));
071 }
072 return checkers;
073 }
074
075 @NotNull
076 private static DescriptorPredicate pattern(@NotNull List<NamePredicate> checkers) {
077 assert !checkers.isEmpty();
078 final List<NamePredicate> checkersWithPrefixChecker = Lists.newArrayList();
079 if (!checkers.get(0).apply(KOTLIN_NAME)) {
080 checkersWithPrefixChecker.add(JET);
081 }
082
083 checkersWithPrefixChecker.addAll(checkers);
084
085 assert checkersWithPrefixChecker.size() > 1;
086
087 return new DescriptorPredicate() {
088 @Override
089 public boolean apply(@NotNull FunctionDescriptor descriptor) {
090 //TODO: no need to wrap if we check beforehand
091 try {
092 return doApply(descriptor);
093 }
094 catch (IllegalArgumentException e) {
095 return false;
096 }
097 }
098
099 private boolean doApply(@NotNull FunctionDescriptor descriptor) {
100 List<Name> nameParts = DescriptorUtils.getFQName(descriptor).pathSegments();
101 if (nameParts.size() != checkersWithPrefixChecker.size()) {
102 return false;
103 }
104 return allNamePartsValid(nameParts);
105 }
106
107 private boolean allNamePartsValid(@NotNull List<Name> nameParts) {
108 for (int i = 0; i < nameParts.size(); ++i) {
109 Name namePart = nameParts.get(i);
110 NamePredicate correspondingPredicate = checkersWithPrefixChecker.get(i);
111 if (!correspondingPredicate.apply(namePart)) {
112 return false;
113 }
114 }
115 return true;
116 }
117 };
118 }
119
120 @NotNull
121 public static DescriptorPredicate pattern(@NotNull NamePredicate... checkers) {
122 return pattern(Arrays.asList(checkers));
123 }
124
125 @NotNull
126 public static DescriptorPredicateImpl pattern(@NotNull String... names) {
127 return new DescriptorPredicateImpl(names);
128 }
129
130 @NotNull
131 public static DescriptorPredicateImpl pattern(@NotNull String[] root, @NotNull String... names) {
132 return new DescriptorPredicateImpl(names).root(root);
133 }
134
135 private static boolean isRootNamespace(DeclarationDescriptor declarationDescriptor) {
136 return declarationDescriptor instanceof NamespaceDescriptor && DescriptorUtils.isRootNamespace((NamespaceDescriptor) declarationDescriptor);
137 }
138
139 public static class DescriptorPredicateImpl implements DescriptorPredicate {
140 private final String[] names;
141
142 private boolean receiverParameterExists;
143
144 private String[] root;
145 private boolean checkOverridden;
146
147 public DescriptorPredicateImpl(String... names) {
148 this.names = names;
149 }
150
151 public DescriptorPredicateImpl receiverExists() {
152 this.receiverParameterExists = true;
153 return this;
154 }
155
156 public DescriptorPredicateImpl root(String... root) {
157 this.root = root;
158 return this;
159 }
160
161 public DescriptorPredicateImpl checkOverridden() {
162 this.checkOverridden = true;
163 return this;
164 }
165
166 private boolean check(FunctionDescriptor functionDescriptor) {
167 DeclarationDescriptor descriptor = functionDescriptor.getContainingDeclaration();
168 String[] list;
169 int nameIndex;
170 if (root == null) {
171 list = names;
172 nameIndex = list.length - 2;
173 }
174 else {
175 assert names.length == 1;
176 list = root;
177 nameIndex = list.length - 1;
178 }
179
180 do {
181 if (nameIndex == -1) {
182 return isRootNamespace(descriptor);
183 }
184 else if (isRootNamespace(descriptor)) {
185 return false;
186 }
187
188 if (!descriptor.getName().asString().equals(list[nameIndex--])) {
189 return false;
190 }
191 }
192 while ((descriptor = descriptor.getContainingDeclaration()) != null);
193 return false;
194 }
195
196 @Override
197 public boolean apply(@NotNull FunctionDescriptor functionDescriptor) {
198 if ((functionDescriptor.getReceiverParameter() == null) == receiverParameterExists) {
199 return false;
200 }
201
202 // avoid unwrap FAKE_OVERRIDE
203 int nameIndex = names.length - 1;
204 if (!functionDescriptor.getName().asString().equals(names[nameIndex--])) {
205 return false;
206 }
207
208 DeclarationDescriptor descriptor;
209 if (functionDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
210 assert functionDescriptor.getOverriddenDescriptors().size() > 0;
211 descriptor = functionDescriptor.getOverriddenDescriptors().iterator().next();
212 }
213 else {
214 descriptor = functionDescriptor;
215 }
216
217 String[] list = names;
218 while ((descriptor = descriptor.getContainingDeclaration()) != null) {
219 if (nameIndex == -1) {
220 if (isRootNamespace(descriptor)) {
221 return list == root || root == null;
222 }
223 else if (root == null) {
224 return false;
225 }
226 else {
227 nameIndex = root.length - 1;
228 list = root;
229 }
230 }
231 else if (isRootNamespace(descriptor)) {
232 return false;
233 }
234
235 if (!descriptor.getName().asString().equals(list[nameIndex--])) {
236 // we check overridden on any mismatch - we can have classes with equal name from different packages
237 return checkOverridden && checkOverridden(functionDescriptor);
238
239 }
240 }
241 return false;
242 }
243
244 private boolean checkOverridden(FunctionDescriptor functionDescriptor) {
245 Set<? extends FunctionDescriptor> overriddenDescriptors = functionDescriptor.getOverriddenDescriptors();
246 if (overriddenDescriptors.isEmpty()) {
247 return false;
248 }
249
250 for (FunctionDescriptor overridden : overriddenDescriptors) {
251 if (overridden.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
252 for (FunctionDescriptor realOverridden : overridden.getOverriddenDescriptors()) {
253 if (check(realOverridden) || checkOverridden(realOverridden)) {
254 return true;
255 }
256 }
257 }
258 else if (check(overridden) || checkOverridden(overridden)) {
259 return true;
260 }
261 }
262 return false;
263 }
264 }
265 }