packages feed

cryptol-3.5.0: src/Cryptol/Parser/Name.hs

-- |
-- Module      :  Cryptol.Parser.Name
-- Copyright   :  (c) 2015-2016 Galois, Inc.
-- License     :  BSD3
-- Maintainer  :  cryptol@galois.com
-- Stability   :  provisional
-- Portability :  portable

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE PatternSynonyms #-}

module Cryptol.Parser.Name (
  NameSource(..)
  , PName(..)
  , Pass(..)
  , mkQual
  , mkUnqual
  , mkUnqualSystem
  , origNameToDefPName
  , getModName
  , getIdent
  , isSystemName
  , pattern UnQual
  ) where

import Cryptol.Utils.Fixity
import Cryptol.Utils.Ident
import Cryptol.Utils.PP
import Cryptol.Utils.Panic (panic)

import           Control.DeepSeq
import           GHC.Generics (Generic)


-- Names -----------------------------------------------------------------------

data NameSource = SystemName | UserName
                    deriving (Generic, Show, Ord, Eq)
-- | Names that originate in the parser.
--   Note here that other kinds of PName do not need this kind of flag because: 
--   (1) NewName are generated by the system, so these should never be user visible.
--   (2) Qual names are user names use to refer to imported modules. Should these names
--       names ever be used to refer to system names, then there make be a bug in the renamer
--       that needs to be fixed.
data PName = UnQual' !Ident !NameSource
             -- ^ Unqualified names like @x@, @Foo@, or @+@.
           | Qual !ModName !Ident
             -- ^ Qualified names like @Foo::bar@ or @module::!@.
           | NewName !Pass !Int
             -- ^ Fresh names generated by a pass.
             deriving (Eq,Ord,Show,Generic)

-- | Passes that can generate fresh names.
data Pass = NoPat
          | MonoValues
          | ExpandPropGuards String
            deriving (Eq,Ord,Show,Generic)

instance NFData PName
instance NFData Pass
instance NFData NameSource

-- | Pattern synonym for when we are trying to deconstruct
--   unqualified PNames to get their identifiers.
pattern UnQual :: Ident -> PName
pattern UnQual i <- UnQual' i _

mkUnqual :: Ident -> PName
mkUnqual  = (`UnQual'` UserName)

mkUnqualSystem :: Ident -> PName
mkUnqualSystem = (`UnQual'` SystemName)

mkQual :: ModName -> Ident -> PName
mkQual  = Qual

-- | Compute a `PName` for the definition site corresponding to the given
-- `OrigName`.   Usually this is an unqualified name, but names that come
-- from module parameters are qualified with the corresponding parameter name.
origNameToDefPName :: OrigName -> NameSource -> PName
origNameToDefPName og vis = toPName (ogName og)
  where
  toPName =
    case ogFromParam og of
      Nothing -> (`UnQual'` vis)
      Just sig -> Qual (identToModName sig)

getModName :: PName -> Maybe ModName
getModName (Qual ns _) = Just ns
getModName _           = Nothing

getIdent :: PName -> Ident
getIdent (UnQual' n _)    = n
getIdent (Qual _ n)    = n
getIdent (NewName p i) = packIdent ("__" ++ pass ++ show i)
  where
  pass = case p of
           NoPat              -> "p"
           MonoValues         -> "mv"
           ExpandPropGuards _ -> "epg"



isSystemName :: PName -> Bool
isSystemName x =
  case x of
    UnQual' _id ns ->   case ns of
                          SystemName -> True
                          UserName -> False
    Qual _md _id -> False
    NewName _p _i -> True

instance PP PName where
  ppPrec _ = ppPrefixName

instance PPName PName where
  ppNameFixity n
    | isInfixIdent i = Just (Fixity NonAssoc 0) -- FIXME?
    | otherwise      = Nothing
    where
    i   = getIdent n

  ppPrefixName n = optParens (isInfixIdent i) (pfx <.> pp i)
    where
    i   = getIdent n
    pfx = case getModName n of
            Just ns -> pp ns <.> text "::"
            Nothing -> mempty

  ppInfixName n
    | isInfixIdent i = pfx <.> pp i
    | otherwise      = panic "AST" [ "non-symbol infix name:" ++ show n ]
    where
    i   = getIdent n
    pfx = case getModName n of
            Just ns -> pp ns <.> text "::"
            Nothing -> mempty