Add basic float support

This commit is contained in:
Apache 2024-06-12 22:36:23 -05:00
parent 10a6a52c04
commit 1f195da2ad
Signed by: apache
GPG key ID: 6B10F3EAF14F4C77
4 changed files with 255 additions and 32 deletions

View file

@ -26,51 +26,254 @@ impl LispState {
vec![LispValue::Nil] vec![LispValue::Nil]
}); });
add_function(&mut table, "add", |x| { add_function(&mut table, "concat", |x| {
if x.len() != 2 { let mut strings = Vec::new();
return vec![LispValue::Nil] for val in x {
strings.push(val.to_string());
} }
if let (LispValue::Integer(lhs), LispValue::Integer(rhs)) = (&x[0], &x[1]) { let str = strings.concat();
return vec![LispValue::Integer(lhs + rhs)]; vec![LispValue::String(str)]
} else if let (LispValue::String(lhs), LispValue::String(rhs)) = (&x[0], &x[1]) { });
return vec![LispValue::String(lhs.to_owned() + rhs)];
} else { add_function(&mut table, "add", |x| {
return vec![LispValue::Nil]; 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| { add_function(&mut table, "sub", |x| {
if x.len() != 2 { if x.len() < 1 {
return vec![LispValue::Nil] 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]) { let mut t = "int";
return vec![LispValue::Integer(lhs - rhs)]; 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| { add_function(&mut table, "mul", |x| {
if x.len() != 2 { if x.len() < 1 {
return vec![LispValue::Nil] 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]) { let mut t = "int";
return vec![LispValue::Integer(lhs * rhs)]; 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| { add_function(&mut table, "div", |x| {
if x.len() != 2 { if x.len() < 1 {
return vec![LispValue::Nil] 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]) { let mut t = "int";
return vec![LispValue::Integer(lhs / rhs)]; 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 { LispState {

View file

@ -7,6 +7,7 @@ pub enum LispValue {
Nil, Nil,
String(String), String(String),
Integer(i32), Integer(i32),
Float(f32),
LispFunction(String, Vec<OpCode>), LispFunction(String, Vec<OpCode>),
RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>), RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>),
Ref(String), Ref(String),
@ -21,6 +22,7 @@ impl fmt::Display for LispValue {
LispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name), LispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name),
LispValue::RustFunction(name, _) => write!(f, "<'{}': Rust Function>", name), LispValue::RustFunction(name, _) => write!(f, "<'{}': Rust Function>", name),
LispValue::Integer(num) => write!(f, "{}", num), LispValue::Integer(num) => write!(f, "{}", num),
LispValue::Float(num) => write!(f, "{}", num),
LispValue::Ref(name) => write!(f, "<'{}': Reference>", name), LispValue::Ref(name) => write!(f, "<'{}': Reference>", name),
_ => todo!() _ => todo!()
} }
@ -106,9 +108,12 @@ fn parse_exp(tokens: Vec<Token>) -> Vec<OpCode> {
Token::Integer(num) => { Token::Integer(num) => {
args.push(LispValue::Integer(*num)); args.push(LispValue::Integer(*num));
}, },
Token::Float(num) => {
args.push(LispValue::Float(*num));
},
Token::String(str) => { Token::String(str) => {
args.push(LispValue::String(str.to_owned())); args.push(LispValue::String(str.to_owned()));
} },
Token::CloseParen => { Token::CloseParen => {
panic!("Unexpected closing parenthesis"); panic!("Unexpected closing parenthesis");
}, },
@ -142,9 +147,5 @@ pub fn parse(tokens: Vec<Token>) -> Vec<OpCode> {
i += 1; i += 1;
} }
// opcodes.push(OpCode::Call("print".to_string(), vec![
// LispValue::from("Hello, World!")
// ]));
opcodes opcodes
} }

View file

@ -1,3 +1,8 @@
; This is a comment ; This is a comment
(print (add 1 (mul (div 16 2) (mul 13 2)))) (print
(add
1.0
(mul 2 3)
)
)

View file

@ -6,7 +6,8 @@ pub enum Token {
CloseParen, CloseParen,
Identifier(String), Identifier(String),
String(String), String(String),
Integer(i32) Integer(i32),
Float(f32)
} }
@ -38,6 +39,7 @@ pub struct Tokenizer {
escape_next_char: bool, escape_next_char: bool,
reading_num: bool, reading_num: bool,
is_float: bool,
reading_identifier: bool, reading_identifier: bool,
skipping_comment: bool, skipping_comment: bool,
@ -53,6 +55,7 @@ impl Tokenizer {
column: 1, column: 1,
reading_num: false, reading_num: false,
is_float: false,
reading_string: false, reading_string: false,
escape_next_char: false, escape_next_char: false,
@ -101,12 +104,20 @@ impl Tokenizer {
if self.reading_num { if self.reading_num {
// Allow spacing numbers like 1_000_000 // Allow spacing numbers like 1_000_000
if !char.is_numeric() && char != '_' { if !char.is_numeric() && char != '_' && char != '.' {
self.reading_num = false; self.reading_num = false;
if self.is_float {
tokens.push(Token::Float(self.storage.iter().collect::<String>().parse().unwrap()));
} else {
tokens.push(Token::Integer(self.storage.iter().collect::<String>().parse().unwrap()));
}
tokens.push(Token::Integer(self.storage.iter().collect::<String>().parse().unwrap()));
self.storage.clear(); self.storage.clear();
} else { } else {
if char == '.' {
self.is_float = true;
}
if char != '_' { if char != '_' {
self.storage.push(char); self.storage.push(char);
} }
@ -165,10 +176,13 @@ impl Tokenizer {
// ______100_0__: 1,000 // ______100_0__: 1,000
// TODO: delete this when I expand identifiers to include more symbols // 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.reading_num = true;
self.storage.clear(); self.storage.clear();
if c != '_' { if c.is_numeric() {
self.storage.push(c);
} else if c == '.' {
self.storage.push('0');
self.storage.push(c); self.storage.push(c);
} }
continue; continue;