feat: working executing simple commands

This commit is contained in:
Daniel Bulant 2021-12-09 21:44:01 +01:00
parent 847e49ec92
commit bd72bdb17f
5 changed files with 198 additions and 48 deletions

View file

@ -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 {

View file

@ -58,7 +58,6 @@ pub enum Value {
ArrayFunction(DefinedFunction),
StringFunction(DefinedFunction),
Expressions(Vec<Expression>),
Expression(Expression),
Values(Vec<Value>)
}
@ -119,7 +118,6 @@ impl Tree {
fn parse_call(&mut self, end: usize) -> Expression {
let mut values: Vec<CommandValue> = Vec::new();
let mut buf: Vec<Value> = 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<Expression> = 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<Tokens>) -> Vec<Expression> {
println!("Building tree");
let mut expressions: Vec<Expression> = Vec::new();
let mut tree = Tree { tokens, i: 0 };
loop {
@ -462,7 +465,5 @@ pub fn build_tree(tokens: Vec<Tokens>) -> Vec<Expression> {
let val = tree.get_expression(tree.tokens.len());
expressions.push(val);
}
dbg!(&expressions);
expressions
}

137
src/parser/exec.rs Normal file
View file

@ -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<Command>;
}
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<Command> {
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<Command> {
let key = self.key.get(ctx);
let val = self.value.get(ctx);
ctx.set_var(key.to_string(), val);
None
}
}
impl ExecExpression for Vec<CommandValue> {
fn exec(mut self, ctx: &mut vars::Context) -> Option<Command> {
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<Command> {
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<Expression>, 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)));
}
}
}
}
}

View file

@ -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 {

View file

@ -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
}