{-# LANGUAGE Haskell2010 #-} {-# OPTIONS -Wall #-} -- | -- Module : Foreign.Java.Utils -- Copyright : (c) Julian Fleischer 2013 -- License : MIT (See LICENSE file in cabal package) -- -- Maintainer : julian.fleischer@fu-berlin.de -- Stability : provisional -- Portability : portable (Haskell2010) -- -- Utilities for dealing with Class, Package, and Module names in -- the Java and Haskell languages. module Foreign.Java.Utils where import Data.Strings javaKeywords, haskellKeywords :: [String] javaKeywords = ["abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private", "protected", "public", "return", "short", "static", "staticfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", -- strictly speaking these three are /reserved words/... "null", "true", "false"] haskellKeywords = ["as", "case", "of", "class", "data", "default", "deriving", "do", "foreign", "hiding", "if", "then", "else", "import", "infixl", "infixr", "instance", "let", "in", "module", "newtype", "qualified", "type", "where", -- either extension words or other reserved words "forall", -- several extensions "mdo", -- ... -fglasgow-exts ... (deprecated?) "rec", -- XDoRec "proc", -- arrow notation "family"] -- type families, to be sure makeName :: Maybe String -- The name of the package -> String -- The name of the class -> String -- The simple name of the class, including the package. -- ^ Build the name of a class based on maybe a package and a class name. makeName pkg clazz = case pkg of (Just package) -> package ++ '.' : clazz _ -> clazz makePackageModuleName :: String -- The name of the package -> String -- The name of the corresponding Haskell module -- ^ Translates a package name into a module name. makePackageModuleName name | null name = name | otherwise = strJoin "." $ map (strCapitalize) $ strSplitAll "." name makeClassModuleName :: String -- The name of the class -> String -- The name of the corresponding Haskell module -- ^ Translates a class name into a module name. makeClassModuleName name = case maybe "" makePackageModuleName (takePackageName name) of "" -> classModuleName package -> package ++ '.' : classModuleName where classModuleName = strCapitalize $ dropWhile (== '_') $ filter (/= '$') $ takeClassName name splitClassName :: String -> (String, String) -- ^ Splits a class name into package name and class name. -- -- If the name does not contain a package component, the first -- string is empty. -- -- See also 'joinClassName'. splitClassName name = (maybe "" id $ takePackageName name, takeClassName name) joinClassName :: (String, String) -> String -- ^ Pendant to 'splitClassName'. joinClassName (package, clazz) = case package of "" -> clazz _ -> package ++ '.' : clazz takePackageName :: String -> Maybe String -- ^ Retrieve the package name form a simple name of a class. -- -- >>> takePackageName "java.lang.A$B" -- Just "java.lang" -- -- >>> takePackageName "Test" -- Nothing takePackageName fullName = if null name then Nothing else Just (init name) where name = (reverse . snd . break (== '.') . reverse) fullName takeClassName :: String -> String -- ^ Retrieve the class name form a simple name of a class. -- This also contains the name of the enclosing class(es). -- -- >>> takeClassName "java.lang.A$B" -- "A$B" -- -- >>> takeClassName "Thread$State" -- "Thread$State" takeClassName = reverse . fst . break (== '.') . reverse takeBaseClassName :: String -> String -- ^ Retrieve the class name form a simple name of a class. -- This contains only the name of the class itself. -- -- >>> takeBaseClassName "java.lang.A$B" -- "B" takeBaseClassName = reverse . fst . break (== '$') . reverse . takeClassName takeEnclosingClasses :: String -> [String] -- ^ Retrieve the names of the enclosing classes from a simple -- class name. -- -- >>> takeEnclosingClasses "java.lang.Map$EntrySet" -- ["java.lang.Map"] -- -- >>> takeEnclosingClasses "package.A$B$C" -- ["package.A", "package.A$B"] takeEnclosingClasses name = map (makeName (takePackageName name)) simpleNames where simpleNames = scanl1 (\x y-> x ++ "$" ++ y) $ init $ names $ takeClassName name names n = let (a, b) = break (== '$') n in a : if null b then [] else names (tail b)