module Parser ( parse, ) where import qualified Data.Map as M import qualified Data.List as L import Control.Monad.Except import Text.Regex.TDFA import Utils validateBalance :: [String] -> [AST] -> LContext [AST] validateBalance allowed asts = do when (ASTSymbol "(" `elem` asts && "(" `notElem` allowed) $ throwL "unbalanced function call" when (ASTSymbol "[" `elem` asts && "[" `notElem` allowed) $ throwL "unbalanced vector" when (ASTSymbol "{" `elem` asts && "{" `notElem` allowed) $ throwL "unbalanced hash map" return asts parseToken :: String -> AST parseToken token | isInteger token = ASTInteger (read token) | isDouble token = ASTDouble (read token) | isString token = ASTString $ removeQuotes token | isBoolean token = ASTBoolean $ asBoolean token | otherwise = ASTSymbol token where integerRegex = "^-?[[:digit:]]+$" isInteger :: String -> Bool isInteger t = t =~ integerRegex doubleRegex = "^-?[[:digit:]]+(\\.[[:digit:]]+)?$" isDouble :: String -> Bool isDouble t = t =~ doubleRegex isString t = "\"" `L.isPrefixOf` t removeQuotes s = drop 1 s $> take (length s - 2) isBoolean t = t `elem` ["true", "false"] asBoolean t = if t == "true" then True else False _parse :: [AST] -> [String] -> LContext [AST] _parse acc' [] = do acc <- validateBalance [] acc' return $ reverse acc _parse acc (")":rest) = do let children' = takeWhile (/= ASTSymbol "(") acc children <- validateBalance ["("] children' let fnCall = ASTFunctionCall (reverse children) let newAcc = fnCall : drop (length children + 1) acc _parse newAcc rest _parse acc ("]":rest) = do let children' = takeWhile (/= ASTSymbol "[") acc children <- validateBalance ["["] children' let vec = ASTVector (reverse children) let newAcc = vec : drop (length children + 1) acc _parse newAcc rest _parse acc ("}":rest) = do let children' = takeWhile (/= ASTSymbol "{") acc children <- validateBalance ["{"] children' pairs <- asPairsM $ reverse children let vec = ASTHashMap (M.fromList pairs) let newAcc = vec : drop (length children + 1) acc _parse newAcc rest _parse acc (token:rest) = _parse (parseToken token : acc) rest parse :: [String] -> LContext [AST] parse = _parse []