Files
newt/src/Main.idr
Steve Dunham 151f678f75 Work on usable codegen
- escape js names
- executable output
- better FC in parsing
- experiment with IO
2024-09-29 22:17:51 -07:00

144 lines
3.8 KiB
Idris

module Main
-- import Control.App
import Control.Monad.Error.Either
import Control.Monad.Error.Interface
import Control.Monad.State
import Data.List
import Data.String
import Data.Vect
import Data.IORef
-- import Lib.Elab
import Lib.Compile
import Lib.Parser
-- import Lib.Parser.Impl
import Lib.Prettier
import Lib.ProcessDecl
import Lib.Token
import Lib.Tokenizer
import Lib.TopContext
import Lib.Types
import Lib.Syntax
import Lib.Syntax
import System
import System.Directory
import System.File
import System.Path
fail : String -> M a
fail msg = putStrLn msg >> exitFailure
dumpContext : TopContext -> M ()
dumpContext top = do
putStrLn "Context:"
go top.defs
putStrLn "---"
where
go : List TopEntry -> M ()
go [] = pure ()
go (x :: xs) = putStrLn " \{show x}" >> go xs
dumpSource : M ()
dumpSource = do
doc <- compile
putStrLn $ render 90 doc
writeSource : String -> M ()
writeSource fn = do
doc <- compile
let src = "#!/usr/bin/env node\n" ++ render 90 doc ++ "\nmain();"
Right _ <- writeFile fn src
| Left err => fail (show err)
Right _ <- chmodRaw fn 493 | Left err => fail (show err)
pure ()
parseFile : String -> M (String,Module)
parseFile fn = do
Right src <- readFile $ fn
| Left err => fail (show err)
let toks = tokenise src
let Right res = parse parseMod toks
| Left y => fail (showError src y)
pure (src, res)
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') => 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"
Right _ <- tryError $ traverse_ processDecl (collectDecl res.decls)
| Left y => fail (showError src y)
pure ()
processFile : String -> M ()
processFile fn = do
putStrLn "*** Process \{fn}"
(src, res) <- parseFile fn
putStrLn "module \{res.name}"
let parts = splitPath fn
let file = fromMaybe "" $ last' parts
let dir = fromMaybe "./" $ parent fn
let (name,ext) = splitFileName (fromMaybe "" $ last' parts)
putStrLn "\{show dir} \{show name} \{show ext}"
loadModule dir [] name
top <- get
-- dumpContext top
[] <- readIORef top.errors
| errors => do
for_ errors $ \err =>
putStrLn (showError src err)
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
(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
-- we'll need to reset for each file, etc.
ctx <- empty
Right _ <- runEitherT $ runStateT ctx $ main'
| Left (E (c, r) str) => do
putStrLn "ERROR at (\{show c}, \{show r}): \{show str}"
exitFailure
putStrLn "done"