Skip to content

Commit 6ec3616

Browse files
Support records in JavaParsers
This is a port of scala/scala#9551
1 parent ce65296 commit 6ec3616

File tree

3 files changed

+70
-4
lines changed

3 files changed

+70
-4
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ object StdNames {
204204
final val Null: N = "Null"
205205
final val Object: N = "Object"
206206
final val FromJavaObject: N = "<FromJavaObject>"
207+
final val Record: N = "Record"
207208
final val Product: N = "Product"
208209
final val PartialFunction: N = "PartialFunction"
209210
final val PrefixType: N = "PrefixType"
@@ -912,6 +913,10 @@ object StdNames {
912913
final val VOLATILEkw: N = kw("volatile")
913914
final val WHILEkw: N = kw("while")
914915

916+
final val RECORDid: N = "record"
917+
final val VARid: N = "var"
918+
final val YIELDid: N = "yield"
919+
915920
final val BoxedBoolean: N = "java.lang.Boolean"
916921
final val BoxedByte: N = "java.lang.Byte"
917922
final val BoxedCharacter: N = "java.lang.Character"
@@ -944,6 +949,8 @@ object StdNames {
944949
final val JavaSerializable: N = "java.io.Serializable"
945950
}
946951

952+
953+
947954
class JavaTermNames extends JavaNames[TermName] {
948955
protected def fromString(s: String): TermName = termName(s)
949956
}

compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ object JavaParsers {
9898

9999
def javaLangObject(): Tree = javaLangDot(tpnme.Object)
100100

101+
def javaLangRecord(): Tree = javaLangDot(tpnme.Record)
102+
101103
def arrayOf(tpt: Tree): AppliedTypeTree =
102104
AppliedTypeTree(scalaDot(tpnme.Array), List(tpt))
103105

@@ -555,6 +557,10 @@ object JavaParsers {
555557

556558
def definesInterface(token: Int): Boolean = token == INTERFACE || token == AT
557559

560+
def adaptRecordIdentifier(): Unit =
561+
if in.token == IDENTIFIER && in.name == jnme.RECORDid then
562+
in.token = RECORD
563+
558564
def termDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = {
559565
val inInterface = definesInterface(parentToken)
560566
val tparams = if (in.token == LT) typeParams(Flags.JavaDefined | Flags.Param) else List()
@@ -581,6 +587,16 @@ object JavaParsers {
581587
TypeTree(), methodBody()).withMods(mods)
582588
}
583589
}
590+
} else if (in.token == LBRACE && rtptName != nme.EMPTY && parentToken == RECORD) {
591+
/*
592+
record RecordName(T param1, ...) {
593+
RecordName { // <- here
594+
// methodBody
595+
}
596+
}
597+
*/
598+
methodBody()
599+
Nil
584600
}
585601
else {
586602
var mods1 = mods
@@ -717,12 +733,11 @@ object JavaParsers {
717733
ValDef(name, tpt2, if (mods.is(Flags.Param)) EmptyTree else unimplementedExpr).withMods(mods1)
718734
}
719735

720-
def memberDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match {
721-
case CLASS | ENUM | INTERFACE | AT =>
736+
def memberDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match
737+
case CLASS | ENUM | RECORD | INTERFACE | AT =>
722738
typeDecl(start, if (definesInterface(parentToken)) mods | Flags.JavaStatic else mods)
723739
case _ =>
724740
termDecl(start, mods, parentToken, parentTParams)
725-
}
726741

727742
def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree =
728743
atSpan(cdef.span) {
@@ -804,6 +819,48 @@ object JavaParsers {
804819
addCompanionObject(statics, cls)
805820
}
806821

822+
def recordDecl(start: Offset, mods: Modifiers): List[Tree] =
823+
accept(RECORD)
824+
val nameOffset = in.offset
825+
val name = identForType()
826+
val tparams = typeParams()
827+
val header = formalParams()
828+
val superclass = javaLangRecord() // records always extend java.lang.Record
829+
val interfaces = interfacesOpt() // records may implement interfaces
830+
val (statics, body) = typeBody(RECORD, name, tparams)
831+
832+
// We need to generate accessors for every param, if no method with the same name is already defined
833+
834+
var fieldsByName = header.map(v => (v.name, (v.tpt, v.mods.annotations))).toMap
835+
836+
for case DefDef(name, paramss, tpt, rhs) <- body
837+
if paramss.isEmpty && fieldsByName.contains(name)
838+
do
839+
fieldsByName -= name
840+
end for
841+
842+
val accessors =
843+
(for (name, (tpt, annots)) <- fieldsByName yield
844+
DefDef(name, Nil, tpt, unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.Method | Flags.Synthetic))
845+
).toList
846+
847+
// generate the canonical constructor
848+
val canonicalConstructor = makeConstructor(header, tparams)
849+
850+
// return the trees, probably with addCompanionObject (like classDecl)
851+
val recordTypeDef = atSpan(start, nameOffset) {
852+
TypeDef(name,
853+
makeTemplate(
854+
parents = superclass :: interfaces,
855+
stats = canonicalConstructor :: accessors ::: body,
856+
tparams = tparams,
857+
false
858+
)
859+
)
860+
}
861+
addCompanionObject(statics, recordTypeDef)
862+
end recordDecl
863+
807864
def interfaceDecl(start: Offset, mods: Modifiers): List[Tree] = {
808865
accept(INTERFACE)
809866
val nameOffset = in.offset
@@ -846,7 +903,7 @@ object JavaParsers {
846903
else if (in.token == SEMI)
847904
in.nextToken()
848905
else {
849-
if (in.token == ENUM || definesInterface(in.token)) mods |= Flags.JavaStatic
906+
if (in.token == ENUM || in.token == RECORD || definesInterface(in.token)) mods |= Flags.JavaStatic
850907
val decls = memberDecl(start, mods, parentToken, parentTParams)
851908
(if (mods.is(Flags.JavaStatic) || inInterface && !(decls exists (_.isInstanceOf[DefDef])))
852909
statics
@@ -952,6 +1009,7 @@ object JavaParsers {
9521009
case INTERFACE => interfaceDecl(start, mods)
9531010
case AT => annotationDecl(start, mods)
9541011
case CLASS => classDecl(start, mods)
1012+
case RECORD => recordDecl(start, mods)
9551013
case _ => in.nextToken(); syntaxError(em"illegal start of type declaration", skipIt = true); List(errorTypeTree)
9561014
}
9571015

compiler/src/dotty/tools/dotc/parsing/JavaTokens.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ object JavaTokens extends TokensCommon {
2222
inline val INTERFACE = 105; enter(INTERFACE, "interface")
2323
inline val ENUM = 106; enter(ENUM, "enum")
2424
inline val IMPLEMENTS = 107; enter(IMPLEMENTS, "implements")
25+
inline val RECORD = 108; enter(RECORD, "record")
2526

2627
/** modifiers */
2728
inline val PUBLIC = 110; enter(PUBLIC, "public")

0 commit comments

Comments
 (0)