@@ -5,13 +5,16 @@ import quoted.*
5
5
import scala .util .chaining .given
6
6
import scala .annotation .implicitNotFound
7
7
8
- @ implicitNotFound(" No OpsMirror could be generated.\n Diagnose any issues by calling OpsMirror.reify[T] directly" )
8
+ @ implicitNotFound(
9
+ " No OpsMirror could be generated.\n Diagnose any issues by calling OpsMirror.reify[T] directly"
10
+ )
9
11
sealed trait OpsMirror :
10
12
type Metadata <: Tuple
11
13
type MirroredType
12
14
type MirroredLabel
13
15
type MirroredOperations <: Tuple
14
16
type MirroredOperationLabels <: Tuple
17
+ end OpsMirror
15
18
16
19
sealed trait Meta
17
20
@@ -28,6 +31,7 @@ sealed trait Operation:
28
31
type InputMetadatas <: Tuple
29
32
type ErrorType
30
33
type OutputType
34
+ end Operation
31
35
32
36
object OpsMirror :
33
37
type Of [T ] = OpsMirror { type MirroredType = T }
@@ -38,7 +42,7 @@ object OpsMirror:
38
42
39
43
def typesFromTuple [Ts : Type ](using Quotes ): List [Type [? ]] =
40
44
Type .of[Ts ] match
41
- case ' [t *: ts] => Type .of[t] :: typesFromTuple[ts]
45
+ case ' [t *: ts] => Type .of[t] :: typesFromTuple[ts]
42
46
case ' [EmptyTuple ] => Nil
43
47
44
48
def stringsFromTuple [Ts : Type ](using Quotes ): List [String ] =
@@ -49,11 +53,17 @@ object OpsMirror:
49
53
import quotes .reflect .*
50
54
TypeRepr .of[T ] match
51
55
case ConstantType (StringConstant (label)) => label
52
- case _ => report.errorAndAbort(s " expected a constant string, got ${TypeRepr .of[T ]}" )
56
+ case _ =>
57
+ report.errorAndAbort(s " expected a constant string, got ${TypeRepr .of[T ]}" )
58
+ end match
59
+ end stringFromType
53
60
54
61
def typesToTuple (list : List [Type [? ]])(using Quotes ): Type [? ] =
55
62
val empty : Type [? <: Tuple ] = Type .of[EmptyTuple ]
56
- list.foldRight(empty)({case (' [t], ' [acc]) => Type .of[t *: (acc & Tuple )]})
63
+ list.foldRight(empty)({ case (' [t], ' [acc]) =>
64
+ Type .of[t *: (acc & Tuple )]
65
+ })
66
+ end typesToTuple
57
67
58
68
def metadata [Op : Type ](using Quotes ): Metadata =
59
69
import quotes .reflect .*
@@ -64,101 +74,130 @@ object OpsMirror:
64
74
65
75
def extractMetas [Metadata : Type ]: List [Expr [Any ]] =
66
76
typesFromTuple[Metadata ].map:
67
- case ' [m] => TypeRepr .of[m] match
68
- case AnnotatedType (_, annot) =>
69
- annot.asExpr
70
- case tpe =>
71
- report.errorAndAbort(s " got the metadata element ${tpe.show}" )
77
+ case ' [m] =>
78
+ TypeRepr .of[m] match
79
+ case AnnotatedType (_, annot) =>
80
+ annot.asExpr
81
+ case tpe =>
82
+ report.errorAndAbort(s " got the metadata element ${tpe.show}" )
72
83
73
84
Type .of[Op ] match
74
85
case ' [Operation {
75
- type Metadata = metadata
76
- type InputMetadatas = inputMetadatas
77
- }] => Metadata (extractMetas[metadata], extractMetass[inputMetadatas])
86
+ type Metadata = metadata
87
+ type InputMetadatas = inputMetadatas
88
+ }] =>
89
+ Metadata (extractMetas[metadata], extractMetass[inputMetadatas])
78
90
case _ => report.errorAndAbort(" expected an Operation with Metadata." )
91
+ end match
92
+ end metadata
79
93
80
94
private def reifyImpl [T : Type ](using Quotes ): Expr [Of [T ]] =
81
95
import quotes .reflect .*
82
96
83
- val tpe = TypeRepr .of[T ]
84
- val cls = tpe.classSymbol.get
85
- val decls = cls.declaredMethods
97
+ val tpe = TypeRepr .of[T ]
98
+ val cls = tpe.classSymbol.get
99
+ val decls = cls.declaredMethods
86
100
val labels = decls.map(m => ConstantType (StringConstant (m.name)))
87
101
88
102
def isMeta (annot : Term ): Boolean =
89
103
if annot.tpe <:< TypeRepr .of[MetaAnnotation ] then true
90
- else if annot.tpe <:< TypeRepr .of[scala.annotation.internal.SourceFile ] then false
104
+ else if annot.tpe <:< TypeRepr .of[scala.annotation.internal.SourceFile ]
105
+ then false
91
106
else
92
- report.error(s " annotation ${annot.show} does not extend ${Type .show[MetaAnnotation ]}" , annot.pos)
107
+ report.error(
108
+ s " annotation ${annot.show} does not extend ${Type .show[MetaAnnotation ]}" ,
109
+ annot.pos
110
+ )
93
111
false
94
112
95
- def encodeMeta (annot : Term ): Type [? ] = AnnotatedType (TypeRepr .of[Meta ], annot).asType
113
+ def encodeMeta (annot : Term ): Type [? ] =
114
+ AnnotatedType (TypeRepr .of[Meta ], annot).asType
96
115
97
116
val (errorTpe, gmeta) =
98
117
val annots = cls.annotations.filter(isMeta)
99
- val (errorAnnots, metaAnnots) = annots.partition(annot => annot.tpe <:< TypeRepr .of[ErrorAnnotation [? ]])
118
+ val (errorAnnots, metaAnnots) =
119
+ annots.partition(annot => annot.tpe <:< TypeRepr .of[ErrorAnnotation [? ]])
100
120
val errorTpe =
101
- if errorAnnots.isEmpty then
102
- Type .of[VoidType ]
121
+ if errorAnnots.isEmpty then Type .of[VoidType ]
103
122
else
104
123
errorAnnots
105
124
.map: annot =>
106
125
annot.asExpr match
107
126
case ' { $a : ErrorAnnotation [t] } => Type .of[t]
108
127
.head
109
128
(errorTpe, metaAnnots.map(encodeMeta))
129
+ end val
110
130
111
131
val ops = decls.map(method =>
112
132
val metaAnnots =
113
133
val annots = method.annotations.filter(isMeta)
114
- val (errorAnnots, metaAnnots) = annots.partition(annot => annot.tpe <:< TypeRepr .of[ErrorAnnotation [? ]])
134
+ val (errorAnnots, metaAnnots) =
135
+ annots.partition(annot => annot.tpe <:< TypeRepr .of[ErrorAnnotation [? ]])
115
136
if errorAnnots.nonEmpty then
116
137
errorAnnots.foreach: annot =>
117
- report.error(s " error annotation ${annot.show} has no meaning on a method, annotate the scope itself. " , annot.pos)
138
+ report.error(
139
+ s " error annotation ${annot.show} has no meaning on a method, annotate the scope itself. " ,
140
+ annot.pos
141
+ )
142
+ end if
118
143
metaAnnots.map(encodeMeta)
144
+ end metaAnnots
119
145
val meta = typesToTuple(metaAnnots)
120
146
val (inputTypes, inputLabels, inputMetas, output) =
121
147
tpe.memberType(method) match
122
148
case ByNameType (res) =>
123
149
val output = res.asType
124
150
(Nil , Nil , Nil , output)
125
151
case MethodType (paramNames, paramTpes, res) =>
126
- val inputTypes = paramTpes.map(_.asType)
152
+ val inputTypes = paramTpes.map(_.asType)
127
153
val inputLabels = paramNames.map(l => ConstantType (StringConstant (l)).asType)
128
- val inputMetas = method.paramSymss.head.map(s => typesToTuple(s.annotations.filter(isMeta).map(encodeMeta)))
154
+ val inputMetas = method.paramSymss.head.map: s =>
155
+ typesToTuple(s.annotations.filter(isMeta).map(encodeMeta))
129
156
val output = res match
130
- case _ : MethodType => report.errorAndAbort(s " curried method ${method.name} is not supported " )
131
- case _ : PolyType => report.errorAndAbort(s " curried method ${method.name} is not supported " )
157
+ case _ : MethodType =>
158
+ report.errorAndAbort(s " curried method ${method.name} is not supported " )
159
+ case _ : PolyType =>
160
+ report.errorAndAbort(s " curried method ${method.name} is not supported " )
132
161
case _ => res.asType
133
162
(inputTypes, inputLabels, inputMetas, output)
134
- case _ : PolyType => report.errorAndAbort(s " generic method ${method.name} is not supported " )
163
+ case _ : PolyType =>
164
+ report.errorAndAbort(s " generic method ${method.name} is not supported " )
135
165
val inTup = typesToTuple(inputTypes)
136
166
val inLab = typesToTuple(inputLabels)
137
167
val inMet = typesToTuple(inputMetas)
138
168
(meta, inTup, inLab, inMet, errorTpe, output) match
139
- case (' [m], ' [i], ' [l], ' [iM], ' [e], ' [o]) => Type .of[Operation {
140
- type Metadata = m
141
- type InputTypes = i
142
- type InputLabels = l
143
- type InputMetadatas = iM
144
- type ErrorType = e
145
- type OutputType = o
146
- }]
147
-
169
+ case (' [m], ' [i], ' [l], ' [iM], ' [e], ' [o]) =>
170
+ Type .of[
171
+ Operation {
172
+ type Metadata = m
173
+ type InputTypes = i
174
+ type InputLabels = l
175
+ type InputMetadatas = iM
176
+ type ErrorType = e
177
+ type OutputType = o
178
+ }
179
+ ]
180
+ end match
148
181
)
149
- val clsMeta = typesToTuple(gmeta)
150
- val opsTup = typesToTuple(ops.toList)
182
+ val clsMeta = typesToTuple(gmeta)
183
+ val opsTup = typesToTuple(ops.toList)
151
184
val labelsTup = typesToTuple(labels.map(_.asType))
152
- val name = ConstantType (StringConstant (cls.name)).asType
185
+ val name = ConstantType (StringConstant (cls.name)).asType
153
186
(clsMeta, opsTup, labelsTup, name) match
154
- case (' [meta], ' [ops], ' [labels], ' [label]) => ' { (new OpsMirror {
155
- type Metadata = meta & Tuple
156
- type MirroredType = T
157
- type MirroredLabel = label
158
- type MirroredOperations = ops & Tuple
159
- type MirroredOperationLabels = labels & Tuple
160
- }): OpsMirror .Of [T ] {
161
- type MirroredLabel = label
162
- type MirroredOperations = ops & Tuple
163
- type MirroredOperationLabels = labels & Tuple
164
- }}
187
+ case (' [meta], ' [ops], ' [labels], ' [label]) =>
188
+ ' {
189
+ (new OpsMirror :
190
+ type Metadata = meta & Tuple
191
+ type MirroredType = T
192
+ type MirroredLabel = label
193
+ type MirroredOperations = ops & Tuple
194
+ type MirroredOperationLabels = labels & Tuple
195
+ ): OpsMirror .Of [T ] {
196
+ type MirroredLabel = label
197
+ type MirroredOperations = ops & Tuple
198
+ type MirroredOperationLabels = labels & Tuple
199
+ }
200
+ }
201
+ end match
202
+ end reifyImpl
203
+ end OpsMirror
0 commit comments