2023-04-28 19:08:56 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
module Algorithm.Lex
|
|
|
|
( lexx
|
2023-04-29 19:36:42 +00:00
|
|
|
, Token(..)
|
|
|
|
, QueryDef(..)
|
2023-05-04 18:34:12 +00:00
|
|
|
, Operator(..)
|
|
|
|
, ParseError(..)) where
|
2023-04-28 19:08:56 +00:00
|
|
|
import Prelude hiding (lex)
|
2023-05-04 18:34:12 +00:00
|
|
|
import Data.Either
|
|
|
|
import Text.Read (readMaybe)
|
2023-04-28 19:08:56 +00:00
|
|
|
|
2023-05-04 18:34:12 +00:00
|
|
|
lexx :: String -> Either ParseError Token
|
2023-04-28 19:08:56 +00:00
|
|
|
lexx qur = do
|
2023-04-30 16:48:50 +00:00
|
|
|
let collected = clearRepeatedSpaces $ collector $ strip $ stripFront $ clearIllegalCharacters qur
|
|
|
|
let parenthesises = matchParenthesis collected 0
|
|
|
|
let (parenthesisFixed, parenthesis) = fixSeparators collected parenthesises
|
2023-04-28 19:08:56 +00:00
|
|
|
seperator parenthesisFixed parenthesis
|
2023-05-04 18:34:12 +00:00
|
|
|
|
2023-04-28 19:08:56 +00:00
|
|
|
|
2023-04-30 16:48:50 +00:00
|
|
|
stripFront :: [Char] -> [Char]
|
|
|
|
stripFront = dropWhile (==' ')
|
|
|
|
|
|
|
|
strip :: String -> String
|
|
|
|
strip (' ':as) = case strip as of
|
|
|
|
[] -> []
|
|
|
|
_ -> ' ' : strip as
|
|
|
|
strip (a:as) = a : strip as
|
|
|
|
strip [] = []
|
|
|
|
|
|
|
|
|
2023-04-28 19:08:56 +00:00
|
|
|
|
2023-04-28 19:39:04 +00:00
|
|
|
fixSeparators :: [String] -> [(Int, Int)] -> ([String], [(Int, Int)])
|
2023-05-04 18:34:12 +00:00
|
|
|
fixSeparators values parenthesis@((start,end):_) | start == 0 && end == ( length values -1) = (values, parenthesis)
|
2023-04-28 19:39:04 +00:00
|
|
|
fixSeparators values parenthesis = ( ["("] ++ values ++ [")"], (0, length values + 1):map addOne parenthesis)
|
2023-04-28 19:08:56 +00:00
|
|
|
|
2023-04-29 19:36:42 +00:00
|
|
|
|
2023-04-28 19:39:04 +00:00
|
|
|
addOne (x,y) = (x+1, y+1)
|
2023-04-28 19:08:56 +00:00
|
|
|
|
|
|
|
isLegal :: Char -> Bool
|
|
|
|
isLegal x = x `notElem` ['(',')',' ']
|
|
|
|
|
2023-04-28 19:39:04 +00:00
|
|
|
|
2023-04-30 16:48:50 +00:00
|
|
|
clearIllegalCharacters :: String -> String
|
|
|
|
clearIllegalCharacters (c:cs) | c `elem` ['\n', '\r'] = ' ':clearIllegalCharacters cs
|
|
|
|
clearIllegalCharacters (c:cs) = c:clearIllegalCharacters cs
|
|
|
|
clearIllegalCharacters [] = []
|
|
|
|
|
2023-04-28 19:39:04 +00:00
|
|
|
clearRepeatedSpaces :: [String] -> [String]
|
|
|
|
clearRepeatedSpaces (a:as) = case a of
|
|
|
|
" " -> " ": clearRepeatedSpaces (dropWhile (==" ") as)
|
|
|
|
b -> b: clearRepeatedSpaces as
|
|
|
|
clearRepeatedSpaces [] = []
|
|
|
|
|
|
|
|
|
2023-04-28 19:08:56 +00:00
|
|
|
collector :: String -> [String]
|
|
|
|
collector [] = []
|
|
|
|
collector (x:r) | not $ isLegal x = [x] : collector r
|
|
|
|
collector elements = case takeWhile isLegal elements of
|
|
|
|
"" -> collector (dropWhile isLegal elements)
|
|
|
|
b -> b : collector (dropWhile isLegal elements)
|
|
|
|
|
|
|
|
|
|
|
|
matchParenthesis :: [String] -> Int -> [(Int, Int)]
|
|
|
|
matchParenthesis ("(":rest) count = (count, findClosing rest 0 (count+1)):matchParenthesis rest (count+1)
|
|
|
|
matchParenthesis (a:rest) count = matchParenthesis rest (count+1)
|
|
|
|
matchParenthesis [] _ = []
|
|
|
|
|
|
|
|
|
|
|
|
findClosing :: [String] -> Int -> Int -> Int
|
|
|
|
findClosing (")":xs) stackCount count | stackCount == 0 = count
|
|
|
|
findClosing (")":xs) stackCount count = findClosing xs (stackCount-1) (count+1)
|
|
|
|
findClosing ("(":xs) stackCount count = findClosing xs (stackCount+1) (count+1)
|
|
|
|
findClosing (x:xs) stackCount count = findClosing xs stackCount (count+1)
|
|
|
|
findClosing [] _ _ = error "Unequal number of parenthesis"
|
|
|
|
|
|
|
|
|
2023-05-04 18:34:12 +00:00
|
|
|
newtype ParseError = ParseError String
|
|
|
|
|
|
|
|
data Token =
|
|
|
|
Func Operator Token Token |
|
|
|
|
Queri QueryDef
|
|
|
|
deriving Show
|
2023-04-30 16:48:50 +00:00
|
|
|
data QueryDef =
|
|
|
|
SuperType String|
|
|
|
|
Color String |
|
|
|
|
CMCLT Int |
|
|
|
|
CMCMT Int |
|
|
|
|
CMCEQ Int
|
|
|
|
deriving Show
|
|
|
|
data Operator =
|
|
|
|
Union |
|
|
|
|
Intersect |
|
|
|
|
Minus
|
|
|
|
deriving Show
|
2023-04-28 19:08:56 +00:00
|
|
|
|
2023-05-04 18:34:12 +00:00
|
|
|
seperator :: [String] -> [(Int, Int)] -> Either ParseError Token
|
|
|
|
|
2023-04-28 19:08:56 +00:00
|
|
|
seperator ("(":rest) ((start,end):points) = case drop (end-start) rest of
|
2023-05-04 18:34:12 +00:00
|
|
|
" ":operator:" ":"(":rightRest -> case spawnBranch (extractOperator operator) (seperator (take (end-start) rest) points) (seperator (init rightRest) points) of
|
|
|
|
Left a -> Left a
|
|
|
|
Right b -> Right b
|
2023-04-28 19:08:56 +00:00
|
|
|
[] -> seperator (take (end-start) rest) points
|
2023-05-04 18:34:12 +00:00
|
|
|
a -> Left $ ParseError $ "Could not parse input, error happened at: " ++ (show (concat a))
|
|
|
|
seperator [name, " ", value, ")"] _ = case extractQueryDef (name, value) of
|
|
|
|
Left a -> Left a
|
|
|
|
Right b -> Right $ Queri $ b
|
|
|
|
seperator a _ = Left (ParseError ("Something went wrong tokenizing the input!\n" ++ (show a)))
|
|
|
|
|
|
|
|
spawnBranch :: Operator -> (Either ParseError Token) -> (Either ParseError Token) -> (Either ParseError Token)
|
|
|
|
spawnBranch _ (Left res1) _ = Left res1
|
|
|
|
spawnBranch _ _ (Left res2) = Left res2
|
|
|
|
spawnBranch operator (Right res1) (Right res2) = Right (Func operator res1 res2)
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-04-28 19:08:56 +00:00
|
|
|
|
2023-05-04 18:34:12 +00:00
|
|
|
extractQueryDef :: (String, String) -> Either ParseError QueryDef
|
|
|
|
extractQueryDef ("SuperType", value) = Right $ SuperType value
|
|
|
|
extractQueryDef ("CmcLT", value) = case readMaybe value :: Maybe Int of
|
|
|
|
Just a -> Right $ CMCLT a
|
|
|
|
Nothing -> Left $ ParseError "Could not parse number from call to CmcLT"
|
|
|
|
extractQueryDef ("CmcMT", value) = case readMaybe value :: Maybe Int of
|
|
|
|
Just a -> Right $ CMCMT a
|
|
|
|
Nothing -> Left $ ParseError "Could not parse number from call to CmcMT"
|
|
|
|
extractQueryDef ("CmcEQ", value) = case readMaybe value :: Maybe Int of
|
|
|
|
Just a -> Right $ CMCEQ a
|
|
|
|
Nothing -> Left $ ParseError "Could not parse number from call to CmcEQ"
|
|
|
|
extractQueryDef (a,b) = Left $ ParseError $ "The following command is invalid " ++ show a
|
2023-04-28 19:08:56 +00:00
|
|
|
|
2023-04-29 19:36:42 +00:00
|
|
|
extractOperator "union" = Union
|
2023-04-29 21:35:43 +00:00
|
|
|
extractOperator "intersect" = Intersect
|
2023-04-30 16:48:50 +00:00
|
|
|
extractOperator "minus" = Minus
|
2023-04-29 19:36:42 +00:00
|
|
|
extractOperator _ = error $ "This operator is not defined"
|