use crate::{io::FileDescriptor, symbol::Symbol};
use super::{lexer, IllFormed, SourcePos};
#[derive(Debug)]
pub enum ArgUnit {
Literal(Box<[u8]>),
Dollar {
symbol: Symbol,
pos: SourcePos,
}
}
impl From<lexer::ArgUnit> for ArgUnit {
fn from(unit: lexer::ArgUnit) -> Self {
match unit {
lexer::ArgUnit::Literal(lit) => Self::Literal(lit),
lexer::ArgUnit::Dollar { symbol, pos } => Self::Dollar { symbol, pos }
}
}
}
#[derive(Debug)]
pub enum ArgExpansion {
Home, Range(i64, i64), Collection(Box<[ArgUnit]>),
Star, Percent, CharClass(Box<[u8]>), }
impl From<lexer::ArgExpansion> for ArgExpansion {
fn from(expansion: lexer::ArgExpansion) -> Self {
match expansion {
lexer::ArgExpansion::Home => Self::Home,
lexer::ArgExpansion::Range(from ,to) => Self::Range(from ,to),
lexer::ArgExpansion::Collection(items) => Self::Collection(
items
.into_vec() .into_iter()
.map(Into::into)
.collect()
),
lexer::ArgExpansion::Star => Self::Star,
lexer::ArgExpansion::Percent => Self::Percent,
lexer::ArgExpansion::CharClass(class) => Self::CharClass(class),
}
}
}
#[derive(Debug)]
pub enum ArgPart {
Unit(ArgUnit),
Expansion(ArgExpansion),
}
#[derive(Debug)]
pub struct Argument {
pub parts: Box<[ArgPart]>,
pub pos: SourcePos,
}
impl IllFormed for Argument {
fn ill_formed() -> Self {
Self {
parts: Default::default(),
pos: SourcePos::ill_formed(),
}
}
fn is_ill_formed(&self) -> bool {
self.pos.is_ill_formed()
}
}
#[derive(Debug)]
pub enum RedirectionTarget {
Fd(FileDescriptor),
Overwrite(Argument),
Append(Argument),
}
#[derive(Debug)]
pub enum Redirection {
IllFormed,
Output {
source: FileDescriptor,
target: RedirectionTarget,
},
Input {
literal: bool,
source: Argument,
},
}
impl IllFormed for Redirection {
fn ill_formed() -> Self {
Self::IllFormed
}
fn is_ill_formed(&self) -> bool {
matches!(self, Self::IllFormed)
}
}
#[derive(Debug)]
pub struct BasicCommand {
pub program: Argument,
pub env: Box<[(ArgUnit, Argument)]>,
pub arguments: Box<[Argument]>,
pub redirections: Box<[Redirection]>,
pub abort_on_error: bool,
pub pos: SourcePos,
}
impl IllFormed for BasicCommand {
fn ill_formed() -> Self {
Self {
program: Argument::ill_formed(),
env: Default::default(),
arguments: Default::default(),
redirections: Default::default(),
abort_on_error: Default::default(),
pos: SourcePos::ill_formed(),
}
}
fn is_ill_formed(&self) -> bool {
self.pos.is_ill_formed()
}
}
#[derive(Debug)]
pub struct Command {
pub head: BasicCommand,
pub tail: Box<[BasicCommand]>,
}
impl IllFormed for Command {
fn ill_formed() -> Self {
Self {
head: BasicCommand::ill_formed(),
tail: Default::default(),
}
}
fn is_ill_formed(&self) -> bool {
self.head.is_ill_formed()
}
}
#[derive(Debug)]
pub struct CommandBlock {
pub kind: CommandBlockKind,
pub head: Command,
pub tail: Box<[Command]>,
}
impl IllFormed for CommandBlock {
fn ill_formed() -> Self {
Self {
kind: CommandBlockKind::Synchronous,
head: Command::ill_formed(),
tail: Default::default(),
}
}
fn is_ill_formed(&self) -> bool {
self.head.is_ill_formed()
}
}
#[derive(Debug)]
pub enum CommandBlockKind {
Synchronous, Asynchronous, Capture, }
impl CommandBlockKind {
pub fn from_token(token: &lexer::TokenKind) -> Option<Self> {
match token {
lexer::TokenKind::Command => Some(Self::Synchronous),
lexer::TokenKind::AsyncCommand => Some(Self::Asynchronous),
lexer::TokenKind::CaptureCommand => Some(Self::Capture),
_ => None,
}
}
pub fn is_sync(&self) -> bool {
matches!(self, Self::Synchronous)
}
}