packages feed

fst-0.10.0.0: tests/email.hs

-- | Email address recogniser using transducer interface API

import FST.TransducerInterface
import Data.Maybe (fromJust)

charsToUnion :: [Char] -> Reg String
charsToUnion cs = foldl (\a b -> a <|> s [b]) (s [head cs]) (tail cs)

digit :: Reg String
digit = charsToUnion ['0'..'9']

digit1 :: Reg String
digit1 = charsToUnion ['1'..'9']

letter :: Reg String
letter = charsToUnion ['a'..'z']

punct :: Reg String
punct = charsToUnion "!#$%&'*+-/=?^_{|}~"

hyphen :: Reg String
hyphen = s "-" ;

-- Local part
local :: RReg String
local = idR $ plus local_sym
  where local_sym = digit <|> letter <|> punct

-- Should be limited to 64 chars, but this is impossible to compile:
-- local = idR $ (plus local_sym) <-> over65
--   where local_sym = digit <|> letter <|> punct
--         over65 = foldl (\a b -> a <|> b) local_sym (replicate 65 local_sym)

-- IP address
ip_segment :: Reg String
ip_segment =
      digit
  <|> (digit1 |> digit)
  <|> (s "1" |> digit |> digit)
  <|> (s "2" |> d0to5 |> digit)
  <|> (s "2" |> s "5" |> (digit <-> d6to9))
  where
    d0to5 = s "0" <|> s "1" <|> s "2" <|> s "3" <|> s "4"
    d6to9 = s "6" <|> s "7" <|> s "8" <|> s "9"

ip :: RReg String
ip = idR $ ip_segment |> dot |> ip_segment |> dot |> ip_segment |> dot |> ip_segment
  where dot = s "."

-- DNS names
hostname :: Reg String
hostname = plus (digit <|> letter <|> hyphen)

subdomain :: RReg String
subdomain = idR hostname

-- | Emulation of optionality (?)
option :: RReg String -> RReg String
option rr = rr <|> idR eps

domain :: RReg String
domain =
      ((star (subdomain |> dot)) |> idR hostname)
  <|> option ((student <|> staff) |> dot) |> "Chalmers University" `r` "chalmers"
  <|> "Apple Inc." `r` "apple"
  <|> option gmail |> ("Google" `r` "google")
  where
    student = "Student" `r` "student"
    staff = "Academic Staff" `r` "staff"
    gmail = "Google Mail" `r` "mail" |> dot
    dot = "at" `r` "."

-- Some known TLDs
tld_se = "Sweden" `r` "se"
tld_mt = "Malta" `r` "com.mt"
tld_uk = "UK" `r` "co.uk"
tld_com = idR (s "com")
tld_net = idR (s "net")
tld_org = idR (s "org")
tld = tld_se <|> tld_mt <|> tld_uk <|> tld_com <|> tld_net <|> tld_org

-- | An email address using either DNS names or IP address
email :: RReg String
email =
      local |> at |> domain |> dot |> tld
  <|> local |> at |> ip
  where
    at = idR (s "@")
    dot = "|" `r` "."

-- | Main test function
main :: IO ()
main = do
  let trans = compile email [] :: Transducer String
      tests = map words [test1, test2, test3, test4, test5, test6]
  sequence_ $ map (handle . applyUp trans) tests
  where
    handle :: Maybe [[String]] -> IO ()
    handle (Just outs) = putStrLn $ unwords $ concat outs
    handle Nothing = putStrLn "Input rejected."

-- Test cases
test1 = "j o h n @ 1 9 2 . 1 6 8 . 0 . 1"
test2 = "j o h n { 8 6 } @ chalmers . se"
test3 = "j - ! @ student . chalmers . se"
test4 = "a b c d @ staff . chalmers . se"
test5 = "# $ % ^ @ mail . google . com.mt"
test6 = "b a l d u r @ apple . co.uk"