#![warn(missing_docs)]
use smol_str::SmolStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Span {
pub start: u32,
pub end: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Program {
pub commands: Vec<CompleteCommand>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CompleteCommand {
pub list: Vec<AndOrList>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct AndOrList {
pub first: Pipeline,
pub rest: Vec<(AndOrOp, Pipeline)>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum AndOrOp {
And,
Or,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Pipeline {
pub timed: bool,
pub time_posix: bool,
pub negated: bool,
pub commands: Vec<Command>,
pub pipe_stderr: Vec<bool>,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Command {
Simple(SimpleCommand),
Subshell(SubshellCommand),
Group(GroupCommand),
If(IfCommand),
While(WhileCommand),
Until(UntilCommand),
For(ForCommand),
ArithFor(ArithForCommand),
FunctionDef(FunctionDef),
Case(CaseCommand),
DoubleBracket(DoubleBracketCommand),
ArithCommand(ArithCommandNode),
Select(SelectCommand),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ArithForCommand {
pub init: SmolStr,
pub cond: SmolStr,
pub step: SmolStr,
pub body: Vec<CompleteCommand>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ArithCommandNode {
pub expr: SmolStr,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SelectCommand {
pub var_name: SmolStr,
pub words: Option<Vec<Word>>,
pub body: Vec<CompleteCommand>,
pub redirections: Vec<Redirection>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DoubleBracketCommand {
pub words: Vec<Word>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SubshellCommand {
pub body: Vec<CompleteCommand>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct GroupCommand {
pub body: Vec<CompleteCommand>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IfCommand {
pub condition: Vec<CompleteCommand>,
pub then_body: Vec<CompleteCommand>,
pub elifs: Vec<ElifClause>,
pub else_body: Option<Vec<CompleteCommand>>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ElifClause {
pub condition: Vec<CompleteCommand>,
pub then_body: Vec<CompleteCommand>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct WhileCommand {
pub condition: Vec<CompleteCommand>,
pub body: Vec<CompleteCommand>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct UntilCommand {
pub condition: Vec<CompleteCommand>,
pub body: Vec<CompleteCommand>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ForCommand {
pub var_name: SmolStr,
pub words: Option<Vec<Word>>,
pub body: Vec<CompleteCommand>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CaseCommand {
pub word: Word,
pub items: Vec<CaseItem>,
pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CaseTerminator {
Break,
Fallthrough,
ContinueTesting,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CaseItem {
pub patterns: Vec<Word>,
pub body: Vec<CompleteCommand>,
pub terminator: CaseTerminator,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionDef {
pub name: SmolStr,
pub body: Box<Command>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SimpleCommand {
pub assignments: Vec<Assignment>,
pub words: Vec<Word>,
pub redirections: Vec<Redirection>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Assignment {
pub name: SmolStr,
pub value: Option<Word>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Word {
pub parts: Vec<WordPart>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum WordPart {
Literal(SmolStr),
SingleQuoted(SmolStr),
DoubleQuoted(Vec<WordPart>),
Parameter(SmolStr),
CommandSubstitution(SmolStr),
Arithmetic(SmolStr),
ProcessSubstIn(SmolStr),
ProcessSubstOut(SmolStr),
}
#[derive(Debug, Clone, PartialEq)]
pub struct Redirection {
pub fd: Option<u32>,
pub op: RedirectionOp,
pub target: Word,
pub here_doc_body: Option<HereDocBody>,
pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RedirectionOp {
Input,
Output,
Append,
Clobber,
AppendBoth,
ReadWrite,
HereDoc,
HereDocStrip,
HereString,
DupOutput,
DupInput,
}
#[derive(Debug, Clone, PartialEq)]
pub struct HereDocBody {
pub content: SmolStr,
pub span: Span,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn span_equality() {
let a = Span { start: 0, end: 5 };
let b = Span { start: 0, end: 5 };
assert_eq!(a, b);
}
#[test]
fn word_with_parts() {
let word = Word {
parts: vec![
WordPart::Literal("hello".into()),
WordPart::Parameter("USER".into()),
],
span: Span { start: 0, end: 11 },
};
assert_eq!(word.parts.len(), 2);
}
}