-- | `DomainParser` is a simple parser for domain names as described in RFC 1035. module DomainParser where import Prelude (class Monoid, bind, mempty, not, pure, ($), (&&), (*>), (<<<), (<>), (==), (>)) import Control.Lazy (defer) import Data.Maybe (Maybe(..)) import Data.Array as A import Data.String as S import Data.Tuple (Tuple(..)) -- import Data.Array.NonEmpty as NonEmpty import Data.String.CodeUnits as CU import Control.Alt ((<|>)) import Control.Plus (empty) import Parser (Parser(..), alphanum, char, letter, many1, parse, string) -- | From RFC 1035: ::= | let_dig :: Parser Char let_dig = alphanum -- | From RFC 1035: ::= | "-" -- | Either a Letter, Digital or an Hyphenation character. let_dig_hyp :: Parser Char let_dig_hyp = let_dig <|> char '-' -- | From RFC 1035: ::= | ldh_str :: Parser (Array Char) ldh_str = many1 let_dig_hyp -- TODO: 63 label_maxsize :: Int label_maxsize = 7 -- TODO: 255? max_domain_length :: Int max_domain_length = 15 last_char :: String -> Maybe Char last_char = A.last <<< CU.toCharArray parse_last_char :: String -> Parser Char -> Boolean parse_last_char s p = case last_char s of Nothing -> false Just c -> case parse p (CU.singleton c) of Nothing -> false _ -> true -- | FIXME: This is flawed. -- | We cannot know if it worked: in case there is a problem with the parser `p`, -- | the code will "continue to work" but without what's been parsed. -- | This may sound reasonable but it prevents knowing if a problem actually occured! -- | We cannot do a `try parser <|> alternative` since it will always work! try :: forall a. Monoid a => Parser a -> Parser a try p = Parser p' where p' str = case parse p str of Nothing -> Just (Tuple mempty str) -- FIXME! Need a better base structure. Just x -> pure x -- | From RFC 1035: