-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathLinter.hs
executable file
·148 lines (126 loc) · 4.77 KB
/
Linter.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
136
137
138
139
140
141
142
143
144
145
146
147
148
module Main where
import System.Environment
import System.IO
import Control.Monad
import Data.List
import Data.Either
import AST
import Parser
import PrettyPrint
import Lintings
import LintTypes
debug = False
data Action = Compile | Suggest | SuggestAST
main = do
args <- getArgs
let (eAction, args1) = actionFromFlag args
let (eLint, args2) = lintFromFlag args1
let eFilename = fileNameFromArgs args2
let eRes = do
a <- eAction
l <- eLint
f <- eFilename
return $ lint l a f
either (\err -> putStrLn err >> putStrLn usage) id eRes
sep = putStrLn $ replicate 80 '-'
actionFromFlag :: [String] -> (Either String Action, [String])
actionFromFlag ("-c" : xs) = (Right Compile, xs)
actionFromFlag ("-s" : xs) = (Right Suggest, xs)
actionFromFlag ("-v" : xs) = (Right SuggestAST, xs)
actionFromFlag (x : xs) | "-" `isPrefixOf` x =
(Left $ "Acción no reconocida: " ++ x, xs)
actionFromFlag _ = (Left "Debe especificar una acción", [])
lintFromFlag :: [String] -> (Either String (Linting FunDef), [String])
lintFromFlag ("-lintComputeConstant" : xs) =
(Right $ liftToFunc lintComputeConstant, xs)
lintFromFlag ("-lintRedBool" : xs) = (Right $ liftToFunc lintRedBool, xs)
lintFromFlag ("-lintRedIfCond" : xs) = (Right $ liftToFunc lintRedIfCond, xs)
lintFromFlag ("-lintRedIfAnd" : xs) = (Right $ liftToFunc lintRedIfAnd, xs)
lintFromFlag ("-lintRedIfOr" : xs) = (Right $ liftToFunc lintRedIfOr, xs)
lintFromFlag ("-lintNull" : xs) = (Right $ liftToFunc lintNull, xs)
lintFromFlag ("-lintAppend" : xs) = (Right $ liftToFunc lintAppend, xs)
lintFromFlag ("-lintComp" : xs) = (Right $ liftToFunc lintComp, xs)
lintFromFlag ("-lintEta" : xs) = (Right $ liftToFunc lintEta, xs)
lintFromFlag ("-lintMap" : xs) = (Right lintMap, xs)
lintFromFlag (x : xs) | "-" `isPrefixOf` x =
(Left $ "Linting no reconocido: " ++ x, xs)
lintFromFlag xs = (Right allLints, xs)
fileNameFromArgs :: [String] -> Either String String
fileNameFromArgs [x] = Right x
fileNameFromArgs [] = Left "Debe especificar un archivo"
fileNameFromArgs _ = Left "Debe especificar un único archivo"
lint lints action filename = do
p <- readFile filename
when debug $ (putStrLn $ "recognized:\n" ++ p) >> sep >> sep
case parser p of
Left error -> do
putStrLn "error de parsing:"
putStrLn $ show $ error
Right program@(Program funcs) ->
case action of
Suggest -> do
lintSugg pp lints program
when
debug
((>>) sep $ putStrLn $
pp $
Program $ map (optimizeAllFunc lints) funcs)
when debug $ putStrLn $ show program
when debug $ putStrLn $ show
$ Program $ map (optimizeAllFunc lints) funcs
SuggestAST -> do
lintSugg show lints program
when
debug
((>>) sep $ putStrLn $
pp $
Program $ map (optimizeAllFunc lints) funcs)
when debug $ putStrLn $ show program
when debug $ putStrLn $ show
$ Program $ map (optimizeAllFunc lints) funcs
Compile ->
putStrLn $
pp $
Program $ map (optimizeAllFunc lints) funcs
lintSugg' lint (Program funcs) =
sequence_ $ map (lintFuncSugg' lint) funcs
lintSugg :: (LintSugg -> String) -> Linting FunDef -> Program -> IO ()
lintSugg disp lint (Program funcs) =
sequence_ $ map (lintFuncSugg disp lint) funcs
lintFuncSugg' lint f@(FunDef name body) = do
putStrLn $ "Función: " ++ name
mapM_ putStrLn $ nilv "Sin sugerencias." $ map pp $ snd $ lintRec lint f
sep
lintFuncSugg disp lint f@(FunDef name body) = do
putStrLn $ "Función: " ++ name
mapM_ putStrLn $ nilv "Sin sugerencias." $ map disp $ snd $ lintRec lint f
sep
nilv :: a -> [a] -> [a]
nilv v [] = [v]
nilv _ xs = xs
allLints =
liftToFunc lintComputeConstant
>==> liftToFunc lintRedBool
>==> liftToFunc lintRedIfCond
>==> liftToFunc lintRedIfAnd
>==> liftToFunc lintRedIfOr
>==> liftToFunc lintNull
>==> liftToFunc lintAppend
>==> liftToFunc lintComp
>==> liftToFunc lintEta
>==> lintMap
optimizeAllFunc lints = fst . lintRec lints
usage =
"Instrucciones:\n"
++ "Linter (-s | -v | -c) {flag} <fuente> (compilado)\n"
++ "runhaskell Linter.hs (-s | -v | -c) {flag} <fuente> (interpretado)\n"
++ "Opciones (exactamente una):\n"
++ " -s: imprime sugerencias en la salida estandar\n"
++ " -v: imprime el AST de las sugerencias en la salida estandar\n"
++ " -c: aplica las sugerencias e imprime el programa resultante\n"
++ "Banderas (a lo sumo una): -<nombre lint>"
++ "ejemplos:\n"
++ "Linter -c ejemplos/ejemplo3.mhs\n"
++ "Linter -s ejemplos/ejemplo3.mhs\n"
++ "Linter -v ejemplos/ejemplo3.mhs\n"
++ "Linter -s -lintEta ejemplos/ejemplo3.mhs\n"