diff --git a/src/main.rs b/src/main.rs index 86e6707..6f78ada 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,24 +67,24 @@ impl Shell { }, }; } -} -fn main() { - loop { - print!("$: "); - io::stdout().flush(); - let mut shell = collect(); - shell.term.input += "\n"; - parser::exec(&mut shell.term.input.as_bytes(), shell.ctx); + fn collect(&mut self) { + let stdin = std::io::stdin(); + let v = stdin.lock().lines().next().unwrap().unwrap(); + self.term.input = v; } } -fn collect() -> Shell { +fn main() { let mut shell = Shell::new(); - let stdin = std::io::stdin(); - let v = stdin.lock().lines().next().unwrap().unwrap(); - shell.term.input = v; - shell + shell.ctx.add_scope(true); + loop { + print!("$: "); + io::stdout().flush(); + shell.collect(); + shell.term.input += "\n"; + parser::exec(&mut shell.term.input.as_bytes(), &mut shell.ctx); + } } fn editor() -> Shell { diff --git a/src/parser/ast.rs b/src/parser/ast.rs index f0164a5..33895bd 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -58,7 +58,6 @@ pub enum Value { ArrayFunction(DefinedFunction), StringFunction(DefinedFunction), Expressions(Vec), - Expression(Expression), Values(Vec) } @@ -119,7 +118,6 @@ impl Tree { fn parse_call(&mut self, end: usize) -> Expression { let mut values: Vec = Vec::new(); let mut buf: Vec = Vec::new(); - dbg!("call parse"); let mut token = self.get_current_token(); loop { if matches!(token, Tokens::Space) { @@ -130,7 +128,6 @@ impl Tree { if self.i >= end - 1 { break } self.i += 1; token = self.get_current_token(); - dbg!("skip space"); continue; } let val = match &token { @@ -145,6 +142,9 @@ impl Tree { Tokens::FileWrite => break, Tokens::FileRead => break, Tokens::RedirectInto => break, + Tokens::And => break, + Tokens::Or => break, + Tokens::JobCommandEnd => break, Tokens::ParenthesisEnd => { if self.i >= end - 1 { break; @@ -160,14 +160,11 @@ impl Tree { self.i += 1; token = self.tokens.get(self.i).unwrap(); if matches!(token, Tokens::CommandEnd(_)) { break } - dbg!("parse call loop"); } - dbg!(&token); match &token { Tokens::FileWrite | Tokens::FileRead | Tokens::RedirectInto => self.i -= 1, _ => {} } - dbg!(&self); // self.next(); if buf.len() > 0 { values.push(CommandValue::Value(Value::Values(buf))); @@ -201,7 +198,6 @@ impl Tree { let mut val_end = self.i; let mut found_first = false; for token in &self.tokens[self.i..] { - dbg!(&token); val_end += 1; match token { Tokens::Space => if found_first { break }, @@ -211,7 +207,6 @@ impl Tree { _ => { found_first = true; } } } - dbg!(&self.tokens[self.i..val_end]); val_end -= 1; let source = Box::new(self.get_value(val_end)); self.inc(); @@ -271,7 +266,6 @@ impl Tree { loop { if self.i >= end - 1 { break; } expressions.push(self.get_expression(end)); - dbg!(&expressions); } expressions } @@ -317,8 +311,6 @@ impl Tree { len += 1; } // self.inc(); - dbg!(&self); - dbg!(len, lvl); if lvl != 0 { panic!("Sub not ended properly"); } @@ -359,20 +351,15 @@ impl Tree { fn get_expression(&mut self, end: usize) -> Expression { let mut token = self.get_current_token(); - dbg!("expr"); let mut expr: Option = None; loop { - dbg!(&token); match token { Tokens::Space => {self.inc();}, - Tokens::CommandEnd(_) => {self.inc();}, + Tokens::CommandEnd(_) => { if matches!(expr, Some(_)) { break }; self.inc();}, Tokens::Literal(t) => if matches!(expr, Some(_)) { - dbg!(t); - dbg!(expr); panic!("Unexpected literal. After file redirect, you need to use a semicolon or newline."); } else { expr = Some(self.parse_call(end)); - dbg!(&self); }, Tokens::ExportSet => panic!("Unexpected token EXPORT_SET (=)"), Tokens::Function => return Expression::Function(self.parse_function(end)), @@ -382,13 +369,10 @@ impl Tree { None => panic!("Unexpected token REDIRECT (|)"), Some(_) => { self.i += 1; - dbg!(&self); expr = Some(Expression::RedirectTargetExpression(RedirectTargetExpression { source: Box::new(expr.unwrap()), target: Box::new(self.get_expression(end)) })); - dbg!("after redirect"); } }, Tokens::ParenthesisStart => if matches!(expr, Some(_)) { - dbg!(expr); panic!("Unexpected parenthesis. After file redirect, you need to use a semicolon or newline."); } else { let mut len = 1; @@ -411,28 +395,48 @@ impl Tree { panic!("Parenthesis not ended properly."); } expr = Some(self.get_expression(self.i + len)); - dbg!(&self); + self.inc(); }, Tokens::ParenthesisEnd => panic!("Unexpected token PARENTHESIS END ())"), Tokens::ArrayFunction(_) => panic!("Unexpected array function"), Tokens::StringFunction(_) => panic!("Unexpected string function"), - Tokens::SubStart => return self.parse_call(end), + Tokens::SubStart => if matches!(expr, Some(_)) { + panic!("Unexpected literal. After file redirect, you need to use a semicolon or newline."); + } else { + expr = Some(self.parse_call(end)); + }, Tokens::Else => panic!("Unexpected token ELSE"), Tokens::End => panic!("Unexpected token END"), - Tokens::For => return Expression::ForExpression(self.parse_for(end)), - Tokens::If => return Expression::IfExpression(self.parse_if(end)), + Tokens::For => match expr { + Some(_) => panic!("Commands must be ended properly"), + None => expr = Some(Expression::ForExpression(self.parse_for(end))), + }, + Tokens::If => match expr { + Some(_) => panic!("Commands must be ended properly"), + None => expr = Some(Expression::IfExpression(self.parse_if(end))), + } Tokens::Let => return self.parse_let(end), Tokens::While => return Expression::WhileExpression(self.parse_while(end)), Tokens::StringVariable(_, _) => if matches!(expr, Some(_)) { - dbg!(expr); panic!("Unexpected variable. After file redirect, you need to use a semicolon or newline."); } else { expr = Some(self.parse_call(end)); - dbg!(&self); }, Tokens::ArrayVariable(_, _) => panic!("Unexpected array variable"), - Tokens::And => panic!("And not yet implemented"), - Tokens::Or => panic!("Or not yet implemented"), + Tokens::And => match expr { + None => panic!("Unexpected AND (&&)"), + Some(_) => { + self.inc(); + expr = Some(Expression::AndExpression(AndExpression { first: Box::new(expr.unwrap()), second: Box::new(self.get_expression(end)) })); + } + }, + Tokens::Or => match expr { + None => panic!("Unexpected OR (||)"), + Some(_) => { + self.inc(); + expr = Some(Expression::OrExpression(OrExpression { first: Box::new(expr.unwrap()), second: Box::new(self.get_expression(end)) })); + } + }, Tokens::JobCommandEnd => panic!("Jobs not yet implemented") } if self.i >= end - 1 { break } @@ -454,7 +458,6 @@ impl Tree { } pub fn build_tree(tokens: Vec) -> Vec { - println!("Building tree"); let mut expressions: Vec = Vec::new(); let mut tree = Tree { tokens, i: 0 }; loop { @@ -462,7 +465,5 @@ pub fn build_tree(tokens: Vec) -> Vec { let val = tree.get_expression(tree.tokens.len()); expressions.push(val); } - dbg!(&expressions); - expressions } diff --git a/src/parser/exec.rs b/src/parser/exec.rs new file mode 100644 index 0000000..6c6ffc1 --- /dev/null +++ b/src/parser/exec.rs @@ -0,0 +1,137 @@ +use std::error::Error; +use std::process::{Command, Stdio}; +use std::io; +use std::ops::Deref; +use crate::parser::ast::{CommandValue, Expression, LetExpression, RedirectTargetExpression, Value}; +use crate::parser::vars; +use crate::parser::vars::Variable; + +trait ExecExpression { + fn exec(self, ctx: &mut vars::Context) -> Option; +} + +trait GetValue { + fn get(self, ctx: &mut vars::Context) -> Variable; +} + +impl GetValue for CommandValue { + fn get(self, ctx: &mut vars::Context) -> Variable { + match self { + CommandValue::Value(val) => val.get(ctx), + CommandValue::Var(_, _) => panic!("Broken executor") + } + } +} + +impl GetValue for Value { + fn get(self, ctx: &mut vars::Context) -> Variable { + match self { + Value::Literal(str) => { + Variable::String(str) + }, + Value::Variable(str) => ctx.get_var(&str).unwrap_or(&mut Variable::String(String::from(""))).clone(), + Value::ArrayVariable(str) => ctx.get_var(&str).unwrap_or(&mut Variable::Array(Vec::new())).clone(), + Value::ArrayFunction(_) => panic!("Not implemented yet"), + Value::StringFunction(_) => panic!("Not implemented yet"), + Value::Expressions(expressions) => { + let mut out = String::new(); + ctx.add_scope(true); + for mut expr in expressions { + let res = expr.exec(ctx); + match res { + None => {}, + Some(mut cmd) => { + out += &*String::from_utf8_lossy(&cmd.output().expect("Failed to read output of command").stdout); + } + } + } + ctx.pop_scope(); + Variable::String(out) + }, + Value::Values(vec) => { + let mut out = Vec::new(); + for mut val in vec { + out.push(val.get(ctx)); + } + Variable::Array(out) + } + } + } +} + +impl ExecExpression for Expression { + fn exec(self, ctx: &mut vars::Context) -> Option { + match self { + Expression::LetExpression(expr) => expr.exec(ctx), + Expression::Command(expr) => expr.exec(ctx), + Expression::JobCommand(_) => panic!("Not implemented yet"), + Expression::Function(_) => panic!("Not implemented yet"), + Expression::IfExpression(_) => panic!("Not implemented yet"), + Expression::WhileExpression(_) => panic!("Not implemented yet"), + Expression::ForExpression(_) => panic!("Not implemented yet"), + Expression::RedirectTargetExpression(expr) => expr.exec(ctx), + Expression::FileTargetExpression(_) => panic!("Not implemented yet"), + Expression::FileSourceExpression(_) => panic!("Not implemented yet"), + Expression::Expressions(_) => panic!("Not implemented yet"), + Expression::OrExpression(_) => panic!("Not implemented yet"), + Expression::AndExpression(_) => panic!("Not implemented yet") + } + } +} + +impl ExecExpression for LetExpression { + fn exec(mut self, ctx: &mut vars::Context) -> Option { + let key = self.key.get(ctx); + let val = self.value.get(ctx); + ctx.set_var(key.to_string(), val); + None + } +} + +impl ExecExpression for Vec { + fn exec(mut self, ctx: &mut vars::Context) -> Option { + if self.len() == 0 { panic!("Command with 0 length"); } + let mut first = self.remove(0); + let command_name = first.get(ctx).to_string(); + let mut cmd = Command::new(command_name); + for mut value in self { + cmd.arg(value.get(ctx).to_string()); + } + Some(cmd) + } +} + +impl ExecExpression for RedirectTargetExpression { + fn exec(mut self, ctx: &mut vars::Context) -> Option { + let mut src = self.source.exec(ctx).unwrap(); + let mut target = self.target.exec(ctx).unwrap(); + src.stdout(Stdio::piped()); + match src.spawn() { + Result::Err(e) => { println!("Error executing: {}", e)}, + Result::Ok(mut res) => { + target.stdin(res.stdout.unwrap()); + } + } + + Some(target) + } +} + +pub fn exec_tree(tree: Vec, ctx: &mut vars::Context) { + println!("Executing"); + for mut expression in tree { + let mut cmd = expression.exec(ctx); + match cmd { + None => {}, + Some(mut cmd) => match cmd.spawn() { + Result::Err(e) => { + println!("Error executing: {}", e); + }, + Result::Ok(mut res) => { + let out = res.wait().unwrap(); + ctx.set_var(String::from("!"), Variable::I32(out.code().unwrap_or(1))); + } + } + } + } +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 6aa6280..95992be 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,11 +1,13 @@ pub mod vars; pub mod ast; pub mod tokens; +mod exec; use crate::parser::ast::{build_tree}; +use crate::parser::exec::exec_tree; use crate::parser::tokens::{tokenize}; -pub fn exec(reader: &mut dyn std::io::BufRead, ctx: vars::Context) { +pub fn exec(reader: &mut dyn std::io::BufRead, ctx: &mut vars::Context) { let tokens = tokenize(reader).unwrap(); dbg!(&tokens); @@ -13,6 +15,8 @@ pub fn exec(reader: &mut dyn std::io::BufRead, ctx: vars::Context) { let expressions = build_tree(tokens); dbg!(&expressions); + + exec_tree(expressions, ctx); } pub fn escape(str: String) -> String { diff --git a/src/parser/vars.rs b/src/parser/vars.rs index 9611a23..ea46273 100644 --- a/src/parser/vars.rs +++ b/src/parser/vars.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::parser::ast::FunctionDefinitionExpression; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Variable { String(String), I32(i32), @@ -19,7 +19,9 @@ pub enum Variable { impl Variable { pub fn to_string(self: &Self) -> String { match self { - Variable::String(var) => String::from(var), + Variable::String(var) => { + var.clone() + }, Variable::I32(num) => num.to_string(), Variable::I64(num) => num.to_string(), Variable::I128(num) => num.to_string(), @@ -32,10 +34,16 @@ impl Variable { String::from("[Object object]") }, Variable::Array(vars) => { + let len = vars.len(); + if len == 1 { return vars.get(0).unwrap().to_string(); } let mut str = String::new(); + let mut i = 0; for var in vars { str += &*var.clone().to_string(); - str += " "; + if i < len - 1 { + str += " "; + } + i += 1; } str }