From 01666cefb91bebef2c12eadddbf4203ae127cb6c Mon Sep 17 00:00:00 2001 From: russ Date: Fri, 27 Oct 2017 20:30:12 -0700 Subject: [PATCH] candidate f64 support --- src/engine.rs | 27 ++++++++++---------- src/parser.rs | 19 +++++++++++--- src/tests.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 16 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 0d163813..1ca8fffa 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -8,7 +8,7 @@ use parser::{lex, parse, Expr, Stmt, FnDef}; use fn_register::FnRegister; use std::ops::{Add, Sub, Mul, Div}; -use std::cmp::{Ord, Eq}; +use std::cmp::{PartialOrd, PartialEq}; #[derive(Debug)] pub enum EvalAltResult { @@ -913,6 +913,7 @@ impl Engine { fn eval_expr(&self, scope: &mut Scope, expr: &Expr) -> Result, EvalAltResult> { match *expr { Expr::IntConst(i) => Ok(Box::new(i)), + Expr::FloatConst(i) => Ok(Box::new(i)), Expr::StringConst(ref s) => Ok(Box::new(s.clone())), Expr::CharConst(ref c) => Ok(Box::new(*c)), Expr::Identifier(ref id) => { @@ -1329,12 +1330,12 @@ impl Engine { fn sub(x: T, y: T) -> ::Output { x - y } fn mul(x: T, y: T) -> ::Output { x * y } fn div(x: T, y: T) -> ::Output { x / y } - fn lt(x: T, y: T) -> bool { x < y } - fn lte(x: T, y: T) -> bool { x <= y } - fn gt(x: T, y: T) -> bool { x > y } - fn gte(x: T, y: T) -> bool { x >= y } - fn eq(x: T, y: T) -> bool { x == y } - fn ne(x: T, y: T) -> bool { x != y } + fn lt(x: T, y: T) -> bool { x < y } + fn lte(x: T, y: T) -> bool { x <= y } + fn gt(x: T, y: T) -> bool { x > y } + fn gte(x: T, y: T) -> bool { x >= y } + fn eq(x: T, y: T) -> bool { x == y } + fn ne(x: T, y: T) -> bool { x != y } fn and(x: bool, y: bool) -> bool { x && y } fn or(x: bool, y: bool) -> bool { x || y } fn concat(x: String, y: String) -> String { x + &y } @@ -1344,12 +1345,12 @@ impl Engine { reg_op!(engine, "*", mul, i32, i64, u32, u64, f32, f64); reg_op!(engine, "/", div, i32, i64, u32, u64, f32, f64); - reg_cmp!(engine, "<", lt, i32, i64, u32, u64, String); - reg_cmp!(engine, "<=", lte, i32, i64, u32, u64, String); - reg_cmp!(engine, ">", gt, i32, i64, u32, u64, String); - reg_cmp!(engine, ">=", gte, i32, i64, u32, u64, String); - reg_cmp!(engine, "==", eq, i32, i64, u32, u64, bool, String); - reg_cmp!(engine, "!=", ne, i32, i64, u32, u64, bool, String); + reg_cmp!(engine, "<", lt, i32, i64, u32, u64, String, f64); + reg_cmp!(engine, "<=", lte, i32, i64, u32, u64, String, f64); + reg_cmp!(engine, ">", gt, i32, i64, u32, u64, String, f64); + reg_cmp!(engine, ">=", gte, i32, i64, u32, u64, String, f64); + reg_cmp!(engine, "==", eq, i32, i64, u32, u64, bool, String, f64); + reg_cmp!(engine, "!=", ne, i32, i64, u32, u64, bool, String, f64); reg_op!(engine, "||", or, bool); reg_op!(engine, "&&", and, bool); diff --git a/src/parser.rs b/src/parser.rs index 4bf5ff32..64e815a0 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -99,6 +99,7 @@ pub enum Stmt { #[derive(Debug, Clone)] pub enum Expr { IntConst(i64), + FloatConst(f64), Identifier(String), CharConst(char), StringConst(String), @@ -114,6 +115,7 @@ pub enum Expr { #[derive(Debug)] pub enum Token { IntConst(i64), + FloatConst(f64), Identifier(String), CharConst(char), StringConst(String), @@ -306,7 +308,6 @@ impl<'a> Iterator for TokenIterator<'a> { } let out: String = result.iter().cloned().collect(); - match out.as_ref() { "true" => return Some(Token::True), "false" => return Some(Token::False), @@ -317,7 +318,18 @@ impl<'a> Iterator for TokenIterator<'a> { "break" => return Some(Token::Break), "return" => return Some(Token::Return), "fn" => return Some(Token::Fn), - x => return Some(Token::Identifier(x.to_string())) + x => { + match out.starts_with("f") { + false => return Some(Token::Identifier(x.to_string())), + true => { + if let Ok(f) = (&out[1..]).to_owned().replace("_", ".").parse::() { + return Some(Token::FloatConst(f)); + } else { + return Some(Token::Identifier(x.to_string())); + } + } + } + } } } '"' => { @@ -458,7 +470,7 @@ fn parse_call_expr<'a>(id: String, input: &mut Peekable>) -> Result { let mut args = Vec::new(); - + if let Some(&Token::RParen) = input.peek() { input.next(); return Ok(Expr::FnCall(id, args)); @@ -549,6 +561,7 @@ fn parse_primary<'a>(input: &mut Peekable>) -> Result Ok(Expr::IntConst(*x)), + Token::FloatConst(ref x) => Ok(Expr::FloatConst(*x)), Token::StringConst(ref s) => Ok(Expr::StringConst(s.clone())), Token::CharConst(ref c) => Ok(Expr::CharConst(*c)), Token::Identifier(ref s) => parse_ident_expr(s.clone(), input), diff --git a/src/tests.rs b/src/tests.rs index 543c13f2..a9afb512 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -401,3 +401,72 @@ fn test_array_with_structs() { assert!(false); } } + +#[test] +fn test_float() { + let mut engine = Engine::new(); + + if let Ok(result) = engine.eval::("let x = f0_0; let y = f1_0; x < y") { + assert!(result); + } else { + assert!(false); + } + + if let Ok(result) = engine.eval::("let x = f0_0; let y = f1_0; x > y") { + assert!(!result); + } else { + assert!(false); + } + + if let Ok(result) = engine.eval::("let x = f9_9999; x") { + assert_eq!(result, 9.9999); + } else { + assert!(false); + } +} + +#[test] +fn struct_with_float() { + #[derive(Clone)] + struct TestStruct { + x: f64, + } + + impl TestStruct { + fn update(&mut self) { + self.x += 5.789_f64; + } + + fn get_x(&mut self) -> f64 { + self.x + } + + fn set_x(&mut self, new_x: f64) { + self.x = new_x; + } + + fn new() -> TestStruct { + TestStruct { x: 1.0 } + } + } + + let mut engine = Engine::new(); + + engine.register_type::(); + + engine.register_get_set("x", TestStruct::get_x, TestStruct::set_x); + engine.register_fn("update", TestStruct::update); + engine.register_fn("new_ts", TestStruct::new); + + if let Ok(result) = engine.eval::("let ts = new_ts(); ts.update(); ts.x") { + assert_eq!(result, 6.789); + } else { + assert!(false); + } + + if let Ok(result) = engine.eval::("let ts = new_ts(); ts.x = f10_1001; ts.x") { + assert_eq!(result, 10.1001); + } else { + assert!(false); + } +} \ No newline at end of file