morloc-0.33.0: library/Morloc/Language.hs
{-|
Module : Language
Description : Handling for specific languages
Copyright : (c) Zebulun Arendsee, 2020
License : GPL-3
Maintainer : zbwrnz@gmail.com
Stability : experimental
The purpose of this module currently is to unify language naming conventions.
We need to streamline the process of adding new languages to Morloc. This
module should serve as the starting place for adding a new language.
-}
module Morloc.Language
( Lang(..)
, mapLang
, parseExtension
, makeExtension
, showLangName
, readLangName
, makeExecutableName
, makeSourceName
, standardizeLangName
, pairwiseCost
) where
import Morloc.Internal
import Data.Text (Text)
-- | Programming languages in the Morloc ecosystem. This is the type that
-- should be used to refer to a language (don't use raw strings). Some of these
-- are languages that can be sourced (Python, R and C). Perl is currently used
-- only in generating the nexus file.
data Lang
= Python3Lang
| RLang
| CLang
| CppLang
| PerlLang
deriving (Ord, Eq, Show)
-- | Map a function over each supported language
mapLang :: (Lang -> a) -> [a]
mapLang f =
[ f Python3Lang
, f RLang
, f CLang
, f CppLang
, f PerlLang
]
-- | very rough function overhead costs that can be used when no benchmark info is available
-- `Nothing` indicates that the language pair are not interoperable
pairwiseCost :: Lang -> Lang -> Maybe Int
-- functional overhead in each language
pairwiseCost CLang CLang = Just 1
pairwiseCost CppLang CppLang = Just 1
pairwiseCost PerlLang PerlLang = Just 10
pairwiseCost Python3Lang Python3Lang = Just 10
pairwiseCost RLang RLang = Just 100
-- pairs of languages for which foreign calls are optimized
pairwiseCost CppLang CLang = Just 1
-- cost of naive foreign function calls
pairwiseCost _ CLang = Just 100
pairwiseCost _ CppLang = Just 100
pairwiseCost _ Python3Lang = Just 10000
pairwiseCost _ PerlLang = Just 10000
pairwiseCost _ RLang = Just 1000000
-- | Try to determine the source language for a file from its extension
parseExtension :: Text -> Maybe Lang
parseExtension "loc" = Nothing
parseExtension "py" = Just Python3Lang
parseExtension "R" = Just RLang
parseExtension "c" = Just CLang
parseExtension "h" = Just CLang
parseExtension "cpp" = Just CppLang
parseExtension "hpp" = Just CppLang
parseExtension "pl" = Just PerlLang
parseExtension _ = Nothing
-- | Create an extension for a given language
makeExtension :: Lang -> Text
makeExtension Python3Lang = "py"
makeExtension RLang = "R"
makeExtension CLang = "c"
makeExtension CppLang = "cpp"
makeExtension PerlLang = "pl"
-- | Create the name of a given language. This is the internal standard name
-- for the language and the string language name used in the RDF.
showLangName :: Lang -> Text
showLangName Python3Lang = "python3"
showLangName RLang = "R"
showLangName CLang = "C"
showLangName CppLang = "Cpp"
showLangName PerlLang = "Perl"
-- | Read the name of a given language and try to translate it
readLangName :: Text -> Maybe Lang
readLangName "python" = Just Python3Lang
readLangName "python3" = Just Python3Lang
readLangName "py" = Just Python3Lang
readLangName "R" = Just RLang
readLangName "r" = Just RLang
readLangName "C" = Just CLang
readLangName "c" = Just CLang
readLangName "cpp" = Just CppLang
readLangName "Cpp" = Just CppLang
readLangName "C++" = Just CppLang
readLangName "c++" = Just CppLang
readLangName "Perl" = Just PerlLang
readLangName "perl" = Just PerlLang
readLangName _ = Nothing
-- | Generate a name for a pool top-level source file given a language.
makeSourceName ::
Lang
-> Text -- ^ basename
-> Text -- ^ source file basename
makeSourceName lang base = base <> "." <> makeExtension lang
-- | Generate a name for a pool executable file given a language. For
-- interpreted languages this will be the same as the output of the
-- @makeSourceName@ function.
makeExecutableName ::
Lang
-> Text -- ^ basename
-> Text -- ^ executable file basename
makeExecutableName CLang base = base <> "-c.out"
makeExecutableName CppLang base = base <> "-cpp.out"
makeExecutableName lang base = makeSourceName lang base -- For interpreted languages
-- TODO: Use this function at the parsing stage to standardize names
-- | Convert a given language name to the standard form of the name (e.g., "py"
-- to "python3")
standardizeLangName :: Text -> Maybe Text
standardizeLangName = fmap showLangName . readLangName