diff --git a/migrator/build.xml b/migrator/build.xml
index a3d1b797c671fa87db7eb15afb019b0056da2c54..a16ddfa0782124b72b3bff52e148dc4e66875fa0 100644
--- a/migrator/build.xml
+++ b/migrator/build.xml
@@ -202,6 +202,38 @@ ${test.err}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ One or several tests have failed!
+ STDERR:
+ ${test.err}
+
+
+
+
+
+
+
+
diff --git a/migrator/lib/kotlin-compiler/kotlin-test.jar b/migrator/lib/kotlin-compiler/kotlin-test.jar
new file mode 100644
index 0000000000000000000000000000000000000000..de1035f93d1fc1f2a85c9ead01a564d4bf4d5d04
Binary files /dev/null and b/migrator/lib/kotlin-compiler/kotlin-test.jar differ
diff --git a/migrator/src/com/ohos/migrator/kotlin/KotlinTransformer.java b/migrator/src/com/ohos/migrator/kotlin/KotlinTransformer.java
index 168912365fda6c3c08e9a3b14a7663dd9d45040c..1c05654be427c8de25eec84573fee9449a63fc85 100644
--- a/migrator/src/com/ohos/migrator/kotlin/KotlinTransformer.java
+++ b/migrator/src/com/ohos/migrator/kotlin/KotlinTransformer.java
@@ -15,35 +15,172 @@
package com.ohos.migrator.kotlin;
+import com.intellij.openapi.util.TextRange;
+import com.ohos.migrator.Main;
+import com.ohos.migrator.ResultCode;
import com.ohos.migrator.Transformer;
+import com.ohos.migrator.staticTS.NodeBuilder;
+import com.ohos.migrator.staticTS.parser.StaticTSParser;
import com.ohos.migrator.staticTS.parser.StaticTSParser.*;
import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+import com.intellij.psi.PsiElement;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
-import org.jetbrains.kotlin.psi.KtFile;
-import org.jetbrains.kotlin.psi.KtVisitor;
+import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils;
+import org.jetbrains.kotlin.lexer.KtTokens;
+import org.jetbrains.kotlin.psi.*;
+import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
+import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.BindingContext;
+import java.io.File;
+
/**
* Performs transformation of the Kotlin AST into StaticTS AST.
*/
public class KotlinTransformer extends KtVisitor implements Transformer {
+ File srcFile;
KtFile ktFile;
AnalysisResult analysisResult;
BindingContext bindingContext;
+ CompilationUnitContext stsCU;
- public KotlinTransformer(KtFile ktFile, AnalysisResult analysisResult) {
+ public KotlinTransformer(KtFile ktFile, File srcFile, AnalysisResult analysisResult) {
+ this.srcFile = srcFile;
this.ktFile = ktFile;
this.analysisResult = analysisResult;
this.bindingContext = analysisResult.getBindingContext();
}
public CompilationUnitContext transform() {
- return (CompilationUnitContext)visitKtFile(ktFile, null);
+ return visitKtFile(ktFile, null);
+ }
+
+ private PsiDiagnosticUtils.LineAndColumn getLineAndColumn(PsiElement psiElement) {
+ TextRange textRange;
+
+ if (psiElement == null) {
+ return PsiDiagnosticUtils.LineAndColumn.NONE;
+ }
+
+ if (psiElement instanceof KtDeclaration) {
+ // If any comment precedes function or class declaration, then it will
+ // be considered a part of declaration and will affect the calculation
+ // of node's line number.
+ textRange = PsiUtilsKt.getTextRangeWithoutComments(psiElement);
+ } else {
+ textRange = psiElement.getTextRange();
+ }
+
+ return PsiDiagnosticUtils.offsetToLineAndColumn(ktFile.getViewProvider().getDocument(), textRange.getStartOffset());
+ }
+
+ private void reportError(String message, PsiElement ktNode) {
+ String loc = srcFile.getPath() + ":" + getLineAndColumn(ktNode);
+ Main.addError(ResultCode.TranspileError, message + " at " + loc);
+ }
+
+
+ /**
+ * Visit element's children and add result of translation of each child to the specified STS context.
+ */
+ private void visitChildren(KtElement ktElement, ParserRuleContext stsContext) {
+ for (PsiElement child : ktElement.getChildren()) {
+ if (child instanceof KtElement) {
+ ParserRuleContext stsResult = ((KtElement) child).accept(this, null);
+
+ if (stsResult != null && stsContext != null) {
+ stsContext.addChild(stsResult).setParent(stsContext);
+ }
+ }
+ }
+ }
+
+ // Default visit method for kotlin node. Simply visit all children of the element.
+ @Override
+ public ParserRuleContext visitKtElement(KtElement ktElement, Void data) {
+ visitChildren(ktElement, null);
+ return null;
}
@Override
- public ParserRuleContext visitKtFile(KtFile node, Void data) {
- return new CompilationUnitContext(null, 0);
+ public CompilationUnitContext visitKtFile(KtFile ktFile, Void data) {
+ stsCU = new CompilationUnitContext(null, 0);
+ visitChildren(ktFile, stsCU);
+ return stsCU;
}
+
+ @Override
+ public ParserRuleContext visitPackageDirective(KtPackageDirective ktPackageDirective, Void data) {
+ PackageDeclarationContext stsPackage = new PackageDeclarationContext(null, 0);
+ stsPackage.addChild(NodeBuilder.terminalNode(StaticTSParser.Package));
+ stsPackage.addChild(NodeBuilder.qualifiedName(ktPackageDirective.getQualifiedName())).setParent(stsPackage);
+ return stsPackage;
+ }
+
+ @Override
+ public ParserRuleContext visitImportDirective(KtImportDirective ktImportDirective, Void data) {
+ ImportDeclarationContext stsImport = new ImportDeclarationContext(null, 0);
+ stsImport.addChild(NodeBuilder.terminalNode(StaticTSParser.Import));
+ stsImport.addChild(NodeBuilder.qualifiedName(ktImportDirective.getImportedFqName().asString())).setParent(stsImport);
+
+ String alias = ktImportDirective.getAliasName();
+ if (alias != null && !alias.isEmpty()) {
+ stsImport.addChild(NodeBuilder.terminalNode(StaticTSParser.As));
+ stsImport.addChild(NodeBuilder.terminalIdentifier(alias));
+ }
+ else if (ktImportDirective.isAllUnder()) {
+ stsImport.addChild(NodeBuilder.terminalNode(StaticTSParser.Dot));
+ stsImport.addChild(NodeBuilder.terminalNode(StaticTSParser.Multiply));
+ }
+
+ stsCU.addChild(stsImport);
+
+ return null;
+ }
+
+ @Override
+ public ParserRuleContext visitClass(KtClass ktClass, Void data) {
+ ParserRuleContext stsResult;
+
+// if (ktClass.isInterface()) {
+// stsResult = new InterfaceDeclarationContext(null, 0);
+// stsResult.addChild(NodeBuilder.terminalNode(StaticTSParser.Interface));
+// } else {
+ stsResult = new ClassDeclarationContext(null, 0);
+ stsResult.addChild(NodeBuilder.terminalNode(StaticTSParser.Class));
+// }
+
+ if (KtPsiUtilKt.isAbstract(ktClass))
+ stsResult.addChild(NodeBuilder.terminalNode(StaticTSParser.Abstract));
+ else if (ktClass.hasModifier(KtTokens.OPEN_KEYWORD))
+ stsResult.addChild(NodeBuilder.terminalNode(StaticTSParser.Open));
+
+
+ stsResult.addChild(NodeBuilder.terminalIdentifier(ktClass.getName()));
+
+ ClassBodyContext stsClassBody = new ClassBodyContext(stsResult, 0);
+ stsResult.addChild(stsClassBody).setParent(stsResult);
+
+ visitChildren(ktClass, stsClassBody);
+
+ if (ktClass.isTopLevel()) {
+ TopDeclarationContext stsTopDecl = new TopDeclarationContext(null, 0);
+
+ if (KtPsiUtilKt.isPublic(ktClass)) {
+ stsTopDecl.addChild(NodeBuilder.terminalNode(StaticTSParser.Export));
+ }
+
+ stsTopDecl.addChild(stsResult).setParent(stsTopDecl);
+ stsResult = stsTopDecl;
+ }
+ // else {
+ // TODO: inner, nested, local
+ // }
+
+ return stsResult;
+ }
+
}
\ No newline at end of file
diff --git a/migrator/src/com/ohos/migrator/kotlin/KotlinTranspiler.java b/migrator/src/com/ohos/migrator/kotlin/KotlinTranspiler.java
index ec393871f92e8834e8e13e31a0f562646c4831c4..a9087d65d3eb5430f83e899b41029fbc9e5ca1c0 100644
--- a/migrator/src/com/ohos/migrator/kotlin/KotlinTranspiler.java
+++ b/migrator/src/com/ohos/migrator/kotlin/KotlinTranspiler.java
@@ -16,9 +16,11 @@
package com.ohos.migrator.kotlin;
import com.ohos.migrator.AbstractTranspiler;
+import com.ohos.migrator.Main;
import com.ohos.migrator.ResultCode;
import com.ohos.migrator.TranspileException;
import com.ohos.migrator.staticTS.parser.StaticTSParser.CompilationUnitContext;
+
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
@@ -36,10 +38,14 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil;
import org.jetbrains.kotlin.psi.KtFile;
+import org.jetbrains.kotlin.utils.PathUtil;
import java.io.File;
import java.io.IOException;
+import java.net.URISyntaxException;
import java.util.*;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
/**
* Kotlin to StaticTS transpiler class inherited from AbstractTranspiler class.
@@ -54,6 +60,8 @@ public class KotlinTranspiler extends AbstractTranspiler {
CompilerConfiguration configuration;
KotlinCoreEnvironment environment;
+ String MANIFEST_IMPLEMENTATION_TITLE = "Implementation-Title";
+
static {
org.jetbrains.kotlin.cli.common.environment.UtilKt.setIdeaIoUseFallback();
}
@@ -116,8 +124,50 @@ public class KotlinTranspiler extends AbstractTranspiler {
// Add user-defined classpaths.
JvmContentRootsKt.addJvmClasspathRoots(configuration, libFiles);
- // TODO: Add Kotlin standard library?
- // TODO: Add JDK standard library?
+ // Configure kotlin libraries.
+ JvmContentRootsKt.addJvmClasspathRoots(configuration, getKotlinJars());
+
+ // Configure JDK classpaths.
+ JvmContentRootsKt.configureJdkClasspathRoots(configuration);
+ }
+
+ private List getKotlinJars() {
+ // NOTE: The Kotlin libraries are currently placed in the same
+ // directory as the application jar.
+ File[] jarFiles = null;
+ try {
+ File libDir = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile();
+ jarFiles = libDir.listFiles(file -> isBuiltinKotlinJar(getManifestImplementationTitle(file)));
+ } catch (URISyntaxException e1)
+ {}
+
+ /* Just to be safe */
+ if (jarFiles == null) {
+ return new ArrayList<>();
+ }
+ return Arrays.asList(jarFiles);
+ }
+
+ private boolean isBuiltinKotlinJar(String name) {
+ return (name != null &&
+ (name.startsWith(PathUtil.KOTLIN_JAVA_STDLIB_NAME) || // kotlin-stdlib
+ name.equals(PathUtil.KOTLIN_TEST_NAME) || // kotlin-test
+ name.equals(PathUtil.KOTLIN_JAVA_REFLECT_NAME) || // kotlin-reflect
+ name.equals(PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_NAME))); // kotlin-script-runtime
+ }
+
+ private String getManifestImplementationTitle(File file){
+ try {
+ JarFile jarFile = new JarFile(file);
+ Manifest manifest = jarFile.getManifest();
+
+ if (manifest == null) {
+ return null;
+ }
+ return manifest.getMainAttributes().getValue(MANIFEST_IMPLEMENTATION_TITLE);
+ } catch (IOException e) {
+ return null;
+ }
}
@Override
@@ -129,7 +179,7 @@ public class KotlinTranspiler extends AbstractTranspiler {
AnalysisResult analysisResult = analyze(sourceToKotlin.values());
for (Map.Entry entry : sourceToKotlin.entrySet()) {
- CompilationUnitContext stsCU = transform(entry.getValue(), analysisResult);
+ CompilationUnitContext stsCU = transform(entry.getValue(), entry.getKey(), analysisResult);
write(stsCU, entry.getKey());
}
} catch (Exception e) {
@@ -177,8 +227,8 @@ public class KotlinTranspiler extends AbstractTranspiler {
return analyzer.getAnalysisResult();
}
- private CompilationUnitContext transform(KtFile ktFile, AnalysisResult analysisResult) {
- KotlinTransformer transformer = new KotlinTransformer(ktFile, analysisResult);
+ private CompilationUnitContext transform(KtFile ktFile, File srcFile, AnalysisResult analysisResult) {
+ KotlinTransformer transformer = new KotlinTransformer(ktFile, srcFile, analysisResult);
return transformer.transform();
}
diff --git a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java
index 3fba2b340c05af650cc40a037126c2d75d643142..44b7c04f3e20d1234288321b69d7b34e9f5b63d4 100644
--- a/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java
+++ b/migrator/src/com/ohos/migrator/staticTS/writer/StaticTSWriter.java
@@ -750,7 +750,7 @@ public class StaticTSWriter extends StaticTSParserBaseVisitor {
sb.append(termMult.getText());
}
else if (termAs != null) {
- sb.append(termAs.getText()).append(' ');
+ sb.append(' ').append(termAs.getText()).append(' ');
TerminalNode termId = stsImportDeclatation.Identifier();
assert(termId != null);
sb.append(termId.getText());
diff --git a/migrator/test/kotlin/empty_class_declaration.kt b/migrator/test/kotlin/empty_class_declaration.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2509632ccd9876fa8f3a32dc70a9cdb8b26f7ee0
--- /dev/null
+++ b/migrator/test/kotlin/empty_class_declaration.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022-2022 Huawei Device Co., Ltd.
+ * 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 com.ohos.migrator.test.kotlin;
+
+class Empty
+
+class EmptyWithBody { }
+
+abstract class AbstractClass
+
+open class OpenClass
+
+final class FinalClass
+
+public class PublicClass
+
+private class PrivateClass
+
+internal class InternalClass
\ No newline at end of file
diff --git a/migrator/test/kotlin/empty_class_declaration.kt.sts b/migrator/test/kotlin/empty_class_declaration.kt.sts
new file mode 100644
index 0000000000000000000000000000000000000000..b6c4a7ba783014c469544b820a484cb9c78b33d0
--- /dev/null
+++ b/migrator/test/kotlin/empty_class_declaration.kt.sts
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022-2022 Huawei Device Co., Ltd.
+ * 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 com.ohos.migrator.test.kotlin;
+
+export class Empty {
+}
+
+export class EmptyWithBody {
+}
+
+export abstract class AbstractClass {
+}
+
+export open class OpenClass {
+}
+
+export class FinalClass {
+}
+
+export class PublicClass {
+}
+
+class PrivateClass {
+}
+
+class InternalClass {
+}
+
+
diff --git a/migrator/test/kotlin/imports.kt b/migrator/test/kotlin/imports.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b9339a12cb106b908b538e420e7a274d3457665a
--- /dev/null
+++ b/migrator/test/kotlin/imports.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022-2022 Huawei Device Co., Ltd.
+ * 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 com.ohos.migrator.test.kotlin;
+
+import kotlin.random.Random; // Random is now accessible without qualification
+import kotlin.math.*; // everything in 'kotlin.math' becomes accessible
+import kotlin.reflect.KClass as Class // 'Class' stands for kotlin.reflect.KClass
+
+fun main() {
+ println(PI);
+
+ var rnd : Random = Random(5);
+
+ var kk : Class;
+}
\ No newline at end of file
diff --git a/migrator/test/kotlin/imports.kt.sts b/migrator/test/kotlin/imports.kt.sts
new file mode 100644
index 0000000000000000000000000000000000000000..38e0ee32a1892db52ec7bc3675e5294115354dae
--- /dev/null
+++ b/migrator/test/kotlin/imports.kt.sts
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2022-2022 Huawei Device Co., Ltd.
+ * 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 com.ohos.migrator.test.kotlin;
+
+import kotlin.random.Random;
+import kotlin.math.*;
+import kotlin.reflect.KClass as Class;
\ No newline at end of file