aboutsummaryrefslogtreecommitdiffstats
path: root/src/parse
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/mod.rs105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index b908441..8cc6a4f 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -79,6 +79,35 @@ pub enum Ast<T: Stage> {
FunDecl(FunDecl<T>),
VarAssign(VarAssign<T>),
Pipes(Pipes<T>),
+ If(If<T>),
+}
+
+#[allow(unused)]
+#[derive(Debug, Clone, PartialEq)]
+enum IfParseProgress {
+ Condition,
+ TrueBlock,
+ FalseBlock,
+ Done,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct If<T: Stage> {
+ pub condition: Pipes<T>,
+ pub true_block: Block,
+ pub false_block: Block,
+ parse_progress: IfParseProgress,
+}
+
+impl If<PreExpansion> {
+ fn expand<E: Expander>(self, e: &mut E) -> Res<If<PostExpansion>, E::Error> {
+ Ok(If {
+ condition: self.condition.expand(e)?,
+ true_block: self.true_block,
+ false_block: self.false_block,
+ parse_progress: self.parse_progress,
+ })
+ }
}
pub fn decl(name: ExpString, body: Block) -> Ast<PreExpansion> {
@@ -189,6 +218,15 @@ impl CmdDisplay for Ast<PreExpansion> {
}
write!(w, "])")?;
}
+ Ast::If(i) => {
+ write!(w, "cond(")?;
+ Ast::Pipes(i.condition.clone()).cdisplay(w)?;
+ write!(w, ", ")?;
+ i.true_block.cdisplay(w)?;
+ write!(w, ", ")?;
+ i.false_block.cdisplay(w)?;
+ write!(w, ")")?;
+ }
}
Ok(())
}
@@ -273,6 +311,7 @@ impl Ast<PreExpansion> {
Ast::VarAssign(va) => Ok(Ast::VarAssign(va.expand(e)?)),
Ast::Pipes(pipes) => Ok(Ast::Pipes(pipes.expand(e)?)),
Ast::FunDecl(fd) => Ok(Ast::FunDecl(fd.expand(e)?)),
+ Ast::If(i) => Ok(Ast::If(i.expand(e)?)),
}
}
}
@@ -348,6 +387,7 @@ impl Parse for Block {
if b.peek() != b'}' {
return Err(ParseError::Expected('}'));
}
+ b.adv();
} else if !b.is_completion() {
return Err(ParseError::Expected('}'));
}
@@ -1059,6 +1099,8 @@ pub enum ParseError {
NotHexDigit,
NotABlock,
+
+ NotAnIf,
}
type Result<T> = std::result::Result<T, ParseError>;
@@ -1104,6 +1146,12 @@ impl Block {
CompletionContext::none()
}
}
+
+ fn empty() -> Self {
+ Self {
+ commands: Vec::with_capacity(0),
+ }
+ }
}
impl Ast<PreExpansion> {
@@ -1112,6 +1160,18 @@ impl Ast<PreExpansion> {
Ast::FunDecl(fd) => fd.body.completion(e),
Ast::VarAssign(va) => va.val.completion(e, CompletionKind::Argument),
Ast::Pipes(p) => p.completion(e),
+ Ast::If(i) => i.completion(e),
+ }
+ }
+}
+
+impl If<PreExpansion> {
+ fn completion<E: Expander>(&self, e: &mut E) -> CompletionContext {
+ match self.parse_progress {
+ IfParseProgress::Condition => self.condition.completion(e),
+ IfParseProgress::TrueBlock => self.true_block.completion(e),
+ IfParseProgress::FalseBlock => self.false_block.completion(e),
+ IfParseProgress::Done => CompletionContext::none(),
}
}
}
@@ -1309,11 +1369,56 @@ impl<'a> Cursor<'a> {
}
}
+impl Parse for If<PreExpansion> {
+ fn parse(b: &mut Cursor<'_>) -> Result<Self> {
+ b.spaces();
+ if !b.buf.starts_with(b"if ") || b.buf.starts_with(b"if\t") {
+ return Err(ParseError::NotAnIf);
+ }
+ b.advance(3);
+ b.spaces();
+ let condition = Pipes::parse(b)?;
+ let true_block = Block::parse(b)?;
+
+ b.spaces();
+
+ let false_block = if b.buf.starts_with(b"else") {
+ b.advance(4);
+ Block::parse(b)?
+ } else if b.buf.starts_with(b"elif") {
+ b.advance(2);
+ let elif = If::parse(b)?;
+ Block {
+ commands: vec![Ast::If(elif)],
+ }
+ } else {
+ Block::empty()
+ };
+
+ Ok(If {
+ condition,
+ true_block,
+ false_block,
+
+ // TODO: for completion one should allow more lenient parsing and set this appropriately then
+ parse_progress: IfParseProgress::Done,
+ })
+ }
+}
+
impl Parse for Ast<PreExpansion> {
fn parse(b: &mut Cursor<'_>) -> Result<Self> {
b.spaces();
let orig_len = b.buf.len();
+ let x = If::parse(b);
+ if let Ok(cond) = x {
+ return Ok(Self::If(cond));
+ } else if b.buf.len() != orig_len {
+ x?;
+ }
+
+ let orig_len = b.buf.len();
let x = VarAssign::parse(b);
if let Ok(va) = x {
return Ok(Self::VarAssign(va));