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]
});
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)];
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 {
return vec![LispValue::Nil];
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 {

View file

@ -7,6 +7,7 @@ pub enum LispValue {
Nil,
String(String),
Integer(i32),
Float(f32),
LispFunction(String, Vec<OpCode>),
RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>),
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<Token>) -> Vec<OpCode> {
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<Token>) -> Vec<OpCode> {
i += 1;
}
// opcodes.push(OpCode::Call("print".to_string(), vec![
// LispValue::from("Hello, World!")
// ]));
opcodes
}

View file

@ -1,3 +1,8 @@
; 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,
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::<String>().parse().unwrap()));
} else {
tokens.push(Token::Integer(self.storage.iter().collect::<String>().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;