@@ -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 ( ) {
0 commit comments