packages feed

mulang-4.0.0: src/Language/Mulang/Signature.hs

module Language.Mulang.Signature (
  arity,
  name,
  nameAndArity,
  parameterNames,
  signatureOf,
  signaturesOf,
  codeSignaturesOf,
  styledCodeSignaturesOf,
  mulangStyle,
  haskellStyle,
  prologStyle,
  untypedCStyle,
  Signature(..),
  SignatureStyle) where

import Language.Mulang.Identifier
import Language.Mulang.Ast
import Language.Mulang.Generator (declarations)

import Data.List (transpose, intercalate, nub, groupBy)
import Data.Maybe (fromMaybe, mapMaybe)
import Control.Monad (msum)
import Data.Function (on)

type SignatureStyle = [Signature] -> [String]

data Signature = AritySignature Identifier Int
               | TypedSignature Identifier [Identifier] Identifier
               | NamedSignature Identifier [Maybe Identifier] deriving (Show, Eq)


arity :: Signature -> Int
arity (AritySignature _ a)    = a
arity (TypedSignature _ ps _) = length ps
arity (NamedSignature _ ps)   = length ps

name :: Signature -> Identifier
name (AritySignature n _)   = n
name (TypedSignature n _ _) = n
name (NamedSignature n _)   = n

nameAndArity :: Signature -> (Identifier, Int)
nameAndArity signature = (name signature, arity signature)

parameterNames :: Signature -> [Maybe Identifier]
parameterNames (AritySignature _ arity)   = replicate arity Nothing
parameterNames (TypedSignature _ types _) = map (const Nothing) types
parameterNames (NamedSignature _ names)   = names

signaturesOf :: Expression -> [Signature]
signaturesOf = nub . mapMaybe signatureOf . declarations

signatureOf :: Expression -> Maybe Signature
signatureOf (Subroutine name es)                  = Just $ NamedSignature name (parameterNamesOf es)
signatureOf (Clause name args _)                  = Just $ AritySignature name (length args)
signatureOf (TypeSignature name t)                = typedSignatureOf name t
signatureOf (Variable name _)                     = Just $ AritySignature name 0
signatureOf _                                     = Nothing

typedSignatureOf :: Identifier -> Type -> Maybe Signature
typedSignatureOf name (ParameterizedType args ret [])  = Just $ TypedSignature name args ret
typedSignatureOf name (SimpleType ret [])              = Just $ TypedSignature name [] ret
typedSignatureOf _ _                                   = Nothing

parameterNamesOf :: [Equation] -> [Maybe Identifier]
parameterNamesOf = map msum . transpose . map (map parameterNameOf . equationPatterns)

parameterNameOf :: Pattern -> Maybe Identifier
parameterNameOf (VariablePattern v) = Just v
parameterNameOf _                   = Nothing

codeSignaturesOf :: Expression -> [Code]
codeSignaturesOf = styledCodeSignaturesOf mulangStyle

styledCodeSignaturesOf :: SignatureStyle -> Expression -> [Code]
styledCodeSignaturesOf style = style . signaturesOf

-- Styles

mulangStyle :: SignatureStyle
mulangStyle = makeLines "--" (return.s)
  where s :: Signature -> String
        s (AritySignature name arity)     = name ++ "/" ++ show arity
        s (NamedSignature name names)     = name ++ "(" ++ (intercalate ", " . makeParamNames $ names) ++ ")"
        s (TypedSignature name types ret) = name ++ "(" ++ (intercalate ", " types) ++ "): " ++ ret

untypedCStyle :: SignatureStyle
untypedCStyle = makeLines "//" s
  where s (AritySignature name 0)     = Just name
        s (NamedSignature name names) = Just $ name ++ "(" ++ (intercalate ", " . makeParamNames $ names) ++ ")"
        s _                           = Nothing

haskellStyle :: SignatureStyle
haskellStyle = groupAndMakeLinesOn "--" name s
  where s (NamedSignature name names)     = Just $ name ++ " " ++ (intercalate " " . makeParamNames $ names)
        s (TypedSignature name types ret) = Just $ name ++ " :: " ++ (intercalate " -> " (types ++ [ret]))
        s (AritySignature name 0)         = Just name
        s _                               = Nothing

prologStyle :: SignatureStyle
prologStyle = groupAndMakeLinesOn "%%" nameAndArity s
  where s (AritySignature name arity) = Just $ name ++ "/" ++ show arity
        s _                           = Nothing

--Style helper functions

makeParamNames :: [Maybe String] -> [String]
makeParamNames = map (fromMaybe "?")

makeLines :: String -> (Signature -> Maybe String) -> [Signature] -> [String]
makeLines comment f = prefixCodeSignaturesWithComment comment . mapMaybe f

groupAndMakeLinesOn :: Eq a => String -> (Signature -> a) -> (Signature -> Maybe String) -> [Signature] -> [String]
groupAndMakeLinesOn comment groupFunction s = map (intercalate "\n" . makeLines comment s) . groupSignaturesOn groupFunction

prefixCodeSignaturesWithComment :: String -> [String] -> [String]
prefixCodeSignaturesWithComment comment = map (\s -> comment ++ " " ++ s)

groupSignaturesOn :: Eq a => (Signature -> a) -> [Signature] -> [[Signature]]
groupSignaturesOn f = groupBy ((==) `on` f)