-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMain.hs
135 lines (120 loc) · 4.37 KB
/
Main.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
-- This module is for testing only. Code is uglier than in main files.
module Main (main) where
import AbsUtil (stringToDecs)
import Control.Monad
import Control.Monad.IO.Class (liftIO)
import Core (builtinVals)
import Data.Either (isRight, rights)
import Data.Function
import Data.List (intercalate, isInfixOf, isPrefixOf, sort)
import qualified Data.Map as Map
import qualified Data.Text as Text
import Eval (EvalState (typeState), emptyEvalState, evalString, insertBuiltins, printVars, runEvalM)
import ParSyntax
import Preprocess (transTree)
import PrintSyntax (printTree)
import System.Directory (listDirectory)
import System.Exit (exitFailure)
import Typecheck (TypeState (globBinds), runTypecheckM, typecheckDecLst)
import Util
groupLines :: [String] -> [[String]]
groupLines [] = []
groupLines lines =
let (group, rest) = break null lines
in group : case rest of
[] -> []
(_ : xs) -> groupLines xs
allEqual :: (Eq a) => [a] -> Bool
allEqual xs = case xs of
[] -> True
x : xs' -> all (== x) xs'
replace :: String -> String -> String -> String
replace a a' s = Text.replace (p a) (p a') (p s) & unp
where
p = Text.pack; unp = Text.unpack
doTest :: String -> (String -> IO (Either a b)) -> (a -> String) -> (b -> String) -> IO ()
doTest inputFile makeResult showLeft showRight = do
putStrLn $ "suite: " ++ inputFile
suite <- readFile inputFile
let groups = suite & lines & filter (not . ("--" `isPrefixOf`)) & groupLines
mapM_ testGroup groups
where
process line = line & replace "#" "" & makeResult
printTree2 = either showLeft showRight
isLineOk line tree = do
let shouldBeOk = not $ "#" `isInfixOf` line
let isOk = tree & isRight
if shouldBeOk /= isOk
then do
putStrLn $ ansiRed ++ (if shouldBeOk then "This should be ok:" else "This shouldn't be ok:") ++ ansiDefault
putStrLn $ ansiBrightWhite ++ " " ++ line ++ ansiDefault
putStrLn $ " " ++ printTree2 tree
return False
else return True
testGroup :: [String] -> IO Bool
testGroup lines = do
trees <- lines & mapM process
let treesPrinted = trees & rights & map showRight
let allMatch = treesPrinted & allEqual
allOk <- zipWithM isLineOk lines trees & fmap and
unless
allMatch
( do
putStrLn $ ansiRed ++ "Results don't match:" ++ ansiDefault
zipWithM_
( \line tree -> do
putStrLn $ ansiBrightWhite ++ " " ++ line ++ ansiDefault
putStrLn $ " " ++ printTree2 tree
)
lines
trees
)
return (allOk && allMatch)
getType :: String -> IO (Either String String)
getType s = do
case (fmap transTree . pListDec . myLexer) s of
Left x -> return $ Left x
Right decs -> do
(Right (_, evalState)) <- runEvalM (insertBuiltins builtinVals) emptyEvalState
let ts = typeState evalState
typeRet <- liftIO $ runTypecheckM (typecheckDecLst decs) ts
case typeRet of
Left (err, _) -> return $ Left $ "type error: " ++ err
Right (_, typeState) -> do
let a = globBinds ts
let b = globBinds typeState
let c = b Map.\\ a
return $ Right $ c & Map.toAscList & map (\(a, b) -> a ++ " : " ++ show b) & intercalate " ; "
getVal :: String -> IO (Either String String)
getVal s = do
(Right (_, evalState)) <- runEvalM (insertBuiltins builtinVals) emptyEvalState
(Right (vars, _)) <- runEvalM printVars evalState
ret <- runEvalM (evalString s) evalState
case ret of
Left err -> return $ Left err
Right (_, evalState') -> do
(Right (vars', _)) <- runEvalM printVars evalState'
return $ Right $ diffLines vars vars' & unlines
doLongTests :: IO ()
doLongTests = do
ok <- listDirectory "good" & fmap sort
mapM_
( ( \file -> do
s <- readFile file
v <- getVal s
case v of
Left err -> putStrLn $ ansiRed ++ "error when executing " ++ show file ++ ": " ++ err ++ ansiDefault
Right _ -> putStrLn $ ansiGreen ++ "executed " ++ show file ++ ansiDefault
return ()
)
. ("good/" ++)
)
ok
main :: IO ()
main = do
doTest "test/test_grammar.txt" (return . pListDec . myLexer) id printTree
doTest "test/test_preprocessor.txt" (return . stringToDecs) id printTree
doTest "test/test_typecheck.txt" getType id id
doTest "test/test_interpreter.txt" getVal id id
doLongTests
exitFailure