blob: c9cef5fcd839ca5ad9006bb6a38efd9bd9901949 [file] [log] [blame]
xbeefe34222014-03-16 00:14:26 -07001#include <stdbool.h>
Damien George20773972014-02-22 18:12:43 +00002#include <stdlib.h>
3
4#include "misc.h"
5#include "mpconfig.h"
6#include "qstr.h"
7#include "nlr.h"
8#include "obj.h"
Damien George06201ff2014-03-01 19:50:50 +00009#include "parsenumbase.h"
Damien George20773972014-02-22 18:12:43 +000010#include "parsenum.h"
11
12#if defined(UNIX)
13
14#include <ctype.h>
15#include <errno.h>
16
17mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
18 // TODO at the moment we ignore len; we should honour it!
19 // TODO detect integer overflow and return bignum
20
21 int c, neg = 0;
22 const char *p = str;
23 char *num;
24 long found;
25
26 // check radix base
27 if ((base != 0 && base < 2) || base > 36) {
28 nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "ValueError: int() arg 2 must be >=2 and <= 36"));
29 }
30 // skip surrounded whitespace
31 while (isspace((c = *(p++))));
32 if (c == 0) {
33 goto value_error;
34 }
35 // preced sign
36 if (c == '+' || c == '-') {
37 neg = - (c == '-');
Damien George20773972014-02-22 18:12:43 +000038 } else {
Damien George20773972014-02-22 18:12:43 +000039 p--;
40 }
41
Damien George06201ff2014-03-01 19:50:50 +000042 len -= p - str;
43 int skip = mp_parse_num_base(p, len, &base);
44 p += skip;
45 len -= skip;
46
Damien George20773972014-02-22 18:12:43 +000047 errno = 0;
48 found = strtol(p, &num, base);
49 if (errno) {
50 goto value_error;
51 } else if (found && *(num) == 0) {
52 goto done;
53 } else if (found || num != p) {
54 goto check_tail_space;
55 } else {
56 goto value_error;
57 }
58
59check_tail_space:
60 if (*(num) != 0) {
61 while (isspace((c = *(num++))));
62 if (c != 0) {
63 goto value_error;
64 }
65 }
66
67done:
68 return MP_OBJ_NEW_SMALL_INT((found ^ neg) - neg);
69
70value_error:
71 nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str));
72}
73
74#else /* defined(UNIX) */
75
76mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
77 // TODO port strtol to stm
78 return MP_OBJ_NEW_SMALL_INT(0);
79}
80
81#endif /* defined(UNIX) */
82
83#define PARSE_DEC_IN_INTG (1)
84#define PARSE_DEC_IN_FRAC (2)
85#define PARSE_DEC_IN_EXP (3)
86
87mp_obj_t mp_parse_num_decimal(const char *str, uint len) {
88#if MICROPY_ENABLE_FLOAT
89 int in = PARSE_DEC_IN_INTG;
90 mp_float_t dec_val = 0;
91 bool exp_neg = false;
92 int exp_val = 0;
93 int exp_extra = 0;
94 bool imag = false;
95 const char *top = str + len;
96 for (; str < top; str++) {
97 int dig = *str;
98 if ('0' <= dig && dig <= '9') {
99 dig -= '0';
100 if (in == PARSE_DEC_IN_EXP) {
101 exp_val = 10 * exp_val + dig;
102 } else {
103 dec_val = 10 * dec_val + dig;
104 if (in == PARSE_DEC_IN_FRAC) {
105 exp_extra -= 1;
106 }
107 }
108 } else if (in == PARSE_DEC_IN_INTG && dig == '.') {
109 in = PARSE_DEC_IN_FRAC;
110 } else if (in != PARSE_DEC_IN_EXP && (dig == 'E' || dig == 'e')) {
111 in = PARSE_DEC_IN_EXP;
112 if (str[1] == '+') {
113 str++;
114 } else if (str[1] == '-') {
115 str++;
116 exp_neg = true;
117 }
118 } else if (dig == 'J' || dig == 'j') {
119 str++;
120 imag = true;
121 break;
122 } else {
123 // unknown character
124 break;
125 }
126 }
127 if (*str != 0) {
128 nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
129 }
130 if (exp_neg) {
131 exp_val = -exp_val;
132 }
133 exp_val += exp_extra;
134 for (; exp_val > 0; exp_val--) {
135 dec_val *= 10;
136 }
137 for (; exp_val < 0; exp_val++) {
138 dec_val *= 0.1;
139 }
140 if (imag) {
141 return mp_obj_new_complex(0, dec_val);
142 } else {
143 return mp_obj_new_float(dec_val);
144 }
145#else
146 nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "decimal numbers not supported"));
147#endif
148}