diff options
Diffstat (limited to 'src/parse/mod.rs')
-rw-r--r-- | src/parse/mod.rs | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs new file mode 100644 index 0000000..e2b7ec0 --- /dev/null +++ b/src/parse/mod.rs @@ -0,0 +1,169 @@ +pub mod ast; + +#[derive(Debug, Eq, PartialEq)] +pub struct Pipeline { + exes: Vec<Exe>, +} + +impl Pipeline { + pub fn into_exes(self) -> impl Iterator<Item = Exe> { + self.exes.into_iter() + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Exe { + exe: std::path::PathBuf, + args: Vec<String>, + redirects: Vec<Redirect>, +} + +impl Exe { + pub fn exe(&self) -> &std::path::Path { + &self.exe + } + + pub fn args(&self) -> &[String] { + &self.args + } + + pub fn append(&mut self, other: Self) { + let Self { + exe: _exe, + args, + redirects, + } = other; + self.args.extend(args); + self.redirects.extend(redirects); + } + + pub fn redirects(&self) -> &[Redirect] { + &self.redirects + } + + pub fn shift(&mut self) { + self.exe = std::path::PathBuf::from(self.args.remove(0)); + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Redirect { + pub from: std::os::unix::io::RawFd, + pub to: RedirectTarget, + pub dir: Direction, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum RedirectTarget { + Fd(std::os::unix::io::RawFd), + File(std::path::PathBuf), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Direction { + In, + Out, + Append, +} + +impl Direction { + pub fn open( + self, + path: &std::path::Path, + ) -> nix::Result<std::os::unix::io::RawFd> { + use nix::fcntl::OFlag; + use nix::sys::stat::Mode; + Ok(match self { + Self::In => nix::fcntl::open( + path, + OFlag::O_NOCTTY | OFlag::O_RDONLY, + Mode::empty(), + )?, + Self::Out => nix::fcntl::open( + path, + OFlag::O_CREAT + | OFlag::O_NOCTTY + | OFlag::O_WRONLY + | OFlag::O_TRUNC, + Mode::S_IRUSR + | Mode::S_IWUSR + | Mode::S_IRGRP + | Mode::S_IWGRP + | Mode::S_IROTH + | Mode::S_IWOTH, + )?, + Self::Append => nix::fcntl::open( + path, + OFlag::O_APPEND + | OFlag::O_CREAT + | OFlag::O_NOCTTY + | OFlag::O_WRONLY, + Mode::S_IRUSR + | Mode::S_IWUSR + | Mode::S_IRGRP + | Mode::S_IWGRP + | Mode::S_IROTH + | Mode::S_IWOTH, + )?, + }) + } +} + +#[derive(Debug, Eq, PartialEq)] +pub struct Error { + input: String, + e: pest::error::Error<ast::Rule>, +} + +impl Error { + fn new(input: String, e: pest::error::Error<ast::Rule>) -> Self { + Self { input, e } + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.e.variant { + pest::error::ErrorVariant::ParsingError { + positives, + negatives, + } => { + if !positives.is_empty() { + write!(f, "expected {:?}", positives[0])?; + for rule in &positives[1..] { + write!(f, ", {:?}", rule)?; + } + if !negatives.is_empty() { + write!(f, "; ")?; + } + } + if !negatives.is_empty() { + write!(f, "unexpected {:?}", negatives[0])?; + for rule in &negatives[1..] { + write!(f, ", {:?}", rule)?; + } + } + writeln!(f)?; + writeln!(f, "{}", self.input)?; + match &self.e.location { + pest::error::InputLocation::Pos(i) => { + write!(f, "{}^", " ".repeat(*i))?; + } + pest::error::InputLocation::Span((i, j)) => { + write!(f, "{}{}", " ".repeat(*i), "^".repeat(j - i))?; + } + } + } + pest::error::ErrorVariant::CustomError { message } => { + write!(f, "{}", message)?; + } + } + Ok(()) + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + Some(&self.e) + } +} |