refactor: first part of moving to results

This commit is contained in:
Daniel Bulant 2021-12-10 17:35:22 +01:00
parent a4fc18f8fe
commit e8b943a8d5
2 changed files with 95 additions and 5 deletions

View file

@ -294,12 +294,15 @@ impl Tree {
Tokens::StringFunction(_) => panic!("Unexpected string function"), Tokens::StringFunction(_) => panic!("Unexpected string function"),
Tokens::ParenthesisStart => panic!("Parenthesis not yet implemented"), Tokens::ParenthesisStart => panic!("Parenthesis not yet implemented"),
Tokens::SubStart => { Tokens::SubStart => {
let mut len = 1; let mut len = 0;
let mut lvl = 1; let mut lvl = 1;
self.inc(); self.inc();
for token in &self.tokens[self.i..] { for token in &self.tokens[self.i..] {
match token { match token {
Tokens::SubStart => lvl += 1, Tokens::SubStart => lvl += 1,
Tokens::StringFunction(_) => lvl += 1,
Tokens::ArrayFunction(_) => lvl += 1,
Tokens::ParenthesisStart => lvl += 1,
Tokens::ParenthesisEnd => lvl -= 1, Tokens::ParenthesisEnd => lvl -= 1,
_ => {} _ => {}
} }
@ -312,9 +315,13 @@ impl Tree {
} }
// self.inc(); // self.inc();
if lvl != 0 { if lvl != 0 {
panic!("Sub not ended properly"); panic!("Parenthesis do not match");
} }
return Value::Expressions(self.parse_sub(self.i + len)); dbg!(&self, len);
let val = Value::Expressions(self.parse_sub(self.i + len));
self.inc();
dbg!(self);
return val;
}, },
Tokens::Else => buf.push(Value::Literal(token.to_str())), Tokens::Else => buf.push(Value::Literal(token.to_str())),
Tokens::End => buf.push(Value::Literal(token.to_str())), Tokens::End => buf.push(Value::Literal(token.to_str())),
@ -361,7 +368,7 @@ impl Tree {
} else { } else {
expr = Some(self.parse_call(end)); expr = Some(self.parse_call(end));
}, },
Tokens::ExportSet => panic!("Unexpected token EXPORT_SET (=)"), Tokens::ExportSet => panic!("Unexpected token EXPORT SET (=)"),
Tokens::Function => return Expression::Function(self.parse_function(end)), Tokens::Function => return Expression::Function(self.parse_function(end)),
Tokens::FileRead => expr = Some(self.parse_read(expr, end)), Tokens::FileRead => expr = Some(self.parse_read(expr, end)),
Tokens::FileWrite => expr = Some(self.parse_write(expr, end)), Tokens::FileWrite => expr = Some(self.parse_write(expr, end)),

View file

@ -1,6 +1,6 @@
use std::error::Error; use std::error::Error;
use std::fs::File; use std::fs::File;
use std::process::{Command, Stdio}; use std::process::{Child, Command, Stdio};
use std::io; use std::io;
use std::ops::Deref; use std::ops::Deref;
use crate::parser::ast::{AndExpression, CommandValue, Expression, FileSourceExpression, FileTargetExpression, LetExpression, OrExpression, RedirectTargetExpression, Value}; use crate::parser::ast::{AndExpression, CommandValue, Expression, FileSourceExpression, FileTargetExpression, LetExpression, OrExpression, RedirectTargetExpression, Value};
@ -15,6 +15,89 @@ trait GetValue {
fn get(self, ctx: &mut vars::Context) -> Variable; fn get(self, ctx: &mut vars::Context) -> Variable;
} }
struct ExecResult {
cmd: Option<Command>,
child: Option<Child>
}
impl ExecResult {
fn new(cmd: Option<Command>, child: Option<Child>) -> Self {
Self { cmd, child }
}
/// Spawns the result, running the command (if any). Non-command results won't be spawned (like let statements)
fn spawn(&mut self) -> &mut Self {
if !self.started() {
match &mut self.cmd {
None => {},
Some(cmd) => {
self.child = Some(cmd.spawn().unwrap());
}
}
}
self
}
/// Checks if the result was spawned before by checking the child property. Non-command results won't ever be spawned (like let statements)
fn started(&self) -> bool {
matches!(self.child, Some(_))
}
/// A simple wrapper for redirecting current result (self) into STDIO (files or streams).
///
/// Does spawn the current result
fn redirect_into<T: std::io::Write>(mut self, into: &mut T) -> &mut T {
match &mut self.cmd {
None => {},
Some(cmd) => {
cmd.stdout(Stdio::piped());
self.spawn();
let child = self.child.unwrap();
let mut stdout = child.stdout.unwrap();
io::copy(&mut stdout, into);
}
}
into
}
/// A shorthand for redirecting current result into the next one
///
/// Uses `redirect_from_result` of the next result. Spawns this result, but not the next one.
fn redirect_into_result(&mut self, into: &mut ExecResult) -> &mut Self {
into.redirect_from_result(self);
self
}
/// Redirects the `from` into the current pending result
///
/// Doesn't spawn the current result
fn redirect_from<T: Into<Stdio>>(&mut self, from: T) -> &mut Self {
match &mut self.cmd {
None => {},
Some(cmd) => {
cmd.stdin(from);
}
}
self
}
/// A shortcut for redirecting a previous result into the current one
///
/// Spawns the previous result to obtain the output, but not the current one (self)
fn redirect_from_result(&mut self, into: &mut ExecResult) -> io::Result<&mut Self> {
if matches!(self.cmd, None) {
return Ok(self);
}
match &mut self.cmd {
None => {},
Some(source) => {
source.stdout(Stdio::piped());
match &mut into.cmd {
None => {},
Some(target) => {
target.stdin(source.spawn()?.stdout.unwrap());
}
};
}
}
Ok(self)
}
}
impl GetValue for CommandValue { impl GetValue for CommandValue {
fn get(self, ctx: &mut vars::Context) -> Variable { fn get(self, ctx: &mut vars::Context) -> Variable {
match self { match self {