From c44bb8d0d95aac5af6f01ea284309f86876574f3 Mon Sep 17 00:00:00 2001 From: "Chris (Krzysztof) Pado" Date: Sun, 29 Oct 2023 20:38:32 -0700 Subject: [PATCH] First impl attempt --- .../tools/dotc/parsing/JavaParsers.scala | 46 ++++++++++++++++++- .../dotc/parsing/JavaJep445ParserTest.scala | 26 ++++++++++- .../UnnamedStartsWithAnnotatedField.java | 5 ++ 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 tests/pos-java21+/jep445/UnnamedStartsWithAnnotatedField.java diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 6ec896dcb200..bdcf190f590c 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -826,6 +826,27 @@ object JavaParsers { addCompanionObject(statics, cls) } + def unnamedClassDecl(priorTypes: List[Tree], start: Offset): List[Tree] = { + val name = source.name.replaceAll("\\.java$", "").nn.toTypeName + val (statics, body) = typeBodyDecls(CLASS, name, Nil) + + val (priorStatics, priorBody) = priorTypes.partition { + case t: TypeDef => t.mods.is(Flags.JavaStatic) + case _: ModuleDef => true + case _ => false + } + + val cls = atSpan(start, 0) { + TypeDef(name, makeTemplate( + parents = Nil, + stats = priorBody ::: body, + tparams = Nil, + needsDummyConstr = true) + ).withMods(Modifiers(Flags.Private | Flags.Final)) + } + addCompanionObject(priorStatics ::: statics, cls) + } + def recordDecl(start: Offset, mods: Modifiers): List[Tree] = accept(RECORD) val nameOffset = in.offset @@ -1067,16 +1088,37 @@ object JavaParsers { val buf = new ListBuffer[Tree] while (in.token == IMPORT) buf ++= importDecl() + + val afterImports = in.offset + val typesBuf = new ListBuffer[Tree] + while (in.token != EOF && in.token != RBRACE) { while (in.token == SEMI) in.nextToken() if (in.token != EOF) { val start = in.offset val mods = modifiers(inInterface = false) adaptRecordIdentifier() // needed for typeDecl - buf ++= typeDecl(start, mods) + + in.token match { + case ENUM | INTERFACE | AT | CLASS | RECORD => typesBuf ++= typeDecl(start, mods) + case _ => + if (thisPackageName == tpnme.EMPTY_PACKAGE) { + // upon encountering non-types directly at a compilation unit level in an unnamed package, + // the entire compilation unit is treated as a JEP-445 unnamed class + //TODO support @annotated members of unnamed class + val cls = unnamedClassDecl(priorTypes = typesBuf.toList, start = afterImports) + typesBuf.clear() + typesBuf ++= cls + } else { + in.nextToken() + syntaxError(em"illegal start of type declaration", skipIt = true) + List(errorTypeTree) + } + } } } - val unit = atSpan(start) { PackageDef(pkg, buf.toList) } + + val unit = atSpan(start) { PackageDef(pkg, (buf ++ typesBuf).toList) } accept(EOF) unit match case PackageDef(Ident(nme.EMPTY_PACKAGE), Nil) => EmptyTree diff --git a/compiler/test/dotty/tools/dotc/parsing/JavaJep445ParserTest.scala b/compiler/test/dotty/tools/dotc/parsing/JavaJep445ParserTest.scala index 240df42acb06..c2bd1fa50532 100644 --- a/compiler/test/dotty/tools/dotc/parsing/JavaJep445ParserTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/JavaJep445ParserTest.scala @@ -21,7 +21,8 @@ class JavaJep445ParserTest extends DottyTest { |import some.pkg.*; | |private volatile int x = 0; - |private String s = "s"; + |@Magic + |protected String s = "s"; | |void main() {} |""".stripMargin @@ -44,6 +45,29 @@ class JavaJep445ParserTest extends DottyTest { | |interface Inner {} | + |static class InnerStatic {} + | + |void main() {} + |""".stripMargin + + val parser = + JavaParsers.JavaParser(SourceFile.virtual("MyUnnamed.java", code)) + val tree = parser.parse() + + println(tree.show) + + fail("TODO") + } + + @Test def `treats leading top-level annotated vars as members of unnamed class`: Unit = { + val code = + s""" + | + |import some.pkg.*; + | + |@MyAnnotation + |int x = 0; + | |void main() {} |""".stripMargin diff --git a/tests/pos-java21+/jep445/UnnamedStartsWithAnnotatedField.java b/tests/pos-java21+/jep445/UnnamedStartsWithAnnotatedField.java new file mode 100644 index 000000000000..ae7df0e58509 --- /dev/null +++ b/tests/pos-java21+/jep445/UnnamedStartsWithAnnotatedField.java @@ -0,0 +1,5 @@ + +@MyAnnotation +int myInt = 10; + +void main() {}