@@ -3,48 +3,17 @@ package mainargs
3
3
import scala .quoted ._
4
4
5
5
object Macros {
6
+ private def mainAnnotation (using Quotes ) = quotes.reflect.TypeRepr .of[mainargs.main].typeSymbol
7
+ private def argAnnotation (using Quotes ) = quotes.reflect.TypeRepr .of[mainargs.arg].typeSymbol
6
8
def parserForMethods [B ](base : Expr [B ])(using Quotes , Type [B ]): Expr [ParserForMethods [B ]] = {
7
9
import quotes .reflect ._
8
10
val allMethods = TypeRepr .of[B ].typeSymbol.memberMethods
9
- val mainAnnotation = TypeRepr .of[mainargs.main].typeSymbol
10
- val argAnnotation = TypeRepr .of[mainargs.arg].typeSymbol
11
11
val annotatedMethodsWithMainAnnotations = allMethods.flatMap { methodSymbol =>
12
12
methodSymbol.getAnnotation(mainAnnotation).map(methodSymbol -> _)
13
13
}.sortBy(_._1.pos.map(_.start))
14
- val mainDatasExprs : Seq [Expr [MainData [Any , B ]]] = annotatedMethodsWithMainAnnotations.map { (annotatedMethod, mainAnnotation) =>
15
- val params = annotatedMethod.paramSymss.headOption.getOrElse(throw new Exception (" Multiple parameter lists not supported" ))
16
- val defaultParams = getDefaultParams(annotatedMethod)
17
- val argSigs = Expr .ofList(params.map { param =>
18
- val paramTree = param.tree.asInstanceOf [ValDef ]
19
- val paramTpe = paramTree.tpt.tpe
20
- val arg = param.getAnnotation(argAnnotation).map(_.asExpr.asInstanceOf [Expr [mainargs.arg]]).getOrElse(' { new mainargs.arg() })
21
- val paramType = paramTpe.asType
22
- paramType match
23
- case ' [t] =>
24
- val defaultParam : Expr [Option [B => t]] = defaultParams.get(param) match {
25
- case Some (v) => ' { Some (((_ : B ) => $v).asInstanceOf [B => t]) }
26
- case None => ' { None }
27
- }
28
- val argReader = Expr .summon[mainargs.ArgReader [t]].getOrElse{
29
- report.error(
30
- s " No mainargs.ArgReader of ${paramTpe.typeSymbol.fullName} found for parameter ${param.name}" ,
31
- param.pos.get
32
- )
33
- ' { ??? }
34
- }
35
- ' { ArgSig .create[t, B ]($ { Expr (param.name) }, $ { arg }, $ { defaultParam })(using $ { argReader }).asInstanceOf [mainargs.ArgSig [Any , B ]] }
36
- })
37
-
38
- val invokeRaw : Expr [(B , Seq [Any ]) => Any ] = {
39
- def callOf (args : Expr [Seq [Any ]]) = call(annotatedMethod, ' { Seq ( $ { args }) })
40
- ' { (b : B , params : Seq [Any ]) =>
41
- $ { callOf(' { params }) }
42
- }
43
- }
44
-
45
- ' { MainData .create[Any , B ]($ { Expr (annotatedMethod.name) }, $ { mainAnnotation.asExprOf[mainargs.main] }, $ { argSigs }, $ { invokeRaw }) }
46
- }
47
- val mainDatas = Expr .ofList(mainDatasExprs)
14
+ val mainDatas = Expr .ofList(annotatedMethodsWithMainAnnotations.map { (annotatedMethod, mainAnnotationInstance) =>
15
+ createMainData[Any , B ](annotatedMethod, mainAnnotationInstance)
16
+ })
48
17
49
18
' {
50
19
new ParserForMethods [B ](
@@ -53,6 +22,65 @@ object Macros {
53
22
}
54
23
}
55
24
25
+ def parserForClass [B ](using Quotes , Type [B ]): Expr [ParserForClass [B ]] = {
26
+ import quotes .reflect ._
27
+ val typeReprOfB = TypeRepr .of[B ]
28
+ val companionModule = typeReprOfB match {
29
+ case TypeRef (a,b) => TermRef (a,b)
30
+ }
31
+ val typeSymbolOfB = typeReprOfB.typeSymbol
32
+ val companionModuleType = typeSymbolOfB.companionModule.tree.asInstanceOf [ValDef ].tpt.tpe.asType
33
+ val companionModuleExpr = Ident (companionModule).asExpr
34
+ val mainAnnotationInstance = typeSymbolOfB.getAnnotation(mainAnnotation).getOrElse {
35
+ report.error(
36
+ s " cannot find @main annotation on ${companionModule.name}" ,
37
+ typeSymbolOfB.pos.get
38
+ )
39
+ ???
40
+ }
41
+ val annotatedMethod = TypeRepr .of[B ].typeSymbol.companionModule.memberMethod(" apply" ).head
42
+ companionModuleType match
43
+ case ' [bCompanion] =>
44
+ val mainData = createMainData[B , bCompanion](annotatedMethod, mainAnnotationInstance)
45
+ ' {
46
+ new ParserForClass [B ](
47
+ ClassMains [B ]($ { mainData }.asInstanceOf [MainData [B , Any ]], () => $ { Ident (companionModule).asExpr })
48
+ )
49
+ }
50
+ }
51
+
52
+ def createMainData [T : Type , B : Type ](using Quotes )(method : quotes.reflect.Symbol , annotation : quotes.reflect.Term ): Expr [MainData [T , B ]] = {
53
+ import quotes .reflect .*
54
+ val params = method.paramSymss.headOption.getOrElse(throw new Exception (" Multiple parameter lists not supported" ))
55
+ val defaultParams = getDefaultParams(method)
56
+ val argSigs = Expr .ofList(params.map { param =>
57
+ val paramTree = param.tree.asInstanceOf [ValDef ]
58
+ val paramTpe = paramTree.tpt.tpe
59
+ val arg = param.getAnnotation(argAnnotation).map(_.asExpr.asInstanceOf [Expr [mainargs.arg]]).getOrElse(' { new mainargs.arg() })
60
+ val paramType = paramTpe.asType
61
+ paramType match
62
+ case ' [t] =>
63
+ val defaultParam : Expr [Option [B => t]] = defaultParams.get(param) match {
64
+ case Some (v) => ' { Some (((_ : B ) => $v).asInstanceOf [B => t]) }
65
+ case None => ' { None }
66
+ }
67
+ val argReader = Expr .summon[mainargs.ArgReader [t]].getOrElse{
68
+ report.error(
69
+ s " No mainargs.ArgReader of ###companionModule### found for parameter ${param.name}" ,
70
+ param.pos.get
71
+ )
72
+ ' { ??? }
73
+ }
74
+ ' { (ArgSig .create[t, B ]($ { Expr (param.name) }, $ { arg }, $ { defaultParam })(using $ { argReader })).asInstanceOf [ArgSig [Any , B ]] }
75
+ })
76
+
77
+ val invokeRaw : Expr [(B , Seq [Any ]) => T ] = {
78
+ def callOf (args : Expr [Seq [Any ]]) = call(method, ' { Seq ( $ { args }) })
79
+ ' { ((b : B , params : Seq [Any ]) => $ { callOf(' { params }) }).asInstanceOf [(B , Seq [Any ]) => T ] }
80
+ }
81
+ ' { MainData .create[T , B ]($ { Expr (method.name) }, $ { annotation.asExprOf[mainargs.main] }, $ { argSigs }, $ { invokeRaw }) }
82
+ }
83
+
56
84
/** Call a method given by its symbol.
57
85
*
58
86
* E.g.
0 commit comments