packages feed

morloc-0.33.0: executable/Subcommands.hs

{-# LANGUAGE OverloadedStrings #-}

{-|
Module      : Subcommands
Description : Morloc executable subcommands
Copyright   : (c) Zebulun Arendsee, 2020
License     : GPL-3
Maintainer  : zbwrnz@gmail.com
Stability   : experimental
-}
module Subcommands
  ( getConfig
  , cmdInstall
  , cmdMake
  , cmdRemove
  , cmdTypecheck
  ) where

import Morloc.Namespace
import System.Console.Docopt
import qualified Morloc as M
import qualified Morloc.Config as Config
import qualified Morloc.Data.Text as MT
import qualified Morloc.Module as Mod
import qualified Morloc.Monad as MM
import qualified Morloc.Frontend.API as F

type Subcommand = Arguments -> Config.Config -> IO ()

getArgOrDie :: Arguments -> Option -> MT.Text
getArgOrDie args opt =
  case getArg args opt of
    Nothing -> error ("Invalid command: Expected option '" <> show opt)
    (Just x) -> MT.pack x

-- | read the global morloc config file or return a default one
getConfig :: Arguments -> IO Config.Config
getConfig args = do
  let givenPath = getArg args (longOption "config")
  let isVanilla = isPresent args (longOption "vanilla")
  defaultPath <- Config.getDefaultConfigFilepath
  let configPath =
        if isVanilla
          then Nothing
          else case givenPath of
                 (Just f) -> Just . Path . MT.pack $ f
                 Nothing -> Just defaultPath
  -- load the config file
  Config.loadMorlocConfig configPath

getVerbosity :: Arguments -> Int
getVerbosity args =
  if isPresent args (longOption "verbose")
    then 1
    else 0

-- | handle the code, either from a file or a raw string
readScript :: Arguments -> IO (Maybe Path, Code)
readScript args = do
  let input = getArgOrDie args (argument "script")
  if isPresent args (longOption "expression") 
  then do
    let code = Code input 
    return (Nothing, code)
  else do
    let filename = Path input
    code <- fmap Code $ MT.readFile (MT.unpack input)
    return (Just filename, code)

-- | install a module
cmdInstall :: Subcommand
cmdInstall args conf =
  (MM.runMorlocMonad (getVerbosity args) conf cmdInstall') >>= MM.writeMorlocReturn
  where
    cmdInstall' = do
      let name = getArgOrDie args (argument "name")
      if isPresent args (longOption "github")
        then Mod.installModule (Mod.GithubRepo name)
        else Mod.installModule (Mod.CoreGithubRepo name)

-- | remove a previously installed module (NOT YET IMPLEMENTED)
cmdRemove :: Subcommand
cmdRemove _ _ = do
  putStrLn "not removing anything"

-- | build a Morloc program, generating the nexus and pool files
cmdMake :: Subcommand
cmdMake args config = do
  (path, code) <- readScript args
  MM.runMorlocMonad (getVerbosity args) config (M.writeProgram path code) >>=
    MM.writeMorlocReturn

cmdTypecheck :: Subcommand
cmdTypecheck args config = do
  let expr = getArgOrDie args (argument "script")
  expr' <-
    if isPresent args (longOption "expression")
      then return expr
      else MT.readFile (MT.unpack expr)
  let base =
        if isPresent args (longOption "expression")
          then Nothing
          else Just (Path expr)
  let writer =
        if isPresent args (longOption "raw")
          then F.ugly
          else F.cute
  if isPresent args (longOption "type")
    then print $ F.readType expr'
    else MM.runMorlocMonad
           (getVerbosity args)
           config
           (M.typecheck base (Code expr') >>= MM.liftIO . writer) >>=
         MM.writeMorlocReturn