Add basic float support
This commit is contained in:
parent
10a6a52c04
commit
1f195da2ad
4 changed files with 255 additions and 32 deletions
243
src/executor.rs
243
src/executor.rs
|
@ -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)];
|
|
||||||
|
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 {
|
} 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| {
|
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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
)
|
||||||
|
)
|
|
@ -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;
|
||||||
|
|
Reference in a new issue