Skip to content

Instantly share code, notes, and snippets.

@jonesnl
Created October 19, 2018 20:41
Show Gist options
  • Save jonesnl/16fac3b532e3b083b72bec1212c61f7c to your computer and use it in GitHub Desktop.
Save jonesnl/16fac3b532e3b083b72bec1212c61f7c to your computer and use it in GitHub Desktop.
Parser for block 2 of shell
use std::io::{self, Write};
use std::process::Command;
trait Statement {
fn run(&self) -> bool;
}
struct AndStatement {
left: Box<Statement>,
right: Box<Statement>,
}
impl Statement for AndStatement {
fn run(&self) -> bool {
if self.left.run() {
self.right.run()
} else {
false
}
}
}
struct OrStatement {
left: Box<Statement>,
right: Box<Statement>,
}
impl Statement for OrStatement {
fn run(&self) -> bool {
if self.left.run() {
true
} else {
self.right.run()
}
}
}
struct SemicolonStatement {
stmts: Vec<Box<Statement>>,
}
impl Statement for SemicolonStatement {
fn run(&self) -> bool {
let mut ret_val = false;
for s in &self.stmts {
ret_val = s.run();
}
ret_val
}
}
struct StrStatement{
string: String,
}
impl Statement for StrStatement {
fn run(&self) -> bool {
let mut split_cmd = self.string.split_whitespace();
let cmd_name = split_cmd.next().unwrap();
let args = split_cmd.collect::<Vec<&str>>();
// execute the cmd in a seperate process
// show output
match Command::new(cmd_name).args(&args).output() {
Ok(output) => {
print!("{}", String::from_utf8_lossy(&output.stdout));
io::stdout().flush().expect("Failed to flush");
output.status.success()
},
Err(msg) => {
println!("Error! {}", msg);
false
}
}
}
}
fn parse_statement(string: &str) -> Box<Statement> {
if string.find(';').is_some() {
let semi_statements = string.split(';').map(|s| parse_statement(s)).collect::<Vec<Box<Statement>>>();
let semi_stmt = Box::new(SemicolonStatement{stmts: semi_statements});
return semi_stmt;
}
if string.find("&&").is_some() {
let mut and_iter = string.splitn(2, "&&");
let left = parse_statement(and_iter.next().unwrap());
let right = parse_statement(and_iter.next().unwrap());
return Box::new(AndStatement{left, right});
}
if string.find("||").is_some() {
let mut and_iter = string.splitn(2, "||");
let left = parse_statement(and_iter.next().unwrap());
let right = parse_statement(and_iter.next().unwrap());
return Box::new(OrStatement{left, right});
}
return Box::new(StrStatement{string: string.to_string()});
}
fn main() -> io::Result<()> {
loop {
// read line from stdin
print!("nsh$ ");
io::stdout().flush().expect("Failed to flush");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Error reading from input");
parse_statement(&input).run();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment