@@ -0,0 +1,892 @@
1+---------------------------------------------------------------------------------------------------
3+-- Module : Language.PureScript.CodeGen.Cpp
4+-- Copyright : (c) 2013-15 Phil Freeman, Andy Arvanitis, and other contributors
7+-- Maintainer : Andy Arvanitis <andy.arvanitis@gmail.com>
8+-- Stability : experimental
12+-- This module generates code in the simplified C++1x intermediate representation from
15+---------------------------------------------------------------------------------------------------
16+{-# LANGUAGE GADTs #-}
17+{-# LANGUAGE ViewPatterns #-}
18+{-# LANGUAGE FlexibleContexts #-}
19+{-# LANGUAGE ScopedTypeVariables #-}
20+{-# LANGUAGE PatternGuards #-}
22+module Language.PureScript.CodeGen.Cpp
29+import Data.Char (isLetter)
31+import Data.Function (on)
32+import Data.Maybe (catMaybes, fromJust)
33+import qualified Data.Map as M
35+import Control.Monad (forM, replicateM)
36+import Control.Monad.Reader (MonadReader, ask)
37+import Control.Monad.Supply.Class
38+import Language.PureScript.AST.SourcePos
39+import Language.PureScript.CodeGen.Cpp.AST as AST
40+import Language.PureScript.CodeGen.Cpp.Common as Common
41+import Language.PureScript.CodeGen.Cpp.File
42+import Language.PureScript.CodeGen.Cpp.Optimizer
43+import Language.PureScript.CodeGen.Cpp.Optimizer.TCO
44+import Language.PureScript.CodeGen.Cpp.Types
45+import Language.PureScript.Comments
46+import Language.PureScript.CoreFn
47+import Language.PureScript.Names
48+import Language.PureScript.Options
49+import Language.PureScript.Sugar.TypeClasses (superClassDictionaryNames)
50+import Language.PureScript.Traversals (sndM)
52+import qualified Language.PureScript.Constants as C
53+import qualified Language.PureScript.Environment as E
54+import qualified Language.PureScript.Pretty.Cpp as P
55+import qualified Language.PureScript.Types as T
58+-- Generate code in the simplified C++1x intermediate representation for all declarations in a
61+---------------------------------------------------------------------------------------------------
62+moduleToCpp :: forall m. (Applicative m, Monad m, MonadReader Options m, MonadSupply m)
63+ => E.Environment -> Module Ann -> m [Cpp]
64+---------------------------------------------------------------------------------------------------
65+moduleToCpp env (Module _ mn imps _ foreigns decls) = do
67+ traverse (pure . runModuleName) .
68+ delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $
70+ let cppImports' = "PureScript" : cppImports
71+ cppDecls <- concat <$> mapM (bindToCpp [CppTopLevel]) decls
72+ cppDecls' <- traverse optimize cppDecls
73+ foreignWrappers <- curriedForeigns
74+ let optimized = cppDecls' ++ foreignWrappers
78+ ((\i -> CppInclude i i) <$> cppImports') ++
79+ (if not (null foreigns)
80+ then [CppInclude [] (runModuleName mn ++ "_ffi")]
83+ [ CppNamespace (runModuleName mn) $
84+ (CppUseNamespace <$> cppImports') ++
87+ toHeader optimized ++
88+ toHeaderFns optimized
92+ let bodyCpps = toBodyDecl optimized ++ toBody optimized
94+ CppInclude (runModuleName mn) (runModuleName mn) :
98+ else [ CppNamespace (runModuleName mn) $
99+ (CppUseNamespace <$> cppImports') ++
100+ P.linebreak ++ bodyCpps ]) ++
103+ then [nativeMain] ++ P.linebreak
105+ return $ moduleHeader ++ CppEndOfHeader : moduleBody
108+ -- Generate code in the simplified C++1x intermediate representation for a declaration
110+ -------------------------------------------------------------------------------------------------
111+ bindToCpp :: [CppValueQual] -> Bind Ann -> m [Cpp]
112+ -------------------------------------------------------------------------------------------------
113+ bindToCpp qs (NonRec ann ident val) = return <$> declToCpp qs (ann, ident) val
114+ bindToCpp qs (Rec vals) = forM vals (uncurry $ declToCpp (CppRecursive:qs))
117+ -- Desugar a declaration into a variable introduction or named function
119+ -------------------------------------------------------------------------------------------------
120+ declToCpp :: [CppValueQual] -> (Ann, Ident) -> Expr Ann -> m Cpp
121+ -------------------------------------------------------------------------------------------------
122+ declToCpp _ (_, ident) e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =
123+ let className = identToCpp ident
124+ (supers, members) = span (C.__superclass_ `isPrefixOf`) (identToCpp <$> (fst $ unAbs e []))
125+ in return $ CppStruct className [CppEnum Nothing Nothing (sort supers ++ members)]
127+ declToCpp _ (_, Op _) (Var (_, _, Nothing, _) _) =
128+ return CppNoOp -- skip operator aliases
130+ declToCpp vqs (_, ident) (Abs (_, com, ty, _) arg body) = do
131+ fn <- if argcnt > 1 && CppTopLevel `elem` vqs
133+ argNames <- replicateM (argcnt - length args' - 1) freshName
134+ let args'' = zip argNames (repeat aty)
135+ block <- asReturnBlock <$> valueToCpp
143+ (Var nullAnn . Qualified Nothing . Ident $ head argNames)))
144+ return $ CppNamespace ""
147+ (arg' : args' ++ args'')
149+ (vqs ++ if isAccessor (snd abs') then [CppInline] else [])
150+ (convertNestedLambdas $ convertDictIndexers block)
158+ (fst <$> args' ++ args'')
159+ (CppApp (CppVar name)
160+ (CppVar . fst <$> (arg' : args' ++ args''))))
163+ block <- valueToCpp body
164+ return $ CppFunction
168+ (vqs ++ if isIndexer block then [CppInline] else [])
169+ (convertNestedLambdas . asReturnBlock $ convertDictIndexers block)
170+ return (CppComment com fn)
172+ ty' | Just t <- ty = Just t
173+ | Just (t, _, _) <- M.lookup (mn, ident) (E.names env) = Just t
174+ | otherwise = Nothing
175+ argcnt = maybe 0 countArgs ty'
176+ name = identToCpp ident
177+ aty = Just $ CppAny [CppConst, CppRef]
178+ rty = Just $ CppAny []
179+ arg' = (identToCpp arg, aty)
180+ args' = (\i -> (identToCpp i, aty)) <$> fst abs'
181+ abs' = unAbs body []
182+ isAccessor :: Expr Ann -> Bool
183+ isAccessor Accessor{} = True
184+ isAccessor _ = False
185+ isIndexer :: Cpp -> Bool
186+ isIndexer (CppIndexer (CppStringLiteral _) (CppVar _)) = True
188+ classes = qualifiedToCpp (Ident . runProperName) . fst <$>
189+ maybe [] extractConstraints ty'
190+ dictClasses = zip (CppVar . fst <$> arg' : args') classes
191+ convertDictIndexers = everywhereOnCpp (dictIndexerToEnum dictClasses)
193+ declToCpp _ (_, ident) (Constructor _ _ (ProperName _) []) =
201+ CppDataLiteral [CppAccessor (CppVar $ identToCpp ident) (CppVar "data")])
203+ declToCpp _ (_, ident) (Constructor _ _ (ProperName _) fields) =
204+ return . CppNamespace "" $
212+ CppAccessor (CppVar name) (CppVar "data") : (CppVar <$> fields'))
214+ if length fields > 1
221+ (CppBlock (fieldLambdas fs))
226+ name = identToCpp ident
227+ fields' = identToCpp <$> fields
228+ (f, fs) | (f' : fs') <- fields' = ([f'], fs')
229+ | otherwise = ([], [])
230+ farg = \x -> (x, Just $ CppAny [CppConst, CppRef])
232+ | (f' : fs') <- flds = [ CppReturn . maybeRemCaps $
237+ (CppBlock $ fieldLambdas fs') ]
238+ | otherwise = [CppReturn $ CppApp (CppVar name) (CppVar <$> fields')]
240+ declToCpp qs (_, ident) e
241+ | Just ty <- exprType e,
242+ CppTopLevel `elem` qs,
243+ argcnt <- countArgs ty,
245+ argNames <- replicateM argcnt freshName
246+ block <- valueToCpp $
249+ (App nullAnn e (Var nullAnn . Qualified Nothing . Ident $ head argNames))
250+ let fn' = CppFunction
252+ [(head argNames, Just $ CppAny [CppConst, CppRef])]
258+ (CppApp (CppVar name)
259+ (CppVar <$> argNames)))
260+ return $ CppNamespace "" $
263+ (zip argNames $ repeat aty)
266+ (asReturnBlock block)
271+ name = identToCpp ident
272+ aty = Just $ CppAny [CppConst, CppRef]
273+ rty = Just $ CppAny []
275+ declToCpp _ (_, ident) val = do
276+ val' <- valueToCpp val
278+ CppVariableIntroduction
279+ (identToCpp ident, Just $ CppAny [CppConst])
283+ -------------------------------------------------------------------------------------------------
284+ exprType :: Expr Ann -> Maybe T.Type
285+ -------------------------------------------------------------------------------------------------
286+ exprType (Var (_, _, Just ty, _) _) = Just ty
287+ exprType (App (_, _, Just ty, _) _ _) = Just ty
288+ exprType (Case (_, _, Just ty, _) _ _) = Just ty
289+ exprType (Let (_, _, Just ty, _) _ _) = Just ty
290+ exprType _ = Nothing
292+ -------------------------------------------------------------------------------------------------
293+ fnToLambda :: Cpp -> Cpp
294+ -------------------------------------------------------------------------------------------------
295+ fnToLambda (CppFunction name args _ qs body) =
296+ CppVariableIntroduction
297+ (name, Just $ CppAny [CppConst])
298+ (filter (==CppStatic) qs)
299+ (Just $ CppLambda cs args (Just $ CppAny []) body)
301+ cs | (not . null) (qs `intersect` [CppInline, CppStatic]) = []
302+ | otherwise = [CppCaptureAll]
303+ fnToLambda (CppComment com cpp) = CppComment com (fnToLambda cpp)
304+ fnToLambda _ = error "Not a function!"
306+ -------------------------------------------------------------------------------------------------
307+ convertNestedLambdas :: Cpp -> Cpp
308+ -------------------------------------------------------------------------------------------------
309+ convertNestedLambdas = everywhereOnCpp go
312+ go f@(CppFunction {}) = maybeRemCaps $ fnToLambda f
313+ go (CppLambda _ args rtyp body) = maybeRemCaps $ CppLambda [CppCaptureAll] args rtyp body
316+ -------------------------------------------------------------------------------------------------
317+ convertRecursiveFns :: [Cpp] -> Cpp -> [Cpp]
318+ -------------------------------------------------------------------------------------------------
319+ convertRecursiveFns cpps otherCpp
320+ | not $ null fns = dict : (accessor topdict <$> filteredFns allCpps) ++ cpps'
322+ cpps' = everywhereOnCpp removeRec <$> cpps
323+ allCpps = CppBlock $ otherCpp : cpps'
325+ fns :: [(String, Cpp)]
326+ fns = toelem <$> concatMap (everythingOnCpp (++) recursive) cpps
328+ filteredFns :: Cpp -> [(String, Cpp)]
329+ filteredFns cpp = filter (\(f,_) -> everythingOnCpp (||) (== CppVar f) cpp) fns
331+ recursive :: Cpp -> [Cpp]
332+ recursive cpp'@(CppFunction _ _ _ qs _) | CppRecursive `elem` qs = [cpp']
335+ removeRec :: Cpp -> Cpp
336+ removeRec(CppFunction _ _ _ qs _) | CppRecursive `elem` qs = CppNoOp
337+ removeRec cpp' = cpp'
340+ dict = CppVariableIntroduction
341+ (topdict, Just $ CppAny [CppConst])
343+ (Just $ CppDataLiteral ((\(f,cpp) -> CppComment [LineComment f] cpp) <$> fns))
345+ accessor :: String -> (String, Cpp) -> Cpp
346+ accessor dictname (name, _) =
347+ CppVariableIntroduction
348+ (name, Just $ CppAny [CppConst])
352+ dict' = CppVar dictname
353+ dict'' = CppCast dataType dict'
356+ (CppNumericLiteral .
359+ fromJust $ findIndex ((== name) . fst) fns)
363+ toelem :: Cpp -> (String, Cpp)
364+ toelem (CppFunction name args rtyp _ body'@(CppBlock body)) =
365+ (name, withdict . maybeRemCaps $ CppLambda
369+ (CppBlock $ (accessor localdict <$> filteredFns body') ++ body))
370+ toelem _ = error "not a function"
372+ withdict :: Cpp -> Cpp
373+ withdict cpp' = maybeRemCaps $ CppLambda
375+ [(localdict, Just $ CppAny [CppConst, CppRef])]
377+ (asReturnBlock cpp')
379+ topdict = "_$dict$_"
381+ localdict = "$dict$"
383+ convertRecursiveFns cpps _ = cpps
386+ -- Generate code in the simplified C++1x intermediate representation for a value or expression.
388+ -------------------------------------------------------------------------------------------------
389+ valueToCpp :: Expr Ann -> m Cpp
390+ -------------------------------------------------------------------------------------------------
391+ valueToCpp (Var (_, _, _, Just (IsConstructor _ [])) ident) =
392+ return $ CppApp (varToCpp ident) []
394+ valueToCpp (Var (_, _, _, Just (IsConstructor _ [_])) ident) =
395+ return $ varToCpp ident
397+ valueToCpp (Var (_, _, _, Just (IsConstructor _ _)) ident) =
398+ return . curriedName' $ varToCpp ident
400+ valueToCpp (Var (_, _, Just ty, _) ident@(Qualified (Just _) _))
401+ | countArgs ty > 1 =
402+ return . curriedName' $ varToCpp ident
404+ valueToCpp (Var _ ident) =
405+ return $ varToCpp ident
407+ valueToCpp (Literal _ (NumericLiteral n)) =
408+ return (CppNumericLiteral n)
410+ valueToCpp (Literal _ (StringLiteral s)) =
411+ return (CppStringLiteral s)
413+ valueToCpp (Literal _ (CharLiteral c)) =
414+ return (CppCharLiteral c)
416+ valueToCpp (Literal _ (BooleanLiteral b)) =
417+ return (CppBooleanLiteral b)
419+ valueToCpp (Literal _ (ArrayLiteral xs)) =
420+ CppArrayLiteral <$> mapM valueToCpp xs
422+ valueToCpp (Literal _ (ObjectLiteral ps)) =
423+ CppObjectLiteral <$> sortBy (compare `on` fst) <$> mapM (sndM valueToCpp) ps
425+ valueToCpp (Accessor _ prop val) =
426+ CppIndexer <$> pure (CppStringLiteral prop) <*> valueToCpp val
428+ -- TODO: use a more efficient way of copying/updating the map?
429+ valueToCpp (ObjectUpdate (_, _, Just ty, _) obj ps) = do
430+ obj' <- valueToCpp obj
431+ updatedFields <- mapM (sndM valueToCpp) ps
432+ let origKeys = (allKeys ty) \\ (fst <$> updatedFields)
433+ origFields = (\key -> (key, CppIndexer (CppStringLiteral key) obj')) <$> origKeys
434+ return $ CppObjectLiteral . sortBy (compare `on` fst) $ origFields ++ updatedFields
436+ allKeys :: T.Type -> [String]
437+ allKeys (T.TypeApp (T.TypeConstructor _) r@(T.RCons {})) = fst <$> (fst $ T.rowToList r)
438+ allKeys (T.ForAll _ t _) = allKeys t
439+ allKeys _ = error $ show "Not a recognized row type"
441+ valueToCpp (ObjectUpdate _ _ _) = error $ "Bad Type in object update!"
443+ valueToCpp (Abs (_, _, ty, _) arg body) = do
444+ cpp <- valueToCpp body
445+ let cpp' = convertNestedLambdas cpp
449+ [(identToCpp arg, Just $ CppAny [CppConst, CppRef])]
451+ (asReturnBlock $ convertDictIndexers cpp')
453+ arg' = identToCpp arg
454+ args' = identToCpp <$> (fst $ unAbs body [])
455+ classes = qualifiedToCpp (Ident . runProperName) . fst <$>
456+ maybe [] extractConstraints ty
457+ dictClasses = zip (CppVar <$> arg' : args') classes
458+ convertDictIndexers = everywhereOnCpp (dictIndexerToEnum dictClasses)
459+ valueToCpp e@App{} = do
460+ let (f, args) = unApp e []
461+ args' <- mapM valueToCpp args
463+ Var (_, _, _, Just IsNewtype) _ -> return (head args')
464+ Var (_, _, _, Just (IsConstructor _ fields)) ident
465+ | length args == length fields ->
466+ return $ CppApp (uncurried' $ qualifiedToCpp id ident) args'
467+ Var (_, _, _, Just IsTypeClassConstructor) (Qualified mn' (Ident classname)) ->
468+ let Just (_, constraints, fns) = findClass (Qualified mn' (ProperName classname)) in
469+ return . CppObjectLiteral $
471+ ((sort $ superClassDictionaryNames constraints) ++ (fst <$> fns))
473+ Var ann (Qualified (Just mn') ident)
474+ | argcnt <- maybe 0 countArgs ty,
477+ let (uncurriedArgs, curriedArgs) =
478+ if length args' >= argcnt
479+ then splitAt argcnt args'
482+ if null uncurriedArgs
483+ then curriedName' f'
484+ else CppApp (uncurried' f') uncurriedArgs
485+ return $ foldl (\fn a -> CppApp fn [a]) fn' curriedArgs
487+ ty | (_, _, Just t, _) <- ann = Just t
488+ | Just (t, _, _) <- M.lookup (mn', ident) (E.names env) = Just t
489+ | otherwise = Nothing
491+ flip (foldl (\fn a -> CppApp fn [a])) args' <$> valueToCpp f
493+ valueToCpp (Case (maybeSpan, _, ty, _) values binders) = do
494+ vals <- mapM valueToCpp values
495+ bindersToCpp maybeSpan ty binders vals
497+ valueToCpp (Let _ ds val) = do
498+ ds' <- concat <$> mapM (bindToCpp []) ds
499+ ret <- valueToCpp val
501+ let ds'' = tco opts <$> ds'
502+ let rs = if hasRecursion ds''
503+ then convertRecursiveFns ds'' ret
505+ let cpps = convertNestedLambdas <$> rs
507+ (CppLambda [] [] Nothing (CppBlock (cpps ++ [CppReturn ret])))
510+ hasRecursion :: [Cpp] -> Bool
511+ hasRecursion cpps' = any (everythingOnCpp (||) hasRecursiveRef) cpps'
514+ fnames = concatMap (everythingOnCpp (++) fname) cpps'
516+ fname :: Cpp -> [String]
517+ fname (CppFunction name _ _ _ _) = [name]
520+ hasRecursiveRef :: Cpp -> Bool
521+ hasRecursiveRef (CppFunction _ _ _ _ body) = everythingOnCpp (||) ref body
522+ hasRecursiveRef _ = False
525+ ref (CppVar name) | name `elem` fnames = True
528+ valueToCpp Constructor{} = return CppNoOp
531+ -- Generate code in the simplified C++1x intermediate representation for a reference to a
534+ -------------------------------------------------------------------------------------------------
535+ varToCpp :: Qualified Ident -> Cpp
536+ -------------------------------------------------------------------------------------------------
537+ varToCpp (Qualified Nothing ident) = CppVar (identToCpp ident)
538+ varToCpp qual = qualifiedToCpp id qual
541+ -- Generate code in the simplified C++1x intermediate representation for pattern match binders
544+ -------------------------------------------------------------------------------------------------
545+ bindersToCpp :: Maybe SourceSpan -> Maybe T.Type -> [CaseAlternative Ann] -> [Cpp] -> m Cpp
546+ -------------------------------------------------------------------------------------------------
547+ bindersToCpp maybeSpan _ binders vals = do
548+ valNames <- replicateM (length vals) freshName
549+ let assignments = zipWith mkVarDecl valNames (map Just vals)
550+ cpps <- forM binders $ \(CaseAlternative bs result) -> do
551+ ret <- guardsToCpp result
559+ (CppBlock (assignments ++ concat cpps ++ [failedPatternError valNames])))
562+ mkVarDecl :: String -> Maybe Cpp -> Cpp
563+ mkVarDecl name = CppVariableIntroduction (name, Nothing) []
564+ go :: [String] -> [Cpp] -> [Binder Ann] -> m [Cpp]
565+ go _ done [] = return done
566+ go (v:vs) done' (b:bs) = do
567+ done'' <- go vs done' bs
568+ binderToCpp v done'' b
569+ go _ _ _ = error "Invalid arguments to bindersToCpp"
571+ failedPatternError :: [String] -> Cpp
572+ failedPatternError _ =
573+ CppThrow $ CppApp (CppVar "runtime_error") [CppStringLiteral errorMessage]
575+ errorMessage :: String
576+ errorMessage = "Failed pattern match" ++
577+ maybe "" (((" at " ++ runModuleName mn ++ " ") ++) . displayStartEndPos) maybeSpan ++
580+ guardsToCpp :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [Cpp]
581+ guardsToCpp (Left gs) = forM gs $ \(cond, val) -> do
582+ cond' <- valueToCpp cond
583+ done <- valueToCpp val
584+ return $ CppIfElse cond' (asReturnBlock done) Nothing
585+ guardsToCpp (Right v) = return . CppReturn <$> valueToCpp v
588+ -- Generate code in the simplified C++1x intermediate representation for a pattern match
591+ -------------------------------------------------------------------------------------------------
592+ binderToCpp :: String -> [Cpp] -> Binder Ann -> m [Cpp]
593+ -------------------------------------------------------------------------------------------------
594+ binderToCpp _ done (NullBinder{}) = return done
596+ binderToCpp varName done (LiteralBinder _ l) =
597+ literalToBinderCpp varName done l
599+ binderToCpp varName done (VarBinder _ ident) =
601+ CppVariableIntroduction
602+ (identToCpp ident, Just $ CppAny [CppConst])
604+ (Just $ CppVar varName)
607+ binderToCpp varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =
608+ binderToCpp varName done b
610+ binderToCpp varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorType fields))
612+ (Qualified mn' (ProperName ctor))
614+ cpps <- go (zip fields bs) done
624+ (CppCast dataType $ CppVar varName))
629+ go :: [(Ident, Binder Ann)] -> [Cpp] -> m [Cpp]
630+ go [] done' = return done'
631+ go ((field, binder) : remain) done' = do
633+ done'' <- go remain done'
634+ cpps <- binderToCpp argVar done'' binder
636+ CppVariableIntroduction
640+ (fieldToIndex field)
641+ (CppCast dataType $ CppVar varName))
643+ fieldToIndex :: Ident -> Cpp
644+ fieldToIndex = CppNumericLiteral . Left . (+1) . read . dropWhile isLetter . runIdent
646+ ctor' = CppAccessor (CppVar . identToCpp $ Ident ctor) (CppVar "data")
648+ ctorCpp | Just mn'' <- mn', mn'' /= mn = CppAccessor ctor' (CppVar $ moduleNameToCpp mn'')
651+ binderToCpp _ _ b@(ConstructorBinder{}) =
652+ error $ "Invalid ConstructorBinder in binderToCpp: " ++ show b
654+ binderToCpp varName done (NamedBinder _ ident binder) = do
655+ cpp <- binderToCpp varName done binder
657+ CppVariableIntroduction
658+ (identToCpp ident, Just $ CppAny [CppConst])
660+ (Just $ CppVar varName)
663+ -------------------------------------------------------------------------------------------------
664+ literalToBinderCpp :: String -> [Cpp] -> Literal (Binder Ann) -> m [Cpp]
665+ -------------------------------------------------------------------------------------------------
666+ literalToBinderCpp varName done (NumericLiteral num) =
668+ (CppBinary Equal (CppVar varName) (CppNumericLiteral num))
672+ literalToBinderCpp varName done (CharLiteral c) =
674+ (CppBinary Equal (CppVar varName) (CppCharLiteral c))
678+ literalToBinderCpp varName done (StringLiteral str) =
680+ (CppBinary Equal (CppVar varName) (CppStringLiteral str))
684+ literalToBinderCpp varName done (BooleanLiteral True) =
690+ literalToBinderCpp varName done (BooleanLiteral False) =
698+ literalToBinderCpp varName done (ObjectLiteral bs) = go done bs
700+ go :: [Cpp] -> [(String, Binder Ann)] -> m [Cpp]
701+ go done' [] = return done'
702+ go done' ((prop, binder):bs') = do
703+ propVar <- freshName
704+ done'' <- go done' bs'
705+ cpp <- binderToCpp propVar done'' binder
707+ CppVariableIntroduction
711+ (CppStringLiteral prop)
715+ literalToBinderCpp varName done (ArrayLiteral bs) = do
721+ (CppCast arrayType $ CppVar varName)
722+ (CppApp (CppVar "empty") [])
723+ n -> let var = CppCast arrayType $ CppVar varName
726+ (CppBinary Dot var (CppApp (CppVar "size") []))
727+ (CppNumericLiteral (Left (fromIntegral n)))
728+ return [ CppIfElse cond (CppBlock cpp) Nothing ]
730+ go :: [Cpp] -> Integer -> [Binder Ann] -> m [Cpp]
731+ go done' _ [] = return done'
732+ go done' index (binder:bs') = do
734+ done'' <- go done' (index + 1) bs'
735+ cpp <- binderToCpp elVar done'' binder
737+ CppVariableIntroduction
741+ (CppNumericLiteral (Left index))
745+ -------------------------------------------------------------------------------------------------
746+ unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])
747+ -------------------------------------------------------------------------------------------------
748+ unApp (App _ val arg) args = unApp val (arg : args)
749+ unApp other args = (other, args)
751+ -------------------------------------------------------------------------------------------------
752+ unAbs :: Expr Ann -> [Ident] -> ([Ident], Expr Ann)
753+ -------------------------------------------------------------------------------------------------
754+ unAbs (Abs _ arg val) args = unAbs val (args ++ [arg])
755+ unAbs other args = (args, other)
757+ -------------------------------------------------------------------------------------------------
758+ qualifiedToCpp :: (a -> Ident) -> Qualified a -> Cpp
759+ -------------------------------------------------------------------------------------------------
760+ qualifiedToCpp f (Qualified (Just (ModuleName [ProperName mn'])) a)
761+ | mn' == C.prim = CppVar . runIdent $ f a
762+ qualifiedToCpp f (Qualified (Just mn') a)
763+ | mn /= mn' = CppAccessor (CppVar . identToCpp $ f a) (CppVar (moduleNameToCpp mn'))
764+ qualifiedToCpp f (Qualified _ a) = CppVar $ identToCpp (f a)
767+ -- Find a class in scope by name, retrieving its list of constraints, function names and types.
769+ -------------------------------------------------------------------------------------------------
770+ findClass :: Qualified (ProperName 'ClassName) -> Maybe ([String], [T.Constraint], [(String, T.Type)])
771+ -------------------------------------------------------------------------------------------------
773+ | Just (params, fns, constraints) <- M.lookup name (E.typeClasses env),
774+ fns' <- (\(i,t) -> (runIdent i, t)) <$> fns
775+ = Just (fst <$> params, constraints, (sortBy (compare `on` normalizedName . fst) fns'))
776+ findClass _ = Nothing
778+ -------------------------------------------------------------------------------------------------
780+ -------------------------------------------------------------------------------------------------
781+ dataCtors = [CppNamespace "data"
782+ [CppEnum Nothing (Just intType) . ("_" :) .
783+ catMaybes . map modCtor . M.keys $ E.dataConstructors env]]
785+ modCtor :: Qualified (ProperName a) -> Maybe String
786+ modCtor (Qualified (Just mn') (ProperName name)) | mn' == mn = Just name
789+ -------------------------------------------------------------------------------------------------
790+ curriedForeigns :: m [Cpp]
791+ -------------------------------------------------------------------------------------------------
792+ curriedForeigns = concat <$> mapM go allForeigns
795+ | argcnt <- countArgs ty,
797+ let name = identToCpp ident
798+ argNames <- replicateM argcnt freshName
802+ [(head argNames, Just $ CppAny [CppConst, CppRef])]
808+ (CppApp (CppVar name)
809+ (CppVar <$> argNames)))
813+ allForeigns :: [(Ident, T.Type)]
814+ allForeigns = map (\((_, ident), (ty, _, _)) -> (ident, ty)) .
815+ filter (\((mn', _), (_, kind, _)) -> mn' == mn && kind == E.External) .
816+ M.toList $ E.names env
818+---------------------------------------------------------------------------------------------------
819+asReturnBlock :: Cpp -> Cpp
820+---------------------------------------------------------------------------------------------------
821+asReturnBlock cpp = CppBlock [CppReturn cpp]
823+---------------------------------------------------------------------------------------------------
824+curriedLambda :: [String] -> Cpp -> Cpp
825+---------------------------------------------------------------------------------------------------
826+curriedLambda args ret = foldr (\arg ret' -> CppLambda
828+ [(arg, Just $ CppAny [CppConst, CppRef])]
830+ (asReturnBlock ret')
833+---------------------------------------------------------------------------------------------------
834+curriedApp :: [String] -> Expr Ann -> Expr Ann
835+---------------------------------------------------------------------------------------------------
836+curriedApp args vals = foldl (\val arg -> App
839+ (Var nullAnn . Qualified Nothing $ Ident arg))
842+---------------------------------------------------------------------------------------------------
843+countArgs :: T.Type -> Int
844+---------------------------------------------------------------------------------------------------
847+ go argcnt (T.ForAll _ t _) = go argcnt t
848+ go argcnt (T.TypeApp (T.TypeApp fn _) t) | fn == E.tyFunction = go (argcnt + 1) t
849+ go argcnt (T.ConstrainedType ts t) = go (argcnt + length ts) t
850+ go argcnt _ = argcnt
852+---------------------------------------------------------------------------------------------------
853+extractConstraints :: T.Type -> [T.Constraint]
854+---------------------------------------------------------------------------------------------------
855+extractConstraints = go []
857+ go cs (T.ForAll _ t _) = go cs t
858+ go cs (T.TypeApp (T.TypeApp fn _) t) | fn == E.tyFunction = go cs t
859+ go cs (T.ConstrainedType ts t) = go (cs ++ ts) t
862+---------------------------------------------------------------------------------------------------
863+dictIndexerToEnum :: [(Cpp,Cpp)] -> Cpp -> Cpp
864+---------------------------------------------------------------------------------------------------
865+dictIndexerToEnum repls (CppIndexer (CppStringLiteral prop) dict)
866+ | Just cls <- lookup dict repls =
869+ (CppAccessor (CppVar . identToCpp $ Ident prop) cls)
870+ (CppCast mapType dict))
872+dictIndexerToEnum _ cpp = cpp
874+---------------------------------------------------------------------------------------------------
875+curriedName :: String -> String
876+---------------------------------------------------------------------------------------------------
877+curriedName name@('$' : _) = name
878+curriedName name = '$' : name
880+---------------------------------------------------------------------------------------------------
881+uncurried' :: Cpp -> Cpp
882+---------------------------------------------------------------------------------------------------
883+uncurried' (CppVar ('$':name)) = CppVar name
884+uncurried' (CppAccessor a b) = CppAccessor (uncurried' a) b
887+---------------------------------------------------------------------------------------------------
888+curriedName' :: Cpp -> Cpp
889+---------------------------------------------------------------------------------------------------
890+curriedName' (CppVar name) = CppVar (curriedName name)
891+curriedName' (CppAccessor a b) = CppAccessor (curriedName' a) b
892+curriedName' cpp = cpp