1
1
package fr .hammons .slinc
2
2
3
- import java .lang .invoke .MethodHandle
4
3
import scala .quoted .*
5
4
import scala .annotation .nowarn
5
+ import fr .hammons .slinc .CFunctionRuntimeInformation .{
6
+ InputTransition ,
7
+ ReturnTransition
8
+ }
9
+ import fr .hammons .slinc .CFunctionBindingGenerator .VariadicTransition
6
10
7
- type InputTransition = (Allocator , Any ) => Any
8
- type OutputTransition = (Object | Null ) => AnyRef
9
- type VariadicInputTransition = (TypeDescriptor , Allocator , Any ) => Any
10
11
trait CFunctionBindingGenerator :
11
12
def generate (
12
13
methodHandler : MethodHandler ,
13
- inputTransitions : IArray [InputTransition ],
14
- outputTransition : OutputTransition ,
15
- scope : Scope
16
- ): AnyRef
17
-
18
- def generateVariadic (
19
- methodHandler : MethodHandler ,
20
- inputTransitions : IArray [InputTransition ],
21
- variadicTransition : VariadicInputTransition ,
22
- outputTransition : OutputTransition ,
14
+ transitionSet : CFunctionRuntimeInformation ,
15
+ variadicTransition : VariadicTransition ,
23
16
scope : Scope
24
17
): AnyRef
25
18
26
19
object CFunctionBindingGenerator :
27
- private def getVariadicExprs (
28
- s : Seq [Variadic ],
29
- variadicTransition : VariadicInputTransition ,
30
- allocator : Allocator
31
- ): Seq [Any ] =
32
- s.map: vararg =>
33
- vararg.use[DescriptorOf ](dc ?=>
34
- d => variadicTransition(dc.descriptor, allocator, d)
35
- )
20
+ type VariadicTransition = (Allocator , Seq [Variadic ]) => Seq [Any ]
21
+
22
+ private enum LambdaInputs :
23
+ case Standard (args : List [Expr [Any ]])
24
+ case VariadicInputs (args : List [Expr [Any ]], varArgs : Expr [Seq [Variadic ]])
25
+
26
+ private object LambdaInputs :
27
+ def choose (args : List [Expr [Any ]], isVariadic : Boolean )(
28
+ variadicInput : => Expr [Seq [Variadic ]]
29
+ ) = if isVariadic then
30
+ LambdaInputs .VariadicInputs (args, varArgs = variadicInput)
31
+ else LambdaInputs .Standard (args)
36
32
37
33
@ nowarn(" msg=unused implicit parameter" )
38
- private def invokeVariadicArguments (
39
- mhGen : Expr [Seq [Variadic ] => MethodHandle ],
40
- inputs : Expr [Seq [Any ]],
41
- varArgs : Expr [Seq [Variadic ]],
42
- variadicTransition : Expr [VariadicInputTransition ],
43
- alloc : Expr [Allocator ]
34
+ private def invokation (
35
+ variadicTransition : Expr [VariadicTransition ],
36
+ mh : Expr [MethodHandler ]
44
37
)(using Quotes ) =
45
- ' {
46
- MethodHandleFacade .callVariadic(
47
- $mhGen($varArgs),
48
- $inputs ++ getVariadicExprs($varArgs, $variadicTransition, $alloc)*
49
- )
50
- }
38
+ (alloc : Expr [Allocator ], inputs : LambdaInputs ) =>
39
+ inputs match
40
+ case LambdaInputs .Standard (args) =>
41
+ MethodHandleTools .invokeArguments(
42
+ ' { $mh.nonVariadic },
43
+ args
44
+ )
45
+ case LambdaInputs .VariadicInputs (args, varArgs) =>
46
+ ' {
47
+ MethodHandleFacade .callVariadic(
48
+ $mh.variadic($varArgs),
49
+ $ { Expr .ofList(args) } ++ $variadicTransition($alloc, $varArgs)*
50
+ )
51
+ }
51
52
52
53
inline def apply [L ](
53
54
name : String
54
55
): CFunctionBindingGenerator = $ {
55
56
applyImpl[L ](' name )
56
57
}
57
58
59
+ @ nowarn(" msg=unused implicit parameter" )
60
+ private def lambda (
61
+ argNumbers : Int ,
62
+ scope : Expr [Scope ],
63
+ inputTransitions : Expr [IArray [InputTransition ]],
64
+ outputTransition : Expr [ReturnTransition ],
65
+ allocatingReturn : Boolean ,
66
+ varArg : Boolean
67
+ )(
68
+ invocationExpr : Quotes ?=> (
69
+ Expr [Allocator ],
70
+ LambdaInputs
71
+ ) => Expr [Object | Null ]
72
+ )(using Quotes ) =
73
+ import quotes .reflect .*
74
+
75
+ val names = List .fill(argNumbers)(" a" )
76
+ val argTypes =
77
+ if varArg then
78
+ List .fill(argNumbers - 1 )(TypeRepr .of[Object ]) :+ TypeRepr
79
+ .of[Seq [Variadic ]]
80
+ else List .fill(argNumbers)(TypeRepr .of[Object ])
81
+
82
+ val methodType =
83
+ MethodType (names)(_ => argTypes, _ => TypeRepr .of[Object ])
84
+
85
+ Lambda (
86
+ Symbol .spliceOwner,
87
+ methodType,
88
+ (sym, inputs) =>
89
+ def inputExprs (alloc : Expr [Allocator ])(using q : Quotes ) =
90
+ val prefix = if allocatingReturn then List (alloc.asTerm) else Nil
91
+ val toTransform = if varArg then inputs.init else inputs
92
+ LambdaInputs .choose(
93
+ prefix
94
+ .concat(toTransform)
95
+ .map(_.asExpr)
96
+ .zipWithIndex
97
+ .map: (exp, i) =>
98
+ ' { $inputTransitions($ { Expr (i) })($alloc, $exp) },
99
+ varArg
100
+ )(inputs.last.asExprOf[Seq [Variadic ]])
101
+
102
+ ' {
103
+ $scope { alloc ?=>
104
+ $outputTransition(
105
+ $ { invocationExpr(' alloc , inputExprs(' alloc )) }
106
+ )
107
+ }
108
+ }.asTerm.changeOwner(sym)
109
+ ).asExprOf[AnyRef ]
110
+
58
111
@ nowarn(" msg=unused implicit parameter" )
59
112
private def applyImpl [L ](name : Expr [String ])(using
60
113
Quotes ,
@@ -69,124 +122,33 @@ object CFunctionBindingGenerator:
69
122
.declaredMethod(name.valueOrAbort)
70
123
.head
71
124
72
- val argNumbers = methodSymbol.paramSymss.map(_.size).sum
73
- val names = List .fill(argNumbers)(" a" )
74
-
75
- def lambda (
76
- methodHandle : Expr [MethodHandle ],
77
- inputTransitions : Expr [IArray [InputTransition ]],
78
- outputTransition : Expr [OutputTransition ],
79
- scope : Expr [Scope ]
80
- )(using Quotes ): Expr [AnyRef ] =
81
- import quotes .reflect .*
82
-
83
- val argsTypes = List .fill(argNumbers)(TypeRepr .of[Object ])
84
-
85
- val methodType =
86
- MethodType (names)(_ => argsTypes, _ => TypeRepr .of[Object ])
87
- Lambda (
88
- Symbol .spliceOwner,
89
- methodType,
90
- (sym, inputs) =>
91
- def inputExprs (using q : Quotes ) = (alloc : Expr [Allocator ]) =>
92
- inputs
93
- .map(i => i.asExpr)
94
- .zipWithIndex
95
- .map((exp, i) =>
96
- ' { $inputTransitions($ { Expr (i) })($alloc, $exp) }
97
- )
98
- ' {
99
- $scope { alloc ?=>
100
- $outputTransition(
101
- $ {
102
- MethodHandleTools .invokeArguments(
103
- methodHandle,
104
- inputExprs(' alloc )
105
- )
106
- }
107
- )
108
- }
109
- }.asTerm.changeOwner(sym)
110
- ).asExprOf[AnyRef ]
111
-
112
- def lambdaVariadic (
113
- methodHandleGen : Expr [Seq [Variadic ] => MethodHandle ],
114
- inputTransitions : Expr [IArray [InputTransition ]],
115
- outputTransition : Expr [OutputTransition ],
116
- variadicTransition : Expr [
117
- VariadicInputTransition
118
- ],
119
- scope : Expr [Scope ]
120
- )(using Quotes ): Expr [AnyRef ] =
121
- import quotes .reflect .*
122
-
123
- val argTypes = List .fill(argNumbers - 1 )(TypeRepr .of[Object ]) :+ TypeRepr
124
- .of[Seq [Variadic ]]
125
-
126
- val methodType =
127
- MethodType (names)(_ => argTypes, _ => TypeRepr .of[Object ])
128
-
129
- Lambda (
130
- Symbol .spliceOwner,
131
- methodType,
132
- (sym, inputs) =>
133
- def inputExprs (using q : Quotes ) = (alloc : Expr [Allocator ]) =>
134
- Expr .ofList(
135
- inputs.init
136
- .map(i => i.asExpr)
137
- .zipWithIndex
138
- .map((exp, i) =>
139
- ' { $inputTransitions($ { Expr (i) })($alloc, $exp) }
140
- )
141
- )
142
-
143
- ' {
144
- $scope { alloc ?=>
145
- $outputTransition(
146
- $ {
147
- invokeVariadicArguments(
148
- methodHandleGen,
149
- inputExprs(' alloc ),
150
- inputs.last.asExprOf[Seq [Variadic ]],
151
- variadicTransition,
152
- ' { alloc }
153
- )
154
- }
155
- )
156
- }
157
- }.asTerm.changeOwner(sym)
158
- ).asExprOf[AnyRef ]
159
-
160
125
' {
161
126
new CFunctionBindingGenerator :
162
127
def generate (
163
128
methodHandler : MethodHandler ,
164
- inputTransitions : IArray [ InputTransition ] ,
165
- outputTransition : OutputTransition ,
129
+ functionInformation : CFunctionRuntimeInformation ,
130
+ variadicTransition : VariadicTransition ,
166
131
scope : Scope
167
132
): AnyRef =
168
133
$ {
169
- lambda(
170
- ' { methodHandler.nonVariadic },
171
- ' inputTransitions ,
172
- ' outputTransition ,
173
- ' scope
174
- )
134
+ def lambdaGen (allocatingReturn : Boolean , variadic : Boolean ) =
135
+ lambda(
136
+ methodSymbol.paramSymss.map(_.size).sum,
137
+ ' scope ,
138
+ ' { functionInformation.inputTransitions },
139
+ ' { functionInformation.returnTransition },
140
+ allocatingReturn,
141
+ variadic
142
+ )(invokation(' variadicTransition , ' methodHandler ))
143
+
144
+ ' {
145
+ if functionInformation.isVariadic && functionInformation.returnAllocates
146
+ then $ { lambdaGen(allocatingReturn = true , variadic = true ) }
147
+ else if functionInformation.isVariadic then
148
+ $ { lambdaGen(allocatingReturn = false , variadic = true ) }
149
+ else if functionInformation.returnAllocates then
150
+ $ { lambdaGen(allocatingReturn = true , variadic = false ) }
151
+ else $ { lambdaGen(allocatingReturn = false , variadic = false ) }
152
+ }
175
153
}
176
-
177
- def generateVariadic (
178
- methodHandler : MethodHandler ,
179
- inputTransitions : IArray [InputTransition ],
180
- variadicTransitions : VariadicInputTransition ,
181
- outputTransition : OutputTransition ,
182
- scope : Scope
183
- ): AnyRef = $ {
184
- lambdaVariadic(
185
- ' { methodHandler.variadic },
186
- ' inputTransitions ,
187
- ' outputTransition ,
188
- ' variadicTransitions ,
189
- ' scope
190
- )
191
- }
192
154
}
0 commit comments