packages feed

dedukti-1.1.3: Dedukti/Module.hs

-- |
-- Copyright : © 2009 CNRS - École Polytechnique - INRIA
-- License   : GPL
--
-- A representation of module names and associated functions to map module
-- names to source files and vice-versa. Qualified names, as required in the
-- presence of modules, are also defined here.

{-# OPTIONS_GHC -funbox-strict-fields #-}
module Dedukti.Module
    ( -- * Data types
      Hierarchy(..), MName
    -- * Exceptions
    , InvalidModuleName(..)
    -- * Functions
    , hierarchy, toList
    , pathFromModule, moduleFromPath
    , srcPathFromModule, objPathFromModule, ifacePathFromModule
    -- * Qualified names
    , Qid, qid_qualifier, qid_stem, qid_suffix
    , qid, (.$), provenance, qualify, unqualify
    -- * Atoms
    , Atom
    , fromAtom, toAtom
    ) where

import Dedukti.DkM
import System.FilePath
import Data.Char (isAlpha, isAlphaNum)
import qualified Data.ByteString.Lazy.Char8 as B
import qualified Data.ByteString as BS (concat)
import Text.PrettyPrint.Leijen
import qualified StringTable.Atom as Atom
import StringTable.Atom (Atom)


-- | A generic stack-like datatype for representing hierarchical names.
data Hierarchy = !Hierarchy :. !Atom | Root
                 deriving (Eq, Ord, Show)

type MName = Hierarchy

newtype InvalidModuleName = InvalidModuleName String
    deriving (Eq, Ord, Typeable)

instance Show InvalidModuleName where
    show (InvalidModuleName name) = "invalid character in " ++ name

instance Exception InvalidModuleName

instance Pretty MName where
    pretty (Root :. x) = text (B.unpack (fromAtom x))
    pretty (xs :. x) = pretty xs <> char '.' <> text (B.unpack (fromAtom x))

fromAtom :: Atom -> B.ByteString
fromAtom = B.fromChunks . return . Atom.fromAtom

toAtom :: B.ByteString -> Atom
toAtom = Atom.toAtom . BS.concat . B.toChunks

hierarchy :: [B.ByteString] -> Hierarchy
hierarchy =  f . reverse where
    f [] = Root
    f (x:xs) = f xs :. toAtom x

toList :: Hierarchy -> [B.ByteString]
toList = reverse . f where
    f Root = []
    f (xs :. x) = fromAtom x : f xs

-- | Raise an exception if module name component is a valid identifier.
check :: String -> String
check cmpt@(x:xs) | isAlpha x, and (map (\x -> isAlphaNum x || elem x "_-+~") xs) = cmpt
                  | otherwise = throw $ InvalidModuleName cmpt

pathFromModule :: String -> MName -> FilePath
pathFromModule ext mod =
    addExtension (joinPath $ map B.unpack $ toList mod) ext

moduleFromPath :: FilePath -> MName
moduleFromPath =
    hierarchy . map (B.pack . check) . splitDirectories . dropExtension

srcPathFromModule :: MName -> FilePath
srcPathFromModule = pathFromModule ".dk"

objPathFromModule :: MName -> FilePath
objPathFromModule = pathFromModule ".dko"

ifacePathFromModule :: MName -> FilePath
ifacePathFromModule = pathFromModule ".dki"

-- | The datatype of qualified names.
data Qid = Qid !Hierarchy !Atom !Hierarchy
           deriving (Eq, Show, Ord)

qid_qualifier (Qid qual _ _) = qual
qid_stem (Qid _ stem _) = stem
qid_suffix (Qid _ _ suf) = suf

-- | Shorthand qid introduction.
qid :: B.ByteString -> Qid
qid x = Qid Root (toAtom x) Root

-- | Append suffix.
(.$) :: Qid -> B.ByteString -> Qid
(Qid qual x sufs) .$ suf = Qid qual x (sufs :. (toAtom suf))

-- | Get the module where the qid is defined, based on its qualifier.
provenance :: Qid -> Maybe MName
provenance (Qid Root _ _) = Nothing
provenance (Qid qual _ _) = Just qual

-- | Set the qualifier.
qualify :: Hierarchy -> Qid -> Qid
qualify qual (Qid _ stem suf) = Qid qual stem suf

-- | Remove any qualifier.
unqualify :: Qid -> Qid
unqualify (Qid _ stem suf) = Qid Root stem suf