From 7de7c2168ec7a6b587ca8361181512d7422716ff Mon Sep 17 00:00:00 2001 From: kisbg Date: Wed, 18 Nov 2020 07:37:56 +0100 Subject: [PATCH] Implement asInteger, asUint32 and asInt32 jerry api methods (#4325) JerryScript-DCO-1.0-Signed-off-by: bence gabor kis kisbg@inf.u-szeged.hu --- docs/02.API-REFERENCE.md | 86 +++++++++++++++ jerry-core/api/jerry.c | 78 ++++++++++++++ jerry-core/include/jerryscript-core.h | 3 + tests/unit-core/test-number-converter.c | 137 ++++++++++++++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 tests/unit-core/test-number-converter.c diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 6159c5cb5..018349adc 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -3777,6 +3777,92 @@ jerry_value_to_bigint (const jerry_value_t value); - [jerry_value_is_bigint](#jerry_value_is_bigint) - [jerry_get_bigint_digits](#jerry_get_bigint_digits) +## jerry_value_as_integer + +**Summary** + +Convert any number to integer number. Returns 0 if value is not number. +Based on ECMA 262 v11 7.1.5 + +**Prototype** + +```c +double +jerry_value_as_integer (const jerry_value_t value); +``` + +- `value` - api value +- return + - 0, if value is not a number + - integer representation of the number, otherwise + +**Example** + +```c +{ + jerry_value_t number_val = jerry_create_number (123321); + double number = jerry_value_as_integer (number_val); + jerry_release_value (number_val); +} +``` + +## jerry_value_as_int32 + +**Summary** + +Convert any number to int32 number. Returns 0 if value is not number. +Based on ECMA 262 v11 7.1.6 + +**Prototype** + +```c +int32_t +jerry_value_as_int32 (const jerry_value_t value); +``` + +- `value` - api value +- return + - 0, if value is not a number + - int32 representation of the number, otherwise + +**Example** + +```c +{ + jerry_value_t number_val = jerry_create_number (123321); + int32_t number = jerry_value_as_int32 (number_val); + jerry_release_value (number_val); +} +``` + +## jerry_value_as_uint32 + +**Summary** + +Convert any number to uint32 number. Returns 0 if value is not number. +Based on ECMA 262 v11 7.1.7 + +**Prototype** + +```c +uint32_t +jerry_value_as_uint32 (const jerry_value_t value); +``` + +- `value` - api value +- return + - 0, if value is not a number + - uint32 representation of the number, otherwise + +**Example** + +```c +{ + jerry_value_t number_val = jerry_create_number (123321); + uint32_t number = jerry_value_as_uint32 (number_val); + jerry_release_value (number_val); +} +``` # Functions for promise objects diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index c78c5fb37..ece2dae80 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -14,6 +14,7 @@ */ #include +#include #include "debugger.h" #include "ecma-alloc.h" @@ -1722,6 +1723,83 @@ jerry_value_to_bigint (const jerry_value_t value) /**< input value */ #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ } /* jerry_value_to_bigint */ +/** + * Convert any number to integer number. + * + * Note: + * For non-number values 0 is returned. + * + * @return integer representation of the number. + */ +double +jerry_value_as_integer (const jerry_value_t value) /**< input value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_number (value)) + { + return 0; + } + + double number = ecma_get_number_from_value (value); + + if (ecma_number_is_nan (number)) + { + return ECMA_NUMBER_ZERO; + } + + if (ecma_number_is_zero (number) || ecma_number_is_infinity (number)) + { + return number; + } + + ecma_number_t floor_fabs = (ecma_number_t) floor (fabs (number)); + + return ecma_number_is_negative (number) ? -floor_fabs : floor_fabs; +} /* jerry_value_as_integer */ + +/** + * Convert any number to int32 number. + * + * Note: + * For non-number values 0 is returned. + * + * @return int32 representation of the number. + */ +int32_t +jerry_value_as_int32 (const jerry_value_t value) /**< input value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_number (value)) + { + return 0; + } + + return ecma_number_to_int32 (ecma_get_number_from_value (value)); +} /* jerry_value_as_int32 */ + +/** + * Convert any number to uint32 number. + * + * Note: + * For non-number values 0 is returned. + * + * @return uint32 representation of the number. + */ +uint32_t +jerry_value_as_uint32 (const jerry_value_t value) /**< input value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_number (value)) + { + return 0; + } + + return ecma_number_to_uint32 (ecma_get_number_from_value (value)); +} /* jerry_value_as_uint32 */ + /** * Acquire specified Jerry API value. * diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 59b6b50f6..6f28f7d5e 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -557,6 +557,9 @@ jerry_value_t jerry_value_to_object (const jerry_value_t value); jerry_value_t jerry_value_to_primitive (const jerry_value_t value); jerry_value_t jerry_value_to_string (const jerry_value_t value); jerry_value_t jerry_value_to_bigint (const jerry_value_t value); +double jerry_value_as_integer (const jerry_value_t value); +int32_t jerry_value_as_int32 (const jerry_value_t value); +uint32_t jerry_value_as_uint32 (const jerry_value_t value); /** * Acquire types with reference counter (increase the references). diff --git a/tests/unit-core/test-number-converter.c b/tests/unit-core/test-number-converter.c new file mode 100644 index 000000000..683d13810 --- /dev/null +++ b/tests/unit-core/test-number-converter.c @@ -0,0 +1,137 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-globals.h" +#include "ecma-helpers.h" + +#include "test-common.h" + +// basic toUint32 tester method +static void +test_to_uint32 (double input, uint32_t test_number) +{ + jerry_value_t number_val = jerry_create_number (input); + uint32_t uint_number = jerry_value_as_uint32 (number_val); + TEST_ASSERT (uint_number == test_number); + jerry_release_value (number_val); +} /* test_to_uint32 */ + +// basic toInt32 tester method +static void +test_to_int32 (double input, int32_t test_number) +{ + jerry_value_t number_val = jerry_create_number (input); + int32_t int_number = jerry_value_as_int32 (number_val); + TEST_ASSERT (int_number == test_number); + jerry_release_value (number_val); +} /* test_to_int32 */ + +// basic toInteger tester method +static void +test_to_interger (double input, double test_number) +{ + jerry_value_t number_val = jerry_create_number (input); + double double_number = jerry_value_as_integer (number_val); + TEST_ASSERT (double_number == test_number); + jerry_release_value (number_val); +} /* test_to_interger */ + +int +main (void) +{ + TEST_INIT (); + + jerry_init (JERRY_INIT_EMPTY); + + // few toUint32 test-cases + test_to_uint32 (1.0, 1); + test_to_uint32 (0.0, 0); + test_to_uint32 (NAN, 0); + test_to_uint32 (-NAN, 0); + test_to_uint32 (INFINITY, 0); + test_to_uint32 (-INFINITY, 0); + test_to_uint32 (0.1, 0); + test_to_uint32 (-0.1, 0); + test_to_uint32 (1.1, 1); + test_to_uint32 (-1.1, 4294967295); + test_to_uint32 (4294967295, 4294967295); + test_to_uint32 (-4294967295, 1); + test_to_uint32 (4294967296, 0); + test_to_uint32 (-4294967296, 0); + test_to_uint32 (4294967297, 1); + test_to_uint32 (-4294967297, 4294967295); + + // few toint32 test-cases + test_to_int32 (1.0, 1); + test_to_int32 (0.0, 0); + test_to_int32 (NAN, 0); + test_to_int32 (-NAN, 0); + test_to_int32 (INFINITY, 0); + test_to_int32 (-INFINITY, 0); + test_to_int32 (0.1, 0); + test_to_int32 (-0.1, 0); + test_to_int32 (1.1, 1); + test_to_int32 (-1.1, -1); + test_to_int32 (4294967295, -1); + test_to_int32 (-4294967295, 1); + test_to_int32 (4294967296, 0); + test_to_int32 (-4294967296, 0); + test_to_int32 (4294967297, 1); + test_to_int32 (-4294967297, -1); + test_to_int32 (2147483648, -2147483648); + test_to_int32 (-2147483648, -2147483648); + test_to_int32 (2147483647, 2147483647); + test_to_int32 (-2147483647, -2147483647); + test_to_int32 (-2147483649, 2147483647); + test_to_int32 (2147483649, -2147483647); + + // few toInteger test-cases + test_to_interger (1.0, 1.0); + test_to_interger (0.0, 0.0); + test_to_interger (NAN, 0); + test_to_interger (-NAN, 0); + test_to_interger (INFINITY, INFINITY); + test_to_interger (-INFINITY, -INFINITY); + test_to_interger (0.1, 0); + test_to_interger (-0.1, -0); + test_to_interger (1.1, 1); + test_to_interger (-1.1, -1); + test_to_interger (4294967295, 4294967295); + test_to_interger (-4294967295, -4294967295); + test_to_interger (4294967295, 4294967295); + test_to_interger (-4294967296, -4294967296); + test_to_interger (4294967297, 4294967297); + test_to_interger (-4294967297, -4294967297); + + // few test-cases which return with error + jerry_value_t error_val = jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t *) "error"); + double number = jerry_value_as_integer (error_val); + jerry_release_value (error_val); + TEST_ASSERT (number == 0); + + error_val = jerry_create_symbol (error_val); + number = jerry_value_as_integer (error_val); + TEST_ASSERT (number == 0); + jerry_release_value (error_val); + + error_val = jerry_eval ((const jerry_char_t *) "({ valueOf() { throw new TypeError('foo')}})", + 44, JERRY_PARSE_NO_OPTS); + number = jerry_value_as_integer (error_val); + TEST_ASSERT (number == 0); + jerry_release_value (error_val); + + jerry_cleanup (); + return 0; +} /* main */