diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 33895bd..01f62b7 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -294,12 +294,15 @@ impl Tree { Tokens::StringFunction(_) => panic!("Unexpected string function"), Tokens::ParenthesisStart => panic!("Parenthesis not yet implemented"), Tokens::SubStart => { - let mut len = 1; + let mut len = 0; let mut lvl = 1; self.inc(); for token in &self.tokens[self.i..] { match token { Tokens::SubStart => lvl += 1, + Tokens::StringFunction(_) => lvl += 1, + Tokens::ArrayFunction(_) => lvl += 1, + Tokens::ParenthesisStart => lvl += 1, Tokens::ParenthesisEnd => lvl -= 1, _ => {} } @@ -312,9 +315,13 @@ impl Tree { } // self.inc(); 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::End => buf.push(Value::Literal(token.to_str())), @@ -361,7 +368,7 @@ impl Tree { } else { 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::FileRead => expr = Some(self.parse_read(expr, end)), Tokens::FileWrite => expr = Some(self.parse_write(expr, end)), diff --git a/src/parser/exec.rs b/src/parser/exec.rs index 38632f2..41694b7 100644 --- a/src/parser/exec.rs +++ b/src/parser/exec.rs @@ -1,6 +1,6 @@ use std::error::Error; use std::fs::File; -use std::process::{Command, Stdio}; +use std::process::{Child, Command, Stdio}; use std::io; use std::ops::Deref; 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; } +struct ExecResult { + cmd: Option, + child: Option +} + +impl ExecResult { + fn new(cmd: Option, child: Option) -> 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(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>(&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 { fn get(self, ctx: &mut vars::Context) -> Variable { match self {