aboutsummaryrefslogtreecommitdiffstats
path: root/src/Parser.hs
diff options
context:
space:
mode:
authorJan Tuomi <jans.tuomi@gmail.com>2022-09-25 18:00:47 +0300
committerJan Tuomi <jans.tuomi@gmail.com>2022-12-05 14:21:53 +0200
commita5ce95f40188c4525bc98307d09015a5dca93bb3 (patch)
treecb364a95ba197eabad7d1e17b95905da9a2ebcd9 /src/Parser.hs
parent6314bf6584f98c735f606155a76c809fd6de5d0b (diff)
Refactor Lib.hs
Diffstat (limited to 'src/Parser.hs')
-rw-r--r--src/Parser.hs67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/Parser.hs b/src/Parser.hs
new file mode 100644
index 0000000..62eff14
--- /dev/null
+++ b/src/Parser.hs
@@ -0,0 +1,67 @@
+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 [] \ No newline at end of file