i6_shell/
lang.rs

1use std::collections::HashMap;
2
3use crate::command::Command;
4
5#[derive(Debug)]
6pub enum TokenType {
7  Command,
8  Argument,
9  Operator,
10}
11
12impl Default for TokenType {
13  fn default() -> Self {
14    todo!()
15  }
16}
17
18#[derive(Debug, Default)]
19pub struct Token {
20  token_type: TokenType,
21  value: String,
22}
23
24#[derive(Debug)]
25pub enum ASTNode {
26  Command { name: String, args: Vec<ASTNode> },
27  Operator { op: String, args: Vec<ASTNode> },
28  Argument { value: String },
29  Pipe { left: Box<ASTNode>, right: Box<ASTNode> },
30}
31
32impl Default for ASTNode {
33  fn default() -> Self {
34    ASTNode::Argument { value: String::new() }
35  }
36}
37
38pub trait Lexer: Default {
39  fn _run(input: &str) -> Vec<Token>;
40}
41pub trait LexerTraitObject {
42  fn run(&self, input: &str) -> Vec<Token>;
43}
44impl<T: Lexer> LexerTraitObject for T {
45  fn run(&self, input: &str) -> Vec<Token> {
46    return <Self as Lexer>::_run(input);
47  }
48}
49
50#[derive(Default)]
51pub struct DefaultLexer;
52impl Lexer for DefaultLexer {
53  fn _run(input: &str) -> Vec<Token> {
54    let mut tokens = Vec::<Token>::new();
55
56    for word in input.split_whitespace() {
57      let token_type = match word {
58        "&&" | "||" | "|" | ">" | ">>" | "<" => TokenType::Operator,
59        _ if tokens.is_empty()
60          || matches!(
61            tokens.last().unwrap().token_type,
62            TokenType::Operator
63          ) =>
64        {
65          TokenType::Command
66        }
67        _ => TokenType::Argument,
68      };
69
70      tokens.push(Token { token_type, value: word.to_string() });
71    }
72
73    tokens
74  }
75}
76
77pub trait Parser: Default {
78  fn _run(tokens: Vec<Token>) -> ASTNode;
79}
80pub trait ParserTraitObject {
81  fn run(&self, tokens: Vec<Token>) -> ASTNode;
82}
83impl<T: Parser> ParserTraitObject for T {
84  fn run(&self, tokens: Vec<Token>) -> ASTNode {
85    return <Self as Parser>::_run(tokens);
86  }
87}
88
89#[derive(Default)]
90pub struct DefaultParser;
91impl Parser for DefaultParser {
92  fn _run(tokens: Vec<Token>) -> ASTNode {
93    let mut iter = tokens.into_iter().peekable();
94
95    let mut root = match iter.next() {
96      Some(Token { token_type: TokenType::Command, value }) => {
97        ASTNode::Command { name: value, args: vec![] }
98      }
99      _ => {
100        eprintln!("Invalid syntax");
101        return ASTNode::default();
102      }
103    };
104
105    while let Some(token) = iter.next() {
106      match token.token_type {
107        TokenType::Argument => {
108          if let ASTNode::Command { name, args } = &mut root {
109            args.push(ASTNode::Argument { value: token.value });
110          }
111        }
112        TokenType::Operator => {
113          let mut args = vec![root];
114          while let Some(Token { token_type: TokenType::Command, value }) =
115            iter.next()
116          {
117            let mut command_args = vec![];
118            while let Some(Token { token_type: TokenType::Argument, value }) =
119              iter.peek()
120            {
121              command_args.push(ASTNode::Argument { value: value.clone() });
122              iter.next();
123            }
124            args.push(ASTNode::Command { name: value, args: command_args });
125            if iter
126              .peek()
127              .map_or(true, |t| matches!(t.token_type, TokenType::Operator))
128            {
129              break;
130            }
131          }
132          if token.value == "|" {
133            let right = args.pop().unwrap();
134            let left = args.pop().unwrap();
135            root =
136              ASTNode::Pipe { left: Box::new(left), right: Box::new(right) };
137          } else {
138            root = ASTNode::Operator { op: token.value, args };
139          }
140        }
141        _ => eprintln!("Invalid syntax"),
142      }
143    }
144
145    root
146  }
147}
148
149pub trait Interpreter: Default {
150  fn _run(ast: ASTNode, custom_commands: &HashMap<String, Box<dyn Command>>);
151}
152pub trait InterpreterTraitObject {
153  fn run(
154    &self,
155    ast: ASTNode,
156    custom_commands: &HashMap<String, Box<dyn Command>>,
157  );
158}
159impl<T: Interpreter> InterpreterTraitObject for T {
160  fn run(
161    &self,
162    ast: ASTNode,
163    custom_commands: &HashMap<String, Box<dyn Command>>,
164  ) {
165    <Self as Interpreter>::_run(ast, custom_commands);
166  }
167}
168
169#[derive(Default)]
170pub struct DefaultInterpreter;
171impl Interpreter for DefaultInterpreter {
172  fn _run(ast: ASTNode, custom_commands: &HashMap<String, Box<dyn Command>>) {
173    match ast {
174      ASTNode::Command { name, args } => {
175        let args: Vec<String> = args
176          .into_iter()
177          .map(|arg| {
178            if let ASTNode::Argument { value } = arg {
179              value
180            } else {
181              eprintln!("Invalid syntax");
182              "".to_owned()
183            }
184          })
185          .collect();
186
187        let args_str = &args.join(" ");
188
189        if let Some(custom_command) = custom_commands.get(&name) {
190          let _ = custom_command
191            .run(args_str)
192            .map(|output| {
193              if !output.is_empty() {
194                println!("{output}");
195              }
196            })
197            .map_err(|e| eprintln!("{e}"));
198
199          return;
200        }
201
202        if let Ok(lock) = crate::command::DEFAULT_COMMANDS.lock() {
203          if let Ok(commands) = lock.as_ref() {
204            if let Some(command) = commands.get(&name) {
205              let _ = command
206                .run(args_str)
207                .map(|output| {
208                  if !output.is_empty() {
209                    println!("{output}");
210                  }
211                })
212                .map_err(|e| eprintln!("{e}"));
213
214              return;
215            }
216          }
217        }
218
219        let command = name.as_str();
220        {
221          let child = std::process::Command::new(command).args(args).spawn();
222
223          match child {
224            Ok(mut child) => {
225              child.wait().unwrap();
226            }
227            Err(e) => eprintln!("{}", e),
228          }
229        }
230      }
231      ASTNode::Operator { op, args } => match op.as_str() {
232        "&&" => {
233          for arg in args {
234            DefaultInterpreter::_run(arg, custom_commands);
235          }
236        }
237        _ => eprintln!("Unknown operator"),
238      },
239      ASTNode::Pipe { left, right } => {
240        let first_command_output =
241          if let ASTNode::Command { name, args } = *left {
242            let args: Vec<String> = args
243              .into_iter()
244              .map(|arg| {
245                if let ASTNode::Argument { value } = arg {
246                  value
247                } else {
248                  eprintln!("Invalid syntax");
249                  "".to_owned()
250                }
251              })
252              .collect();
253
254            let args_str = &args.join(" ");
255
256            if let Some(custom_command) = custom_commands.get(&name) {
257              custom_command.run(args_str).unwrap_or_default()
258            } else if let Ok(lock) = crate::command::DEFAULT_COMMANDS.lock() {
259              if let Ok(commands) = lock.as_ref() {
260                if let Some(command) = commands.get(&name) {
261                  command.run(args_str).unwrap_or_default()
262                } else {
263                  {
264                    let child =
265                      std::process::Command::new(&name).args(args).spawn();
266
267                    match child {
268                      Ok(mut child) => {
269                        child.wait().unwrap();
270                      }
271                      Err(e) => eprintln!("{}", e),
272                    }
273                  }
274
275                  return;
276                }
277              } else {
278                eprintln!("Failed to acquire lock");
279                return;
280              }
281            } else {
282              eprintln!("Failed to acquire lock");
283              return;
284            }
285          } else {
286            return;
287          };
288
289        if let ASTNode::Command { name, args } = *right {
290          let args: Vec<String> = args
291            .into_iter()
292            .map(|arg| {
293              if let ASTNode::Argument { value } = arg {
294                value
295              } else {
296                eprintln!("Invalid syntax");
297                "".to_owned()
298              }
299            })
300            .collect();
301
302          let args_str = &args.join(" ");
303
304          if let Some(custom_command) = custom_commands.get(&name) {
305            let _ = custom_command
306              .run(&format!("\"{}\" \"{}\"", args_str, first_command_output))
307              .map(|output| {
308                if !output.is_empty() {
309                  println!("{output}");
310                }
311              })
312              .map_err(|e| eprintln!("{e}"));
313          } else if let Ok(lock) = crate::command::DEFAULT_COMMANDS.lock() {
314            if let Ok(commands) = lock.as_ref() {
315              if let Some(command) = commands.get(&name) {
316                let _ = command
317                  .run(&format!(
318                    "\"{}\" \"{}\"",
319                    args_str, first_command_output
320                  ))
321                  .map(|output| {
322                    if !output.is_empty() {
323                      println!("{output}");
324                    }
325                  })
326                  .map_err(|e| eprintln!("{e}"));
327              } else {
328                {
329                  let child =
330                    std::process::Command::new(&name).args(args).spawn();
331
332                  match child {
333                    Ok(mut child) => {
334                      child.wait().unwrap();
335                    }
336                    Err(e) => eprintln!("{}", e),
337                  }
338                }
339
340                return;
341              }
342            } else {
343              eprintln!("Failed to acquire lock");
344            }
345          } else {
346            eprintln!("Failed to acquire lock");
347          }
348        } else {
349          return;
350        }
351      }
352      _ => eprintln!("Invalid syntax"),
353    }
354  }
355}