xref: /third_party/jerryscript/jerry-ext/arg/arg.c (revision 425bb815)
1/* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "arg-internal.h"
17#include "jerryscript-ext/arg.h"
18#include "jerryscript.h"
19#if defined(JERRY_FOR_IAR_CONFIG)
20#include "jerryscript-core.h"
21#endif
22
23#define JERRYX_STATIC_ASSERT(x, msg) \
24  enum { static_assertion_failed_ ## msg = 1 / (!!(x)) }
25
26JERRYX_STATIC_ASSERT (sizeof (jerryx_arg_int_option_t) <= sizeof (((jerryx_arg_t *) 0)->extra_info),
27                      jerryx_arg_number_options_t_must_fit_into_extra_info);
28
29#undef JERRYX_STATIC_ASSERT
30
31/**
32 * Validate the JS arguments and assign them to the native arguments.
33 *
34 * @return jerry undefined: all validators passed,
35 *         jerry error: a validator failed.
36 */
37jerry_value_t
38jerryx_arg_transform_args (const jerry_value_t *js_arg_p, /**< points to the array with JS arguments */
39                           const jerry_length_t js_arg_cnt, /**< the count of the `js_arg_p` array */
40                           const jerryx_arg_t *c_arg_p, /**< points to the array of validation/transformation steps */
41                           jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
42{
43  jerry_value_t ret = jerry_create_undefined ();
44
45  jerryx_arg_js_iterator_t iterator =
46  {
47    .js_arg_p = js_arg_p,
48    .js_arg_cnt = js_arg_cnt,
49    .js_arg_idx = 0
50  };
51
52  for (; c_arg_cnt != 0 && !jerry_value_is_error (ret); c_arg_cnt--, c_arg_p++)
53  {
54    ret = c_arg_p->func (&iterator, c_arg_p);
55  }
56
57  return ret;
58} /* jerryx_arg_transform_args */
59
60/**
61 * Validate the this value and the JS arguments,
62 * and assign them to the native arguments.
63 * This function is useful to perform input validation inside external
64 * function handlers (see jerry_external_handler_t).
65 * @note this_val is processed as the first value, before the array of arguments.
66 *
67 * @return jerry undefined: all validators passed,
68 *         jerry error: a validator failed.
69 */
70jerry_value_t
71jerryx_arg_transform_this_and_args (const jerry_value_t this_val, /**< the this_val for the external function */
72                                    const jerry_value_t *js_arg_p, /**< points to the array with JS arguments */
73                                    const jerry_length_t js_arg_cnt, /**< the count of the `js_arg_p` array */
74                                    const jerryx_arg_t *c_arg_p, /**< points to the array of transformation steps */
75                                    jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
76{
77  if (c_arg_cnt == 0)
78  {
79    return jerry_create_undefined ();
80  }
81
82  jerryx_arg_js_iterator_t iterator =
83  {
84    .js_arg_p = &this_val,
85    .js_arg_cnt = 1,
86    .js_arg_idx = 0
87  };
88
89  jerry_value_t ret = c_arg_p->func (&iterator, c_arg_p);
90
91  if (jerry_value_is_error (ret))
92  {
93    jerry_release_value (ret);
94
95    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "'this' validation failed.");
96  }
97
98  return jerryx_arg_transform_args (js_arg_p, js_arg_cnt, c_arg_p + 1, c_arg_cnt - 1);
99} /* jerryx_arg_transform_this_and_args */
100
101/**
102 * Validate the `obj_val`'s properties,
103 * and assign them to the native arguments.
104 *
105 * @return jerry undefined: all validators passed,
106 *         jerry error: a validator failed.
107 */
108jerry_value_t
109jerryx_arg_transform_object_properties (const jerry_value_t obj_val,/**< the JS object */
110                                        const jerry_char_t **name_p, /**< property name list of the JS object */
111                                        const jerry_length_t name_cnt, /**< count of the name list */
112                                        const jerryx_arg_t *c_arg_p, /**< points to the array of transformation steps */
113                                        jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
114{
115#if defined(JERRY_FOR_IAR_CONFIG)
116  jerry_value_t* prop;
117  jerry_value_t prop_i;
118#endif
119  if (!jerry_value_is_object (obj_val))
120  {
121    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an object.");
122  }
123
124#if defined(JERRY_FOR_IAR_CONFIG)
125  prop = (jerry_value_t*) jerry_vla_malloc (sizeof(jerry_value_t) * name_cnt);
126  if (!prop)
127  {
128    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "malloc prop fail.");
129  }
130#else
131  JERRY_VLA (jerry_value_t, prop, name_cnt);
132#endif
133  for (jerry_length_t i = 0; i < name_cnt; i++, name_p++)
134  {
135    const jerry_value_t name_str = jerry_create_string (*name_p);
136    prop[i] = jerry_get_property (obj_val, name_str);
137    jerry_release_value (name_str);
138
139    if (jerry_value_is_error (prop[i]))
140    {
141      for (jerry_length_t j = 0; j < i; j++)
142      {
143        jerry_release_value (prop[j]);
144      }
145#if defined(JERRY_FOR_IAR_CONFIG)
146      prop_i = prop[i];
147      jerry_vla_free ((char*)prop);
148      return prop_i;
149#else
150      return prop[i];
151#endif
152    }
153  }
154
155  const jerry_value_t ret = jerryx_arg_transform_args (prop, name_cnt, c_arg_p, c_arg_cnt);
156
157  for (jerry_length_t i = 0; i < name_cnt; i++)
158  {
159    jerry_release_value (prop[i]);
160  }
161#if defined(JERRY_FOR_IAR_CONFIG)
162  jerry_vla_free ((char*)prop);
163#endif
164  return ret;
165} /* jerryx_arg_transform_object_properties */
166
167/**
168 * Validate the items in the JS array and assign them to the native arguments.
169 *
170 * @return jerry undefined: all validators passed,
171 *         jerry error: a validator failed.
172 */
173jerry_value_t
174jerryx_arg_transform_array (const jerry_value_t array_val, /**< points to the JS array */
175                            const jerryx_arg_t *c_arg_p, /**< points to the array of validation/transformation steps */
176                            jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
177{
178#if defined(JERRY_FOR_IAR_CONFIG)
179  jerry_value_t* arr;
180  jerry_value_t arr_i;
181#endif
182  if (!jerry_value_is_array (array_val))
183  {
184    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an array.");
185  }
186
187#if defined(JERRY_FOR_IAR_CONFIG)
188  arr = (jerry_value_t*) jerry_vla_malloc (sizeof(jerry_value_t) * c_arg_cnt);
189  if (!arr)
190  {
191    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "malloc arr fail.");
192  }
193#else
194  JERRY_VLA (jerry_value_t, arr, c_arg_cnt);
195#endif
196  for (jerry_length_t i = 0; i < c_arg_cnt; i++)
197  {
198    arr[i] = jerry_get_property_by_index (array_val, i);
199
200    if (jerry_value_is_error (arr[i]))
201    {
202      for (jerry_length_t j = 0; j < i; j++)
203      {
204        jerry_release_value (arr[j]);
205      }
206#if defined(JERRY_FOR_IAR_CONFIG)
207      arr_i = arr[i];
208      jerry_vla_free ((char*)arr);
209      return arr_i;
210#else
211      return arr[i];
212#endif
213    }
214  }
215
216  const jerry_value_t ret = jerryx_arg_transform_args (arr, c_arg_cnt, c_arg_p, c_arg_cnt);
217
218  for (jerry_length_t i = 0; i < c_arg_cnt; i++)
219  {
220    jerry_release_value (arr[i]);
221  }
222#if defined(JERRY_FOR_IAR_CONFIG)
223  jerry_vla_free ((char*)arr);
224#endif
225  return ret;
226} /* jerryx_arg_transform_array */
227