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>),
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 step_rpl,
41 help_rpl,
42 quit_rpl,
43 save_rpl,
44 symbols_rpl,
45 plan_rpl,
46 ls_rpl,
47 cd_rpl,
48 whos_rpl,
49 clear_rpl,
50 clc_rpl,
51 load_rpl,
52 docs_rpl,
53 ))(input)?;
54 let (input, _) = opt(tag("\r\n"))(input)?;
55 Ok((input, command))
56}
57
58fn save_rpl(input: &str) -> IResult<&str, ReplCommand> {
59 let (input, _) = tag("save")(input)?;
60 let (input, _) = space1(input)?;
61 let (input, path) = take_while(|c: char| c.is_alphanumeric() || c == '/' || c == '.' || c == '_')(input)?;
62 Ok((input, ReplCommand::Save(path.to_string())))
63}
64
65fn docs_rpl(input: &str) -> IResult<&str, ReplCommand> {
66 let (input, _) = alt((tag("docs"), tag("d")))(input)?;
67 let (input, _) = space0(input)?;
68 let (input, name) = opt(take_till1(|c| c == '\r' || c == '\n'))(input)?;
69 let name = name.map(|s| s.to_string());
70 Ok((input, ReplCommand::Docs(name)))
71}
72
73fn help_rpl(input: &str) -> IResult<&str, ReplCommand> {
74 let (input, _) = alt((tag("h"), tag("help")))(input)?;
75 Ok((input, ReplCommand::Help))
76}
77
78fn quit_rpl(input: &str) -> IResult<&str, ReplCommand> {
79 let (input, _) = alt((tag("q"), tag("quit"), tag("exit")))(input)?;
80 Ok((input, ReplCommand::Quit))
81}
82
83fn cd_rpl(input: &str) -> IResult<&str, ReplCommand> {
84 let (input, _) = tag("cd")(input)?;
85 let (input, _) = space0(input)?;
86 let (input, path) = take_until("\r\n")(input)?;
87 Ok((input, ReplCommand::Cd(path.to_string())))
88}
89
90fn symbols_rpl(input: &str) -> IResult<&str, ReplCommand> {
91 let (input, _) = alt((tag("s"), tag("symbols")))(input)?;
92 let (input, _) = space0(input)?;
93 let (input, name) = opt(take_while(|c: char| c.is_alphanumeric()))(input)?;
94 Ok((input, ReplCommand::Symbols(name.map(|s| s.to_string()))))
95}
96
97fn plan_rpl(input: &str) -> IResult<&str, ReplCommand> {
98 let (input, _) = alt((tag("p"), tag("plan")))(input)?;
99 Ok((input, ReplCommand::Plan))
100}
101
102fn identifier(input: &str) -> IResult<&str, String> {
103 let (input, id) = take_till1(|c| c == ' ' || c == '\n' || c == '\r')(input)?;
104 Ok((input, id.to_string()))
105}
106
107fn whos_rpl(input: &str) -> IResult<&str, ReplCommand> {
108 let (input, _) = alt((tag("whos"), tag("w")))(input)?;
109 let (input, _) = space0(input)?;
110 let (input, names) = separated_list0(many1(tag(" ")), identifier)(input)?;
111 Ok((input, ReplCommand::Whos(names)))
112}
113
114fn clear_rpl(input: &str) -> IResult<&str, ReplCommand> {
115 let (input, _) = tag("clear")(input)?;
116 Ok((input, ReplCommand::Clear(None)))
117}
118
119fn clc_rpl(input: &str) -> IResult<&str, ReplCommand> {
120 let (input, _) = alt((tag("c"), tag("clc")))(input)?;
121 Ok((input, ReplCommand::Clc))
122}
123
124fn ls_rpl(input: &str) -> IResult<&str, ReplCommand> {
125 let (input, _) = tag("ls")(input)?;
126 Ok((input, ReplCommand::Ls))
127}
128
129fn load_rpl(input: &str) -> IResult<&str, ReplCommand> {
130 let (input, _) = tag("load")(input)?;
131 let (input, _) = space1(input)?;
132 let (input, path_strings) = separated_list1(space1, alt((take_until(" "),take_until("\r\n"))))(input)?;
133 Ok((input, ReplCommand::Load(path_strings.iter().map(|s| s.to_string()).collect())))
134}
135
136fn step_rpl(input: &str) -> IResult<&str, ReplCommand> {
137 let (input, _) = tag("step")(input)?;
138 let (input, _) = space0(input)?;
139 let (input, count) = opt(digit1)(input)?;
140 Ok((input, ReplCommand::Step(count.map(|s| s.parse().unwrap()))))
141}