From: Dmitry Volyntsev Date: Tue, 30 May 2017 16:35:08 +0000 (+0300) Subject: Added support of hex literals. X-Git-Tag: 0.1.11~32 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=e74215ef8ac59e29ab6f4aca676f729e99c63f2e;p=njs.git Added support of hex literals. --- diff --git a/njs/njs_lexer.c b/njs/njs_lexer.c index 1c8c62ff..71d89913 100644 --- a/njs/njs_lexer.c +++ b/njs/njs_lexer.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -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; - - /* Values below '0' become >= 208. */ - c = c - '0'; + /* Hexadecimal literal values. */ - if (nxt_slow_path(c > 9)) { - break; - } + if (c == '0' && p != lexer->end && (*p == 'x' || *p == 'X')) { + p++; - num = num * 10 + c; - p++; + if (p == lexer->end) { + return NJS_TOKEN_ILLEGAL; } - } - if (*p == '.') { + lexer->start = p; + lexer->number = njs_number_hex_parse(&lexer->start, lexer->end); - 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; + return NJS_TOKEN_NUMBER; } - 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 --git a/njs/njs_number.c b/njs/njs_number.c index fb8d39fa..6223b76d 100644 --- a/njs/njs_number.c +++ b/njs/njs_number.c @@ -37,20 +37,21 @@ static njs_ret_t njs_number_to_string_radix(njs_vm_t *vm, njs_value_t *string, 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, const u_char *end) 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, const u_char *end) } +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_value_t *args, nxt_uint_t nargs, 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 --git a/njs/njs_number.h b/njs/njs_number.h index e864ae21..ee3c3b5e 100644 --- a/njs/njs_number.h +++ b/njs/njs_number.h @@ -11,8 +11,9 @@ #include -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 --git a/njs/njs_parser.c b/njs/njs_parser.c index bccdde60..de03722e 100644 --- a/njs/njs_parser.c +++ b/njs/njs_parser.c @@ -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 *vm, njs_parser_t *parser, 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 *vm, njs_parser_t *parser, } } else { - if ((src - p) > 6 || src == end || *src++ != '}') { + if (src == p || (src - p) > 6) { + goto invalid; + } + + if (src == end || *src++ != '}') { goto invalid; } } diff --git a/njs/njs_string.c b/njs/njs_string.c index 9e539940..70f62fbe 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -2943,12 +2943,12 @@ njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst, 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, nxt_bool_t exact) 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); - num = INFINITY; - p += infinity; + if (p == start) { + if (p + infinity > end || memcmp(p, "Infinity", infinity) != 0) { + return NAN; + } + + 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, nxt_bool_t exact) } +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 --git a/njs/njs_string.h b/njs/njs_string.h index e8298533..0f605c3c 100644 --- a/njs/njs_string.h +++ b/njs/njs_string.h @@ -142,7 +142,8 @@ nxt_noinline uint32_t njs_string_index(njs_string_prop_t *string, 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 --git a/njs/njs_vm.c b/njs/njs_vm.c index d4801070..4d4746cd 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -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, njs_value_t *object, /* string[n]. */ - num = njs_value_to_number(property); - index = (int32_t) num; + index = (int32_t) njs_value_to_index(property); - if (index >= 0 && index == num) { + 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,21 +974,14 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object, 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); - } 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) { + if (nxt_fast_path(index < NJS_ARRAY_MAX_LENGTH)) { return njs_array_property_query(vm, pq, object, index); } + + } else { + return NJS_TRAP_PROPERTY; } } @@ -3026,7 +3015,7 @@ njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld, njs_value_t *narg) 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, njs_value_t *invld1, 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 --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 0262ac93..b339d775 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -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"),