py: Implement parsing of infinity and nan for floats.
diff --git a/py/parsenum.c b/py/parsenum.c
index c9cef5f..b1a70c3 100644
--- a/py/parsenum.c
+++ b/py/parsenum.c
@@ -9,6 +9,10 @@
 #include "parsenumbase.h"
 #include "parsenum.h"
 
+#if MICROPY_ENABLE_FLOAT
+#include <math.h>
+#endif
+
 #if defined(UNIX)
 
 #include <ctype.h>
@@ -84,64 +88,120 @@
 #define PARSE_DEC_IN_FRAC (2)
 #define PARSE_DEC_IN_EXP  (3)
 
-mp_obj_t mp_parse_num_decimal(const char *str, uint len) {
+mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag) {
 #if MICROPY_ENABLE_FLOAT
-    int in = PARSE_DEC_IN_INTG;
-    mp_float_t dec_val = 0;
-    bool exp_neg = false;
-    int exp_val = 0;
-    int exp_extra = 0;
-    bool imag = false;
     const char *top = str + len;
-    for (; str < top; str++) {
-        int dig = *str;
-        if ('0' <= dig && dig <= '9') {
-            dig -= '0';
-            if (in == PARSE_DEC_IN_EXP) {
-                exp_val = 10 * exp_val + dig;
-            } else {
-                dec_val = 10 * dec_val + dig;
-                if (in == PARSE_DEC_IN_FRAC) {
-                    exp_extra -= 1;
-                }
-            }
-        } else if (in == PARSE_DEC_IN_INTG && dig == '.') {
-            in = PARSE_DEC_IN_FRAC;
-        } else if (in != PARSE_DEC_IN_EXP && (dig == 'E' || dig == 'e')) {
-            in = PARSE_DEC_IN_EXP;
-            if (str[1] == '+') {
-                str++;
-            } else if (str[1] == '-') {
-                str++;
-                exp_neg = true;
-            }
-        } else if (dig == 'J' || dig == 'j') {
+    mp_float_t dec_val = 0;
+    bool dec_neg = false;
+    bool imag = false;
+
+    // skip leading space
+    for (; str < top && isspace(*str); str++) {
+    }
+
+    // get optional sign
+    if (str < top) {
+        if (*str == '+') {
             str++;
-            imag = true;
-            break;
-        } else {
-            // unknown character
-            break;
+        } else if (*str == '-') {
+            str++;
+            dec_neg = true;
         }
     }
-    if (*str != 0) {
+
+    // determine what the string is
+    if (str < top && (str[0] | 0x20) == 'i') {
+        // string starts with 'i', should be 'inf' or 'infinity' (case insensitive)
+        if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') {
+            // inf
+            str += 3;
+            dec_val = INFINITY;
+            if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') {
+                // infinity
+                str += 5;
+            }
+        }
+    } else if (str < top && (str[0] | 0x20) == 'n') {
+        // string starts with 'n', should be 'nan' (case insensitive)
+        if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') {
+            // NaN
+            str += 3;
+            dec_val = MICROPY_FLOAT_C_FUN(nan)("");
+        }
+    } else {
+        // parse the digits
+        int in = PARSE_DEC_IN_INTG;
+        bool exp_neg = false;
+        int exp_val = 0;
+        int exp_extra = 0;
+        for (; str < top; str++) {
+            int dig = *str;
+            if ('0' <= dig && dig <= '9') {
+                dig -= '0';
+                if (in == PARSE_DEC_IN_EXP) {
+                    exp_val = 10 * exp_val + dig;
+                } else {
+                    dec_val = 10 * dec_val + dig;
+                    if (in == PARSE_DEC_IN_FRAC) {
+                        exp_extra -= 1;
+                    }
+                }
+            } else if (in == PARSE_DEC_IN_INTG && dig == '.') {
+                in = PARSE_DEC_IN_FRAC;
+            } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) {
+                in = PARSE_DEC_IN_EXP;
+                if (str[1] == '+') {
+                    str++;
+                } else if (str[1] == '-') {
+                    str++;
+                    exp_neg = true;
+                }
+            } else if (allow_imag && (dig | 0x20) == 'j') {
+                str++;
+                imag = true;
+                break;
+            } else {
+                // unknown character
+                break;
+            }
+        }
+
+        // work out the exponent
+        if (exp_neg) {
+            exp_val = -exp_val;
+        }
+        exp_val += exp_extra;
+
+        // apply the exponent
+        for (; exp_val > 0; exp_val--) {
+            dec_val *= 10;
+        }
+        for (; exp_val < 0; exp_val++) {
+            dec_val *= 0.1;
+        }
+    }
+
+    // negate value if needed
+    if (dec_neg) {
+        dec_val = -dec_val;
+    }
+
+    // skip trailing space
+    for (; str < top && isspace(*str); str++) {
+    }
+
+    // check we reached the end of the string
+    if (str != top) {
         nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
     }
-    if (exp_neg) {
-        exp_val = -exp_val;
-    }
-    exp_val += exp_extra;
-    for (; exp_val > 0; exp_val--) {
-        dec_val *= 10;
-    }
-    for (; exp_val < 0; exp_val++) {
-        dec_val *= 0.1;
-    }
+
+    // return the object
     if (imag) {
         return mp_obj_new_complex(0, dec_val);
     } else {
         return mp_obj_new_float(dec_val);
     }
+
 #else
     nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "decimal numbers not supported"));
 #endif