@@ -28,9 +28,13 @@ class Select[F[_]](api: Gopher[F]):
28
28
*/
29
29
transparent inline def apply [A ](inline pf : PartialFunction [Any ,A ]): A =
30
30
$ {
31
- Select .onceImpl[F ,A ](' pf , ' api )
31
+ SelectMacro .onceImpl[F ,A ](' pf , ' api )
32
32
}
33
33
34
+ /** *
35
+ * create select groop
36
+ *@see [gopher.SelectGroup]
37
+ **/
34
38
def group [S ]: SelectGroup [F ,S ] = new SelectGroup [F ,S ](api)
35
39
36
40
def once [S ]: SelectGroup [F ,S ] = new SelectGroup [F ,S ](api)
@@ -92,287 +96,25 @@ class Select[F[_]](api: Gopher[F]):
92
96
}
93
97
r
94
98
95
- def forever : SelectForever [F ] = new SelectForever [F ](api )
99
+ /**
100
+ * create forever runner.
101
+ **/
102
+ def forever : SelectForever [F ] = new SelectForever [F ](api)
96
103
104
+ /**
105
+ * run forever expression in `pf`, return
106
+ **/
97
107
transparent inline def aforever (inline pf : PartialFunction [Any ,Unit ]): F [Unit ] =
98
- async(using api.asyncMonad).apply {
99
- val runner = new SelectForever [F ](api)
100
- runner.apply(pf)
101
- }
108
+ $ { SelectMacro .aforeverImpl(' pf , ' api ) }
102
109
103
- def aforever_async (pf : PartialFunction [Any ,F [Unit ]]): F [Unit ] =
110
+ /*
111
+ transparent inline def aforever_async(inline pf: PartialFunction[Any,F[Unit]]): F[Unit] =
104
112
given CpsSchedulingMonad[F] = api.asyncMonad
105
113
async(using api.asyncMonad).apply {
106
114
val runner = new SelectForever[F](api)
107
115
runner.applyAsync(pf)
108
116
}
109
-
117
+ */
110
118
111
119
112
120
113
- object Select :
114
-
115
- import cps .forest .TransformUtil
116
-
117
- sealed trait SelectGroupExpr [F [_],S , R ]:
118
- def toExprOf [X <: SelectListeners [F ,S , R ]]: Expr [X ]
119
-
120
- sealed trait SelectorCaseExpr [F [_]: Type , S : Type , R : Type ]:
121
- type Monad [X ] = F [X ]
122
- def appended [L <: SelectListeners [F ,S ,R ] : Type ](base : Expr [L ])(using Quotes ): Expr [L ]
123
-
124
- case class ReadExpression [F [_]: Type , A : Type , S : Type , R : Type ](ch : Expr [ReadChannel [F ,A ]], f : Expr [A => S ], isDone : Boolean ) extends SelectorCaseExpr [F ,S ,R ]:
125
- def appended [L <: SelectListeners [F ,S ,R ]: Type ](base : Expr [L ])(using Quotes ): Expr [L ] =
126
- ' { $base.onRead($ch)($f) }
127
-
128
- case class WriteExpression [F [_]: Type , A : Type , S : Type , R : Type ](ch : Expr [WriteChannel [F ,A ]], a : Expr [A ], f : Expr [A => S ]) extends SelectorCaseExpr [F ,S ,R ]:
129
- def appended [L <: SelectListeners [F ,S ,R ]: Type ](base : Expr [L ])(using Quotes ): Expr [L ] =
130
- ' { $base.onWrite($ch,$a)($f) }
131
-
132
- case class TimeoutExpression [F [_]: Type ,S : Type , R : Type ](t : Expr [FiniteDuration ], f : Expr [ FiniteDuration => S ]) extends SelectorCaseExpr [F ,S ,R ]:
133
- def appended [L <: SelectListeners [F ,S ,R ]: Type ](base : Expr [L ])(using Quotes ): Expr [L ] =
134
- ' { $base.onTimeout($t)($f) }
135
-
136
- case class DoneExression [F [_]: Type , A : Type , S : Type , R : Type ](ch : Expr [ReadChannel [F ,A ]], f : Expr [Unit => S ]) extends SelectorCaseExpr [F ,S ,R ]:
137
- def appended [L <: SelectListeners [F ,S ,R ]: Type ](base : Expr [L ])(using Quotes ): Expr [L ] =
138
- ' { $base.onRead($ch.done)($f) }
139
-
140
- def selectListenerBuilder [F [_]: Type , S : Type , R : Type , L <: SelectListeners [F ,S ,R ]: Type ](
141
- constructor : Expr [L ], caseDefs : List [SelectorCaseExpr [F ,S ,R ]], api: Expr [Gopher [F ]])(using Quotes ): Expr [R ] =
142
- val s0 = constructor
143
- val g = caseDefs.foldLeft(s0){(s,e) =>
144
- e.appended(s)
145
- }
146
- // dotty bug if g.run
147
- val r = ' { await($g.runAsync())(using $ {api}.asyncMonad) }
148
- r.asExprOf[R ]
149
-
150
-
151
- def onceImpl [F [_]: Type , A : Type ](pf : Expr [PartialFunction [Any ,A ]], api : Expr [Gopher [F ]])(using Quotes ): Expr [A ] =
152
- def builder (caseDefs : List [SelectorCaseExpr [F ,A ,A ]]): Expr [A ] = {
153
- val s0 = ' {
154
- new SelectGroup [F ,A ]($api)
155
- }
156
- selectListenerBuilder(s0, caseDefs, api)
157
- }
158
- runImpl(builder, pf)
159
-
160
- def loopImpl [F [_]: Type ](pf : Expr [PartialFunction [Any ,Boolean ]], api : Expr [Gopher [F ]])(using Quotes ): Expr [Unit ] =
161
- def builder (caseDefs : List [SelectorCaseExpr [F ,Boolean ,Unit ]]): Expr [Unit ] = {
162
- val s0 = ' {
163
- new SelectLoop [F ]($api)
164
- }
165
- selectListenerBuilder(s0, caseDefs, api)
166
- }
167
- runImpl( builder, pf)
168
-
169
-
170
- def foreverImpl [F [_]: Type ](pf : Expr [PartialFunction [Any ,Unit ]], api: Expr [Gopher [F ]])(using Quotes ): Expr [Unit ] =
171
- def builder (caseDefs : List [SelectorCaseExpr [F ,Unit ,Unit ]]): Expr [Unit ] = {
172
- val s0 = ' {
173
- new SelectForever [F ]($api)
174
- }
175
- selectListenerBuilder(s0, caseDefs, api)
176
- }
177
- runImpl(builder, pf)
178
-
179
-
180
-
181
- def runImpl [F [_]: Type , A : Type ,B : Type ](builder : List [SelectorCaseExpr [F ,A ,B ]]=> Expr [B ],
182
- pf : Expr [PartialFunction [Any ,A ]])(using Quotes ): Expr [B ] =
183
- import quotes .reflect ._
184
- runImplTree[F ,A ,B ](builder, pf.asTerm)
185
-
186
- def runImplTree [F [_]: Type , A : Type , B : Type ](using Quotes )(
187
- builder : List [SelectorCaseExpr [F ,A ,B ]] => Expr [B ],
188
- pf : quotes.reflect.Term
189
- ): Expr [B ] =
190
- import quotes .reflect ._
191
- pf match
192
- case Lambda (valDefs, body) =>
193
- runImplTree[F ,A ,B ](builder, body)
194
- case Inlined (_,List (),body) =>
195
- runImplTree[F ,A ,B ](builder, body)
196
- case Match (scrutinee,cases) =>
197
- // val caseExprs = cases map(x => parseCaseDef[F,A](x))
198
- // if (caseExprs.find(_.isInstanceOf[DefaultExpression[?]]).isDefined) {
199
- // report.error("default is not supported")
200
- // }
201
- val unorderedCases = cases.map(parseCaseDef[F ,A ,B ](_))
202
- // done should be
203
- val (isDone,notDone) = unorderedCases.partition{ x =>
204
- x match
205
- case DoneExression (_,_) => true
206
- case ReadExpression (_,_,isDone) => isDone
207
- case _ => false
208
- }
209
- val doneFirstCases = isDone ++ notDone
210
- builder(doneFirstCases)
211
-
212
-
213
- def parseCaseDef [F [_]: Type ,S : Type ,R : Type ](using Quotes )(caseDef : quotes.reflect.CaseDef ): SelectorCaseExpr [F ,S ,R ] =
214
- import quotes .reflect ._
215
-
216
- val caseDefGuard = parseCaseDefGuard(caseDef)
217
-
218
- def handleRead (bind : Bind , valName : String , channel: Term , tp: TypeRepr ): SelectorCaseExpr [F ,S ,R ] =
219
- val readFun = makeLambda(valName,tp,bind.symbol,caseDef.rhs)
220
- if (channel.tpe <:< TypeRepr .of[ReadChannel [F ,? ]])
221
- tp.asType match
222
- case ' [a] =>
223
- val isDone = channel match
224
- case quotes.reflect.Select (ch1," done" ) if (ch1.tpe <:< TypeRepr .of[ReadChannel [F ,? ]]) => true
225
- case _ => false
226
- ReadExpression (channel.asExprOf[ReadChannel [F ,a]],readFun.asExprOf[a=> S ],isDone)
227
- case _ =>
228
- reportError(" can't determinate read type" , caseDef.pattern.asExpr)
229
- else
230
- reportError(" read pattern is not a read channel" , channel.asExpr)
231
-
232
- def handleWrite (bind : Bind , valName : String , channel: Term , tp: TypeRepr ): SelectorCaseExpr [F ,S ,R ] =
233
- val writeFun = makeLambda(valName,tp, bind.symbol, caseDef.rhs)
234
- val e = caseDefGuard.getOrElse(valName,
235
- reportError(s " not found binding ${valName} in write condition " , channel.asExpr)
236
- )
237
- if (channel.tpe <:< TypeRepr .of[WriteChannel [F ,? ]]) then
238
- tp.asType match
239
- case ' [a] =>
240
- WriteExpression (channel.asExprOf[WriteChannel [F ,a]],e.asExprOf[a], writeFun.asExprOf[a=> S ])
241
- case _ =>
242
- reportError(" Can't determinate type of write" , caseDef.pattern.asExpr)
243
- else
244
- reportError(" Write channel expected" , channel.asExpr)
245
-
246
- def extractType [F [_]: Type ](name : " read" | " write" , channelTerm : Term , pat : Tree ): TypeRepr =
247
- import quotes .reflect ._
248
- pat match
249
- case Typed (_,tp) => tp.tpe
250
- case _ =>
251
- TypeSelect (channelTerm,name).tpe
252
-
253
-
254
- caseDef.pattern match
255
- case Inlined (_,List (),body) =>
256
- parseCaseDef(CaseDef (body, caseDef.guard, caseDef.rhs))
257
- case b@ Bind (v, tp@ Typed (expr, TypeSelect (ch," read" ))) =>
258
- handleRead(b,v,ch,tp.tpe)
259
- case b@ Bind (v, tp@ Typed (expr, Annotated (TypeSelect (ch," read" ),_))) =>
260
- handleRead(b,v,ch,tp.tpe)
261
- case tp@ Typed (expr, TypeSelect (ch," read" )) =>
262
- // todo: introduce 'dummy' val
263
- reportError(" binding var in read expression is mandatory" , caseDef.pattern.asExpr)
264
- case b@ Bind (v, tp@ Typed (expr, TypeSelect (ch," write" ))) =>
265
- handleWrite(b,v,ch,tp.tpe)
266
- case b@ Bind (v, tp@ Typed (expr, Annotated (TypeSelect (ch," write" ),_))) =>
267
- handleWrite(b,v,ch,tp.tpe)
268
- case b@ Bind (v, tp@ Typed (expr, TypeSelect (ch," after" ))) =>
269
- val timeoutFun = makeLambda(v, tp.tpe, b.symbol, caseDef.rhs)
270
- val e = caseDefGuard.getOrElse(v, reportError(s " can't find condifion for $v" ,caseDef.pattern.asExpr))
271
- if (ch.tpe <:< TypeRepr .of[gopher.Time ] || ch.tpe <:< TypeRepr .of[gopher.Time .type ])
272
- TimeoutExpression (e.asExprOf[FiniteDuration ], timeoutFun.asExprOf[FiniteDuration => S ])
273
- else
274
- reportError(s " Expected Time, we have ${ch.show}" , ch.asExpr)
275
- case b@ Bind (v, tp@ Typed (expr, TypeSelect (ch," done" ))) =>
276
- val readFun = makeLambda(v,tp.tpe,b.symbol,caseDef.rhs)
277
- tp.tpe.asType match
278
- case ' [a] =>
279
- if (ch.tpe <:< TypeRepr .of[ReadChannel [F ,a]]) then
280
- DoneExression (ch.asExprOf[ReadChannel [F ,a]],readFun.asExprOf[Unit => S ])
281
- else
282
- reportError(" done base is not a read channel" , ch.asExpr)
283
- case _ =>
284
- reportError(" can't determinate read type" , caseDef.pattern.asExpr)
285
- case pat@ Unapply (TypeApply (quotes.reflect.Select (
286
- quotes.reflect.Select (chobj,nameReadOrWrite),
287
- " unapply" ),targs),
288
- impl,List (b@ Bind (e,ePat),Bind (ch,chPat))) =>
289
- if (chobj.tpe == ' {gopher.Channel }.asTerm.tpe)
290
- val chExpr = caseDefGuard.getOrElse(ch,reportError(s " select condition for ${ch} is not found " ,caseDef.pattern.asExpr))
291
- nameReadOrWrite match
292
- case " Read" =>
293
- val elementType = extractType(" read" ,chExpr, ePat)
294
- handleRead(b,e,chExpr,elementType)
295
- case " Write" =>
296
- val elementType = extractType(" write" ,chExpr, ePat)
297
- handleWrite(b,e,chExpr,elementType)
298
- case _ =>
299
- reportError(s " Read or Write expected, we have ${nameReadOrWrite}" , caseDef.pattern.asExpr)
300
- else
301
- reportError(" Incorrect select pattern, expected or x:channel.{read,write} or Channel.{Read,Write}" ,chobj.asExpr)
302
- case _ =>
303
- report.error(
304
- s """
305
- expected one of:
306
- v: channel.read
307
- v: channel.write if v == expr
308
- v: Time.after if v == expr
309
- we have
310
- ${caseDef.pattern.show}
311
- (tree: ${caseDef.pattern})
312
- """ , caseDef.pattern.asExpr)
313
- reportError(s " unparsed caseDef pattern: ${caseDef.pattern}" , caseDef.pattern.asExpr)
314
-
315
- end parseCaseDef
316
-
317
-
318
- def parseCaseDefGuard (using Quotes )(caseDef : quotes.reflect.CaseDef ): Map [String ,quotes.reflect.Term ] =
319
- import quotes .reflect ._
320
- caseDef.guard match
321
- case Some (condition) =>
322
- parseSelectCondition(condition, Map .empty)
323
- case None =>
324
- Map .empty
325
-
326
-
327
- def parseSelectCondition (using Quotes )(condition : quotes.reflect.Term ,
328
- entries: Map [String ,quotes.reflect.Term ]): Map [String ,quotes.reflect.Term ] =
329
- import quotes .reflect ._
330
- condition match
331
- case Apply (quotes.reflect.Select (Ident (v1)," ==" ),List (expr)) =>
332
- entries.updated(v1, expr)
333
- case Apply (quotes.reflect.Select (frs, " &&" ), List (snd)) =>
334
- parseSelectCondition(snd, parseSelectCondition(frs, entries))
335
- case _ =>
336
- reportError(
337
- s """ Invalid select guard form, expected one of
338
- channelName == channelEpxr
339
- writeBind == writeExpresion
340
- condition && condition
341
- we have
342
- ${condition.show}
343
- """ ,
344
- condition.asExpr)
345
-
346
-
347
- def makeLambda (using Quotes )(argName : String ,
348
- argType : quotes.reflect.TypeRepr ,
349
- oldArgSymbol : quotes.reflect.Symbol ,
350
- body : quotes.reflect.Term ): quotes.reflect.Term =
351
- import quotes .reflect ._
352
- val widenReturnType = TransformUtil .veryWiden(body.tpe)
353
- val mt = MethodType (List (argName))(_ => List (argType.widen), _ => widenReturnType)
354
- Lambda (Symbol .spliceOwner, mt, (owner,args) =>
355
- substIdent(body,oldArgSymbol, args.head.asInstanceOf [Term ], owner).changeOwner(owner))
356
-
357
-
358
- def substIdent (using Quotes )(term : quotes.reflect.Term ,
359
- fromSym : quotes.reflect.Symbol ,
360
- toTerm : quotes.reflect.Term ,
361
- owner : quotes.reflect.Symbol ): quotes.reflect.Term =
362
- import quotes .reflect ._
363
- val argTransformer = new TreeMap () {
364
- override def transformTerm (tree : Term )(owner : Symbol ): Term =
365
- tree match
366
- case Ident (name) if tree.symbol == fromSym => toTerm
367
- case _ => super .transformTerm(tree)(owner)
368
- }
369
- argTransformer.transformTerm(term)(owner)
370
-
371
-
372
- def reportError (message : String , posExpr : Expr [? ])(using Quotes ): Nothing =
373
- import quotes .reflect ._
374
- report.error(message, posExpr)
375
- throw new RuntimeException (s " Error in macro: $message" )
376
-
377
-
378
-
0 commit comments