Skip to content

Commit 4388804

Browse files
committed
adopted do scala3.0.1 and dotty-cps-async 0.9.0
1 parent ee2a04e commit 4388804

File tree

8 files changed

+353
-287
lines changed

8 files changed

+353
-287
lines changed

build.sbt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
//val dottyVersion = "3.0.0-RC2-bin-SNAPSHOT"
2-
val dottyVersion = "3.0.1-RC2"
2+
val dottyVersion = "3.0.1"
33
//val dottyVersion = dottyLatestNightlyBuild.get
44

5-
ThisBuild/version := "2.0.4-SNAPSHOT"
5+
ThisBuild/version := "2.0.4"
66
ThisBuild/versionScheme := Some("semver-spec")
77

88
val sharedSettings = Seq(
99
organization := "com.github.rssh",
1010
scalaVersion := dottyVersion,
1111
name := "scala-gopher",
1212
resolvers += "Local Ivy Repository" at "file://"+Path.userHome.absolutePath+"/.ivy2/local",
13-
libraryDependencies += "com.github.rssh" %%% "dotty-cps-async" % "0.8.1",
13+
libraryDependencies += "com.github.rssh" %%% "dotty-cps-async" % "0.9.0",
1414
libraryDependencies += "org.scalameta" %%% "munit" % "0.7.26" % Test,
1515
testFrameworks += new TestFramework("munit.Framework")
1616
)

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version=1.5.1
1+
sbt.version=1.5.5

shared/src/main/scala/gopher/Select.scala

Lines changed: 16 additions & 274 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@ class Select[F[_]](api: Gopher[F]):
2828
*/
2929
transparent inline def apply[A](inline pf: PartialFunction[Any,A]): A =
3030
${
31-
Select.onceImpl[F,A]('pf, 'api )
31+
SelectMacro.onceImpl[F,A]('pf, 'api )
3232
}
3333

34+
/***
35+
* create select groop
36+
*@see [gopher.SelectGroup]
37+
**/
3438
def group[S]: SelectGroup[F,S] = new SelectGroup[F,S](api)
3539

3640
def once[S]: SelectGroup[F,S] = new SelectGroup[F,S](api)
@@ -92,287 +96,25 @@ class Select[F[_]](api: Gopher[F]):
9296
}
9397
r
9498

95-
def forever: SelectForever[F] = new SelectForever[F](api )
99+
/**
100+
* create forever runner.
101+
**/
102+
def forever: SelectForever[F] = new SelectForever[F](api)
96103

104+
/**
105+
* run forever expression in `pf`, return
106+
**/
97107
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) }
102109

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] =
104112
given CpsSchedulingMonad[F] = api.asyncMonad
105113
async(using api.asyncMonad).apply {
106114
val runner = new SelectForever[F](api)
107115
runner.applyAsync(pf)
108116
}
109-
117+
*/
110118

111119

112120

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-

shared/src/main/scala/gopher/SelectForever.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@ import scala.compiletime._
66
import scala.concurrent.duration._
77

88

9+
/**
10+
* forever Apply
11+
**/
912
class SelectForever[F[_]](api: Gopher[F]) extends SelectGroupBuilder[F,Unit, Unit](api):
1013

1114

1215
transparent inline def apply(inline pf: PartialFunction[Any,Unit]): Unit =
1316
${
14-
Select.foreverImpl('pf,'api)
17+
SelectMacro.foreverImpl('pf,'api)
1518
}
1619

17-
transparent inline def applyAsync(inline pf: PartialFunction[Any,F[Unit]]): Unit =
18-
???
20+
transparent inline def applyAsync(inline pf: PartialFunction[Any,Unit]): F[Unit] =
21+
${
22+
SelectMacro.aforeverImpl('pf, 'api)
23+
}
1924

2025
def runAsync(): F[Unit] =
2126
given CpsSchedulingMonad[F] = api.asyncMonad

shared/src/main/scala/gopher/SelectGroup.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ class SelectGroup[F[_], S](api: Gopher[F]) extends SelectListeners[F,S,S]:
6565

6666
transparent inline def apply(inline pf: PartialFunction[Any,S]): S =
6767
${
68-
Select.onceImpl[F,S]('pf, 'api )
68+
SelectMacro.onceImpl[F,S]('pf, 'api )
6969
}
7070

7171
transparent inline def select(inline pf: PartialFunction[Any,S]): S =
7272
${
73-
Select.onceImpl[F,S]('pf, 'api )
73+
SelectMacro.onceImpl[F,S]('pf, 'api )
7474
}
7575

7676
/**

shared/src/main/scala/gopher/SelectLoop.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class SelectLoop[F[_]](api: Gopher[F]) extends SelectGroupBuilder[F,Boolean, Uni
1313

1414
transparent inline def apply(inline pf: PartialFunction[Any,Boolean]): Unit =
1515
${
16-
Select.loopImpl[F]('pf, 'api )
16+
SelectMacro.loopImpl[F]('pf, 'api )
1717
}
1818

1919
def runAsync(): F[Unit] =

0 commit comments

Comments
 (0)