summaryrefslogtreecommitdiff
path: root/lambda-calcul/haskell/app/Main.hs
blob: 8846c81e08fafd7a40f80065b3c20933eadf9dee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import Minilang.REPL (evaluatorFromEnv, withIO, withTerminal)
import Minilang.REPL.Types (Evaluator (..))
import Minilang.Server (startServer, waitServer)
import Options.Applicative
import System.IO (stdin, stdout)
import System.Posix.IO (stdInput)
import System.Posix.Terminal (queryTerminal)
import Text.Read (readMaybe)

data RunMode
  = Local
  | Server
  deriving (Eq, Show)

data Options = Options
  { serverPort :: Int,
    runMode    :: RunMode,
    -- | 'Nothing' means "read from MINILANG_EVAL env var".
    evalOpt    :: Maybe Evaluator
  }
  deriving (Eq, Show)

optionsParser :: ParserInfo Options
optionsParser =
  info
    (helper <*> minilangOptions)
    ( header "Minilang"
        <> fullDesc
    )

minilangOptions :: Parser Options
minilangOptions =
  Options <$> portOption <*> runModeOption <*> evalOption

portOption :: Parser Int
portOption =
  option
    auto
    ( long "port"
        <> short 'p'
        <> value 7890
        <> metavar "INT"
        <> help "port to listen on (default: 7890)"
    )

runModeOption :: Parser RunMode
runModeOption =
  flag
    Local
    Server
    ( long "server"
        <> short 'S'
        <> help "run in server mode, listening for client REPLs over HTTP"
    )

evalOption :: Parser (Maybe Evaluator)
evalOption =
  optional $
    option
      (eitherReader parseEvaluator)
      ( long "eval"
          <> short 'E'
          <> metavar "EVALUATOR"
          <> help "reduction strategy: DeBruijn (default) or NbE. \
                  \Falls back to the MINILANG_EVAL environment variable."
      )

parseEvaluator :: String -> Either String Evaluator
parseEvaluator s = case readMaybe s of
  Just ev -> Right ev
  Nothing -> Left $ "Unknown evaluator: " <> show s <> ". Valid values: DeBruijn, NbE"

main :: IO ()
main = do
  Options {..} <- execParser optionsParser
  -- CLI flag takes precedence; fall back to env var.
  ev <- maybe evaluatorFromEnv pure evalOpt
  case runMode of
    Local -> do
      hasTty <- queryTerminal stdInput
      if hasTty
        then withTerminal ev
        else withIO ev stdin stdout
    Server -> startServer serverPort ev >>= waitServer