blob: 9729ffe64a34ce68c9301c824f122a7414c171af [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
xbeefe34222014-03-16 00:14:26 -070027#include <stdbool.h>
Damien George20773972014-02-22 18:12:43 +000028#include <stdlib.h>
29
30#include "misc.h"
31#include "mpconfig.h"
32#include "qstr.h"
33#include "nlr.h"
34#include "obj.h"
Damien George06201ff2014-03-01 19:50:50 +000035#include "parsenumbase.h"
Damien George20773972014-02-22 18:12:43 +000036#include "parsenum.h"
Damien Georged1e355e2014-05-28 14:51:12 +010037#include "smallint.h"
Damien George20773972014-02-22 18:12:43 +000038
Damien Georgec06ea7a2014-03-21 10:55:08 +000039#if MICROPY_ENABLE_FLOAT
40#include <math.h>
41#endif
42
Damien George20773972014-02-22 18:12:43 +000043mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
Damien Georgedfbafab2014-03-21 12:15:59 +000044 const char *restrict top = str + len;
45 bool neg = false;
Damien George503d6112014-05-28 14:07:21 +010046 mp_obj_t ret_val;
Damien George20773972014-02-22 18:12:43 +000047
48 // check radix base
49 if ((base != 0 && base < 2) || base > 36) {
Andrew Schellerf78cfaf2014-04-09 19:56:38 +010050 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "int() arg 2 must be >= 2 and <= 36"));
Damien George20773972014-02-22 18:12:43 +000051 }
Damien Georgedfbafab2014-03-21 12:15:59 +000052
53 // skip leading space
54 for (; str < top && unichar_isspace(*str); str++) {
Damien George20773972014-02-22 18:12:43 +000055 }
56
Damien Georgedfbafab2014-03-21 12:15:59 +000057 // parse optional sign
58 if (str < top) {
59 if (*str == '+') {
60 str++;
61 } else if (*str == '-') {
62 str++;
63 neg = true;
Damien George20773972014-02-22 18:12:43 +000064 }
65 }
66
Damien Georgedfbafab2014-03-21 12:15:59 +000067 // parse optional base prefix
68 str += mp_parse_num_base(str, top - str, &base);
Damien George20773972014-02-22 18:12:43 +000069
Damien Georgedfbafab2014-03-21 12:15:59 +000070 // string should be an integer number
71 machine_int_t int_val = 0;
Damien George7b4b78b2014-03-21 20:46:38 +000072 const char *restrict str_val_start = str;
Damien Georgedfbafab2014-03-21 12:15:59 +000073 for (; str < top; str++) {
Damien Georged1e355e2014-05-28 14:51:12 +010074 // get next digit as a value
Damien Georgedfbafab2014-03-21 12:15:59 +000075 int dig = *str;
76 if (unichar_isdigit(dig) && dig - '0' < base) {
77 // 0-9 digit
Damien Georged1e355e2014-05-28 14:51:12 +010078 dig = dig - '0';
Damien Georgedfbafab2014-03-21 12:15:59 +000079 } else if (base == 16) {
80 dig |= 0x20;
81 if ('a' <= dig && dig <= 'f') {
82 // a-f hex digit
Damien Georged1e355e2014-05-28 14:51:12 +010083 dig = dig - 'a' + 10;
Damien Georgedfbafab2014-03-21 12:15:59 +000084 } else {
85 // unknown character
86 break;
87 }
88 } else {
89 // unknown character
90 break;
91 }
Damien Georged1e355e2014-05-28 14:51:12 +010092
93 // add next digi and check for overflow
94 if (mp_small_int_mul_overflow(int_val, base)) {
Damien Georgedfbafab2014-03-21 12:15:59 +000095 goto overflow;
Damien Georged1e355e2014-05-28 14:51:12 +010096 }
97 int_val = int_val * base + dig;
98 if (!MP_SMALL_INT_FITS(int_val)) {
Damien Georgedfbafab2014-03-21 12:15:59 +000099 goto overflow;
100 }
101 }
102
103 // negate value if needed
104 if (neg) {
105 int_val = -int_val;
106 }
107
Damien George503d6112014-05-28 14:07:21 +0100108 // create the small int
109 ret_val = MP_OBJ_NEW_SMALL_INT(int_val);
110
111have_ret_val:
112 // check we parsed something
113 if (str == str_val_start) {
114 goto value_error;
115 }
116
Damien Georgedfbafab2014-03-21 12:15:59 +0000117 // skip trailing space
118 for (; str < top && unichar_isspace(*str); str++) {
119 }
120
121 // check we reached the end of the string
122 if (str != top) {
Damien George7b4b78b2014-03-21 20:46:38 +0000123 goto value_error;
Damien Georgedfbafab2014-03-21 12:15:59 +0000124 }
125
126 // return the object
Damien George503d6112014-05-28 14:07:21 +0100127 return ret_val;
Damien George7b4b78b2014-03-21 20:46:38 +0000128
Damien Georgedfbafab2014-03-21 12:15:59 +0000129overflow:
Damien George503d6112014-05-28 14:07:21 +0100130 // reparse using long int
131 {
132 const char *s2 = str_val_start;
133 ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
134 str = s2;
135 goto have_ret_val;
136 }
137
138value_error:
139 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid syntax for integer with base %d: '%s'", base, str));
Damien George20773972014-02-22 18:12:43 +0000140}
141
Damien George20773972014-02-22 18:12:43 +0000142#define PARSE_DEC_IN_INTG (1)
143#define PARSE_DEC_IN_FRAC (2)
144#define PARSE_DEC_IN_EXP (3)
145
Damien George6e48f7f2014-03-21 11:45:46 +0000146mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex) {
Damien George20773972014-02-22 18:12:43 +0000147#if MICROPY_ENABLE_FLOAT
Damien George20773972014-02-22 18:12:43 +0000148 const char *top = str + len;
Damien Georgec06ea7a2014-03-21 10:55:08 +0000149 mp_float_t dec_val = 0;
150 bool dec_neg = false;
151 bool imag = false;
152
153 // skip leading space
Damien Georgedfbafab2014-03-21 12:15:59 +0000154 for (; str < top && unichar_isspace(*str); str++) {
Damien Georgec06ea7a2014-03-21 10:55:08 +0000155 }
156
Damien Georgedfbafab2014-03-21 12:15:59 +0000157 // parse optional sign
Damien Georgec06ea7a2014-03-21 10:55:08 +0000158 if (str < top) {
159 if (*str == '+') {
Damien George20773972014-02-22 18:12:43 +0000160 str++;
Damien Georgec06ea7a2014-03-21 10:55:08 +0000161 } else if (*str == '-') {
162 str++;
163 dec_neg = true;
Damien George20773972014-02-22 18:12:43 +0000164 }
165 }
Damien Georgec06ea7a2014-03-21 10:55:08 +0000166
167 // determine what the string is
168 if (str < top && (str[0] | 0x20) == 'i') {
169 // string starts with 'i', should be 'inf' or 'infinity' (case insensitive)
170 if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') {
171 // inf
172 str += 3;
173 dec_val = INFINITY;
174 if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') {
175 // infinity
176 str += 5;
177 }
178 }
179 } else if (str < top && (str[0] | 0x20) == 'n') {
180 // string starts with 'n', should be 'nan' (case insensitive)
181 if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') {
182 // NaN
183 str += 3;
184 dec_val = MICROPY_FLOAT_C_FUN(nan)("");
185 }
186 } else {
Damien George6e48f7f2014-03-21 11:45:46 +0000187 // string should be a decimal number
Damien Georgec06ea7a2014-03-21 10:55:08 +0000188 int in = PARSE_DEC_IN_INTG;
189 bool exp_neg = false;
190 int exp_val = 0;
191 int exp_extra = 0;
192 for (; str < top; str++) {
193 int dig = *str;
194 if ('0' <= dig && dig <= '9') {
195 dig -= '0';
196 if (in == PARSE_DEC_IN_EXP) {
197 exp_val = 10 * exp_val + dig;
198 } else {
199 dec_val = 10 * dec_val + dig;
200 if (in == PARSE_DEC_IN_FRAC) {
201 exp_extra -= 1;
202 }
203 }
204 } else if (in == PARSE_DEC_IN_INTG && dig == '.') {
205 in = PARSE_DEC_IN_FRAC;
206 } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) {
207 in = PARSE_DEC_IN_EXP;
208 if (str[1] == '+') {
209 str++;
210 } else if (str[1] == '-') {
211 str++;
212 exp_neg = true;
213 }
214 } else if (allow_imag && (dig | 0x20) == 'j') {
215 str++;
216 imag = true;
217 break;
218 } else {
219 // unknown character
220 break;
221 }
222 }
223
224 // work out the exponent
225 if (exp_neg) {
226 exp_val = -exp_val;
227 }
228 exp_val += exp_extra;
229
230 // apply the exponent
231 for (; exp_val > 0; exp_val--) {
232 dec_val *= 10;
233 }
234 for (; exp_val < 0; exp_val++) {
235 dec_val *= 0.1;
236 }
237 }
238
239 // negate value if needed
240 if (dec_neg) {
241 dec_val = -dec_val;
242 }
243
244 // skip trailing space
Damien Georgedfbafab2014-03-21 12:15:59 +0000245 for (; str < top && unichar_isspace(*str); str++) {
Damien Georgec06ea7a2014-03-21 10:55:08 +0000246 }
247
248 // check we reached the end of the string
249 if (str != top) {
Damien Georgeea13f402014-04-05 18:32:08 +0100250 nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
Damien George20773972014-02-22 18:12:43 +0000251 }
Damien Georgec06ea7a2014-03-21 10:55:08 +0000252
253 // return the object
Damien George20773972014-02-22 18:12:43 +0000254 if (imag) {
255 return mp_obj_new_complex(0, dec_val);
Damien George6e48f7f2014-03-21 11:45:46 +0000256 } else if (force_complex) {
257 return mp_obj_new_complex(dec_val, 0);
Damien George20773972014-02-22 18:12:43 +0000258 } else {
259 return mp_obj_new_float(dec_val);
260 }
Damien Georgec06ea7a2014-03-21 10:55:08 +0000261
Damien George20773972014-02-22 18:12:43 +0000262#else
Damien Georgeea13f402014-04-05 18:32:08 +0100263 nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "decimal numbers not supported"));
Damien George20773972014-02-22 18:12:43 +0000264#endif
265}