working if, else and while

This commit is contained in:
Daniel Bulant 2022-02-21 14:44:02 +01:00
parent 0bb157c9e7
commit b0b6eb7d48
6 changed files with 79 additions and 30 deletions

View file

@ -110,8 +110,13 @@ mod test {
} }
#[test] #[test]
fn if_expr() -> Result<()> { fn if_base() -> Result<()> {
load_and_run("test/if.rush") load_and_run("test/base_if.rush")
}
#[test]
fn if_else() -> Result<()> {
load_and_run("test/if_else.rush")
} }
#[test] #[test]

View file

@ -275,33 +275,70 @@ impl Tree {
fn parse_if(&mut self, end: usize) -> Result<IfExpression> { fn parse_if(&mut self, end: usize) -> Result<IfExpression> {
self.inc(); self.inc();
let condition = self.get_expression(end).with_context(|| "Error getting condition for if expression")?; let condition = self.get_expression(end).with_context(|| "Error getting condition for if expression")?;
dbg!(&condition);
let mut contents = Vec::new(); let mut contents = Vec::new();
loop { loop {
match self.get_next_token() { match self.get_current_token() {
Tokens::End => break, Tokens::End => break,
Tokens::Space => { self.inc(); }, Tokens::Space => {},
Tokens::Else => break,
Tokens::CommandEnd(_) => {}
_ => contents.push(self.get_expression(end).with_context(|| "Error getting contents for if expression")?) _ => contents.push(self.get_expression(end).with_context(|| "Error getting contents for if expression")?)
}; };
self.inc();
}
loop {
match self.get_current_token() {
Tokens::CommandEnd(_) => { self.inc(); },
Tokens::Space => { self.inc(); },
_ => break
}
} }
let mut else_contents = Vec::new(); let mut else_contents = Vec::new();
if matches!(self.get_current_token(), Tokens::Else) {
self.inc();
loop {
match self.get_current_token() {
Tokens::End => break,
Tokens::Space => {},
Tokens::CommandEnd(_) => {}
Tokens::Else => break,
Tokens::If => {
else_contents.push(self.get_expression(end).with_context(|| "Error getting contents for if expression")?);
if else_contents.len() == 1 { break };
}
_ => else_contents.push(self.get_expression(end).with_context(|| "Error getting contents for if expression")?)
};
self.inc();
}
}
if self.i < self.tokens.len() {
loop {
match self.get_current_token() {
Tokens::CommandEnd(_) => { self.inc(); },
Tokens::Space => { self.inc(); },
_ => break
}
if self.i >= self.tokens.len() - 1 { break }
}
self.inc();
}
Ok(IfExpression { condition: Box::new(condition), contents, else_contents }) Ok(IfExpression { condition: Box::new(condition), contents, else_contents })
} }
fn parse_while(&mut self, end: usize) -> Result<WhileExpression> { fn parse_while(&mut self, end: usize) -> Result<WhileExpression> {
self.inc(); self.inc();
let condition = self.get_expression(end).with_context(|| "Error getting condition for while expression")?; let condition = self.get_expression(end).with_context(|| "Error getting condition for while expression")?;
dbg!(&condition);
dbg!(self.i);
let mut contents = Vec::new(); let mut contents = Vec::new();
self.inc();
loop { loop {
let token = self.get_next_token(); let token = self.get_current_token();
dbg!(token, matches!(token, Tokens::End));
match token { match token {
Tokens::End => break, Tokens::End => break,
Tokens::Else => bail!("Unexpected ELSE. Support for ELSE statements after WHILE may come later."),
Tokens::CommandEnd(_) => { self.inc(); },
Tokens::Space => { self.inc(); },
_ => contents.push(self.get_expression(end).with_context(|| "Error getting contents for while expression")?) _ => contents.push(self.get_expression(end).with_context(|| "Error getting contents for while expression")?)
}; };
dbg!(&contents);
} }
self.inc(); self.inc();
Ok(WhileExpression { condition: Box::new(condition), contents }) Ok(WhileExpression { condition: Box::new(condition), contents })
@ -404,9 +441,10 @@ impl Tree {
} }
fn get_expression(&mut self, end: usize) -> Result<Expression> { fn get_expression(&mut self, end: usize) -> Result<Expression> {
let mut token = self.get_current_token();
let mut expr: Option<Expression> = None; let mut expr: Option<Expression> = None;
let mut token = self.get_current_token();
loop { loop {
dbg!(token);
match token { match token {
Tokens::Space => {self.inc();}, Tokens::Space => {self.inc();},
Tokens::CommandEnd(_) => { if matches!(expr, Some(_)) { break }; self.inc();}, Tokens::CommandEnd(_) => { if matches!(expr, Some(_)) { break }; self.inc();},
@ -460,14 +498,14 @@ impl Tree {
_ => expr = Some(self.parse_call(end)?) _ => expr = Some(self.parse_call(end)?)
}, },
Tokens::Else => bail!("Unexpected token ELSE"), Tokens::Else => bail!("Unexpected token ELSE"),
Tokens::End => bail!("Unexpected token END\nCurrent expression:{:?}", expr), Tokens::End => { dbg!(expr); bail!("Unexpected token END"); },
Tokens::For => match expr { Tokens::For => match expr {
Some(_) => bail!("Commands must be ended properly"), Some(_) => bail!("Commands must be ended properly"),
None => expr = Some(Expression::ForExpression(self.parse_for(end)?)), None => expr = Some(Expression::ForExpression(self.parse_for(end)?)),
}, },
Tokens::If => match expr { Tokens::If => match expr {
Some(_) => bail!("Commands must be ended properly"), Some(_) => bail!("Commands must be ended properly"),
None => expr = Some(Expression::IfExpression(self.parse_if(end)?)), None => {expr = Some(Expression::IfExpression(self.parse_if(end)?)); dbg!(&expr); },
} }
Tokens::Let => return Ok(self.parse_let(end)?), Tokens::Let => return Ok(self.parse_let(end)?),
Tokens::While => return Ok(Expression::WhileExpression(self.parse_while(end)?)), Tokens::While => return Ok(Expression::WhileExpression(self.parse_while(end)?)),
@ -501,6 +539,7 @@ impl Tree {
Tokens::JobCommandEnd => bail!("Jobs not yet implemented") Tokens::JobCommandEnd => bail!("Jobs not yet implemented")
} }
if self.i >= end - 1 { break } if self.i >= end - 1 { break }
dbg!("finished loop", &expr);
token = self.get_current_token(); token = self.get_current_token();
} }
match expr { match expr {
@ -526,6 +565,7 @@ pub fn build_tree(tokens: Vec<Tokens>) -> Result<Vec<Expression>> {
match val { match val {
Ok(val) => expressions.push(val), Ok(val) => expressions.push(val),
Err(error) => { Err(error) => {
if error.to_string() == "No expression found" { break }
dbg!(tree); dbg!(tree);
return Err(error); return Err(error);
} }

View file

@ -215,21 +215,20 @@ impl ExecExpression for IfExpression {
None => bail!("Invalid IF expression"), None => bail!("Invalid IF expression"),
Some(cmd) => cmd Some(cmd) => cmd
}; };
ctx.add_scope();
let res = match condition.spawn() { let res = match condition.spawn() {
Result::Err(_) => { Result::Err(_) => {
Some(condition) self.else_contents.exec(ctx)?
}, },
Result::Ok(mut res) => { Result::Ok(mut res) => {
if !res.wait()?.success() { if !res.wait()?.success() {
Some(condition) self.else_contents.exec(ctx)?
} else { } else {
ctx.add_scope(); self.contents.exec(ctx)?
let res = self.contents.exec(ctx)?;
ctx.pop_scope();
res
} }
} }
}; };
ctx.pop_scope();
Ok(res) Ok(res)
} }

View file

@ -175,11 +175,13 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Tokens>> {
';' | '\r' | '\n' => if !escape_active && !quote_active && !double_quote_active { ';' | '\r' | '\n' => if !escape_active && !quote_active && !double_quote_active {
save_buf(&mut buf, &mut tokens); save_buf(&mut buf, &mut tokens);
tokens.push(Tokens::CommandEnd(letter.clone())); tokens.push(Tokens::CommandEnd(letter.clone()));
let mut x = i; let mut x = 0;
while x < text.len() - 1 && matches!(text.chars().nth(x).unwrap(), '\n' | '\r' | ';' | ' ') { while x < text.len() - 1 && matches!(text.chars().nth(x).unwrap(), '\n' | '\r' | ';' | ' ') {
x += 1; x += 1;
} }
skipper = x - i - 1; if x > 0 {
skipper = x - 1;
}
buf_add = false; buf_add = false;
}, },
'&' => if !escape_active && !quote_active && !double_quote_active { '&' => if !escape_active && !quote_active && !double_quote_active {
@ -233,6 +235,15 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Tokens>> {
tokens.push(Tokens::ExportSet); tokens.push(Tokens::ExportSet);
buf_add = false; buf_add = false;
}, },
'#' => if !escape_active && !quote_active && !double_quote_active {
save_buf(&mut buf, &mut tokens);
buf_add = false;
let mut x = 0;
while x + i + 1 < text.len() && text.chars().nth(x + i + 1).unwrap() != '\n' {
x += 1;
}
skipper = x;
}
_ => {} _ => {}
} }
if letter.clone() != '\\' { escape_active = false; } if letter.clone() != '\\' { escape_active = false; }

3
test/base_if.rush Normal file
View file

@ -0,0 +1,3 @@
if true
echo condition true
end

View file

@ -1,12 +1,3 @@
if true
echo condition true
end
if false
echo condition false
end
if true if true
echo condition true echo condition true
else else