mech_syntax/
repl.rs

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