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