packages feed

fnotation-0.2.0.1: src/FNotation/Names.hs

-- SPDX-FileCopyrightText: 2026 Coln contributors
--
-- SPDX-License-Identifier: Apache-2.0 OR MIT

module FNotation.Names (
  Name (..),
  dprettyWithKinds,
  dprettyOpWithKinds,
) where

import Data.Char (isDigit, isLetter)
import Data.List (intersperse)
import Data.String (IsString, fromString)
import Data.Text (Text)
import Data.Text qualified as T
import Diagnostician
import FNotation.Config (ConfTable, confTableLookup)
import FNotation.Kinds (Kind (..))
import Prettyprinter

{- | A name of the form `a/b/c`

The properties of a name (such as the precedence when used as an operator) are
determined by the *last* segment. Thus, `a/+` is an infix operator with the
same precedence as `+`.  If you quote the `+` with backticks, however, it will parse as a simple identifier with the same name.

Using a keyword as the last segment of a name is an error unless the keyword is quoted with backticks, in which case it is still not a keyword but an ordinary identifier.
-}
data Name = Name
  { init :: [Text]
  , last :: Text
  }
  deriving (Eq, Ord)

instance Show Name where
  show x = mconcat ((<> "/") . T.unpack <$> x.init) <> T.unpack x.last

instance DPretty Name where
  dpretty x = mconcat ((<> "/") . pretty <$> x.init) <> pretty x.last

pand :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
pand f g x = f x && g x

por :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
por f g x = f x || g x

dprettyWithKinds :: ConfTable Kind -> Name -> DDoc
dprettyWithKinds config x = mconcat . intersperse "/" . map (namesegWithKinds config) $ x.init ++ [x.last]

dprettyOpWithKinds :: ConfTable Kind -> Name -> DDoc
dprettyOpWithKinds config x = mconcat . intersperse "/" $ (namesegWithKinds config `map` x.init) ++ [pretty x.last]

namesegWithKinds :: ConfTable Kind -> Text -> DDoc
namesegWithKinds config x = case confTableLookup config x of
  (Nothing; Just AIdent)
    | T.all (isLetter `por` isDigit `por` ('_' ==) `por` ('-' ==)) `pand` (T.any (isLetter `por` ('_' ==)) . T.take 1) $ x ->
        pretty x
  _ -> "`" <> pretty x <> "`"

instance IsString Name where
  fromString s = Name [] (fromString s)