From 76e627825c7c089c0cd95351bea3ebcae1c02c74 Mon Sep 17 00:00:00 2001 From: Steve Dunham Date: Sun, 29 Sep 2024 11:06:48 -0700 Subject: [PATCH] write output to file (if `-o`), cmd line parser, handle dup imports --- TODO.md | 3 +- src/Lib/TopContext.idr | 4 +-- src/Lib/Types.idr | 2 ++ src/Main.idr | 73 +++++++++++++++++++++++--------------- tests/black/DupImport.newt | 5 +++ 5 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 tests/black/DupImport.newt diff --git a/TODO.md b/TODO.md index 153a01b..2937238 100644 --- a/TODO.md +++ b/TODO.md @@ -34,7 +34,8 @@ I may be done with `U` - I keep typing `Type`. - [ ] do blocks - [ ] some solution for `+` problem (classes? ambiguity?) - [x] show compiler failure in the editor (exit code != 0) -- [ ] write js files into `out` directory +- [x] write output to file + - uses `-o` option - [ ] detect extra clauses in case statements - [ ] add test framework - [ ] decide what to do for erasure diff --git a/src/Lib/TopContext.idr b/src/Lib/TopContext.idr index 976b181..548152f 100644 --- a/src/Lib/TopContext.idr +++ b/src/Lib/TopContext.idr @@ -19,11 +19,11 @@ lookup nm top = go top.defs export covering Show TopContext where - show (MkTop defs metas _ _) = "\nContext:\n [\{ joinBy "\n" $ map show defs}]" + show (MkTop defs metas _ _ _) = "\nContext:\n [\{ joinBy "\n" $ map show defs}]" public export empty : HasIO m => m TopContext -empty = pure $ MkTop [] !(newIORef (MC [] 0)) False !(newIORef []) +empty = pure $ MkTop [] !(newIORef (MC [] 0)) False !(newIORef []) [] ||| set or replace def. probably need to check types and Axiom on replace public export diff --git a/src/Lib/Types.idr b/src/Lib/Types.idr index 8a7a8e8..d809084 100644 --- a/src/Lib/Types.idr +++ b/src/Lib/Types.idr @@ -342,6 +342,8 @@ record TopContext where metas : IORef MetaContext verbose : Bool errors : IORef (List Error) + ||| loaded modules + loaded : List String -- we'll use this for typechecking, but need to keep a TopContext around too. diff --git a/src/Main.idr b/src/Main.idr index e3e02b7..ee0a58a 100644 --- a/src/Main.idr +++ b/src/Main.idr @@ -25,21 +25,6 @@ import System.Directory import System.File import System.Path -{- - -import - -need to find the file. -- get base directory -- . to / -- add .newt - - - -loop back to processFile - --} - fail : String -> M a fail msg = putStrLn msg >> exitFailure @@ -58,6 +43,13 @@ dumpSource = do doc <- compile putStrLn $ render 90 doc +writeSource : String -> M () +writeSource fn = do + doc <- compile + Right _ <- writeFile fn $ render 90 doc + | Left err => fail (show err) + pure () + parseFile : String -> M (String,Module) parseFile fn = do Right src <- readFile $ fn @@ -67,15 +59,22 @@ parseFile fn = do | Left y => fail (showError src y) pure (src, res) -loadModule : String -> String -> M () -loadModule base name = do +loadModule : String -> List String -> String -> M () +loadModule base stk name = do + top <- get + -- already loaded? + let False := elem name top.loaded | _ => pure () + modify { loaded $= (name::) } let fn = base ++ "/" ++ name ++ ".newt" (src, res) <- parseFile fn putStrLn "module \{res.name}" let True = name == res.name | _ => fail "module name \{show res.name} doesn't match file name \{show fn}" -- TODO separate imports and detect loops / redundant - for_ res.imports $ \ (MkImport fc name) => loadModule base name + for_ res.imports $ \ (MkImport fc name') => do + -- we could use `fc` if it had a filename in it + when (name' `elem` stk) $ error emptyFC "import loop \{show name} -> \{show name'}" + loadModule base (name :: stk) name' -- TODO Lift the error exit, so import errors can get a FC in current file putStrLn "process Decls" @@ -92,12 +91,11 @@ processFile fn = do let parts = splitPath fn let file = fromMaybe "" $ last' parts let dir = fromMaybe "./" $ parent fn - let (base,ext) = splitFileName (fromMaybe "" $ last' parts) - putStrLn "\{show dir} \{show base} \{show ext}" - loadModule dir base + let (name,ext) = splitFileName (fromMaybe "" $ last' parts) + putStrLn "\{show dir} \{show name} \{show ext}" + loadModule dir [] name top <- get - dumpContext top - dumpSource + -- dumpContext top [] <- readIORef top.errors | errors => do @@ -106,14 +104,31 @@ processFile fn = do exitFailure pure () +cmdLine : List String -> M (Maybe String, List String) +cmdLine [] = pure (Nothing, []) +cmdLine ("-v" :: args) = do + modify { verbose := True } + cmdLine args +cmdLine ("-o" :: fn :: args) = do + (out, files) <- cmdLine args + pure (out <|> Just fn, files) + +cmdLine (fn :: args) = do + let True := ".newt" `isSuffixOf` fn + | _ => error emptyFC "Bad argument \{show fn}" + (out, files) <- cmdLine args + pure $ (out, fn :: files) + main' : M () main' = do - args <- getArgs - putStrLn "Args: \{show args}" - let (_ :: files) = args - | _ => putStrLn "Usage: newt foo.newt" - when ("-v" `elem` files) $ modify { verbose := True } - traverse_ processFile (filter (".newt" `isSuffixOf`) files) + (arg0 :: args) <- getArgs + | _ => error emptyFC "error reading args" + (out, files) <- cmdLine args + traverse_ processFile files + case out of + Nothing => pure () + Just name => writeSource name + -- traverse_ processFile (filter (".newt" `isSuffixOf`) files) out main : IO () main = do diff --git a/tests/black/DupImport.newt b/tests/black/DupImport.newt new file mode 100644 index 0000000..9377415 --- /dev/null +++ b/tests/black/DupImport.newt @@ -0,0 +1,5 @@ +module DupImport + +import Prelude +import Prelude +