diff options
author | xyb <xieyanbo@gmail.com> | 2014-01-14 21:39:05 +0800 |
---|---|---|
committer | xyb <xieyanbo@gmail.com> | 2014-01-14 21:39:05 +0800 |
commit | c178ea471ee30f32439741181d30d6a89830aabf (patch) | |
tree | bbd572854f1491523ab70f122695f511c3d9c265 | |
parent | 729e9cce7bd31d3f107a4d6e9498b0fa27119e22 (diff) | |
download | micropython-c178ea471ee30f32439741181d30d6a89830aabf.tar.gz micropython-c178ea471ee30f32439741181d30d6a89830aabf.zip |
Implemented int(str) in UNIX
-rw-r--r-- | py/obj.c | 18 | ||||
-rw-r--r-- | py/obj.h | 1 | ||||
-rw-r--r-- | py/objint.c | 5 | ||||
-rw-r--r-- | py/py.mk | 1 | ||||
-rw-r--r-- | py/strtonum.c | 168 | ||||
-rw-r--r-- | py/strtonum.h | 1 | ||||
-rw-r--r-- | tests/basics/tests/int1.py | 54 | ||||
-rw-r--r-- | unix-cpy/Makefile | 2 | ||||
-rw-r--r-- | unix/Makefile | 2 |
9 files changed, 248 insertions, 4 deletions
@@ -13,6 +13,7 @@ #include "runtime0.h" #include "runtime.h" #include "map.h" +#include "strtonum.h" mp_obj_t mp_obj_get_type(mp_obj_t o_in) { if (MP_OBJ_IS_SMALL_INT(o_in)) { @@ -136,6 +137,12 @@ bool mp_obj_less(mp_obj_t o1, mp_obj_t o2) { } machine_int_t mp_obj_get_int(mp_obj_t arg) { + return mp_obj_get_int_base(arg, 0); +} + +machine_int_t mp_obj_get_int_base(mp_obj_t arg, mp_obj_t base_arg) { + const char *value; + int base; if (arg == mp_const_false) { return 0; } else if (arg == mp_const_true) { @@ -147,6 +154,17 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) { // TODO work out if this should be floor, ceil or trunc return (machine_int_t)mp_obj_float_get(arg); #endif + } else if (MP_OBJ_IS_TYPE(arg, &str_type)) { + if (base_arg == 0) { + value = qstr_str(mp_obj_str_get(arg)); + return (machine_int_t)strtonum(value, 0); + } else if (MP_OBJ_IS_TYPE(base_arg, &int_type)) { + base = MP_OBJ_SMALL_INT_VALUE(base_arg); + value = qstr_str(mp_obj_str_get(arg)); + return (machine_int_t)strtonum(value, base); + } else { + nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "an integer is required")); + } } else { nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); } @@ -235,6 +235,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); bool mp_obj_less(mp_obj_t o1, mp_obj_t o2); machine_int_t mp_obj_get_int(mp_obj_t arg); +machine_int_t mp_obj_get_int_base(mp_obj_t arg, mp_obj_t base_arg); #if MICROPY_ENABLE_FLOAT mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); diff --git a/py/objint.c b/py/objint.c index 9cd5ebae29..58fc37b3bb 100644 --- a/py/objint.c +++ b/py/objint.c @@ -22,8 +22,9 @@ static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) // TODO allow string as arg and parse it return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0])); - //case 2: - // TODO, parse with given base + case 2: + // TODO make args[0] and args[1] correct + return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_base(args[0], args[1])); default: nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "int takes at most 2 arguments, %d given", (void*)(machine_int_t)n_args)); @@ -70,6 +70,7 @@ PY_O_BASENAME = \ emitinlinethumb.o \ runtime.o \ map.o \ + strtonum.o \ obj.o \ objbool.o \ objboundmeth.o \ diff --git a/py/strtonum.c b/py/strtonum.c new file mode 100644 index 0000000000..7cc45bcba4 --- /dev/null +++ b/py/strtonum.c @@ -0,0 +1,168 @@ +#if defined(UNIX) + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "misc.h" +#include "mpconfig.h" +#include "mpqstr.h" +#include "nlr.h" +#include "obj.h" + + +long strtonum(const char *restrict s, int base) { + int c, neg = 0; + const char *p = s; + char *num; + long found; + + // check radix base + if ((base != 0 && base < 2) || base > 36) { + printf("ValueError: int() arg 2 must be >=2 and <= 36\n"); + return 0; + } + // skip surrounded whitespace + while (isspace((c = *(p++)))); + if (c == 0) { + goto value_error; + } + // preced sign + if (c == '+' || c == '-') { + neg = - (c == '-'); + c = *(p++); + } + + // find real radix base, and strip preced '0x', '0o' and '0b' + if ((base == 0 || base == 16) && c == '0') { + c = *(p++); + if ((c | 32) == 'x') { + base = 16; + } else if (base == 0 && (c | 32) == 'o') { + base = 8; + } else if (base == 0 && (c | 32) == 'b') { + base = 2; + } else { + base = 10; + p -= 2; + } + } else if (base == 8 && c == '0') { + if ((c | 32) == 'o') { + base = 8; + } else { + goto value_error; + } + } else if (base == 2 && c == '0') { + if ((c | 32) == 'b') { + base = 2; + } else { + goto value_error; + } + } else { + if (base == 0) base = 10; + p--; + } + + found = strtol(p, &num, base); + if (errno) { + goto value_error; + } else if (found && *(num) == 0) { + goto done; + } else if (found || num != p) { + goto check_tail_space; + } else { + goto value_error; + } + +check_tail_space: + if (*(num) != 0) { + while (isspace((c = *(num++)))); + if (c != 0) { + goto value_error; + } + } + +done: + return (found ^ neg) - neg; + +value_error: + nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_ValueError, "invalid literal for int() with base %d: '%s'", (void*)(machine_uint_t)base, s)); + //printf("invalid literal for int() with base %d: '%s'\n", base, s); + //return 0; +} + +/* +int main(void) { + printf(" 0 %ld\n", strtonum("0", 0)); + printf(" 1 %ld\n", strtonum("1", 0)); + printf(" 1 %ld\n", strtonum("+1", 0)); + printf(" -1 %ld\n", strtonum("-1", 0)); + printf(" 0 %ld\n", strtonum("+0", 0)); + printf(" 0 %ld\n", strtonum("-0", 0)); + printf(" 1 %ld\n", strtonum("01", 0)); + printf(" 9 %ld\n", strtonum("9", 0)); + printf(" 10 %ld\n", strtonum("10", 0)); + printf(" 10 %ld\n", strtonum("+10", 0)); + printf("-10 %ld\n", strtonum("-10", 0)); + printf(" 12 %ld\n", strtonum("12", 0)); + printf("-12 %ld\n", strtonum("-12", 0)); + printf(" 99 %ld\n", strtonum("99", 0)); + printf("100 %ld\n", strtonum("100", 0)); + printf("314 %ld\n", strtonum("314", 0)); + printf("314 %ld\n", strtonum(" 314", 0)); + printf("314 %ld\n", strtonum("314 ", 0)); + printf("314 %ld\n", strtonum(" \t\t 314 \t\t ", 0)); + printf(" 1 %ld\n", strtonum(" 1 ", 0)); + printf(" -3 %ld\n", strtonum(" -3 ", 0)); + printf(" 83 %ld\n", strtonum("0o123", 0)); + printf(" 18 %ld\n", strtonum("0x12", 0)); + printf(" 10 %ld\n", strtonum("0o12", 0)); + printf(" 10 %ld\n", strtonum("0o12", 0)); + printf(" 10 %ld\n", strtonum(" \t 0o12", 0)); + printf(" 10 %ld\n", strtonum("0o12 \t ", 0)); + printf(" 10 %ld\n", strtonum("0O12", 0)); + printf(" 5 %ld\n", strtonum("0b101", 0)); + printf(" 5 %ld\n", strtonum("0b101", 0)); + + printf(" 0 %ld\n", strtonum("0", 10)); + printf(" 1 %ld\n", strtonum("1", 10)); + printf(" 1 %ld\n", strtonum(" \t 1 \t ", 10)); + printf(" 11 %ld\n", strtonum("11", 10)); + printf(" 17 %ld\n", strtonum("11", 16)); + printf(" 9 %ld\n", strtonum("11", 8)); + printf(" 3 %ld\n", strtonum("11", 2)); + printf(" 37 %ld\n", strtonum("11", 36)); + printf("4294967296 %ld\n", strtonum("4294967296", 0)); + + printf("%ld\n", strtonum("x", 0)); + printf("%ld\n", strtonum("1x", 0)); + printf("%ld\n", strtonum(" 1x", 0)); + printf("%ld\n", strtonum(" 1\02 ", 0)); + printf("%ld\n", strtonum("", 0)); + printf("%ld\n", strtonum(" ", 0)); + printf("%ld\n", strtonum(" \t\t ", 0)); + printf("%ld\n", strtonum("0x", 0)); + printf("%ld\n", strtonum("0x", 16)); + printf("%ld\n", strtonum("0o", 0)); + printf("%ld\n", strtonum("0o", 8)); + printf("%ld\n", strtonum("0b", 0)); + printf("%ld\n", strtonum("0b", 2)); + printf("%ld\n", strtonum("0b2", 2)); + printf("%ld\n", strtonum("0o8", 8)); + printf("%ld\n", strtonum("0xg", 16)); + + printf("%ld\n", strtonum("1 1", 0)); + printf("%ld\n", strtonum("18446744073709551616", 0)); +} +*/ + +#else /* defined(UNIX) */ + +long strtonum(const char *restrict s, int base) { + // TODO port strtol to stm + return 0; +} + +#endif /* defined(UNIX) */ diff --git a/py/strtonum.h b/py/strtonum.h new file mode 100644 index 0000000000..03565cca14 --- /dev/null +++ b/py/strtonum.h @@ -0,0 +1 @@ +long strtonum(const char *restrict s, int base); diff --git a/tests/basics/tests/int1.py b/tests/basics/tests/int1.py new file mode 100644 index 0000000000..d766216d44 --- /dev/null +++ b/tests/basics/tests/int1.py @@ -0,0 +1,54 @@ +print(int(0)) +print(int(1)) +print(int(+1)) +print(int(-1)) + +print(int('0')) +print(int('+0')) +print(int('-0')) +print(int('1')) +print(int('+1')) +print(int('-1')) +print(int('9')) +print(int('10')) +print(int('+10')) +print(int('-10')) +print(int('99')) +print(int('100')) +print(int('314')) +print(int(' 314')) +print(int('314 ')) +print(int(' \t\t 314 \t\t ')) +print(int(' 1 ')) +print(int(' -3 ')) + +print(int('10', 16)) +print(int('0o123', 0)) +print(int('0x123', 16)) +print(int('0X123', 16)) +print(int('0O123', 8)) +print(int('0B100', 2)) + + +def test(value, base): + try: + print(int(value, base)) + except ValueError: + print('ValueError') + + +test(' 1x', 0) +test(' 1\02 ', 0) +test('', 0) +test(' ', 0) +test(' \t\t ', 0) +test("\u0200", 0) +test('0x', 16) +test('0x', 0) +test('0o', 8) +test('0o', 0) +test('0b', 2) +test('0b', 0) +test('0b2', 2) +test('0o8', 8) +test('0xg', 16) diff --git a/unix-cpy/Makefile b/unix-cpy/Makefile index 90e1f733d5..d5397dac9a 100644 --- a/unix-cpy/Makefile +++ b/unix-cpy/Makefile @@ -11,7 +11,7 @@ ECHO = @echo # compiler settings CC = gcc -CFLAGS = -I. -I$(PY_SRC) -Wall -Werror -ansi -std=gnu99 -Os #-DNDEBUG +CFLAGS = -I. -I$(PY_SRC) -Wall -Werror -ansi -std=gnu99 -Os -DUNIX #-DNDEBUG LDFLAGS = -lm # source files diff --git a/unix/Makefile b/unix/Makefile index e9bae4768e..9af86b9855 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -11,7 +11,7 @@ ECHO = @echo # compiler settings CC = gcc -CFLAGS = -I. -I$(PY_SRC) -Wall -Werror -ansi -std=gnu99 -Os #-DNDEBUG +CFLAGS = -I. -I$(PY_SRC) -Wall -Werror -ansi -std=gnu99 -Os -DUNIX #-DNDEBUG LDFLAGS = -lm # source files |