1 implementation module GenC
3 import StdEnv, StdGeneric, StdMaybe
4 import Data.Map => qualified updateAt
5 import Data.Func, Data.Tuple
14 potInf :: Box Bool a | gPotInf{|*|} a
15 potInf = gPotInf{|*|} []
17 generic gPotInf a :: [String] -> Box Bool a
18 gPotInf{|Int|} _ = box False
19 gPotInf{|Bool|} _ = box False
20 gPotInf{|Char|} _ = box False
21 gPotInf{|Real|} _ = box False
22 gPotInf{|World|} _ = box False
23 gPotInf{|Dynamic|} _ = box False
24 gPotInf{|c|} _ = box False
25 gPotInf{|UNIT|} _ = box False
26 gPotInf{|CONS|} f s = reBox (f s)
27 gPotInf{|FIELD|} f s = reBox (f s)
28 gPotInf{|EITHER|} fl fr s = box (unBox (fl s) || unBox (fr s))
29 gPotInf{|PAIR|} fl fr s = box (unBox (fl s) || unBox (fr s))
30 gPotInf{|OBJECT of {gtd_name}|} f s
31 = if (isMember gtd_name s) (box True) (reBox (f [gtd_name:s]))
32 gPotInf{|RECORD of {grd_name}|} f s
33 = if (isMember grd_name s) (box True) (reBox (f [grd_name:s]))
38 | CTStruct [(String, [(String, Bool, String)])]
40 :: GTSState = {dict :: Map String CType}
41 instance zero GTSState where zero = {dict=newMap}
43 toStruct :: Box GTSState a | gToStruct{|*|} a
44 toStruct = snd $ gToStruct{|*|} zero
45 generic gToStruct a | gPotInf a :: GTSState -> (GTSResult, Box GTSState a)
47 = GTSType Bool String //ispointer and the name
49 | GTSEither [GTSResult]
53 putst k v st = {st & dict=put k v st.dict}
55 gToStruct{|Int|} st = (GTSType False "uint64_t", box st)
56 gToStruct{|Bool|} st = (GTSType False "bool", box st)
57 gToStruct{|Char|} st = (GTSType False "char", box st)
58 gToStruct{|Real|} st = (GTSType False "double", box st)
59 gToStruct{|UNIT|} st = (GTSUnit, box st)
60 gToStruct{|CONS|} f _ st = appSnd reBox $ f st
61 gToStruct{|FIELD|} f _ st = appSnd reBox $ f st
62 gToStruct{|EITHER|} fl _ fr _ st
66 (GTSEither l, GTSEither r) = GTSEither (l ++ r)
67 (a, GTSEither l) = GTSEither [a:l]
68 (l, r) = GTSEither [l, r]
70 gToStruct{|PAIR|} fl _ fr _ st
74 (GTSPair l, GTSPair r) = GTSPair (l ++ r)
75 (a, GTSPair l) = GTSPair [a:l]
76 (l, r) = GTSPair [l, r]
78 gToStruct{|OBJECT of {gtd_name,gtd_conses,gtd_num_conses}|} f i st
81 = case get gtd_name st.dict of
82 Just _ = (GTSType isPInf gtd_name, box st)
87 (GTSType pi n, Box st) = (GTSType pi gtd_name, box $ putst gtd_name (CTTypeDef n) st)
88 //If it is just an enumeration, Just the enum
89 | and [gcd.gcd_arity == 0\\gcd<-gtd_conses]
90 = (GTSType False gtd_name, box $ putst gtd_name (CTEnum [gcd.gcd_name\\gcd<-gtd_conses]) st)
91 //Constructors with data fields
92 # (n, Box st) = appFst mkty $ f $ putst gtd_name (CTTypeDef gtd_name) st
94 ( GTSType isPInf gtd_name
95 , box $ putst gtd_name (CTStruct (zip2 [gcd.gcd_name\\gcd<-gtd_conses] (map (toT o mkccons) n))) st
98 mkty (GTSEither l) = l
101 mkccons (GTSType pi t) = [GTSType pi t]
102 mkccons (GTSPair t) = t
105 toT cons = [(t, pi, "f"+++toString i)\\i<-[0..] & GTSType pi t<-cons]
106 gToStruct{|RECORD of {grd_name,grd_fields}|} f i st
107 # (Box isPInf) = i []
108 = case get grd_name st.dict of
109 Just n = (GTSType isPInf grd_name, box st)
111 # (n, Box st) = f $ putst grd_name (CTTypeDef grd_name) st
114 ( GTSType isPInf grd_name
115 , box $ putst grd_name (CTStruct [(grd_name, [(t, pi, gfd)\\GTSType pi t<-l & gfd<-grd_fields])]) st)
116 _ = (GTSError, box st)
119 * Given a GTSState, generate typedefinitions
121 toCType :: GTSState -> [String]
122 toCType {dict=m} = foldr proc [] $ scc $ map (appSnd refs) $ toList m
124 refs (CTTypeDef s) = [s]
126 refs (CTStruct cs) = map fst3 (flatten (map snd cs))
129 proc [x] c = ctypedef x (find x m) c
130 proc xs c = foldr (prototype o fst) (foldr (uncurry ctypedef) c ts) ts
132 ts = [(x, find x m)\\x<-xs]
133 prototype x c = ["struct ", x, ";\n":c]
135 ctypedef :: String CType [String] -> [String]
136 ctypedef name (CTTypeDef a) c = ["typedef ", a, " ", name, ";\n":c]
137 ctypedef name (CTEnum a) c = ["enum ", name, " {": enum a ["};\n":c]]
138 ctypedef name (CTStruct [(_, fs)]) c =
139 [ "struct ", name, " {\n"
140 : foldr (uncurry3 (field 1))
143 ctypedef name (CTStruct cs) c =
144 [ "struct ", name, " {\n"
149 : foldr (uncurry struct)
150 (ind 1 ["} data;\n};\n":c])
154 struct name [(ty, pi, _)] c = field 2 ty pi name c
155 struct name fs c = ind 2 ["struct {\n" :foldr (uncurry3 (field 3)) (ind 2 ["} ", name, ";\n":c]) fs]
158 = ind i $ typeName ty m [if pi " *" " ", name, ";\n":c]
162 enum [x:xs] c = [x, ",": enum xs c]
164 typeName ty m c = [case get ty m of
165 Just (CTStruct _) = "struct "
166 Just (CTEnum _) = "enum "
170 ind n c = [createArray n '\t':c]
172 uncurry3 f (x,y,z) = f x y z
175 * Given a GTSState, generate a parser
176 * @result Function signature
179 toCParser :: GTSState -> ([String], [String])
180 toCParser {dict=m} = (funsigs, foldr funbody [] (toList m))
182 funsigs = [concat $ funsig n [";\n"]\\(n, _)<-toList m]
183 pfname n c = ["parse_", n:c]
184 pfcall n c = pfname n ["(get, alloc, err);":c]
186 = typeName n m [" ": pfname n ["(\n"
187 : ind 1 ["uint8_t (*get)(void),\n"
188 : ind 1 ["void *(*alloc)(size_t),\n"
189 : ind 1 ["void (*err)(const char *errmsg, ...))"
191 funbody (n, ty) c = funsig n
193 :ind 1 $ typeName n m [" r;\n"
194 :funb ty $ ind 1 ["return r;\n}\n":c]]]
196 funb (CTTypeDef a) c = ind 1 ["r = ":pfcall a ["\n":c]]
197 funb (CTEnum a) c = ind 1 ["r = get()\n":c]
198 funb (CTStruct [(_, fs)]) c = foldr (sfield 1 "r") c fs
200 = ind 1 ["switch(r.cons = get()) {\n"
202 ( ind 1 ["default:\n"
204 : ind 1 ["}\n":c]]]) fs]
208 ind 1 ["case ", n, ":\n"
209 : foldr (sfield 2 ("r.data."+++ n))
210 (ind 2 ["break;\n":c]) fs]
212 sfield i r (ty, ptr, f) c
213 = (\c->if ptr (ind i [r, ".", f, " = alloc(sizeof(":typeName ty m ["));\n":c]]) c)
214 $ ind i [if ptr "*" "", r, ".", f, " = ":pfcall ty ["\n":c]]
217 * Given a GTSState, generate a printer
218 * @result Function signature
221 toCPrinter :: GTSState -> ([String], [String])
222 toCPrinter {dict=m} = (funsigs, foldr funbody [] (toList m))
224 funsigs = [concat $ funsig n [";\n"]\\(n, _)<-toList m]
225 pfname n c = ["print_", n:c]
226 pfcall r n c = pfname n ["(", r, ", put);":c]
228 ["void ":pfname n ["(\n"
229 : ind 1 $ typeName n m [" r,\n"
230 : ind 1 ["void (*put)(uint8_t))"
232 funbody (n, ty) c = funsig n ["\n{\n":funb ty ["}\n":c]]
234 funb (CTTypeDef a) c = ind 1 $ pfcall "r" a ["\n":c]
235 funb (CTEnum a) c = ind 1 ["put(r)\n":c]
236 funb (CTStruct [(_, fs)]) c = foldr (sfield 1 "r") c fs
237 funb (CTStruct fs) c =
238 ind 1 ["put(r.cons);\n"
239 : ind 1 ["switch(r.cons) {\n"
241 ( ind 1 ["default:\n"
243 : ind 1 ["}\n":c]]]) fs]]
247 = ind 1 ["case ", n, ":\n"
248 : foldr (sfield 2 ("r.data."+++ n))
249 (ind 2 ["break;\n":c]) fs]
251 sfield i r (ty, ptr, f) c
252 = ind i $ pfcall (concat [if ptr "*" "", r, ".", f]) ty ["\n":c]
254 toCValue :: a [Char] -> [Char] | gToCValue{|*|} a
255 toCValue a c = gToCValue{|*|} a c
257 gToCValue{|Char|} x c = [x:c]
258 gToCValue{|Int|} x c =
267 gToCValue{|Bool|} x c = [toChar (if x 1 0):c]
268 gToCValue{|UNIT|} x c = c
269 gToCValue{|EITHER|} l _ (LEFT x) c = l x c
270 gToCValue{|EITHER|} _ r (RIGHT x) c = r x c
271 gToCValue{|PAIR|} l r (PAIR x y) c = l x $ r y c
272 gToCValue{|CONS of {gcd_index}|} f (CONS x) c = [toChar gcd_index:f x c]
273 gToCValue{|FIELD|} f (FIELD x) c = f x c
274 gToCValue{|RECORD|} f (RECORD x) c = f x c
275 gToCValue{|OBJECT|} f (OBJECT x) c = f x c
277 fromCValue :: [Char] -> Either FromCValueError (a, [Char]) | gFromCValue{|*|} a
278 fromCValue i = gFromCValue{|*|} i
280 :: Parser a :== [Char] -> Either FromCValueError (a, [Char])
282 top = satisfy (\_->True) CVEInputExhausted
284 satisfy :: (Char -> Bool) FromCValueError -> Parser Char
285 satisfy f e = \c->case c of
287 | f c = Right (c, cs)
289 [] = Left CVEInputExhausted
291 yield :: a -> Parser a
292 yield a = \c->Right (a, c)
294 list :: [Parser a] -> Parser [a]
296 list [x:xs] = cons <<$>> x <<*>> list xs
300 (<<$>>) infixl 4 :: (a -> b) (Parser a) -> Parser b
301 (<<$>>) f a = fmap (\(a, b)->(f a, b)) <$> a
303 (<<*>>) infixl 4 :: (Parser (a -> b)) (Parser a) -> Parser b
304 (<<*>>) f a = either Left (\(fa, c)->(fa <<$>> a) c) o f
306 (<<|>>) infixr 4 :: (Parser a) (Parser a) -> Parser a
307 (<<|>>) l r = \c->either (\_->r c) Right $ l c
309 int b = sum <<$>> list [(\x->toInt x << (i*8)) <<$>> top \\i<-[b-1,b-2..0]]
310 gFromCValue{|Char|} = top
311 gFromCValue{|Int|} = fromInt <<$>> int 8
312 gFromCValue{|Bool|} = ((==) '\1') <<$>> top
313 gFromCValue{|UNIT|} = yield UNIT
314 gFromCValue{|EITHER|} l r = (LEFT <<$>> l) <<|>> (RIGHT <<$>> r)
315 gFromCValue{|PAIR|} l r = PAIR <<$>> l <<*>> r
316 gFromCValue{|CONS of {gcd_index}|} f
317 = (\x->CONS) <<$>> satisfy ((==)(toChar gcd_index)) CVEUnknownConstructor <<*>> f
318 gFromCValue{|FIELD|} f = (\x->FIELD x) <<$>> f
319 gFromCValue{|RECORD|} f = RECORD <<$>> f
320 gFromCValue{|OBJECT|} f = (\x->OBJECT x) <<$>> f
322 toCFiles :: (Box String a) -> ([String], [String]) | gToStruct{|*|} a
324 # (padefs, paimp) = toCParser gts
325 # (prdefs, primp) = toCPrinter gts
328 [["#ifndef ", guard, "\n"
329 , "#define ", guard, "\n"
330 , "#include <stdint.h>\n"
331 , "#include <stddef.h>\n"
332 , "#include <stdarg.h>\n"]
333 , toCType gts, padefs, prdefs
337 [["#include \"", fn, ".h\"\n"]
342 guard = {safe c\\c<-:fn +++ ".h"}
344 | not (isAlphanum c) = '_'
348 cast :: (Box x a) -> (Box GTSState a) | gToStruct{|*|} a