aboutsummaryrefslogtreecommitdiff
path: root/silc.icl
diff options
context:
space:
mode:
authorCamil Staps2017-08-13 19:21:43 +0200
committerCamil Staps2017-08-13 19:21:48 +0200
commitbb762e08e950b4d6d16bf0782c3e8d689f28c5dc (patch)
treec01e0dbca3b9761a4fcadcfc34c15d4b5a0a0193 /silc.icl
parentcleanup (diff)
Improved compiler interface (#8)
Specifically: - --check, --compile and --generate are implicit, there are --no-* options to disable. - --help added. - --run removed. - Renamed to silc (sil compiler). - Output files are relative to input file.
Diffstat (limited to 'silc.icl')
-rw-r--r--silc.icl155
1 files changed, 155 insertions, 0 deletions
diff --git a/silc.icl b/silc.icl
new file mode 100644
index 0000000..4861d3c
--- /dev/null
+++ b/silc.icl
@@ -0,0 +1,155 @@
+module silc
+
+import StdBool
+import StdChar
+import StdFile
+from StdFunc import o, seq
+import StdList
+import StdOverloaded
+import StdString
+import StdTuple
+
+import Control.Applicative
+import Control.Monad
+import Data.Error
+from Data.Func import $
+import Data.Functor
+import Data.Tuple
+import System.CommandLine
+import System.Directory
+import System.File
+import System.FilePath
+import System.Process
+
+import ABC.Assembler
+
+from Sil.Check import checkProgram
+import qualified Sil.Compile as SC
+import Sil.Error
+import Sil.Parse
+from Sil.Syntax import :: Program
+import Sil.Util.Parser
+from Sil.Util.Printer import :: PrintState, instance zero PrintState,
+ class PrettyPrinter(..), instance PrettyPrinter Program
+
+:: CLI =
+ { prettyprint :: Bool
+ , check :: Bool
+ , compile :: Bool
+ , generate :: Bool
+ , help :: Bool
+ , inputfile :: Maybe String
+ }
+
+instance zero CLI
+where
+ zero =
+ { prettyprint = False
+ , check = True
+ , compile = True
+ , generate = True
+ , help = False
+ , inputfile = Nothing
+ }
+
+Start w
+#! (io,w) = stdio w
+#! err = stderr
+#! (cmd,w) = getCommandLine w
+#! (args,_) = runParser (arg until eof) $ makeParseState $ map PI_Token $ tl cmd
+| isError args
+ # err = err <<< toString (fromError args) <<< "\r\n"
+ = finish 1 io err w
+#! args = seq (fromOk args) zero
+| args.help
+ # io = io <<< HELP
+ = finish 0 io err w
+| isNothing args.inputfile
+ # err = err <<< "No input file given.\r\n"
+ = finish 1 io err w
+# infile = fromJust args.inputfile
+# (dir, module, dclfile, sysfiles, abcfile) =
+ ( dir
+ , name
+ , dir </> addExtension name "dcl"
+ , dir </> "Clean System Files"
+ , dir </> "Clean System Files" </> addExtension name "abc")
+ with
+ (dir, name) = splitFileName $ if (ext == "sil") base` infile
+ (base`, ext) = splitExtension infile
+#! (file,w) = readFile infile w
+| isError file
+ # err = err <<< "Could not open '" <<< infile <<< "' for reading.\r\n"
+ = finish 1 io err w
+#! prog = tokenise (fromString $ fromOk file) >>= parse
+| isError prog
+ # err = err <<< toString (fromError prog) <<< "\r\n"
+ = finish 1 io err w
+#! prog = fromOk prog
+#! io = if args.prettyprint
+ (io <<< print zero prog <<< "\r\n")
+ io
+#! (errs, err) = if args.check
+ (appSnd fromJust $ checkProgram (Just err) prog)
+ ([], err)
+| not (isEmpty errs)
+ = finish 1 io err w
+| not args.compile
+ = finish 0 io err w
+#! (ok,f,w) = fopen dclfile FWriteText w
+| not ok
+ # err = err <<< "Could not open '" <<< dclfile <<< "' for writing\r\n"
+ = finish 1 io err w
+#! f = f <<< "definition module " <<< module
+#! (_,w) = fclose f w
+#! (_,w) = sleep 1 w
+#! (_,w) = createDirectory sysfiles w
+#! (ok,f,w) = fopen abcfile FWriteText w
+| not ok
+ # err = err <<< "Could not open '" <<< abcfile <<< "' for writing\r\n"
+ = finish 1 io err w
+#! prog = 'SC'.compile prog
+| isError prog
+ # err = err <<< fromError prog
+ = finish 1 io err w
+#! f = f <<< fromOk prog
+#! (_,w) = fclose f w
+| not args.generate
+ = finish 0 io err w
+#! (p,w) = callProcess "/opt/clean/bin/clm" ["-l", "-no-pie", module, "-o", module] (Just dir) w
+| isError p
+ # err = err <<< snd (fromError p) <<< "\r\n"
+ = finish 1 io err w
+| fromOk p <> 0
+ = finish (fromOk p) io err w
+= finish 0 io err w
+where
+ arg :: Parser String (CLI -> CLI)
+ arg = peek >>= \opt ->
+ ( (\ cli -> {cli & prettyprint=True}) <$ anyItem ["-p", "--pretty-print"]
+ <|> (\ cli -> {cli & check=False}) <$ item "--no-check"
+ <|> (\ cli -> {cli & compile=False}) <$ item "--no-compile"
+ <|> (\ cli -> {cli & generate=False}) <$ item "--no-generate"
+ <|> (\ cli -> {cli & help=True}) <$ anyItem ["-h", "--help"]
+ <|> (\name cli -> {cli & inputfile=Just name}) <$> satisfy isFilename
+ <?> P_Invalid "command line argument" opt
+ )
+
+ HELP = "silc: simple imperative language compiler\r\n\r\n" +++
+ "Usage: silc [-p|--pretty-print] [--no-check] [--no-compile] [--no-generate] [-h|--help] [FILE]\r\n\r\n" +++
+ "\t-p, --pretty-print Pretty-print program\r\n" +++
+ "\t--no-check Do not check program for common errors\r\n" +++
+ "\t--no-compile Do not compile program to ABC-code\r\n" +++
+ "\t--no-generate Do not generate machine code from ABC-code\r\n" +++
+ "\t-h, --help Print this help\r\n"
+
+ isFilename :: (String -> Bool)
+ isFilename = all (\c -> isAlphanum c || isMember c ['./-']) o fromString
+
+ finish :: !Int !*File !*File -> *(*World -> *World)
+ finish ret io err = setReturnCode ret o snd o fclose err o snd o fclose io
+
+ sleep :: !Int !*World -> *(!Int, !*World)
+ sleep i w = code inline {
+ ccall sleep "I:I:A"
+ }