diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java index 271b576535c..e05d86dc588 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java @@ -28,7 +28,7 @@ import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.utils.BindingUtils; -import org.jetbrains.k2js.translate.utils.ClassSorter; +import org.jetbrains.k2js.translate.utils.ClassSortingUtils; import java.util.ArrayList; import java.util.HashMap; @@ -128,7 +128,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { for (ClassDescriptor classDescriptor : descriptors) { classes.add(BindingUtils.getClassForDescriptor(bindingContext(), classDescriptor)); } - return ClassSorter.sortUsingInheritanceOrder(classes, bindingContext()); + return ClassSortingUtils.sortUsingInheritanceOrder(classes, bindingContext()); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/ClassSorter.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/ClassSorter.java deleted file mode 100644 index ada856d14d3..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/ClassSorter.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.k2js.translate.utils; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.resolve.BindingContext; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getSuperclassDescriptors; - - -//TODO: can optimise using less dumb implementation -//TODO: pass list of descriptors here, not the list of jet classes - -/** - * @author Pavel Talanov - */ -public final class ClassSorter { - - @NotNull - private final List descriptorList; - @NotNull - private final List classesWithNoAncestors; - @NotNull - private final Map classWasInheritedCount = new HashMap(); - @NotNull - private final BindingContext bindingContext; - - @NotNull - public static List sortUsingInheritanceOrder(@NotNull List original, - @NotNull BindingContext bindingContext) { - ClassSorter sorter = new ClassSorter(original, bindingContext); - return sorter.sortUsingInheritanceOrder(); - } - - private ClassSorter(@NotNull List original, @NotNull BindingContext bindingContext) { - this.bindingContext = bindingContext; - this.descriptorList = getDescriptorList(original); - this.classesWithNoAncestors = new ArrayList(descriptorList); - setInitialCount(); - } - - @NotNull - private List sortUsingInheritanceOrder() { - List sortedClasses = new ArrayList(); - while (!classesWithNoAncestors.isEmpty()) { - ClassDescriptor classDescriptor = getNextClass(); - sortedClasses.add(BindingUtils.getClassForDescriptor(bindingContext, classDescriptor)); - } - assert sortedClasses.size() == descriptorList.size(); - return sortedClasses; - } - - @NotNull - private ClassDescriptor getNextClass() { - ClassDescriptor result = popFromList(); - decreaseCountForDerivedClasses(result); - classWasInheritedCount.remove(result); - return result; - } - - private void decreaseCountForDerivedClasses(@NotNull ClassDescriptor result) { - for (ClassDescriptor derived : descriptorList) { - if (isDerivedClass(result, derived)) { - decreaseCountForDerivedClass(derived); - } - } - } - - private void decreaseCountForDerivedClass(@NotNull ClassDescriptor derived) { - Integer timesInherited = classWasInheritedCount.get(derived); - assert timesInherited != null; - assert timesInherited > 0; - int newCount = timesInherited - 1; - classWasInheritedCount.put(derived, newCount); - if (newCount == 0) { - classesWithNoAncestors.add(derived); - } - } - - private static boolean isDerivedClass(@NotNull ClassDescriptor ancestor, @NotNull ClassDescriptor derived) { - return (getSuperclassDescriptors(derived).contains(ancestor)); - } - - @NotNull - private ClassDescriptor popFromList() { - assert !classesWithNoAncestors.isEmpty(); - ClassDescriptor result = classesWithNoAncestors.get(classesWithNoAncestors.size() - 1); - ClassDescriptor removed = classesWithNoAncestors.remove(classesWithNoAncestors.size() - 1); - assert removed != null; - return result; - } - - - @NotNull - private List getDescriptorList(@NotNull List classesToSort) { - List descriptorList = new ArrayList(); - for (JetClass jetClass : classesToSort) { - descriptorList.add(BindingUtils.getClassDescriptor(bindingContext, jetClass)); - } - return descriptorList; - } - - private void setInitialCount() { - for (ClassDescriptor descriptor : descriptorList) { - List superclasses = getSuperclassDescriptors(descriptor); - int count = 0; - for (ClassDescriptor superclassDescriptor : superclasses) { - if (descriptorList.contains(superclassDescriptor)) { - count++; - } - } - classWasInheritedCount.put(descriptor, superclasses.size()); - if (count > 0) { - boolean success = classesWithNoAncestors.remove(descriptor); - assert success; - } - } - } - -} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/ClassSortingUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/ClassSortingUtils.java new file mode 100644 index 00000000000..cf4817eda37 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/ClassSortingUtils.java @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.translate.utils; + +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.resolve.BindingContext; + +import java.util.ArrayList; +import java.util.List; + +import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getSuperclassDescriptors; + + +//TODO: can optimise using less dumb implementation +//TODO: pass list of descriptors here, not the list of jet classes + +/** + * @author Pavel Talanov + */ +public final class ClassSortingUtils { + + private ClassSortingUtils() { + } + + @NotNull + public static List sortUsingInheritanceOrder(@NotNull List elements, + @NotNull BindingContext bindingContext) { + List descriptors = descriptorsFromClasses(elements, bindingContext); + PartiallyOrderedSet partiallyOrderedSet + = new PartiallyOrderedSet(descriptors, inheritanceOrder()); + List sortedClasses = descriptorsToClasses(partiallyOrderedSet.partiallySortedElements(), bindingContext); + assert elements.size() == sortedClasses.size(); + return sortedClasses; + } + + @NotNull + private static PartiallyOrderedSet.Order inheritanceOrder() { + return new PartiallyOrderedSet.Order() { + @Override + public boolean firstDependsOnSecond(@NotNull ClassDescriptor first, @NotNull ClassDescriptor second) { + return isDerivedClass(first, second); + } + }; + } + + private static boolean isDerivedClass(@NotNull ClassDescriptor ancestor, @NotNull ClassDescriptor derived) { + return (getSuperclassDescriptors(derived).contains(ancestor)); + } + + @NotNull + private static List descriptorsToClasses(@NotNull List descriptors, + @NotNull BindingContext bindingContext) { + List sortedClasses = Lists.newArrayList(); + for (ClassDescriptor descriptor : descriptors) { + sortedClasses.add(BindingUtils.getClassForDescriptor(bindingContext, descriptor)); + } + return sortedClasses; + } + + + @NotNull + private static List descriptorsFromClasses(@NotNull List classesToSort, + @NotNull BindingContext bindingContext) { + List descriptorList = new ArrayList(); + for (JetClass jetClass : classesToSort) { + descriptorList.add(BindingUtils.getClassDescriptor(bindingContext, jetClass)); + } + return descriptorList; + } + +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/PartiallyOrderedSet.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/PartiallyOrderedSet.java new file mode 100644 index 00000000000..86d1f90a473 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/PartiallyOrderedSet.java @@ -0,0 +1,121 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.translate.utils; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author Pavel Talanov + *

+ * This is very inefficient but simple implementation of partially orderered set. + * Feel free to replace with library implementation. + */ +public final class PartiallyOrderedSet { + + private class Arc { + @NotNull + public final Element from; + @NotNull + public final Element to; + + private Arc(@NotNull Element from, @NotNull Element to) { + this.from = from; + this.to = to; + } + } + + public interface Order { + boolean firstDependsOnSecond(@NotNull Element first, @NotNull Element Second); + } + + @NotNull + private final List arcs = Lists.newArrayList(); + @NotNull + private final Map incomingArcs = Maps.newHashMap(); + @NotNull + private final List elementsWithZeroIncoming = Lists.newArrayList(); + + public PartiallyOrderedSet(@NotNull Collection elements, @NotNull Order order) { + elementsWithZeroIncoming.addAll(elements); + for (@NotNull Element first : elements) { + for (@NotNull Element second : elements) { + if (order.firstDependsOnSecond(first, second)) { + arcs.add(new Arc(first, second)); + increaseIncomingCount(second); + } + } + } + } + + private void increaseIncomingCount(@NotNull Element element) { + if (!incomingArcs.containsKey(element)) { + incomingArcs.put(element, 1); + elementsWithZeroIncoming.remove(element); + } + else { + Integer count = incomingArcs.get(element); + incomingArcs.put(element, count + 1); + } + } + + private void decreaseIncomingCount(@NotNull Element element) { + assert incomingArcs.containsKey(element); + Integer count = incomingArcs.get(element); + if (count == 1) { + incomingArcs.remove(element); + elementsWithZeroIncoming.add(element); + } + else { + incomingArcs.put(element, count - 1); + } + } + + @NotNull + public List partiallySortedElements() { + List result = Lists.newArrayList(); + while (!elementsWithZeroIncoming.isEmpty()) { + result.add(getNextElement()); + } + return result; + } + + @NotNull + private Element getNextElement() { + Element elementWithZeroIncoming = getElementWithZeroIncoming(); + for (Arc arc : arcs) { + if (arc.from == elementWithZeroIncoming) { + decreaseIncomingCount(arc.to); + } + } + return elementWithZeroIncoming; + } + + @NotNull + private Element getElementWithZeroIncoming() { + int indexOfLast = elementsWithZeroIncoming.size() - 1; + Element element = elementsWithZeroIncoming.get(indexOfLast); + elementsWithZeroIncoming.remove(indexOfLast); + return element; + } + +}