Sockeye: Remove debug imports
[barrelfish] / tools / sockeye / Main.hs
1 {-
2   SockeyeMain.hs: Sockeye
3
4   Copyright (c) 2017, ETH Zurich.
5
6   All rights reserved.
7
8   This file is distributed under the terms in the attached LICENSE file.
9   If you do not find this file, copies can be found by writing to:
10   ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
11   Attn: Systems Group.
12 -}
13
14 module Main where
15
16 import Control.Monad
17
18 import Data.List
19
20 import System.Console.GetOpt
21 import System.Exit
22 import System.Environment
23 import System.IO
24
25 import qualified SockeyeASTParser as ParseAST
26 import qualified SockeyeAST as AST
27 import qualified SockeyeASTDecodingNet as NetAST
28
29 import SockeyeParser
30 import SockeyeChecker
31 import SockeyeNetBuilder
32
33 import qualified SockeyeBackendProlog as Prolog
34
35 {- Exit codes -}
36 usageError :: ExitCode
37 usageError = ExitFailure 1
38
39 parseError :: ExitCode
40 parseError = ExitFailure 2
41
42 checkError :: ExitCode
43 checkError = ExitFailure 3
44
45 buildError :: ExitCode
46 buildError = ExitFailure 4
47
48 {- Compilation targets -}
49 data Target = None | Prolog
50
51 {- Possible options for the Sockeye Compiler -}
52 data Options = Options { optInputFile  :: FilePath
53                        , optTarget     :: Target
54                        , optOutputFile :: Maybe FilePath
55                        }
56
57 {- Default options -}
58 defaultOptions :: Options
59 defaultOptions = Options { optInputFile  = ""
60                          , optTarget     = Prolog
61                          , optOutputFile = Nothing
62                          }
63
64 {- Set the input file name -}
65 optSetInputFileName :: FilePath -> Options -> Options
66 optSetInputFileName f o = o { optInputFile = f }
67
68 {- Set the target -}
69 optSetTarget :: Target -> Options -> Options
70 optSetTarget t o = o { optTarget = t }
71
72 {- Set the outpue file name -}
73 optSetOutputFile :: Maybe String -> Options -> Options
74 optSetOutputFile f o = o { optOutputFile = f }
75
76 {- Prints usage information possibly with usage errors -}
77 usage :: [String] -> IO ()
78 usage errors = do
79     prg <- getProgName
80     let usageString = "Usage: " ++ prg ++ " [options] file\nOptions:"
81     hPutStrLn stderr $ usageInfo (concat errors ++ usageString) options
82     hPutStrLn stderr "The backend (capital letter options) specified last takes precedence."
83
84
85 {- Setup option parser -}
86 options :: [OptDescr (Options -> IO Options)]
87 options = 
88     [ Option "P" ["Prolog"]
89         (NoArg (\opts -> return $ optSetTarget Prolog opts))
90         "Generate a prolog file that can be loaded into the SKB (default)."
91     , Option "C" ["Check"]
92         (NoArg (\opts -> return $ optSetTarget None opts))
93         "Just check the file, do not compile."
94     , Option "o" ["output-file"]
95         (ReqArg (\f opts -> return $ optSetOutputFile (Just f) opts) "FILE")
96         "If no output file is specified the compilation result is written to stdout."
97     , Option "h" ["help"]
98         (NoArg (\_ -> do
99                     usage []
100                     exitWith ExitSuccess))
101         "Show help."
102     ]
103
104 {- evaluates the compiler options -}
105 compilerOpts :: [String] -> IO (Options)
106 compilerOpts argv =
107     case getOpt Permute options argv of
108         (actions, fs, []) -> do
109             opts <- foldl (>>=) (return defaultOptions) actions
110             case fs of
111                 []  -> do
112                     usage ["No input file\n"]
113                     exitWith usageError
114                 [f] -> return $ optSetInputFileName f opts
115                 _   -> do
116                     usage ["Multiple input files not supported\n"]
117                     exitWith usageError
118
119         (_, _, errors) -> do
120             usage errors
121             exitWith $ usageError
122
123 {- Runs the parser -}
124 parseFile :: FilePath -> IO (ParseAST.SockeyeSpec)
125 parseFile file = do
126     src <- readFile file
127     case parseSockeye file src of
128         Left err -> do
129             hPutStrLn stderr $ "Parse error at " ++ show err
130             exitWith parseError
131         Right ast -> return ast
132
133 {- Runs the checker -}
134 checkAST :: ParseAST.SockeyeSpec -> IO AST.SockeyeSpec
135 checkAST parsedAst = do
136     case checkSockeye parsedAst of 
137         Left fail -> do
138             hPutStr stderr $ show fail
139             exitWith checkError
140         Right intermAst -> return intermAst
141
142 {- Builds the decoding net from the Sockeye AST -}
143 buildNet :: AST.SockeyeSpec -> IO NetAST.NetSpec
144 buildNet ast = do
145     case sockeyeBuildNet ast of 
146         Left fail -> do
147             hPutStr stderr $ show fail
148             exitWith buildError
149         Right netAst -> return netAst
150
151 {- Compiles the AST with the appropriate backend -}
152 compile :: Target -> NetAST.NetSpec -> IO String
153 compile None     _   = return ""
154 compile Prolog   ast = return $ Prolog.compile ast
155
156 {- Outputs the compilation result -}
157 output :: Maybe FilePath -> String -> IO ()
158 output outFile out = do
159     case outFile of
160         Nothing -> putStr out
161         Just f  -> writeFile f out
162
163 main = do
164     args <- getArgs
165     opts <- compilerOpts args
166     let inFile = optInputFile opts
167     parsedAst <- parseFile inFile
168     ast <- checkAST parsedAst
169     netAst <- buildNet ast
170     out <- compile (optTarget opts) netAst
171     output (optOutputFile opts) out
172