|
@ -1,6 +1,8 @@ |
|
|
|
|
|
{-# LANGUAGE LambdaCase #-} |
|
|
{-# LANGUAGE BlockArguments #-} |
|
|
{-# LANGUAGE BlockArguments #-} |
|
|
{-# LANGUAGE OverloadedStrings #-} |
|
|
{-# LANGUAGE OverloadedStrings #-} |
|
|
{-# LANGUAGE ScopedTypeVariables #-} |
|
|
{-# LANGUAGE ScopedTypeVariables #-} |
|
|
|
|
|
{-# LANGUAGE DeriveAnyClass #-} |
|
|
module Main where |
|
|
module Main where |
|
|
|
|
|
|
|
|
import Control.Monad.IO.Class |
|
|
import Control.Monad.IO.Class |
|
@ -34,6 +36,8 @@ import Syntax |
|
|
|
|
|
|
|
|
import System.Console.Haskeline |
|
|
import System.Console.Haskeline |
|
|
import System.Exit |
|
|
import System.Exit |
|
|
|
|
|
import qualified Data.Set as Set |
|
|
|
|
|
import Data.Maybe |
|
|
|
|
|
|
|
|
main :: IO () |
|
|
main :: IO () |
|
|
main = do |
|
|
main = do |
|
@ -44,7 +48,7 @@ main = do |
|
|
enterReplIn env |
|
|
enterReplIn env |
|
|
Check files verbose -> do |
|
|
Check files verbose -> do |
|
|
env <- checkFiles files |
|
|
env <- checkFiles files |
|
|
when verbose $ dumpEnv (getEnv env) |
|
|
|
|
|
|
|
|
when verbose $ dumpEnv env |
|
|
Repl -> enterReplIn emptyEnv |
|
|
Repl -> enterReplIn emptyEnv |
|
|
|
|
|
|
|
|
enterReplIn :: ElabEnv -> IO () |
|
|
enterReplIn :: ElabEnv -> IO () |
|
@ -71,18 +75,28 @@ enterReplIn env = runInputT defaultSettings (loop env') where |
|
|
|
|
|
|
|
|
checkFiles :: [String] -> IO ElabEnv |
|
|
checkFiles :: [String] -> IO ElabEnv |
|
|
checkFiles files = runElab (go files ask) emptyEnv where |
|
|
checkFiles files = runElab (go files ask) emptyEnv where |
|
|
go [] k = k |
|
|
|
|
|
|
|
|
go [] k = do |
|
|
|
|
|
env <- ask |
|
|
|
|
|
for_ (Map.toList (nameMap env)) \case |
|
|
|
|
|
(_, v@Defined{}) |
|
|
|
|
|
| Set.member v (definedNames env) -> pure () |
|
|
|
|
|
| otherwise -> |
|
|
|
|
|
let |
|
|
|
|
|
pos = fromJust (Map.lookup v (whereBound env)) |
|
|
|
|
|
in withSpan (fst pos) (snd pos) $ throwElab $ DeclaredUndefined v |
|
|
|
|
|
_ -> pure () |
|
|
|
|
|
k |
|
|
go (x:xs) k = do |
|
|
go (x:xs) k = do |
|
|
code <- liftIO $ Bsl.readFile x |
|
|
code <- liftIO $ Bsl.readFile x |
|
|
case runAlex code parseProg of |
|
|
case runAlex code parseProg of |
|
|
Left e -> liftIO $ print e *> error (show e) |
|
|
Left e -> liftIO $ print e *> error (show e) |
|
|
Right prog -> do |
|
|
|
|
|
env <- ask |
|
|
|
|
|
liftIO $ runElab (checkProgram prog (go xs k)) env |
|
|
|
|
|
`catch` \e -> displayAndDie (T.decodeUtf8 (Bsl.toStrict code)) (e :: SomeException) |
|
|
|
|
|
|
|
|
Right prog -> |
|
|
|
|
|
checkProgram prog (go xs k) |
|
|
|
|
|
`catchElab` \e -> liftIO $ displayAndDie (T.decodeUtf8 (Bsl.toStrict code)) (e :: SomeException) |
|
|
|
|
|
|
|
|
dumpEnv :: Map.Map Name (NFType, Value) -> IO () |
|
|
|
|
|
dumpEnv env = for_ (Map.toList env) $ \(name, (nft, _)) -> |
|
|
|
|
|
|
|
|
dumpEnv :: ElabEnv -> IO () |
|
|
|
|
|
dumpEnv env = for_ (Map.toList (nameMap env)) $ \(_, name) -> |
|
|
|
|
|
let nft = fst $ getEnv env Map.! name in |
|
|
T.putStrLn $ render (pretty name <+> align (nest (negate 1) (colon <+> prettyTm (quote (zonk nft))))) |
|
|
T.putStrLn $ render (pretty name <+> align (nest (negate 1) (colon <+> prettyTm (quote (zonk nft))))) |
|
|
|
|
|
|
|
|
parser :: ParserInfo Opts |
|
|
parser :: ParserInfo Opts |
|
@ -109,7 +123,7 @@ displayAndDie lines e = do |
|
|
exitFailure |
|
|
exitFailure |
|
|
|
|
|
|
|
|
displayExceptions :: Text -> [Handler ()] |
|
|
displayExceptions :: Text -> [Handler ()] |
|
|
displayExceptions lines = |
|
|
|
|
|
|
|
|
displayExceptions lines = |
|
|
[ Handler \(WhileChecking a b e) -> do |
|
|
[ Handler \(WhileChecking a b e) -> do |
|
|
T.putStrLn $ squiggleUnder a b lines |
|
|
T.putStrLn $ squiggleUnder a b lines |
|
|
displayExceptions' lines e |
|
|
displayExceptions' lines e |
|
@ -140,7 +154,9 @@ displayExceptions lines = |
|
|
, Handler \(NoSuchPrimitive x) -> do |
|
|
, Handler \(NoSuchPrimitive x) -> do |
|
|
putStrLn $ "Unknown primitive: " ++ T.unpack x |
|
|
putStrLn $ "Unknown primitive: " ++ T.unpack x |
|
|
, Handler \(NotInScope x) -> do |
|
|
, Handler \(NotInScope x) -> do |
|
|
putStrLn $ "Variable not in scope: " ++ show x |
|
|
|
|
|
|
|
|
putStrLn $ "Variable not in scope: " ++ show (pretty x) |
|
|
|
|
|
, Handler \(DeclaredUndefined n) -> do |
|
|
|
|
|
putStrLn $ "Name declared but not defined: " ++ show (pretty n) |
|
|
] |
|
|
] |
|
|
|
|
|
|
|
|
displayExceptions' :: Exception e => Text -> e -> IO () |
|
|
displayExceptions' :: Exception e => Text -> e -> IO () |
|
@ -155,4 +171,7 @@ squiggleUnder (Posn l c) (Posn l' c') file |
|
|
squiggle = T.replicate c " " <> T.pack "\x1b[1;31m" <> T.replicate (c' - c) "~" <> T.pack "\x1b[0m" |
|
|
squiggle = T.replicate c " " <> T.pack "\x1b[1;31m" <> T.replicate (c' - c) "~" <> T.pack "\x1b[0m" |
|
|
|
|
|
|
|
|
in T.unlines [ padding, line, padding <> squiggle ] |
|
|
in T.unlines [ padding, line, padding <> squiggle ] |
|
|
| otherwise = T.pack (show (Posn l c, Posn l' c')) |
|
|
|
|
|
|
|
|
| otherwise = T.unlines (take (l' - l) (drop l (T.lines file))) |
|
|
|
|
|
|
|
|
|
|
|
newtype DeclaredUndefined = DeclaredUndefined { declaredUndefName :: Name } |
|
|
|
|
|
deriving (Eq, Show, Exception) |