1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation
2425bb815Sopenharmony_ci *
3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License.
5425bb815Sopenharmony_ci * You may obtain a copy of the License at
6425bb815Sopenharmony_ci *
7425bb815Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8425bb815Sopenharmony_ci *
9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS
11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and
13425bb815Sopenharmony_ci * limitations under the License.
14425bb815Sopenharmony_ci */
15425bb815Sopenharmony_ci
16425bb815Sopenharmony_ci#include "arg-internal.h"
17425bb815Sopenharmony_ci#include "jerryscript-ext/arg.h"
18425bb815Sopenharmony_ci#include "jerryscript.h"
19425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
20425bb815Sopenharmony_ci#include "jerryscript-core.h"
21425bb815Sopenharmony_ci#endif
22425bb815Sopenharmony_ci
23425bb815Sopenharmony_ci#define JERRYX_STATIC_ASSERT(x, msg) \
24425bb815Sopenharmony_ci  enum { static_assertion_failed_ ## msg = 1 / (!!(x)) }
25425bb815Sopenharmony_ci
26425bb815Sopenharmony_ciJERRYX_STATIC_ASSERT (sizeof (jerryx_arg_int_option_t) <= sizeof (((jerryx_arg_t *) 0)->extra_info),
27425bb815Sopenharmony_ci                      jerryx_arg_number_options_t_must_fit_into_extra_info);
28425bb815Sopenharmony_ci
29425bb815Sopenharmony_ci#undef JERRYX_STATIC_ASSERT
30425bb815Sopenharmony_ci
31425bb815Sopenharmony_ci/**
32425bb815Sopenharmony_ci * Validate the JS arguments and assign them to the native arguments.
33425bb815Sopenharmony_ci *
34425bb815Sopenharmony_ci * @return jerry undefined: all validators passed,
35425bb815Sopenharmony_ci *         jerry error: a validator failed.
36425bb815Sopenharmony_ci */
37425bb815Sopenharmony_cijerry_value_t
38425bb815Sopenharmony_cijerryx_arg_transform_args (const jerry_value_t *js_arg_p, /**< points to the array with JS arguments */
39425bb815Sopenharmony_ci                           const jerry_length_t js_arg_cnt, /**< the count of the `js_arg_p` array */
40425bb815Sopenharmony_ci                           const jerryx_arg_t *c_arg_p, /**< points to the array of validation/transformation steps */
41425bb815Sopenharmony_ci                           jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
42425bb815Sopenharmony_ci{
43425bb815Sopenharmony_ci  jerry_value_t ret = jerry_create_undefined ();
44425bb815Sopenharmony_ci
45425bb815Sopenharmony_ci  jerryx_arg_js_iterator_t iterator =
46425bb815Sopenharmony_ci  {
47425bb815Sopenharmony_ci    .js_arg_p = js_arg_p,
48425bb815Sopenharmony_ci    .js_arg_cnt = js_arg_cnt,
49425bb815Sopenharmony_ci    .js_arg_idx = 0
50425bb815Sopenharmony_ci  };
51425bb815Sopenharmony_ci
52425bb815Sopenharmony_ci  for (; c_arg_cnt != 0 && !jerry_value_is_error (ret); c_arg_cnt--, c_arg_p++)
53425bb815Sopenharmony_ci  {
54425bb815Sopenharmony_ci    ret = c_arg_p->func (&iterator, c_arg_p);
55425bb815Sopenharmony_ci  }
56425bb815Sopenharmony_ci
57425bb815Sopenharmony_ci  return ret;
58425bb815Sopenharmony_ci} /* jerryx_arg_transform_args */
59425bb815Sopenharmony_ci
60425bb815Sopenharmony_ci/**
61425bb815Sopenharmony_ci * Validate the this value and the JS arguments,
62425bb815Sopenharmony_ci * and assign them to the native arguments.
63425bb815Sopenharmony_ci * This function is useful to perform input validation inside external
64425bb815Sopenharmony_ci * function handlers (see jerry_external_handler_t).
65425bb815Sopenharmony_ci * @note this_val is processed as the first value, before the array of arguments.
66425bb815Sopenharmony_ci *
67425bb815Sopenharmony_ci * @return jerry undefined: all validators passed,
68425bb815Sopenharmony_ci *         jerry error: a validator failed.
69425bb815Sopenharmony_ci */
70425bb815Sopenharmony_cijerry_value_t
71425bb815Sopenharmony_cijerryx_arg_transform_this_and_args (const jerry_value_t this_val, /**< the this_val for the external function */
72425bb815Sopenharmony_ci                                    const jerry_value_t *js_arg_p, /**< points to the array with JS arguments */
73425bb815Sopenharmony_ci                                    const jerry_length_t js_arg_cnt, /**< the count of the `js_arg_p` array */
74425bb815Sopenharmony_ci                                    const jerryx_arg_t *c_arg_p, /**< points to the array of transformation steps */
75425bb815Sopenharmony_ci                                    jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
76425bb815Sopenharmony_ci{
77425bb815Sopenharmony_ci  if (c_arg_cnt == 0)
78425bb815Sopenharmony_ci  {
79425bb815Sopenharmony_ci    return jerry_create_undefined ();
80425bb815Sopenharmony_ci  }
81425bb815Sopenharmony_ci
82425bb815Sopenharmony_ci  jerryx_arg_js_iterator_t iterator =
83425bb815Sopenharmony_ci  {
84425bb815Sopenharmony_ci    .js_arg_p = &this_val,
85425bb815Sopenharmony_ci    .js_arg_cnt = 1,
86425bb815Sopenharmony_ci    .js_arg_idx = 0
87425bb815Sopenharmony_ci  };
88425bb815Sopenharmony_ci
89425bb815Sopenharmony_ci  jerry_value_t ret = c_arg_p->func (&iterator, c_arg_p);
90425bb815Sopenharmony_ci
91425bb815Sopenharmony_ci  if (jerry_value_is_error (ret))
92425bb815Sopenharmony_ci  {
93425bb815Sopenharmony_ci    jerry_release_value (ret);
94425bb815Sopenharmony_ci
95425bb815Sopenharmony_ci    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "'this' validation failed.");
96425bb815Sopenharmony_ci  }
97425bb815Sopenharmony_ci
98425bb815Sopenharmony_ci  return jerryx_arg_transform_args (js_arg_p, js_arg_cnt, c_arg_p + 1, c_arg_cnt - 1);
99425bb815Sopenharmony_ci} /* jerryx_arg_transform_this_and_args */
100425bb815Sopenharmony_ci
101425bb815Sopenharmony_ci/**
102425bb815Sopenharmony_ci * Validate the `obj_val`'s properties,
103425bb815Sopenharmony_ci * and assign them to the native arguments.
104425bb815Sopenharmony_ci *
105425bb815Sopenharmony_ci * @return jerry undefined: all validators passed,
106425bb815Sopenharmony_ci *         jerry error: a validator failed.
107425bb815Sopenharmony_ci */
108425bb815Sopenharmony_cijerry_value_t
109425bb815Sopenharmony_cijerryx_arg_transform_object_properties (const jerry_value_t obj_val,/**< the JS object */
110425bb815Sopenharmony_ci                                        const jerry_char_t **name_p, /**< property name list of the JS object */
111425bb815Sopenharmony_ci                                        const jerry_length_t name_cnt, /**< count of the name list */
112425bb815Sopenharmony_ci                                        const jerryx_arg_t *c_arg_p, /**< points to the array of transformation steps */
113425bb815Sopenharmony_ci                                        jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
114425bb815Sopenharmony_ci{
115425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
116425bb815Sopenharmony_ci  jerry_value_t* prop;
117425bb815Sopenharmony_ci  jerry_value_t prop_i;
118425bb815Sopenharmony_ci#endif
119425bb815Sopenharmony_ci  if (!jerry_value_is_object (obj_val))
120425bb815Sopenharmony_ci  {
121425bb815Sopenharmony_ci    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an object.");
122425bb815Sopenharmony_ci  }
123425bb815Sopenharmony_ci
124425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
125425bb815Sopenharmony_ci  prop = (jerry_value_t*) jerry_vla_malloc (sizeof(jerry_value_t) * name_cnt);
126425bb815Sopenharmony_ci  if (!prop)
127425bb815Sopenharmony_ci  {
128425bb815Sopenharmony_ci    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "malloc prop fail.");
129425bb815Sopenharmony_ci  }
130425bb815Sopenharmony_ci#else
131425bb815Sopenharmony_ci  JERRY_VLA (jerry_value_t, prop, name_cnt);
132425bb815Sopenharmony_ci#endif
133425bb815Sopenharmony_ci  for (jerry_length_t i = 0; i < name_cnt; i++, name_p++)
134425bb815Sopenharmony_ci  {
135425bb815Sopenharmony_ci    const jerry_value_t name_str = jerry_create_string (*name_p);
136425bb815Sopenharmony_ci    prop[i] = jerry_get_property (obj_val, name_str);
137425bb815Sopenharmony_ci    jerry_release_value (name_str);
138425bb815Sopenharmony_ci
139425bb815Sopenharmony_ci    if (jerry_value_is_error (prop[i]))
140425bb815Sopenharmony_ci    {
141425bb815Sopenharmony_ci      for (jerry_length_t j = 0; j < i; j++)
142425bb815Sopenharmony_ci      {
143425bb815Sopenharmony_ci        jerry_release_value (prop[j]);
144425bb815Sopenharmony_ci      }
145425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
146425bb815Sopenharmony_ci      prop_i = prop[i];
147425bb815Sopenharmony_ci      jerry_vla_free ((char*)prop);
148425bb815Sopenharmony_ci      return prop_i;
149425bb815Sopenharmony_ci#else
150425bb815Sopenharmony_ci      return prop[i];
151425bb815Sopenharmony_ci#endif
152425bb815Sopenharmony_ci    }
153425bb815Sopenharmony_ci  }
154425bb815Sopenharmony_ci
155425bb815Sopenharmony_ci  const jerry_value_t ret = jerryx_arg_transform_args (prop, name_cnt, c_arg_p, c_arg_cnt);
156425bb815Sopenharmony_ci
157425bb815Sopenharmony_ci  for (jerry_length_t i = 0; i < name_cnt; i++)
158425bb815Sopenharmony_ci  {
159425bb815Sopenharmony_ci    jerry_release_value (prop[i]);
160425bb815Sopenharmony_ci  }
161425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
162425bb815Sopenharmony_ci  jerry_vla_free ((char*)prop);
163425bb815Sopenharmony_ci#endif
164425bb815Sopenharmony_ci  return ret;
165425bb815Sopenharmony_ci} /* jerryx_arg_transform_object_properties */
166425bb815Sopenharmony_ci
167425bb815Sopenharmony_ci/**
168425bb815Sopenharmony_ci * Validate the items in the JS array and assign them to the native arguments.
169425bb815Sopenharmony_ci *
170425bb815Sopenharmony_ci * @return jerry undefined: all validators passed,
171425bb815Sopenharmony_ci *         jerry error: a validator failed.
172425bb815Sopenharmony_ci */
173425bb815Sopenharmony_cijerry_value_t
174425bb815Sopenharmony_cijerryx_arg_transform_array (const jerry_value_t array_val, /**< points to the JS array */
175425bb815Sopenharmony_ci                            const jerryx_arg_t *c_arg_p, /**< points to the array of validation/transformation steps */
176425bb815Sopenharmony_ci                            jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
177425bb815Sopenharmony_ci{
178425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
179425bb815Sopenharmony_ci  jerry_value_t* arr;
180425bb815Sopenharmony_ci  jerry_value_t arr_i;
181425bb815Sopenharmony_ci#endif
182425bb815Sopenharmony_ci  if (!jerry_value_is_array (array_val))
183425bb815Sopenharmony_ci  {
184425bb815Sopenharmony_ci    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an array.");
185425bb815Sopenharmony_ci  }
186425bb815Sopenharmony_ci
187425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
188425bb815Sopenharmony_ci  arr = (jerry_value_t*) jerry_vla_malloc (sizeof(jerry_value_t) * c_arg_cnt);
189425bb815Sopenharmony_ci  if (!arr)
190425bb815Sopenharmony_ci  {
191425bb815Sopenharmony_ci    return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "malloc arr fail.");
192425bb815Sopenharmony_ci  }
193425bb815Sopenharmony_ci#else
194425bb815Sopenharmony_ci  JERRY_VLA (jerry_value_t, arr, c_arg_cnt);
195425bb815Sopenharmony_ci#endif
196425bb815Sopenharmony_ci  for (jerry_length_t i = 0; i < c_arg_cnt; i++)
197425bb815Sopenharmony_ci  {
198425bb815Sopenharmony_ci    arr[i] = jerry_get_property_by_index (array_val, i);
199425bb815Sopenharmony_ci
200425bb815Sopenharmony_ci    if (jerry_value_is_error (arr[i]))
201425bb815Sopenharmony_ci    {
202425bb815Sopenharmony_ci      for (jerry_length_t j = 0; j < i; j++)
203425bb815Sopenharmony_ci      {
204425bb815Sopenharmony_ci        jerry_release_value (arr[j]);
205425bb815Sopenharmony_ci      }
206425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
207425bb815Sopenharmony_ci      arr_i = arr[i];
208425bb815Sopenharmony_ci      jerry_vla_free ((char*)arr);
209425bb815Sopenharmony_ci      return arr_i;
210425bb815Sopenharmony_ci#else
211425bb815Sopenharmony_ci      return arr[i];
212425bb815Sopenharmony_ci#endif
213425bb815Sopenharmony_ci    }
214425bb815Sopenharmony_ci  }
215425bb815Sopenharmony_ci
216425bb815Sopenharmony_ci  const jerry_value_t ret = jerryx_arg_transform_args (arr, c_arg_cnt, c_arg_p, c_arg_cnt);
217425bb815Sopenharmony_ci
218425bb815Sopenharmony_ci  for (jerry_length_t i = 0; i < c_arg_cnt; i++)
219425bb815Sopenharmony_ci  {
220425bb815Sopenharmony_ci    jerry_release_value (arr[i]);
221425bb815Sopenharmony_ci  }
222425bb815Sopenharmony_ci#if defined(JERRY_FOR_IAR_CONFIG)
223425bb815Sopenharmony_ci  jerry_vla_free ((char*)arr);
224425bb815Sopenharmony_ci#endif
225425bb815Sopenharmony_ci  return ret;
226425bb815Sopenharmony_ci} /* jerryx_arg_transform_array */
227