@@ -20,7 +20,8 @@ import StdNames._
20
20
import reporting ._
21
21
import dotty .tools .dotc .util .SourceFile
22
22
import util .Spans ._
23
- import scala .collection .mutable .ListBuffer
23
+
24
+ import scala .collection .mutable .{ListBuffer , LinkedHashMap }
24
25
25
26
object JavaParsers {
26
27
@@ -96,8 +97,12 @@ object JavaParsers {
96
97
def javaLangDot (name : Name ): Tree =
97
98
Select (javaDot(nme.lang), name)
98
99
100
+ /** Tree representing `java.lang.Object` */
99
101
def javaLangObject (): Tree = javaLangDot(tpnme.Object )
100
102
103
+ /** Tree representing `java.lang.Record` */
104
+ def javaLangRecord (): Tree = javaLangDot(tpnme.Record )
105
+
101
106
def arrayOf (tpt : Tree ): AppliedTypeTree =
102
107
AppliedTypeTree (scalaDot(tpnme.Array ), List (tpt))
103
108
@@ -555,6 +560,14 @@ object JavaParsers {
555
560
556
561
def definesInterface (token : Int ): Boolean = token == INTERFACE || token == AT
557
562
563
+ /** If the next token is the identifier "record", convert it into the RECORD token.
564
+ * This makes it easier to handle records in various parts of the code,
565
+ * in particular when a `parentToken` is passed to some functions.
566
+ */
567
+ def adaptRecordIdentifier (): Unit =
568
+ if in.token == IDENTIFIER && in.name == jnme.RECORDid then
569
+ in.token = RECORD
570
+
558
571
def termDecl (start : Offset , mods : Modifiers , parentToken : Int , parentTParams : List [TypeDef ]): List [Tree ] = {
559
572
val inInterface = definesInterface(parentToken)
560
573
val tparams = if (in.token == LT ) typeParams(Flags .JavaDefined | Flags .Param ) else List ()
@@ -581,6 +594,16 @@ object JavaParsers {
581
594
TypeTree (), methodBody()).withMods(mods)
582
595
}
583
596
}
597
+ } else if (in.token == LBRACE && rtptName != nme.EMPTY && parentToken == RECORD ) {
598
+ /*
599
+ record RecordName(T param1, ...) {
600
+ RecordName { // <- here
601
+ // methodBody
602
+ }
603
+ }
604
+ */
605
+ methodBody()
606
+ Nil
584
607
}
585
608
else {
586
609
var mods1 = mods
@@ -717,12 +740,11 @@ object JavaParsers {
717
740
ValDef (name, tpt2, if (mods.is(Flags .Param )) EmptyTree else unimplementedExpr).withMods(mods1)
718
741
}
719
742
720
- def memberDecl (start : Offset , mods : Modifiers , parentToken : Int , parentTParams : List [TypeDef ]): List [Tree ] = in.token match {
721
- case CLASS | ENUM | INTERFACE | AT =>
722
- typeDecl(start, if ( definesInterface(parentToken)) mods | Flags .JavaStatic else mods)
743
+ def memberDecl (start : Offset , mods : Modifiers , parentToken : Int , parentTParams : List [TypeDef ]): List [Tree ] = in.token match
744
+ case CLASS | ENUM | RECORD | INTERFACE | AT =>
745
+ typeDecl(start, if definesInterface(parentToken) then mods | Flags .JavaStatic else mods)
723
746
case _ =>
724
747
termDecl(start, mods, parentToken, parentTParams)
725
- }
726
748
727
749
def makeCompanionObject (cdef : TypeDef , statics : List [Tree ]): Tree =
728
750
atSpan(cdef.span) {
@@ -804,6 +826,51 @@ object JavaParsers {
804
826
addCompanionObject(statics, cls)
805
827
}
806
828
829
+ def recordDecl (start : Offset , mods : Modifiers ): List [Tree ] =
830
+ accept(RECORD )
831
+ val nameOffset = in.offset
832
+ val name = identForType()
833
+ val tparams = typeParams()
834
+ val header = formalParams()
835
+ val superclass = javaLangRecord() // records always extend java.lang.Record
836
+ val interfaces = interfacesOpt() // records may implement interfaces
837
+ val (statics, body) = typeBody(RECORD , name, tparams)
838
+
839
+ // We need to generate accessors for every param, if no method with the same name is already defined
840
+
841
+ var fieldsByName = header.map(v => (v.name, (v.tpt, v.mods.annotations))).to(LinkedHashMap )
842
+
843
+ for case DefDef (name, paramss, _, _) <- body
844
+ if paramss.isEmpty && fieldsByName.contains(name)
845
+ do
846
+ fieldsByName -= name
847
+ end for
848
+
849
+ val accessors =
850
+ (for (name, (tpt, annots)) <- fieldsByName yield
851
+ DefDef (name, Nil , tpt, unimplementedExpr)
852
+ .withMods(Modifiers (Flags .JavaDefined | Flags .Method | Flags .Synthetic ))
853
+ ).toList
854
+
855
+ // generate the canonical constructor
856
+ val canonicalConstructor =
857
+ DefDef (nme.CONSTRUCTOR , joinParams(tparams, List (header)), TypeTree (), EmptyTree )
858
+ .withMods(Modifiers (Flags .JavaDefined | Flags .Synthetic , mods.privateWithin))
859
+
860
+ // return the trees
861
+ val recordTypeDef = atSpan(start, nameOffset) {
862
+ TypeDef (name,
863
+ makeTemplate(
864
+ parents = superclass :: interfaces,
865
+ stats = canonicalConstructor :: accessors ::: body,
866
+ tparams = tparams,
867
+ true
868
+ )
869
+ ).withMods(mods)
870
+ }
871
+ addCompanionObject(statics, recordTypeDef)
872
+ end recordDecl
873
+
807
874
def interfaceDecl (start : Offset , mods : Modifiers ): List [Tree ] = {
808
875
accept(INTERFACE )
809
876
val nameOffset = in.offset
@@ -846,7 +913,8 @@ object JavaParsers {
846
913
else if (in.token == SEMI )
847
914
in.nextToken()
848
915
else {
849
- if (in.token == ENUM || definesInterface(in.token)) mods |= Flags .JavaStatic
916
+ adaptRecordIdentifier()
917
+ if (in.token == ENUM || in.token == RECORD || definesInterface(in.token)) mods |= Flags .JavaStatic
850
918
val decls = memberDecl(start, mods, parentToken, parentTParams)
851
919
(if (mods.is(Flags .JavaStatic ) || inInterface && ! (decls exists (_.isInstanceOf [DefDef ])))
852
920
statics
@@ -947,13 +1015,13 @@ object JavaParsers {
947
1015
}
948
1016
}
949
1017
950
- def typeDecl (start : Offset , mods : Modifiers ): List [Tree ] = in.token match {
1018
+ def typeDecl (start : Offset , mods : Modifiers ): List [Tree ] = in.token match
951
1019
case ENUM => enumDecl(start, mods)
952
1020
case INTERFACE => interfaceDecl(start, mods)
953
1021
case AT => annotationDecl(start, mods)
954
1022
case CLASS => classDecl(start, mods)
1023
+ case RECORD => recordDecl(start, mods)
955
1024
case _ => in.nextToken(); syntaxError(em " illegal start of type declaration " , skipIt = true ); List (errorTypeTree)
956
- }
957
1025
958
1026
def tryConstant : Option [Constant ] = {
959
1027
val negate = in.token match {
@@ -1004,6 +1072,7 @@ object JavaParsers {
1004
1072
if (in.token != EOF ) {
1005
1073
val start = in.offset
1006
1074
val mods = modifiers(inInterface = false )
1075
+ adaptRecordIdentifier() // needed for typeDecl
1007
1076
buf ++= typeDecl(start, mods)
1008
1077
}
1009
1078
}
0 commit comments