details: http://hg.nginx.org/njs/rev/a38c33e9f728 branches: changeset: 347:a38c33e9f728 user: Dmitry Volyntsev <xei...@nginx.com> date: Tue May 30 19:35:08 2017 +0300 description: Added support of hex literals.
diffstat: njs/njs_lexer.c | 57 ++++---------------- njs/njs_number.c | 87 ++++++++++++++++++++++---------- njs/njs_number.h | 5 +- njs/njs_parser.c | 18 +++--- njs/njs_string.c | 64 ++++++++++++++++++++--- njs/njs_string.h | 3 +- njs/njs_vm.c | 31 +++------- njs/test/njs_unit_test.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 275 insertions(+), 114 deletions(-) diffs (682 lines): diff -r 4e2da602c2a3 -r a38c33e9f728 njs/njs_lexer.c --- a/njs/njs_lexer.c Mon May 29 22:13:21 2017 +0300 +++ b/njs/njs_lexer.c Tue May 30 19:35:08 2017 +0300 @@ -16,6 +16,7 @@ #include <nxt_mem_cache_pool.h> #include <njscript.h> #include <njs_vm.h> +#include <njs_number.h> #include <njs_variable.h> #include <njs_parser.h> #include <string.h> @@ -538,59 +539,27 @@ static njs_token_t njs_lexer_number(njs_lexer_t *lexer) { u_char c, *p; - double num, frac, scale; - - /* TODO: "1e2" */ p = lexer->start; c = p[-1]; - /* Values below '0' become >= 208. */ - c = c - '0'; - - num = c; - - if (c != 0) { - - while (p < lexer->end) { - c = *p; + /* Hexadecimal literal values. */ - /* Values below '0' become >= 208. */ - c = c - '0'; + if (c == '0' && p != lexer->end && (*p == 'x' || *p == 'X')) { + p++; - if (nxt_slow_path(c > 9)) { - break; - } + if (p == lexer->end) { + return NJS_TOKEN_ILLEGAL; + } - num = num * 10 + c; - p++; - } + lexer->start = p; + lexer->number = njs_number_hex_parse(&lexer->start, lexer->end); + + return NJS_TOKEN_NUMBER; } - if (*p == '.') { - - frac = 0; - scale = 1; - - for (p++; p < lexer->end; p++) { - c = *p; - - /* Values below '0' become >= 208. */ - c = c - '0'; - - if (nxt_slow_path(c > 9)) { - break; - } - - frac = frac * 10 + c; - scale *= 10; - } - - num += frac / scale; - } - - lexer->number = num; - lexer->start = p; + lexer->start = p - 1; + lexer->number = njs_number_dec_parse(&lexer->start, lexer->end); return NJS_TOKEN_NUMBER; } diff -r 4e2da602c2a3 -r a38c33e9f728 njs/njs_number.c --- a/njs/njs_number.c Mon May 29 22:13:21 2017 +0300 +++ b/njs/njs_number.c Tue May 30 19:35:08 2017 +0300 @@ -37,20 +37,21 @@ static njs_ret_t njs_number_to_string_ra double number, uint32_t radix); -double -njs_value_to_number(njs_value_t *value) +uint32_t +njs_value_to_index(njs_value_t *value) { + double num; njs_array_t *array; + num = NAN; + if (nxt_fast_path(njs_is_numeric(value))) { - return value->data.u.number; - } + num = value->data.u.number; - if (njs_is_string(value)) { - return njs_string_to_number(value, 1); - } + } else if (njs_is_string(value)) { + num = njs_string_to_index(value); - if (njs_is_array(value)) { + } else if (njs_is_array(value)) { array = value->data.u.array; @@ -58,42 +59,39 @@ njs_value_to_number(njs_value_t *value) if (array->length == 0) { /* An empty array value is zero. */ - return 0.0; + return 0; } if (array->length == 1 && njs_is_valid(&array->start[0])) { /* A single value array is the zeroth array value. */ - return njs_value_to_number(&array->start[0]); + return njs_value_to_index(&array->start[0]); } } } - return NAN; + if ((uint32_t) num == num) { + return (uint32_t) num; + } + + return NJS_ARRAY_INVALID_INDEX; } double -njs_number_parse(const u_char **start, const u_char *end) +njs_number_dec_parse(u_char **start, u_char *end) { - u_char c; - double num, frac, scale; - const u_char *p; + u_char c, *p; + double num, frac, scale; /* TODO: "1e2" */ p = *start; - c = *p++; - /* Values below '0' become >= 208. */ - c = c - '0'; - - num = c; + num = 0; while (p < end) { - c = *p; - /* Values below '0' become >= 208. */ - c = c - '0'; + c = *p - '0'; if (nxt_slow_path(c > 9)) { break; @@ -109,10 +107,8 @@ njs_number_parse(const u_char **start, c scale = 1; for (p++; p < end; p++) { - c = *p; - /* Values below '0' become >= 208. */ - c = c - '0'; + c = *p - '0'; if (nxt_slow_path(c > 9)) { break; @@ -131,6 +127,43 @@ njs_number_parse(const u_char **start, c } +uint64_t +njs_number_hex_parse(u_char **start, u_char *end) +{ + u_char c, *p; + uint64_t num; + + p = *start; + + num = 0; + + while (p < end) { + c = (u_char) (*p | 0x20); + + /* Values below '0' become >= 208. */ + c = c - '0'; + + if (c > 9) { + /* Values below 'a' become >= 159. */ + c = c - ('a' - '0'); + + if (nxt_slow_path(c > 5)) { + break; + } + + c += 10; + } + + num = num * 16 + c; + p++; + } + + *start = p; + + return num; +} + + int64_t njs_number_radix_parse(u_char **start, u_char *end, uint8_t radix) { @@ -745,7 +778,7 @@ njs_number_parse_float(njs_vm_t *vm, njs num = NAN; if (nargs > 1) { - num = njs_string_to_number(&args[1], 0); + num = njs_string_to_number(&args[1], 1); } njs_number_set(&vm->retval, num); diff -r 4e2da602c2a3 -r a38c33e9f728 njs/njs_number.h --- a/njs/njs_number.h Mon May 29 22:13:21 2017 +0300 +++ b/njs/njs_number.h Tue May 30 19:35:08 2017 +0300 @@ -11,8 +11,9 @@ #include <math.h> -double njs_value_to_number(njs_value_t *value); -double njs_number_parse(const u_char **start, const u_char *end); +uint32_t njs_value_to_index(njs_value_t *value); +double njs_number_dec_parse(u_char **start, u_char *end); +uint64_t njs_number_hex_parse(u_char **start, u_char *end); int64_t njs_number_radix_parse(u_char **start, u_char *end, uint8_t radix); njs_ret_t njs_number_to_string(njs_vm_t *vm, njs_value_t *string, const njs_value_t *number); diff -r 4e2da602c2a3 -r a38c33e9f728 njs/njs_parser.c --- a/njs/njs_parser.c Mon May 29 22:13:21 2017 +0300 +++ b/njs/njs_parser.c Tue May 30 19:35:08 2017 +0300 @@ -2302,9 +2302,9 @@ static njs_token_t njs_parser_escape_string_create(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value) { - u_char c, *p, *start, *dst, *src, *end, *hex_end; - size_t size, length, hex_length; - int64_t u; + u_char c, *p, *start, *dst, *src, *end, *hex_end; + size_t size, length, hex_length; + uint64_t u; start = NULL; dst = NULL; @@ -2422,11 +2422,7 @@ njs_parser_escape_string_create(njs_vm_t hex: p = src; - u = njs_number_radix_parse(&src, hex_end, 16); - - if (nxt_slow_path(u < 0)) { - goto invalid; - } + u = njs_number_hex_parse(&src, hex_end); if (hex_length != 0) { if (src != hex_end) { @@ -2434,7 +2430,11 @@ njs_parser_escape_string_create(njs_vm_t } } else { - if ((src - p) > 6 || src == end || *src++ != '}') { + if (src == p || (src - p) > 6) { + goto invalid; + } + + if (src == end || *src++ != '}') { goto invalid; } } diff -r 4e2da602c2a3 -r a38c33e9f728 njs/njs_string.c --- a/njs/njs_string.c Mon May 29 22:13:21 2017 +0300 +++ b/njs/njs_string.c Tue May 30 19:35:08 2017 +0300 @@ -2943,12 +2943,12 @@ njs_primitive_value_to_string(njs_vm_t * double -njs_string_to_number(njs_value_t *value, nxt_bool_t exact) +njs_string_to_number(njs_value_t *value, nxt_bool_t parse_float) { + u_char *p, *start, *end; double num; size_t size; nxt_bool_t minus; - const u_char *p, *end; const size_t infinity = sizeof("Infinity") - 1; @@ -2990,19 +2990,27 @@ njs_string_to_number(njs_value_t *value, return NAN; } - if (*p >= '0' && *p <= '9') { - num = njs_number_parse(&p, end); + if (!parse_float + && p + 2 < end && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + num = njs_number_hex_parse(&p, end); } else { - if (p + infinity > end || memcmp(p, "Infinity", infinity) != 0) { - return NAN; + start = p; + num = njs_number_dec_parse(&p, end); + + if (p == start) { + if (p + infinity > end || memcmp(p, "Infinity", infinity) != 0) { + return NAN; + } + + num = INFINITY; + p += infinity; } - - num = INFINITY; - p += infinity; } - if (exact) { + if (!parse_float) { while (p < end) { if (*p != ' ' && *p != '\t') { return NAN; @@ -3016,6 +3024,42 @@ njs_string_to_number(njs_value_t *value, } +double +njs_string_to_index(njs_value_t *value) +{ + u_char *p, *end; + double num; + size_t size; + + size = value->short_string.size; + + if (size != NJS_STRING_LONG) { + p = value->short_string.start; + + } else { + size = value->data.string_size; + p = value->data.u.string->start; + } + + if (size == 0) { + return NAN; + } + + if (*p == '0' && size > 1) { + return NAN; + } + + end = p + size; + num = njs_number_dec_parse(&p, end); + + if (p != end) { + return NAN; + } + + return num; +} + + static const njs_object_prop_t njs_string_prototype_properties[] = { { diff -r 4e2da602c2a3 -r a38c33e9f728 njs/njs_string.h --- a/njs/njs_string.h Mon May 29 22:13:21 2017 +0300 +++ b/njs/njs_string.h Tue May 30 19:35:08 2017 +0300 @@ -142,7 +142,8 @@ nxt_noinline uint32_t njs_string_index(n void njs_string_offset_map_init(const u_char *start, size_t size); njs_ret_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *src); -double njs_string_to_number(njs_value_t *value, nxt_bool_t exact); +double njs_string_to_index(njs_value_t *value); +double njs_string_to_number(njs_value_t *value, nxt_bool_t parse_float); njs_ret_t njs_string_encode_uri(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); njs_ret_t njs_string_encode_uri_component(njs_vm_t *vm, njs_value_t *args, diff -r 4e2da602c2a3 -r a38c33e9f728 njs/njs_vm.c --- a/njs/njs_vm.c Mon May 29 22:13:21 2017 +0300 +++ b/njs/njs_vm.c Tue May 30 19:35:08 2017 +0300 @@ -509,7 +509,6 @@ njs_ret_t njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object, njs_value_t *property) { - double num; int32_t index; uintptr_t data; njs_ret_t ret; @@ -576,10 +575,9 @@ njs_vmcode_property_get(njs_vm_t *vm, nj /* string[n]. */ - num = njs_value_to_number(property); - index = (int32_t) num; - - if (index >= 0 && index == num) { + index = (int32_t) njs_value_to_index(property); + + if (nxt_fast_path(index >= 0)) { slice.start = index; slice.length = 1; slice.string_length = njs_string_prop(&string, object); @@ -943,11 +941,9 @@ static nxt_noinline njs_ret_t njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object, njs_value_t *property) { - double num; uint32_t index; uint32_t (*hash)(const void *, size_t); njs_ret_t ret; - nxt_bool_t valid; njs_extern_t *ext; njs_object_t *obj; njs_function_t *function; @@ -978,22 +974,15 @@ njs_property_query(njs_vm_t *vm, njs_pro if (nxt_fast_path(!njs_is_null_or_void_or_boolean(property))) { if (nxt_fast_path(njs_is_primitive(property))) { - num = njs_value_to_number(property); + index = njs_value_to_index(property); + + if (nxt_fast_path(index < NJS_ARRAY_MAX_LENGTH)) { + return njs_array_property_query(vm, pq, object, index); + } } else { return NJS_TRAP_PROPERTY; } - - if (nxt_fast_path(num >= 0)) { - index = (uint32_t) num; - - valid = nxt_expect(1, (index < NJS_ARRAY_MAX_LENGTH - && (double) index == num)); - - if (valid) { - return njs_array_property_query(vm, pq, object, index); - } - } } /* Fall through. */ @@ -3026,7 +3015,7 @@ njs_vmcode_number_primitive(njs_vm_t *vm num = NAN; if (njs_is_string(value)) { - num = njs_string_to_number(value, 1); + num = njs_string_to_number(value, 0); } njs_number_set(value, num); @@ -3079,7 +3068,7 @@ njs_vmcode_number_argument(njs_vm_t *vm, num = NAN; if (njs_is_string(value)) { - num = njs_string_to_number(value, 1); + num = njs_string_to_number(value, 0); } njs_number_set(value, num); diff -r 4e2da602c2a3 -r a38c33e9f728 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon May 29 22:13:21 2017 +0300 +++ b/njs/test/njs_unit_test.c Tue May 30 19:35:08 2017 +0300 @@ -115,6 +115,29 @@ static njs_unit_test_t njs_test[] = { nxt_string("+1\n"), nxt_string("1") }, + /* Hex Numbers. */ + + { nxt_string("0x0"), + nxt_string("0") }, + + { nxt_string("-0x1"), + nxt_string("-1") }, + + { nxt_string("0xffFF"), + nxt_string("65535") }, + + { nxt_string("0X0000BEEF"), + nxt_string("48879") }, + + { nxt_string("0x"), + nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + + { nxt_string("0xffff."), + nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + + { nxt_string("0x12g"), + nxt_string("SyntaxError: Unexpected token \"g\" in 1") }, + { nxt_string(""), nxt_string("undefined") }, @@ -127,6 +150,17 @@ static njs_unit_test_t njs_test[] = { nxt_string("\n +1"), nxt_string("1") }, + /* Indexes. */ + + { nxt_string("var a = []; a[-1] = 2; a[-1] == a['-1']"), + nxt_string("true") }, + + { nxt_string("var a = []; a[Infinity] = 2; a[Infinity] == a['Infinity']"), + nxt_string("true") }, + + { nxt_string("var a = []; a[NaN] = 2; a[NaN] == a['NaN']"), + nxt_string("true") }, + /* Number.toString(radix) method. */ { nxt_string("0..toString(2)"), @@ -153,6 +187,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("81985529216486895..toString(16)"), nxt_string("123456789abcdf0") }, + { nxt_string("0xffff.toString(16)"), + nxt_string("ffff") }, + { nxt_string("1845449130881..toString(36)"), nxt_string("njscript") }, @@ -220,12 +257,18 @@ static njs_unit_test_t njs_test[] = { nxt_string("1 + ''"), nxt_string("1") }, + { nxt_string("0xA + ''"), + nxt_string("10") }, + { nxt_string("undefined + undefined"), nxt_string("NaN") }, { nxt_string("1.2 + 5.7"), nxt_string("6.9") }, + { nxt_string("0xf + 1"), + nxt_string("16") }, + { nxt_string("1 + 1 + '2' + 1 + 1"), nxt_string("2211") }, @@ -235,6 +278,30 @@ static njs_unit_test_t njs_test[] = { nxt_string("1.2 + -'5.7'"), nxt_string("-4.5") }, + { nxt_string("1.2 - '-5.7'"), + nxt_string("6.9") }, + + { nxt_string("5 - ' \t 12 \t'"), + nxt_string("-7") }, + + { nxt_string("5 - '12zz'"), + nxt_string("NaN") }, + + { nxt_string("5 - '0x2'"), + nxt_string("3") }, + + { nxt_string("5 - '-0x2'"), + nxt_string("7") }, + + { nxt_string("5 - '\t 0x2 \t'"), + nxt_string("3") }, + + { nxt_string("5 - '0x2 z'"), + nxt_string("NaN") }, + + { nxt_string("5 - '0x'"), + nxt_string("NaN") }, + { nxt_string("1 + +'3'"), nxt_string("4") }, @@ -2334,6 +2401,18 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = [ 1, 2, 3 ]; a[0] +' '+ a[1] +' '+ a[2] +' '+ a[3]"), nxt_string("1 2 3 undefined") }, + { nxt_string("var a = [ 5, 6, 7 ]; a['1']"), + nxt_string("6") }, + + { nxt_string("var a = [ 5, 6, 7 ]; a['01']"), + nxt_string("undefined") }, + + { nxt_string("var a = [ 5, 6, 7 ]; a[0x1]"), + nxt_string("6") }, + + { nxt_string("var a = [ 5, 6, 7 ]; a['0x1']"), + nxt_string("undefined") }, + { nxt_string("[] - 2"), nxt_string("-2") }, @@ -3145,6 +3224,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("'\\u03B'"), nxt_string("SyntaxError: Invalid Unicode code point \"\\u03B\" in 1") }, + { nxt_string("'\\u03BG'"), + nxt_string("SyntaxError: Invalid Unicode code point \"\\u03BG\" in 1") }, + + { nxt_string("'\\u03B '"), + nxt_string("SyntaxError: Invalid Unicode code point \"\\u03B \" in 1") }, + { nxt_string("'\\u{61}\\u{3B1}\\u{20AC}'"), nxt_string("aα€") }, @@ -3449,6 +3534,30 @@ static njs_unit_test_t njs_test[] = { nxt_string("'abcdef'[8]"), nxt_string("undefined") }, + { nxt_string("'abcdef'['1']"), + nxt_string("b") }, + + { nxt_string("'abcdef'[' 1']"), + nxt_string("undefined") }, + + { nxt_string("'abcdef'['1 ']"), + nxt_string("undefined") }, + + { nxt_string("'abcdef'['']"), + nxt_string("undefined") }, + + { nxt_string("'abcdef'['-']"), + nxt_string("undefined") }, + + { nxt_string("'abcdef'['-1']"), + nxt_string("undefined") }, + + { nxt_string("'abcdef'['01']"), + nxt_string("undefined") }, + + { nxt_string("'abcdef'['0x01']"), + nxt_string("undefined") }, + { nxt_string("var a = 'abcdef', b = 1 + 2; a[b]"), nxt_string("d") }, @@ -7077,6 +7186,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("parseFloat('12345abc')"), nxt_string("12345") }, + { nxt_string("parseFloat('0x')"), + nxt_string("0") }, + + { nxt_string("parseFloat('0xff')"), + nxt_string("0") }, + + { nxt_string("parseFloat('Infinity')"), + nxt_string("Infinity") }, + + { nxt_string("parseFloat(' Infinityzz')"), + nxt_string("Infinity") }, + + { nxt_string("parseFloat('Infinit')"), + nxt_string("NaN") }, + /* Trick: number to boolean. */ { nxt_string("var a = 0; !!a"), _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel