1#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
4pub enum OutputType {
5 #[default]
6 Both,
7 Jbo,
8 Loj,
9 Prolog,
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
13pub enum InputType {
14 #[default]
15 WholeText,
16 Lines,
17 Paras,
18}
19
20#[derive(Debug, Clone, Default)]
21pub struct Options {
22 pub output: OutputType,
23 pub input: InputType,
24 pub utf8: bool,
25 pub json: bool,
26 pub indicator_texticules: bool,
27 pub egglog: bool,
29}
30
31pub fn print_version() {
32 println!("1.0.0");
33}
34
35pub fn print_help() {
36 eprintln!(
37 "Usage: camxes [OPTION...] [in] [out]\n\
38 \t(use '-' for stdin/stdout)\n\
39 Options:\n\
40 \t-l --loj output logical form only\n\
41 \t-j --jbo output forethoughtful lojbanic form only\n\
42 \t-P --prolog output Prolog (SWI-Prolog) source\n\
43 \t-L --lines interpret each line as a lojban text\n\
44 \t-p --paragraphs interpret each blank-line-separated paragraph as a lojban text\n\
45 \t-u --utf8 output utf8 encoded text rather than ascii\n\
46 \t-v --version show version\n\
47 \t-h --help show help\n\
48 \t --json output one JSON object per line (NDJSON)\n\
49 \t --indicator-texticules turn supported attitudinals into side texticules\n\
50 \t-E --egglog run egglog equality-saturation analysis (adds egglog_graph to JSON)\n"
51 );
52}
53
54pub fn parse_args(args: &[String]) -> Result<(Options, Vec<String>), String> {
56 let mut opts = Options::default();
57 let mut rest = Vec::new();
58 let mut i = 0;
59 while i < args.len() {
60 let a = &args[i];
61 match a.as_str() {
62 "-h" | "--help" => {
63 print_help();
64 std::process::exit(0);
65 }
66 "-v" | "--version" => {
67 print_version();
68 std::process::exit(0);
69 }
70 "-l" | "--loj" => opts.output = OutputType::Loj,
71 "-j" | "--jbo" => opts.output = OutputType::Jbo,
72 "-P" | "--prolog" => opts.output = OutputType::Prolog,
73 "-L" | "--lines" => opts.input = InputType::Lines,
74 "-p" | "--paragraphs" => opts.input = InputType::Paras,
75 "-u" | "--utf8" => opts.utf8 = true,
76 "--json" => opts.json = true,
77 "--indicator-texticules" => opts.indicator_texticules = true,
78 "-E" | "--egglog" => opts.egglog = true,
79 "-" => rest.push(a.clone()),
81 s if s.starts_with('-') => {
82 return Err(format!("unknown option {s}\nRun with --help for usage."));
83 }
84 _ => rest.push(a.clone()),
85 }
86 i += 1;
87 }
88 Ok((opts, rest))
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn bare_dash_is_stdin_not_unknown_option() {
97 let (_opts, rest) = parse_args(&["-".to_string()]).expect("parse");
98 assert_eq!(rest, vec!["-".to_string()]);
99 }
100
101 #[test]
102 fn indicator_texticules_flag_is_opt_in() {
103 let (opts, rest) = parse_args(&["--indicator-texticules".to_string(), "in.loj".to_string()]).expect("parse");
104 assert!(opts.indicator_texticules);
105 assert_eq!(rest, vec!["in.loj".to_string()]);
106 }
107}