Skip to content

add transform functions for integer in jerryx/arg #1883

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions docs/09.EXT-REFERENCE-ARG.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,42 @@ Enum that indicates whether an argument is optional or required.
- [jerryx_arg_function](#jerryx_arg_function)
- [jerryx_arg_native_pointer](#jerryx_arg_native_pointer)

## jerryx_arg_round_t

Enum that indicates the rounding policy which will be chosen to transform an integer.

- JERRYX_ARG_ROUND - use round() method.
- JERRYX_ARG_FLOOR - use floor() method.
- JERRYX_ARG_CEIL - use ceil() method.

**See also**

- [jerryx_arg_uint8](#jerryx_arg_uint8)
- [jerryx_arg_uint16](#jerryx_arg_uint16)
- [jerryx_arg_uint32](#jerryx_arg_uint32)
- [jerryx_arg_int8](#jerryx_arg_int8)
- [jerryx_arg_int16](#jerryx_arg_int16)
- [jerryx_arg_int32](#jerryx_arg_int32)


## jerryx_arg_clamp_t

Indicates the clamping policy which will be chosen to transform an integer.
If the policy is NO_CLAMP, and the number is out of range,
then the transformer will throw a range error.

- JERRYX_ARG_CLAMP - clamp the number when it is out of range
- JERRYX_ARG_NO_CLAMP - throw a range error

**See also**

- [jerryx_arg_uint8](#jerryx_arg_uint8)
- [jerryx_arg_uint16](#jerryx_arg_uint16)
- [jerryx_arg_uint32](#jerryx_arg_uint32)
- [jerryx_arg_int8](#jerryx_arg_int8)
- [jerryx_arg_int16](#jerryx_arg_int16)
- [jerryx_arg_int32](#jerryx_arg_int32)

# Main functions

## jerryx_arg_transform_this_and_args
Expand Down Expand Up @@ -270,6 +306,49 @@ jerryx_arg_transform_object_properties (const jerry_value_t obj_val,

# Helpers for commonly used validations

## jerryx_arg_uint8

## jerryx_arg_uint16

## jerryx_arg_uint32

## jerryx_arg_int8

## jerryx_arg_int16

## jerryx_arg_int32

**Summary**

All above jerryx_arg_[u]intX functions are used to create a validation/transformation step
(`jerryx_arg_t`) that expects to consume one `number` JS argument
and stores it into a C integer (uint8, int8, uint16, ...)

**Prototype**

Take jerryx_arg_int32 as an example

```c
static inline jerryx_arg_t
jerryx_arg_int32 (int32_t *dest,
jerryx_arg_round_t round_flag,
jerryx_arg_clamp_t clamp_flag,
jerryx_arg_coerce_t coerce_flag,
jerryx_arg_optional_t opt_flag);
```

- return value - the created `jerryx_arg_t` instance.
- `dest` - pointer to the `int32_t` where the result should be stored.
- `round_flag` - the rounding policy.
- `clamp_flag` - the clamping policy.
- `coerce_flag` - whether type coercion is allowed.
- `opt_flag` - whether the argument is optional.

**See also**

- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args)


## jerryx_arg_number

**Summary**
Expand Down
161 changes: 142 additions & 19 deletions jerry-ext/arg/arg-transform-functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* limitations under the License.
*/

#include <math.h>

#include "jerryscript-ext/arg.h"
#include "jerryscript.h"

Expand All @@ -39,14 +41,15 @@ jerryx_arg_transform_optional (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< ava
} /* jerryx_arg_transform_optional */

/**
* Tranform a JS argument to a double. Type coercion is not allowed.
* The common part in transforming a JS argument to a number (double or certain int) type.
* Type coercion is not allowed.
*
* @return jerry undefined: the transformer passes,
* jerry error: the transformer fails.
*/
jerry_value_t
jerryx_arg_transform_number_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
const jerryx_arg_t *c_arg_p) /**< the native arg */
static jerry_value_t
jerryx_arg_transform_number_strict_common (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
double *number_p) /**< [out] the number in JS arg */
{
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);

Expand All @@ -56,21 +59,21 @@ jerryx_arg_transform_number_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /**
(jerry_char_t *) "It is not a number.");
}

double *dest = c_arg_p->dest;
*dest = jerry_get_number_value (js_arg);
*number_p = jerry_get_number_value (js_arg);

return jerry_create_undefined ();
} /* jerryx_arg_transform_number_strict */
} /* jerryx_arg_transform_number_strict_common */

/**
* Transform a JS argument to a double. Type coercion is allowed.
* The common part in transforming a JS argument to a number (double or certain int) type.
* Type coercion is allowed.
*
* @return jerry undefined: the transformer passes,
* jerry error: the transformer fails.
*/
jerry_value_t
jerryx_arg_transform_number (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
const jerryx_arg_t *c_arg_p) /**< the native arg */
static jerry_value_t
jerryx_arg_transform_number_common (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
double *number_p) /**< [out] the number in JS arg */
{
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);

Expand All @@ -84,13 +87,118 @@ jerryx_arg_transform_number (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< avail
(jerry_char_t *) "It can not be converted to a number.");
}

double *dest = c_arg_p->dest;
*dest = jerry_get_number_value (to_number);
*number_p = jerry_get_number_value (to_number);
jerry_release_value (to_number);

return jerry_create_undefined ();
} /* jerryx_arg_transform_number_common */

/**
* Transform a JS argument to a double. Type coercion is not allowed.
*
* @return jerry undefined: the transformer passes,
* jerry error: the transformer fails.
*/
jerry_value_t
jerryx_arg_transform_number_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
const jerryx_arg_t *c_arg_p) /**< the native arg */
{
return jerryx_arg_transform_number_strict_common (js_arg_iter_p, c_arg_p->dest);
} /* jerryx_arg_transform_number_strict */

/**
* Tranform a JS argument to a double. Type coercion is allowed.
*
* @return jerry undefined: the transformer passes,
* jerry error: the transformer fails.
*/
jerry_value_t
jerryx_arg_transform_number (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
const jerryx_arg_t *c_arg_p) /**< the native arg */
{
return jerryx_arg_transform_number_common (js_arg_iter_p, c_arg_p->dest);
} /* jerryx_arg_transform_number */

/**
* Helper function to process a double number before converting it
* to an integer.
*
* @return jerry undefined: the transformer passes,
* jerry error: the transformer fails.
*/
static jerry_value_t
jerryx_arg_helper_process_double (double *d, /**< [in, out] the number to be processed */
double min, /**< the min value for clamping */
double max, /**< the max value for clamping */
jerryx_arg_int_option_t option) /**< the converting policies */
{
if (option.clamp == JERRYX_ARG_NO_CLAMP)
{
if (*d > max || *d < min)
{
return jerry_create_error (JERRY_ERROR_TYPE,
(jerry_char_t *) "The number is out of range.");
}
}
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we are using an enum with potentially multiple values (not necessarily just a boolean yes/no), we should get future-proof. There are three alternatives:

  • if (x == VALUE1) { ... } else { assert (x == VALUE2); ... }
  • if (x == VALUE1) { ... } else if (x == VALUE2) { ... } else { assert (false); }
  • switch (x) { case VALUE1: ... break; case VALUE2: ... break; default: assert (false); }

Perhaps the last one is the best (after fleshing the sketch out).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to perfect the above code after we impl the assert/unreachable/ndebug such things in jerryx?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, leave it for now

{
*d = *d < min ? min : *d;
*d = *d > max ? max : *d;
}

if (option.round == JERRYX_ARG_ROUND)
{
*d = (*d >= 0.0) ? floor (*d + 0.5) : ceil (*d - 0.5);
}
else if (option.round == JERRYX_ARG_FLOOR)
{
*d = floor (*d);
}
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here as above, for safely covering all enum values (especially since we really have more than two possible values in this case)

{
*d = ceil (*d);
}

return jerry_create_undefined ();
} /* jerryx_arg_helper_process_double */

/**
* Use the macro to define thr transform functions for int type.
*/
#define JERRYX_ARG_TRANSFORM_FUNC_FOR_INT_TEMPLATE(type, suffix, min, max) \
jerry_value_t jerryx_arg_transform_ ## type ## suffix (jerryx_arg_js_iterator_t *js_arg_iter_p, \
const jerryx_arg_t *c_arg_p) \
{ \
double tmp; \
jerry_value_t rv = jerryx_arg_transform_number ## suffix ## _common (js_arg_iter_p, &tmp); \
if (jerry_value_has_error_flag (rv)) \
{ \
return rv; \
} \
jerry_release_value (rv); \
jerryx_arg_int_option_t *options_p = (jerryx_arg_int_option_t *) &c_arg_p->extra_info; \
rv = jerryx_arg_helper_process_double (&tmp, min, max, *options_p); \
if (jerry_value_has_error_flag (rv)) \
{ \
return rv; \
} \
*(type ## _t *) c_arg_p->dest = (type ## _t) tmp; \
return rv; \
}

#define JERRYX_ARG_TRANSFORM_FUNC_FOR_INT(type, min, max) \
JERRYX_ARG_TRANSFORM_FUNC_FOR_INT_TEMPLATE (type, _strict, min, max) \
JERRYX_ARG_TRANSFORM_FUNC_FOR_INT_TEMPLATE (type, , min, max)

JERRYX_ARG_TRANSFORM_FUNC_FOR_INT (uint8, 0, UINT8_MAX)
JERRYX_ARG_TRANSFORM_FUNC_FOR_INT (int8, INT8_MIN, INT8_MAX)
JERRYX_ARG_TRANSFORM_FUNC_FOR_INT (uint16, 0, UINT16_MAX)
JERRYX_ARG_TRANSFORM_FUNC_FOR_INT (int16, INT16_MIN, INT16_MAX)
JERRYX_ARG_TRANSFORM_FUNC_FOR_INT (uint32, 0, UINT32_MAX)
JERRYX_ARG_TRANSFORM_FUNC_FOR_INT (int32, INT32_MIN, INT32_MAX)

#undef JERRYX_ARG_TRANSFORM_FUNC_FOR_INT_TEMPLATE
#undef JERRYX_ARG_TRANSFORM_FUNC_FOR_INT
/**
* Tranform a JS argument to a boolean. Type coercion is not allowed.
*
Expand Down Expand Up @@ -294,12 +402,12 @@ jerryx_arg_transform_object_props (jerryx_arg_js_iterator_t *js_arg_iter_p, /**<
* Define transformer for optional argument.
*/
#define JERRYX_ARG_TRANSFORM_OPTIONAL(type) \
jerry_value_t \
jerryx_arg_transform_ ## type ## _optional (jerryx_arg_js_iterator_t *js_arg_iter_p, \
const jerryx_arg_t *c_arg_p) \
{ \
return jerryx_arg_transform_optional (js_arg_iter_p, c_arg_p, jerryx_arg_transform_ ## type); \
}
jerry_value_t \
jerryx_arg_transform_ ## type ## _optional (jerryx_arg_js_iterator_t *js_arg_iter_p, \
const jerryx_arg_t *c_arg_p) \
{ \
return jerryx_arg_transform_optional (js_arg_iter_p, c_arg_p, jerryx_arg_transform_ ## type); \
}

JERRYX_ARG_TRANSFORM_OPTIONAL (number)
JERRYX_ARG_TRANSFORM_OPTIONAL (number_strict)
Expand All @@ -311,6 +419,21 @@ JERRYX_ARG_TRANSFORM_OPTIONAL (function)
JERRYX_ARG_TRANSFORM_OPTIONAL (native_pointer)
JERRYX_ARG_TRANSFORM_OPTIONAL (object_props)

JERRYX_ARG_TRANSFORM_OPTIONAL (uint8)
JERRYX_ARG_TRANSFORM_OPTIONAL (uint16)
JERRYX_ARG_TRANSFORM_OPTIONAL (uint32)
JERRYX_ARG_TRANSFORM_OPTIONAL (int8)
JERRYX_ARG_TRANSFORM_OPTIONAL (int16)
JERRYX_ARG_TRANSFORM_OPTIONAL (int32)
JERRYX_ARG_TRANSFORM_OPTIONAL (int8_strict)
JERRYX_ARG_TRANSFORM_OPTIONAL (int16_strict)
JERRYX_ARG_TRANSFORM_OPTIONAL (int32_strict)
JERRYX_ARG_TRANSFORM_OPTIONAL (uint8_strict)
JERRYX_ARG_TRANSFORM_OPTIONAL (uint16_strict)
JERRYX_ARG_TRANSFORM_OPTIONAL (uint32_strict)

#undef JERRYX_ARG_TRANSFORM_OPTIONAL

/**
* Ignore the JS argument.
*
Expand Down
9 changes: 9 additions & 0 deletions jerry-ext/arg/arg.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@
#include "jerryscript-ext/arg.h"
#include "jerryscript.h"


#define JERRYX_STATIC_ASSERT(x, msg) \
enum { static_assertion_failed_ ## msg = 1 / (!!(x)) }

JERRYX_STATIC_ASSERT (sizeof (jerryx_arg_int_option_t) <= sizeof (((jerryx_arg_t *) 0)->extra_info),
jerryx_arg_number_options_t_must_fit_into_extra_info);

#undef JERRYX_STATIC_ASSERT

/**
* Validate the JS arguments and assign them to the native arguments.
*
Expand Down
45 changes: 42 additions & 3 deletions jerry-ext/include/jerryscript-ext/arg.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,52 @@ typedef enum
JERRYX_ARG_REQUIRED
} jerryx_arg_optional_t;

/**
* Indicates the rounding policy which will be chosen to transform an integer.
*/
typedef enum
{
JERRYX_ARG_ROUND, /**< round */
JERRYX_ARG_FLOOR, /**< floor */
JERRYX_ARG_CEIL /**< ceil */
} jerryx_arg_round_t;

/**
* Indicates the clamping policy which will be chosen to transform an integer.
* If the policy is NO_CLAMP, and the number is out of range,
* then the transformer will throw a range error.
*/
typedef enum
{
JERRYX_ARG_CLAMP,/**< clamp the number when it is out of range */
JERRYX_ARG_NO_CLAMP /**< throw a range error */
} jerryx_arg_clamp_t;

/* Inline functions for initializing jerryx_arg_t */

#define JERRYX_ARG_INTEGER(type) \
static inline jerryx_arg_t \
jerryx_arg_ ## type (type ## _t *dest, \
jerryx_arg_round_t round_flag, \
jerryx_arg_clamp_t clamp_flag, \
jerryx_arg_coerce_t coerce_flag, \
jerryx_arg_optional_t opt_flag);

JERRYX_ARG_INTEGER (uint8)
JERRYX_ARG_INTEGER (int8)
JERRYX_ARG_INTEGER (uint16)
JERRYX_ARG_INTEGER (int16)
JERRYX_ARG_INTEGER (uint32)
JERRYX_ARG_INTEGER (int32)

#undef JERRYX_ARG_INTEGER

static inline jerryx_arg_t
jerryx_arg_number (double *dest, jerryx_arg_coerce_t conv_flag, jerryx_arg_optional_t opt_flag);
jerryx_arg_number (double *dest, jerryx_arg_coerce_t coerce_flag, jerryx_arg_optional_t opt_flag);
static inline jerryx_arg_t
jerryx_arg_boolean (bool *dest, jerryx_arg_coerce_t conv_flag, jerryx_arg_optional_t opt_flag);
jerryx_arg_boolean (bool *dest, jerryx_arg_coerce_t coerce_flag, jerryx_arg_optional_t opt_flag);
static inline jerryx_arg_t
jerryx_arg_string (char *dest, uint32_t size, jerryx_arg_coerce_t conv_flag, jerryx_arg_optional_t opt_flag);
jerryx_arg_string (char *dest, uint32_t size, jerryx_arg_coerce_t coerce_flag, jerryx_arg_optional_t opt_flag);
static inline jerryx_arg_t
jerryx_arg_function (jerry_value_t *dest, jerryx_arg_optional_t opt_flag);
static inline jerryx_arg_t
Expand Down
Loading