Welcome! Log In Create A New Profile

Advanced

[njs] Aligned Number constructor to the spec.

Dmitry Volyntsev
March 29, 2023 11:48PM
details: https://hg.nginx.org/njs/rev/8dcea0ba0bf8
branches:
changeset: 2078:8dcea0ba0bf8
user: Dmitry Volyntsev <xeioex@nginx.com>
date: Wed Mar 29 20:28:33 2023 -0700
description:
Aligned Number constructor to the spec.

Previously, negative hexadecimal numbers were accepted as valid,
whereas they are invalid input for the constructor.
Also previously, the constructor did not accepted positive binary or
octadecimal numbers as valid.

This closes #630 issue on Github.

diffstat:

src/njs_lexer.c | 4 +-
src/njs_number.c | 57 ++++++++++++++++++++++++++++++++++++++++-----
src/njs_number.h | 6 +++-
src/njs_string.c | 54 ++++++++++++++++++++++++-------------------
src/njs_value.h | 2 +-
src/njs_value_conversion.h | 2 +-
src/njs_vmcode.c | 6 ++--
src/test/njs_unit_test.c | 38 +++++++++++++++++++++++++++++-
8 files changed, 128 insertions(+), 41 deletions(-)

diffs (337 lines):

diff -r 5e7fc8efebdc -r 8dcea0ba0bf8 src/njs_lexer.c
--- a/src/njs_lexer.c Mon Mar 27 22:41:27 2023 -0700
+++ b/src/njs_lexer.c Wed Mar 29 20:28:33 2023 -0700
@@ -933,7 +933,7 @@ njs_lexer_number(njs_lexer_t *lexer, njs
goto illegal_token;
}

- token->number = njs_number_oct_parse(&p, lexer->end);
+ token->number = njs_number_oct_parse(&p, lexer->end, 1);

if (p < lexer->end && (*p == '8' || *p == '9')) {
goto illegal_trailer;
@@ -951,7 +951,7 @@ njs_lexer_number(njs_lexer_t *lexer, njs
goto illegal_token;
}

- token->number = njs_number_bin_parse(&p, lexer->end);
+ token->number = njs_number_bin_parse(&p, lexer->end, 1);

if (p < lexer->end && (*p >= '2' && *p <= '9')) {
goto illegal_trailer;
diff -r 5e7fc8efebdc -r 8dcea0ba0bf8 src/njs_number.c
--- a/src/njs_number.c Mon Mar 27 22:41:27 2023 -0700
+++ b/src/njs_number.c Wed Mar 29 20:28:33 2023 -0700
@@ -62,7 +62,8 @@ njs_number_dec_parse(const u_char **star


double
-njs_number_oct_parse(const u_char **start, const u_char *end)
+njs_number_oct_parse(const u_char **start, const u_char *end,
+ njs_bool_t literal)
{
u_char c;
double num;
@@ -78,7 +79,7 @@ njs_number_oct_parse(const u_char **star
c = *p - '0';

if (njs_slow_path(c > 7)) {
- if (*p == '_' && (p - _) > 1) {
+ if (literal && *p == '_' && (p - _) > 1) {
_ = p;
continue;
}
@@ -96,7 +97,8 @@ njs_number_oct_parse(const u_char **star


double
-njs_number_bin_parse(const u_char **start, const u_char *end)
+njs_number_bin_parse(const u_char **start, const u_char *end,
+ njs_bool_t literal)
{
u_char c;
double num;
@@ -112,7 +114,7 @@ njs_number_bin_parse(const u_char **star
c = *p - '0';

if (njs_slow_path(c > 1)) {
- if (*p == '_' && (p - _) > 1) {
+ if (literal && *p == '_' && (p - _) > 1) {
_ = p;
continue;
}
@@ -1030,8 +1032,12 @@ njs_int_t
njs_number_parse_float(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- njs_int_t ret;
- njs_value_t *value, lvalue;
+ double num;
+ njs_int_t ret;
+ njs_value_t *value, lvalue;
+ njs_bool_t minus;
+ const u_char *p, *start, *end;
+ njs_string_prop_t string;

value = njs_lvalue_arg(&lvalue, args, nargs, 1);

@@ -1040,7 +1046,44 @@ njs_number_parse_float(njs_vm_t *vm, njs
return ret;
}

- njs_set_number(&vm->retval, njs_string_to_number(value, 1));
+ (void) njs_string_trim(value, &string, NJS_TRIM_START);
+
+ p = string.start;
+ end = p + string.size;
+
+ minus = 0;
+
+ if (p == end) {
+ num = NAN;
+ goto done;
+ }
+
+ if (*p == '+') {
+ p++;
+
+ } else if (*p == '-') {
+ p++;
+ minus = 1;
+ }
+
+ start = p;
+ num = njs_number_dec_parse(&p, end, 0);
+
+ if (p == start) {
+ if (p + njs_length("Infinity") > end
+ || memcmp(p, "Infinity", njs_length("Infinity")) != 0)
+ {
+ num = NAN;
+ goto done;
+ }
+
+ num = INFINITY;
+ p += njs_length("Infinity");
+ }
+
+done:
+
+ njs_set_number(&vm->retval, minus ? -num : num);

return NJS_OK;
}
diff -r 5e7fc8efebdc -r 8dcea0ba0bf8 src/njs_number.h
--- a/src/njs_number.h Mon Mar 27 22:41:27 2023 -0700
+++ b/src/njs_number.h Wed Mar 29 20:28:33 2023 -0700
@@ -16,8 +16,10 @@
double njs_key_to_index(const njs_value_t *value);
double njs_number_dec_parse(const u_char **start, const u_char *end,
njs_bool_t literal);
-double njs_number_oct_parse(const u_char **start, const u_char *end);
-double njs_number_bin_parse(const u_char **start, const u_char *end);
+double njs_number_oct_parse(const u_char **start, const u_char *end,
+ njs_bool_t literal);
+double njs_number_bin_parse(const u_char **start, const u_char *end,
+ njs_bool_t literal);
double njs_number_hex_parse(const u_char **start, const u_char *end,
njs_bool_t literal);
njs_int_t njs_number_to_string(njs_vm_t *vm, njs_value_t *string,
diff -r 5e7fc8efebdc -r 8dcea0ba0bf8 src/njs_string.c
--- a/src/njs_string.c Mon Mar 27 22:41:27 2023 -0700
+++ b/src/njs_string.c Wed Mar 29 20:28:33 2023 -0700
@@ -3874,7 +3874,7 @@ njs_string_prototype_iterator_obj(njs_vm


double
-njs_string_to_number(const njs_value_t *value, njs_bool_t parse_float)
+njs_string_to_number(const njs_value_t *value)
{
double num;
njs_bool_t minus;
@@ -3889,30 +3889,38 @@ njs_string_to_number(const njs_value_t *
end = p + string.size;

if (p == end) {
- return parse_float ? NAN : 0.0;
+ return 0.0;
}

minus = 0;

- if (*p == '+') {
- p++;
-
- } else if (*p == '-') {
- p++;
- minus = 1;
- }
-
- if (p == end) {
- return NAN;
- }
-
- if (!parse_float
- && p + 2 < end && p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
+ if (p + 2 < end && p[0] == '0'
+ && (p[1] == 'x' || p[1] == 'X'
+ || p[1] == 'b' || p[1] == 'B'
+ || p[1] == 'o' || p[1] == 'O'))
{
p += 2;
- num = njs_number_hex_parse(&p, end, 0);
+
+ if (p[-1] == 'x' || p[-1] == 'X') {
+ num = njs_number_hex_parse(&p, end, 0);
+
+ } else if (p[-1] == 'b' || p[-1] == 'B') {
+ num = njs_number_bin_parse(&p, end, 0);
+
+ } else {
+ num = njs_number_oct_parse(&p, end, 0);
+ }

} else {
+
+ if (*p == '+') {
+ p++;
+
+ } else if (*p == '-') {
+ p++;
+ minus = 1;
+ }
+
start = p;
num = njs_number_dec_parse(&p, end, 0);

@@ -3926,14 +3934,12 @@ njs_string_to_number(const njs_value_t *
}
}

- if (!parse_float) {
- while (p < end) {
- if (!njs_is_whitespace(*p)) {
- return NAN;
- }
-
- p++;
+ while (p < end) {
+ if (!njs_is_whitespace(*p)) {
+ return NAN;
}
+
+ p++;
}

return minus ? -num : num;
diff -r 5e7fc8efebdc -r 8dcea0ba0bf8 src/njs_value.h
--- a/src/njs_value.h Mon Mar 27 22:41:27 2023 -0700
+++ b/src/njs_value.h Wed Mar 29 20:28:33 2023 -0700
@@ -1073,7 +1073,7 @@ njs_int_t njs_primitive_value_to_string(
const njs_value_t *src);
njs_int_t njs_primitive_value_to_chain(njs_vm_t *vm, njs_chb_t *chain,
const njs_value_t *src);
-double njs_string_to_number(const njs_value_t *value, njs_bool_t parse_float);
+double njs_string_to_number(const njs_value_t *value);
njs_int_t njs_int64_to_string(njs_vm_t *vm, njs_value_t *value, int64_t i64);

njs_bool_t njs_string_eq(const njs_value_t *v1, const njs_value_t *v2);
diff -r 5e7fc8efebdc -r 8dcea0ba0bf8 src/njs_value_conversion.h
--- a/src/njs_value_conversion.h Mon Mar 27 22:41:27 2023 -0700
+++ b/src/njs_value_conversion.h Wed Mar 29 20:28:33 2023 -0700
@@ -33,7 +33,7 @@ njs_value_to_number(njs_vm_t *vm, njs_va
*dst = NAN;

if (njs_is_string(value)) {
- *dst = njs_string_to_number(value, 0);
+ *dst = njs_string_to_number(value);
}

return NJS_OK;
diff -r 5e7fc8efebdc -r 8dcea0ba0bf8 src/njs_vmcode.c
--- a/src/njs_vmcode.c Mon Mar 27 22:41:27 2023 -0700
+++ b/src/njs_vmcode.c Wed Mar 29 20:28:33 2023 -0700
@@ -2512,7 +2512,7 @@ again:
/* If "hv" is a string then "lv" can be a numeric or symbol. */
if (njs_is_string(hv)) {
return !njs_is_symbol(lv)
- && (njs_number(lv) == njs_string_to_number(hv, 0));
+ && (njs_number(lv) == njs_string_to_number(hv));
}

/* "hv" is an object and "lv" is either a string or a symbol or a numeric. */
@@ -2549,11 +2549,11 @@ njs_primitive_values_compare(njs_vm_t *v
num2 = njs_number(val2);

} else {
- num2 = njs_string_to_number(val2, 0);
+ num2 = njs_string_to_number(val2);
}

} else if (njs_is_numeric(val2)) {
- num1 = njs_string_to_number(val1, 0);
+ num1 = njs_string_to_number(val1);
num2 = njs_number(val2);

} else {
diff -r 5e7fc8efebdc -r 8dcea0ba0bf8 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Mon Mar 27 22:41:27 2023 -0700
+++ b/src/test/njs_unit_test.c Wed Mar 29 20:28:33 2023 -0700
@@ -994,7 +994,7 @@ static njs_unit_test_t njs_test[] =
njs_str("3") },

{ njs_str("5 - '-0x2'"),
- njs_str("7") },
+ njs_str("NaN") },

{ njs_str("5 - '\t 0x2 \t'"),
njs_str("3") },
@@ -13344,12 +13344,48 @@ static njs_unit_test_t njs_test[] =
{ njs_str("Number(false)"),
njs_str("0") },

+ { njs_str("Number('0b111')"),
+ njs_str("7") },
+
+ { njs_str("Number('0B111')"),
+ njs_str("7") },
+
+ { njs_str("Number('0b1_11')"),
+ njs_str("NaN") },
+
+ { njs_str("Number('-0b111')"),
+ njs_str("NaN") },
+
{ njs_str("Number(123)"),
njs_str("123") },

{ njs_str("Number('123')"),
njs_str("123") },

+ { njs_str("Number('0o123')"),
+ njs_str("83") },
+
+ { njs_str("Number('0O123')"),
+ njs_str("83") },
+
+ { njs_str("Number('0o1_23')"),
+ njs_str("NaN") },
+
+ { njs_str("Number('-0o123')"),
+ njs_str("NaN") },
+
+ { njs_str("Number('0x123')"),
+ njs_str("291") },
+
+ { njs_str("Number('0X123')"),
+ njs_str("291") },
+
+ { njs_str("Number('0x1_23')"),
+ njs_str("NaN") },
+
+ { njs_str("Number('-0x123')"),
+ njs_str("NaN") },
+
{ njs_str("['1', ' 1 ', '1\\t', '1\\n', '1\\r\\n'].reduce((a, x) => a + Number(x), 0)"),
njs_str("5") },

_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[njs] Aligned Number constructor to the spec.

Dmitry Volyntsev 544 March 29, 2023 11:48PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 278
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready