mirror of
https://github.com/danbulant/rush
synced 2026-05-24 12:35:38 +00:00
working if, else and while
This commit is contained in:
parent
0bb157c9e7
commit
b0b6eb7d48
6 changed files with 79 additions and 30 deletions
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
3
test/base_if.rush
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
if true
|
||||||
|
echo condition true
|
||||||
|
end
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in a new issue