8000 py/parsenum: Support parsing complex numbers of the form "a+bj". · micropython/micropython@0172292 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0172292

Browse files
jimmodpgeorge
authored andcommitted
py/parsenum: Support parsing complex numbers of the form "a+bj".
To conform with CPython. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
1 parent 7861edd commit 0172292

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
lines changed

py/parsenum.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m
166166
}
167167
}
168168

169+
enum {
170+
REAL_IMAG_STATE_START = 0,
171+
REAL_IMAG_STATE_HAVE_REAL = 1,
172+
REAL_IMAG_STATE_HAVE_IMAG = 2,
173+
};
174+
169175
typedef enum {
170176
PARSE_DEC_IN_INTG,
171177
PARSE_DEC_IN_FRAC,
@@ -196,7 +202,12 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
196202
const char *top = str + len;
197203
mp_float_t dec_val = 0;
198204
bool dec_neg = false;
199-
bool imag = false;
205+
unsigned int real_imag_state = REAL_IMAG_STATE_START;
206+
207+
#if MICROPY_PY_BUILTINS_COMPLEX
208+
mp_float_t dec_real = 0;
209+
parse_start:
210+
#endif 10000
200211

201212
// skip leading space
202213
for (; str < top && unichar_isspace(*str); str++) {
@@ -281,7 +292,7 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
281292
goto value_error;
282293
}
283294
} else if (allow_imag && (dig | 0x20) == 'j') {
284-
imag = true;
295+
real_imag_state |= REAL_IMAG_STATE_HAVE_IMAG;
285296
break;
286297
} else if (dig == '_') {
287298
continue;
@@ -332,18 +343,34 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
332343

333344
// check we reached the end of the string
334345
if (str != top) {
346+
#if MICROPY_PY_BUILTINS_COMPLEX
347+
if (force_complex && real_imag_state == REAL_IMAG_STATE_START) {
348+
// If we've only seen a real so far, keep parsing for the imaginary part.
349+
dec_real = dec_val;
350+
dec_val = 0;
351+
real_imag_state |= REAL_IMAG_STATE_HAVE_REAL;
352+
goto parse_start;
353+
}
354+
#endif
335355
goto value_error;
336356
}
337357

358+
#if MICROPY_PY_BUILTINS_COMPLEX
359+
if (real_imag_state == REAL_IMAG_STATE_HAVE_REAL) {
360+
// We're on the second part, but didn't get the expected imaginary number.
361+
goto value_error;
362+
}
363+
#endif
364+
338365
// return the object
339366
#if MICROPY_PY_BUILTINS_COMPLEX
340-
if (imag) {
341-
return mp_obj_new_complex(0, dec_val);
367+
if (real_imag_state != REAL_IMAG_STATE_START) {
368+
return mp_obj_new_complex(dec_real, dec_val);
342369
} else if (force_complex) {
343370
return mp_obj_new_complex(dec_val, 0);
344371
}
345372
#else
346-
if (imag || force_complex) {
373+
if (real_imag_state != REAL_IMAG_STATE_START || force_complex) {
347374
raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, MP_ERROR_TEXT("complex values not supported")), lex);
348375
}
349376
#endif

tests/float/complex1.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
print(complex("1"))
88
print(complex("1.2"))
99
print(complex("1.2j"))
10+
print(complex("1+2j"))
11+
print(complex("-1-2j"))
12+
print(complex("+1-2j"))
13+
print(complex(" -1-2j "))
14+
print(complex(" +1-2j "))
1015
print(complex(1, 2))
1116
print(complex(1j, 2j))
1217

@@ -72,6 +77,13 @@
7277
print(float("inf") * (1 + 1j))
7378
print(float("-inf") * (1 + 1j))
7479

80+
# malformed complex strings
81+
for test in ("1+2", "1j+2", "1+2j+3", "1+2+3j", "1 + 2j"):
82+
try:
83+
complex(test)
84+
except ValueError:
85+
print("ValueError", test)
86+
7587
# can't assign to attributes
7688
try:
7789
(1j).imag = 0

0 commit comments

Comments
 (0)
0