{-# language DeriveAnyClass #-}
{-# language DeriveGeneric #-}
{-# language DerivingStrategies #-}
{-# language GeneralizedNewtypeDeriving #-}
{-# language OverloadedStrings #-}
{-# language ViewPatterns #-}
module Language.Elm.Name where

import Data.Bifunctor
import qualified Data.Char as Char
import Data.Hashable
import Data.String
import Data.Text (Text)
import qualified Data.Text as Text
import GHC.Generics (Generic)

type Module = [Text]

newtype Local = Local Text
  deriving stock (Local -> Local -> Bool
(Local -> Local -> Bool) -> (Local -> Local -> Bool) -> Eq Local
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Local -> Local -> Bool
== :: Local -> Local -> Bool
$c/= :: Local -> Local -> Bool
/= :: Local -> Local -> Bool
Eq, Eq Local
Eq Local =>
(Local -> Local -> Ordering)
-> (Local -> Local -> Bool)
-> (Local -> Local -> Bool)
-> (Local -> Local -> Bool)
-> (Local -> Local -> Bool)
-> (Local -> Local -> Local)
-> (Local -> Local -> Local)
-> Ord Local
Local -> Local -> Bool
Local -> Local -> Ordering
Local -> Local -> Local
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Local -> Local -> Ordering
compare :: Local -> Local -> Ordering
$c< :: Local -> Local -> Bool
< :: Local -> Local -> Bool
$c<= :: Local -> Local -> Bool
<= :: Local -> Local -> Bool
$c> :: Local -> Local -> Bool
> :: Local -> Local -> Bool
$c>= :: Local -> Local -> Bool
>= :: Local -> Local -> Bool
$cmax :: Local -> Local -> Local
max :: Local -> Local -> Local
$cmin :: Local -> Local -> Local
min :: Local -> Local -> Local
Ord, Int -> Local -> ShowS
[Local] -> ShowS
Local -> String
(Int -> Local -> ShowS)
-> (Local -> String) -> ([Local] -> ShowS) -> Show Local
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Local -> ShowS
showsPrec :: Int -> Local -> ShowS
$cshow :: Local -> String
show :: Local -> String
$cshowList :: [Local] -> ShowS
showList :: [Local] -> ShowS
Show, (forall x. Local -> Rep Local x)
-> (forall x. Rep Local x -> Local) -> Generic Local
forall x. Rep Local x -> Local
forall x. Local -> Rep Local x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Local -> Rep Local x
from :: forall x. Local -> Rep Local x
$cto :: forall x. Rep Local x -> Local
to :: forall x. Rep Local x -> Local
Generic)
  deriving newtype (String -> Local
(String -> Local) -> IsString Local
forall a. (String -> a) -> IsString a
$cfromString :: String -> Local
fromString :: String -> Local
IsString)
  deriving anyclass (Eq Local
Eq Local =>
(Int -> Local -> Int) -> (Local -> Int) -> Hashable Local
Int -> Local -> Int
Local -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> Local -> Int
hashWithSalt :: Int -> Local -> Int
$chash :: Local -> Int
hash :: Local -> Int
Hashable)

data Qualified = Qualified Module Text
  deriving (Qualified -> Qualified -> Bool
(Qualified -> Qualified -> Bool)
-> (Qualified -> Qualified -> Bool) -> Eq Qualified
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Qualified -> Qualified -> Bool
== :: Qualified -> Qualified -> Bool
$c/= :: Qualified -> Qualified -> Bool
/= :: Qualified -> Qualified -> Bool
Eq, Eq Qualified
Eq Qualified =>
(Qualified -> Qualified -> Ordering)
-> (Qualified -> Qualified -> Bool)
-> (Qualified -> Qualified -> Bool)
-> (Qualified -> Qualified -> Bool)
-> (Qualified -> Qualified -> Bool)
-> (Qualified -> Qualified -> Qualified)
-> (Qualified -> Qualified -> Qualified)
-> Ord Qualified
Qualified -> Qualified -> Bool
Qualified -> Qualified -> Ordering
Qualified -> Qualified -> Qualified
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Qualified -> Qualified -> Ordering
compare :: Qualified -> Qualified -> Ordering
$c< :: Qualified -> Qualified -> Bool
< :: Qualified -> Qualified -> Bool
$c<= :: Qualified -> Qualified -> Bool
<= :: Qualified -> Qualified -> Bool
$c> :: Qualified -> Qualified -> Bool
> :: Qualified -> Qualified -> Bool
$c>= :: Qualified -> Qualified -> Bool
>= :: Qualified -> Qualified -> Bool
$cmax :: Qualified -> Qualified -> Qualified
max :: Qualified -> Qualified -> Qualified
$cmin :: Qualified -> Qualified -> Qualified
min :: Qualified -> Qualified -> Qualified
Ord, Int -> Qualified -> ShowS
[Qualified] -> ShowS
Qualified -> String
(Int -> Qualified -> ShowS)
-> (Qualified -> String)
-> ([Qualified] -> ShowS)
-> Show Qualified
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Qualified -> ShowS
showsPrec :: Int -> Qualified -> ShowS
$cshow :: Qualified -> String
show :: Qualified -> String
$cshowList :: [Qualified] -> ShowS
showList :: [Qualified] -> ShowS
Show, (forall x. Qualified -> Rep Qualified x)
-> (forall x. Rep Qualified x -> Qualified) -> Generic Qualified
forall x. Rep Qualified x -> Qualified
forall x. Qualified -> Rep Qualified x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Qualified -> Rep Qualified x
from :: forall x. Qualified -> Rep Qualified x
$cto :: forall x. Rep Qualified x -> Qualified
to :: forall x. Rep Qualified x -> Qualified
Generic)
  deriving anyclass (Eq Qualified
Eq Qualified =>
(Int -> Qualified -> Int)
-> (Qualified -> Int) -> Hashable Qualified
Int -> Qualified -> Int
Qualified -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> Qualified -> Int
hashWithSalt :: Int -> Qualified -> Int
$chash :: Qualified -> Int
hash :: Qualified -> Int
Hashable)

newtype Field = Field Text
  deriving stock (Field -> Field -> Bool
(Field -> Field -> Bool) -> (Field -> Field -> Bool) -> Eq Field
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Field -> Field -> Bool
== :: Field -> Field -> Bool
$c/= :: Field -> Field -> Bool
/= :: Field -> Field -> Bool
Eq, Eq Field
Eq Field =>
(Field -> Field -> Ordering)
-> (Field -> Field -> Bool)
-> (Field -> Field -> Bool)
-> (Field -> Field -> Bool)
-> (Field -> Field -> Bool)
-> (Field -> Field -> Field)
-> (Field -> Field -> Field)
-> Ord Field
Field -> Field -> Bool
Field -> Field -> Ordering
Field -> Field -> Field
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Field -> Field -> Ordering
compare :: Field -> Field -> Ordering
$c< :: Field -> Field -> Bool
< :: Field -> Field -> Bool
$c<= :: Field -> Field -> Bool
<= :: Field -> Field -> Bool
$c> :: Field -> Field -> Bool
> :: Field -> Field -> Bool
$c>= :: Field -> Field -> Bool
>= :: Field -> Field -> Bool
$cmax :: Field -> Field -> Field
max :: Field -> Field -> Field
$cmin :: Field -> Field -> Field
min :: Field -> Field -> Field
Ord, Int -> Field -> ShowS
[Field] -> ShowS
Field -> String
(Int -> Field -> ShowS)
-> (Field -> String) -> ([Field] -> ShowS) -> Show Field
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Field -> ShowS
showsPrec :: Int -> Field -> ShowS
$cshow :: Field -> String
show :: Field -> String
$cshowList :: [Field] -> ShowS
showList :: [Field] -> ShowS
Show, (forall x. Field -> Rep Field x)
-> (forall x. Rep Field x -> Field) -> Generic Field
forall x. Rep Field x -> Field
forall x. Field -> Rep Field x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Field -> Rep Field x
from :: forall x. Field -> Rep Field x
$cto :: forall x. Rep Field x -> Field
to :: forall x. Rep Field x -> Field
Generic)
  deriving newtype (String -> Field
(String -> Field) -> IsString Field
forall a. (String -> a) -> IsString a
$cfromString :: String -> Field
fromString :: String -> Field
IsString)
  deriving anyclass (Eq Field
Eq Field =>
(Int -> Field -> Int) -> (Field -> Int) -> Hashable Field
Int -> Field -> Int
Field -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> Field -> Int
hashWithSalt :: Int -> Field -> Int
$chash :: Field -> Int
hash :: Field -> Int
Hashable)

newtype Constructor = Constructor Text
  deriving stock (Constructor -> Constructor -> Bool
(Constructor -> Constructor -> Bool)
-> (Constructor -> Constructor -> Bool) -> Eq Constructor
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Constructor -> Constructor -> Bool
== :: Constructor -> Constructor -> Bool
$c/= :: Constructor -> Constructor -> Bool
/= :: Constructor -> Constructor -> Bool
Eq, Eq Constructor
Eq Constructor =>
(Constructor -> Constructor -> Ordering)
-> (Constructor -> Constructor -> Bool)
-> (Constructor -> Constructor -> Bool)
-> (Constructor -> Constructor -> Bool)
-> (Constructor -> Constructor -> Bool)
-> (Constructor -> Constructor -> Constructor)
-> (Constructor -> Constructor -> Constructor)
-> Ord Constructor
Constructor -> Constructor -> Bool
Constructor -> Constructor -> Ordering
Constructor -> Constructor -> Constructor
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Constructor -> Constructor -> Ordering
compare :: Constructor -> Constructor -> Ordering
$c< :: Constructor -> Constructor -> Bool
< :: Constructor -> Constructor -> Bool
$c<= :: Constructor -> Constructor -> Bool
<= :: Constructor -> Constructor -> Bool
$c> :: Constructor -> Constructor -> Bool
> :: Constructor -> Constructor -> Bool
$c>= :: Constructor -> Constructor -> Bool
>= :: Constructor -> Constructor -> Bool
$cmax :: Constructor -> Constructor -> Constructor
max :: Constructor -> Constructor -> Constructor
$cmin :: Constructor -> Constructor -> Constructor
min :: Constructor -> Constructor -> Constructor
Ord, Int -> Constructor -> ShowS
[Constructor] -> ShowS
Constructor -> String
(Int -> Constructor -> ShowS)
-> (Constructor -> String)
-> ([Constructor] -> ShowS)
-> Show Constructor
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Constructor -> ShowS
showsPrec :: Int -> Constructor -> ShowS
$cshow :: Constructor -> String
show :: Constructor -> String
$cshowList :: [Constructor] -> ShowS
showList :: [Constructor] -> ShowS
Show, (forall x. Constructor -> Rep Constructor x)
-> (forall x. Rep Constructor x -> Constructor)
-> Generic Constructor
forall x. Rep Constructor x -> Constructor
forall x. Constructor -> Rep Constructor x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Constructor -> Rep Constructor x
from :: forall x. Constructor -> Rep Constructor x
$cto :: forall x. Rep Constructor x -> Constructor
to :: forall x. Rep Constructor x -> Constructor
Generic)
  deriving newtype (String -> Constructor
(String -> Constructor) -> IsString Constructor
forall a. (String -> a) -> IsString a
$cfromString :: String -> Constructor
fromString :: String -> Constructor
IsString)
  deriving anyclass (Eq Constructor
Eq Constructor =>
(Int -> Constructor -> Int)
-> (Constructor -> Int) -> Hashable Constructor
Int -> Constructor -> Int
Constructor -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> Constructor -> Int
hashWithSalt :: Int -> Constructor -> Int
$chash :: Constructor -> Int
hash :: Constructor -> Int
Hashable)

isConstructor :: Qualified -> Bool
isConstructor :: Qualified -> Bool
isConstructor Qualified
name =
  case Qualified
name of
    Qualified
"List.::" ->
      Bool
True

    Qualified
"Basics.," ->
      Bool
True

    Qualified
"Basics.()" ->
      Bool
True

    Qualified Module
_ (Text -> Maybe (Char, Text)
Text.uncons -> Just (Char
firstChar, Text
_)) ->
      Char -> Bool
Char.isUpper Char
firstChar

    Qualified
_ ->
      Bool
False

instance IsString Qualified where
  fromString :: String -> Qualified
fromString String
s =
    case Module -> Maybe (Module, Text)
forall a. [a] -> Maybe ([a], a)
unsnoc (Module -> Maybe (Module, Text)) -> Module -> Maybe (Module, Text)
forall a b. (a -> b) -> a -> b
$ HasCallStack => Text -> Text -> Module
Text -> Text -> Module
Text.splitOn Text
"." (Text -> Module) -> Text -> Module
forall a b. (a -> b) -> a -> b
$ String -> Text
forall a. IsString a => String -> a
fromString String
s of
      Maybe (Module, Text)
Nothing ->
        String -> Qualified
forall a. HasCallStack => String -> a
error String
"Empty name"

      Just ([], Text
x) ->
        String -> Qualified
forall a. HasCallStack => String -> a
error (String -> Qualified) -> String -> Qualified
forall a b. (a -> b) -> a -> b
$ String
"Unqualified name " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
forall a. Show a => a -> String
show Text
x

      Just (Module
xs, Text
x) ->
        Module -> Text -> Qualified
Qualified Module
xs Text
x
    where
      unsnoc :: [a] -> Maybe ([a], a)
      unsnoc :: forall a. [a] -> Maybe ([a], a)
unsnoc [] = Maybe ([a], a)
forall a. Maybe a
Nothing
      unsnoc (a
a:[a]
as) = ([a], a) -> Maybe ([a], a)
forall a. a -> Maybe a
Just (([a], a) -> Maybe ([a], a)) -> ([a], a) -> Maybe ([a], a)
forall a b. (a -> b) -> a -> b
$ a -> [a] -> ([a], a)
forall a. a -> [a] -> ([a], a)
go a
a [a]
as

      go :: a -> [a] -> ([a], a)
      go :: forall a. a -> [a] -> ([a], a)
go a
a [] = ([], a
a)
      go a
a (a
a':[a]
as) = ([a] -> [a]) -> ([a], a) -> ([a], a)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (a
aa -> [a] -> [a]
forall a. a -> [a] -> [a]
:) (([a], a) -> ([a], a)) -> ([a], a) -> ([a], a)
forall a b. (a -> b) -> a -> b
$ a -> [a] -> ([a], a)
forall a. a -> [a] -> ([a], a)
go a
a' [a]
as