module Text.Haiji.Syntax.Identifier
       ( Identifier
       , identifier
       ) where

import Control.Applicative
import Control.Monad
import Data.Attoparsec.Text
import Data.String

newtype Identifier = Identifier { Identifier -> [Char]
unIdentifier :: String } deriving Identifier -> Identifier -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Identifier -> Identifier -> Bool
$c/= :: Identifier -> Identifier -> Bool
== :: Identifier -> Identifier -> Bool
$c== :: Identifier -> Identifier -> Bool
Eq

instance Show Identifier where
  show :: Identifier -> [Char]
show = Identifier -> [Char]
unIdentifier

instance IsString Identifier where
  fromString :: [Char] -> Identifier
fromString = [Char] -> Identifier
Identifier

-- | python identifier
--
-- https://docs.python.org/2.7/reference/lexical_analysis.html#identifiers
--
-- >>> import Control.Arrow (left)
-- >>> let eval = left (const "parse error") . parseOnly identifier
-- >>> eval "a"
-- Right a
-- >>> eval "ab"
-- Right ab
-- >>> eval "A"
-- Right A
-- >>> eval "Ab"
-- Right Ab
-- >>> eval "_"
-- Right _
-- >>> eval "_a"
-- Right _a
-- >>> eval "_1"
-- Right _1
-- >>> eval "__"
-- Right __
-- >>> eval "_ "
-- Right _
-- >>> eval " _"
-- Left "parse error"
-- >>> eval "and"
-- Left "parse error"
-- >>> eval "1"
-- Left "parse error"
-- >>> eval "1b"
-- Left "parse error"
-- >>> eval "'x"
-- Left "parse error"
--
identifier :: Parser Identifier
identifier :: Parser Identifier
identifier = do
  Char
h <- Parser Text Char
letter forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Char -> Parser Text Char
char Char
'_'
  [Char]
ts <- forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Parser Text Char
letter forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser Text Char
digit forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Char -> Parser Text Char
char Char
'_')
  let candidate :: [Char]
candidate = Char
h forall a. a -> [a] -> [a]
: [Char]
ts
  forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([Char]
candidate forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [[Char]]
keywords) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"identifier"
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Char] -> Identifier
Identifier [Char]
candidate

-- | python keywords
--
-- https://docs.python.org/2.7/reference/lexical_analysis.html#keywords
--
keywords :: [String]
keywords :: [[Char]]
keywords = [Char] -> [[Char]]
words [Char]
"and       del       from      not       while \
                 \as        elif      global    or        with  \
                 \assert    else      if        pass      yield \
                 \break     except    import    print           \
                 \class     exec      in        raise           \
                 \continue  finally   is        return          \
                 \def       for       lambda    try             "