module Language.Docker.Parser.Expose
  ( parseExpose,
  )
where

import qualified Data.Text as T
import Language.Docker.Parser.Prelude
import Language.Docker.Syntax

parseExpose :: (?esc :: Char) => Parser (Instruction Text)
parseExpose :: (?esc::Char) => Parser (Instruction Text)
parseExpose = do
  (?esc::Char) => Text -> Parser ()
reserved Text
"EXPOSE"
  forall args. Ports -> Instruction args
Expose forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (?esc::Char) => Parser Ports
ports

port :: (?esc :: Char) => Parser Port
port :: (?esc::Char) => Parser Port
port = (forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (?esc::Char) => Parser Port
portVariable forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> String -> m a
<?> String
"a variable")
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try Parser Port
portRange forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> String -> m a
<?> String
"a port range optionally followed by the protocol (udp/tcp)") -- There a many valid representations of ports
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try Parser Port
portWithProtocol forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> String -> m a
<?> String
"a port with its protocol (udp/tcp)")
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Parser Port
portInt forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> String -> m a
<?> String
"a valid port number")

ports :: (?esc :: Char) => Parser Ports
ports :: (?esc::Char) => Parser Ports
ports = [Port] -> Ports
Ports forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (?esc::Char) => Parser Port
port forall (m :: * -> *) a sep. MonadPlus m => m a -> m sep -> m [a]
`sepEndBy` (?esc::Char) => Parser ()
requiredWhitespace

portRange :: Parser Port
portRange :: Parser Port
portRange = do
  Integer
start <- Parser Integer
natural
  forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
'-'
  Integer
finish <- forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try Parser Integer
natural
  Protocol
proto <- forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try ParsecT DockerfileError Text Identity Protocol
protocol forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (m :: * -> *) a. Monad m => a -> m a
return Protocol
TCP
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int -> Int -> Protocol -> Port
PortRange (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
start) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
finish) Protocol
proto

protocol :: Parser Protocol
protocol :: ParsecT DockerfileError Text Identity Protocol
protocol = do
  forall (f :: * -> *) a. Functor f => f a -> f ()
void (forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
'/')
  forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (ParsecT DockerfileError Text Identity Protocol
tcp forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT DockerfileError Text Identity Protocol
udp) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"invalid protocol"
  where
    tcp :: ParsecT DockerfileError Text Identity Protocol
tcp = Text -> Parser Text
caseInsensitiveString Text
"tcp" forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return Protocol
TCP
    udp :: ParsecT DockerfileError Text Identity Protocol
udp = Text -> Parser Text
caseInsensitiveString Text
"udp" forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return Protocol
UDP

portInt :: Parser Port
portInt :: Parser Port
portInt = do
  Integer
portNumber <- Parser Integer
natural
  forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m ()
notFollowedBy (forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens Text
"/" forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens Text
"-")
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int -> Protocol -> Port
Port (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
portNumber) Protocol
TCP

portWithProtocol :: Parser Port
portWithProtocol :: Parser Port
portWithProtocol = do
  Integer
portNumber <- Parser Integer
natural
  Int -> Protocol -> Port
Port (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
portNumber) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT DockerfileError Text Identity Protocol
protocol

portVariable :: (?esc :: Char) => Parser Port
portVariable :: (?esc::Char) => Parser Port
portVariable = do
  forall (f :: * -> *) a. Functor f => f a -> f ()
void (forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
'$')
  Text
variable <- (?esc::Char) => String -> (Char -> Bool) -> Parser Text
someUnless String
"the variable name" (forall a. Eq a => a -> a -> Bool
== Char
'$')
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Text -> Port
PortStr (Text -> Text -> Text
T.append Text
"$" Text
variable)