1use crate::*;
2use mech_core::*;
3use nom::{
4 IResult,
5 bytes::complete::tag,
6 branch::alt,
7 bytes::complete::{take_while, take_until, take_till1},
8 combinator::{opt, not},
9 multi::{separated_list1, separated_list0},
10 character::complete::{space0,space1,digit1},
11 sequence::tuple as nom_tuple,
12};
13
14#[derive(Debug, Clone)]
15pub enum ReplCommand {
16 Help,
17 Quit,
18 Save(String),
22 Docs(Option<String>),
23 Code(Vec<(String,MechSourceCode)>),
24 Ls,
25 Cd(String),
26 Step(Option<usize>,Option<u64>),
27 Load(Vec<String>),
28 Whos(Vec<String>),
29 Plan,
30 Symbols(Option<String>),
31 Clear(Option<String>),
32 Clc,
33 }
36
37pub fn parse_repl_command(input: &str) -> IResult<&str, ReplCommand> {
38 let (input, _) = tag(":")(input)?;
39 let (input, command) = alt((
40 cd_rpl,
41 step_rpl,
42 clear_rpl,
43 clc_rpl,
44 load_rpl,
45 code_rpl,
46 help_rpl,
47 quit_rpl,
48 save_rpl,
49 symbols_rpl,
50 plan_rpl,
51 ls_rpl,
52 whos_rpl,
53 docs_rpl,
54 ))(input)?;
55 let (input, _) = opt(tag("\r\n"))(input)?;
56 if !input.is_empty() {
57 return Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Eof)));
58 }
59 Ok((input, command))
60}
61
62fn save_rpl(input: &str) -> IResult<&str, ReplCommand> {
63 let (input, _) = tag("save")(input)?;
64 let (input, _) = space1(input)?;
65 let (input, path) = take_while(|c: char| c.is_alphanumeric() || c == '/' || c == '.' || c == '_')(input)?;
66 Ok((input, ReplCommand::Save(path.to_string())))
67}
68
69fn code_rpl(input: &str) -> IResult<&str, ReplCommand> {
70 let (input, _) = alt((tag("code"), tag("c")))(input)?;
71 let (input, _) = space0(input)?;
72 let (input, code) = take_while(|_| true)(input)?;
73 Ok((input, ReplCommand::Code(vec![("repl".to_string(), MechSourceCode::String(code.to_string()))])))
74}
75
76fn docs_rpl(input: &str) -> IResult<&str, ReplCommand> {
77 let (input, _) = alt((tag("docs"), tag("d")))(input)?;
78 let (input, _) = space0(input)?;
79 let (input, name) = opt(take_till1(|c| c == '\r' || c == '\n'))(input)?;
80 let name = name.map(|s| s.to_string());
81 Ok((input, ReplCommand::Docs(name)))
82}
83
84fn help_rpl(input: &str) -> IResult<&str, ReplCommand> {
85 let (input, _) = alt((tag("help"),tag("h")))(input)?;
86 Ok((input, ReplCommand::Help))
87}
88
89fn quit_rpl(input: &str) -> IResult<&str, ReplCommand> {
90 let (input, _) = alt((tag("quit"), tag("exit"), tag("q")))(input)?;
91 Ok((input, ReplCommand::Quit))
92}
93
94fn cd_rpl(input: &str) -> IResult<&str, ReplCommand> {
95 let (input, _) = tag("cd")(input)?;
96 let (input, _) = space0(input)?;
97 let (input, path) = take_until("\r\n")(input)?;
98 Ok((input, ReplCommand::Cd(path.to_string())))
99}
100
101fn symbols_rpl(input: &str) -> IResult<&str, ReplCommand> {
102 let (input, _) = alt((tag("symbols"), tag("s")))(input)?;
103 let (input, _) = space0(input)?;
104 let (input, name) = opt(take_while(|c: char| c.is_alphanumeric()))(input)?;
105 Ok((input, ReplCommand::Symbols(name.map(|s| s.to_string()))))
106}
107
108fn plan_rpl(input: &str) -> IResult<&str, ReplCommand> {
109 let (input, _) = alt((tag("plan"), tag("p")))(input)?;
110 Ok((input, ReplCommand::Plan))
111}
112
113fn identifier(input: &str) -> IResult<&str, String> {
114 let (input, id) = take_till1(|c| c == ' ' || c == '\n' || c == '\r')(input)?;
115 Ok((input, id.to_string()))
116}
117
118fn whos_rpl(input: &str) -> IResult<&str, ReplCommand> {
119 let (input, _) = alt((tag("whos"), tag("w")))(input)?;
120 let (input, _) = space0(input)?;
121 let (input, names) = separated_list0(many1(tag(" ")), identifier)(input)?;
122 Ok((input, ReplCommand::Whos(names)))
123}
124
125fn clear_rpl(input: &str) -> IResult<&str, ReplCommand> {
126 let (input, _) = tag("clear")(input)?;
127 Ok((input, ReplCommand::Clear(None)))
128}
129
130fn clc_rpl(input: &str) -> IResult<&str, ReplCommand> {
131 let (input, _) = tag("clc")(input)?;
132 Ok((input, ReplCommand::Clc))
133}
134
135fn ls_rpl(input: &str) -> IResult<&str, ReplCommand> {
136 let (input, _) = tag("ls")(input)?;
137 Ok((input, ReplCommand::Ls))
138}
139
140fn load_rpl(input: &str) -> IResult<&str, ReplCommand> {
141 let (input, _) = tag("load")(input)?;
142 let (input, _) = space1(input)?;
143 let (input, path_strings) = separated_list1(space1, alt((take_until(" "),take_until("\r\n"))))(input)?;
144 Ok((input, ReplCommand::Load(path_strings.iter().map(|s| s.to_string()).collect())))
145}
146
147fn step_rpl(input: &str) -> IResult<&str, ReplCommand> {
148 let (input, _) = tag("step")(input)?;
149 let (input, _) = space1(input)?;
150 let (input, step_id) = opt(nom_tuple((tag("#"), digit1, space1)))(input)?;
151 let (input, count) = opt(digit1)(input)?;
152 let step_id = match step_id {
153 Some((_, id_str, _)) => match id_str.parse::<usize>() {
154 Ok(id) => Some(id),
155 Err(_) => None,
156 },
157 _ => None,
158 };
159 let count = match count {
160 Some(count_str) => match count_str.parse::<u64>() {
161 Ok(count) => Some(count),
162 Err(_) => None,
163 },
164 _ => None,
165 };
166 Ok((input, ReplCommand::Step(step_id, count)))
167}