packages feed

ntha-0.1.0: app/Main.hs

module Main where

import Paths_ntha
import Ast (Expr(..), EPath, isImport)
import Type (Type(..))
import Eval (eval)
import Infer (analyze)
import Refined (checker)
import Parser (parseExpr)
import Value (ValueScope(..), Value(..))
import TypeScope (TypeScope(..))
import Prologue (assumptions, builtins)
import Control.Lens
import Control.Monad (foldM)
import Control.Monad.Trans
import System.Environment
import System.Console.Haskeline
import Data.List (intercalate)
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Control.Exception as E

type Env = (TypeScope, ValueScope)

emptyEnv :: (TypeScope, ValueScope)
emptyEnv = (TypeScope Nothing M.empty, ValueScope Nothing M.empty)

loadFile :: Env -> EPath -> IO Env
loadFile env path = do
  file <- getDataFileName path
  fileContent <- readFile file
  (env', _, _) <- process' env $ parseExpr fileContent
  return env'

loadImport :: Env -> Expr -> IO (Env, Expr)
loadImport env expr = case expr of
  EProgram instructions -> do
    let imports = filter isImport instructions
    let continueAst = EProgram $ filter (not . isImport) instructions
    importEnv <- foldM (\env (EImport path) -> loadFile env path) env imports
    return (importEnv, continueAst)
  _ -> return (env, expr)

loadLib :: IO Env
loadLib = do
  assumps <- assumptions
  loadFile (assumps, builtins) "lib/std.ntha"

process' :: Env -> Expr -> IO (Env, Value, Type)
process' env expr = do
   ((importAssumps, importBuiltins), ast) <- loadImport env expr
   (assumps', t) <- analyze ast importAssumps S.empty
   checker ast assumps'
   let (builtins', v) = eval ast importBuiltins
   return ((assumps', builtins'), v, t)

process :: Env -> String -> IO Env
process env@(assumps, prevBuiltins) expr =
  E.catch (do
           (env', v, t) <- process' env $ parseExpr expr
           putStrLn $ show v ++ " : " ++ show t
           return env')
          (\(E.ErrorCall e) -> do
           putStrLn e
           return (assumps, prevBuiltins))

loop :: Env -> InputT IO Env
loop env = do
  minput <- getInputLine "λ> "
  case minput of
    Nothing -> do
      outputStrLn "Goodbye."
      return emptyEnv
    Just input -> (liftIO $ process env input) >>= (\env' -> loop env')

prologueMessage :: String
prologueMessage = intercalate "\n"
  ["      _   __   __     __",
   "     / | / /  / /_   / /_   ____ _",
   "    /  |/ /  / __/  / __ \\ / __ `/",
   "   / /|  /  / /_   / / / // /_/ /",
   "  /_/ |_/   \\__/  /_/ /_/ \\__,_/",
   ""
   ]

main :: IO Env
main = do
  env <- loadLib
  args <- getArgs
  case (args ^? element 0) of
    Just arg -> if arg == "repl"
                then repl env
                else do
                  file <- readFile arg
                  process env file
    Nothing -> repl env
  where repl ev = do putStrLn prologueMessage
                     runInputT defaultSettings (loop ev)