Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / mlton / atoms / c-function.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 2015 Matthew Fluet.
2 * Copyright (C) 2003-2007 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 *
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
7 *)
8
9functor CFunction (S: C_FUNCTION_STRUCTS): C_FUNCTION =
10struct
11
12open S
13
14structure Convention =
15 struct
16 datatype t =
17 Cdecl
18 | Stdcall
19
20 val toString =
21 fn Cdecl => "cdecl"
22 | Stdcall => "stdcall"
23
24 val layout = Layout.str o toString
25 end
26
27structure Kind =
28 struct
29 datatype t =
30 Impure
31 | Pure
32 | Runtime of {bytesNeeded: int option,
33 ensuresBytesFree: bool,
34 mayGC: bool,
35 maySwitchThreads: bool,
36 modifiesFrontier: bool,
37 readsStackTop: bool,
38 writesStackTop: bool}
39
40 val runtimeDefault = Runtime {bytesNeeded = NONE,
41 ensuresBytesFree = false,
42 mayGC = true,
43 maySwitchThreads = false,
44 modifiesFrontier = true,
45 readsStackTop = true,
46 writesStackTop = true}
47 val pure = Pure
48 val impure = Impure
49 val reentrant = runtimeDefault
50
51 fun layout k =
52 case k of
53 Impure => Layout.str "Impure"
54 | Pure => Layout.str "Pure"
55 | Runtime {bytesNeeded, ensuresBytesFree, mayGC,
56 maySwitchThreads, modifiesFrontier,
57 readsStackTop, writesStackTop} =>
58 Layout.namedRecord
59 ("Runtime",
60 [("bytesNeeded", Option.layout Int.layout bytesNeeded),
61 ("ensuresBytesFree", Bool.layout ensuresBytesFree),
62 ("mayGC", Bool.layout mayGC),
63 ("maySwitchThreads", Bool.layout maySwitchThreads),
64 ("modifiesFrontier", Bool.layout modifiesFrontier),
65 ("readsStackTop", Bool.layout readsStackTop),
66 ("writesStackTop", Bool.layout writesStackTop)])
67
68 val toString = Layout.toString o layout
69
70 local
71 fun make (sel, default) k =
72 case k of
73 Impure => default
74 | Pure => default
75 | Runtime r => sel r
76 fun makeBool sel = make (sel, false)
77 fun makeOpt sel = make (sel, NONE)
78 in
79 val bytesNeeded = makeOpt #bytesNeeded
80 val ensuresBytesFree = makeBool #ensuresBytesFree
81 val mayGC = makeBool #mayGC
82 val maySwitchThreads = makeBool #maySwitchThreads
83 val modifiesFrontier = makeBool #modifiesFrontier
84 val readsStackTop = makeBool #readsStackTop
85 val writesStackTop = makeBool #writesStackTop
86 end
87 end
88
89structure SymbolScope =
90 struct
91 datatype t =
92 External
93 | Private
94 | Public
95
96 val toString =
97 fn External => "external"
98 | Private => "private"
99 | Public => "public"
100
101 val layout = Layout.str o toString
102 end
103
104structure Target =
105 struct
106 datatype t =
107 Direct of string
108 | Indirect
109
110 val toString =
111 fn Direct name => name
112 | Indirect => "<*>"
113
114 val layout = Layout.str o toString
115
116 val equals =
117 fn (Direct name, Direct name') => name = name'
118 | (Indirect, Indirect) => true
119 | _ => false
120 end
121datatype z = datatype Target.t
122
123datatype 'a t = T of {args: 'a vector,
124 convention: Convention.t,
125 kind: Kind.t,
126 prototype: CType.t vector * CType.t option,
127 return: 'a,
128 symbolScope: SymbolScope.t,
129 target: Target.t}
130
131fun layout (T {args, convention, kind, prototype, return, symbolScope, target, ...},
132 layoutType) =
133 Layout.record
134 [("args", Vector.layout layoutType args),
135 ("convention", Convention.layout convention),
136 ("kind", Kind.layout kind),
137 ("prototype", (fn (args,ret) =>
138 Layout.record
139 [("args", Vector.layout CType.layout args),
140 ("res", Option.layout CType.layout ret)]) prototype),
141 ("return", layoutType return),
142 ("symbolScope", SymbolScope.layout symbolScope),
143 ("target", Target.layout target)]
144
145local
146 fun make f (T r) = f r
147 fun makeKind f (T r) = f (#kind r)
148in
149 fun args z = make #args z
150 fun bytesNeeded z = makeKind Kind.bytesNeeded z
151 fun convention z = make #convention z
152 fun ensuresBytesFree z = makeKind Kind.ensuresBytesFree z
153 fun mayGC z = makeKind Kind.mayGC z
154 fun maySwitchThreads z = makeKind Kind.maySwitchThreads z
155 fun modifiesFrontier z = makeKind Kind.modifiesFrontier z
156 fun prototype z = make #prototype z
157 fun readsStackTop z = makeKind Kind.readsStackTop z
158 fun return z = make #return z
159 fun symbolScope z = make #symbolScope z
160 fun target z = make #target z
161 fun writesStackTop z = makeKind Kind.writesStackTop z
162end
163(* quell unused warnings *)
164val _ = (modifiesFrontier, readsStackTop, writesStackTop)
165
166fun equals (f, f') = Target.equals (target f, target f')
167
168fun map (T {args, convention, kind, prototype, return, symbolScope, target},
169 f) =
170 T {args = Vector.map (args, f),
171 convention = convention,
172 kind = kind,
173 prototype = prototype,
174 return = f return,
175 symbolScope = symbolScope,
176 target = target}
177
178fun isOk (T {kind, return, ...},
179 {isUnit}): bool =
180 (if Kind.maySwitchThreads kind
181 then Kind.mayGC kind andalso isUnit return
182 else true)
183 andalso (if Kind.ensuresBytesFree kind orelse Kind.maySwitchThreads kind
184 then Kind.mayGC kind
185 else true)
186 andalso (if Kind.mayGC kind
187 then (Kind.modifiesFrontier kind
188 andalso Kind.readsStackTop kind andalso Kind.writesStackTop kind)
189 else true)
190 andalso (not (Kind.writesStackTop kind) orelse Kind.readsStackTop kind)
191
192fun vanilla {args, name, prototype, return} =
193 T {args = args,
194 convention = Convention.Cdecl,
195 kind = Kind.Impure,
196 prototype = prototype,
197 return = return,
198 symbolScope = SymbolScope.Private,
199 target = Direct name}
200
201fun cPrototype (T {convention, prototype = (args, return), symbolScope, target,
202 ...}) =
203 let
204 val convention =
205 if convention <> Convention.Cdecl
206 then concat [" __attribute__ ((",
207 Convention.toString convention,
208 ")) "]
209 else " "
210 val symbolScope =
211 case symbolScope of
212 SymbolScope.External => "EXTERNAL "
213 | SymbolScope.Private => "PRIVATE "
214 | SymbolScope.Public => "PUBLIC "
215 val name =
216 case target of
217 Direct name => name
218 | Indirect => Error.bug "CFunction.cPrototype: Indirect"
219 val c = Counter.new 0
220 fun arg t =
221 concat [CType.toString t, " x", Int.toString (Counter.next c)]
222 val return =
223 case return of
224 NONE => "void"
225 | SOME t => CType.toString t
226 in
227 concat [symbolScope, return, convention, name,
228 " (",
229 concat (List.separate (Vector.toListMap (args, arg), ", ")),
230 ")"]
231 end
232
233fun cPointerType (T {convention, prototype = (args, return), ...}) =
234 let
235 val attributes =
236 if convention <> Convention.Cdecl
237 then concat [" __attribute__ ((",
238 Convention.toString convention,
239 ")) "]
240 else " "
241 fun arg t = CType.toString t
242 val return =
243 case return of
244 NONE => "void"
245 | SOME t => CType.toString t
246 in
247 concat
248 ["(", return, attributes,
249 "(*)(",
250 concat (List.separate (Vector.toListMap (args, arg), ", ")),
251 "))"]
252 end
253
254end