packages feed

disco-0.1.6: src/Disco/Names.hs

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE OverloadedStrings #-}

-----------------------------------------------------------------------------

-----------------------------------------------------------------------------

-- SPDX-License-Identifier: BSD-3-Clause

-- |
-- Module      :  Disco.Names
-- Copyright   :  disco team and contributors
-- Maintainer  :  byorgey@gmail.com
--
-- Names for modules and identifiers.
module Disco.Names (
  -- * Modules and their provenance
  ModuleProvenance (..),
  ModuleName (..),

  -- * Names and their provenance
  NameProvenance (..),
  QName (..),
  isFree,
  localName,
  (.-),

  -- * Name-related utilities
  fvQ,
  substQ,
  substsQ,
) where

import Control.Lens (Traversal', filtered)
import Data.Data (Data)
import Data.Data.Lens (template)
import Data.Typeable (Typeable)
import GHC.Generics (Generic)
import System.FilePath (dropExtension)
import Unbound.Generics.LocallyNameless
import Prelude hiding ((<>))

import Disco.Pretty
import Disco.Types

------------------------------------------------------------
-- Modules
------------------------------------------------------------

-- | Where did a module come from?
data ModuleProvenance
  = -- | From a particular directory (relative to cwd)
    Dir FilePath
  | -- | From the standard library
    Stdlib
  deriving (Eq, Ord, Show, Generic, Data, Alpha, Subst Type)

-- | The name of a module.
data ModuleName
  = -- | The special top-level "module" consisting of
    -- what has been entered at the REPL.
    REPLModule
  | -- | A named module, with its name and provenance.
    Named ModuleProvenance String
  deriving (Eq, Ord, Show, Generic, Data, Alpha, Subst Type)

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

-- | Where did a name come from?
data NameProvenance
  = -- | The name is locally bound
    LocalName
  | -- | The name is exported by the given module
    QualifiedName ModuleName
  deriving (Eq, Ord, Show, Generic, Data, Alpha, Subst Type)

-- | A @QName@, or qualified name, is a 'Name' paired with its
--   'NameProvenance'.
data QName a = QName {qnameProvenance :: NameProvenance, qname :: Name a}
  deriving (Eq, Ord, Show, Generic, Data, Alpha, Subst Type)

-- | Does this name correspond to a free variable?
isFree :: QName a -> Bool
isFree (QName (QualifiedName _) _) = True
isFree (QName LocalName n) = isFreeName n

-- | Create a locally bound qualified name.
localName :: Name a -> QName a
localName = QName LocalName

-- | Create a module-bound qualified name.
(.-) :: ModuleName -> Name a -> QName a
m .- x = QName (QualifiedName m) x

------------------------------------------------------------
-- Free variables and substitution
------------------------------------------------------------

-- | The @unbound-generics@ library gives us free variables for free.
--   But when dealing with typed and desugared ASTs, we want all the
--   free 'QName's instead of just 'Name's.
fvQ :: (Data t, Typeable e) => Traversal' t (QName e)
fvQ = template . filtered isFree

substQ :: Subst b a => QName b -> b -> a -> a
substQ = undefined

substsQ :: Subst b a => [(QName b, b)] -> a -> a
substsQ = undefined

------------------------------------------------------------
-- Pretty-printing
------------------------------------------------------------

instance Pretty ModuleName where
  pretty REPLModule = "REPL"
  pretty (Named (Dir _) s) = text (dropExtension s)
  pretty (Named Stdlib s) = text (dropExtension s)

instance Pretty (QName a) where
  pretty (QName LocalName x) = pretty x
  pretty (QName (QualifiedName mn) x) = pretty mn <> "." <> pretty x