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