blob: 842a9e9599bdf0ef0ed9f3f6a141e9afc04dac81 [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"
37
Damien Georgec06ea7a2014-03-21 10:55:08 +000038#if MICROPY_ENABLE_FLOAT
39#include <math.h>
40#endif
41
Damien George20773972014-02-22 18:12:43 +000042mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
Damien Georgedfbafab2014-03-21 12:15:59 +000043 const char *restrict top = str + len;
44 bool neg = false;
Damien George503d6112014-05-28 14:07:21 +010045 mp_obj_t ret_val;
Damien George20773972014-02-22 18:12:43 +000046
47 // check radix base
48 if ((base != 0 && base < 2) || base > 36) {
Andrew Schellerf78cfaf2014-04-09 19:56:38 +010049 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 +000050 }
Damien Georgedfbafab2014-03-21 12:15:59 +000051
52 // skip leading space
53 for (; str < top && unichar_isspace(*str); str++) {
Damien George20773972014-02-22 18:12:43 +000054 }
55
Damien Georgedfbafab2014-03-21 12:15:59 +000056 // parse optional sign
57 if (str < top) {
58 if (*str == '+') {
59 str++;
60 } else if (*str == '-') {
61 str++;
62 neg = true;
Damien George20773972014-02-22 18:12:43 +000063 }
64 }
65
Damien Georgedfbafab2014-03-21 12:15:59 +000066 // parse optional base prefix
67 str += mp_parse_num_base(str, top - str, &base);
Damien George20773972014-02-22 18:12:43 +000068
Damien Georgedfbafab2014-03-21 12:15:59 +000069 // string should be an integer number
70 machine_int_t int_val = 0;
Damien George7b4b78b2014-03-21 20:46:38 +000071 const char *restrict str_val_start = str;
Damien Georgedfbafab2014-03-21 12:15:59 +000072 for (; str < top; str++) {
73 machine_int_t old_val = int_val;
74 int dig = *str;
75 if (unichar_isdigit(dig) && dig - '0' < base) {
76 // 0-9 digit
77 int_val = base * int_val + dig - '0';
78 } else if (base == 16) {
79 dig |= 0x20;
80 if ('a' <= dig && dig <= 'f') {
81 // a-f hex digit
82 int_val = base * int_val + dig - 'a' + 10;
83 } else {
84 // unknown character
85 break;
86 }
87 } else {
88 // unknown character
89 break;
90 }
91 if (int_val < old_val) {
92 // If new value became less than previous, it's overflow
93 goto overflow;
94 } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
95 // If signed number changed sign - it's overflow
96 goto overflow;
97 }
98 }
99
100 // negate value if needed
101 if (neg) {
102 int_val = -int_val;
103 }
104
Damien George503d6112014-05-28 14:07:21 +0100105 // create the small int
106 ret_val = MP_OBJ_NEW_SMALL_INT(int_val);
107
108have_ret_val:
109 // check we parsed something
110 if (str == str_val_start) {
111 goto value_error;
112 }
113
Damien Georgedfbafab2014-03-21 12:15:59 +0000114 // skip trailing space
115 for (; str < top && unichar_isspace(*str); str++) {
116 }
117
118 // check we reached the end of the string
119 if (str != top) {
Damien George7b4b78b2014-03-21 20:46:38 +0000120 goto value_error;
Damien Georgedfbafab2014-03-21 12:15:59 +0000121 }
122
123 // return the object
Damien George503d6112014-05-28 14:07:21 +0100124 return ret_val;
Damien George7b4b78b2014-03-21 20:46:38 +0000125
Damien Georgedfbafab2014-03-21 12:15:59 +0000126overflow:
Damien George503d6112014-05-28 14:07:21 +0100127 // reparse using long int
128 {
129 const char *s2 = str_val_start;
130 ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
131 str = s2;
132 goto have_ret_val;
133 }
134
135value_error:
136 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 +0000137}
138
Damien George20773972014-02-22 18:12:43 +0000139#define PARSE_DEC_IN_INTG (1)
140#define PARSE_DEC_IN_FRAC (2)
141#define PARSE_DEC_IN_EXP (3)
142
Damien George6e48f7f2014-03-21 11:45:46 +0000143mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex) {
Damien George20773972014-02-22 18:12:43 +0000144#if MICROPY_ENABLE_FLOAT
Damien George20773972014-02-22 18:12:43 +0000145 const char *top = str + len;
Damien Georgec06ea7a2014-03-21 10:55:08 +0000146 mp_float_t dec_val = 0;
147 bool dec_neg = false;
148 bool imag = false;
149
150 // skip leading space
Damien Georgedfbafab2014-03-21 12:15:59 +0000151 for (; str < top && unichar_isspace(*str); str++) {
Damien Georgec06ea7a2014-03-21 10:55:08 +0000152 }
153
Damien Georgedfbafab2014-03-21 12:15:59 +0000154 // parse optional sign
Damien Georgec06ea7a2014-03-21 10:55:08 +0000155 if (str < top) {
156 if (*str == '+') {
Damien George20773972014-02-22 18:12:43 +0000157 str++;
Damien Georgec06ea7a2014-03-21 10:55:08 +0000158 } else if (*str == '-') {
159 str++;
160 dec_neg = true;
Damien George20773972014-02-22 18:12:43 +0000161 }
162 }
Damien Georgec06ea7a2014-03-21 10:55:08 +0000163
164 // determine what the string is
165 if (str < top && (str[0] | 0x20) == 'i') {
166 // string starts with 'i', should be 'inf' or 'infinity' (case insensitive)
167 if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') {
168 // inf
169 str += 3;
170 dec_val = INFINITY;
171 if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') {
172 // infinity
173 str += 5;
174 }
175 }
176 } else if (str < top && (str[0] | 0x20) == 'n') {
177 // string starts with 'n', should be 'nan' (case insensitive)
178 if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') {
179 // NaN
180 str += 3;
181 dec_val = MICROPY_FLOAT_C_FUN(nan)("");
182 }
183 } else {
Damien George6e48f7f2014-03-21 11:45:46 +0000184 // string should be a decimal number
Damien Georgec06ea7a2014-03-21 10:55:08 +0000185 int in = PARSE_DEC_IN_INTG;
186 bool exp_neg = false;
187 int exp_val = 0;
188 int exp_extra = 0;
189 for (; str < top; str++) {
190 int dig = *str;
191 if ('0' <= dig && dig <= '9') {
192 dig -= '0';
193 if (in == PARSE_DEC_IN_EXP) {
194 exp_val = 10 * exp_val + dig;
195 } else {
196 dec_val = 10 * dec_val + dig;
197 if (in == PARSE_DEC_IN_FRAC) {
198 exp_extra -= 1;
199 }
200 }
201 } else if (in == PARSE_DEC_IN_INTG && dig == '.') {
202 in = PARSE_DEC_IN_FRAC;
203 } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) {
204 in = PARSE_DEC_IN_EXP;
205 if (str[1] == '+') {
206 str++;
207 } else if (str[1] == '-') {
208 str++;
209 exp_neg = true;
210 }
211 } else if (allow_imag && (dig | 0x20) == 'j') {
212 str++;
213 imag = true;
214 break;
215 } else {
216 // unknown character
217 break;
218 }
219 }
220
221 // work out the exponent
222 if (exp_neg) {
223 exp_val = -exp_val;
224 }
225 exp_val += exp_extra;
226
227 // apply the exponent
228 for (; exp_val > 0; exp_val--) {
229 dec_val *= 10;
230 }
231 for (; exp_val < 0; exp_val++) {
232 dec_val *= 0.1;
233 }
234 }
235
236 // negate value if needed
237 if (dec_neg) {
238 dec_val = -dec_val;
239 }
240
241 // skip trailing space
Damien Georgedfbafab2014-03-21 12:15:59 +0000242 for (; str < top && unichar_isspace(*str); str++) {
Damien Georgec06ea7a2014-03-21 10:55:08 +0000243 }
244
245 // check we reached the end of the string
246 if (str != top) {
Damien Georgeea13f402014-04-05 18:32:08 +0100247 nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
Damien George20773972014-02-22 18:12:43 +0000248 }
Damien Georgec06ea7a2014-03-21 10:55:08 +0000249
250 // return the object
Damien George20773972014-02-22 18:12:43 +0000251 if (imag) {
252 return mp_obj_new_complex(0, dec_val);
Damien George6e48f7f2014-03-21 11:45:46 +0000253 } else if (force_complex) {
254 return mp_obj_new_complex(dec_val, 0);
Damien George20773972014-02-22 18:12:43 +0000255 } else {
256 return mp_obj_new_float(dec_val);
257 }
Damien Georgec06ea7a2014-03-21 10:55:08 +0000258
Damien George20773972014-02-22 18:12:43 +0000259#else
Damien Georgeea13f402014-04-05 18:32:08 +0100260 nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "decimal numbers not supported"));
Damien George20773972014-02-22 18:12:43 +0000261#endif
262}