Skip to content

Commit 1547e92

Browse files
committed
Add json parse and stringify function to jerryscript c api
JerryScript-DCO-1.0-Signed-off-by: Zsolt Raduska [email protected]
1 parent 29b337d commit 1547e92

File tree

7 files changed

+323
-80
lines changed

7 files changed

+323
-80
lines changed

docs/02.API-REFERENCE.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5561,3 +5561,67 @@ jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value,
55615561
**See also**
55625562

55635563
- [jerry_create_typedarray](#jerry_create_typedarray)
5564+
5565+
# JSON functions
5566+
5567+
## jerry_json_parse
5568+
5569+
**Summary**
5570+
5571+
Parse a JSON string.
5572+
Returns a jerry_value_t which contains key-value pairs imported from the JSON string.
5573+
5574+
**Prototype**
5575+
5576+
```c
5577+
jerry_value_t jerry_json_parse (const char *json_string)
5578+
```
5579+
5580+
- `json_string` - a JSON formated string to parse
5581+
5582+
**Example**
5583+
5584+
```c
5585+
{
5586+
const char *data_in_json = "{\"name\": \"John\", \"age\": 5}";
5587+
jerry_value_t parsed_json = jerry_json_parse (data_in_json);
5588+
5589+
// parsed_json now conatins all of data stored in data_in_json
5590+
5591+
jerry_release_value (parsed_json);
5592+
}
5593+
```
5594+
5595+
## jerry_stringify
5596+
5597+
**Summary**
5598+
5599+
Stringify a jerry_value_t object.
5600+
Convert a jerry_value_t object into a json formated string.
5601+
5602+
**Prototype**
5603+
5604+
```c
5605+
jerry_value_t jerry_json_stringfy (const jerry_value_t object_to_stringify)
5606+
```
5607+
5608+
- `object_to_stringify` - a jerry_value_t object to stringify
5609+
5610+
**Example**
5611+
5612+
```c
5613+
{
5614+
jerry_value_t obj = jerry_create_object ();
5615+
jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name");
5616+
jerry_value_t value = jerry_create_string ((const jerry_char_t *) "John");
5617+
jerry_set_property (obj, key, value);
5618+
jerry_value_t stringified = jerry_json_stringfy (obj);
5619+
5620+
//stringified now contains a json formated string
5621+
5622+
jerry_release_value (obj);
5623+
jerry_release_value (key);
5624+
jerry_release_value (value);
5625+
jerry_release_value (stringified);
5626+
}
5627+
```

jerry-core/api/jerry.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3334,6 +3334,63 @@ jerry_get_typedarray_buffer (jerry_value_t value, /**< TypedArray to get the arr
33343334
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
33353335
} /* jerry_get_typedarray_buffer */
33363336

3337+
/**
3338+
* Create an object from JSON
3339+
*
3340+
* Note:
3341+
* The returned value must be freed with jerry_release_value
3342+
* @return jerry_value_t from json formated string
3343+
*/
3344+
jerry_value_t
3345+
jerry_json_parse (const char *json_string)
3346+
{
3347+
jerry_assert_api_available ();
3348+
3349+
#ifndef CONFIG_DISABLE_JSON_BUILTIN
3350+
lit_utf8_size_t json_string_size = lit_zt_utf8_string_size ((lit_utf8_byte_t *) json_string);
3351+
const lit_utf8_byte_t *json_string_p = (const lit_utf8_byte_t *) (json_string);
3352+
ecma_value_t ret_value = ecma_builtin_json_fill_token_fields_from_string (json_string_p, json_string_size);
3353+
3354+
if (ecma_is_value_undefined (ret_value))
3355+
{
3356+
ret_value = jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("JSON string parse error.")));
3357+
}
3358+
3359+
return ret_value;
3360+
#else /* CONFIG_DISABLE_JSON_BUILTIN */
3361+
JERRY_UNUSED (json_string);
3362+
3363+
return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The JSON has been disabled.")));
3364+
#endif /* !CONFIG_DISABLE_JSON_BUILTIN */
3365+
} /* jerry_json_parse */
3366+
3367+
/**
3368+
* Create a Json formated string from an object
3369+
*
3370+
* Note:
3371+
* The returned value must be freed with jerry_release_value
3372+
* @return json formated jerry_value_t
3373+
*/
3374+
jerry_value_t
3375+
jerry_json_stringfy (const jerry_value_t object_to_stringify)
3376+
{
3377+
jerry_assert_api_available ();
3378+
#ifndef CONFIG_DISABLE_JSON_BUILTIN
3379+
ecma_value_t ret_value = ecma_builtin_json_string_from_object (object_to_stringify);
3380+
3381+
if (ecma_is_value_undefined (ret_value))
3382+
{
3383+
ret_value = jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("JSON stringify error.")));
3384+
}
3385+
3386+
return ret_value;
3387+
#else /* CONFIG_DISABLE_JSON_BUILTIN */
3388+
JERRY_UNUSED (object_to_stringify);
3389+
3390+
return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The JSON has been disabled.")));
3391+
#endif /* !CONFIG_DISABLE_JSON_BUILTIN */
3392+
} /* jerry_json_stringfy */
3393+
33373394
/**
33383395
* @}
33393396
*/

jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include "ecma-helpers.h"
1818
#include "ecma-builtin-helpers.h"
1919
#include "lit-char-helpers.h"
20+
#include "ecma-try-catch-macro.h"
21+
#include "ecma-objects.h"
22+
23+
#ifndef CONFIG_DISABLE_JSON_BUILTIN
2024

2125
/** \addtogroup ecma ECMA
2226
* @{
@@ -221,6 +225,91 @@ ecma_builtin_helper_json_create_non_formatted_json (lit_utf8_byte_t left_bracket
221225
return ecma_make_string_value (result_str_p);
222226
} /* ecma_builtin_helper_json_create_non_formatted_json */
223227

228+
/**
229+
* Function to set a string token from the given arguments, fill its fields and advances the string pointer.
230+
*
231+
* @return ecma value
232+
* Returned value must be freed with ecma_free_value.
233+
*/
234+
ecma_value_t
235+
ecma_builtin_json_fill_token_fields_from_string (const lit_utf8_byte_t * str_start_p, lit_utf8_size_t string_size)
236+
{
237+
ecma_json_token_t token;
238+
token.current_p = str_start_p;
239+
token.end_p = str_start_p + string_size;
240+
241+
ecma_value_t final_result = ecma_builtin_json_parse_value (&token);
242+
243+
if (!ecma_is_value_undefined (final_result))
244+
{
245+
ecma_builtin_json_parse_next_token (&token, false);
246+
247+
if (token.type != end_token)
248+
{
249+
ecma_free_value (final_result);
250+
final_result = ECMA_VALUE_UNDEFINED;
251+
}
252+
}
253+
return final_result;
254+
} /*ecma_builtin_json_fill_token_fields_from_string*/
255+
256+
/**
257+
* Helper functions to stringify an object in JSON format representing an ecma_value.
258+
*
259+
* @return ecma value
260+
* Returned value must be freed with ecma_free_value.
261+
*
262+
*/
263+
ecma_value_t ema_builtin_json_str_helper (const ecma_value_t arg1, ecma_json_stringify_context_t context)
264+
{
265+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
266+
ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg ();
267+
ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
268+
ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p,
269+
empty_str_p,
270+
arg1,
271+
false);
272+
JERRY_ASSERT (ecma_is_value_true (put_comp_val));
273+
ecma_free_value (put_comp_val);
274+
ECMA_TRY_CATCH (str_val,
275+
ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context),
276+
ret_value);
277+
ret_value = ecma_copy_value (str_val);
278+
ECMA_FINALIZE (str_val);
279+
ecma_free_value (put_comp_val);
280+
ecma_deref_ecma_string (empty_str_p);
281+
ecma_deref_object (obj_wrapper_p);
282+
283+
return ret_value;
284+
} /* ema_builtin_json_str_helper */
285+
286+
/**
287+
* Function to create a json formated string from an object
288+
*
289+
* @return ecma value
290+
* Returned value must be freed with ecma_free_value.
291+
*/
292+
ecma_value_t
293+
ecma_builtin_json_string_from_object (const ecma_value_t arg1)
294+
{
295+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
296+
ecma_json_stringify_context_t context;
297+
context.occurence_stack_last_p = NULL;
298+
context.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
299+
context.property_list_p = ecma_new_values_collection ();
300+
context.replacer_function_p = NULL;
301+
context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
302+
303+
ret_value = ema_builtin_json_str_helper (arg1, context);
304+
305+
ecma_deref_ecma_string (context.gap_str_p);
306+
ecma_deref_ecma_string (context.indent_str_p);
307+
ecma_free_values_collection (context.property_list_p, 0);
308+
return ret_value;
309+
} /*ecma_builtin_json_string_from_object*/
310+
311+
#endif /* !CONFIG_DISABLE_JSON_BUILTIN */
312+
224313
/**
225314
* @}
226315
* @}

jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,44 @@ typedef struct struct_ecma_json_occurence_stack_item_t
131131
ecma_object_t *object_p; /**< current object */
132132
} ecma_json_occurence_stack_item_t;
133133

134+
/**
135+
* JSON token type
136+
*/
137+
typedef enum
138+
{
139+
invalid_token, /**< error token */
140+
end_token, /**< end of stream reached */
141+
number_token, /**< JSON number */
142+
string_token, /**< JSON string */
143+
null_token, /**< JSON null primitive value */
144+
true_token, /**< JSON true primitive value */
145+
false_token, /**< JSON false primitive value */
146+
left_brace_token, /**< JSON left brace */
147+
right_brace_token, /**< JSON right brace */
148+
left_square_token, /**< JSON left square bracket */
149+
comma_token, /**< JSON comma */
150+
colon_token /**< JSON colon */
151+
} ecma_json_token_type_t;
152+
153+
/**
154+
* JSON token
155+
*/
156+
typedef struct
157+
{
158+
ecma_json_token_type_t type; /**< type of the current token */
159+
const lit_utf8_byte_t *current_p; /**< current position of the string processed by the parser */
160+
const lit_utf8_byte_t *end_p; /**< end of the string processed by the parser */
161+
162+
/**
163+
* Fields depending on type.
164+
*/
165+
union
166+
{
167+
ecma_string_t *string_p; /**< when type is string_token it contains the string */
168+
ecma_number_t number; /**< when type is number_token, it contains the value of the number */
169+
} u;
170+
} ecma_json_token_t;
171+
134172
/**
135173
* Context for JSON.stringify()
136174
*/
@@ -152,6 +190,26 @@ typedef struct
152190
ecma_object_t *replacer_function_p;
153191
} ecma_json_stringify_context_t;
154192

193+
ecma_value_t ecma_builtin_json_parse_value (ecma_json_token_t *token_p);
194+
void ecma_builtin_json_parse_next_token (ecma_json_token_t *token_p, /**< token argument */
195+
bool parse_string); /**< strings are allowed to parse */
196+
ecma_object_t *ecma_op_create_object_object_noarg (void);
197+
ecma_value_t
198+
ecma_op_object_put (ecma_object_t *object_p, /**< the object */
199+
ecma_string_t *property_name_p, /**< property name */
200+
ecma_value_t value, /**< ecma value */
201+
bool is_throw); /**< flag that controls failure handling */
202+
ecma_value_t
203+
ecma_builtin_json_str (ecma_string_t *key_p, /**< property key*/
204+
ecma_object_t *holder_p, /**< the object*/
205+
ecma_json_stringify_context_t *context_p) ;/**< context*/
206+
ecma_value_t ecma_builtin_json_fill_token_fields_from_string (const lit_utf8_byte_t * str_start_p,
207+
lit_utf8_size_t string_size);
208+
void ecma_deref_object (ecma_object_t *object_p);
209+
bool
210+
ecma_op_is_callable (ecma_value_t value);
211+
ecma_value_t ecma_builtin_json_string_from_object (const ecma_value_t arg1);
212+
ecma_value_t ema_builtin_json_str_helper (const ecma_value_t arg1, ecma_json_stringify_context_t context);
155213
bool ecma_json_has_object_in_stack (ecma_json_occurence_stack_item_t *stack_p, ecma_object_t *object_p);
156214
bool ecma_has_string_value_in_collection (ecma_collection_header_t *collection_p, ecma_value_t string_value);
157215

0 commit comments

Comments
 (0)