impl loop and add tests for both unary operators and loops
This commit is contained in:
parent
679f0de6b6
commit
caf8a411aa
@ -1153,6 +1153,19 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Stmt::Loop(ref body) => {
|
||||||
|
loop {
|
||||||
|
match self.eval_stmt(scope, body) {
|
||||||
|
Err(EvalAltResult::LoopBreak) => {
|
||||||
|
return Ok(Box::new(()));
|
||||||
|
}
|
||||||
|
Err(x) => {
|
||||||
|
return Err(x);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Stmt::Break => Err(EvalAltResult::LoopBreak),
|
Stmt::Break => Err(EvalAltResult::LoopBreak),
|
||||||
Stmt::Return => Err(EvalAltResult::Return(Box::new(()))),
|
Stmt::Return => Err(EvalAltResult::Return(Box::new(()))),
|
||||||
Stmt::ReturnWithVal(ref a) => {
|
Stmt::ReturnWithVal(ref a) => {
|
||||||
|
@ -90,6 +90,7 @@ pub enum Stmt {
|
|||||||
If(Box<Expr>, Box<Stmt>),
|
If(Box<Expr>, Box<Stmt>),
|
||||||
IfElse(Box<Expr>, Box<Stmt>, Box<Stmt>),
|
IfElse(Box<Expr>, Box<Stmt>, Box<Stmt>),
|
||||||
While(Box<Expr>, Box<Stmt>),
|
While(Box<Expr>, Box<Stmt>),
|
||||||
|
Loop(Box<Stmt>),
|
||||||
Var(String, Option<Box<Expr>>),
|
Var(String, Option<Box<Expr>>),
|
||||||
Block(Vec<Stmt>),
|
Block(Vec<Stmt>),
|
||||||
Expr(Box<Expr>),
|
Expr(Box<Expr>),
|
||||||
@ -142,6 +143,7 @@ pub enum Token {
|
|||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
While,
|
While,
|
||||||
|
Loop,
|
||||||
LessThan,
|
LessThan,
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
Bang,
|
Bang,
|
||||||
@ -398,6 +400,7 @@ impl<'a> TokenIterator<'a> {
|
|||||||
"if" => return Some(Token::If),
|
"if" => return Some(Token::If),
|
||||||
"else" => return Some(Token::Else),
|
"else" => return Some(Token::Else),
|
||||||
"while" => return Some(Token::While),
|
"while" => return Some(Token::While),
|
||||||
|
"loop" => return Some(Token::Loop),
|
||||||
"break" => return Some(Token::Break),
|
"break" => return Some(Token::Break),
|
||||||
"return" => return Some(Token::Return),
|
"return" => return Some(Token::Return),
|
||||||
"fn" => return Some(Token::Fn),
|
"fn" => return Some(Token::Fn),
|
||||||
@ -805,6 +808,14 @@ fn parse_while<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Pars
|
|||||||
Ok(Stmt::While(Box::new(guard), Box::new(body)))
|
Ok(Stmt::While(Box::new(guard), Box::new(body)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_loop<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
||||||
|
input.next();
|
||||||
|
|
||||||
|
let body = try!(parse_block(input));
|
||||||
|
|
||||||
|
Ok(Stmt::Loop(Box::new(body)))
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_var<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
fn parse_var<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
||||||
input.next();
|
input.next();
|
||||||
|
|
||||||
@ -868,6 +879,7 @@ fn parse_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Parse
|
|||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(&Token::If) => parse_if(input),
|
Some(&Token::If) => parse_if(input),
|
||||||
Some(&Token::While) => parse_while(input),
|
Some(&Token::While) => parse_while(input),
|
||||||
|
Some(&Token::Loop) => parse_loop(input),
|
||||||
Some(&Token::Break) => {
|
Some(&Token::Break) => {
|
||||||
input.next();
|
input.next();
|
||||||
Ok(Stmt::Break)
|
Ok(Stmt::Break)
|
||||||
|
47
src/tests.rs
47
src/tests.rs
@ -410,3 +410,50 @@ fn test_comments() {
|
|||||||
|
|
||||||
assert!(engine.eval::<i64>("let /* I am a multiline comment, yay! */ x = 5; x").is_ok());
|
assert!(engine.eval::<i64>("let /* I am a multiline comment, yay! */ x = 5; x").is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unary_minus() {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<i64>("let x = -5; x").unwrap(), -5);
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<i64>("fn n(x) { -x } n(5)").unwrap(), -5);
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<i64>("5 - -(-5)").unwrap(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not() {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<bool>("let not_true = !true; not_true").unwrap(), false);
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<bool>("fn not(x) { !x } not(false)").unwrap(), true);
|
||||||
|
|
||||||
|
// TODO - do we allow stacking unary operators directly? e.g '!!!!!!!true'
|
||||||
|
assert_eq!(engine.eval::<bool>("!(!(!(!(true))))").unwrap(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_loop() {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
engine.eval::<bool>("
|
||||||
|
let x = 0;
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if i < 10 {
|
||||||
|
x = x + i;
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x == 45
|
||||||
|
").unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user