From: Igor Sysoev Date: Mon, 25 Apr 2016 14:28:34 +0000 (+0300) Subject: parseInt() function. X-Git-Tag: 0.1.0~23 X-Git-Url: http://git.kaiwu.me/sitemap.xml?a=commitdiff_plain;h=0cffdfc1036ce387a5741d130cb85f07c4091efc;p=njs.git parseInt() function. --- diff --git a/njs/njs_builtin.c b/njs/njs_builtin.c index d320d3b9..895deb2b 100644 --- a/njs/njs_builtin.c +++ b/njs/njs_builtin.c @@ -83,6 +83,7 @@ njs_builtin_objects_create(njs_vm_t *vm) NULL, NULL, NULL, + NULL, }; static const njs_function_init_t native_functions[] = { @@ -91,6 +92,8 @@ njs_builtin_objects_create(njs_vm_t *vm) { njs_object_prototype_to_string, { 0 } }, { njs_number_is_nan, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, { njs_number_is_finite, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, + { njs_number_parse_int, + { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG } }, }; static const njs_object_prop_t null_proto_property = { diff --git a/njs/njs_generator.c b/njs/njs_generator.c index ce585c49..5deb1ded 100644 --- a/njs/njs_generator.c +++ b/njs/njs_generator.c @@ -297,6 +297,7 @@ njs_generator(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) case NJS_TOKEN_TO_STRING: case NJS_TOKEN_IS_NAN: case NJS_TOKEN_IS_FINITE: + case NJS_TOKEN_PARSE_INT: return njs_generate_builtin_object(vm, parser, node); case NJS_TOKEN_FUNCTION: diff --git a/njs/njs_lexer_keyword.c b/njs/njs_lexer_keyword.c index 0f726e3b..53d84cd8 100644 --- a/njs/njs_lexer_keyword.c +++ b/njs/njs_lexer_keyword.c @@ -91,6 +91,7 @@ static const njs_keyword_t njs_keywords[] = { { nxt_string("toString"), NJS_TOKEN_TO_STRING, 0 }, { nxt_string("isNaN"), NJS_TOKEN_IS_NAN, 0 }, { nxt_string("isFinite"), NJS_TOKEN_IS_FINITE, 0 }, + { nxt_string("parseInt"), NJS_TOKEN_PARSE_INT, 0 }, /* Reserved words. */ diff --git a/njs/njs_number.c b/njs/njs_number.c index ed816788..5fa81452 100644 --- a/njs/njs_number.c +++ b/njs/njs_number.c @@ -121,22 +121,22 @@ njs_number_parse(const u_char **start, const u_char *end) int64_t -njs_hex_number_parse(u_char *p, u_char *end) +njs_number_radix_parse(u_char *p, u_char *end, uint8_t radix, nxt_bool_t exact) { - int8_t d; - uint32_t n; + uint8_t d; + uint64_t n; - static const int8_t hex[256] + static const int8_t digits[256] nxt_aligned(32) = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -150,13 +150,13 @@ njs_hex_number_parse(u_char *p, u_char *end) n = 0; while (p < end) { - d = hex[*p++]; + d = digits[*p++]; - if (nxt_slow_path(d < 0)) { - return -1; + if (nxt_slow_path(d >= radix)) { + return (exact) ? -1 : (int64_t) n; } - n = (n << 4) + d; + n = (n * radix) + d; } return n; @@ -474,3 +474,78 @@ njs_number_is_finite(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, return NXT_OK; } + + +njs_ret_t +njs_number_parse_int(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + double num; + u_char *p, *end; + int64_t n; + uint8_t radix; + nxt_bool_t minus; + njs_string_prop_t string; + + num = NJS_NAN; + + if (nargs > 1) { + (void) njs_string_prop(&string, &args[1]); + + p = string.start; + end = string.start + string.size; + + while (p < end) { + if (*p != ' ') { + goto found; + } + } + + goto done; + + found: + + minus = 0; + + if (p[0] == '-') { + p++; + minus = 1; + + } else if (p[0] == '+') { + p++; + } + + if (end - p > 1 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + radix = 16; + + } else { + radix = 10; + } + + if (nargs > 2) { + n = args[2].data.u.number; + + if (n != 0) { + + if (n < 2 || n > 36) { + goto done; + } + + radix = n; + } + } + + n = njs_number_radix_parse(p, end, radix, 0); + + if (n >= 0) { + num = (minus) ? -n : n; + } + } + +done: + + njs_number_set(&vm->retval, num); + + return NXT_OK; +} diff --git a/njs/njs_number.h b/njs/njs_number.h index d008168c..4fa27804 100644 --- a/njs/njs_number.h +++ b/njs/njs_number.h @@ -25,7 +25,8 @@ double njs_value_to_number(njs_value_t *value); double njs_number_parse(const u_char **start, const u_char *end); -int64_t njs_hex_number_parse(u_char *p, u_char *end); +int64_t njs_number_radix_parse(u_char *p, u_char *end, uint8_t radix, + nxt_bool_t exact); njs_ret_t njs_number_to_string(njs_vm_t *vm, njs_value_t *string, const njs_value_t *number); njs_ret_t njs_number_constructor(njs_vm_t *vm, njs_value_t *args, @@ -34,6 +35,8 @@ njs_ret_t njs_number_is_nan(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); njs_ret_t njs_number_is_finite(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_number_parse_int(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); extern const njs_object_init_t njs_number_constructor_init; diff --git a/njs/njs_parser.c b/njs/njs_parser.c index dd316d2e..575c2e6a 100644 --- a/njs/njs_parser.c +++ b/njs/njs_parser.c @@ -1647,6 +1647,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) case NJS_TOKEN_TO_STRING: case NJS_TOKEN_IS_NAN: case NJS_TOKEN_IS_FINITE: + case NJS_TOKEN_PARSE_INT: return njs_parser_builtin_function(vm, parser, node); default: @@ -2071,7 +2072,7 @@ njs_parser_escape_string_create(njs_vm_t *vm, njs_value_t *value) return NJS_TOKEN_ILLEGAL; } - u = njs_hex_number_parse(src, hex_end); + u = njs_number_radix_parse(src, hex_end, 16, 1); if (nxt_slow_path(u < 0)) { return NJS_TOKEN_ILLEGAL; } diff --git a/njs/njs_parser.h b/njs/njs_parser.h index 3f4b2001..3d35f096 100644 --- a/njs/njs_parser.h +++ b/njs/njs_parser.h @@ -178,6 +178,7 @@ typedef enum { NJS_TOKEN_TO_STRING, NJS_TOKEN_IS_NAN, NJS_TOKEN_IS_FINITE, + NJS_TOKEN_PARSE_INT, NJS_TOKEN_RESERVED, } njs_token_t; diff --git a/njs/njs_vm.h b/njs/njs_vm.h index e9d7f154..9e9fb69c 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -704,7 +704,8 @@ enum njs_function_e { NJS_FUNCTION_TO_STRING = 1, NJS_FUNCTION_IS_NAN = 2, NJS_FUNCTION_IS_FINITE = 3, -#define NJS_FUNCTION_MAX (NJS_FUNCTION_IS_FINITE + 1) + NJS_FUNCTION_PARSE_INT = 4, +#define NJS_FUNCTION_MAX (NJS_FUNCTION_PARSE_INT + 1) }; diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 53b7409f..f4b8b66a 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -4431,6 +4431,24 @@ static njs_unit_test_t njs_test[] = { nxt_string("isFinite('abc')"), nxt_string("false") }, + { nxt_string("parseInt('12345abc')"), + nxt_string("12345") }, + + { nxt_string("parseInt('1010', 2)"), + nxt_string("10") }, + + { nxt_string("parseInt('aBc', 16)"), + nxt_string("2748") }, + + { nxt_string("parseInt('0XaBc')"), + nxt_string("2748") }, + + { nxt_string("parseInt('-0xabc')"), + nxt_string("-2748") }, + + { nxt_string("parseInt('njscript', 36)"), + nxt_string("1845449130881") }, + /* External interface. */ { nxt_string("function f(req) { return req.uri }"),