Skip to content

Commit 8204979

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 8204979

File tree

7 files changed

+264
-38
lines changed

7 files changed

+264
-38
lines changed

docs/02.API-REFERENCE.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5561,3 +5561,73 @@ 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+
Returns the same result as JSON.parse ecmascript function.
5572+
5573+
**Prototype**
5574+
5575+
```c
5576+
jerry_value_t jerry_json_parse (const jerry_char_t *string_p, jerry_size_t string_size)
5577+
```
5578+
5579+
- `string_p` - a JSON string
5580+
- `string_size` - size of the string
5581+
- return
5582+
- jerry_value_t containing the same as json.parse()
5583+
- jerry_value_t containing error massage
5584+
5585+
**Example**
5586+
5587+
```c
5588+
{
5589+
const char *data = "{\"name\": \"John\", \"age\": 5}";
5590+
jerry_size_t str_length = (jerry_size_t)strlen (data);
5591+
jerry_value_t parsed_json = jerry_json_parse ((jerry_char_t*)data, str_length);
5592+
5593+
// parsed_json now conatins all data stored in data_in_json
5594+
5595+
jerry_release_value (parsed_json);
5596+
}
5597+
```
5598+
5599+
## jerry_stringify
5600+
5601+
**Summary**
5602+
5603+
Returns the same value as JSON.stringify() ecmascript function.
5604+
5605+
**Prototype**
5606+
5607+
```c
5608+
jerry_value_t jerry_json_stringfy (const jerry_value_t object_to_stringify)
5609+
```
5610+
5611+
- `object_to_stringify` - a jerry_value_t object to stringify
5612+
- return
5613+
- jerry_value_t containing the same as json.stringify()
5614+
- jerry_value_t containing error massage
5615+
5616+
**Example**
5617+
5618+
```c
5619+
{
5620+
jerry_value_t obj = jerry_create_object ();
5621+
jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name");
5622+
jerry_value_t value = jerry_create_string ((const jerry_char_t *) "John");
5623+
jerry_set_property (obj, key, value);
5624+
jerry_value_t stringified = jerry_json_stringfy (obj);
5625+
5626+
//stringified now contains a json formated string
5627+
5628+
jerry_release_value (obj);
5629+
jerry_release_value (key);
5630+
jerry_release_value (value);
5631+
jerry_release_value (stringified);
5632+
}
5633+
```

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 or an error massage
3343+
*/
3344+
jerry_value_t
3345+
jerry_json_parse (const jerry_char_t *string_p, /**< json string */
3346+
jerry_size_t string_size) /**< json string size */
3347+
{
3348+
jerry_assert_api_available ();
3349+
3350+
#ifndef CONFIG_DISABLE_JSON_BUILTIN
3351+
ecma_value_t ret_value = ecma_builtin_json_parse_buffer (string_p, string_size);
3352+
3353+
if (ecma_is_value_undefined (ret_value))
3354+
{
3355+
ret_value = jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("JSON string parse error.")));
3356+
}
3357+
3358+
return ret_value;
3359+
#else /* CONFIG_DISABLE_JSON_BUILTIN */
3360+
JERRY_UNUSED (string_p);
3361+
JERRY_UNUSED (string_size);
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 or an error massage
3373+
*/
3374+
jerry_value_t
3375+
jerry_json_stringfy (const jerry_value_t object_to_stringify) /**< a jerry_object_t 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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "ecma-builtin-helpers.h"
1919
#include "lit-char-helpers.h"
2020

21+
#ifndef CONFIG_DISABLE_JSON_BUILTIN
22+
2123
/** \addtogroup ecma ECMA
2224
* @{
2325
*
@@ -221,6 +223,8 @@ ecma_builtin_helper_json_create_non_formatted_json (lit_utf8_byte_t left_bracket
221223
return ecma_make_string_value (result_str_p);
222224
} /* ecma_builtin_helper_json_create_non_formatted_json */
223225

226+
#endif /* !CONFIG_DISABLE_JSON_BUILTIN */
227+
224228
/**
225229
* @}
226230
* @}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ typedef struct
152152
ecma_object_t *replacer_function_p;
153153
} ecma_json_stringify_context_t;
154154

155+
ecma_value_t ecma_builtin_json_parse_buffer (const lit_utf8_byte_t * str_start_p,
156+
lit_utf8_size_t string_size);
157+
ecma_value_t ecma_builtin_json_string_from_object (const ecma_value_t arg1);
155158
bool ecma_json_has_object_in_stack (ecma_json_occurence_stack_item_t *stack_p, ecma_object_t *object_p);
156159
bool ecma_has_string_value_in_collection (ecma_collection_header_t *collection_p, ecma_value_t string_value);
157160

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

Lines changed: 86 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,35 @@ ecma_builtin_json_walk (ecma_object_t *reviver_p, /**< reviver function */
805805
return ret_value;
806806
} /* ecma_builtin_json_walk */
807807

808+
/**
809+
* Function to set a string token from the given arguments, fill its fields and advances the string pointer.
810+
*
811+
* @return ecma_value_t containing an object or an error massage
812+
* Returned value must be freed with ecma_free_value.
813+
*/
814+
ecma_value_t
815+
ecma_builtin_json_parse_buffer (const lit_utf8_byte_t * str_start_p, /**< String to parse */
816+
lit_utf8_size_t string_size) /**< size of the string */
817+
{
818+
ecma_json_token_t token;
819+
token.current_p = str_start_p;
820+
token.end_p = str_start_p + string_size;
821+
822+
ecma_value_t final_result = ecma_builtin_json_parse_value (&token);
823+
824+
if (!ecma_is_value_undefined (final_result))
825+
{
826+
ecma_builtin_json_parse_next_token (&token, false);
827+
828+
if (token.type != end_token)
829+
{
830+
ecma_free_value (final_result);
831+
final_result = ECMA_VALUE_UNDEFINED;
832+
}
833+
}
834+
return final_result;
835+
} /*ecma_builtin_json_parse_buffer*/
836+
808837
/**
809838
* The JSON object's 'parse' routine
810839
*
@@ -830,22 +859,7 @@ ecma_builtin_json_parse (ecma_value_t this_arg, /**< 'this' argument */
830859

831860
ECMA_STRING_TO_UTF8_STRING (string_p, str_start_p, string_size);
832861

833-
ecma_json_token_t token;
834-
token.current_p = str_start_p;
835-
token.end_p = str_start_p + string_size;
836-
837-
ecma_value_t final_result = ecma_builtin_json_parse_value (&token);
838-
839-
if (!ecma_is_value_undefined (final_result))
840-
{
841-
ecma_builtin_json_parse_next_token (&token, false);
842-
843-
if (token.type != end_token)
844-
{
845-
ecma_free_value (final_result);
846-
final_result = ECMA_VALUE_UNDEFINED;
847-
}
848-
}
862+
ecma_value_t final_result = ecma_builtin_json_parse_buffer (str_start_p, string_size);
849863

850864
if (ecma_is_value_undefined (final_result))
851865
{
@@ -892,6 +906,61 @@ ecma_builtin_json_object (ecma_object_t *obj_p, ecma_json_stringify_context_t *c
892906
static ecma_value_t
893907
ecma_builtin_json_array (ecma_object_t *obj_p, ecma_json_stringify_context_t *context_p);
894908

909+
/**
910+
* Helper functions to stringify an object in JSON format representing an ecma_value.
911+
*
912+
* @return ecma_value_t string created from an abject formating by a given context
913+
* Returned value must be freed with ecma_free_value.
914+
*
915+
*/
916+
static ecma_value_t ecma_builtin_json_str_helper (const ecma_value_t arg1, /**< object argument */
917+
ecma_json_stringify_context_t context) /**< context argument */
918+
{
919+
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
920+
ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg ();
921+
ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
922+
ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p,
923+
empty_str_p,
924+
arg1,
925+
false);
926+
JERRY_ASSERT (ecma_is_value_true (put_comp_val));
927+
ecma_free_value (put_comp_val);
928+
ECMA_TRY_CATCH (str_val,
929+
ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context),
930+
ret_value);
931+
ret_value = ecma_copy_value (str_val);
932+
ECMA_FINALIZE (str_val);
933+
ecma_free_value (put_comp_val);
934+
ecma_deref_ecma_string (empty_str_p);
935+
ecma_deref_object (obj_wrapper_p);
936+
937+
return ret_value;
938+
} /* ecma_builtin_json_str_helper */
939+
940+
/**
941+
* Function to create a json formated string from an object
942+
*
943+
* @return ecma_value_t containing a json string
944+
* Returned value must be freed with ecma_free_value.
945+
*/
946+
ecma_value_t
947+
ecma_builtin_json_string_from_object (const ecma_value_t arg1) /**< object argument */
948+
{
949+
ecma_json_stringify_context_t context;
950+
context.occurence_stack_last_p = NULL;
951+
context.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
952+
context.property_list_p = ecma_new_values_collection ();
953+
context.replacer_function_p = NULL;
954+
context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
955+
956+
ecma_value_t ret_value = ecma_builtin_json_str_helper (arg1, context);
957+
958+
ecma_deref_ecma_string (context.gap_str_p);
959+
ecma_deref_ecma_string (context.indent_str_p);
960+
ecma_free_values_collection (context.property_list_p, 0);
961+
return ret_value;
962+
} /*ecma_builtin_json_string_from_object*/
963+
895964
/**
896965
* The JSON object's 'stringify' routine
897966
*
@@ -1119,28 +1188,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */
11191188
if (ecma_is_value_empty (ret_value))
11201189
{
11211190
/* 9. */
1122-
ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg ();
1123-
ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
1124-
1125-
/* 10. */
1126-
ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p,
1127-
empty_str_p,
1128-
arg1,
1129-
false);
1130-
1131-
JERRY_ASSERT (ecma_is_value_true (put_comp_val));
1132-
ecma_free_value (put_comp_val);
1133-
1134-
/* 11. */
1135-
ECMA_TRY_CATCH (str_val,
1136-
ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context),
1137-
ret_value);
1138-
1139-
ret_value = ecma_copy_value (str_val);
1140-
1141-
ECMA_FINALIZE (str_val);
1142-
1143-
ecma_deref_object (obj_wrapper_p);
1191+
ret_value = ecma_builtin_json_str_helper (arg1, context);
11441192
}
11451193

11461194
ecma_deref_ecma_string (context.gap_str_p);

jerry-core/include/jerryscript-core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,8 @@ jerry_length_t jerry_get_typedarray_length (jerry_value_t value);
522522
jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value,
523523
jerry_length_t *byte_offset,
524524
jerry_length_t *byte_length);
525+
jerry_value_t jerry_json_parse (const jerry_char_t *string_p, jerry_size_t string_size);
526+
jerry_value_t jerry_json_stringfy (const jerry_value_t object_to_stringify);
525527

526528
/**
527529
* @}

tests/unit-core/test-api.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,48 @@ main (void)
11301130

11311131
jerry_release_value (args[1]);
11321132

1133+
{
1134+
/*json parser check*/
1135+
char data_check[]="John";
1136+
jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name");
1137+
const char *data = "{\"name\": \"John\", \"age\": 5}";
1138+
jerry_size_t str_length = (jerry_size_t) strlen (data);
1139+
jerry_value_t parsed_json = jerry_json_parse ((jerry_char_t *) data, str_length);
1140+
jerry_value_t has_prop_js = jerry_has_property (parsed_json, key);
1141+
TEST_ASSERT (jerry_get_boolean_value (has_prop_js));
1142+
jerry_release_value (has_prop_js);
1143+
jerry_value_t parsed_data = jerry_get_property (parsed_json, key);
1144+
TEST_ASSERT (jerry_value_is_string (parsed_data)== true);
1145+
jerry_size_t buff_size = (jerry_size_t) jerry_get_string_length (parsed_data);
1146+
char buff[jerry_get_string_length (parsed_data)];
1147+
jerry_char_t *buff_p = (jerry_char_t *) buff;
1148+
jerry_string_to_char_buffer (parsed_data, buff_p, buff_size);
1149+
buff[buff_size] = '\0';
1150+
TEST_ASSERT (strcmp ((const char *) data_check, (const char *) buff) == false);
1151+
jerry_release_value (parsed_json);
1152+
jerry_release_value (key);
1153+
jerry_release_value (parsed_data);
1154+
}
1155+
1156+
/*json stringify test*/
1157+
{
1158+
jerry_value_t obj = jerry_create_object ();
1159+
char check_value[] = "{\"name\":\"John\"}";
1160+
jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name");
1161+
jerry_value_t value = jerry_create_string ((const jerry_char_t *) "John");
1162+
jerry_set_property (obj, key, value);
1163+
jerry_value_t stringified = jerry_json_stringfy (obj);
1164+
TEST_ASSERT (jerry_value_is_string (stringified));
1165+
char buff[jerry_get_string_length (stringified)];
1166+
jerry_string_to_char_buffer (stringified, (jerry_char_t *) buff,
1167+
(jerry_size_t) jerry_get_string_length (stringified));
1168+
buff[jerry_get_string_length (stringified)] = '\0';
1169+
TEST_ASSERT (strcmp ((const char *) check_value, (const char *) buff) == 0);
1170+
jerry_release_value (stringified);
1171+
jerry_release_value (obj);
1172+
jerry_release_value (key);
1173+
jerry_release_value (value);
1174+
}
11331175
jerry_cleanup ();
11341176

11351177
return 0;

0 commit comments

Comments
 (0)