Skip to main content

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