1use std::{io::IsTerminal, path::PathBuf, str::FromStr};
4
5argwerk::define! {
6 #[usage = "conlang [<file>] [-I <include...>] [-m <mode>] [-r <repl>]"]
9 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
10 pub struct Args {
11 pub file: Option<PathBuf>,
12 pub include: Vec<PathBuf>,
13 pub mode: Mode,
14 pub repl: bool = is_terminal(),
15 }
16
17 ["-I" | "--include", path] => {
19 include.push(path.into());
20 }
21 ["-m" | "--mode", flr] => {
23 mode = flr.parse()?;
24 }
25 ["-r" | "--repl", bool] => {
27 repl = bool.parse()?;
28 }
29 ["-h" | "--help"] => {
31 println!("{}", Args::help());
32 if true { std::process::exit(0); }
33 }
34 [#[option] path] if file.is_none() => {
36 file = path.map(Into::into);
37 }
38
39 [path] if file.is_some() => {
40 include.push(path.into());
41 }
42}
43
44pub fn is_terminal() -> bool {
46 std::io::stdin().is_terminal() && std::io::stdout().is_terminal()
47}
48
49#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
51pub enum Mode {
52 #[default]
53 Menu,
54 Lex,
55 Fmt,
56 Run,
57}
58
59impl FromStr for Mode {
60 type Err = &'static str;
61 fn from_str(s: &str) -> Result<Self, &'static str> {
62 Ok(match s {
63 "f" | "fmt" | "p" | "pretty" => Mode::Fmt,
64 "l" | "lex" | "tokenize" | "token" => Mode::Lex,
65 "r" | "run" => Mode::Run,
66 _ => Err("Recognized modes are: 'r' \"run\", 'f' \"fmt\", 'l' \"lex\"")?,
67 })
68 }
69}