diff --git a/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java index d6c0191d062..44418e9fb9a 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java @@ -22,6 +22,7 @@ import com.google.common.base.Predicates; import com.google.common.collect.Iterables; import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.psi.PsiFile; import jet.Function0; import org.jetbrains.annotations.NotNull; @@ -40,6 +41,7 @@ import org.jetbrains.k2js.config.*; import org.jetbrains.k2js.facade.K2JSTranslator; import org.jetbrains.k2js.facade.MainCallParameters; +import java.io.File; import java.util.List; import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.NO_LOCATION; @@ -101,7 +103,6 @@ public class K2JSCompiler extends CLICompiler modules = new THashSet(); collectModuleDependencies(module, modules); if (!modules.isEmpty()) { - VirtualFile[] files = CompilerManager.getInstance(module.getProject()).createModulesCompileScope( - modules.toArray(new Module[modules.size()]), false).getFiles(JetFileType.INSTANCE, true); - for (VirtualFile file : files) { - sb.append(file.getPath()).append(','); + for (Module dependency : modules) { + sb.append('@').append(dependency.getName()).append(','); + VirtualFile[] files = CompilerManager.getInstance(module.getProject()).createModuleCompileScope(dependency, false) + .getFiles(JetFileType.INSTANCE, true); + for (VirtualFile file : files) { + sb.append(file.getPath()).append(','); + } } } diff --git a/idea/src/org/jetbrains/jet/plugin/project/IDEAConfig.java b/idea/src/org/jetbrains/jet/plugin/project/IDEAConfig.java index 74f003e8b21..2afd9df2842 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/IDEAConfig.java +++ b/idea/src/org/jetbrains/jet/plugin/project/IDEAConfig.java @@ -28,6 +28,6 @@ import static org.jetbrains.jet.plugin.project.JsModuleDetector.getLibLocationAn */ public final class IDEAConfig extends LibrarySourcesConfig { public IDEAConfig(@NotNull Project project) { - super(project, getLibLocationAndTargetForProject(project).first, EcmaVersion.defaultVersion()); + super(project, "default", getLibLocationAndTargetForProject(project).first, EcmaVersion.defaultVersion()); } } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/SingleFileTranslationTest.java b/js/js.tests/test/org/jetbrains/k2js/test/SingleFileTranslationTest.java index 3f09631dfaf..4d3dc54ca1f 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/SingleFileTranslationTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/SingleFileTranslationTest.java @@ -42,7 +42,7 @@ public abstract class SingleFileTranslationTest extends BasicTest { runFunctionOutputTest(EcmaVersion.all(), kotlinFilename, namespaceName, functionName, expectedResult); } - protected void runFunctionOutputTest(@NotNull EnumSet ecmaVersions, @NotNull String kotlinFilename, + protected void runFunctionOutputTest(@NotNull Iterable ecmaVersions, @NotNull String kotlinFilename, @NotNull String namespaceName, @NotNull String functionName, @NotNull Object expectedResult) throws Exception { @@ -50,7 +50,7 @@ public abstract class SingleFileTranslationTest extends BasicTest { runRhinoTests(kotlinFilename, ecmaVersions, new RhinoFunctionResultChecker(namespaceName, functionName, expectedResult)); } - public void checkFooBoxIsTrue(@NotNull String filename, @NotNull EnumSet ecmaVersions) throws Exception { + public void checkFooBoxIsTrue(@NotNull String filename, @NotNull Iterable ecmaVersions) throws Exception { runFunctionOutputTest(ecmaVersions, filename, "foo", "box", true); } @@ -58,7 +58,7 @@ public abstract class SingleFileTranslationTest extends BasicTest { checkFooBoxIsTrue(getTestName(true) + ".kt", EcmaVersion.all()); } - protected void fooBoxTest(@NotNull EnumSet ecmaVersions) throws Exception { + protected void fooBoxTest(@NotNull Iterable ecmaVersions) throws Exception { checkFooBoxIsTrue(getTestName(true) + ".kt", ecmaVersions); } @@ -84,7 +84,7 @@ public abstract class SingleFileTranslationTest extends BasicTest { runRhinoTests(kotlinFilename, ecmaVersions, new RhinoSystemOutputChecker(expectedResult)); } - protected void performTestWithMain(@NotNull EnumSet ecmaVersions, + protected void performTestWithMain(@NotNull Iterable ecmaVersions, @NotNull String testName, @NotNull String testId, @NotNull String... args) throws Exception { diff --git a/js/js.tests/test/org/jetbrains/k2js/test/config/TestConfig.java b/js/js.tests/test/org/jetbrains/k2js/test/config/TestConfig.java index b71bfed31b9..9144d006aef 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/config/TestConfig.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/config/TestConfig.java @@ -41,7 +41,7 @@ public final class TestConfig extends Config { private /*var*/ List jsLibFiles = null; public TestConfig(@NotNull Project project, @NotNull EcmaVersion version) { - super(project, version); + super(project, "main", version); } @NotNull diff --git a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionManager.java b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionManager.java index ff853335424..99bf5fec3b4 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionManager.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionManager.java @@ -39,11 +39,6 @@ class RhinoFunctionManager { this.functionName = functionName; } - @NotNull - public String getFunctionName() { - return functionName; - } - private Script compileScript(int optimizationLevel) { long startNano = System.nanoTime(); Context context = Context.enter(); diff --git a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionResultChecker.java b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionResultChecker.java index 2cf3960b16d..e2dbea4a227 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionResultChecker.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionResultChecker.java @@ -17,6 +17,7 @@ package org.jetbrains.k2js.test.rhino; import org.jetbrains.annotations.Nullable; +import org.jetbrains.k2js.translate.context.Namer; import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; @@ -59,10 +60,14 @@ public class RhinoFunctionResultChecker implements RhinoResultChecker { } private String functionCallString() { - String result = functionName + "()"; + StringBuilder sb = new StringBuilder(); if (namespaceName != null) { - result = "Kotlin.defs." + namespaceName + "." + result; + sb.append("Kotlin.modules.main"); + if (namespaceName != Namer.getRootNamespaceName()) { + sb.append('.').append(namespaceName); + } + sb.append('.'); } - return result; + return sb.append(functionName).append("()").toString(); } } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java index a8259b64ace..b295fcff3a8 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java @@ -26,7 +26,6 @@ import org.jetbrains.k2js.test.BasicTest; import org.mozilla.javascript.*; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.util.List; import java.util.Map; @@ -49,12 +48,7 @@ public final class RhinoUtils { new Supplier() { @Override public String get() { - try { - return FileUtil.loadFile(new File(BasicTest.JSLINT_LIB)); - } - catch (IOException e) { - throw new RuntimeException(e); - } + return fileToString(BasicTest.JSLINT_LIB); } }, "JSLINT" @@ -64,15 +58,19 @@ public final class RhinoUtils { } + private static String fileToString(String file) { + try { + return FileUtil.loadFile(new File(file)); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + private static void runFileWithRhino(@NotNull String inputFile, @NotNull Context context, @NotNull Scriptable scope) throws Exception { - FileReader reader = new FileReader(inputFile); - try { - context.evaluateReader(scope, reader, inputFile, 1, null); - } finally { - reader.close(); - } + context.evaluateString(scope, fileToString(inputFile), inputFile, 1, null); } public static void runRhinoTest(@NotNull List fileNames, diff --git a/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java b/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java index 4477b83962c..72f936ae228 100644 --- a/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java +++ b/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java @@ -18,7 +18,6 @@ package org.jetbrains.k2js.analyze; import com.google.common.base.Predicate; import com.google.common.base.Predicates; -import com.google.common.collect.Sets; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; @@ -39,10 +38,10 @@ import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.k2js.config.Config; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; /** * @author Pavel Talanov @@ -125,7 +124,7 @@ public final class AnalyzerFacadeForJS { @NotNull public static Collection withJsLibAdded(@NotNull Collection files, @NotNull Config config) { - Set allFiles = Sets.newHashSet(); + Collection allFiles = new ArrayList(); allFiles.addAll(files); allFiles.addAll(config.getLibFiles()); return allFiles; diff --git a/js/js.translator/src/org/jetbrains/k2js/config/ClassPathLibraryDefintionsConfig.java b/js/js.translator/src/org/jetbrains/k2js/config/ClassPathLibraryDefintionsConfig.java index 41133aebb07..6cc291e1b40 100644 --- a/js/js.translator/src/org/jetbrains/k2js/config/ClassPathLibraryDefintionsConfig.java +++ b/js/js.translator/src/org/jetbrains/k2js/config/ClassPathLibraryDefintionsConfig.java @@ -28,8 +28,8 @@ import java.util.*; public class ClassPathLibraryDefintionsConfig extends Config { public static final String META_INF_SERVICES_FILE = "META-INF/services/org.jetbrains.kotlin.js.libraryDefinitions"; - public ClassPathLibraryDefintionsConfig(@NotNull Project project, @NotNull EcmaVersion version) { - super(project, version); + public ClassPathLibraryDefintionsConfig(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion version) { + super(project, moduleId, version); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/config/Config.java b/js/js.translator/src/org/jetbrains/k2js/config/Config.java index 3345e27227a..a1eab460a8c 100644 --- a/js/js.translator/src/org/jetbrains/k2js/config/Config.java +++ b/js/js.translator/src/org/jetbrains/k2js/config/Config.java @@ -34,7 +34,7 @@ public abstract class Config { @NotNull public static Config getEmptyConfig(@NotNull Project project, @NotNull EcmaVersion ecmaVersion) { - return new Config(project, ecmaVersion) { + return new Config(project, "main", ecmaVersion) { @NotNull @Override protected List generateLibFiles() { @@ -117,9 +117,13 @@ public abstract class Config { @NotNull private final EcmaVersion target; - public Config(@NotNull Project project, @NotNull EcmaVersion ecmaVersion) { + @NotNull + private final String moduleId; + + public Config(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion ecmaVersion) { this.project = project; this.target = ecmaVersion; + this.moduleId = moduleId; } @NotNull @@ -132,6 +136,11 @@ public abstract class Config { return target; } + @NotNull + public String getModuleId() { + return moduleId; + } + @NotNull protected abstract List generateLibFiles(); diff --git a/js/js.translator/src/org/jetbrains/k2js/config/LibrarySourcesConfig.java b/js/js.translator/src/org/jetbrains/k2js/config/LibrarySourcesConfig.java index 17bc500c55b..bbf31d8dc8a 100644 --- a/js/js.translator/src/org/jetbrains/k2js/config/LibrarySourcesConfig.java +++ b/js/js.translator/src/org/jetbrains/k2js/config/LibrarySourcesConfig.java @@ -39,13 +39,17 @@ import java.util.zip.ZipFile; * @author Pavel Talanov */ public class LibrarySourcesConfig extends Config { - public static final Key EXTERNAL_LIB = new Key("externalLib"); + public static final Key EXTERNAL_MODULE_NAME = new Key("externalModule"); + public static final String UNKNOWN_EXTERNAL_MODULE_NAME = ""; @Nullable private final String[] files; - public LibrarySourcesConfig(@NotNull Project project, @Nullable String[] files, @NotNull EcmaVersion ecmaVersion) { - super(project, ecmaVersion); + public LibrarySourcesConfig(@NotNull Project project, + @NotNull String moduleId, + @Nullable String[] files, + @NotNull EcmaVersion ecmaVersion) { + super(project, moduleId, ecmaVersion); this.files = files; } @@ -57,16 +61,22 @@ public class LibrarySourcesConfig extends Config { } List jetFiles = new ArrayList(); + String moduleName = UNKNOWN_EXTERNAL_MODULE_NAME; for (String path : files) { File file = new File(path); try { String name = file.getName(); + if (path.charAt(0) == '@') { + moduleName = path.substring(1); + continue; + } + if (name.endsWith(".jar") || name.endsWith(".zip")) { jetFiles.addAll(readZip(file)); } else { JetFile psiFile = JetFileUtils.createPsiFile(path, FileUtil.loadFile(file), getProject()); - psiFile.putUserData(EXTERNAL_LIB, true); + psiFile.putUserData(EXTERNAL_MODULE_NAME, moduleName); jetFiles.add(psiFile); } } @@ -98,7 +108,7 @@ public class LibrarySourcesConfig extends Config { InputStream stream = file.getInputStream(entry); String text = FileUtil.loadTextAndClose(stream); JetFile jetFile = JetFileUtils.createPsiFile(entry.getName(), text, getProject()); - jetFile.putUserData(EXTERNAL_LIB, true); + jetFile.putUserData(EXTERNAL_MODULE_NAME, UNKNOWN_EXTERNAL_MODULE_NAME); result.add(jetFile); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java index 1ecf6050d93..01d9f34fd1f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java @@ -32,7 +32,6 @@ import org.jetbrains.k2js.utils.JetFileUtils; import java.io.IOException; import java.util.Arrays; -import java.util.Collection; import java.util.List; import static org.jetbrains.k2js.facade.FacadeUtils.parseString; @@ -96,7 +95,7 @@ public final class K2JSTranslator { throws TranslationException { JetStandardLibrary.initialize(config.getProject()); BindingContext bindingContext = AnalyzerFacadeForJS.analyzeFilesAndCheckErrors(filesToTranslate, config); - return Translation.generateAst(bindingContext, filesToTranslate, mainCallParameters, config.getTarget(), rawStatements); + return Translation.generateAst(bindingContext, filesToTranslate, mainCallParameters, config, rawStatements); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java index 61499a1b728..871ddbadedd 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java @@ -32,14 +32,13 @@ public final class Namer { private static final String INITIALIZE_METHOD_NAME = "initialize"; private static final String CLASS_OBJECT_NAME = "createClass"; private static final String TRAIT_OBJECT_NAME = "createTrait"; - private static final String NAMESPACE_OBJECT_NAME = "createNamespace"; private static final String OBJECT_OBJECT_NAME = "createObject"; private static final String SETTER_PREFIX = "set_"; private static final String GETTER_PREFIX = "get_"; private static final String BACKING_FIELD_PREFIX = "$"; private static final String SUPER_METHOD_NAME = "super_init"; private static final String KOTLIN_OBJECT_NAME = "Kotlin"; - private static final String ROOT_NAMESPACE = "Root"; + private static final String ROOT_NAMESPACE = "_"; private static final String RECEIVER_PARAMETER_NAME = "receiver"; private static final String CLASSES_OBJECT_NAME = "classes"; private static final String THROW_NPE_FUN_NAME = "throwNPE"; @@ -112,7 +111,7 @@ public final class Namer { @NotNull private final JsName traitName; @NotNull - private final JsName namespaceName; + private final JsExpression definePackage; @NotNull private final JsName objectName; @@ -129,7 +128,9 @@ public final class Namer { kotlinName = rootScope.declareName(KOTLIN_OBJECT_NAME); kotlinScope = new JsScope(rootScope, "Kotlin standard object"); traitName = kotlinScope.declareName(TRAIT_OBJECT_NAME); - namespaceName = kotlinScope.declareName(NAMESPACE_OBJECT_NAME); + + definePackage = kotlin("definePackage"); + className = kotlinScope.declareName(CLASS_OBJECT_NAME); objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME); @@ -151,8 +152,8 @@ public final class Namer { } @NotNull - public JsExpression namespaceCreationMethodReference() { - return kotlin(namespaceName); + public JsExpression packageDefinitionMethodReference() { + return definePackage; } @NotNull @@ -169,14 +170,17 @@ public final class Namer { @NotNull private JsExpression kotlin(@NotNull JsName name) { - JsNameRef reference = name.makeRef(); - reference.setQualifier(kotlinName.makeRef()); - return reference; + return kotlin(name.makeRef()); + } + + @NotNull + public JsExpression kotlin(@NotNull String name) { + return kotlin(kotlinScope.declareName(name)); } @NotNull private JsExpression kotlin(@NotNull JsExpression reference) { - setQualifier(reference, kotlinName.makeRef()); + setQualifier(reference, kotlinObject()); return reference; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java index d4aa5c4c3ef..094942b172b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java @@ -18,13 +18,17 @@ package org.jetbrains.k2js.translate.context; import com.google.common.collect.Maps; import com.google.dart.compiler.backend.js.ast.*; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.k2js.config.EcmaVersion; +import org.jetbrains.k2js.config.LibrarySourcesConfig; import org.jetbrains.k2js.translate.context.generator.Generator; import org.jetbrains.k2js.translate.context.generator.Rule; import org.jetbrains.k2js.translate.intrinsic.Intrinsics; @@ -105,6 +109,11 @@ public final class StaticContext { return ecmaVersion == EcmaVersion.v5; } + @NotNull + public EcmaVersion getEcmaVersion() { + return ecmaVersion; + } + @NotNull public JsProgram getProgram() { return program; @@ -179,8 +188,16 @@ public final class StaticContext { if (!(descriptor instanceof NamespaceDescriptor)) { return null; } - String nameForNamespace = getNameForNamespace((NamespaceDescriptor) descriptor); - return getRootScope().declareUnobfuscatableName(nameForNamespace); + + String name; + if (DescriptorUtils.isRootNamespace((NamespaceDescriptor) descriptor)) { + name = Namer.getRootNamespaceName(); + } + else { + name = descriptor.getName().getName(); + } + + return getRootScope().declareUnobfuscatableName(name); } }; Rule memberDeclarationsInsideParentsScope = new Rule() { @@ -385,14 +402,50 @@ public final class StaticContext { Rule namespaceLevelDeclarationsHaveEnclosingNamespacesNamesAsQualifier = new Rule() { @Override public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) { - DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor); - if (!(containingDeclaration instanceof NamespaceDescriptor)) { + DeclarationDescriptor containingDescriptor = getContainingDeclaration(descriptor); + if (!(containingDescriptor instanceof NamespaceDescriptor)) { return null; } - JsName containingDeclarationName = getNameForDescriptor(containingDeclaration); - JsNameRef qualifier = containingDeclarationName.makeRef(); - qualifier.setQualifier(getQualifierForDescriptor(containingDeclaration)); - return qualifier; + + final JsNameRef result = new JsNameRef(getNameForDescriptor(containingDescriptor)); + if (DescriptorUtils.isRootNamespace((NamespaceDescriptor) containingDescriptor)) { + return result; + } + + JsNameRef qualifier = result; + while ((containingDescriptor = getContainingDeclaration(containingDescriptor)) instanceof NamespaceDescriptor && + !DescriptorUtils.isRootNamespace((NamespaceDescriptor) containingDescriptor)) { + JsNameRef ref = getNameForDescriptor(containingDescriptor).makeRef(); + qualifier.setQualifier(ref); + qualifier = ref; + } + + PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor); + if (element == null && descriptor instanceof PropertyAccessorDescriptor) { + element = BindingContextUtils.descriptorToDeclaration(bindingContext, ((PropertyAccessorDescriptor) descriptor) + .getCorrespondingProperty()); + } + + if (element != null) { + PsiFile file = element.getContainingFile(); + String moduleName = file.getUserData(LibrarySourcesConfig.EXTERNAL_MODULE_NAME); + if (LibrarySourcesConfig.UNKNOWN_EXTERNAL_MODULE_NAME.equals(moduleName)) { + return null; + } + else if (moduleName != null) { + qualifier.setQualifier(new JsArrayAccess(namer.kotlin("modules"), program.getStringLiteral(moduleName))); + } + else if (result == qualifier && result.getIdent().equals("kotlin")) { + // todo WebDemoExamples2Test#testBuilder, package "kotlin" from kotlin/js/js.libraries/src/stdlib/JUMaps.kt must be inlined + return qualifier; + } + } + + if (qualifier.getQualifier() == null) { + qualifier.setQualifier(new JsNameRef(Namer.getRootNamespaceName())); + } + + return result; } }; Rule constructorHaveTheSameQualifierAsTheClass = new Rule() { @@ -448,10 +501,7 @@ public final class StaticContext { Rule topLevelNamespaceHaveNoQualifier = new Rule() { @Override public Boolean apply(@NotNull DeclarationDescriptor descriptor) { - if (!(descriptor instanceof NamespaceDescriptor)) { - return null; - } - if (DescriptorUtils.isTopLevelNamespace((NamespaceDescriptor) descriptor)) { + if (descriptor instanceof NamespaceDescriptor && DescriptorUtils.isRootNamespace((NamespaceDescriptor) descriptor)) { return true; } return null; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java index a55a17687e9..07fc4f3ce79 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java @@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.k2js.config.EcmaVersion; import org.jetbrains.k2js.translate.intrinsic.Intrinsics; import java.util.Map; @@ -58,6 +59,10 @@ public final class TranslationContext { return staticContext.isEcma5(); } + public boolean isNotEcma3() { + return staticContext.getEcmaVersion() != EcmaVersion.v3; + } + private TranslationContext(@NotNull StaticContext staticContext, @NotNull DynamicContext dynamicContext, @NotNull AliasingContext context) { 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 67d5b0566bf..f6013a3c30e 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 @@ -18,13 +18,11 @@ package org.jetbrains.k2js.translate.declaration; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import com.google.common.collect.Lists; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; @@ -32,12 +30,12 @@ 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.ClassSortingUtils; +import org.jetbrains.k2js.translate.utils.JsAstUtils; import java.util.ArrayList; import java.util.List; import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getAllClassesDefinedInNamespace; /** * @author Pavel Talanov @@ -142,18 +140,17 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { } @NotNull - public List classDeclarationsForNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { - List result = Lists.newArrayList(); - for (ClassDescriptor classDescriptor : getAllClassesDefinedInNamespace(namespaceDescriptor, bindingContext())) { - result.add(getClassNameToClassObject(classDescriptor)); - } - return result; - } - - @NotNull - private JsPropertyInitializer getClassNameToClassObject(@NotNull ClassDescriptor classDescriptor) { + public JsPropertyInitializer getClassNameToClassObject(@NotNull ClassDescriptor classDescriptor) { JsName className = context().getNameForDescriptor(classDescriptor); JsNameRef alreadyDefinedClassReference = qualified(className, getDeclarationsObjectName().makeRef()); - return new JsPropertyInitializer(className.makeRef(), alreadyDefinedClassReference); + JsExpression value; + if (context().isEcma5()) { + value = JsAstUtils.createDataDescriptor(alreadyDefinedClassReference, false, context()); + } + else { + value = alreadyDefinedClassReference; + } + + return new JsPropertyInitializer(className.makeRef(), value); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java index 73a973e089a..540d47e980b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java @@ -19,6 +19,8 @@ package org.jetbrains.k2js.translate.declaration; import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; @@ -39,6 +41,17 @@ import static org.jetbrains.k2js.translate.utils.BindingUtils.*; * @author Pavel Talanov */ public final class DeclarationBodyVisitor extends TranslatorVisitor> { + @Nullable + private final ClassDeclarationTranslator classDeclarationTranslator; + + public DeclarationBodyVisitor() { + classDeclarationTranslator = null; + } + + public DeclarationBodyVisitor(ClassDeclarationTranslator classDeclarationTranslator) { + this.classDeclarationTranslator = classDeclarationTranslator; + } + @NotNull public List traverseClass(@NotNull JetClassOrObject jetClass, @NotNull TranslationContext context) { @@ -51,7 +64,7 @@ public final class DeclarationBodyVisitor extends TranslatorVisitor traverseNamespace(@NotNull NamespaceDescriptor namespace, - @NotNull TranslationContext context) { + @NotNull TranslationContext context) { List properties = new ArrayList(); for (JetDeclaration declaration : getDeclarationsForNamespace(context.bindingContext(), namespace)) { properties.addAll(declaration.accept(this, context)); @@ -62,7 +75,12 @@ public final class DeclarationBodyVisitor extends TranslatorVisitor visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { - return Collections.emptyList(); + if (classDeclarationTranslator == null) { + return Collections.emptyList(); + } + + ClassDescriptor classDescriptor = getClassDescriptor(context.bindingContext(), expression); + return Collections.singletonList(classDeclarationTranslator.getClassNameToClassObject(classDescriptor)); } @Override diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceDeclarationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceDeclarationTranslator.java index 6edbad6fac6..e69fa16dc6d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceDeclarationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceDeclarationTranslator.java @@ -24,12 +24,10 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.utils.JsAstUtils; import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; -import org.jetbrains.k2js.translate.utils.TranslationUtils; import java.util.ArrayList; import java.util.List; @@ -37,7 +35,6 @@ import java.util.Set; import static org.jetbrains.k2js.translate.utils.BindingUtils.getAllNonNativeNamespaceDescriptors; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getAllClassesDefinedInNamespace; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; /** * @author Pavel Talanov @@ -85,8 +82,8 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator { private void namespacesDeclarations(List statements) { List namespaceTranslators = getTranslatorsForNonEmptyNamespaces(); - statements.addAll(declarationStatements(namespaceTranslators, context())); - statements.addAll(initializeStatements()); + declarationStatements(namespaceTranslators, statements); + initializeStatements(namespaceTranslators, statements); } @NotNull @@ -98,34 +95,31 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator { return namespaceTranslators; } - @NotNull - private static List declarationStatements(@NotNull List namespaceTranslators, TranslationContext context) { - List result = Lists.newArrayList(); - - JsNameRef defs = JsAstUtils.qualified(context.jsScope().declareName("defs"), context.namer().kotlinObject()); - for (NamespaceTranslator translator : namespaceTranslators) { - JsVars vars = translator.getDeclarationAsVar(); - - JsVars.JsVar var = vars.iterator().next(); - JsNameRef ref = new JsNameRef(var.getName()); - ref.setQualifier(defs); - - result.add(vars); - result.add(JsAstUtils.assignment(ref, new JsNameRef(var.getName())).makeStmt()); + private void declarationStatements(@NotNull List namespaceTranslators, + @NotNull List statements) { + JsObjectLiteral objectLiteral = new JsObjectLiteral(); + JsNameRef packageMapNameRef = context().jsScope().declareName("_").makeRef(); + JsExpression packageMapValue; + if (context().isNotEcma3()) { + packageMapValue = AstUtil.newInvocation(JsAstUtils.CREATE_OBJECT, context().program().getNullLiteral(), objectLiteral); + } + else { + packageMapValue = objectLiteral; + } + statements.add(JsAstUtils.newVar(packageMapNameRef.getName(), packageMapValue)); + + for (NamespaceTranslator translator : namespaceTranslators) { + translator.addNamespaceDeclaration(objectLiteral.getPropertyInitializers()); } - return result; } - @NotNull - private List initializeStatements() { - List result = Lists.newArrayList(); - for (NamespaceDescriptor descriptor : filterNonEmptyNamespaces(namespaceDescriptors)) { - JsNameRef initializeMethodReference = Namer.initializeMethodReference(); - JsNameRef fqNamespaceNameRef = TranslationUtils.getQualifiedReference(context(), descriptor); - setQualifier(initializeMethodReference, fqNamespaceNameRef); - result.add(AstUtil.newInvocation(initializeMethodReference).makeStmt()); + private static void initializeStatements(@NotNull List namespaceTranslators, + @NotNull List statements) { + for (NamespaceTranslator translator : namespaceTranslators) { + for (JsExpression expression : translator.getInitializers()) { + statements.add(expression.makeStmt()); + } } - return result; } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java index f72784bcfd3..6a92dd3340b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java @@ -25,15 +25,14 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils; 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.initializer.InitializerUtils; +import org.jetbrains.k2js.translate.utils.JsAstUtils; import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; +import org.jetbrains.k2js.translate.utils.TranslationUtils; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import static org.jetbrains.k2js.translate.utils.JsAstUtils.newObjectLiteral; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.newVar; /** * @author Pavel.Talanov @@ -49,6 +48,9 @@ public final class NamespaceTranslator extends AbstractTranslator { @NotNull private final ClassDeclarationTranslator classDeclarationTranslator; + @NotNull + private final List initializers = new ArrayList(); + /*package*/ NamespaceTranslator(@NotNull NamespaceDescriptor descriptor, @NotNull ClassDeclarationTranslator classDeclarationTranslator, @NotNull TranslationContext context) { @@ -58,80 +60,81 @@ public final class NamespaceTranslator extends AbstractTranslator { this.classDeclarationTranslator = classDeclarationTranslator; } - @NotNull - public JsVars getDeclarationAsVar() { - return newVar(namespaceName, getNamespaceDeclaration()); + public List getInitializers() { + return initializers; } @NotNull public JsPropertyInitializer getDeclarationAsInitializer() { + addNamespaceInitializer(); return new JsPropertyInitializer(namespaceName.makeRef(), getNamespaceDeclaration()); } + public void addNamespaceDeclaration(List list) { + addNamespaceInitializer(); + + if (DescriptorUtils.isRootNamespace(descriptor)) { + list.addAll(getFunctionsAndClasses()); + return; + } + + JsExpression value = getNamespaceDeclaration(); + if (context().isNotEcma3()) { + value = JsAstUtils.createDataDescriptor(value, false, context()); + } + + list.add(new JsPropertyInitializer(namespaceName.makeRef(), value)); + } + @NotNull private JsInvocation getNamespaceDeclaration() { JsInvocation namespaceDeclaration = namespaceCreateMethodInvocation(); - addNamespaceInitializersAndProperties(namespaceDeclaration); - namespaceDeclaration.getArguments().add(getClassesAndNestedNamespaces()); + addIfNeed(getFunctionsAndClasses(), namespaceDeclaration.getArguments()); + addIfNeed(getNestedNamespaceDeclarations(), namespaceDeclaration.getArguments()); return namespaceDeclaration; } - private void addNamespaceInitializersAndProperties(@NotNull JsInvocation namespaceDeclaration) { + private void addNamespaceInitializer() { JsFunction initializer = Translation.generateNamespaceInitializerMethod(descriptor, context()); - List properties = new DeclarationBodyVisitor().traverseNamespace(descriptor, context()); - if (context().isEcma5()) { - addEcma5InitializersAndProperties(namespaceDeclaration.getArguments(), initializer, properties); - } - else { - addEcma3InitializersAndProperties(namespaceDeclaration, initializer, properties); + if (!initializer.getBody().getStatements().isEmpty()) { + JsNameRef call = new JsNameRef("call"); + call.setQualifier(initializer); + JsInvocation invocation = new JsInvocation(); + invocation.setQualifier(call); + invocation.getArguments().add(TranslationUtils.getQualifiedReference(context(), descriptor)); + initializers.add(invocation); } } - private static void addEcma3InitializersAndProperties(@NotNull JsInvocation namespaceDeclaration, - @NotNull JsFunction initializer, - @NotNull List properties) { - List propertyList = new ArrayList(); - propertyList.add(InitializerUtils.generateInitializeMethod(initializer)); - propertyList.addAll(properties); - namespaceDeclaration.getArguments().add(newObjectLiteral(propertyList)); - } - - private void addEcma5InitializersAndProperties(@NotNull List expressions, - @NotNull JsFunction initializer, - @NotNull List properties) { - expressions.add(initializer.getBody().getStatements().isEmpty() ? context().program().getNullLiteral() : initializer); - expressions.add(properties.isEmpty() ? context().program().getNullLiteral() : newObjectLiteral(properties)); + private List getFunctionsAndClasses() { + return new DeclarationBodyVisitor(classDeclarationTranslator).traverseNamespace(descriptor, context()); } @NotNull private JsInvocation namespaceCreateMethodInvocation() { - return AstUtil.newInvocation(context().namer().namespaceCreationMethodReference()); + return AstUtil.newInvocation(context().namer().packageDefinitionMethodReference()); } - @NotNull - private JsObjectLiteral getClassesAndNestedNamespaces() { - JsObjectLiteral classesAndNestedNamespaces = new JsObjectLiteral(); - classesAndNestedNamespaces.getPropertyInitializers().addAll(getClassesDefined()); - classesAndNestedNamespaces.getPropertyInitializers().addAll(getNestedNamespaceDeclarations()); - return classesAndNestedNamespaces; - } - - @NotNull - private List getClassesDefined() { - return classDeclarationTranslator.classDeclarationsForNamespace(descriptor); + private void addIfNeed(@NotNull List declarations, @NotNull List expressions) { + // ecma5 expects strict number of arguments, but ecma3 doesn't + if (!declarations.isEmpty()) { + expressions.add(newObjectLiteral(declarations)); + } + else if (context().isNotEcma3()) { + expressions.add(context().program().getNullLiteral()); + } } @NotNull private List getNestedNamespaceDeclarations() { - if (DescriptorUtils.isRootNamespace(descriptor)) { - return Collections.emptyList(); - } List result = Lists.newArrayList(); List nestedNamespaces = JsDescriptorUtils.getNestedNamespaces(descriptor, context().bindingContext()); for (NamespaceDescriptor nestedNamespace : nestedNamespaces) { NamespaceTranslator nestedNamespaceTranslator = new NamespaceTranslator(nestedNamespace, classDeclarationTranslator, context()); result.add(nestedNamespaceTranslator.getDeclarationAsInitializer()); + + initializers.addAll(nestedNamespaceTranslator.getInitializers()); } return result; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java index f784f264771..1bc80741eb5 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java @@ -19,6 +19,7 @@ package org.jetbrains.k2js.translate.general; import com.google.dart.compiler.backend.js.JsNamer; import com.google.dart.compiler.backend.js.JsPrettyNamer; import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.util.AstUtil; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -28,7 +29,7 @@ import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; -import org.jetbrains.k2js.config.EcmaVersion; +import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.facade.MainCallParameters; import org.jetbrains.k2js.facade.exceptions.MainFunctionNotFoundException; import org.jetbrains.k2js.facade.exceptions.TranslationException; @@ -148,10 +149,10 @@ public final class Translation { @NotNull public static JsProgram generateAst(@NotNull BindingContext bindingContext, @NotNull List files, @NotNull MainCallParameters mainCallParameters, - @NotNull EcmaVersion ecmaVersion, List rawStatements) + @NotNull Config config, List rawStatements) throws TranslationException { try { - return doGenerateAst(bindingContext, files, mainCallParameters, ecmaVersion, rawStatements); + return doGenerateAst(bindingContext, files, mainCallParameters, config, rawStatements); } catch (UnsupportedOperationException e) { throw new UnsupportedFeatureException("Unsupported feature used.", e); @@ -164,10 +165,10 @@ public final class Translation { @NotNull private static JsProgram doGenerateAst(@NotNull BindingContext bindingContext, @NotNull List files, @NotNull MainCallParameters mainCallParameters, - @NotNull EcmaVersion ecmaVersion, List rawStatements) throws MainFunctionNotFoundException { + @NotNull Config config, List rawStatements) throws MainFunctionNotFoundException { //TODO: move some of the code somewhere JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance(); - StaticContext staticContext = StaticContext.generateStaticContext(standardLibrary, bindingContext, ecmaVersion); + StaticContext staticContext = StaticContext.generateStaticContext(standardLibrary, bindingContext, config.getTarget()); JsProgram program = staticContext.getProgram(); JsBlock block = program.getGlobalBlock(); @@ -177,6 +178,8 @@ public final class Translation { TranslationContext context = TranslationContext.rootContext(staticContext); statements.addAll(translateFiles(files, context)); + defineModule(statements, context, config); + if (mainCallParameters.shouldBeGenerated()) { statements.add(generateCallToMain(context, files, mainCallParameters.arguments())); } @@ -186,6 +189,14 @@ public final class Translation { return context.program(); } + private static void defineModule(@NotNull List statements, + @NotNull TranslationContext context, + @NotNull Config config) { + statements.add(AstUtil.newInvocation(context.namer().kotlin("defineModule"), + context.program().getStringLiteral(config.getModuleId()), + context.jsScope().declareName("_").makeRef()).makeStmt()); + } + @NotNull private static JsStatement generateCallToMain(@NotNull TranslationContext context, @NotNull List files, @NotNull List arguments) throws MainFunctionNotFoundException { @@ -214,12 +225,12 @@ public final class Translation { JsAstUtils.setArguments(translatedCall, Collections.singletonList(arrayLiteral)); } - @NotNull private static void generateTestCalls(@NotNull TranslationContext context, @NotNull List files, @NotNull JsBlock block, List rawStatements) { ClassDescriptor lastClassDescriptor = null; + boolean declaredVar = false; List functions = JetTestFunctionDetector.findTestFunctions(context.bindingContext(), files); for (JetNamedFunction function : functions) { FunctionDescriptor functionDescriptor = getFunctionDescriptor(context.bindingContext(), function); @@ -228,9 +239,16 @@ public final class Translation { if (containingDeclaration instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; String className = getQualifiedName(classDescriptor); + if (lastClassDescriptor != classDescriptor) { + lastClassDescriptor = classDescriptor; + String prefix = ""; + if (!declaredVar) { + prefix = "var "; + declaredVar = true; + } + rawStatements.add(prefix + "_testCase = new Kotlin.main." + className + "();"); + } rawStatements.add("QUnit.test( \"" + className + "." + funName + "()\" , function() {"); - String prefix = " var "; - rawStatements.add(prefix + "_testCase = new Kotlin.defs." + className + "();"); //rawStatements.add(" expect(0);"); rawStatements.add(" _testCase." + funName + "();"); } else { diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java index ca42397faaf..ff97abb9815 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java @@ -213,7 +213,7 @@ public final class CallTranslator extends AbstractTranslator { @NotNull private JsInvocation generateCallMethodInvocation() { - JsNameRef callMethodNameRef = AstUtil.newQualifiedNameRef("call"); + JsNameRef callMethodNameRef = new JsNameRef("call"); JsInvocation callMethodInvocation = new JsInvocation(); callMethodInvocation.setQualifier(callMethodNameRef); setQualifier(callMethodInvocation, callParameters.getFunctionReference()); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java index a5e0f1de3b2..74185298b9f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java @@ -16,8 +16,8 @@ package org.jetbrains.k2js.translate.utils; -import com.google.common.collect.Sets; import com.intellij.psi.PsiElement; +import com.intellij.util.containers.OrderedSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -321,7 +321,7 @@ public final class BindingUtils { @NotNull public static Set getAllNonNativeNamespaceDescriptors(@NotNull BindingContext context, @NotNull List files) { - Set descriptorSet = Sets.newHashSet(); + Set descriptorSet = new OrderedSet(); for (JetFile file : files) { //TODO: can't be NamespaceDescriptor namespaceDescriptor = getNamespaceDescriptor(context, file); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java index 199a00d85af..f9a479d7bfd 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java @@ -33,11 +33,13 @@ import java.util.*; */ public final class JsAstUtils { private static final JsNameRef DEFINE_PROPERTY = new JsNameRef("defineProperty"); + public static final JsNameRef CREATE_OBJECT = new JsNameRef("create"); private static final JsNameRef EMPTY_REF = new JsNameRef(""); static { JsNameRef globalObjectReference = new JsNameRef("Object"); DEFINE_PROPERTY.setQualifier(globalObjectReference); + CREATE_OBJECT.setQualifier(globalObjectReference); } private JsAstUtils() { @@ -301,21 +303,26 @@ public final class JsAstUtils { return createPropertyDataDescriptor(descriptor.getModality().isOverridable(), descriptor, value, context); } + @NotNull + public static JsObjectLiteral createDataDescriptor(@NotNull JsExpression value, boolean writable, @NotNull TranslationContext context) { + JsObjectLiteral dataDescriptor = new JsObjectLiteral(); + dataDescriptor.getPropertyInitializers().add(new JsPropertyInitializer(context.program().getStringLiteral("value"), value)); + if (writable) { + dataDescriptor.getPropertyInitializers().add(context.namer().writablePropertyDescriptorField()); + } + return dataDescriptor; + } + @NotNull private static JsObjectLiteral createPropertyDataDescriptor(boolean writable, @NotNull DeclarationDescriptor descriptor, @NotNull JsExpression value, @NotNull TranslationContext context) { - JsObjectLiteral jsPropertyDescriptor = new JsObjectLiteral(); - List meta = jsPropertyDescriptor.getPropertyInitializers(); - meta.add(new JsPropertyInitializer(context.program().getStringLiteral("value"), value)); - if (writable) { - meta.add(context.namer().writablePropertyDescriptorField()); - } + JsObjectLiteral dataDescriptor = createDataDescriptor(value, writable, context); if (AnnotationsUtils.isEnumerable(descriptor)) { - meta.add(context.namer().enumerablePropertyDescriptorField()); + dataDescriptor.getPropertyInitializers().add(context.namer().enumerablePropertyDescriptorField()); } - return jsPropertyDescriptor; + return dataDescriptor; } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java index 2c488397016..bf7f76bb8f7 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java @@ -30,7 +30,6 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.k2js.config.LibrarySourcesConfig; -import org.jetbrains.k2js.translate.context.Namer; import java.util.ArrayList; import java.util.Collection; @@ -145,16 +144,6 @@ public final class JsDescriptorUtils { return (functionDescriptor.getReceiverParameter().exists()); } - @NotNull - public static String getNameForNamespace(@NotNull NamespaceDescriptor descriptor) { - if (descriptor.getContainingDeclaration() instanceof ModuleDescriptor) { - return Namer.getRootNamespaceName(); - } - else { - return descriptor.getName().getName(); - } - } - //TODO: why callable descriptor @Nullable public static DeclarationDescriptor getExpectedThisDescriptor(@NotNull CallableDescriptor callableDescriptor) { @@ -239,13 +228,18 @@ public final class JsDescriptorUtils { List result = Lists.newArrayList(); for (DeclarationDescriptor descriptor : namespace.getMemberScope().getAllDescriptors()) { if (!AnnotationsUtils.isPredefinedObject(descriptor)) { - PsiElement psiElement = BindingContextUtils.descriptorToDeclaration(context, descriptor); - if (psiElement != null) { - PsiFile file = psiElement.getContainingFile(); - if (file.getUserData(LibrarySourcesConfig.EXTERNAL_LIB) == null) { - result.add(descriptor); + // namespace may be defined in multiple files + if (!(descriptor instanceof NamespaceDescriptor)) { + PsiElement psiElement = BindingContextUtils.descriptorToDeclaration(context, descriptor); + if (psiElement != null) { + PsiFile file = psiElement.getContainingFile(); + if (file.getUserData(LibrarySourcesConfig.EXTERNAL_MODULE_NAME) != null) { + continue; + } } } + + result.add(descriptor); } } return result; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java index 4a505f325f3..e4f08b3a55a 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/PsiUtils.java @@ -23,7 +23,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.k2js.translate.context.Namer; import java.util.Collections; import java.util.List; @@ -143,17 +142,6 @@ public final class PsiUtils { return nameAsDeclaration; } - @NotNull - public static String getNamespaceName(@NotNull JetFile psiFile) { - JetNamespaceHeader namespaceHeader = psiFile.getNamespaceHeader(); - String name = namespaceHeader.getName(); - assert name != null : "NamespaceHeader must have a name"; - if (name.isEmpty()) { - return Namer.getRootNamespaceName(); - } - return name; - } - @NotNull public static JetExpression getLoopRange(@NotNull JetForExpression expression) { JetExpression rangeExpression = expression.getLoopRange(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index bfa8dbd6463..30a5d686e18 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -43,7 +43,7 @@ import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getExpectedRe */ public final class TranslationUtils { - private static JsNameRef UNDEFINED_LITERAL = AstUtil.newQualifiedNameRef("undefined"); + private static final JsNameRef UNDEFINED_LITERAL = AstUtil.newQualifiedNameRef("undefined"); private TranslationUtils() { } @@ -64,11 +64,7 @@ public final class TranslationUtils { @NotNull private static JsPropertyInitializer translateExtensionFunctionAsEcma5PropertyDescriptor(@NotNull JsFunction function, @NotNull FunctionDescriptor descriptor, @NotNull TranslationContext context) { - JsObjectLiteral meta = new JsObjectLiteral(); - meta.getPropertyInitializers().add(new JsPropertyInitializer(context.program().getStringLiteral("value"), function)); - if (descriptor.getModality().isOverridable()) { - meta.getPropertyInitializers().add(context.namer().writablePropertyDescriptorField()); - } + JsObjectLiteral meta = JsAstUtils.createDataDescriptor(function, descriptor.getModality().isOverridable(), context); return new JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), meta); } diff --git a/js/js.translator/testFiles/kotlinLib/cases/namespace.js b/js/js.translator/testFiles/kotlinLib/cases/namespace.js index 2348996f0a9..6339c2bbf7d 100644 --- a/js/js.translator/testFiles/kotlinLib/cases/namespace.js +++ b/js/js.translator/testFiles/kotlinLib/cases/namespace.js @@ -14,9 +14,7 @@ * limitations under the License. */ -foo = Kotlin.createNamespace({initialize:function(){ -} -, box:function(){ +foo = Kotlin.definePackage({box:function(){ return !false; } }); diff --git a/js/js.translator/testFiles/kotlinLib/cases/namespaceWithClasses.js b/js/js.translator/testFiles/kotlinLib/cases/namespaceWithClasses.js index 69a33df0984..97b14892e1d 100644 --- a/js/js.translator/testFiles/kotlinLib/cases/namespaceWithClasses.js +++ b/js/js.translator/testFiles/kotlinLib/cases/namespaceWithClasses.js @@ -46,9 +46,7 @@ return {A:A, B:B, C:C}; } (); - foo = Kotlin.createNamespace(classes, {initialize:function(){ - } - , box:function(){ + foo = Kotlin.definePackage(classes, {box:function(){ return (new foo.C).get_order() === 'ABC' && (new foo.B).get_order() === 'AB' && (new foo.A).get_order() === 'A'; } }); diff --git a/js/js.translator/testFiles/kotlin_lib.js b/js/js.translator/testFiles/kotlin_lib.js index 6a16d9011aa..fd4ba8320f1 100644 --- a/js/js.translator/testFiles/kotlin_lib.js +++ b/js/js.translator/testFiles/kotlin_lib.js @@ -31,7 +31,7 @@ var kotlin = {set:function (receiver, key, value) { return (obj1 === obj2); }; - Kotlin.defs = {}; + Kotlin.modules = {}; Kotlin.Exceptions = {}; Kotlin.Exception = Kotlin.$createClass(); Kotlin.RuntimeException = Kotlin.$createClass(Kotlin.Exception); @@ -44,7 +44,7 @@ var kotlin = {set:function (receiver, key, value) { Kotlin.Exceptions.UnsupportedOperationException = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.IOException = Kotlin.$createClass(Kotlin.Exception); - Kotlin.throwNPE = function() { + Kotlin.throwNPE = function () { throw Kotlin.$new(Kotlin.Exceptions.NullPointerException)(); }; diff --git a/js/js.translator/testFiles/kotlin_lib_ecma3.js b/js/js.translator/testFiles/kotlin_lib_ecma3.js index f20ce1955b2..81a472c5312 100644 --- a/js/js.translator/testFiles/kotlin_lib_ecma3.js +++ b/js/js.translator/testFiles/kotlin_lib_ecma3.js @@ -141,9 +141,7 @@ var Kotlin = {}; } })(); - Kotlin.createNamespace = function () { - return Kotlin.createTrait.apply(null, arguments); - }; + Kotlin.definePackage = Kotlin.createTrait; Kotlin.createClass = (function () { var METHODS = {addMethods: addMethods}; @@ -243,4 +241,12 @@ var Kotlin = {}; var singletonClass = Kotlin.createClass.apply(null, arguments); return new singletonClass(); }; + + Kotlin.defineModule = function (id, module) { + if (id in Kotlin.modules) { + throw Kotlin.$new(Kotlin.Exceptions.IllegalArgumentException)(); + } + + Kotlin.modules[id] = module; + }; })(); diff --git a/js/js.translator/testFiles/kotlin_lib_ecma5.js b/js/js.translator/testFiles/kotlin_lib_ecma5.js index b97c3e2800f..2398cc00ae4 100644 --- a/js/js.translator/testFiles/kotlin_lib_ecma5.js +++ b/js/js.translator/testFiles/kotlin_lib_ecma5.js @@ -110,18 +110,27 @@ var Kotlin = {}; return o; }; - function emptyFunction() { - } - Kotlin.createNamespace = function (initializer, properties, classesAndNestedNamespaces) { - var o = Object.create(null, properties || undefined); - Object.defineProperty(o, "initialize", {value: initializer || emptyFunction}); - var keys = Object.keys(classesAndNestedNamespaces); - for (var i = 0, n = keys.length; i < n; i++) { - var name = keys[i]; - Object.defineProperty(o, name, {value: classesAndNestedNamespaces[name]}); + Kotlin.definePackage = function (functionsAndClasses, nestedNamespaces) { + //var p = parent[localName]; + //if (!p) { + // p = Object.create(null, functionsAndClasses || undefined); + // Object.defineProperty(parent, localName, {value: p}); + //} + //else if (functionsAndClasses) { + // Object.defineProperties(p, functionsAndClasses); + //} + var p = Object.create(null, functionsAndClasses || undefined); + + if (nestedNamespaces) { + var keys = Object.keys(nestedNamespaces); + for (var i = 0, n = keys.length; i < n; i++) { + var name = keys[i]; + Object.defineProperty(p, name, {value:nestedNamespaces[name]}); + } } - return o; + + return p; }; Kotlin.$new = function (f) { @@ -170,4 +179,13 @@ var Kotlin = {}; return Kotlin.createClass(parent || null, initializer, descriptors); }; + + Kotlin.defineModule = function (id, module) { + if (id in Kotlin.modules) { + throw Kotlin.$new(Kotlin.Exceptions.IllegalArgumentException)(); + } + + Object.freeze(module); + Object.defineProperty(Kotlin.modules, id, {value: module}); + }; })();