#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Program {
pub statements: Vec<Statement>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Statement {
List(AndOrList),
If(IfStatement),
For(ForLoop),
While(WhileLoop),
Case(CaseStatement),
Function(FunctionDefinition),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AndOrList {
pub first: Pipeline,
pub rest: Vec<(AndOr, Pipeline)>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AndOr {
And,
Or,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Pipeline {
pub commands: Vec<SimpleCommand>,
pub negated: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SimpleCommand {
pub assignments: Vec<Assignment>,
pub words: Vec<Word>,
pub redirect: Option<Redirect>,
pub here_doc: Option<Word>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Assignment {
pub name: String,
pub value: Word,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Redirect {
pub append: bool,
pub target: Word,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IfStatement {
pub branches: Vec<(AndOrList, Program)>,
pub otherwise: Option<Program>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ForLoop {
pub variable: String,
pub words: Vec<Word>,
pub body: Program,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WhileLoop {
pub condition: AndOrList,
pub body: Program,
pub until: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CaseStatement {
pub subject: Word,
pub clauses: Vec<CaseClause>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CaseClause {
pub patterns: Vec<CasePattern>,
pub body: Program,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CasePattern {
Any,
Literal(Word),
Expanded(Word),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FunctionDefinition {
pub name: String,
pub body: Program,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Word {
pub parts: Vec<WordPart>,
}
impl Word {
#[must_use]
pub fn as_literal(&self) -> Option<&str> {
match self.parts.as_slice() {
[WordPart::Literal(text)] => Some(text),
_ => None,
}
}
#[must_use]
pub fn is_bare_command_substitution(&self) -> bool {
matches!(self.parts.as_slice(), [WordPart::CommandSubstitution(_)])
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum WordPart {
Literal(String),
SingleQuoted(String),
DoubleQuoted(Vec<WordPart>),
Parameter(Parameter),
CommandSubstitution(Program),
Arithmetic(ArithExpr),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Parameter {
Named {
name: String,
indices: Vec<Word>,
},
Positional(usize),
AllPositional,
AllPositionalJoined,
PositionalCount,
LastStatus,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ArithExpr {
Integer(i64),
Float(f64),
Variable(String),
Unary(ArithUnaryOp, Box<ArithExpr>),
Binary(ArithBinaryOp, Box<ArithExpr>, Box<ArithExpr>),
}
impl Eq for ArithExpr {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ArithUnaryOp {
Negate,
Not,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ArithBinaryOp {
Add,
Subtract,
Multiply,
Divide,
Remainder,
Less,
LessOrEqual,
Greater,
GreaterOrEqual,
Equal,
NotEqual,
And,
Or,
}