diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 0c2faf99960..17a8af73b69 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,12 +5,15 @@
-
-
-
+
+
-
-
+
+
+
+
+
+
@@ -230,94 +233,99 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -327,93 +335,91 @@
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
@@ -440,22 +446,22 @@
@@ -541,7 +547,7 @@
-
+
@@ -562,6 +568,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -719,6 +815,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -751,6 +917,10 @@
+
+
+
+
@@ -818,6 +988,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -841,6 +1065,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -911,39 +1235,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1062,6 +1353,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1189,11 +1509,11 @@
-
-
-
-
-
+
+
+
+
+
localhost
@@ -1254,10 +1574,11 @@
+
-
+
@@ -1268,11 +1589,10 @@
-
+
-
@@ -1312,7 +1632,7 @@
-
+
@@ -1325,7 +1645,6 @@
-
@@ -1350,6 +1669,7 @@
+
@@ -1359,116 +1679,119 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
diff --git a/translator/src/org/jetbrains/k2js/translate/context/Namer.java b/translator/src/org/jetbrains/k2js/translate/context/Namer.java
index a98566bec15..cd9ee889d3f 100644
--- a/translator/src/org/jetbrains/k2js/translate/context/Namer.java
+++ b/translator/src/org/jetbrains/k2js/translate/context/Namer.java
@@ -144,4 +144,9 @@ public final class Namer {
public JsNameRef isOperationReference() {
return kotlin(AstUtil.newQualifiedNameRef("isType"));
}
+
+ @NotNull
+ /*package*/ JsScope getKotlinScope() {
+ return kotlinScope;
+ }
}
diff --git a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java
new file mode 100644
index 00000000000..c9d3e7bccce
--- /dev/null
+++ b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java
@@ -0,0 +1,93 @@
+package org.jetbrains.k2js.translate.context;
+
+import com.google.dart.compiler.backend.js.ast.JsName;
+import com.google.dart.compiler.backend.js.ast.JsScope;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
+import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
+import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
+import org.jetbrains.jet.lang.types.JetStandardLibrary;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.jetbrains.jet.resolve.DescriptorRenderer.getFQName;
+
+/**
+ * @author Talanov Pavel
+ */
+public final class StandardClasses {
+
+ @NotNull
+ public static StandardClasses bindImplementations(@NotNull JetStandardLibrary standardLibrary,
+ @NotNull JsScope kotlinScope) {
+ StandardClasses standardClasses = new StandardClasses(kotlinScope);
+
+ return standardClasses;
+ }
+
+ @NotNull
+ private final JsScope kotlinScope;
+
+ @NotNull
+ private final Map topLevelNameMap = new HashMap();
+
+ @NotNull
+ private final Map scopeMap = new HashMap();
+
+ @NotNull
+ private final Map> methodNameMap = new HashMap>();
+
+
+ private StandardClasses(@NotNull JsScope kotlinScope) {
+ this.kotlinScope = kotlinScope;
+ }
+
+ private void declareStandardTopLevelObject(@NotNull String fullQualifiedName, @NotNull String kotlinLibName) {
+ topLevelNameMap.put(fullQualifiedName, kotlinScope.declareName(kotlinLibName));
+ scopeMap.put(fullQualifiedName, new JsScope(kotlinScope, "class " + kotlinLibName));
+ methodNameMap.put(fullQualifiedName, new HashMap());
+ }
+
+ private void declareStandardMethod(@NotNull String fullQualifiedClassName, @NotNull String methodName,
+ @NotNull String kotlinLibName) {
+ JsScope classScope = scopeMap.get(fullQualifiedClassName);
+ Map classMethodsMap = methodNameMap.get(fullQualifiedClassName);
+ classMethodsMap.put(methodName, classScope.declareName(kotlinLibName));
+ }
+
+ //TODO: refactor
+ public boolean isStandardObject(@NotNull DeclarationDescriptor descriptor) {
+ if (descriptor instanceof ClassDescriptor) {
+ ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
+ return topLevelNameMap.containsKey(getFQName(classDescriptor));
+ }
+ if (descriptor instanceof FunctionDescriptor) {
+ FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
+ DeclarationDescriptor containing = descriptor.getContainingDeclaration();
+ assert containing != null : "Cannot have top level functions.";
+ if (!isStandardObject(containing)) {
+ return false;
+ }
+ Map methodMapForClass = methodNameMap.get(getFQName(containing));
+ return methodMapForClass.containsKey(functionDescriptor.getName());
+ }
+ return false;
+ }
+
+ @NotNull
+ public JsName getStandardObjectName(@NotNull DeclarationDescriptor descriptor) {
+ if (descriptor instanceof ClassDescriptor) {
+ ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
+ return topLevelNameMap.get(getFQName(classDescriptor));
+ }
+ if (descriptor instanceof FunctionDescriptor) {
+ FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
+ DeclarationDescriptor containing = descriptor.getContainingDeclaration();
+ assert containing != null : "Cannot have top level functions.";
+ Map methodMapForClass = methodNameMap.get(getFQName(containing));
+ return methodMapForClass.get(functionDescriptor.getName());
+ }
+ throw new AssertionError("Only classes and functions can be standard objects.");
+ }
+}
diff --git a/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java
index 9ce4523fd44..f8bb8b96ae5 100644
--- a/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java
+++ b/translator/src/org/jetbrains/k2js/translate/context/StaticContext.java
@@ -22,7 +22,9 @@ public class StaticContext {
NamingScope scope = NamingScope.rootScope(jsRootScope);
Declarations declarations = Declarations.newInstance(scope);
Intrinsics intrinsics = Intrinsics.standardLibraryIntrinsics(library);
- return new StaticContext(program, bindingContext, declarations, aliaser, namer, intrinsics, scope);
+ StandardClasses standardClasses = StandardClasses.bindImplementations(library, namer.getKotlinScope());
+ return new StaticContext(program, bindingContext, declarations, aliaser,
+ namer, intrinsics, standardClasses, scope);
}
@NotNull
@@ -43,6 +45,9 @@ public class StaticContext {
@NotNull
private final Intrinsics intrinsics;
+ @NotNull
+ private final StandardClasses standardClasses;
+
@NotNull
private final NamingScope rootScope;
@@ -50,7 +55,7 @@ public class StaticContext {
private StaticContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext,
@NotNull Declarations declarations, @NotNull Aliaser aliaser,
@NotNull Namer namer, @NotNull Intrinsics intrinsics,
- @NotNull NamingScope rootScope) {
+ @NotNull StandardClasses standardClasses, @NotNull NamingScope rootScope) {
this.program = program;
this.bindingContext = bindingContext;
this.declarations = declarations;
@@ -58,6 +63,7 @@ public class StaticContext {
this.namer = namer;
this.intrinsics = intrinsics;
this.rootScope = rootScope;
+ this.standardClasses = standardClasses;
}
@NotNull
@@ -95,6 +101,11 @@ public class StaticContext {
return rootScope;
}
+ @NotNull
+ public StandardClasses getStandardClasses() {
+ return standardClasses;
+ }
+
@NotNull
public NamingScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) {
return declarations.getScope(descriptor);
diff --git a/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java b/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java
index 7d9de98768d..ca62e634a73 100644
--- a/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java
+++ b/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java
@@ -95,6 +95,9 @@ public final class TranslationContext {
if (aliaser().hasAliasForDeclaration(descriptor)) {
return aliaser().getAliasForDeclaration(descriptor);
}
+ if (staticContext.getStandardClasses().isStandardObject(descriptor)) {
+ return staticContext.getStandardClasses().getStandardObjectName(descriptor);
+ }
if (dynamicContext.isDeclared(descriptor)) {
return dynamicContext.getLocalName(descriptor);
}
diff --git a/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java
index 3ed85bd0cf6..947405c82c4 100644
--- a/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/expression/ForTranslator.java
@@ -11,6 +11,9 @@ import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.Translation;
+import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody;
+import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopParameter;
+
/**
* @author Talanov Pavel
*/
@@ -33,41 +36,56 @@ public final class ForTranslator extends AbstractTranslator {
@NotNull
private JsBlock translate() {
- JetParameter loopParameter = expression.getLoopParameter();
- assert loopParameter != null;
- JsName parameterName = context().declareLocalVariable(loopParameter);
+ JsName parameterName = declareParameter();
TemporaryVariable iterator = context().declareTemporary(iteratorMethodInvocation());
- JsBlock bodyBlock = new JsBlock();
- bodyBlock.addStatement(AstUtil.newAssignmentStatement(parameterName.makeRef(), nextMethodInvocation(iterator)));
- bodyBlock.addStatement(AstUtil.convertToBlock(Translation.translateExpression(expression.getBody(), context())));
+ JsBlock bodyBlock = generateCycleBody(parameterName, iterator);
JsWhile cycle = new JsWhile(hasNextMethodInvocation(iterator), bodyBlock);
return AstUtil.newBlock(iterator.assignmentExpression().makeStmt(), cycle);
}
+ @NotNull
+ private JsName declareParameter() {
+ JetParameter loopParameter = getLoopParameter(expression);
+ return context().declareLocalVariable(loopParameter);
+ }
+
+ @NotNull
+ private JsBlock generateCycleBody(@NotNull JsName parameterName, @NotNull TemporaryVariable iterator) {
+ JsStatement parameterAssignment = AstUtil.newAssignmentStatement(parameterName.makeRef(), nextMethodInvocation(iterator));
+ JsNode originalBody = Translation.translateExpression(getLoopBody(expression), context());
+ return AstUtil.newBlock(parameterAssignment, AstUtil.convertToBlock(originalBody));
+ }
+
@NotNull
private JsExpression nextMethodInvocation(@NotNull TemporaryVariable iterator) {
- JsNameRef next = AstUtil.newQualifiedNameRef("next");
- JsNameRef result = iterator.nameReference();
- AstUtil.setQualifier(next, result);
- return AstUtil.newInvocation(next);
+ return callStandardMethodOnExpression("next", iterator.nameReference());
}
@NotNull
private JsExpression hasNextMethodInvocation(@NotNull TemporaryVariable iterator) {
- JsNameRef hasNext = AstUtil.newQualifiedNameRef("hasNext");
- JsNameRef result = iterator.nameReference();
- AstUtil.setQualifier(hasNext, result);
+ return callStandardMethodOnExpression("hasNext", iterator.nameReference());
+ }
+
+ @NotNull
+ private JsExpression callStandardMethodOnExpression(@NotNull String methodName, @NotNull JsNameRef expression) {
+ JsNameRef hasNext = AstUtil.newQualifiedNameRef(methodName);
+ AstUtil.setQualifier(hasNext, expression);
return AstUtil.newInvocation(hasNext);
}
-
@NotNull
private JsExpression iteratorMethodInvocation() {
- JetExpression rangeExpression = expression.getLoopRange();
- assert rangeExpression != null;
+ JetExpression rangeExpression = getLoopRange();
JsExpression range = Translation.translateAsExpression(rangeExpression, context());
JsNameRef iteratorMethodReference = AstUtil.newQualifiedNameRef("iterator");
AstUtil.setQualifier(iteratorMethodReference, range);
return AstUtil.newInvocation(iteratorMethodReference);
}
+
+ @NotNull
+ private JetExpression getLoopRange() {
+ JetExpression rangeExpression = expression.getLoopRange();
+ assert rangeExpression != null;
+ return rangeExpression;
+ }
}
diff --git a/translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java b/translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java
index bb84f5ced33..3eb7170e450 100644
--- a/translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java
+++ b/translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java
@@ -58,4 +58,18 @@ public final class PsiUtils {
assert calleeExpression != null;
return calleeExpression;
}
+
+ @NotNull
+ public static JetExpression getLoopBody(@NotNull JetLoopExpression expression) {
+ JetExpression body = expression.getBody();
+ assert body != null : "Loops cannot have null bodies.";
+ return body;
+ }
+
+ @NotNull
+ public static JetParameter getLoopParameter(@NotNull JetForExpression expression) {
+ JetParameter loopParameter = expression.getLoopParameter();
+ assert loopParameter != null;
+ return loopParameter;
+ }
}
diff --git a/translator/test/org/jetbrains/k2js/test/ForTest.java b/translator/test/org/jetbrains/k2js/test/ForTest.java
index cad1cd7ca2c..eef8a9dcc4d 100644
--- a/translator/test/org/jetbrains/k2js/test/ForTest.java
+++ b/translator/test/org/jetbrains/k2js/test/ForTest.java
@@ -18,4 +18,9 @@ public final class ForTest extends AbstractExpressionTest {
public void forIteratesOverArray() throws Exception {
testFooBoxIsTrue("forIteratesOverArray.kt");
}
-}
+
+ @Test
+ public void forOnEmptyArray() throws Exception {
+ testFooBoxIsTrue("forOnEmptyArray.kt");
+ }
+}
\ No newline at end of file
diff --git a/translator/testFiles/expression/for/cases/forOnEmptyArray.kt b/translator/testFiles/expression/for/cases/forOnEmptyArray.kt
new file mode 100644
index 00000000000..925f0051e1f
--- /dev/null
+++ b/translator/testFiles/expression/for/cases/forOnEmptyArray.kt
@@ -0,0 +1,10 @@
+namespace foo
+
+val a1 = Array(0)
+
+fun box() : Boolean {
+ for (a in a1) {
+ return false;
+ }
+ return true;
+}
\ No newline at end of file