Advertisement
Guest User

oh god why

a guest
Aug 11th, 2018
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import System.IO
  2. import Control.Monad
  3. import Control.Arrow
  4. import Data.List (break, find, unfoldr)
  5. import System.Environment
  6. import qualified System.Console.Terminal.Size as TS
  7. import Data.Map (empty, insert, adjust, keys, findWithDefault, lookup, fromList, Map)
  8.  
  9. data Var = I Int | S String | P String | B Bool | N (IO ())
  10. data Graph = Edge String [Path] | Func [Path] | Orphan String | Label String | Return deriving Show
  11. data Path = Choice [String] [String] Graph String | Auto [String] [String] | Exec [String] [String] Graph | Print String deriving Show
  12.  
  13. instance Show Var where
  14.     show (B x) = show x
  15.     show (I x) = show x
  16.     show (S x) = x
  17.     show (P x) = x
  18.     show (N _) = "()"
  19.    
  20. instance Eq Var where
  21.     (I a) == (I b) = a == b
  22.     (S a) == (S b) = a == b
  23.     (B a) == (B b) = a == b
  24.     _ == _ = False
  25.  
  26. instance Ord Var where
  27.     compare (I a) (I b) | a == b = EQ
  28.                         | a > b = GT
  29.                         | a < b = LT
  30.  
  31. xor True False  = True
  32. xor False True  = True
  33. xor True True   = False
  34. xor False False = False
  35.  
  36. wordWrap Nothing string = string
  37. wordWrap (Just x) string = wordWrap' (TS.width x) string
  38. wordWrap' w = foldl1 (wrapper w) . words where
  39.     lastLine        = length . last . lines
  40.     wrapper w acc x = if lastLine acc + length x + 1 >= w then acc ++ "\n" ++ x else acc ++ " " ++ x
  41.  
  42. nodeMap = fromList . decompose . fst . murder ([], []) . map words . filter ((/=) '#' . head) . filter (/= "") . lines where
  43.     decompose = map (extractLabel &&& processGraph) . map splitColons
  44.     murder = foldr (\x (a, c) -> if (head x `elem` ["function", "node"]) then ((x:c) : a, []) else (a, x : c))
  45. findNode file k = findWithDefault (Orphan "ERROR: Label not found!") k $ nodeMap file
  46.  
  47. lookupVar :: String -> Map String Var -> Var
  48. lookupVar k m = lookupVar' (fst $ break (=='_') k) (Data.Map.lookup k m) where
  49.    lookupVar' y (Just x)     = x
  50.     lookupVar' "s" Nothing    = S ""
  51.    lookupVar' "i" Nothing    = I 0
  52.     lookupVar' "b" Nothing    = B False
  53.  
  54. reader vars "true"  = B True
  55. reader vars "false" = B False
  56. reader vars x | all (flip elem ['-','0','1','2','3','4','5','6','7','8','9']) x = I (read x)
  57.              | head x == '"' && last x == '"'                                  = S x
  58.              | otherwise                                                       = lookupVar x vars
  59.  
  60. splitColons = map (unfoldr (\x -> if (length x > 0) then (Just $ (id *** (\z -> if (length z > 0) then (tail z) else z)) $ break (==":") x) else Nothing))
  61.  
  62. substituteVars vars string = unwords $ map (\x -> if (x `elem` keys vars) then (show $ lookupVar x vars) else x) $ words string
  63.  
  64. unVarB (B x) = x
  65. unVarI (I x) = x
  66. unVarS (S x) = x
  67.  
  68. adjustWithDefault :: Ord k => a -> (a -> a) -> k -> Map k a -> Map k a
  69. adjustWithDefault d f k m = if k `notElem` keys m then insert k (f d) m else insert k (f $ findWithDefault d k m) m
  70.    
  71. execute vars = foldr execute' (vars, []) where
  72.     execute' "=" (v, xs)   = (v, (P "="):xs)
  73.    execute' "++" (v, xs)   = (v, (P "++"):xs)
  74.     execute' "--" (v, xs)   = (v, (P "--"):xs)
  75.    execute' "+=" (v, xs)   = (v, (P "+="):xs)
  76.     execute' "-=" (v, xs)   = (v, (P "-="):xs)
  77.    execute' "*=" (v, xs)   = (v, (P "*="):xs)
  78.     execute' "/=" (v, xs)   = (v, (P "/="):xs)
  79.    execute' "%=" (v, xs)   = (v, (P "%="):xs)
  80.     execute' x (v, P "=":y:xs)      = (insert x y v, xs)
  81.    execute' x (v, (P "++"):xs)     = (adjustWithDefault (I 0) (I . succ . unVarI) x v, xs)
  82.     execute' x (v, (P "--"):xs)     = (adjustWithDefault (I 0) (I . pred . unVarI) x v, xs)
  83.    execute' x (v, (P "+="):y:xs)   = (adjustWithDefault (I 0) (I . (+) (unVarI y) . unVarI) x v, xs)
  84.     execute' x (v, (P "-="):y:xs)   = (adjustWithDefault (I 0) (I . (flip (-)) (unVarI y) . unVarI) x v, xs)
  85.    execute' x (v, (P "*="):y:xs)   = (adjustWithDefault (I 0) (I . (*) (unVarI y) . unVarI) x v, xs)
  86.     execute' x (v, (P "/="):y:xs)   = (adjustWithDefault (I 0) (I . (flip div) (unVarI y) . unVarI) x v, xs)
  87.    execute' x (v, (P "mod="):y:xs) = (adjust (I . (flip mod) (unVarI y) . unVarI) x v, xs)
  88.     execute' "set" (v, x:y:xs)      = (insert (read $ unVarS x) y v, xs)
  89.    execute' "setT" (v, x:xs)       = (insert (read $ unVarS x) (B True) v, xs)
  90.     execute' "setF" (v, x:xs)       = (insert (read $ unVarS x) (B False) v, xs)
  91.    execute' "succ" (v, x:xs)       = (adjustWithDefault (I 0) (I . succ . unVarI) (read $ unVarS x) v, xs)
  92.     execute' "pred" (v, x:xs)       = (adjustWithDefault (I 0) (I . pred . unVarI) (read $ unVarS x) v, xs)
  93.    execute' "if" (v, z:x:y:xs)     = if (unVarB z) then (v, x:xs) else (v, y:xs)
  94.     execute' "eq" (v, x:y:xs)       = (v, B (x == y) : xs)
  95.    execute' "lt" (v, x:y:xs)       = (v, B (x < y) : xs)
  96.     execute' "gt" (v, x:y:xs)       = (v, B (x > y) : xs)
  97.    execute' "le" (v, x:y:xs)       = (v, B (x <= y) : xs)
  98.     execute' "ge" (v, x:y:xs)       = (v, B (x >= y) : xs)
  99.    execute' "and" (v, x:y:xs)      = (v, B (unVarB x && unVarB y) : xs)
  100.     execute' "or" (v, x:y:xs)       = (v, B (unVarB x || unVarB y) : xs)
  101.    execute' "xor" (v, x:y:xs)      = (v, B (unVarB x `xor` unVarB y) : xs)
  102.     execute' "not" (v, x:xs)        = (v, B (not $ unVarB x) : xs)
  103.    execute' "plus" (v, x:y:xs)     = (v, I (unVarI x + unVarI y) : xs)
  104.     execute' "minus" (v, x:y:xs)    = (v, I (unVarI x - unVarI y) : xs)
  105.    execute' "mult" (v, x:y:xs)     = (v, I (unVarI x * unVarI y) : xs)
  106.     execute' "div" (v, x:y:xs)      = (v, I (unVarI x `div` unVarI y) : xs)
  107.    execute' "mod" (v, x:y:xs)      = (v, I (unVarI x `mod` unVarI y) : xs)
  108.     execute' "print" (v, x:xs)      = (v, N (print $ unVarS x) : xs)
  109.    execute' x (v, xs)              = (v, (reader v x):xs)
  110.    
  111. extractType = head . head . head
  112. extractLabel = head . tail . head . head
  113. extractIntro = unwords . head . tail . head
  114. extractChoices = tail
  115. extractor s q              = if (z == Nothing) then [] else (\(Just j) -> tail j) z where z = find (\x -> head x == s) q
  116. extractConditionChoice     = extractor "show"
  117. extractActionChoice        = extractor "choice"
  118. extractConditionFunction   = extractor "exec"
  119. extractActionFunction      = extractor "do"
  120.  
  121. extractTarget :: [[String]] -> Maybe [[Char]]
  122. extractTarget = find (\x -> head x == "goto" || head x == "return")
  123. makePathFunction c a Nothing  = Auto c a
  124. makePathFunction c a (Just x) = if (head x == "goto") then Exec c a (Label $ head $ tail x) else Exec c a Return
  125. makePathChoice c a (Just x) l = if (head x == "goto") then Choice c a (Label $ head $ tail x) l else Choice c a Return l
  126. makePath c               = if (extractActionFunction c /= []) then makePathFunction (extractConditionFunction c) (extractActionFunction c) (extractTarget c) else makePathChoice (extractConditionChoice c) (extractActionChoice c) (extractTarget c) (unwords $ last c)
  127.  
  128. processGraph x = if (extractType x == "node") then (if (length (extractChoices x) == 0) then Orphan (extractIntro x) else Edge (extractIntro x) (map makePath $ extractChoices x)) else Func (map makePath $ extractChoices x)
  129.  
  130. unfoldGraph file (Orphan a) = Orphan a
  131. unfoldGraph file Return     = Return
  132. unfoldGraph file (Label a)  = unfoldGraph file $ findNode file a
  133. unfoldGraph file (Edge intro actions) = Edge intro $ map (transformPath file) actions
  134. unfoldGraph file (Func actions)       = Func $ map (transformPath file) actions
  135.  
  136. transformPath file (Choice a b g d)    = Choice a b (unfoldGraph file g) d
  137. transformPath file (Exec a b g)        = Exec a b (unfoldGraph file g)
  138. transformPath file (Auto a b)          = Auto a b
  139.  
  140. expandGraph file = unfoldGraph file . findNode file
  141.  
  142. checkChoice (Choice _ _ _ _) = True
  143. checkChoice _                = False
  144. checkExec (Exec _ _ _)       = True
  145. checkExec _                  = False
  146. checkAuto (Auto _ _)         = True
  147. checkAuto _                  = False
  148. checkPrint (Print _)         = True
  149. checkPrint _                 = False
  150.  
  151. nextGraph (Choice _ _ g _)   = g
  152. nextGraph (Exec _ _ g)       = g
  153.  
  154. walkGraph size vars (x:y:xs, Return)         = walkGraph size vars (xs, y)
  155. walkGraph size vars (_, Orphan a)            = do
  156.     putStrLn $ wordWrap size $ substituteVars vars a
  157.     putStrLn "Press enter to exit..."
  158.     getLine
  159. walkGraph size vars (xs, Func actions)       = walkFunc size vars (Func actions : xs, filter checkAuto actions, find checkValid actions) where
  160.     checkValid (Exec cond _ _) = and $ map unVarB $ snd $ execute vars cond
  161.     checkValid _ = False
  162. walkGraph size vars (xs, Edge intro actions) = walkEdge size vars (Edge intro actions : xs, filter checkAuto actions, intro, filter checkChoice actions)
  163.  
  164. runAuto acc (Auto cond f) = if (and $ map unVarB $ snd $ execute acc cond) then (fst $ execute acc f) else acc
  165. walkFunc size vars (xs, autos, Just exec) = walkExec size (foldl runAuto vars autos) (xs, exec)
  166.    
  167. walkExec size vars (xs, Exec cond f g) = walkGraph size (if (and $ map unVarB $ snd $ execute vars cond) then (fst $ execute vars f) else vars) (xs, g)
  168. walkEdge size vars (xs, autos, intro, choices) = walkChoice size (foldl runAuto vars autos) (xs, intro, choices)
  169.  
  170. walkChoice size vars (xs, intro, choices) = do
  171.     putStrLn $ wordWrap size $ substituteVars vars intro
  172.     valid <- return $ filter (\(Choice cond _ _ _) -> and $ map unVarB $ snd $ execute vars cond) choices
  173.     if (length valid > 1)
  174.         then do
  175.               mapM_ (\(a, Choice _ _ _ label) -> putStrLn $ wordWrap size $ show a ++ ". " ++ (substituteVars vars label)) $ zip [1..length valid] valid
  176.               r <- getLine
  177.               (Choice cond f g label) <- return $ valid !! (pred $ read r)
  178.               walkGraph size (fst $ execute vars f) (xs, g)
  179.         else do
  180.               (Choice cond f g label) <- return $ head valid
  181.               putStrLn $ wordWrap size $ substituteVars vars label
  182.               getLine
  183.               walkGraph size (fst $ execute vars f) (xs, g)
  184.    
  185. main = do
  186.     args <- getArgs
  187.     handle <- openFile (head args) ReadMode
  188.     contents <- hGetContents handle
  189.     size <- TS.size
  190.     walkGraph size empty $ ([], expandGraph contents "_start")
  191.     hClose handle
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement