use crate::parser::lex::Keyword;
use crate::parser::lex::Operator;
use crate::parser::lex::TryFromOperatorError;
use crate::source::Location;
use std::cell::OnceCell;
use std::rc::Rc;
use std::str::FromStr;
#[doc(no_inline)]
pub use yash_env::io::Fd;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SpecialParam {
At,
Asterisk,
Number,
Question,
Hyphen,
Dollar,
Exclamation,
Zero,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum ParamType {
Variable,
Special(SpecialParam),
Positional(usize),
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Param {
pub id: String,
pub r#type: ParamType,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SwitchAction {
Alter,
Default,
Assign,
Error,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SwitchCondition {
Unset,
UnsetOrEmpty,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Switch {
pub action: SwitchAction,
pub condition: SwitchCondition,
pub word: Word,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TrimSide {
Prefix,
Suffix,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TrimLength {
Shortest,
Longest,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Trim {
pub side: TrimSide,
pub length: TrimLength,
pub pattern: Word,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Modifier {
None,
Length,
Switch(Switch),
Trim(Trim),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BracedParam {
pub param: Param,
pub modifier: Modifier,
pub location: Location,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BackquoteUnit {
Literal(char),
Backslashed(char),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TextUnit {
Literal(char),
Backslashed(char),
RawParam {
param: Param,
location: Location,
},
BracedParam(BracedParam),
CommandSubst {
content: Rc<str>,
location: Location,
},
Backquote {
content: Vec<BackquoteUnit>,
location: Location,
},
Arith {
content: Text,
location: Location,
},
}
pub use TextUnit::*;
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Text(pub Vec<TextUnit>);
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum EscapeUnit {
Literal(char),
DoubleQuote,
SingleQuote,
Backslash,
Question,
Alert,
Backspace,
Escape,
FormFeed,
Newline,
CarriageReturn,
Tab,
VerticalTab,
Control(u8),
Octal(u8),
Hex(u8),
Unicode(char),
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct EscapedString(pub Vec<EscapeUnit>);
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum WordUnit {
Unquoted(TextUnit),
SingleQuote(String),
DoubleQuote(Text),
DollarSingleQuote(EscapedString),
Tilde {
name: String,
followed_by_slash: bool,
},
}
pub use WordUnit::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Word {
pub units: Vec<WordUnit>,
pub location: Location,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Value {
Scalar(Word),
Array(Vec<Word>),
}
pub use Value::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Assign {
pub name: String,
pub value: Value,
pub location: Location,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RedirOp {
FileIn,
FileInOut,
FileOut,
FileAppend,
FileClobber,
FdIn,
FdOut,
Pipe,
String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HereDoc {
pub delimiter: Word,
pub remove_tabs: bool,
pub content: OnceCell<Text>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RedirBody {
Normal { operator: RedirOp, operand: Word },
HereDoc(Rc<HereDoc>),
}
impl RedirBody {
pub fn operand(&self) -> &Word {
match self {
RedirBody::Normal { operand, .. } => operand,
RedirBody::HereDoc(here_doc) => &here_doc.delimiter,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Redir {
pub fd: Option<Fd>,
pub body: RedirBody,
}
impl Redir {
pub fn fd_or_default(&self) -> Fd {
use RedirOp::*;
self.fd.unwrap_or(match self.body {
RedirBody::Normal { operator, .. } => match operator {
FileIn | FileInOut | FdIn | String => Fd::STDIN,
FileOut | FileAppend | FileClobber | FdOut | Pipe => Fd::STDOUT,
},
RedirBody::HereDoc { .. } => Fd::STDIN,
})
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExpansionMode {
Single,
Multiple,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SimpleCommand {
pub assigns: Vec<Assign>,
pub words: Vec<(Word, ExpansionMode)>,
pub redirs: Rc<Vec<Redir>>,
}
impl SimpleCommand {
pub fn is_empty(&self) -> bool {
self.assigns.is_empty() && self.words.is_empty() && self.redirs.is_empty()
}
pub fn is_one_word(&self) -> bool {
self.assigns.is_empty() && self.words.len() == 1 && self.redirs.is_empty()
}
#[must_use]
fn first_word_is_keyword(&self) -> bool {
let Some((word, _)) = self.words.first() else {
return false;
};
let Some(literal) = word.to_string_if_literal() else {
return false;
};
literal.parse::<Keyword>().is_ok()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ElifThen {
pub condition: List,
pub body: List,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum CaseContinuation {
#[default]
Break,
FallThrough,
Continue,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CaseItem {
pub patterns: Vec<Word>,
pub body: List,
pub continuation: CaseContinuation,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CompoundCommand {
Grouping(List),
Subshell { body: Rc<List>, location: Location },
For {
name: Word,
values: Option<Vec<Word>>,
body: List,
},
While { condition: List, body: List },
Until { condition: List, body: List },
If {
condition: List,
body: List,
elifs: Vec<ElifThen>,
r#else: Option<List>,
},
Case { subject: Word, items: Vec<CaseItem> },
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FullCompoundCommand {
pub command: CompoundCommand,
pub redirs: Vec<Redir>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FunctionDefinition {
pub has_keyword: bool,
pub name: Word,
pub body: Rc<FullCompoundCommand>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Command {
Simple(SimpleCommand),
Compound(FullCompoundCommand),
Function(FunctionDefinition),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Pipeline {
pub commands: Vec<Rc<Command>>,
pub negation: bool,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AndOr {
AndThen,
OrElse,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AndOrList {
pub first: Pipeline,
pub rest: Vec<(AndOr, Pipeline)>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Item {
pub and_or: Rc<AndOrList>,
pub async_flag: Option<Location>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct List(pub Vec<Item>);
mod conversions;
mod impl_display;
pub use conversions::{MaybeLiteral, NotLiteral, NotSpecialParam, Unquote};