feat: rudimentary float support

This commit is contained in:
Roman Godmaire 2024-05-06 08:50:38 -04:00
parent 1ed451e696
commit e49dbab859
5 changed files with 31 additions and 2 deletions

16
src/env/core.rs vendored
View file

@ -102,6 +102,10 @@ pub(super) fn core() -> HashMap<String, Node> {
Node::Int128(lhs as i128 + rhs as i128) Node::Int128(lhs as i128 + rhs as i128)
} }
(Node::Int128(lhs), Node::Int(rhs)) => Node::Int128(lhs + rhs as i128), (Node::Int128(lhs), Node::Int(rhs)) => Node::Int128(lhs + rhs as i128),
(Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs + rhs),
(Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 + rhs),
(Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs + rhs as f64),
_ => todo!(), _ => todo!(),
}) })
.unwrap_or(Node::Int(0)); .unwrap_or(Node::Int(0));
@ -124,6 +128,10 @@ pub(super) fn core() -> HashMap<String, Node> {
Node::Int128(lhs as i128 - rhs as i128) Node::Int128(lhs as i128 - rhs as i128)
} }
(Node::Int128(lhs), Node::Int(rhs)) => Node::Int128(lhs - rhs as i128), (Node::Int128(lhs), Node::Int(rhs)) => Node::Int128(lhs - rhs as i128),
(Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs - rhs),
(Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs - rhs as f64),
(Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 - rhs),
_ => todo!(), _ => todo!(),
}) })
.unwrap_or(Node::Int(0)); .unwrap_or(Node::Int(0));
@ -146,6 +154,10 @@ pub(super) fn core() -> HashMap<String, Node> {
Node::Int128(lhs as i128 * rhs as i128) Node::Int128(lhs as i128 * rhs as i128)
} }
(Node::Int128(lhs), Node::Int(rhs)) => Node::Int128(lhs * rhs as i128), (Node::Int128(lhs), Node::Int(rhs)) => Node::Int128(lhs * rhs as i128),
(Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs * rhs),
(Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs * rhs as f64),
(Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 * rhs),
_ => todo!(), _ => todo!(),
}) })
.unwrap_or(Node::Int(0)); .unwrap_or(Node::Int(0));
@ -168,6 +180,10 @@ pub(super) fn core() -> HashMap<String, Node> {
Node::Int128(lhs as i128 / rhs as i128) Node::Int128(lhs as i128 / rhs as i128)
} }
(Node::Int128(lhs), Node::Int(rhs)) => Node::Int128(lhs / rhs as i128), (Node::Int128(lhs), Node::Int(rhs)) => Node::Int128(lhs / rhs as i128),
(Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs / rhs),
(Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs / rhs as f64),
(Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 / rhs),
_ => todo!(), _ => todo!(),
}) })
.unwrap_or(Node::Int(0)); .unwrap_or(Node::Int(0));

View file

@ -109,6 +109,10 @@ mod test {
#[case("(* 8 9)", "72")] #[case("(* 8 9)", "72")]
#[case("(/ 86 2)", "43")] #[case("(/ 86 2)", "43")]
#[case("(+ 1 2 (- 3 4))", "2")] #[case("(+ 1 2 (- 3 4))", "2")]
#[case("(+ 1 0.5)", "1.5")]
#[case("(- 1 0.5)", "0.5")]
#[case("(* 1 0.5)", "0.5")]
#[case("(/ 1.0 2.0)", "0.5")]
// Native functions defaults // Native functions defaults
#[case("(+)", "0")] #[case("(+)", "0")]
#[case("(-)", "0")] #[case("(-)", "0")]
@ -198,6 +202,7 @@ mod test {
#[case("(str (+ 1 2))", "3")] #[case("(str (+ 1 2))", "3")]
#[case("(str (list 1 2 3))", "(1 2 3)")] #[case("(str (list 1 2 3))", "(1 2 3)")]
fn test_evaluator(#[case] input: &str, #[case] expected: &str) { fn test_evaluator(#[case] input: &str, #[case] expected: &str) {
dbg!(input);
let env = Environment::default(); let env = Environment::default();
let ast = parser::parse_str(input).unwrap(); let ast = parser::parse_str(input).unwrap();
let res = eval(&env, ast) let res = eval(&env, ast)

View file

@ -12,6 +12,7 @@ pub enum Node {
Keyword(String), Keyword(String),
Int(i64), Int(i64),
Int128(i128), Int128(i128),
Float(f64),
String(String), String(String),
Boolean(bool), Boolean(bool),
Nil, Nil,
@ -44,6 +45,7 @@ impl std::fmt::Display for Node {
Node::Int(val) => write!(f, "{}", val), Node::Int(val) => write!(f, "{}", val),
Node::Int128(val) => write!(f, "{}", val), Node::Int128(val) => write!(f, "{}", val),
Node::Float(val) => write!(f, "{}", val),
Node::Boolean(true) => write!(f, "true"), Node::Boolean(true) => write!(f, "true"),
Node::Boolean(false) => write!(f, "false"), Node::Boolean(false) => write!(f, "false"),
Node::Symbol(val) => write!(f, "{}", val), Node::Symbol(val) => write!(f, "{}", val),

View file

@ -34,6 +34,7 @@ pub enum Token {
// Values // Values
Keyword(String), Keyword(String),
Int(i64), Int(i64),
Float(f64),
String(String), String(String),
Ident(String), Ident(String),
True, True,
@ -178,14 +179,18 @@ fn read_int(input: &mut Peekable<Chars>, first: char) -> Token {
continue; continue;
} }
if !c.is_ascii_digit() { if !c.is_ascii_digit() && *c != '.' {
break; break;
} }
raw_int.push(input.next().unwrap()); raw_int.push(input.next().unwrap());
} }
Token::Int(raw_int.iter().collect::<String>().parse::<i64>().unwrap()) if raw_int.iter().any(|c| *c == '.') {
Token::Float(raw_int.iter().collect::<String>().parse::<f64>().unwrap())
} else {
Token::Int(raw_int.iter().collect::<String>().parse::<i64>().unwrap())
}
} }
fn read_ident(input: &mut Peekable<Chars>, first: char) -> Token { fn read_ident(input: &mut Peekable<Chars>, first: char) -> Token {

View file

@ -60,6 +60,7 @@ fn next_statement(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Option<Node>
Token::Ident(val) => Node::Symbol(val), Token::Ident(val) => Node::Symbol(val),
Token::String(val) => Node::String(val), Token::String(val) => Node::String(val),
Token::Int(int) => Node::Int(int), Token::Int(int) => Node::Int(int),
Token::Float(float) => Node::Float(float),
Token::True => Node::Boolean(true), Token::True => Node::Boolean(true),
Token::False => Node::Boolean(false), Token::False => Node::Boolean(false),
Token::Nil => Node::Nil, Token::Nil => Node::Nil,