module Language.Syntax.Regex (regex,runRegex) where

import Language.Parser

runRegex :: String -> String -> [([(String,String)],String)]
runRegex re = join (pure re >*> regex)^..parser <&> map snd

regex :: Parser String (Parser String ([(String,String)],String))
regex = _union
  where _union = (adjacent`sepBy`single '|') <&> sum
        adjacent = many postfixed <&> map concat.sequence
        atom = dot <+> range <+> otherChar <+> between (single '(') (single ')') (named _union)
        named p = cut (option id (map . register<$>between (single '<') (single '>') (many1 (satisfy (/='>'))))) <*> p
          where register n (l,s) = ((n,s):l,s)
        postfixed = comp<$>atom<*>many postfun
          where postfun = satisfy (`elem`"*+?") <&> \c -> case c of
                  '*' -> map sum.many
                  '+' -> map sum.many1
                  '?' -> (+ pure ([],""))
                  _ -> undefined
                comp a fs = compose fs a
        dot = shallow token <$ single '.'
        otherChar = shallow.char<$>noneOf "()[*?|+"
        range = between (single '[') (single ']') t'i'ranges
          where t'i'ranges = shallow . satisfy <$> (option id (map not <$ single '^')
                                                <*> (many subRange <&> \rs c -> any ($c) rs))
                subRange = mkRange<$>subChar<*single '-' <*>subChar
                           <+> (==)<$>subChar
                mkRange a b = \c -> c>=a && c<=b
                subChar = noneOf "]"
        shallow = (([],).pure<$>)
        char c = c<$single c