Skip to content

Commit 8d05159

Browse files
Harry Garroodbergmark
authored andcommitted
Desugar: adding FFI type signatures on toplevel
* Add a desugar step which copies the type signature for toplevel FFI declarations to an explicit one in the RHS expression. * Remove (now unnecessary) code from compileDecls and compileDecl Still todo: * Adding FFI type signatures in let/where bindings * Find out why StrictWrapper test is broken. Seems to be ignoring the last statement in the do block.
1 parent e25225a commit 8d05159

File tree

6 files changed

+92
-61
lines changed

6 files changed

+92
-61
lines changed

src/Fay/Compiler/Decl.hs

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import Fay.Compiler.GADT
1414
import Fay.Compiler.Misc
1515
import Fay.Compiler.Pattern
1616
import Fay.Compiler.State
17-
import Fay.Compiler.QName (unname)
1817
import Fay.Data.List.Extra
1918
import Fay.Exts (convertFieldDecl, fieldDeclNames)
2019
import Fay.Exts.NoAnnotation (unAnn)
@@ -28,37 +27,7 @@ import Language.Haskell.Exts.Annotated
2827

2928
-- | Compile Haskell declaration.
3029
compileDecls :: Bool -> [S.Decl] -> Compile [JsStmt]
31-
compileDecls toplevel' decls' = go toplevel' decls'
32-
where
33-
isTypeSig (TypeSig _ _ _) = True
34-
isTypeSig _ = False
35-
36-
typeSigs = filter isTypeSig decls'
37-
38-
getSigFor decl = case decl of
39-
(PatBind _ (PVar _ name) _ _ _) ->
40-
case filter (includesName name) typeSigs of
41-
[] -> Nothing
42-
[(TypeSig _ _ sig)] -> Just sig
43-
_ -> error "(todo) multiple type signatures"
44-
_ -> Nothing
45-
46-
-- Tests whether a type signature declares what the type of a given name is
47-
includesName name (TypeSig _ names _) =
48-
any (== (unname name)) $ map unname names
49-
includesName _ _ = False
50-
51-
go toplevel decls = case decls of
52-
[] -> return []
53-
(bind@PatBind{}:decls) -> appendM (compilePatBind toplevel (getSigFor bind) bind)
54-
(compileDecls toplevel decls)
55-
(decl:decls) -> appendM (compileDecl toplevel decl)
56-
(go toplevel decls)
57-
58-
appendM m n = do x <- m
59-
xs <- n
60-
return (x ++ xs)
61-
30+
compileDecls toplevel = fmap concat . sequence . map (compileDecl toplevel)
6231

6332
-- | Compile a declaration.
6433
compileDecl :: Bool -> S.Decl -> Compile [JsStmt]
@@ -104,11 +73,7 @@ compilePatBind toplevel sig patDecl = case patDecl of
10473
sig)) Nothing ->
10574
compileFFI True ident' formatstr sig
10675
PatBind srcloc (PVar _ ident) Nothing (UnGuardedRhs _ rhs) Nothing ->
107-
case ffiExp rhs of
108-
Just formatstr -> case sig of
109-
Just sig -> compileFFI False ident formatstr sig
110-
Nothing -> throwError $ FfiNeedsTypeSig patDecl
111-
_ -> compileUnguardedRhs toplevel srcloc ident rhs
76+
compileUnguardedRhs toplevel srcloc ident rhs
11277
-- TODO: Generalize to all patterns
11378
PatBind srcloc (PVar _ ident) Nothing (UnGuardedRhs _ rhs) (Just bdecls) ->
11479
compileUnguardedRhs toplevel srcloc ident (Let S.noI bdecls rhs)

src/Fay/Compiler/Desugar.hs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ module Fay.Compiler.Desugar
77
(desugar
88
) where
99

10-
import Fay.Compiler.Misc (hasLanguagePragma)
10+
import Fay.Compiler.QName (unname)
11+
import Fay.Compiler.Misc (hasLanguagePragma, ffiExp)
1112
import Fay.Exts.NoAnnotation (unAnn)
1213
import Fay.Types (CompileError (..))
1314

@@ -65,6 +66,7 @@ desugar emptyAnnotation md = runDesugar emptyAnnotation $
6566
>>= desugarDo
6667
>>= desugarTupleSection
6768
>>= desugarImplicitPrelude
69+
>>= desugarToplevelFFITypeSigs
6870

6971
-- | Desugaring
7072

@@ -164,7 +166,7 @@ desugarPatFieldPun = transformBi $ \pf -> case pf of
164166
PFieldPun l n -> PFieldPat l (UnQual l n) (PVar l n)
165167
_ -> pf
166168

167-
-- | Desugar l list comprehensions.
169+
-- | Desugar list comprehensions.
168170
desugarListComp :: (Data l, Typeable l) => Module l -> Desugar l (Module l)
169171
desugarListComp = transformBiM $ \ex -> case ex of
170172
ListComp l exp stmts -> desugarListComp' l exp stmts
@@ -254,6 +256,63 @@ desugarImplicitPrelude m =
254256
noInfo <- asks readerNoInfo
255257
return $ ImportDecl noInfo (ModuleName noInfo "Prelude") False False Nothing Nothing Nothing
256258

259+
-- | For each toplevel FFI pattern binding, search the module for the relevant
260+
-- type declaration; if found, add a type signature to the ffi expression.
261+
-- e.g.
262+
-- foo :: Int
263+
-- foo = ffi "3"
264+
-- becomes
265+
-- foo :: Int
266+
-- foo = (ffi "3" :: Int)
267+
desugarToplevelFFITypeSigs :: (Data l, Typeable l) => Module l -> Desugar l (Module l)
268+
desugarToplevelFFITypeSigs m = case m of
269+
Module a b c d decls -> do
270+
let toplevelTypeSigs = getToplevelTypeSigs decls
271+
decls' <- sequence $ go toplevelTypeSigs decls
272+
return $ Module a b c d decls'
273+
_ -> return m
274+
where
275+
getToplevelTypeSigs decls =
276+
[ (unname n, typ) | TypeSig _ names typ <- decls, n <- names ]
277+
278+
go toplevelTypeSigs decls =
279+
map (addTypeSig toplevelTypeSigs) decls
280+
281+
addTypeSig sigs decl = case decl of
282+
(PatBind loc pat typ rhs binds) ->
283+
case getUnguardedRhs rhs of
284+
Just (srcInfo, rhExp) ->
285+
if isFFI rhExp
286+
then do
287+
rhExp' <- addSigToExp sigs decl rhExp
288+
return $ PatBind loc pat typ (UnGuardedRhs srcInfo rhExp') binds
289+
else return decl
290+
_ -> return decl
291+
_ -> return decl
292+
293+
getUnguardedRhs rhs = case rhs of
294+
(UnGuardedRhs srcInfo exp) -> Just (srcInfo, exp)
295+
_ -> Nothing
296+
297+
isFFI = isJust . ffiExp
298+
299+
-- | Adds an explicit type signature to an expression (which is assumed to
300+
-- be the RHS of a declaration). This should only need to be called for FFI
301+
-- function declarations.
302+
-- Arguments:
303+
-- sigs: List of toplevel type signatures
304+
-- decl: The declaration, which should be a PatBind.
305+
-- rhExp: Expression comprising the RHS of the declaration
306+
addSigToExp sigs decl rhExp = case getTypeFor sigs decl of
307+
Just typ -> do
308+
noInfo <- asks readerNoInfo
309+
return $ ExpTypeSig noInfo rhExp typ
310+
Nothing -> return rhExp
311+
312+
getTypeFor sigs decl = case decl of
313+
(PatBind _ (PVar _ name) _ _ _) -> lookup (unname name) sigs
314+
_ -> Nothing
315+
257316
transformBi :: U.Biplate (from a) (to a) => (to a -> to a) -> from a -> from a
258317
transformBi = U.transformBi
259318

tests/CorrectTypeSigFFI.hs

Lines changed: 0 additions & 21 deletions
This file was deleted.

tests/CorrectTypeSigFFI.res

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/DesugarFFI.hs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module DesugarFFI where
2+
3+
import Prelude
4+
import FFI
5+
6+
-- top-level FFI call with multi type signature
7+
addOne, addTwo :: Int -> Int
8+
9+
addOne = ffi "%1 + 1"
10+
addTwo = ffi "%1 + 2"
11+
12+
-- FFI call in a let binding
13+
-- addThree :: Int -> Int
14+
-- addThree x =
15+
-- let go :: Int -> Int
16+
-- go = ffi "%1 + 3"
17+
-- in go x
18+
19+
-- FFI call in a where binding
20+
-- addFour :: Int -> Int
21+
-- addFour x = go x
22+
-- where
23+
-- go :: Int -> Int
24+
-- go = ffi "%1 + 3"
25+
26+
main = do
27+
let result = addOne . addTwo {-. addThree . addFour -} $ 0
28+
putStrLn $ show result

tests/DesugarFFI.res

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
10

0 commit comments

Comments
 (0)