packages feed

ychr-0.1.0.0: src/YCHR/Internal/Rename/Types.hs

{-# LANGUAGE OverloadedStrings #-}

-- |
-- Module      : YCHR.Internal.Rename.Types
-- Description : Environment types shared by the renamer.
--
-- The renamer (see "YCHR.Internal.Rename") consults two kinds of global environments
-- when resolving a surface name to a fully-qualified one:
--
-- * 'DeclEnv' — where each @(name, arity)@ is /declared/. Used to resolve
--   references to the module a rule belongs to (\"what does this module
--   itself provide?\") and to validate already-qualified references.
-- * 'ExportEnv' — where each @(name, arity)@ is /exported/. Used to resolve
--   references to imported modules (\"what do the modules I import give
--   me?\").
--
-- Both wrap a @Map (name, arity) [module]@ because a single identifier can
-- resolve to several modules (which triggers an ambiguity error). They are
-- kept as distinct newtypes so that callers can't accidentally use a
-- declaration map in place of an export map.
module YCHR.Internal.Rename.Types
  ( -- * Export environment
    ExportEnv,
    makeExportEnv,
    lookupExport,
    toListExport,

    -- * Declaration environment
    DeclEnv,
    makeDeclEnv,
    lookupDecl,
    toListDecl,

    -- * Reserved names
    isReserved,
  )
where

import Data.Map.Strict qualified as Map
import Data.Set (Set)
import Data.Set qualified as Set
import Data.Text (Text)

-- | All names exported by each module, indexed by @(name, arity)@. For a
-- module without an explicit @module@ directive, every declaration is
-- considered exported.
newtype ExportEnv = ExportEnv (Map.Map (Text, Int) [Text])

makeExportEnv :: [((Text, Int), [Text])] -> ExportEnv
makeExportEnv = ExportEnv . Map.fromListWith (++)

lookupExport :: (Text, Int) -> ExportEnv -> [Text]
lookupExport k (ExportEnv m) = Map.findWithDefault [] k m

toListExport :: ExportEnv -> [((Text, Int), [Text])]
toListExport (ExportEnv m) = Map.toList m

-- | All names declared anywhere in the program, indexed by @(name, arity)@.
-- Unlike 'ExportEnv', this ignores export lists: it answers \"is this name
-- visible within its own declaring module?\".
newtype DeclEnv = DeclEnv (Map.Map (Text, Int) [Text])

makeDeclEnv :: [((Text, Int), [Text])] -> DeclEnv
makeDeclEnv = DeclEnv . Map.fromListWith (++)

lookupDecl :: (Text, Int) -> DeclEnv -> [Text]
lookupDecl k (DeclEnv m) = Map.findWithDefault [] k m

toListDecl :: DeclEnv -> [((Text, Int), [Text])]
toListDecl (DeclEnv m) = Map.toList m

-- | Names that must stay 'YCHR.Types.Unqualified' even in resolving
-- contexts. These are desugaring-level keywords (@true@, @=@, @is@, @->@,
-- @$call@) that the desugarer matches by name; qualifying them
-- would break that dispatch.
--
-- Most of these forms are handled by dedicated shape-matching cases in
-- 'YCHR.Internal.Rename.renameTerm'. This set is the fallback for shapes that don't
-- match those cases (e.g. @is/3@).
reservedSymbolSet :: Set Text
reservedSymbolSet = Set.fromList ["true", "=", "is", "->", "$call", "quote", "fun"]

isReserved :: Text -> Bool
isReserved t = Set.member t reservedSymbolSet