diff --git a/src/executor.rs b/src/executor.rs index 1a5fcf9..f50de47 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -26,51 +26,254 @@ impl LispState { vec![LispValue::Nil] }); - add_function(&mut table, "add", |x| { - if x.len() != 2 { - return vec![LispValue::Nil] + add_function(&mut table, "concat", |x| { + let mut strings = Vec::new(); + for val in x { + strings.push(val.to_string()); } - if let (LispValue::Integer(lhs), LispValue::Integer(rhs)) = (&x[0], &x[1]) { - return vec![LispValue::Integer(lhs + rhs)]; - } else if let (LispValue::String(lhs), LispValue::String(rhs)) = (&x[0], &x[1]) { - return vec![LispValue::String(lhs.to_owned() + rhs)]; - } else { - return vec![LispValue::Nil]; + let str = strings.concat(); + vec![LispValue::String(str)] + }); + + add_function(&mut table, "add", |x| { + if x.len() < 1 { + return vec![LispValue::Nil] + } else if x.len() == 1 { + return vec![x[0].clone()]; + } + + let mut t = "int"; + for v in &x { + match v { + LispValue::Float(_) => t = "float", + LispValue::Integer(_) => (), + _ => return vec![LispValue::Nil] + } + } + + match t { + "int" => { + let mut sum = 0; + for v in &x { + if let LispValue::Integer(n) = v { + sum += n; + } else { + unreachable!() + } + } + return vec![LispValue::Integer(sum)]; + }, + "float" => { + let mut sum = 0.0 as f32; + for v in &x { + if let LispValue::Float(n) = v { + sum += n; + } else if let LispValue::Integer(n) = v{ + sum += *n as f32; + } else { + unreachable!() + } + } + return vec![LispValue::Float(sum)]; + }, + _ => unreachable!() } }); add_function(&mut table, "sub", |x| { - if x.len() != 2 { + if x.len() < 1 { return vec![LispValue::Nil] + } else if x.len() == 1 { + return vec![x[0].clone()]; } - if let (LispValue::Integer(lhs), LispValue::Integer(rhs)) = (&x[0], &x[1]) { - return vec![LispValue::Integer(lhs - rhs)]; + let mut t = "int"; + for v in &x { + match v { + LispValue::Float(_) => t = "float", + LispValue::Integer(_) => (), + _ => return vec![LispValue::Nil] + } + } + + match t { + "int" => { + if let LispValue::Integer(n) = x[0] { + let mut sum = n; + for i in 1..x.len() { + if let LispValue::Integer(n) = &x[i] { + sum -= n; + } else { + unreachable!() + } + } + return vec![LispValue::Integer(sum)]; + } else { + unreachable!() + } + }, + "float" => { + if let LispValue::Float(n) = x[0] { + let mut sum = n; + for i in 1..x.len() { + if let LispValue::Float(n) = &x[i] { + sum -= *n; + } else if let LispValue::Integer(n) = &x[i] { + sum -= *n as f32; + } else { + unreachable!() + } + } + return vec![LispValue::Float(sum)]; + } else if let LispValue::Integer(n) = x[0] { + let mut sum = n as f32; + for i in 1..x.len() { + if let LispValue::Float(n) = &x[i] { + sum -= *n; + } else if let LispValue::Integer(n) = &x[i] { + sum -= *n as f32; + } else { + unreachable!() + } + } + return vec![LispValue::Float(sum)]; + } { + unreachable!() + } + }, + _ => unreachable!() } - vec![LispValue::Nil] }); add_function(&mut table, "mul", |x| { - if x.len() != 2 { + if x.len() < 1 { return vec![LispValue::Nil] + } else if x.len() == 1 { + return vec![x[0].clone()]; } - if let (LispValue::Integer(lhs), LispValue::Integer(rhs)) = (&x[0], &x[1]) { - return vec![LispValue::Integer(lhs * rhs)]; + let mut t = "int"; + for v in &x { + match v { + LispValue::Float(_) => t = "float", + LispValue::Integer(_) => (), + _ => return vec![LispValue::Nil] + } + } + + match t { + "int" => { + if let LispValue::Integer(n) = x[0] { + let mut sum = n; + for i in 1..x.len() { + if let LispValue::Integer(n) = &x[i] { + sum *= n; + } else { + unreachable!() + } + } + return vec![LispValue::Integer(sum)]; + } else { + unreachable!() + } + }, + "float" => { + if let LispValue::Float(n) = x[0] { + let mut product = n; + for i in 1..x.len() { + if let LispValue::Float(n) = &x[i] { + product *= *n; + } else if let LispValue::Integer(n) = &x[i] { + product *= *n as f32; + } else { + unreachable!() + } + } + return vec![LispValue::Float(product)]; + } else if let LispValue::Integer(n) = x[0] { + let mut product = n as f32; + for i in 1..x.len() { + if let LispValue::Float(n) = &x[i] { + product *= *n; + } else if let LispValue::Integer(n) = &x[i] { + product *= *n as f32; + } else { + unreachable!() + } + } + return vec![LispValue::Float(product)]; + } { + unreachable!() + } + }, + _ => unreachable!() } - vec![LispValue::Nil] }); add_function(&mut table, "div", |x| { - if x.len() != 2 { + if x.len() < 1 { return vec![LispValue::Nil] + } else if x.len() == 1 { + return vec![x[0].clone()]; } - if let (LispValue::Integer(lhs), LispValue::Integer(rhs)) = (&x[0], &x[1]) { - return vec![LispValue::Integer(lhs / rhs)]; + let mut t = "int"; + for v in &x { + match v { + LispValue::Float(_) => t = "float", + LispValue::Integer(_) => (), + _ => return vec![LispValue::Nil] + } + } + + match t { + "int" => { + if let LispValue::Integer(n) = x[0] { + let mut sum = n; + for i in 1..x.len() { + if let LispValue::Integer(n) = &x[i] { + sum /= n; + } else { + unreachable!() + } + } + return vec![LispValue::Integer(sum)]; + } else { + unreachable!() + } + }, + "float" => { + if let LispValue::Float(n) = x[0] { + let mut product = n; + for i in 1..x.len() { + if let LispValue::Float(n) = &x[i] { + product /= *n; + } else if let LispValue::Integer(n) = &x[i] { + product /= *n as f32; + } else { + unreachable!() + } + } + return vec![LispValue::Float(product)]; + } else if let LispValue::Integer(n) = x[0] { + let mut product = n as f32; + for i in 1..x.len() { + if let LispValue::Float(n) = &x[i] { + product /= *n; + } else if let LispValue::Integer(n) = &x[i] { + product /= *n as f32; + } else { + unreachable!() + } + } + return vec![LispValue::Float(product)]; + } { + unreachable!() + } + }, + _ => unreachable!() } - vec![LispValue::Nil] }); LispState { diff --git a/src/parser.rs b/src/parser.rs index 4a903a1..822a42e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -7,6 +7,7 @@ pub enum LispValue { Nil, String(String), Integer(i32), + Float(f32), LispFunction(String, Vec), RustFunction(String, fn(Vec) -> Vec), Ref(String), @@ -21,6 +22,7 @@ impl fmt::Display for LispValue { LispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name), LispValue::RustFunction(name, _) => write!(f, "<'{}': Rust Function>", name), LispValue::Integer(num) => write!(f, "{}", num), + LispValue::Float(num) => write!(f, "{}", num), LispValue::Ref(name) => write!(f, "<'{}': Reference>", name), _ => todo!() } @@ -106,9 +108,12 @@ fn parse_exp(tokens: Vec) -> Vec { Token::Integer(num) => { args.push(LispValue::Integer(*num)); }, + Token::Float(num) => { + args.push(LispValue::Float(*num)); + }, Token::String(str) => { args.push(LispValue::String(str.to_owned())); - } + }, Token::CloseParen => { panic!("Unexpected closing parenthesis"); }, @@ -142,9 +147,5 @@ pub fn parse(tokens: Vec) -> Vec { i += 1; } - // opcodes.push(OpCode::Call("print".to_string(), vec![ - // LispValue::from("Hello, World!") - // ])); - opcodes } \ No newline at end of file diff --git a/src/test.lisp b/src/test.lisp index bb4be9e..9d552d0 100644 --- a/src/test.lisp +++ b/src/test.lisp @@ -1,3 +1,8 @@ ; This is a comment -(print (add 1 (mul (div 16 2) (mul 13 2)))) \ No newline at end of file +(print + (add + 1.0 + (mul 2 3) + ) +) \ No newline at end of file diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 0ea24e1..c94609d 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -6,7 +6,8 @@ pub enum Token { CloseParen, Identifier(String), String(String), - Integer(i32) + Integer(i32), + Float(f32) } @@ -38,6 +39,7 @@ pub struct Tokenizer { escape_next_char: bool, reading_num: bool, + is_float: bool, reading_identifier: bool, skipping_comment: bool, @@ -53,6 +55,7 @@ impl Tokenizer { column: 1, reading_num: false, + is_float: false, reading_string: false, escape_next_char: false, @@ -101,12 +104,20 @@ impl Tokenizer { if self.reading_num { // Allow spacing numbers like 1_000_000 - if !char.is_numeric() && char != '_' { + if !char.is_numeric() && char != '_' && char != '.' { self.reading_num = false; + + if self.is_float { + tokens.push(Token::Float(self.storage.iter().collect::().parse().unwrap())); + } else { + tokens.push(Token::Integer(self.storage.iter().collect::().parse().unwrap())); + } - tokens.push(Token::Integer(self.storage.iter().collect::().parse().unwrap())); self.storage.clear(); } else { + if char == '.' { + self.is_float = true; + } if char != '_' { self.storage.push(char); } @@ -165,10 +176,13 @@ impl Tokenizer { // ______100_0__: 1,000 // TODO: delete this when I expand identifiers to include more symbols - } else if c.is_numeric() || c == '_' { + } else if c.is_numeric() || c == '_' || c == '.' { self.reading_num = true; self.storage.clear(); - if c != '_' { + if c.is_numeric() { + self.storage.push(c); + } else if c == '.' { + self.storage.push('0'); self.storage.push(c); } continue;