Skip to content

Commit 4720422

Browse files
committed
f64 type, addition works with floats and ints together
1 parent 26cbc6c commit 4720422

File tree

4 files changed

+90
-2
lines changed

4 files changed

+90
-2
lines changed

src/reader.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ fn is_minus_char(chr: char) -> bool {
122122
chr == '-'
123123
}
124124

125+
/// Returns true if given character is a period character
126+
/// - `-`,
127+
fn is_period_char(chr: char) -> bool {
128+
chr == '.'
129+
}
130+
131+
125132
/// Parses valid Clojure identifiers
126133
/// Example Successes: ab, cat, -12+3, |blah|, <well>
127134
/// Example Failures: 'a, 12b, ,cat
@@ -173,6 +180,31 @@ pub fn integer_parser(input: &str) -> IResult<&str, i32> {
173180
integer_lexer(input).map(|(rest, digits)| (rest, digits.parse().unwrap()))
174181
}
175182

183+
/// Parses valid doubles
184+
/// Example Successes: -1.0, 0.023, 1234.3223423
185+
///
186+
///
187+
pub fn double_parser(input: &str) -> IResult<&str, f64> {
188+
named!(integer_sign<&str, &str>,
189+
map!(
190+
opt!(take_while_m_n!(1, 1, is_minus_char)),
191+
|maybe_minus| maybe_minus.unwrap_or("")
192+
)
193+
);
194+
named!(integer_part<&str, &str>, take_while1!(|c: char| c.is_digit(10)));
195+
named!(decimal_point<&str, &str>, take_while_m_n!(1, 1, is_period_char));
196+
named!(decimal_part<&str, &str>, take_while1!(|c: char| c.is_digit(10)));
197+
named!(double_lexer <&str, String>,
198+
do_parse!(
199+
sign: integer_sign >>
200+
integer: integer_part >>
201+
point: decimal_point >>
202+
decimal: decimal_part >>
203+
(format!("{}{}{}{}",sign,integer, point, decimal))
204+
)
205+
);
206+
double_lexer(input).map(|(rest, digits)| (rest, digits.parse().unwrap()))
207+
}
176208
// Currently used to create 'try_readers', which are readers (or
177209
// reader functions, at least) that are basically composable InputType
178210
// -> IResult<InputType,Value> parsers, that our normal read function
@@ -214,7 +246,14 @@ pub fn try_read_bool(input: &str) -> IResult<&str, Value> {
214246
Ok((rest_input, Value::Boolean(bool.parse().unwrap())))
215247
}
216248

217-
// Perhaps generalize this into reader macros
249+
250+
/// Tries to parse &str into Value::double
251+
///
252+
pub fn try_read_f64(input: &str) -> IResult<&str, Value> {
253+
to_value_parser(double_parser)(input)
254+
}
255+
256+
// Perhaps generalize this into reader macros
218257
/// Tries to parse &str into Value::Keyword
219258
/// Example Successes:
220259
/// :a => Value::Keyword(Keyword { sym: Symbol { name: "a" })
@@ -337,6 +376,7 @@ pub fn try_read(input: &str) -> IResult<&str, Value> {
337376
alt((
338377
try_read_map,
339378
try_read_string,
379+
try_read_f64,
340380
try_read_i32,
341381
try_read_bool,
342382
try_read_symbol,
@@ -485,8 +525,30 @@ mod tests {
485525
}
486526
}
487527

528+
mod double_parser_tests {
529+
use crate::reader::double_parser;
530+
531+
#[test]
532+
fn double_parser_parses_negative_one() {
533+
let s = "-1.2 ";
534+
assert_eq!(Some((" ", -1.2)), double_parser(s).ok());
535+
}
536+
537+
#[test]
538+
fn double_parser_parses_one() {
539+
let s = "1.12 ";
540+
assert_eq!(Some((" ", 1.12)), double_parser(s).ok());
541+
}
542+
543+
#[test]
544+
fn double_parser_parses_integer_zero() {
545+
let s = "0.0001 ";
546+
assert_eq!(Some((" ", 0.0001)), double_parser(s).ok());
547+
}
548+
}
549+
488550
mod integer_parser_tests {
489-
use crate::reader::{debug_try_read, integer_parser};
551+
use crate::reader::{integer_parser};
490552

491553
#[test]
492554
fn integer_parser_parses_integer_one() {

src/rust_core.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,20 @@ impl IFn for AddFn {
7070
args.into_iter().fold(0_i32.to_value(), |a, b| match a {
7171
Value::I32(a_) => match *b {
7272
Value::I32(b_) => Value::I32(a_ + b_),
73+
Value::F64(b_) => Value::F64(a_ as f64 + b_),
7374
_ => Value::Condition(format!( // TODO: what error message should be returned regarding using typetags?
7475
"Type mismatch; Expecting: (i32 | i64 | f32 | f64), Found: {}",
7576
b.type_tag()
7677
)),
7778
},
79+
Value::F64(a_) => match *b {
80+
Value::I32(b_) => Value::F64(a_ + b_ as f64),
81+
Value::F64(b_) => Value::F64(a_ + b_),
82+
_ => Value::Condition(format!( // TODO: what error message should be returned regarding using typetags?
83+
"Type mismatch; Expecting: (i32 | i64 | f32 | f64), Found: {}",
84+
b.type_tag()
85+
)),
86+
},
7887
_ => Value::Condition(format!( // TODO: what error message should be returned regarding using typetags?
7988
"Type mismatch: Expecting: (i32 | i64 | f32 | f64), Found: {}",
8089
a.type_tag()

src/type_tag.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fmt;
33
#[derive(Debug, Clone)]
44
pub enum TypeTag {
55
I32,
6+
F64,
67
Boolean,
78
Symbol,
89
Keyword,
@@ -26,6 +27,7 @@ impl fmt::Display for TypeTag {
2627
let str = match self {
2728
I32 => std::string::String::from("rust.std.i32"),
2829
Boolean => std::string::String::from("rust.std.bool"),
30+
F64 => std::string::String::from("rust.std.f64"),
2931
Symbol => std::string::String::from("clojure.lang.Symbol"),
3032
Keyword => std::string::String::from("clojure.lang.Keyword"),
3133
IFn => std::string::String::from("clojure.lang.Function"),

src/value.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use std::rc::Rc;
2828
#[derive(Debug, Clone)]
2929
pub enum Value {
3030
I32(i32),
31+
F64(f64),
3132
Boolean(bool),
3233
Symbol(Symbol),
3334
Keyword(Keyword),
@@ -75,6 +76,12 @@ impl PartialEq for Value {
7576
}
7677
}
7778

79+
if let F64(d) = self {
80+
if let F64(d2) = other {
81+
return d == d2;
82+
}
83+
}
84+
7885
if let Boolean(b) = self {
7986
if let Boolean(b2) = other {
8087
return b == b2;
@@ -187,6 +194,7 @@ impl Hash for Value {
187194
fn hash<H: Hasher>(&self, state: &mut H) {
188195
match self {
189196
I32(i) => i.hash(state),
197+
F64(d) => d.to_value().hash(state),
190198
Boolean(b) => b.hash(state),
191199
Symbol(sym) => sym.hash(state),
192200
Keyword(kw) => kw.hash(state),
@@ -224,6 +232,7 @@ impl fmt::Display for Value {
224232
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225233
let str = match self {
226234
I32(val) => val.to_string(),
235+
F64(val) => val.to_string(),
227236
Boolean(val) => val.to_string(),
228237
Symbol(sym) => sym.to_string(),
229238
Keyword(kw) => kw.to_string(),
@@ -263,6 +272,7 @@ impl Value {
263272
pub fn type_tag(&self) -> TypeTag {
264273
match self {
265274
Value::I32(_) => TypeTag::I32,
275+
Value::F64(_) => TypeTag::F64,
266276
Value::Boolean(_) => TypeTag::Boolean,
267277
Value::Symbol(_) => TypeTag::Symbol,
268278
Value::Keyword(_) => TypeTag::Keyword,
@@ -600,6 +610,11 @@ impl ToValue for i32 {
600610
Value::I32(*self)
601611
}
602612
}
613+
impl ToValue for f64 {
614+
fn to_value(&self) -> Value {
615+
Value::F64(*self)
616+
}
617+
}
603618
impl ToValue for bool {
604619
fn to_value(&self) -> Value {
605620
Value::Boolean(*self)

0 commit comments

Comments
 (0)