From ac8733ec1a47bb6bffeb3b1db6adf0a10a7b87a6 Mon Sep 17 00:00:00 2001 From: Jonas Maier Date: Fri, 8 May 2026 09:45:32 +0200 Subject: if statement parsing --- src/parse/mod.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) (limited to 'src/parse') 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 { FunDecl(FunDecl), VarAssign(VarAssign), Pipes(Pipes), + If(If), +} + +#[allow(unused)] +#[derive(Debug, Clone, PartialEq)] +enum IfParseProgress { + Condition, + TrueBlock, + FalseBlock, + Done, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct If { + pub condition: Pipes, + pub true_block: Block, + pub false_block: Block, + parse_progress: IfParseProgress, +} + +impl If { + fn expand(self, e: &mut E) -> Res, 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 { @@ -189,6 +218,15 @@ impl CmdDisplay for Ast { } 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 { 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 = std::result::Result; @@ -1104,6 +1146,12 @@ impl Block { CompletionContext::none() } } + + fn empty() -> Self { + Self { + commands: Vec::with_capacity(0), + } + } } impl Ast { @@ -1112,6 +1160,18 @@ impl Ast { 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 { + fn completion(&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,10 +1369,55 @@ impl<'a> Cursor<'a> { } } +impl Parse for If { + fn parse(b: &mut Cursor<'_>) -> Result { + 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 { fn parse(b: &mut Cursor<'_>) -> Result { 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 { -- cgit v1.2.3