Skip to content

Commit 575b03b

Browse files
committed
A tool in jerry-ext: arg transformer for binding
It provides some APIs for binding developers, so that they can validate the type of the js argument and convert/assign them to the native argument. Related Issue: #1716 JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang [email protected]
1 parent 14c455b commit 575b03b

File tree

16 files changed

+1242
-3
lines changed

16 files changed

+1242
-3
lines changed

CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS )
2626
set(JERRY_CMDLINE ON CACHE BOOL "Build jerry command line tool?")
2727
set(JERRY_CMDLINE_MINIMAL OFF CACHE BOOL "Build jerry minimal command line tool?")
2828
set(JERRY_PORT_DEFAULT ON CACHE BOOL "Build default jerry port implementation?")
29+
set(JERRY_EXT ON CACHE BOOL "Build jerry-ext?")
2930
set(JERRY_LIBC ON CACHE BOOL "Build and use jerry-libc?")
3031
set(JERRY_LIBM ON CACHE BOOL "Build and use jerry-libm?")
3132
set(UNITTESTS OFF CACHE BOOL "Build unit tests?")
@@ -94,6 +95,7 @@ message(STATUS "ENABLE_STRIP " ${ENABLE_STRIP} ${ENABLE_STRIP_MESSA
9495
message(STATUS "JERRY_CMDLINE " ${JERRY_CMDLINE})
9596
message(STATUS "JERRY_CMDLINE_MINIMAL " ${JERRY_CMDLINE_MINIMAL})
9697
message(STATUS "JERRY_PORT_DEFAULT " ${JERRY_PORT_DEFAULT} ${JERRY_PORT_DEFAULT_MESSAGE})
98+
message(STATUS "JERRY_EXT " ${JERRY_EXT} ${JERRY_EXT_MESSAGE})
9799
message(STATUS "JERRY_LIBC " ${JERRY_LIBC} ${JERRY_LIBC_MESSAGE})
98100
message(STATUS "JERRY_LIBM " ${JERRY_LIBM} ${JERRY_LIBM_MESSAGE})
99101
message(STATUS "UNITTESTS " ${UNITTESTS})
@@ -238,6 +240,11 @@ if(JERRY_PORT_DEFAULT)
238240
add_subdirectory(jerry-port/default)
239241
endif()
240242

243+
# Jerry's extension tools
244+
if(JERRY_EXT)
245+
add_subdirectory(jerry-ext)
246+
endif()
247+
241248
# Jerry command line tool
242249
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL)
243250
add_subdirectory(jerry-main)
@@ -249,4 +256,7 @@ if(UNITTESTS)
249256
if(JERRY_LIBM)
250257
add_subdirectory(tests/unit-libm)
251258
endif()
259+
if(JERRY_EXT)
260+
add_subdirectory(tests/unit-ext)
261+
endif()
252262
endif()

jerry-ext/CMakeLists.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
cmake_minimum_required (VERSION 2.8.12)
16+
set(JERRY_EXT_NAME jerry-ext)
17+
project (${JERRY_EXT_NAME} C)
18+
19+
# Include directories
20+
set(INCLUDE_EXT "${CMAKE_CURRENT_SOURCE_DIR}/include")
21+
22+
# Source directories
23+
file(GLOB SOURCE_EXT args/*.c)
24+
25+
add_library(${JERRY_EXT_NAME} STATIC ${SOURCE_EXT})
26+
27+
target_include_directories(${JERRY_EXT_NAME} PUBLIC ${INCLUDE_EXT})
28+
29+
target_link_libraries(${JERRY_EXT_NAME} jerry-core)
30+
31+
install(TARGETS ${JERRY_EXT_NAME} DESTINATION lib)
32+
install(DIRECTORY ${INCLUDE_EXT}/ DESTINATION include)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 "args-internal.h"
17+
#include "jerryscript-ext/args.h"
18+
#include "jerryscript.h"
19+
20+
/**
21+
* Pop the current JS argument from the iterator.
22+
* It will change the index and js_arg_p value in the iterator.
23+
*
24+
* @return the current JS argument.
25+
*/
26+
jerry_value_t
27+
jerryx_arg_js_iterator_pop (jerryx_arg_js_iterator_t *js_arg_iter_p) /**< the JS arg iterator */
28+
{
29+
return (js_arg_iter_p->js_arg_idx++ < js_arg_iter_p->js_arg_cnt ? *js_arg_iter_p->js_arg_p++
30+
: jerry_create_undefined ());
31+
} /* jerryx_arg_js_iterator_pop */
32+
33+
/**
34+
* Get the current JS argument from the iterator.
35+
*
36+
* Note:
37+
* Unlike jerryx_arg_js_iterator_pop, it will not change index and
38+
* js_arg_p value in the iterator.
39+
*
40+
* @return the current JS argument.
41+
*/
42+
jerry_value_t
43+
jerryx_arg_js_iterator_peek (jerryx_arg_js_iterator_t *js_arg_iter_p) /**< the JS arg iterator */
44+
{
45+
return (js_arg_iter_p->js_arg_idx < js_arg_iter_p->js_arg_cnt ? *js_arg_iter_p->js_arg_p
46+
: jerry_create_undefined ());
47+
} /* jerryx_arg_js_iterator_peek */
48+
49+
/**
50+
* Get the index of the current JS argument
51+
*
52+
* @return the index
53+
*/
54+
jerry_length_t
55+
jerryx_arg_js_iterator_get_index (jerryx_arg_js_iterator_t *js_arg_iter_p) /**< the JS arg iterator */
56+
{
57+
return js_arg_iter_p->js_arg_idx;
58+
} /* jerryx_arg_js_iterator_get_index */
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
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 "args-internal.h"
17+
#include "jerryscript-ext/args.h"
18+
#include "jerryscript.h"
19+
20+
/**
21+
* The common function to deal with optional arguments.
22+
* The core transform function is provided by argument `func`.
23+
*
24+
* @return jerry undefined: the transformer passes,
25+
* jerry error: the transformer fails.
26+
*/
27+
jerry_value_t
28+
jerryx_arg_transform_optional (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
29+
const jerryx_arg_t *c_arg_p, /**< native arg */
30+
jerryx_arg_transform_func_t func) /**< the core transform function */
31+
{
32+
jerry_value_t js_arg = jerryx_arg_js_iterator_peek (js_arg_iter_p);
33+
34+
if (jerry_value_is_undefined (js_arg))
35+
{
36+
return js_arg;
37+
}
38+
39+
return func (js_arg_iter_p, c_arg_p);
40+
} /* jerryx_arg_transform_optional */
41+
42+
/**
43+
* Tranform a JS argument to a double. Type coercion is not allowed.
44+
*/
45+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_number_strict)
46+
{
47+
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
48+
49+
if (!jerry_value_is_number (js_arg))
50+
{
51+
return jerry_create_error (JERRY_ERROR_TYPE,
52+
(jerry_char_t *) "It is not a number.");
53+
}
54+
55+
double *dest = c_arg_p->dest;
56+
*dest = jerry_get_number_value (js_arg);
57+
58+
return jerry_create_undefined ();
59+
} /* JERRYX_ARG_TRANSFORM_FUNC */
60+
61+
/**
62+
* Tranform a JS argument to a double. Type coercion is allowed.
63+
*/
64+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_number)
65+
{
66+
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
67+
68+
jerry_value_t to_number = jerry_value_to_number (js_arg);
69+
70+
if (jerry_value_has_error_flag (to_number))
71+
{
72+
jerry_release_value (to_number);
73+
74+
return jerry_create_error (JERRY_ERROR_TYPE,
75+
(jerry_char_t *) "It can not be converted to a number.");
76+
}
77+
78+
double *dest = c_arg_p->dest;
79+
*dest = jerry_get_number_value (to_number);
80+
jerry_release_value (to_number);
81+
82+
return jerry_create_undefined ();
83+
} /* JERRYX_ARG_TRANSFORM_FUNC */
84+
85+
/**
86+
* Tranform a JS argument to a boolean. Type coercion is not allowed.
87+
*/
88+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_boolean_strict)
89+
{
90+
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
91+
92+
if (!jerry_value_is_boolean (js_arg))
93+
{
94+
return jerry_create_error (JERRY_ERROR_TYPE,
95+
(jerry_char_t *) "It is not a boolean.");
96+
}
97+
98+
bool *dest = c_arg_p->dest;
99+
*dest = jerry_get_boolean_value (js_arg);
100+
101+
return jerry_create_undefined ();
102+
} /* JERRYX_ARG_TRANSFORM_FUNC */
103+
104+
/**
105+
* Tranform a JS argument to a boolean. Type coercion is allowed.
106+
*/
107+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_boolean)
108+
{
109+
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
110+
111+
bool to_boolean = jerry_value_to_boolean (js_arg);
112+
113+
bool *dest = c_arg_p->dest;
114+
*dest = to_boolean;
115+
116+
return jerry_create_undefined ();
117+
} /* JERRYX_ARG_TRANSFORM_FUNC */
118+
119+
/**
120+
* The common routine for string transformer.
121+
*
122+
* @return jerry undefined: the transformer passes,
123+
* jerry error: the transformer fails.
124+
*/
125+
static jerry_value_t
126+
jerryx_arg_string_common_routine (jerry_value_t js_arg, /**< JS arg */
127+
const jerryx_arg_t *c_arg_p) /**< native arg */
128+
{
129+
jerry_size_t size = jerry_string_to_char_buffer (js_arg,
130+
(jerry_char_t *) c_arg_p->dest,
131+
(jerry_size_t) c_arg_p->extra_info);
132+
133+
if (size == 0)
134+
{
135+
return jerry_create_error (JERRY_ERROR_TYPE,
136+
(jerry_char_t *) "The size of the buffer is not large enough.");
137+
}
138+
139+
return jerry_create_undefined ();
140+
} /* jerryx_arg_string_common_routine */
141+
142+
/**
143+
* Tranform a JS argument to a char array. Type coercion is not allowed.
144+
*/
145+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_string_strict)
146+
{
147+
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
148+
149+
if (!jerry_value_is_string (js_arg))
150+
{
151+
return jerry_create_error (JERRY_ERROR_TYPE,
152+
(jerry_char_t *) "It is not a string.");
153+
}
154+
155+
return jerryx_arg_string_common_routine (js_arg, c_arg_p);
156+
} /* JERRYX_ARG_TRANSFORM_FUNC */
157+
158+
/**
159+
* Tranform a JS argument to a char array. Type coercion is allowed.
160+
*/
161+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_string)
162+
{
163+
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
164+
165+
jerry_value_t to_string = jerry_value_to_string (js_arg);
166+
167+
if (jerry_value_has_error_flag (to_string))
168+
{
169+
jerry_release_value (to_string);
170+
171+
return jerry_create_error (JERRY_ERROR_TYPE,
172+
(jerry_char_t *) "It can not be converted to a string.");
173+
}
174+
175+
jerry_value_t ret = jerryx_arg_string_common_routine (to_string, c_arg_p);
176+
jerry_release_value (to_string);
177+
178+
return ret;
179+
} /* JERRYX_ARG_TRANSFORM_FUNC */
180+
181+
/**
182+
* Check whether the JS argument is jerry function, if so, assign to the native argument.
183+
*/
184+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_function)
185+
{
186+
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
187+
188+
if (!jerry_value_is_function (js_arg))
189+
{
190+
return jerry_create_error (JERRY_ERROR_TYPE,
191+
(jerry_char_t *) "It is not a function.");
192+
}
193+
194+
jerry_value_t *func_p = c_arg_p->dest;
195+
*func_p = jerry_acquire_value (js_arg);
196+
197+
return jerry_create_undefined ();
198+
} /* JERRYX_ARG_TRANSFORM_FUNC */
199+
200+
/**
201+
* Check whether the native pointer has the expected type info.
202+
* If so, assign it to the native argument.
203+
*/
204+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_native_pointer)
205+
{
206+
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
207+
208+
if (!jerry_value_is_object (js_arg))
209+
{
210+
return jerry_create_error (JERRY_ERROR_TYPE,
211+
(jerry_char_t *) "It is not a object.");
212+
}
213+
214+
const jerry_object_native_info_t *expected_info_p;
215+
const jerry_object_native_info_t *out_info_p;
216+
expected_info_p = (const jerry_object_native_info_t *) c_arg_p->extra_info;
217+
void **ptr_p = (void **) c_arg_p->dest;
218+
bool is_ok = jerry_get_object_native_pointer (js_arg, ptr_p, &out_info_p);
219+
220+
if (!is_ok || out_info_p != expected_info_p)
221+
{
222+
return jerry_create_error (JERRY_ERROR_TYPE,
223+
(jerry_char_t *) "The object has no native pointer or type does not match.");
224+
}
225+
226+
return jerry_create_undefined ();
227+
} /* JERRYX_ARG_TRANSFORM_FUNC */
228+
229+
/**
230+
* Define transformer for optional argument.
231+
*/
232+
#define JERRYX_ARG_TRANSFORM_OPTIONAL(type) \
233+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_ ## type ## _optional) \
234+
{ \
235+
return jerryx_arg_transform_optional (js_arg_iter_p, c_arg_p, jerryx_arg_transform_ ## type); \
236+
}
237+
238+
JERRYX_ARG_TRANSFORM_OPTIONAL (number)
239+
JERRYX_ARG_TRANSFORM_OPTIONAL (number_strict)
240+
JERRYX_ARG_TRANSFORM_OPTIONAL (boolean)
241+
JERRYX_ARG_TRANSFORM_OPTIONAL (boolean_strict)
242+
JERRYX_ARG_TRANSFORM_OPTIONAL (string)
243+
JERRYX_ARG_TRANSFORM_OPTIONAL (string_strict)
244+
JERRYX_ARG_TRANSFORM_OPTIONAL (function)
245+
JERRYX_ARG_TRANSFORM_OPTIONAL (native_pointer)
246+
247+
/**
248+
* Ignore the JS argument.
249+
*/
250+
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_ignore)
251+
{
252+
(void) js_arg_iter_p; /* unused */
253+
(void) c_arg_p; /* unused */
254+
255+
return jerry_create_undefined ();
256+
} /* JERRYX_ARG_TRANSFORM_FUNC */

0 commit comments

Comments
 (0)