1
1
package fred
2
2
3
3
import scala .collection .mutable
4
+ import scala .jdk .CollectionConverters .*
4
5
5
6
import org .scalacheck .Gen
6
7
7
8
object GenerateTypes {
8
- case class GeneratedType (refs : List [Int ])
9
+ private val SomeField = " value"
10
+
11
+ case class GenTypeAux (refs : List [Int ])
9
12
10
13
/** Generate a bunch of types. Each type is its own strongly-connected
11
14
* component. The returned list is sorted backwards (types that come later in
@@ -17,69 +20,130 @@ object GenerateTypes {
17
20
*
18
21
* All references are mutable, for testing cycles.
19
22
*/
20
- def genTypes (): Gen [List [GeneratedType ]] = {
23
+ def genTypesAux (): Gen [List [GenTypeAux ]] = {
21
24
Gen .choose(1 , 40 ).flatMap { numSccs =>
22
25
Gen .sequence(0 .until(numSccs).map { i =>
23
- Gen .listOf(Gen .chooseNum(0 , i)).map(GeneratedType (_))
26
+ Gen .listOf(Gen .chooseNum(0 , i)).map(GenTypeAux (_))
24
27
})
25
28
}
26
29
}
27
30
28
- def generateAst (typeAuxes : List [GeneratedType ]): ParsedFile = {
29
- def nameFor (ind : Int ) = s " T $ind"
31
+ private def nameForType (ind : Int ) = s " T $ind"
32
+
33
+ /** Name for the optional type corresponding to the type at index `ind` */
34
+ private def nameForOptType (ind : Int ) = s " OptT $ind"
35
+ private def someCtorName (ind : Int ) = s " Some $ind"
36
+ private def noneCtorName (ind : Int ) = s " None $ind"
30
37
31
- /** Name for the optional type corresponding to the type at index `ind` */
32
- def nameForOpt (ind : Int ) = s " OptT $ind"
38
+ private def nameForField (ind : Int ) = s " f $ind"
33
39
34
- val types = typeAuxes.zipWithIndex.map { case (GeneratedType (refs), i) =>
35
- val typeName = Spanned (nameFor(i), Span .synthetic)
40
+ def toTypes (typeAuxes : List [GenTypeAux ]): List [TypeDef ] = {
41
+ val types = typeAuxes.zipWithIndex.map { case (GenTypeAux (refs), i) =>
42
+ val typeName = Spanned (nameForType(i), Span .synth)
36
43
TypeDef (
37
44
typeName,
38
45
List (
39
46
EnumCase (
40
47
typeName,
41
48
refs.zipWithIndex.map { (typeInd, fieldInd) =>
42
49
val fieldType =
43
- if (i == typeInd) nameForOpt(typeInd) else nameFor(typeInd)
50
+ if (i == typeInd) nameForOptType(typeInd)
51
+ else nameForType(typeInd)
44
52
FieldDef (
45
53
true ,
46
- Spanned (s " f $ fieldInd" , Span .synthetic ),
47
- TypeRef (fieldType, Span .synthetic ),
48
- Span .synthetic
54
+ Spanned (nameForField( fieldInd) , Span .synth ),
55
+ TypeRef (fieldType, Span .synth ),
56
+ Span .synth
49
57
)
50
58
},
51
- Span .synthetic
59
+ Span .synth
52
60
)
53
61
),
54
- Span .synthetic
62
+ Span .synth
55
63
)
56
64
}
57
65
// Generate optional types for self-referential types
58
66
val optTypes = typeAuxes.zipWithIndex
59
- .filter { case (GeneratedType (refs), i) =>
67
+ .filter { case (GenTypeAux (refs), i) =>
60
68
refs.contains(i)
61
69
}
62
70
.map { (_, i) =>
63
- val name = Spanned (nameForOpt(i), Span .synthetic)
64
71
TypeDef (
65
- name ,
72
+ Spanned (nameForOptType(i), Span .synth) ,
66
73
List (
67
74
EnumCase (
68
- name ,
75
+ Spanned (someCtorName(i), Span .synth) ,
69
76
List (
70
77
FieldDef (
71
78
false ,
72
- Spanned (" value " , Span .synthetic ),
73
- TypeRef (nameFor (i), Span .synthetic ),
74
- Span .synthetic
79
+ Spanned (SomeField , Span .synth ),
80
+ TypeRef (nameForType (i), Span .synth ),
81
+ Span .synth
75
82
)
76
83
),
77
- Span .synthetic
84
+ Span .synth
85
+ ),
86
+ EnumCase (
87
+ Spanned (noneCtorName(i), Span .synth),
88
+ Nil ,
89
+ Span .synth
78
90
)
79
91
),
80
- Span .synthetic
92
+ Span .synth
93
+ )
94
+ }
95
+ types ++ optTypes
96
+ }
97
+
98
+ def genCode (typeAuxes : List [GenTypeAux ]): Gen [ParsedFile ] = {
99
+ val types = toTypes(typeAuxes)
100
+
101
+ def genExpr (typeInd : Int ): Gen [Expr ] = {
102
+ val GenTypeAux (refs) = typeAuxes(typeInd)
103
+ val fieldGens = refs.zipWithIndex.map { case (fieldTypeInd, fieldInd) =>
104
+ val fieldName = Spanned (nameForField(fieldInd), Span .synth)
105
+ val value =
106
+ if (fieldTypeInd < typeInd) {
107
+ genExpr(fieldTypeInd)
108
+ } else {
109
+ Gen .const(
110
+ CtorCall (
111
+ Spanned (noneCtorName(typeInd), Span .synth),
112
+ Nil ,
113
+ Span .synth
114
+ )
115
+ )
116
+ }
117
+ value.map((fieldName, _))
118
+ }
119
+ // TODO Why in the world is this an ArrayList?
120
+ Gen .sequence(fieldGens).map { fields =>
121
+ CtorCall (
122
+ Spanned (nameForType(typeInd), Span .synth),
123
+ fields.asScala.toList,
124
+ Span .synth
81
125
)
82
126
}
83
- ParsedFile (types ++ optTypes, Nil )
127
+ }
128
+
129
+ genExpr(typeAuxes.length - 1 ).map { expr =>
130
+ ParsedFile (
131
+ types,
132
+ List (
133
+ FnDef (
134
+ Spanned (" main" , Span .synth),
135
+ Nil ,
136
+ TypeRef (" int" , Span .synth),
137
+ LetExpr (
138
+ Spanned (" ignored" , Span .synth),
139
+ expr,
140
+ IntLiteral (0 , Span .synth),
141
+ Span .synth
142
+ ),
143
+ Span .synth
144
+ )
145
+ )
146
+ )
147
+ }
84
148
}
85
149
}
0 commit comments