aboutsummaryrefslogtreecommitdiffstats
path: root/src/parse/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse/mod.rs')
-rw-r--r--src/parse/mod.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 6ce3133..68a5e56 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -87,6 +87,7 @@ pub enum Ast<T: Stage> {
Pipes(Pipes<T>),
If(If<T>),
While(While),
+ Case(Case<T>),
}
#[derive(Debug, Clone, PartialEq)]
@@ -276,6 +277,20 @@ impl CmdDisplay for Ast<PreExpansion> {
l.block.cdisplay(w)?;
write!(w, ")")?;
}
+ Ast::Case(c) => {
+ write!(w, "case(")?;
+ c.discriminant.cdisplay(w)?;
+ write!(w, ", [")?;
+ let mut first = true;
+ for case in c.branches.iter() {
+ if !first {
+ write!(w, ", ")?;
+ }
+ first = false;
+ case.cdisplay(w)?;
+ }
+ write!(w, "])")?;
+ }
}
Ok(())
}
@@ -360,6 +375,7 @@ impl Ast<PreExpansion> {
Ast::FunDecl(fd) => Ok(Ast::FunDecl(fd.expand(e)?)),
Ast::If(i) => Ok(Ast::If(i.expand(e)?)),
Ast::While(w) => Ok(Ast::While(w)),
+ Ast::Case(c) => Ok(Ast::Case(c.expand(e)?)),
}
}
}
@@ -1231,6 +1247,7 @@ impl Ast<PreExpansion> {
Ast::Pipes(p) => p.completion(e),
Ast::If(i) => i.completion(e),
Ast::While(_) => todo!(),
+ Ast::Case(_) => todo!(),
}
}
}
@@ -1621,6 +1638,7 @@ pub enum Keyword {
Elif,
OpenBrace,
CloseBrace,
+ Case,
}
impl Keyword {
@@ -1632,6 +1650,7 @@ impl Keyword {
Keyword::Else => b"else",
Keyword::OpenBrace => b"{",
Keyword::CloseBrace => b"}",
+ Keyword::Case => b"case",
}
}
@@ -1643,6 +1662,7 @@ impl Keyword {
Keyword::Else => false,
Keyword::OpenBrace => false,
Keyword::CloseBrace => false,
+ Keyword::Case => true,
}
}
@@ -1750,6 +1770,14 @@ impl Ast<PreExpansion> {
x?;
}
+ let orig_len = b.buf.len();
+ let x = Case::parse(b);
+ if let Ok(c) = x {
+ return Ok(Self::Case(c));
+ } else if b.buf.len() != orig_len {
+ x?;
+ }
+
Ok(Self::Pipes(b.parse()?))
}
}
@@ -1813,3 +1841,70 @@ impl Parse for Pipes<PreExpansion> {
}
}
}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct CaseBranch {
+ pub pattern: BString,
+ pub block: Block,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct Case<T: Stage> {
+ pub discriminant: T::Str,
+ pub branches: Vec<CaseBranch>,
+}
+
+impl CmdDisplay for CaseBranch {
+ fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> {
+ write!(w, "cbranch(b\"{}\", ", self.pattern.escape_ascii())?;
+ self.block.cdisplay(w)?;
+ write!(w, ")")
+ }
+}
+
+impl Case<PreExpansion> {
+ fn expand<E: Expander>(self, e: &mut E) -> Res<Case<PostExpansion>, E::Error> {
+ Ok(Case {
+ discriminant: self.discriminant.expand(e)?,
+ branches: self.branches,
+ })
+ }
+}
+
+impl Parse for CaseBranch {
+ fn parse(b: &mut Cursor<'_>) -> Result<Self> {
+ b.spaces();
+
+ let mut pattern = Vec::new();
+ while b.has() && b.peek() != b'{' {
+ pattern.push(b.adv());
+ }
+ while let Some(b' ' | b'\n' | b'\t' | b'\r') = pattern.last() {
+ pattern.pop();
+ }
+
+ let block = Block::parse(b)?;
+
+ Ok(Self { pattern, block })
+ }
+}
+
+impl Parse for Case<PreExpansion> {
+ fn parse(b: &mut Cursor<'_>) -> Result<Self> {
+ b.consume_keyword(Keyword::Case)?;
+ let discriminant = ExpString::parse(b)?;
+ b.consume_keyword(Keyword::OpenBrace)?;
+ let mut branches = Vec::new();
+ loop {
+ b.spaces();
+ if let Ok(_) = b.consume_keyword(Keyword::CloseBrace) {
+ break;
+ }
+ branches.push(CaseBranch::parse(b)?);
+ }
+ Ok(Self {
+ discriminant,
+ branches,
+ })
+ }
+}