packages feed

ddc-core-0.4.3.1: DDC/Core/Lexer/Token/Operator.hs

module DDC.Core.Lexer.Token.Operator
        ( scanPrefixOperator
        , scanInfixOperator
        , acceptInfixOperator
        , isOpName
        , isOpStart
        , isOpBody)
where
import Text.Lexer.Inchworm.Char
import DDC.Core.Lexer.Unicode
import qualified Data.Set       as Set
import qualified Data.List      as List


-------------------------------------------------------------------------------
-- | Scanner for operators used prefix.
scanPrefixOperator :: Scanner IO Location [Char] (Location, String)
scanPrefixOperator 
 = munchPred Nothing matchPrefixOperator acceptPrefixOperator


-- | Patch a prefix operator name.
matchPrefixOperator :: Int -> Char -> Bool
matchPrefixOperator 0 c         = c == '('
matchPrefixOperator _ c         = isOpBody c || c == ')'


-- | Accept a prefix operator name.
acceptPrefixOperator :: String -> Maybe String
acceptPrefixOperator str
        | '(' : cs1     <- str
        , c   : cs2     <- cs1
        , isOpStart c
        , (body , cs3)  <- List.span isOpBody cs2
        , ')' : []      <- cs3
        , not $ null (c : body)
        = Just (c : body)

        | otherwise
        = Nothing



-------------------------------------------------------------------------------
-- | Scanner for operators used infix.
scanInfixOperator  :: Scanner IO Location [Char] (Location, String)
scanInfixOperator 
 = munchPred Nothing matchInfixOperator acceptInfixOperator


-- | Match an operator name.
matchInfixOperator  :: Int -> Char -> Bool
matchInfixOperator 0 c       = isOpStart c
matchInfixOperator _ c       = isOpBody  c


-- | Accept an operator name.
acceptInfixOperator :: String -> Maybe String
acceptInfixOperator str
 = case str of
        "="     -> Nothing
        "|"     -> Nothing
        "~>"    -> Nothing
        "->"    -> Nothing
        "<-"    -> Nothing
        "=>"    -> Nothing
        "/\\"   -> Nothing
        _       -> Just str


-- | String is the name of some operator.
isOpName :: String -> Bool
isOpName str
 = case str of
        []      -> False
        c : cs
         | isOpStart c
         , and (map isOpBody cs)
         -> True

         | otherwise
         -> False


-- | Character can start an operator.
isOpStart :: Char -> Bool
isOpStart c
        =  c == '~'     || c == '!'                     || c == '#'     
        || c == '$'     || c == '%'                     || c == '&'     
        || c == '*'     || c == '-'     || c == '+'     || c == '='
        || c == ':'                     || c == '/'     || c == '|'
        || c == '<'     || c == '>'
        || Set.member c unicodeOperatorsInfix


-- | Character can be part of an operator body.
isOpBody :: Char -> Bool
isOpBody c
        =  c == '~'     || c == '!'                     || c == '#'     
        || c == '$'     || c == '%'                     || c == '&'     
        || c == '*'     || c == '-'     || c == '+'     || c == '='
        || c == ':'     || c == '?'     || c == '/'     || c == '|'
        || c == '<'     || c == '>'
        || c == '\\'
        || Set.member c unicodeOperatorsInfix