diff --git a/compiler/cli/src/org/jetbrains/jet/cli/common/CompilerVersion.java b/compiler/cli/src/org/jetbrains/jet/cli/common/CompilerVersion.java index 98f1b3940e6..34d17bc7b94 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/common/CompilerVersion.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/common/CompilerVersion.java @@ -22,5 +22,5 @@ package org.jetbrains.jet.cli.common; public class CompilerVersion { // The value of this constant is generated by the build script // DON'T MODIFY IT - public static final String VERSION = "@snapshot@"; + public static final String VERSION = "snapshot"; } 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 27114b42a1c..ec756937b4a 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java @@ -121,8 +121,8 @@ public class K2JSCompiler extends CLICompiler args = Lists.newArrayList("-tags", "-verbose", "-version"); addPathToSourcesDir(args, srcDir); - addOutputPath(project, outDir, args); - addPathToZippedLib(project, args); + addOutputPath(outFile, args); + Pair data = JsModuleDetector.getLibLocationAndTargetForProject(project); + if (data.first != null) { + args.add("-libzip"); + args.add(data.first); + } + if (data.second != null) { + args.add("-target"); + args.add(data.second); + } return ArrayUtil.toStringArray(args); } @@ -138,23 +155,13 @@ public final class K2JSCompiler implements TranslatingCompiler { args.add(srcPath); } - private static void addOutputPath(@NotNull Project project, @Nullable VirtualFile outDir, @NotNull ArrayList args) { - if (outDir != null) { - String outPath = outDir.getPath(); - String outFile = K2JSRunnerUtils.constructPathToGeneratedFile(project, outPath); + private static void addOutputPath(@Nullable String outFile, @NotNull ArrayList args) { + if (outFile != null) { args.add("-output"); args.add(outFile); } } - private static void addPathToZippedLib(@NotNull Project project, @NotNull ArrayList args) { - String libLocationForProject = JsModuleDetector.getLibLocationForProject(project); - if (libLocationForProject != null) { - args.add("-libzip"); - args.add(libLocationForProject); - } - } - @NotNull @Override public String getDescription() { diff --git a/idea/src/org/jetbrains/jet/plugin/project/IDEAConfig.java b/idea/src/org/jetbrains/jet/plugin/project/IDEAConfig.java index 4032da59ec2..d9fb9627575 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/IDEAConfig.java +++ b/idea/src/org/jetbrains/jet/plugin/project/IDEAConfig.java @@ -20,7 +20,7 @@ import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.k2js.config.ZippedLibrarySourcesConfig; -import static org.jetbrains.jet.plugin.project.JsModuleDetector.getLibLocationForProject; +import static org.jetbrains.jet.plugin.project.JsModuleDetector.getLibLocationAndTargetForProject; /** * @author Pavel Talanov @@ -28,6 +28,6 @@ import static org.jetbrains.jet.plugin.project.JsModuleDetector.getLibLocationFo public final class IDEAConfig extends ZippedLibrarySourcesConfig { public IDEAConfig(@NotNull Project project) { - super(project, getLibLocationForProject(project)); + super(project, getLibLocationAndTargetForProject(project).first, null); } } diff --git a/idea/src/org/jetbrains/jet/plugin/project/JsModuleDetector.java b/idea/src/org/jetbrains/jet/plugin/project/JsModuleDetector.java index c8849436032..efd5931a8e6 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/JsModuleDetector.java +++ b/idea/src/org/jetbrains/jet/plugin/project/JsModuleDetector.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.plugin.project; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; @@ -60,42 +61,35 @@ public final class JsModuleDetector { } //TODO: refactor - @Nullable - public static String getLibLocationForProject(@NotNull Project project) { + @NotNull + public static Pair getLibLocationAndTargetForProject(@NotNull Project project) { VirtualFile indicationFile = findIndicationFileInContentRoots(project); if (indicationFile == null) { - return null; + return Pair.empty(); } + try { InputStream stream = indicationFile.getInputStream(); - String path = FileUtil.loadTextAndClose(stream); - String pathToLibFile = getFirstLine(path); - if (pathToLibFile == null) { - return null; - } + BufferedReader reader = new BufferedReader(new StringReader(FileUtil.loadTextAndClose(stream))); try { + String pathToLibFile = reader.readLine(); + if (pathToLibFile == null) { + return Pair.empty(); + } + URI pathToLibFileUri = new URI(pathToLibFile); URI pathToIndicationFileUri = new URI(indicationFile.getPath()); - return pathToIndicationFileUri.resolve(pathToLibFileUri).toString(); + return new Pair(pathToIndicationFileUri.resolve(pathToLibFileUri).toString(), reader.readLine()); } catch (URISyntaxException e) { - return null; + return Pair.empty(); + } + finally { + reader.close(); } } catch (IOException e) { - return null; - } - } - - @Nullable - private static String getFirstLine(@NotNull String path) throws IOException { - BufferedReader reader = new BufferedReader(new StringReader(path)); - try { - return reader.readLine(); - } - - finally { - reader.close(); + return Pair.empty(); } } } 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 66760d4ebdd..021bc4494a0 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) { - super(project); + super(project, null); } @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 ae3b12449be..f5bf2dcae15 100644 --- a/js/js.translator/src/org/jetbrains/k2js/config/Config.java +++ b/js/js.translator/src/org/jetbrains/k2js/config/Config.java @@ -17,6 +17,7 @@ package org.jetbrains.k2js.config; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetFile; @@ -25,6 +26,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import static org.jetbrains.k2js.translate.general.Translation.EcmaVersion; + /** * @author Pavel Talanov *

@@ -33,8 +36,8 @@ import java.util.List; public abstract class Config { @NotNull - public static Config getEmptyConfig(@NotNull Project project) { - return new Config(project) { + public static Config getEmptyConfig(@NotNull Project project, @Nullable String target) { + return new Config(project, target) { @NotNull @Override protected List generateLibFiles() { @@ -67,9 +70,12 @@ public abstract class Config { private final Project project; @Nullable private List libFiles = null; + @NotNull + private final EcmaVersion target; - public Config(@NotNull Project project) { + public Config(@NotNull Project project, @Nullable String target) { this.project = project; + this.target = StringUtil.compareVersionNumbers(target, "5") >= 0 ? EcmaVersion.v5 : EcmaVersion.v3; } @NotNull @@ -77,6 +83,11 @@ public abstract class Config { return project; } + @NotNull + public EcmaVersion getTarget() { + return target; + } + @NotNull protected abstract List generateLibFiles(); diff --git a/js/js.translator/src/org/jetbrains/k2js/config/ZippedLibrarySourcesConfig.java b/js/js.translator/src/org/jetbrains/k2js/config/ZippedLibrarySourcesConfig.java index dec84239cac..d873252e882 100644 --- a/js/js.translator/src/org/jetbrains/k2js/config/ZippedLibrarySourcesConfig.java +++ b/js/js.translator/src/org/jetbrains/k2js/config/ZippedLibrarySourcesConfig.java @@ -40,8 +40,8 @@ public class ZippedLibrarySourcesConfig extends Config { @Nullable protected final String pathToLibZip; - public ZippedLibrarySourcesConfig(@NotNull Project project, @Nullable String pathToZip) { - super(project); + public ZippedLibrarySourcesConfig(@NotNull Project project, @Nullable String pathToZip, @Nullable String target) { + super(project, target); pathToLibZip = pathToZip; } 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 99a0c17ee32..18025ec0cc8 100644 --- a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java @@ -103,7 +103,8 @@ public final class K2JSTranslator { JetStandardLibrary.initialize(config.getProject()); BindingContext bindingContext = AnalyzerFacadeForJS.analyzeFilesAndCheckErrors(filesToTranslate, config); Collection files = AnalyzerFacadeForJS.withJsLibAdded(filesToTranslate, config); - return Translation.generateAst(bindingContext, Lists.newArrayList(files), mainCallParameters); + + return Translation.generateAst(bindingContext, Lists.newArrayList(files), mainCallParameters, config.getTarget()); } //TODO: util 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 36ae40622ae..a1b50867982 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 @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.k2js.translate.context.generator.Generator; import org.jetbrains.k2js.translate.context.generator.Rule; +import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.intrinsic.Intrinsics; import org.jetbrains.k2js.translate.utils.AnnotationsUtils; import org.jetbrains.k2js.translate.utils.JsAstUtils; @@ -44,7 +45,7 @@ import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*; public final class StaticContext { public static StaticContext generateStaticContext(@NotNull JetStandardLibrary library, - @NotNull BindingContext bindingContext) { + @NotNull BindingContext bindingContext, Translation.EcmaVersion ecmaVersion) { JsProgram program = new JsProgram("main"); JsRootScope jsRootScope = program.getRootScope(); Namer namer = Namer.newInstance(jsRootScope); @@ -52,7 +53,7 @@ public final class StaticContext { Intrinsics intrinsics = Intrinsics.standardLibraryIntrinsics(library); StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope()); - return new StaticContext(program, bindingContext, namer, intrinsics, standardClasses, scope); + return new StaticContext(program, bindingContext, namer, intrinsics, standardClasses, scope, ecmaVersion); } @NotNull @@ -83,17 +84,24 @@ public final class StaticContext { @NotNull private final Map scopeToFunction = Maps.newHashMap(); + @NotNull + private final Translation.EcmaVersion ecmaVersion; //TODO: too many parameters in constructor private StaticContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext, - @NotNull Namer namer, @NotNull Intrinsics intrinsics, - @NotNull StandardClasses standardClasses, @NotNull NamingScope rootScope) { + @NotNull Namer namer, @NotNull Intrinsics intrinsics, + @NotNull StandardClasses standardClasses, @NotNull NamingScope rootScope, @NotNull Translation.EcmaVersion ecmaVersion) { this.program = program; this.bindingContext = bindingContext; this.namer = namer; this.intrinsics = intrinsics; this.rootScope = rootScope; this.standardClasses = standardClasses; + this.ecmaVersion = ecmaVersion; + } + + public boolean isEcma5() { + return ecmaVersion == Translation.EcmaVersion.v5; } @NotNull @@ -219,8 +227,25 @@ public final class StaticContext { if (!(descriptor instanceof PropertyDescriptor)) { return null; } + NamingScope enclosingScope = getEnclosingScope(descriptor); - return enclosingScope.declareObfuscatableName(Namer.getKotlinBackingFieldName(descriptor.getName())); + if (isEcma5()) { + String name = descriptor.getName(); + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + if (!isDefaultAccessor(propertyDescriptor.getGetter()) || !isDefaultAccessor(propertyDescriptor.getSetter())) { + // _ is more preferable than $ — should be discussed later + name = '_' + name; + } + + return enclosingScope.declareUnobfuscatableName(name); + } + else { + return enclosingScope.declareObfuscatableName(Namer.getKotlinBackingFieldName(descriptor.getName())); + } + } + + private boolean isDefaultAccessor(PropertyAccessorDescriptor accessorDescriptor) { + return accessorDescriptor == null || accessorDescriptor.isDefault(); } }; //TODO: hack! 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 2ffea662b1d..a55a17687e9 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 @@ -54,6 +54,10 @@ public final class TranslationContext { rootDynamicContext, rootAliasingContext); } + public boolean isEcma5() { + return staticContext.isEcma5(); + } + 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 f1f803550b5..bf67a37340b 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 @@ -36,8 +36,8 @@ import org.jetbrains.k2js.translate.utils.ClassSortingUtils; import java.util.ArrayList; import java.util.List; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getAllClassesDefinedInNamespace; import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; +import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getAllClassesDefinedInNamespace; /** * @author Pavel Talanov diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java index 9c6c9b1e2f2..c3c82da08a9 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java @@ -213,7 +213,10 @@ public final class ClassTranslator extends AbstractTranslator { if (!isTrait()) { propertyList.add(Translation.generateClassInitializerMethod(classDeclaration, classDeclarationContext)); } - propertyList.addAll(translatePropertiesAsConstructorParameters(classDeclarationContext)); + // skip for ecma5, because accessors defined via Object.defineProperties + if (!context().isEcma5()) { + propertyList.addAll(translatePropertiesAsConstructorParameters(classDeclarationContext)); + } propertyList.addAll(declarationBodyVisitor.traverseClass(classDeclaration, classDeclarationContext)); return JsAstUtils.newObjectLiteral(propertyList); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java index 0488084bc17..b3130f3520b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java @@ -29,6 +29,7 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyForDescriptor; @@ -53,6 +54,10 @@ public final class PropertyTranslator extends AbstractTranslator { static public List translateAccessors(@NotNull PropertyDescriptor descriptor, @NotNull TranslationContext context) { + if (context.isEcma5()) { + return Collections.emptyList(); + } + PropertyTranslator propertyTranslator = new PropertyTranslator(descriptor, context); return propertyTranslator.translate(); } 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 a73256bc3bc..a477c0deaea 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 @@ -61,6 +61,9 @@ import static org.jetbrains.k2js.translate.utils.dangerous.DangerousData.collect * Goal is to simlify interaction between translators. */ public final class Translation { + public enum EcmaVersion { + v3, v5 + } private Translation() { } @@ -142,9 +145,9 @@ public final class Translation { @NotNull public static JsProgram generateAst(@NotNull BindingContext bindingContext, - @NotNull List files, @NotNull MainCallParameters mainCallParameters) throws TranslationException { + @NotNull List files, @NotNull MainCallParameters mainCallParameters, EcmaVersion ecmaVersion) throws TranslationException { try { - return doGenerateAst(bindingContext, files, mainCallParameters); + return doGenerateAst(bindingContext, files, mainCallParameters, ecmaVersion); } catch (UnsupportedOperationException e) { throw new UnsupportedFeatureException("Unsupported feature used.", e); @@ -156,10 +159,10 @@ public final class Translation { @NotNull private static JsProgram doGenerateAst(@NotNull BindingContext bindingContext, @NotNull List files, - @NotNull MainCallParameters mainCallParameters) throws MainFunctionNotFoundException { + @NotNull MainCallParameters mainCallParameters, EcmaVersion ecmaVersion) throws MainFunctionNotFoundException { //TODO: move some of the code somewhere JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance(); - StaticContext staticContext = StaticContext.generateStaticContext(standardLibrary, bindingContext); + StaticContext staticContext = StaticContext.generateStaticContext(standardLibrary, bindingContext, ecmaVersion); JsBlock block = staticContext.getProgram().getFragmentBlock(0); TranslationContext context = TranslationContext.rootContext(staticContext); block.getStatements().addAll(translateFiles(files, context)); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java index f1438688fbd..c2ef7b08644 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java @@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.psi.JetParameter; 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 java.util.ArrayList; import java.util.List; @@ -43,12 +44,13 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateArgum * @author Pavel Talanov */ public final class ClassInitializerTranslator extends AbstractTranslator { - @NotNull private final JetClassOrObject classDeclaration; @NotNull private final List initializerStatements = new ArrayList(); + private final JsObjectLiteral propertiesDefinition = new JsObjectLiteral(); + public ClassInitializerTranslator(@NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context) { // Note: it's important we use scope for class descriptor because anonymous function used in property initializers // belong to the properties themselves @@ -65,8 +67,12 @@ public final class ClassInitializerTranslator extends AbstractTranslator { // for properties declared as constructor parameters setParameters(result, translatePrimaryConstructorParameters()); mayBeAddCallToSuperMethod(); - initializerStatements.addAll((new InitializerVisitor()).traverseClass(classDeclaration, context())); + initializerStatements.addAll((InitializerVisitor.create(context())).traverseClass(classDeclaration, context())); result.getBody().getStatements().addAll(initializerStatements); + if (!propertiesDefinition.getPropertyInitializers().isEmpty()) { + result.getBody().getStatements().add(JsAstUtils.defineProperties(propertiesDefinition)); + } + return InitializerUtils.generateInitializeMethod(result); } @@ -123,15 +129,20 @@ public final class ClassInitializerTranslator extends AbstractTranslator { } private void mayBeAddInitializerStatementForProperty(@NotNull JsParameter jsParameter, - @NotNull JetParameter jetParameter) { + @NotNull JetParameter jetParameter) { PropertyDescriptor propertyDescriptor = getPropertyDescriptorForConstructorParameter(bindingContext(), jetParameter); - if (propertyDescriptor != null) { - JsStatement assignmentToBackingFieldExpression = assignmentToBackingField - (context(), propertyDescriptor, jsParameter.getName().makeRef()).makeStmt(); + if (propertyDescriptor == null) { + return; + } + + final JsNameRef nameRef = jsParameter.getName().makeRef(); + if (context().isEcma5()) { + propertiesDefinition.getPropertyInitializers().add(JsAstUtils.propertyDescriptor(propertyDescriptor, context(), nameRef)); + } + else { + JsStatement assignmentToBackingFieldExpression = assignmentToBackingField(context(), propertyDescriptor, nameRef).makeStmt(); initializerStatements.add(assignmentToBackingFieldExpression); } } - - } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerEcma5Visitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerEcma5Visitor.java new file mode 100644 index 00000000000..106a82eccf7 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerEcma5Visitor.java @@ -0,0 +1,54 @@ +/* + * 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.initializer; + +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsObjectLiteral; +import com.google.dart.compiler.backend.js.ast.JsStatement; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.utils.JsAstUtils; + +import java.util.List; + +final class InitializerEcma5Visitor extends InitializerVisitor { + private final JsObjectLiteral propertiesDefinition = new JsObjectLiteral(); + + @Nullable + @Override + protected JsExpression defineMember(TranslationContext context, PropertyDescriptor propertyDescriptor, JsExpression value) { + propertiesDefinition.getPropertyInitializers().add(JsAstUtils.propertyDescriptor(propertyDescriptor, context, value)); + return null; + } + + @Override + protected List createStatements(List declarations, TranslationContext context) { + List statements = super.createStatements(declarations, context); + if (!propertiesDefinition.getPropertyInitializers().isEmpty()) { + JsStatement statement = JsAstUtils.defineProperties(propertiesDefinition); + if (statements.isEmpty()) { + statements.add(statement); + } + else { + statements.add(0, statement); + } + } + return statements; + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java index ab05b3209c7..94b4b88293d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java @@ -16,11 +16,9 @@ package org.jetbrains.k2js.translate.initializer; -import com.google.dart.compiler.backend.js.ast.JsExprStmt; -import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.backend.js.ast.JsInvocation; -import com.google.dart.compiler.backend.js.ast.JsStatement; +import com.google.dart.compiler.backend.js.ast.*; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.psi.*; @@ -36,6 +34,7 @@ import java.util.List; import static org.jetbrains.k2js.translate.general.Translation.translateAsStatement; import static org.jetbrains.k2js.translate.utils.BindingUtils.getDeclarationsForNamespace; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptor; import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForObjectDeclaration; import static org.jetbrains.k2js.translate.utils.PsiUtils.getObjectDeclarationForName; import static org.jetbrains.k2js.translate.utils.TranslationUtils.assignmentToBackingField; @@ -43,26 +42,25 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.assignmentToBa /** * @author Pavel Talanov */ -public final class InitializerVisitor extends TranslatorVisitor> { - - /*package*/ InitializerVisitor() { +class InitializerVisitor extends TranslatorVisitor> { + static InitializerVisitor create(TranslationContext context) { + return context.isEcma5() ? new InitializerEcma5Visitor() : new InitializerVisitor(); } @Override @NotNull - public List visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) { - JetExpression initializer = expression.getInitializer(); + public final List visitProperty(@NotNull JetProperty property, @NotNull TranslationContext context) { + JetExpression initializer = property.getInitializer(); if (initializer == null) { - return new ArrayList(); + return Collections.emptyList(); } - return Arrays.asList(translateInitializer(expression, context, initializer)); + return toStatements(defineMember(context, getPropertyDescriptor(context.bindingContext(), property), + Translation.translateAsExpression(initializer, context))); } - @NotNull - private static JsStatement translateInitializer(@NotNull JetProperty property, @NotNull TranslationContext context, - @NotNull JetExpression initializer) { - JsExpression initExpression = Translation.translateAsExpression(initializer, context); - return assignmentToBackingField(context, property, initExpression).makeStmt(); + @Nullable + protected JsExpression defineMember(TranslationContext context, PropertyDescriptor propertyDescriptor, JsExpression value) { + return assignmentToBackingField(context, propertyDescriptor, value); } @Override @@ -81,32 +79,37 @@ public final class InitializerVisitor extends TranslatorVisitor visitObjectDeclarationName(@NotNull JetObjectDeclarationName objectName, - @NotNull TranslationContext context) { - PropertyDescriptor propertyDescriptorForObjectDeclaration - = getPropertyDescriptorForObjectDeclaration(context.bindingContext(), objectName); + public final List visitObjectDeclarationName(@NotNull JetObjectDeclarationName objectName, + @NotNull TranslationContext context) { + PropertyDescriptor propertyDescriptor = getPropertyDescriptorForObjectDeclaration(context.bindingContext(), objectName); JetObjectDeclaration objectDeclaration = getObjectDeclarationForName(objectName); JsInvocation objectValue = ClassTranslator.generateClassCreationExpression(objectDeclaration, context); - JsExprStmt assignment = assignmentToBackingField(context, propertyDescriptorForObjectDeclaration, objectValue) - .makeStmt(); - return Collections.singletonList(assignment); + return toStatements(defineMember(context, propertyDescriptor, objectValue)); + } + + private static List toStatements(@Nullable JsExpression expression) { + return expression == null ? Collections.emptyList() : Collections.singletonList(expression.makeStmt()); + } + + protected List createStatements(List declarations, TranslationContext context) { + if (declarations.isEmpty()) { + return Collections.emptyList(); + } + + List statements = new ArrayList(declarations.size()); + for (JetDeclaration declaration : declarations) { + statements.addAll(declaration.accept(this, context)); + } + return statements; } @NotNull - public List traverseClass(@NotNull JetClassOrObject expression, @NotNull TranslationContext context) { - List initializerStatements = new ArrayList(); - for (JetDeclaration declaration : expression.getDeclarations()) { - initializerStatements.addAll(declaration.accept(this, context)); - } - return initializerStatements; + public final List traverseClass(@NotNull JetClassOrObject expression, @NotNull TranslationContext context) { + return createStatements(expression.getDeclarations(), context); } @NotNull - public List traverseNamespace(@NotNull NamespaceDescriptor namespace, @NotNull TranslationContext context) { - List initializerStatements = new ArrayList(); - for (JetDeclaration declaration : getDeclarationsForNamespace(context.bindingContext(), namespace)) { - initializerStatements.addAll(declaration.accept(this, context)); - } - return initializerStatements; + public final List traverseNamespace(@NotNull NamespaceDescriptor namespace, @NotNull TranslationContext context) { + return createStatements(getDeclarationsForNamespace(context.bindingContext(), namespace), context); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/NamespaceInitializerTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/NamespaceInitializerTranslator.java index 923cb522cce..d539718c14d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/NamespaceInitializerTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/NamespaceInitializerTranslator.java @@ -46,11 +46,10 @@ public final class NamespaceInitializerTranslator { JsFunction result = JsAstUtils.createFunctionWithEmptyBody(namespaceContext.jsScope()); TranslationContext namespaceInitializerContext = namespaceContext.innerContextWithGivenScopeAndBlock(result.getScope(), result.getBody()); - List initializerStatements = - (new InitializerVisitor()).traverseNamespace(namespace, namespaceInitializerContext); + + List initializerStatements = (InitializerVisitor.create(namespaceContext)).traverseNamespace(namespace, + namespaceInitializerContext); result.getBody().getStatements().addAll(initializerStatements); return InitializerUtils.generateInitializeMethod(result); } - - -} +} \ No newline at end of file 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 e3adc795fd5..798353c74de 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 @@ -24,9 +24,7 @@ import com.google.dart.compiler.backend.js.ast.JsNew; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.calls.ExpressionAsFunctionDescriptor; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.VariableAsFunctionResolvedCall; @@ -238,6 +236,17 @@ public final class CallTranslator extends AbstractTranslator { if (receiver != null) { setQualifier(callee, receiver); } + + if (context().isEcma5()) { + if (descriptor instanceof PropertyGetterDescriptor) { + return callee; + } + else if (descriptor instanceof PropertySetterDescriptor) { + assert arguments.size() == 1; + return assignment(callee, arguments.get(0)); + } + } + return newInvocation(callee, arguments); } }, context()); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/NativePropertyAccessTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/NativePropertyAccessTranslator.java index d0cafec5e4c..9e3ff6e7847 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/NativePropertyAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/NativePropertyAccessTranslator.java @@ -20,14 +20,13 @@ import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsName; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.utils.TranslationUtils; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getExpectedThisDescriptor; import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment; import static org.jetbrains.k2js.translate.utils.JsAstUtils.qualified; +import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getExpectedThisDescriptor; /** * @author Pavel Talanov @@ -73,7 +72,7 @@ public final class NativePropertyAccessTranslator extends PropertyAccessTranslat @NotNull protected JsExpression translateAsSet(@Nullable JsExpression receiver, @NotNull JsExpression setTo) { assert receiver != null; - return assignment(translateAsGet(getReceiver()), setTo); + return assignment(translateAsGet(receiver), setTo); } @NotNull @@ -83,7 +82,7 @@ public final class NativePropertyAccessTranslator extends PropertyAccessTranslat } @Nullable - public JsExpression getReceiver() { + private JsExpression getReceiver() { if (receiver != null) { return receiver; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java index 3858c20f211..df7fedefdea 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java @@ -21,6 +21,7 @@ import com.google.dart.compiler.backend.js.ast.JsName; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.k2js.translate.context.TranslationContext; @@ -55,8 +56,14 @@ public final class ReferenceTranslator { @NotNull public static JsExpression translateAsLocalNameReference(@NotNull DeclarationDescriptor referencedDescriptor, @NotNull TranslationContext context) { - JsName referencedName = context.getNameForDescriptor(referencedDescriptor); - return referencedName.makeRef(); + DeclarationDescriptor effectiveDescriptor; + if (context.isEcma5() && referencedDescriptor instanceof PropertyAccessorDescriptor) { + effectiveDescriptor = ((PropertyAccessorDescriptor) referencedDescriptor).getCorrespondingProperty(); + } + else { + effectiveDescriptor = referencedDescriptor; + } + return context.getNameForDescriptor(effectiveDescriptor).makeRef(); } @NotNull 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 cd27a872d82..2e31f258059 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 @@ -20,6 +20,9 @@ import com.google.common.collect.Lists; import com.google.dart.compiler.backend.js.ast.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.k2js.translate.context.TranslationContext; import java.util.*; @@ -27,6 +30,16 @@ import java.util.*; * @author Pavel Talanov */ public final class JsAstUtils { + private static final JsNameRef VALUE = new JsNameRef("value"); + private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(new JsNameRef("writable"), null) ; + private static final JsNameRef DEFINE_PROPERTIES = new JsNameRef("defineProperties"); + private static final JsNameRef CREATE = new JsNameRef("create"); + + static { + JsNameRef nameRef = new JsNameRef("Object"); + DEFINE_PROPERTIES.setQualifier(nameRef); + CREATE.setQualifier(nameRef); + } private JsAstUtils() { } @@ -272,4 +285,38 @@ public final class JsAstUtils { } return result; } + + @NotNull + public static JsStatement defineProperties(JsObjectLiteral propertiesDefinition) { + JsInvocation invoke = new JsInvocation(); + invoke.setQualifier(DEFINE_PROPERTIES); + invoke.getArguments().add(new JsThisRef()); + invoke.getArguments().add(propertiesDefinition); + return invoke.makeStmt(); + } + + @NotNull + public static JsPropertyInitializer propertyDescriptor(PropertyDescriptor ktDescriptor, + TranslationContext context, + JsExpression value) { + return propertyDescriptor(ktDescriptor, context, value, ktDescriptor.isVar()); + } + + @NotNull + public static JsPropertyInitializer propertyDescriptor(DeclarationDescriptor ktDescriptor, + TranslationContext context, + JsExpression value, + boolean writable) { + JsObjectLiteral descriptor = new JsObjectLiteral(); + List meta = descriptor.getPropertyInitializers(); + meta.add(new JsPropertyInitializer(VALUE, value)); + if (writable) { + if (WRITABLE.getValueExpr() == null) { + WRITABLE.setValueExpr(context.program().getTrueLiteral()); + } + meta.add(WRITABLE); + } + // todo accessors + return new JsPropertyInitializer(context.getNameForDescriptor(ktDescriptor).makeRef(), descriptor); + } } 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 efdf8c9a8a5..c7a87419c46 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 @@ -33,10 +33,9 @@ import java.util.List; import static com.google.dart.compiler.util.AstUtil.newAssignment; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; -import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptor; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getDeclarationDescriptorForReceiver; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getExpectedReceiverDescriptor; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; /** * @author Pavel Talanov @@ -204,13 +203,6 @@ public final class TranslationUtils { return intrinsic.apply(left, Arrays.asList(right), context); } - @NotNull - public static JsExpression assignmentToBackingField(@NotNull TranslationContext context, @NotNull JetProperty property, - @NotNull JsExpression initExpression) { - PropertyDescriptor propertyDescriptor = getPropertyDescriptor(context.bindingContext(), property); - return assignmentToBackingField(context, propertyDescriptor, initExpression); - } - @Nullable public static JsExpression resolveThisObjectForResolvedCall(@NotNull ResolvedCall call, @NotNull TranslationContext context) { @@ -219,6 +211,6 @@ public final class TranslationUtils { return null; } DeclarationDescriptor expectedThisDescriptor = getDeclarationDescriptorForReceiver(thisObject); - return TranslationUtils.getThisObject(context, expectedThisDescriptor); + return getThisObject(context, expectedThisDescriptor); } }