diff --git a/migrator/src/com/ohos/migrator/AbstractTranspiler.java b/migrator/src/com/ohos/migrator/AbstractTranspiler.java index 2cc14383f9ec1278c025f00bf27a4d20071be99f..4c263ce325473173b553219e0a6325906aafa61d 100644 --- a/migrator/src/com/ohos/migrator/AbstractTranspiler.java +++ b/migrator/src/com/ohos/migrator/AbstractTranspiler.java @@ -17,6 +17,7 @@ package com.ohos.migrator; import com.ohos.migrator.staticTS.parser.StaticTSParser.CompilationUnitContext; import com.ohos.migrator.staticTS.writer.StaticTSWriter; +import com.ohos.migrator.util.FileUtils; import java.io.File; import java.io.FileWriter; @@ -54,12 +55,19 @@ public abstract class AbstractTranspiler implements Transpiler { public ResultCode transpile() { ResultCode transpileResult = ResultCode.OK; - for (File f:sourceFiles) { + for (File f : sourceFiles) { try { transpileFile(f); } catch (TranspileException e) { + // On parse errors, write commented-out + // contents of input file to output file + ResultCode result = e.getResult(); + if (result == ResultCode.ParseError) + writeUntranslatedFile(f); + errorList.add(e); - transpileResult = ResultCode.majorValue(e.getResult(), transpileResult); + + transpileResult = ResultCode.majorValue(result, transpileResult); if (Main.isStrictMode()) return transpileResult; } catch (Exception e) { @@ -69,7 +77,7 @@ public abstract class AbstractTranspiler implements Transpiler { for (StackTraceElement ste : e.getStackTrace()) sb.append(ste.toString()).append("\n"); - errorList.add(new TranspileException(ResultCode.InputError, sb.toString())); + errorList.add(new TranspileException(ResultCode.TranspileError, sb.toString())); transpileResult = ResultCode.majorValue(ResultCode.TranspileError, transpileResult); if (Main.isStrictMode()) return transpileResult; } @@ -82,9 +90,7 @@ public abstract class AbstractTranspiler implements Transpiler { protected void write(CompilationUnitContext stsCU, File srcFile) { try { - File outFile = new File(srcFile.getPath() + Main.STS_EXT); - if (outDir != null) outFile = new File(outDir, outFile.getName()); - + File outFile = getOutFile(srcFile); StaticTSWriter writer = new StaticTSWriter(outFile.getPath()); writer.visit(stsCU); writer.close(); @@ -93,10 +99,27 @@ public abstract class AbstractTranspiler implements Transpiler { } catch (IOException e) { // TODO: - System.out.println(e); + System.err.println(e); } } + private File getOutFile(File srcFile) { + File outFile = new File(srcFile.getPath() + Main.STS_EXT); + if (outDir != null) outFile = new File(outDir, outFile.getName()); + return outFile; + } + + protected void writeUntranslatedFile(File srcFile) { + File outFile = getOutFile(srcFile); + try (FileWriter outFW = new FileWriter(outFile.getPath())){ + outFW.write("/* Untranslated source code:\n"); + FileUtils.copyFile(srcFile, outFW); + outFW.write("*/\n"); + } + catch (IOException ioe) { + System.err.println(ioe); + } + } @Override public double getConversionRate() { return 0; diff --git a/migrator/src/com/ohos/migrator/Main.java b/migrator/src/com/ohos/migrator/Main.java index fe277dd1cca6857381b0b0b42a0baac998e1d782..9663c2e9d57a292857e7841fd76f229ef23439dd 100644 --- a/migrator/src/com/ohos/migrator/Main.java +++ b/migrator/src/com/ohos/migrator/Main.java @@ -43,19 +43,22 @@ public class Main { static boolean convRateMode = false; public static void finish(ResultCode exitCode) { - if(verboseMode) { + if (verboseMode) { for (TranspileException e: errorList) { + String errorName = e.getResult().getErrorName(); + System.err.print("[" + errorName + "] "); + if (e.getCause() != null) - System.err.println("[error] " + e.getCause().getMessage()); + System.err.println(e.getCause().getMessage()); else - System.err.println("[error] " + e.getMessage()); + System.err.println(e.getMessage()); } } if (!runningTests) - System.exit(exitCode.value); + System.exit(exitCode.value); - errorList = new ArrayList<>(); + errorList = new ArrayList<>(); } private static boolean runningTests = false; diff --git a/migrator/src/com/ohos/migrator/ResultCode.java b/migrator/src/com/ohos/migrator/ResultCode.java index 00b852ec8e7c0e4ab1b28ba9882f56b269c7af4d..777ca18646308c67ef9c99a31f2c3ebf18256f51 100644 --- a/migrator/src/com/ohos/migrator/ResultCode.java +++ b/migrator/src/com/ohos/migrator/ResultCode.java @@ -47,4 +47,19 @@ public enum ResultCode { return OK; } + + public String getErrorName() { + switch (this) { + case CmdLineError: + return "command-line error"; + case InputError: + return "input file error"; + case ParseError: + return "parse error"; + case TranspileError: + return "transpile error"; + default: + return ""; + } + } } diff --git a/migrator/src/com/ohos/migrator/java/JavaParser.java b/migrator/src/com/ohos/migrator/java/JavaParser.java index 214f4c7cb7e1934822b5fe4f5adf5cc10c9baaf1..203a79f27cc30b2397b424823ebfaceb9d4ed641 100644 --- a/migrator/src/com/ohos/migrator/java/JavaParser.java +++ b/migrator/src/com/ohos/migrator/java/JavaParser.java @@ -17,6 +17,7 @@ package com.ohos.migrator.java; import com.ohos.migrator.Main; import com.ohos.migrator.ResultCode; +import com.ohos.migrator.TranspileException; import com.ohos.migrator.util.FileUtils; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -102,7 +103,7 @@ public class JavaParser { // only care about package name. parser.setFocalPosition(0); - CompilationUnit cu = (CompilationUnit) parser.createAST(null); + CompilationUnit cu = createCU(parser); if (cu != null) { PackageDeclaration pkg = cu.getPackage(); @@ -112,7 +113,7 @@ public class JavaParser { packagePath = packagePath.replace('.', File.separatorChar); } } - } catch (IOException ex) { + } catch (Exception ex) { caughtEx = ex; } finally { // Warn if in verbose mode and package path is null @@ -180,6 +181,19 @@ public class JavaParser { return parser; } + private static CompilationUnit createCU(ASTParser parser) throws JavaParserException { + CompilationUnit cu = null; + try { + cu = (CompilationUnit) parser.createAST(null); + } + catch (Exception e) { + throw new JavaParserException(e); + } + + if (cu == null) throw new JavaParserException("unknown Java parsing error"); + + return cu; + } public CompilationUnit parse() throws JavaParserException { ASTParser parser = createASTParser(ASTParser.K_COMPILATION_UNIT); parser.setSource(source); @@ -196,8 +210,7 @@ public class JavaParser { parser.setEnvironment(classpathEntries, sourcepathEntries, null, includeRunningVMBootclasspath); parser.setUnitName(sourceFile.getPath()); - CompilationUnit cu = (CompilationUnit) parser.createAST(null); - if (cu == null) throw new JavaParserException("unknown Java parsing error"); + CompilationUnit cu = createCU(parser); // In strict mode, terminate on syntax or semantic errors; // otherwise, report them and continue. diff --git a/migrator/src/com/ohos/migrator/java/JavaParserException.java b/migrator/src/com/ohos/migrator/java/JavaParserException.java index 8dad5a2bc25ffd6cf926f6273253ab6930dac448..f6541d877f44c749050be5ad6d13aee11900090b 100644 --- a/migrator/src/com/ohos/migrator/java/JavaParserException.java +++ b/migrator/src/com/ohos/migrator/java/JavaParserException.java @@ -33,5 +33,9 @@ public class JavaParserException extends Exception { public JavaParserException(String s) { super(s); } + + public JavaParserException(Throwable cause) { + super(cause); + } } diff --git a/migrator/src/com/ohos/migrator/java/JavaTransformer.java b/migrator/src/com/ohos/migrator/java/JavaTransformer.java index 35347934524f4b2f766c04726d2ab64a01f61575..5068db07eb629032bcf6ddea3153eea3b6c27972 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTransformer.java +++ b/migrator/src/com/ohos/migrator/java/JavaTransformer.java @@ -53,6 +53,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { private final String USED_IN_ANOTHER_CASE_CLAUSE = "USED_IN_ANOTHER_CASE_CLAUSE"; private final String ENUM_TYPE_NAME = "ENUM_TYPE_NAME"; private final String ENUM_CONST_ORDINAL = "ENUM_CONST_ORDINAL"; + + private final String OUTER_OBJECT = "OUTER_OBJECT"; + + private final String CTOR_ARGUMENTS = "CTOR_ARGUMENTS"; private final String RUNTIME_EXCEPTION_TYPE_NAME = "java.lang.RuntimeException"; private final String THROWABLE_TYPE_NAME = "java.lang.Throwable"; @@ -783,7 +787,7 @@ public class JavaTransformer extends ASTVisitor implements Transformer { return stsMemberContext; } - private void addInstanceInitializersToCtors(AbstractTypeDeclaration javaTypeDeclaration) { + private ConstructorDeclarationContext addInstanceInitializersToCtors(ASTNode javaTypeDeclaration) { // Put statements from instance initializers into constructors which don't call // another constructor (i.e. don't have 'this()' call). List stsInitStmts = (List)javaTypeDeclaration.getProperty(INSTANCE_INITIALIZER); @@ -823,8 +827,10 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ClassMemberContext addInstanceInitializersToCtor(stsDefaultCtor, stsInitStmts); + return stsDefaultCtor; } } + return null; } private void addInstanceInitializersToCtor(ConstructorDeclarationContext stsCtorDecl, List stsInitStmts) { // Sanity check. @@ -2870,20 +2876,24 @@ public class JavaTransformer extends ASTVisitor implements Transformer { popCurrent(); // ConstructorCallContext } - private void translateArguments(List javaArgs) { + private List translateArguments(List javaArgs) { pushCurrent(new ArgumentsContext(stsCurrent, 0)); + List result = null; if (javaArgs != null && !javaArgs.isEmpty()) { - pushCurrent(new ExpressionSequenceContext(stsCurrent, 0)); + ExpressionSequenceContext stsExprSeq = new ExpressionSequenceContext(stsCurrent, 0); + pushCurrent(stsExprSeq); for (Expression javaExpr : javaArgs) { javaExpr.accept(this); } popCurrent(); // ExpressionSequenceContext + result = stsExprSeq.singleExpression(); } popCurrent(); // ArgumentsContext + return result; } // Java tree: @@ -3017,18 +3027,45 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // STS tree: // classBody: OpenBrace classMember* clinit=classInitializer? classMember* CloseBrace @Override - public boolean visit(AnonymousClassDeclaration javaAnonymousClassDeclaration) { + public boolean visit(AnonymousClassDeclaration javaAnonClassDecl) { pushCurrent(new ClassBodyContext(stsCurrent, 0)); - List javaBodyDeclarations = javaAnonymousClassDeclaration.bodyDeclarations(); - assert (javaBodyDeclarations != null); - for (BodyDeclaration javaBodyDeclaration : javaBodyDeclarations) { - javaBodyDeclaration.accept(this); + List javaBodyDeclarations = javaAnonClassDecl.bodyDeclarations(); + if (javaBodyDeclarations != null && !javaBodyDeclarations.isEmpty()) { + for (BodyDeclaration javaBodyDeclaration : javaBodyDeclarations) { + javaBodyDeclaration.accept(this); + } + + // If we saw an instance initializer, create ctor and put initializer statements into it. + if (javaAnonClassDecl.getProperty(INSTANCE_INITIALIZER) != null) { + ConstructorDeclarationContext stsCtor = addInstanceInitializersToCtors(javaAnonClassDecl); + + if (stsCtor != null) { + // Create superclass' ctor call and pass it ctor arguments and + // outer instance (if any) from the parent context. + List stsCtorArgs = new ArrayList<>(); + Object outerObjProp = javaAnonClassDecl.getProperty(OUTER_OBJECT); + if (outerObjProp != null) stsCtorArgs.add((SingleExpressionContext)outerObjProp); + + Object ctorArgsProp = javaAnonClassDecl.getProperty(CTOR_ARGUMENTS); + if (ctorArgsProp != null) { + stsCtorArgs.addAll((List)ctorArgsProp); + } + + ConstructorCallContext stsSuperCtorCall = + NodeBuilder.ctorCall(true,outerObjProp != null, + stsCtorArgs.toArray(new SingleExpressionContext[0])); + + ConstructorBodyContext stsCtorBody = stsCtor.constructorBody(); + stsCtorBody.children.add(0, stsSuperCtorCall); + stsSuperCtorCall.setParent(stsCtorBody); + } + } } popCurrent(); // ClassBodyContext - declTransformed.add(javaAnonymousClassDeclaration); + declTransformed.add(javaAnonClassDecl); return false; } @@ -3068,9 +3105,11 @@ public class JavaTransformer extends ASTVisitor implements Transformer { // Add outer class object, if any. Expression javaOuterObject = javaClassInstanceCreation.getExpression(); + SingleExpressionContext stsOuterObject = null; if (javaOuterObject != null) { pushCurrent(new NewInnerClassInstanceExpressionContext(pushSingleExpression())); javaOuterObject.accept(this); + stsOuterObject = ((NewInnerClassInstanceExpressionContext)stsCurrent).singleExpression(); } else { pushCurrent(new NewClassInstanceExpressionContext(pushSingleExpression())); @@ -3081,10 +3120,19 @@ public class JavaTransformer extends ASTVisitor implements Transformer { javaClassInstanceCreation.getType().accept(this); - translateArguments(javaClassInstanceCreation.arguments()); + List stsArgs = translateArguments(javaClassInstanceCreation.arguments()); AnonymousClassDeclaration javaAnonymousClassDeclaration = javaClassInstanceCreation.getAnonymousClassDeclaration(); if (javaAnonymousClassDeclaration != null) { + // Store outer object and ctor arguments (if any) in javaAnonymousClassDeclaration. + // We might need them if anonymous class contains instance initializer, see + // visit(AnonymousClassDeclaration) for details. + if (stsOuterObject != null) + javaAnonymousClassDeclaration.setProperty(OUTER_OBJECT, stsOuterObject); + + if (stsArgs != null && !stsArgs.isEmpty()) + javaAnonymousClassDeclaration.setProperty(CTOR_ARGUMENTS, stsArgs); + javaAnonymousClassDeclaration.accept(this); } diff --git a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java index 0579956eefae7f5c4140b07d3c0f51b49b43c79d..3899959e7a0a9cc08272f0e0a112b16b605ee880 100644 --- a/migrator/src/com/ohos/migrator/java/JavaTranspiler.java +++ b/migrator/src/com/ohos/migrator/java/JavaTranspiler.java @@ -55,7 +55,15 @@ public class JavaTranspiler extends AbstractTranspiler { } catch (IOException e) { throw new TranspileException(ResultCode.InputError, e); } catch (JavaParserException e) { - throw new TranspileException(ResultCode.ParseError, e); + StringBuilder sb = new StringBuilder("Failed to parse "); + sb.append(srcFile.getPath()).append(" due to "); + if (e.getCause() != null) { + sb.append(e.getCause().toString()); + } + else + sb.append(e.getMessage()); + + throw new TranspileException(ResultCode.ParseError, sb.toString()); } } diff --git a/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java b/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java index ed9ac8f233512f45daff6ec7000324b3d5435c52..86f4f94951fab13ab38caf4c751d58d72b84a0ba 100644 --- a/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java +++ b/migrator/src/com/ohos/migrator/staticTS/NodeBuilderBase.java @@ -23,12 +23,14 @@ import org.antlr.v4.runtime.Vocabulary; import org.antlr.v4.runtime.tree.TerminalNode; import org.antlr.v4.runtime.tree.TerminalNodeImpl; +import java.util.ArrayList; +import java.util.List; + public class NodeBuilderBase { private static final Vocabulary vocabulary = StaticTSParser.VOCABULARY; protected static final String UNKNOWN_TYPE_NAME = "__UnknownType__"; protected static final String UNTRANSLATED_EXPRESSION = "__untranslated_expression"; protected static final String UNTRANSLATED_STATEMENT = "__untranslated_statement"; - public static TerminalNode terminalNode(int type) { return new TerminalNodeImpl(new CommonToken(type, stsName(type))); } @@ -250,34 +252,25 @@ public class NodeBuilderBase { return stsArrayType; } - public static TypeAnnotationContext typeAnnotation(TypeReferenceContext stsTypeRef) { + public static TypeAnnotationContext typeAnnotation(ParserRuleContext stsType) { + if (stsType.getRuleIndex() != StaticTSParser.RULE_predefinedType && + stsType.getRuleIndex() != StaticTSParser.RULE_arrayType && + stsType.getRuleIndex() != StaticTSParser.RULE_typeReference) { + // Sanity check. Shouldn't even get here. + return unknownTypeAnnotation(); + } + TypeAnnotationContext stsTypeAnno = new TypeAnnotationContext(null, 0); PrimaryTypeContext stsPrimaryType = new PrimaryTypeContext(stsTypeAnno, 0); - stsPrimaryType.addChild(stsTypeRef).setParent(stsPrimaryType); + stsPrimaryType.addChild(stsType).setParent(stsPrimaryType); stsTypeAnno.addChild(stsPrimaryType).setParent(stsTypeAnno); return stsTypeAnno; } - public static TypeAnnotationContext typeAnnotation(String stsTypeName) { TypeReferenceContext stsTypeRef = typeReference(stsTypeName); return typeAnnotation(stsTypeRef); } - public static TypeAnnotationContext typeAnnotation(PredefinedTypeContext stsPredefType) { - TypeAnnotationContext stsTypeAnno = new TypeAnnotationContext(null, 0); - PrimaryTypeContext stsPrimaryType = new PrimaryTypeContext(stsTypeAnno, 0); - stsPrimaryType.addChild(stsPredefType).setParent(stsPrimaryType); - stsTypeAnno.addChild(stsPrimaryType).setParent(stsTypeAnno); - return stsTypeAnno; - } - public static TypeAnnotationContext typeAnnotation(ArrayTypeContext stsArrayType) { - TypeAnnotationContext stsTypeAnno = new TypeAnnotationContext(null, 0); - PrimaryTypeContext stsPrimaryType = new PrimaryTypeContext(stsTypeAnno, 0); - stsPrimaryType.addChild(stsArrayType).setParent(stsPrimaryType); - stsTypeAnno.addChild(stsPrimaryType).setParent(stsTypeAnno); - return stsTypeAnno; - } - public static ParameterContext parameter(String stsParamName, String stsParamType) { ParameterContext stsParam = new ParameterContext(null, 0); stsParam.addChild(terminalIdentifier(stsParamName)); @@ -285,22 +278,49 @@ public class NodeBuilderBase { return stsParam; } + public static ParameterContext parameter(String stsParamName, ParserRuleContext stsParamType) { + ParameterContext stsParam = new ParameterContext(null, 0); + stsParam.addChild(terminalIdentifier(stsParamName)); + stsParam.addChild(typeAnnotation(stsParamType)).setParent(stsParam); + return stsParam; + } public static ConstructorCallContext ctorCall(boolean isSuperCall, String... stsArgNames) { + List stsArgs = new ArrayList<>(); + for (String stsArgName : stsArgNames) { + stsArgs.add(identifierExpression(stsArgName)); + } + + return ctorCall(isSuperCall, false, stsArgs.toArray(new SingleExpressionContext[0])); + } + + public static ConstructorCallContext ctorCall(boolean isSuperCall, boolean hasOuterObj, + SingleExpressionContext... stsArgs) { ConstructorCallContext stsSuperCtorCall = new ConstructorCallContext(null, 0); - stsSuperCtorCall.addChild(terminalNode(isSuperCall ? StaticTSParser.Super : StaticTSParser.This)); + + int argStartIndex = 0; + if (isSuperCall) { + if (hasOuterObj && stsArgs.length > 0) { + stsSuperCtorCall.addChild(stsArgs[0]).setParent(stsSuperCtorCall); + argStartIndex = 1; + } + + stsSuperCtorCall.addChild(terminalNode(StaticTSParser.Super)); + } + else + stsSuperCtorCall.addChild(terminalNode(StaticTSParser.This)); ArgumentsContext stsSuperCtorCallArgs = new ArgumentsContext(stsSuperCtorCall, 0); stsSuperCtorCall.addChild(stsSuperCtorCallArgs).setParent(stsSuperCtorCall); + ExpressionSequenceContext stsExprSeq = new ExpressionSequenceContext(stsSuperCtorCallArgs, 0); stsSuperCtorCallArgs.addChild(stsExprSeq).setParent(stsSuperCtorCallArgs); - for (String stsArgName : stsArgNames) { - stsExprSeq.addChild(identifierExpression(stsArgName)).setParent(stsExprSeq); + for (int i = argStartIndex; i < stsArgs.length; ++i) { + stsExprSeq.addChild(stsArgs[i]).setParent(stsExprSeq); } return stsSuperCtorCall; } - public static TypeAnnotationContext unknownTypeAnnotation() { return typeAnnotation(UNKNOWN_TYPE_NAME); } diff --git a/migrator/src/com/ohos/migrator/util/FileUtils.java b/migrator/src/com/ohos/migrator/util/FileUtils.java index 0cf0f7d4125b3874946062979816533f5ac3ad14..1da9953107a398bd6db38521ec8cc2f7b815f6c4 100644 --- a/migrator/src/com/ohos/migrator/util/FileUtils.java +++ b/migrator/src/com/ohos/migrator/util/FileUtils.java @@ -15,10 +15,7 @@ package com.ohos.migrator.util; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; +import java.io.*; import java.util.ArrayList; import java.util.List; @@ -80,4 +77,16 @@ public class FileUtils { return result.toArray(new String[0]); } + + public static void copyFile(File file, FileWriter fw) { + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + String line; + while ((line = br.readLine()) != null) { + fw.write(line + "\n"); + } + } + catch (IOException ioe) { + System.err.println("Failed to copy file " + file.getPath()); + } + } } diff --git a/migrator/test/java/class_instance_creation.java b/migrator/test/java/class_instance_creation.java index f609c943c6b3769fad38bba47fbe03e3ba582c6c..095f510fa278bbfbfd086d1c18afb5cd3dd1836f 100644 --- a/migrator/test/java/class_instance_creation.java +++ b/migrator/test/java/class_instance_creation.java @@ -27,6 +27,7 @@ class class_instance_creation { static class_instance_creation inst3 = new class_instance_creation("ss", 7.8); static class_instance_creation inst4 = new class_instance_creation(3) { private int f; + { f = 3; } public void foo() { f = 2; } }; @@ -39,5 +40,6 @@ class class_instance_creation { inner inner_inst3 = inst4.new inner(3) { private String s; public void bar() { s = "bar"; } + { bar(); } }; } diff --git a/migrator/test/java/class_instance_creation.java.sts b/migrator/test/java/class_instance_creation.java.sts index a3fe1f61dfe21d6cd6339df6db29fb76a8e4f5c2..2bfd07f8859ef2d1f0041bb1de16e6815446d330 100644 --- a/migrator/test/java/class_instance_creation.java.sts +++ b/migrator/test/java/class_instance_creation.java.sts @@ -35,6 +35,10 @@ open class class_instance_creation { public override foo(): void { f = 2; } + public constructor() { + super(3); + f = 3; + } }; open class inner { @@ -49,6 +53,10 @@ open class class_instance_creation { public open bar(): void { s = "bar"; } + public constructor() { + inst4.super(3); + bar(); + } }; }