mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Notable changes:
- Updated and the port API interface, new functions have been added
and some have been changed. The port library is now cleaned up to
not have any dependency on jerry-core, as it should be. The port library
is now strictly a collection of functions that implement
embedding/platform specific behavior.
- The default port implementation has been split for windows and unix.
Implemented port functions have been categorized and reorganized,
and marked with attribute((weak)) for better reusability.
- External context allocation has been moved to the port API instead
of a core API callback. The iterface has also been extended with a
function to free the allocated context. When external context is
enabled, jerry_init now automatically calls the port implementation
to allocate the context and jerry_cleanup automatically calls the port
to free the context.
- jerry_port_log has been changed to no longer require formatting to
be implemented by the port. The reason beind this is that it was vague what
format specifiers were used by the engine, and in what manner. The port
function now takes a zero-terminated string, and should only implement
how the string should be logged.
- Logging and log message formatting is now handled by the core jerry library
where it can be implemented as necessary. Logging can be done through a new
core API function, which uses the port to output the final log message.
- Log level has been moved into jerry-core, and an API function has
been added to set the log level. It should be the library that
filters log messages based on the requested log level, instead of
logging everything and requiring the user to do so.
- Module resolving logic has been moved into jerry-core. There's no
reason to have it in the port library and requiring embedders to
duplicate the code. It also added an unnecessary dependency on
jerry-core to the port. Platform specific behavior is still used through
the port API, like resolving module specifiers, and reading source file
contents. If necessary, the resolving logic can still be overridden as
previously.
- The jerry-ext library has also been cleaned up, and many utility
functions have been added that previously were implemented in
jerry-main. This allows easier reusability for some common operations,
like printing unhandled exceptions or providing a repl console.
- Debugger interaction with logged/printed messages has been fixed, so
that it's no longer the port implementations responsibility to send
the output to the debugger, as the port should have no notion of what a
debugger is. The printing and logging functions will now pass the
result message to the debugger, if connected.
- Cleaned up TZA handling in the date port implementation, and simplified
the API function prototype.
- Moved property access helper functions that use ASCII strings as
keys from jerry-ext to the core API.
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
7287 lines
217 KiB
C
7287 lines
217 KiB
C
/* Copyright JS Foundation and other contributors, http://js.foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "jerryscript.h"
|
|
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
|
|
#include "jerryscript-debugger-transport.h"
|
|
|
|
#include "ecma-alloc.h"
|
|
#include "ecma-array-object.h"
|
|
#include "ecma-arraybuffer-object.h"
|
|
#include "ecma-bigint.h"
|
|
#include "ecma-builtin-helpers.h"
|
|
#include "ecma-builtins.h"
|
|
#include "ecma-comparison.h"
|
|
#include "ecma-container-object.h"
|
|
#include "ecma-dataview-object.h"
|
|
#include "ecma-errors.h"
|
|
#include "ecma-eval.h"
|
|
#include "ecma-exceptions.h"
|
|
#include "ecma-extended-info.h"
|
|
#include "ecma-function-object.h"
|
|
#include "ecma-gc.h"
|
|
#include "ecma-globals.h"
|
|
#include "ecma-helpers.h"
|
|
#include "ecma-init-finalize.h"
|
|
#include "ecma-iterator-object.h"
|
|
#include "ecma-lex-env.h"
|
|
#include "ecma-line-info.h"
|
|
#include "ecma-literal-storage.h"
|
|
#include "ecma-objects-general.h"
|
|
#include "ecma-objects.h"
|
|
#include "ecma-promise-object.h"
|
|
#include "ecma-proxy-object.h"
|
|
#include "ecma-regexp-object.h"
|
|
#include "ecma-shared-arraybuffer-object.h"
|
|
#include "ecma-symbol-object.h"
|
|
#include "ecma-typedarray-object.h"
|
|
|
|
#include "debugger.h"
|
|
#include "jcontext.h"
|
|
#include "jmem.h"
|
|
#include "jrt.h"
|
|
#include "js-parser.h"
|
|
#include "lit-char-helpers.h"
|
|
#include "opcodes.h"
|
|
#include "re-compiler.h"
|
|
|
|
JERRY_STATIC_ASSERT (sizeof (jerry_value_t) == sizeof (ecma_value_t),
|
|
size_of_jerry_value_t_must_be_equal_to_size_of_ecma_value_t);
|
|
|
|
#if JERRY_BUILTIN_REGEXP
|
|
JERRY_STATIC_ASSERT ((int) RE_FLAG_GLOBAL == (int) JERRY_REGEXP_FLAG_GLOBAL
|
|
&& (int) RE_FLAG_MULTILINE == (int) JERRY_REGEXP_FLAG_MULTILINE
|
|
&& (int) RE_FLAG_IGNORE_CASE == (int) JERRY_REGEXP_FLAG_IGNORE_CASE
|
|
&& (int) RE_FLAG_STICKY == (int) JERRY_REGEXP_FLAG_STICKY
|
|
&& (int) RE_FLAG_UNICODE == (int) JERRY_REGEXP_FLAG_UNICODE
|
|
&& (int) RE_FLAG_DOTALL == (int) JERRY_REGEXP_FLAG_DOTALL,
|
|
re_flags_t_must_be_equal_to_jerry_regexp_flags_t);
|
|
#endif /* JERRY_BUILTIN_REGEXP */
|
|
|
|
#if JERRY_ESNEXT
|
|
/* The internal ECMA_PROMISE_STATE_* values are "one byte away" from the API values */
|
|
JERRY_STATIC_ASSERT ((int) ECMA_PROMISE_IS_PENDING == (int) JERRY_PROMISE_STATE_PENDING
|
|
&& (int) ECMA_PROMISE_IS_FULFILLED == (int) JERRY_PROMISE_STATE_FULFILLED,
|
|
promise_internal_state_matches_external);
|
|
#endif /* JERRY_ESNEXT */
|
|
|
|
/**
|
|
* Offset between internal and external arithmetic operator types
|
|
*/
|
|
#define ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET (JERRY_BIN_OP_SUB - NUMBER_ARITHMETIC_SUBTRACTION)
|
|
|
|
JERRY_STATIC_ASSERT (((NUMBER_ARITHMETIC_SUBTRACTION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_SUB)
|
|
&& ((NUMBER_ARITHMETIC_MULTIPLICATION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET)
|
|
== JERRY_BIN_OP_MUL)
|
|
&& ((NUMBER_ARITHMETIC_DIVISION + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_DIV)
|
|
&& ((NUMBER_ARITHMETIC_REMAINDER + ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET) == JERRY_BIN_OP_REM),
|
|
number_arithmetics_operation_type_matches_external);
|
|
|
|
#if !JERRY_PARSER && !JERRY_SNAPSHOT_EXEC
|
|
#error "JERRY_SNAPSHOT_EXEC must be enabled if JERRY_PARSER is disabled!"
|
|
#endif /* !JERRY_PARSER && !JERRY_SNAPSHOT_EXEC */
|
|
|
|
/** \addtogroup jerry Jerry engine interface
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Assert that it is correct to call API in current state.
|
|
*
|
|
* Note:
|
|
* By convention, there are some states when API could not be invoked.
|
|
*
|
|
* The API can be and only be invoked when the ECMA_STATUS_API_ENABLED
|
|
* flag is set.
|
|
*
|
|
* This procedure checks whether the API is available, and terminates
|
|
* the engine if it is unavailable. Otherwise it is a no-op.
|
|
*
|
|
* Note:
|
|
* The API could not be invoked in the following cases:
|
|
* - before jerry_init and after jerry_cleanup
|
|
* - between enter to and return from a native free callback
|
|
*/
|
|
static inline void JERRY_ATTR_ALWAYS_INLINE
|
|
jerry_assert_api_enabled (void)
|
|
{
|
|
JERRY_ASSERT (JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_ENABLED);
|
|
} /* jerry_assert_api_enabled */
|
|
|
|
/**
|
|
* Turn on API availability
|
|
*/
|
|
static inline void JERRY_ATTR_ALWAYS_INLINE
|
|
jerry_api_enable (void)
|
|
{
|
|
#ifndef JERRY_NDEBUG
|
|
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_API_ENABLED;
|
|
#endif /* JERRY_NDEBUG */
|
|
} /* jerry_make_api_available */
|
|
|
|
/**
|
|
* Turn off API availability
|
|
*/
|
|
static inline void JERRY_ATTR_ALWAYS_INLINE
|
|
jerry_api_disable (void)
|
|
{
|
|
#ifndef JERRY_NDEBUG
|
|
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_API_ENABLED;
|
|
#endif /* JERRY_NDEBUG */
|
|
} /* jerry_make_api_unavailable */
|
|
|
|
/**
|
|
* Create an API compatible return value.
|
|
*
|
|
* @return return value for Jerry API functions
|
|
*/
|
|
static jerry_value_t
|
|
jerry_return (const jerry_value_t value) /**< return value */
|
|
{
|
|
if (ECMA_IS_VALUE_ERROR (value))
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
return value;
|
|
} /* jerry_return */
|
|
|
|
/**
|
|
* Jerry engine initialization
|
|
*/
|
|
void
|
|
jerry_init (jerry_init_flag_t flags) /**< combination of Jerry flags */
|
|
{
|
|
#if JERRY_EXTERNAL_CONTEXT
|
|
size_t total_size = jerry_port_context_alloc (sizeof (jerry_context_t));
|
|
JERRY_UNUSED (total_size);
|
|
#endif /* JERRY_EXTERNAL_CONTEXT */
|
|
|
|
jerry_context_t *context_p = &JERRY_CONTEXT_STRUCT;
|
|
memset (context_p, 0, sizeof (jerry_context_t));
|
|
|
|
#if JERRY_EXTERNAL_CONTEXT && !JERRY_SYSTEM_ALLOCATOR
|
|
uint32_t heap_start_offset = JERRY_ALIGNUP (sizeof (jerry_context_t), JMEM_ALIGNMENT);
|
|
uint8_t *heap_p = ((uint8_t *) context_p) + heap_start_offset;
|
|
uint32_t heap_size = JERRY_ALIGNDOWN (total_size - heap_start_offset, JMEM_ALIGNMENT);
|
|
|
|
JERRY_ASSERT (heap_p + heap_size <= ((uint8_t *) context_p) + total_size);
|
|
|
|
context_p->heap_p = (jmem_heap_t *) heap_p;
|
|
context_p->heap_size = heap_size;
|
|
#endif /* JERRY_EXTERNAL_CONTEXT && !JERRY_SYSTEM_ALLOCATOR */
|
|
|
|
JERRY_CONTEXT (jerry_init_flags) = flags;
|
|
|
|
jerry_api_enable ();
|
|
|
|
jmem_init ();
|
|
ecma_init ();
|
|
} /* jerry_init */
|
|
|
|
/**
|
|
* Terminate Jerry engine
|
|
*/
|
|
void
|
|
jerry_cleanup (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_DEBUGGER
|
|
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
|
|
{
|
|
jerry_debugger_send_type (JERRY_DEBUGGER_CLOSE_CONNECTION);
|
|
|
|
jerry_debugger_transport_close ();
|
|
}
|
|
#endif /* JERRY_DEBUGGER */
|
|
|
|
for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p); this_p != NULL; this_p = this_p->next_p)
|
|
{
|
|
if (this_p->manager_p->deinit_cb)
|
|
{
|
|
void *data = (this_p->manager_p->bytes_needed > 0) ? JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p) : NULL;
|
|
this_p->manager_p->deinit_cb (data);
|
|
}
|
|
}
|
|
|
|
#if JERRY_ESNEXT
|
|
ecma_free_all_enqueued_jobs ();
|
|
#endif /* JERRY_ESNEXT */
|
|
ecma_finalize ();
|
|
jerry_api_disable ();
|
|
|
|
for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p), *next_p = NULL; this_p != NULL;
|
|
this_p = next_p)
|
|
{
|
|
next_p = this_p->next_p;
|
|
|
|
if (this_p->manager_p->finalize_cb)
|
|
{
|
|
void *data = (this_p->manager_p->bytes_needed > 0) ? JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p) : NULL;
|
|
this_p->manager_p->finalize_cb (data);
|
|
}
|
|
|
|
jmem_heap_free_block (this_p, sizeof (jerry_context_data_header_t) + this_p->manager_p->bytes_needed);
|
|
}
|
|
|
|
jmem_finalize ();
|
|
#if JERRY_EXTERNAL_CONTEXT
|
|
jerry_port_context_free ();
|
|
#endif /* JERRY_EXTERNAL_CONTEXT */
|
|
} /* jerry_cleanup */
|
|
|
|
/**
|
|
* Retrieve a context data item, or create a new one.
|
|
*
|
|
* @param manager_p pointer to the manager whose context data item should be returned.
|
|
*
|
|
* @return a pointer to the user-provided context-specific data item for the given manager, creating such a pointer if
|
|
* none was found.
|
|
*/
|
|
void *
|
|
jerry_context_data (const jerry_context_data_manager_t *manager_p)
|
|
{
|
|
void *ret = NULL;
|
|
jerry_context_data_header_t *item_p;
|
|
|
|
for (item_p = JERRY_CONTEXT (context_data_p); item_p != NULL; item_p = item_p->next_p)
|
|
{
|
|
if (item_p->manager_p == manager_p)
|
|
{
|
|
return (manager_p->bytes_needed > 0) ? JERRY_CONTEXT_DATA_HEADER_USER_DATA (item_p) : NULL;
|
|
}
|
|
}
|
|
|
|
item_p = jmem_heap_alloc_block (sizeof (jerry_context_data_header_t) + manager_p->bytes_needed);
|
|
item_p->manager_p = manager_p;
|
|
item_p->next_p = JERRY_CONTEXT (context_data_p);
|
|
JERRY_CONTEXT (context_data_p) = item_p;
|
|
|
|
if (manager_p->bytes_needed > 0)
|
|
{
|
|
ret = JERRY_CONTEXT_DATA_HEADER_USER_DATA (item_p);
|
|
memset (ret, 0, manager_p->bytes_needed);
|
|
}
|
|
|
|
if (manager_p->init_cb)
|
|
{
|
|
manager_p->init_cb (ret);
|
|
}
|
|
|
|
return ret;
|
|
} /* jerry_context_data */
|
|
|
|
/**
|
|
* Register external magic string array
|
|
*/
|
|
void
|
|
jerry_register_magic_strings (const jerry_char_t *const *ext_strings_p, /**< character arrays, representing
|
|
* external magic strings' contents */
|
|
uint32_t count, /**< number of the strings */
|
|
const jerry_length_t *str_lengths_p) /**< lengths of all strings */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
lit_magic_strings_ex_set ((const lit_utf8_byte_t *const *) ext_strings_p,
|
|
count,
|
|
(const lit_utf8_size_t *) str_lengths_p);
|
|
} /* jerry_register_magic_strings */
|
|
|
|
/**
|
|
* Run garbage collection
|
|
*/
|
|
void
|
|
jerry_heap_gc (jerry_gc_mode_t mode) /**< operational mode */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (mode == JERRY_GC_PRESSURE_LOW)
|
|
{
|
|
/* Call GC directly, because 'ecma_free_unused_memory' might decide it's not yet worth it. */
|
|
ecma_gc_run ();
|
|
return;
|
|
}
|
|
|
|
ecma_free_unused_memory (JMEM_PRESSURE_HIGH);
|
|
} /* jerry_heap_gc */
|
|
|
|
/**
|
|
* Get heap memory stats.
|
|
*
|
|
* @return true - get the heap stats successful
|
|
* false - otherwise. Usually it is because the MEM_STATS feature is not enabled.
|
|
*/
|
|
bool
|
|
jerry_heap_stats (jerry_heap_stats_t *out_stats_p) /**< [out] heap memory stats */
|
|
{
|
|
#if JERRY_MEM_STATS
|
|
if (out_stats_p == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
jmem_heap_stats_t jmem_heap_stats;
|
|
memset (&jmem_heap_stats, 0, sizeof (jmem_heap_stats));
|
|
jmem_heap_get_stats (&jmem_heap_stats);
|
|
|
|
*out_stats_p = (jerry_heap_stats_t){ .version = 1,
|
|
.size = jmem_heap_stats.size,
|
|
.allocated_bytes = jmem_heap_stats.allocated_bytes,
|
|
.peak_allocated_bytes = jmem_heap_stats.peak_allocated_bytes };
|
|
|
|
return true;
|
|
#else /* !JERRY_MEM_STATS */
|
|
JERRY_UNUSED (out_stats_p);
|
|
return false;
|
|
#endif /* JERRY_MEM_STATS */
|
|
} /* jerry_heap_stats */
|
|
|
|
#if JERRY_PARSER
|
|
/**
|
|
* Common code for parsing a script, module, or function.
|
|
*
|
|
* @return function object value - if script was parsed successfully,
|
|
* thrown error - otherwise
|
|
*/
|
|
static jerry_value_t
|
|
jerry_parse_common (void *source_p, /**< script source */
|
|
const jerry_parse_options_t *options_p, /**< parsing options, can be NULL if not used */
|
|
uint32_t parse_opts) /**< internal parsing options */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (options_p != NULL)
|
|
{
|
|
const uint32_t allowed_options =
|
|
(JERRY_PARSE_STRICT_MODE | JERRY_PARSE_MODULE | JERRY_PARSE_HAS_ARGUMENT_LIST | JERRY_PARSE_HAS_SOURCE_NAME
|
|
| JERRY_PARSE_HAS_START | JERRY_PARSE_HAS_USER_VALUE);
|
|
uint32_t options = options_p->options;
|
|
|
|
if ((options & ~allowed_options) != 0
|
|
|| ((options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST)
|
|
&& ((options_p->options & JERRY_PARSE_MODULE) || !ecma_is_value_string (options_p->argument_list)))
|
|
|| ((options_p->options & JERRY_PARSE_HAS_SOURCE_NAME) && !ecma_is_value_string (options_p->source_name)))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
}
|
|
|
|
#if JERRY_DEBUGGER
|
|
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && options_p != NULL
|
|
&& (options_p->options & JERRY_PARSE_HAS_SOURCE_NAME) && ecma_is_value_string (options_p->source_name))
|
|
{
|
|
ECMA_STRING_TO_UTF8_STRING (ecma_get_string_from_value (options_p->source_name),
|
|
source_name_start_p,
|
|
source_name_size);
|
|
jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE_NAME,
|
|
JERRY_DEBUGGER_NO_SUBTYPE,
|
|
source_name_start_p,
|
|
source_name_size);
|
|
ECMA_FINALIZE_UTF8_STRING (source_name_start_p, source_name_size);
|
|
}
|
|
#endif /* JERRY_DEBUGGER */
|
|
|
|
if (options_p != NULL)
|
|
{
|
|
parse_opts |= options_p->options & (JERRY_PARSE_STRICT_MODE | JERRY_PARSE_MODULE);
|
|
}
|
|
|
|
if ((parse_opts & JERRY_PARSE_MODULE) != 0)
|
|
{
|
|
#if JERRY_MODULE_SYSTEM
|
|
JERRY_CONTEXT (module_current_p) = ecma_module_create ();
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
}
|
|
|
|
ecma_compiled_code_t *bytecode_data_p;
|
|
bytecode_data_p = parser_parse_script (source_p, parse_opts, options_p);
|
|
|
|
if (JERRY_UNLIKELY (bytecode_data_p == NULL))
|
|
{
|
|
#if JERRY_MODULE_SYSTEM
|
|
if ((parse_opts & JERRY_PARSE_MODULE) != 0)
|
|
{
|
|
ecma_module_cleanup_context ();
|
|
}
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
if (JERRY_UNLIKELY (parse_opts & JERRY_PARSE_MODULE))
|
|
{
|
|
ecma_module_t *module_p = JERRY_CONTEXT (module_current_p);
|
|
module_p->u.compiled_code_p = bytecode_data_p;
|
|
|
|
JERRY_CONTEXT (module_current_p) = NULL;
|
|
|
|
return ecma_make_object_value ((ecma_object_t *) module_p);
|
|
}
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
|
|
if (JERRY_UNLIKELY (options_p != NULL && (options_p->options & JERRY_PARSE_HAS_ARGUMENT_LIST)))
|
|
{
|
|
ecma_object_t *global_object_p = ecma_builtin_get_global ();
|
|
|
|
#if JERRY_BUILTIN_REALMS
|
|
JERRY_ASSERT (global_object_p == (ecma_object_t *) ecma_op_function_get_realm (bytecode_data_p));
|
|
#endif /* JERRY_BUILTIN_REALMS */
|
|
|
|
ecma_object_t *lex_env_p = ecma_get_global_environment (global_object_p);
|
|
ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_data_p);
|
|
ecma_bytecode_deref (bytecode_data_p);
|
|
|
|
return ecma_make_object_value (func_obj_p);
|
|
}
|
|
|
|
ecma_object_t *object_p = ecma_create_object (NULL, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS);
|
|
|
|
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
|
|
ext_object_p->u.cls.type = ECMA_OBJECT_CLASS_SCRIPT;
|
|
ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.cls.u3.value, bytecode_data_p);
|
|
|
|
return ecma_make_object_value (object_p);
|
|
} /* jerry_parse_common */
|
|
|
|
#endif /* JERRY_PARSER */
|
|
|
|
/**
|
|
* Parse a script, module, or function and create a compiled code using a character string
|
|
*
|
|
* @return function object value - if script was parsed successfully,
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_parse (const jerry_char_t *source_p, /**< script source */
|
|
size_t source_size, /**< script source size */
|
|
const jerry_parse_options_t *options_p) /**< parsing options, can be NULL if not used */
|
|
{
|
|
#if JERRY_PARSER
|
|
parser_source_char_t source_char;
|
|
source_char.source_p = source_p;
|
|
source_char.source_size = source_size;
|
|
|
|
return jerry_parse_common ((void *) &source_char, options_p, JERRY_PARSE_NO_OPTS);
|
|
#else /* !JERRY_PARSER */
|
|
JERRY_UNUSED (source_p);
|
|
JERRY_UNUSED (source_size);
|
|
JERRY_UNUSED (options_p);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_PARSER_NOT_SUPPORTED));
|
|
#endif /* JERRY_PARSER */
|
|
} /* jerry_parse */
|
|
|
|
/**
|
|
* Parse a script, module, or function and create a compiled code using a string value
|
|
*
|
|
* @return function object value - if script was parsed successfully,
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_parse_value (const jerry_value_t source, /**< script source */
|
|
const jerry_parse_options_t *options_p) /**< parsing options, can be NULL if not used */
|
|
{
|
|
#if JERRY_PARSER
|
|
if (!ecma_is_value_string (source))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
return jerry_parse_common ((void *) &source, options_p, ECMA_PARSE_HAS_SOURCE_VALUE);
|
|
#else /* !JERRY_PARSER */
|
|
JERRY_UNUSED (source);
|
|
JERRY_UNUSED (options_p);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_PARSER_NOT_SUPPORTED));
|
|
#endif /* JERRY_PARSER */
|
|
} /* jerry_parse_value */
|
|
|
|
/**
|
|
* Run a Script or Module created by jerry_parse.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return result of bytecode - if run was successful
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_run (const jerry_value_t script) /**< script or module to run */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (script))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_object_t *object_p = ecma_get_object_from_value (script);
|
|
|
|
if (!ecma_object_class_is (object_p, ECMA_OBJECT_CLASS_SCRIPT))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
|
|
|
|
const ecma_compiled_code_t *bytecode_data_p;
|
|
bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_object_p->u.cls.u3.value);
|
|
|
|
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_SCRIPT);
|
|
|
|
return jerry_return (vm_run_global (bytecode_data_p, object_p));
|
|
} /* jerry_run */
|
|
|
|
/**
|
|
* Perform eval
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return result of eval, may be error value.
|
|
*/
|
|
jerry_value_t
|
|
jerry_eval (const jerry_char_t *source_p, /**< source code */
|
|
size_t source_size, /**< length of source code */
|
|
uint32_t flags) /**< jerry_parse_opts_t flags */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
uint32_t allowed_parse_options = JERRY_PARSE_STRICT_MODE;
|
|
|
|
if ((flags & ~allowed_parse_options) != 0)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
parser_source_char_t source_char;
|
|
source_char.source_p = source_p;
|
|
source_char.source_size = source_size;
|
|
|
|
return jerry_return (ecma_op_eval_chars_buffer ((void *) &source_char, flags));
|
|
} /* jerry_eval */
|
|
|
|
/**
|
|
* Link modules to their dependencies. The dependencies are resolved by a user callback.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return true - if linking is successful, error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_module_link (const jerry_value_t module, /**< root module */
|
|
jerry_module_resolve_cb_t callback, /**< resolve module callback, uses
|
|
* jerry_module_resolve when NULL is passed */
|
|
void *user_p) /**< pointer passed to the resolve callback */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
if (callback == NULL)
|
|
{
|
|
callback = jerry_module_resolve;
|
|
}
|
|
|
|
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
|
|
|
|
if (module_p == NULL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
|
|
}
|
|
|
|
return jerry_return (ecma_module_link (module_p, callback, user_p));
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (module);
|
|
JERRY_UNUSED (callback);
|
|
JERRY_UNUSED (user_p);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_link */
|
|
|
|
/**
|
|
* Evaluate a module and its dependencies. The module must be in linked state.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return result of module bytecode execution - if evaluation was successful
|
|
* error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_module_evaluate (const jerry_value_t module) /**< root module */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
|
|
|
|
if (module_p == NULL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
|
|
}
|
|
|
|
if (module_p->header.u.cls.u1.module_state != JERRY_MODULE_STATE_LINKED)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_MUST_BE_IN_LINKED_STATE));
|
|
}
|
|
|
|
return jerry_return (ecma_module_evaluate (module_p));
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (module);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_evaluate */
|
|
|
|
/**
|
|
* Returns the current status of a module
|
|
*
|
|
* @return current status - if module is a module,
|
|
* JERRY_MODULE_STATE_INVALID - otherwise
|
|
*/
|
|
jerry_module_state_t
|
|
jerry_module_state (const jerry_value_t module) /**< module object */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
|
|
|
|
if (module_p == NULL)
|
|
{
|
|
return JERRY_MODULE_STATE_INVALID;
|
|
}
|
|
|
|
return (jerry_module_state_t) module_p->header.u.cls.u1.module_state;
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (module);
|
|
|
|
return JERRY_MODULE_STATE_INVALID;
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_state */
|
|
|
|
/**
|
|
* Sets a callback which is called after a module state is changed to linked, evaluated, or error.
|
|
*/
|
|
void
|
|
jerry_module_on_state_changed (jerry_module_state_changed_cb_t callback, /**< callback */
|
|
void *user_p) /**< pointer passed to the callback */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
JERRY_CONTEXT (module_state_changed_callback_p) = callback;
|
|
JERRY_CONTEXT (module_state_changed_callback_user_p) = user_p;
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (callback);
|
|
JERRY_UNUSED (user_p);
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_on_state_changed */
|
|
|
|
/**
|
|
* Sets a callback which is called when an import.meta expression of a module is evaluated the first time.
|
|
*/
|
|
void
|
|
jerry_module_on_import_meta (jerry_module_import_meta_cb_t callback, /**< callback */
|
|
void *user_p) /**< pointer passed to the callback */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
JERRY_CONTEXT (module_import_meta_callback_p) = callback;
|
|
JERRY_CONTEXT (module_import_meta_callback_user_p) = user_p;
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (callback);
|
|
JERRY_UNUSED (user_p);
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_on_import_meta */
|
|
|
|
/**
|
|
* Returns the number of import/export requests of a module
|
|
*
|
|
* @return number of import/export requests of a module
|
|
*/
|
|
size_t
|
|
jerry_module_request_count (const jerry_value_t module) /**< module */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
|
|
|
|
if (module_p == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t number_of_requests = 0;
|
|
|
|
ecma_module_node_t *node_p = module_p->imports_p;
|
|
|
|
while (node_p != NULL)
|
|
{
|
|
number_of_requests++;
|
|
node_p = node_p->next_p;
|
|
}
|
|
|
|
return number_of_requests;
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (module);
|
|
|
|
return 0;
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_request_count */
|
|
|
|
/**
|
|
* Returns the module request specified by the request_index argument
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return string - if the request has not been resolved yet,
|
|
* module object - if the request has been resolved successfully,
|
|
* error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_module_request (const jerry_value_t module, /**< module */
|
|
size_t request_index) /**< request index */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
|
|
|
|
if (module_p == NULL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
|
|
}
|
|
|
|
ecma_module_node_t *node_p = module_p->imports_p;
|
|
|
|
while (node_p != NULL)
|
|
{
|
|
if (request_index == 0)
|
|
{
|
|
return ecma_copy_value (node_p->u.path_or_module);
|
|
}
|
|
|
|
--request_index;
|
|
node_p = node_p->next_p;
|
|
}
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_RANGE, ecma_get_error_msg (ECMA_ERR_REQUEST_IS_NOT_AVAILABLE));
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (module);
|
|
JERRY_UNUSED (request_index);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_RANGE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_request */
|
|
|
|
/**
|
|
* Returns the namespace object of a module
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return object - if namespace object is available,
|
|
* error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_module_namespace (const jerry_value_t module) /**< module */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
ecma_module_t *module_p = ecma_module_get_resolved_module (module);
|
|
|
|
if (module_p == NULL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
|
|
}
|
|
|
|
if (module_p->header.u.cls.u1.module_state < JERRY_MODULE_STATE_LINKED
|
|
|| module_p->header.u.cls.u1.module_state > JERRY_MODULE_STATE_EVALUATED)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_RANGE, ecma_get_error_msg (ECMA_ERR_NAMESPACE_OBJECT_IS_NOT_AVAILABLE));
|
|
}
|
|
|
|
JERRY_ASSERT (module_p->namespace_object_p != NULL);
|
|
|
|
ecma_ref_object (module_p->namespace_object_p);
|
|
return ecma_make_object_value (module_p->namespace_object_p);
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (module);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_namespace */
|
|
|
|
/**
|
|
* Sets the callback which is called when dynamic imports are resolved
|
|
*/
|
|
void
|
|
jerry_module_on_import (jerry_module_import_cb_t callback_p, /**< callback which handles
|
|
* dynamic import calls */
|
|
void *user_p) /**< user pointer passed to the callback */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
JERRY_CONTEXT (module_import_callback_p) = callback_p;
|
|
JERRY_CONTEXT (module_import_callback_user_p) = user_p;
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (callback_p);
|
|
JERRY_UNUSED (user_p);
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_module_on_import */
|
|
|
|
/**
|
|
* Creates a native module with a list of exports. The initial state of the module is linked.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return native module - if the module is successfully created,
|
|
* error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_native_module (jerry_native_module_evaluate_cb_t callback, /**< evaluation callback for
|
|
* native modules */
|
|
const jerry_value_t *const exports_p, /**< list of the exported bindings of the module,
|
|
* must be valid string identifiers */
|
|
size_t export_count) /**< number of exports in the exports_p list */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
ecma_object_t *global_object_p = ecma_builtin_get_global ();
|
|
ecma_object_t *scope_p = ecma_create_decl_lex_env (ecma_get_global_environment (global_object_p));
|
|
ecma_module_names_t *local_exports_p = NULL;
|
|
|
|
for (size_t i = 0; i < export_count; i++)
|
|
{
|
|
if (!ecma_is_value_string (exports_p[i]))
|
|
{
|
|
ecma_deref_object (scope_p);
|
|
ecma_module_release_module_names (local_exports_p);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_EXPORTS_MUST_BE_STRING_VALUES));
|
|
}
|
|
|
|
ecma_string_t *name_str_p = ecma_get_string_from_value (exports_p[i]);
|
|
|
|
bool valid_identifier = false;
|
|
|
|
ECMA_STRING_TO_UTF8_STRING (name_str_p, name_start_p, name_size);
|
|
|
|
if (name_size > 0)
|
|
{
|
|
const lit_utf8_byte_t *name_p = name_start_p;
|
|
const lit_utf8_byte_t *name_end_p = name_start_p + name_size;
|
|
lit_code_point_t code_point;
|
|
|
|
lit_utf8_size_t size = lit_read_code_point_from_cesu8 (name_p, name_end_p, &code_point);
|
|
|
|
if (lit_code_point_is_identifier_start (code_point))
|
|
{
|
|
name_p += size;
|
|
|
|
valid_identifier = true;
|
|
|
|
while (name_p < name_end_p)
|
|
{
|
|
size = lit_read_code_point_from_cesu8 (name_p, name_end_p, &code_point);
|
|
|
|
if (!lit_code_point_is_identifier_part (code_point))
|
|
{
|
|
valid_identifier = false;
|
|
break;
|
|
}
|
|
|
|
name_p += size;
|
|
}
|
|
}
|
|
}
|
|
|
|
ECMA_FINALIZE_UTF8_STRING (name_start_p, name_size);
|
|
|
|
if (!valid_identifier)
|
|
{
|
|
ecma_deref_object (scope_p);
|
|
ecma_module_release_module_names (local_exports_p);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_EXPORTS_MUST_BE_VALID_IDENTIFIERS));
|
|
}
|
|
|
|
if (ecma_find_named_property (scope_p, name_str_p) != NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ecma_create_named_data_property (scope_p, name_str_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL);
|
|
|
|
ecma_module_names_t *new_export_p;
|
|
new_export_p = (ecma_module_names_t *) jmem_heap_alloc_block (sizeof (ecma_module_names_t));
|
|
|
|
new_export_p->next_p = local_exports_p;
|
|
local_exports_p = new_export_p;
|
|
|
|
ecma_ref_ecma_string (name_str_p);
|
|
new_export_p->imex_name_p = name_str_p;
|
|
|
|
ecma_ref_ecma_string (name_str_p);
|
|
new_export_p->local_name_p = name_str_p;
|
|
}
|
|
|
|
ecma_module_t *module_p = ecma_module_create ();
|
|
|
|
module_p->header.u.cls.u2.module_flags |= ECMA_MODULE_IS_NATIVE;
|
|
module_p->scope_p = scope_p;
|
|
module_p->local_exports_p = local_exports_p;
|
|
module_p->u.callback = callback;
|
|
|
|
ecma_deref_object (scope_p);
|
|
|
|
return ecma_make_object_value (&module_p->header.object);
|
|
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (callback);
|
|
JERRY_UNUSED (exports_p);
|
|
JERRY_UNUSED (export_count);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_native_module */
|
|
|
|
/**
|
|
* Gets the value of an export which belongs to a native module.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the export - if success
|
|
* error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_native_module_get (const jerry_value_t native_module, /**< a native module object */
|
|
const jerry_value_t export_name) /**< string identifier of the export */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
ecma_module_t *module_p = ecma_module_get_resolved_module (native_module);
|
|
|
|
if (module_p == NULL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
|
|
}
|
|
|
|
if (!(module_p->header.u.cls.u2.module_flags & ECMA_MODULE_IS_NATIVE) || !ecma_is_value_string (export_name))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_property_t *property_p = ecma_find_named_property (module_p->scope_p, ecma_get_string_from_value (export_name));
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_REFERENCE, ecma_get_error_msg (ECMA_ERR_UNKNOWN_EXPORT));
|
|
}
|
|
|
|
return ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (native_module);
|
|
JERRY_UNUSED (export_name);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_native_module_get */
|
|
|
|
/**
|
|
* Sets the value of an export which belongs to a native module.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return true value - if the operation was successful
|
|
* error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_native_module_set (jerry_value_t native_module, /**< a native module object */
|
|
const jerry_value_t export_name, /**< string identifier of the export */
|
|
const jerry_value_t value) /**< new value of the export */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_MODULE_SYSTEM
|
|
ecma_module_t *module_p = ecma_module_get_resolved_module (native_module);
|
|
|
|
if (module_p == NULL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_NOT_MODULE));
|
|
}
|
|
|
|
if (!(module_p->header.u.cls.u2.module_flags & ECMA_MODULE_IS_NATIVE) || !ecma_is_value_string (export_name)
|
|
|| ecma_is_value_exception (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_property_t *property_p = ecma_find_named_property (module_p->scope_p, ecma_get_string_from_value (export_name));
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_REFERENCE, ecma_get_error_msg (ECMA_ERR_UNKNOWN_EXPORT));
|
|
}
|
|
|
|
ecma_named_data_property_assign_value (module_p->scope_p, ECMA_PROPERTY_VALUE_PTR (property_p), value);
|
|
return ECMA_VALUE_TRUE;
|
|
#else /* !JERRY_MODULE_SYSTEM */
|
|
JERRY_UNUSED (native_module);
|
|
JERRY_UNUSED (export_name);
|
|
JERRY_UNUSED (value);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_MODULE_NOT_SUPPORTED));
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
} /* jerry_native_module_set */
|
|
|
|
/**
|
|
* Run enqueued microtasks created by Promise or AsyncFunction objects.
|
|
* Tasks are executed until an exception is thrown or all tasks are executed.
|
|
*
|
|
* Note: returned value must be freed with jerry_value_free
|
|
*
|
|
* @return result of last executed job, possibly an exception.
|
|
*/
|
|
jerry_value_t
|
|
jerry_run_jobs (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
return jerry_return (ecma_process_all_enqueued_jobs ());
|
|
#else /* !JERRY_ESNEXT */
|
|
return ECMA_VALUE_UNDEFINED;
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_run_jobs */
|
|
|
|
/**
|
|
* Get global object
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return api value of global object
|
|
*/
|
|
jerry_value_t
|
|
jerry_current_realm (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
ecma_object_t *global_obj_p = ecma_builtin_get_global ();
|
|
ecma_ref_object (global_obj_p);
|
|
return ecma_make_object_value (global_obj_p);
|
|
} /* jerry_current_realm */
|
|
|
|
/**
|
|
* Check if the specified value is an abort value.
|
|
*
|
|
* @return true - if both the error and abort values are set,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_abort (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_exception (value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_extended_primitive_t *error_ref_p = ecma_get_extended_primitive_from_value (value);
|
|
|
|
return (error_ref_p->refs_and_type & ECMA_ERROR_API_FLAG_ABORT) != 0;
|
|
} /* jerry_value_is_abort */
|
|
|
|
/**
|
|
* Check if the specified value is an array object value.
|
|
*
|
|
* @return true - if the specified value is an array object,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_array (const jerry_value_t value) /**< jerry api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return (ecma_is_value_object (value)
|
|
&& ecma_get_object_base_type (ecma_get_object_from_value (value)) == ECMA_OBJECT_BASE_TYPE_ARRAY);
|
|
} /* jerry_value_is_array */
|
|
|
|
/**
|
|
* Check if the specified value is boolean.
|
|
*
|
|
* @return true - if the specified value is boolean,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_boolean (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_boolean (value);
|
|
} /* jerry_value_is_boolean */
|
|
|
|
/**
|
|
* Check if the specified value is true.
|
|
*
|
|
* @return true - if the specified value is true
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_true (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_true (value);
|
|
} /* jerry_value_is_true */
|
|
|
|
/**
|
|
* Check if the specified value is false.
|
|
*
|
|
* @return true - if the specified value is false
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_false (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_false (value);
|
|
} /* jerry_value_is_false */
|
|
|
|
/**
|
|
* Check if the specified value is a constructor function object value.
|
|
*
|
|
* @return true - if the specified value is a function value that implements [[Construct]],
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_constructor (const jerry_value_t value) /**< jerry api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_constructor (value);
|
|
} /* jerry_value_is_constructor */
|
|
|
|
/**
|
|
* Check if the specified value is an error or abort value.
|
|
*
|
|
* @return true - if the specified value is an error value,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_exception (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_exception (value);
|
|
} /* jerry_value_is_exception */
|
|
|
|
/**
|
|
* Check if the specified value is a function object value.
|
|
*
|
|
* @return true - if the specified value is callable,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_function (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_op_is_callable (value);
|
|
} /* jerry_value_is_function */
|
|
|
|
/**
|
|
* Check if the specified value is an async function object value.
|
|
*
|
|
* @return true - if the specified value is an async function,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_async_function (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
if (ecma_is_value_object (value))
|
|
{
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
|
|
|
if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
|
|
{
|
|
const ecma_compiled_code_t *bytecode_data_p;
|
|
bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) obj_p);
|
|
uint16_t type = CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags);
|
|
|
|
return (type == CBC_FUNCTION_ASYNC || type == CBC_FUNCTION_ASYNC_ARROW || type == CBC_FUNCTION_ASYNC_GENERATOR);
|
|
}
|
|
}
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (value);
|
|
#endif /* JERRY_ESNEXT */
|
|
|
|
return false;
|
|
} /* jerry_value_is_async_function */
|
|
|
|
/**
|
|
* Check if the specified value is number.
|
|
*
|
|
* @return true - if the specified value is number,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_number (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_number (value);
|
|
} /* jerry_value_is_number */
|
|
|
|
/**
|
|
* Check if the specified value is null.
|
|
*
|
|
* @return true - if the specified value is null,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_null (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_null (value);
|
|
} /* jerry_value_is_null */
|
|
|
|
/**
|
|
* Check if the specified value is object.
|
|
*
|
|
* @return true - if the specified value is object,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_object (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_object (value);
|
|
} /* jerry_value_is_object */
|
|
|
|
/**
|
|
* Check if the specified value is promise.
|
|
*
|
|
* @return true - if the specified value is promise,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_promise (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
#if JERRY_ESNEXT
|
|
return (ecma_is_value_object (value) && ecma_is_promise (ecma_get_object_from_value (value)));
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_value_is_promise */
|
|
|
|
/**
|
|
* Check if the specified value is a proxy object.
|
|
*
|
|
* @return true - if the specified value is a proxy object,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_proxy (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
#if JERRY_BUILTIN_PROXY
|
|
return (ecma_is_value_object (value) && ECMA_OBJECT_IS_PROXY (ecma_get_object_from_value (value)));
|
|
#else /* !JERRY_BUILTIN_PROXY */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
} /* jerry_value_is_proxy */
|
|
|
|
/**
|
|
* Check if the specified value is string.
|
|
*
|
|
* @return true - if the specified value is string,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_string (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_string (value);
|
|
} /* jerry_value_is_string */
|
|
|
|
/**
|
|
* Check if the specified value is symbol.
|
|
*
|
|
* @return true - if the specified value is symbol,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_symbol (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
return ecma_is_value_symbol (value);
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_value_is_symbol */
|
|
|
|
/**
|
|
* Check if the specified value is BigInt.
|
|
*
|
|
* @return true - if the specified value is BigInt,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_bigint (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_BIGINT
|
|
return ecma_is_value_bigint (value);
|
|
#else /* !JERRY_BUILTIN_BIGINT */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
} /* jerry_value_is_bigint */
|
|
|
|
/**
|
|
* Check if the specified value is undefined.
|
|
*
|
|
* @return true - if the specified value is undefined,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_undefined (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_value_undefined (value);
|
|
} /* jerry_value_is_undefined */
|
|
|
|
/**
|
|
* Perform the base type of the JavaScript value.
|
|
*
|
|
* @return jerry_type_t value
|
|
*/
|
|
jerry_type_t
|
|
jerry_value_type (const jerry_value_t value) /**< input value to check */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return JERRY_TYPE_EXCEPTION;
|
|
}
|
|
|
|
lit_magic_string_id_t lit_id = ecma_get_typeof_lit_id (value);
|
|
|
|
JERRY_ASSERT (lit_id != LIT_MAGIC_STRING__EMPTY);
|
|
|
|
switch (lit_id)
|
|
{
|
|
case LIT_MAGIC_STRING_UNDEFINED:
|
|
{
|
|
return JERRY_TYPE_UNDEFINED;
|
|
}
|
|
case LIT_MAGIC_STRING_BOOLEAN:
|
|
{
|
|
return JERRY_TYPE_BOOLEAN;
|
|
}
|
|
case LIT_MAGIC_STRING_NUMBER:
|
|
{
|
|
return JERRY_TYPE_NUMBER;
|
|
}
|
|
case LIT_MAGIC_STRING_STRING:
|
|
{
|
|
return JERRY_TYPE_STRING;
|
|
}
|
|
#if JERRY_ESNEXT
|
|
case LIT_MAGIC_STRING_SYMBOL:
|
|
{
|
|
return JERRY_TYPE_SYMBOL;
|
|
}
|
|
#endif /* JERRY_ESNEXT */
|
|
case LIT_MAGIC_STRING_FUNCTION:
|
|
{
|
|
return JERRY_TYPE_FUNCTION;
|
|
}
|
|
#if JERRY_BUILTIN_BIGINT
|
|
case LIT_MAGIC_STRING_BIGINT:
|
|
{
|
|
return JERRY_TYPE_BIGINT;
|
|
}
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
default:
|
|
{
|
|
JERRY_ASSERT (lit_id == LIT_MAGIC_STRING_OBJECT);
|
|
|
|
/* Based on the ECMA 262 5.1 standard the 'null' value is an object.
|
|
* Thus we'll do an extra check for 'null' here.
|
|
*/
|
|
return ecma_is_value_null (value) ? JERRY_TYPE_NULL : JERRY_TYPE_OBJECT;
|
|
}
|
|
}
|
|
} /* jerry_value_type */
|
|
|
|
/**
|
|
* Used by jerry_object_type to get the type of class objects
|
|
*/
|
|
static const uint8_t jerry_class_object_type[] = {
|
|
/* These objects require custom property resolving. */
|
|
JERRY_OBJECT_TYPE_STRING, /**< type of ECMA_OBJECT_CLASS_STRING */
|
|
JERRY_OBJECT_TYPE_ARGUMENTS, /**< type of ECMA_OBJECT_CLASS_ARGUMENTS */
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
JERRY_OBJECT_TYPE_TYPEDARRAY, /**< type of ECMA_OBJECT_CLASS_TYPEDARRAY */
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
#if JERRY_MODULE_SYSTEM
|
|
JERRY_OBJECT_TYPE_MODULE_NAMESPACE, /**< type of ECMA_OBJECT_CLASS_MODULE_NAMESPACE */
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
|
|
/* These objects are marked by Garbage Collector. */
|
|
#if JERRY_ESNEXT
|
|
JERRY_OBJECT_TYPE_GENERATOR, /**< type of ECMA_OBJECT_CLASS_GENERATOR */
|
|
JERRY_OBJECT_TYPE_GENERATOR, /**< type of ECMA_OBJECT_CLASS_ASYNC_GENERATOR */
|
|
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_ARRAY_ITERATOR */
|
|
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_SET_ITERATOR */
|
|
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_MAP_ITERATOR */
|
|
#if JERRY_BUILTIN_REGEXP
|
|
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_REGEXP_STRING_ITERATOR */
|
|
#endif /* JERRY_BUILTIN_REGEXP */
|
|
#endif /* JERRY_ESNEXT */
|
|
#if JERRY_MODULE_SYSTEM
|
|
JERRY_OBJECT_TYPE_MODULE, /**< type of ECMA_OBJECT_CLASS_MODULE */
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
#if JERRY_ESNEXT
|
|
JERRY_OBJECT_TYPE_PROMISE, /**< type of ECMA_OBJECT_CLASS_PROMISE */
|
|
JERRY_OBJECT_TYPE_GENERIC, /**< type of ECMA_OBJECT_CLASS_PROMISE_CAPABILITY */
|
|
JERRY_OBJECT_TYPE_GENERIC, /**< type of ECMA_OBJECT_CLASS_ASYNC_FROM_SYNC_ITERATOR */
|
|
#endif /* JERRY_ESNEXT */
|
|
#if JERRY_BUILTIN_DATAVIEW
|
|
JERRY_OBJECT_TYPE_DATAVIEW, /**< type of ECMA_OBJECT_CLASS_DATAVIEW */
|
|
#endif /* JERRY_BUILTIN_DATAVIEW */
|
|
#if JERRY_BUILTIN_CONTAINER
|
|
JERRY_OBJECT_TYPE_CONTAINER, /**< type of ECMA_OBJECT_CLASS_CONTAINER */
|
|
#endif /* JERRY_BUILTIN_CONTAINER */
|
|
|
|
/* Normal objects. */
|
|
JERRY_OBJECT_TYPE_BOOLEAN, /**< type of ECMA_OBJECT_CLASS_BOOLEAN */
|
|
JERRY_OBJECT_TYPE_NUMBER, /**< type of ECMA_OBJECT_CLASS_NUMBER */
|
|
JERRY_OBJECT_TYPE_ERROR, /**< type of ECMA_OBJECT_CLASS_ERROR */
|
|
JERRY_OBJECT_TYPE_GENERIC, /**< type of ECMA_OBJECT_CLASS_INTERNAL_OBJECT */
|
|
#if JERRY_PARSER
|
|
JERRY_OBJECT_TYPE_SCRIPT, /**< type of ECMA_OBJECT_CLASS_SCRIPT */
|
|
#endif /* JERRY_PARSER */
|
|
#if JERRY_BUILTIN_DATE
|
|
JERRY_OBJECT_TYPE_DATE, /**< type of ECMA_OBJECT_CLASS_DATE */
|
|
#endif /* JERRY_BUILTIN_DATE */
|
|
#if JERRY_BUILTIN_REGEXP
|
|
JERRY_OBJECT_TYPE_REGEXP, /**< type of ECMA_OBJECT_CLASS_REGEXP */
|
|
#endif /* JERRY_BUILTIN_REGEXP */
|
|
#if JERRY_ESNEXT
|
|
JERRY_OBJECT_TYPE_SYMBOL, /**< type of ECMA_OBJECT_CLASS_SYMBOL */
|
|
JERRY_OBJECT_TYPE_ITERATOR, /**< type of ECMA_OBJECT_CLASS_STRING_ITERATOR */
|
|
#endif /* JERRY_ESNEXT */
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
JERRY_OBJECT_TYPE_ARRAYBUFFER, /**< type of ECMA_OBJECT_CLASS_ARRAY_BUFFER */
|
|
#if JERRY_BUILTIN_SHAREDARRAYBUFFER
|
|
JERRY_OBJECT_TYPE_SHARED_ARRAY_BUFFER, /**< type of ECMA_OBJECT_CLASS_SHARED_ARRAY_BUFFER */
|
|
#endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
#if JERRY_BUILTIN_BIGINT
|
|
JERRY_OBJECT_TYPE_BIGINT, /**< type of ECMA_OBJECT_CLASS_BIGINT */
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
#if JERRY_BUILTIN_WEAKREF
|
|
JERRY_OBJECT_TYPE_WEAKREF, /**< type of ECMA_OBJECT_CLASS_WEAKREF */
|
|
#endif /* JERRY_BUILTIN_WEAKREF */
|
|
};
|
|
|
|
JERRY_STATIC_ASSERT (sizeof (jerry_class_object_type) == ECMA_OBJECT_CLASS__MAX,
|
|
jerry_class_object_type_must_have_object_class_max_elements);
|
|
|
|
/**
|
|
* Get the object type of the given value
|
|
*
|
|
* @return JERRY_OBJECT_TYPE_NONE - if the given value is not an object
|
|
* jerry_object_type_t value - otherwise
|
|
*/
|
|
jerry_object_type_t
|
|
jerry_object_type (const jerry_value_t value) /**< input value to check */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (value))
|
|
{
|
|
return JERRY_OBJECT_TYPE_NONE;
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
|
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
|
|
|
|
switch (ecma_get_object_type (obj_p))
|
|
{
|
|
case ECMA_OBJECT_TYPE_CLASS:
|
|
case ECMA_OBJECT_TYPE_BUILT_IN_CLASS:
|
|
{
|
|
JERRY_ASSERT (ext_obj_p->u.cls.type < ECMA_OBJECT_CLASS__MAX);
|
|
return jerry_class_object_type[ext_obj_p->u.cls.type];
|
|
}
|
|
case ECMA_OBJECT_TYPE_ARRAY:
|
|
case ECMA_OBJECT_TYPE_BUILT_IN_ARRAY:
|
|
{
|
|
return JERRY_OBJECT_TYPE_ARRAY;
|
|
}
|
|
#if JERRY_ESNEXT
|
|
case ECMA_OBJECT_TYPE_PROXY:
|
|
{
|
|
return JERRY_OBJECT_TYPE_PROXY;
|
|
}
|
|
#endif /* JERRY_ESNEXT */
|
|
case ECMA_OBJECT_TYPE_FUNCTION:
|
|
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
|
|
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
|
|
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
|
|
{
|
|
return JERRY_OBJECT_TYPE_FUNCTION;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return JERRY_OBJECT_TYPE_GENERIC;
|
|
} /* jerry_object_type */
|
|
|
|
/**
|
|
* Get the function type of the given value
|
|
*
|
|
* @return JERRY_FUNCTION_TYPE_NONE - if the given value is not a function object
|
|
* jerry_function_type_t value - otherwise
|
|
*/
|
|
jerry_function_type_t
|
|
jerry_function_type (const jerry_value_t value) /**< input value to check */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_object (value))
|
|
{
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
|
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
|
|
|
|
switch (ecma_get_object_type (obj_p))
|
|
{
|
|
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
|
|
{
|
|
return JERRY_FUNCTION_TYPE_BOUND;
|
|
}
|
|
case ECMA_OBJECT_TYPE_NATIVE_FUNCTION:
|
|
case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION:
|
|
{
|
|
return JERRY_FUNCTION_TYPE_GENERIC;
|
|
}
|
|
case ECMA_OBJECT_TYPE_FUNCTION:
|
|
{
|
|
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_obj_p);
|
|
|
|
switch (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags))
|
|
{
|
|
#if JERRY_ESNEXT
|
|
case CBC_FUNCTION_ARROW:
|
|
case CBC_FUNCTION_ASYNC_ARROW:
|
|
{
|
|
return JERRY_FUNCTION_TYPE_ARROW;
|
|
}
|
|
case CBC_FUNCTION_GENERATOR:
|
|
case CBC_FUNCTION_ASYNC_GENERATOR:
|
|
{
|
|
return JERRY_FUNCTION_TYPE_GENERATOR;
|
|
}
|
|
#endif /* JERRY_ESNEXT */
|
|
case CBC_FUNCTION_ACCESSOR:
|
|
{
|
|
return JERRY_FUNCTION_TYPE_ACCESSOR;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return JERRY_FUNCTION_TYPE_GENERIC;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return JERRY_FUNCTION_TYPE_NONE;
|
|
} /* jerry_function_type */
|
|
|
|
/**
|
|
* Get the itearator type of the given value
|
|
*
|
|
* @return JERRY_ITERATOR_TYPE_NONE - if the given value is not an iterator object
|
|
* jerry_iterator_type_t value - otherwise
|
|
*/
|
|
jerry_iterator_type_t
|
|
jerry_iterator_type (const jerry_value_t value) /**< input value to check */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
if (ecma_is_value_object (value))
|
|
{
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
|
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
|
|
|
|
if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_CLASS)
|
|
{
|
|
switch (ext_obj_p->u.cls.type)
|
|
{
|
|
case ECMA_OBJECT_CLASS_ARRAY_ITERATOR:
|
|
{
|
|
return JERRY_ITERATOR_TYPE_ARRAY;
|
|
}
|
|
#if JERRY_BUILTIN_CONTAINER
|
|
case ECMA_OBJECT_CLASS_SET_ITERATOR:
|
|
{
|
|
return JERRY_ITERATOR_TYPE_SET;
|
|
}
|
|
case ECMA_OBJECT_CLASS_MAP_ITERATOR:
|
|
{
|
|
return JERRY_ITERATOR_TYPE_MAP;
|
|
}
|
|
#endif /* JERRY_BUILTIN_CONTAINER */
|
|
case ECMA_OBJECT_CLASS_STRING_ITERATOR:
|
|
{
|
|
return JERRY_ITERATOR_TYPE_STRING;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (value);
|
|
#endif /* JERRY_ESNEXT */
|
|
|
|
return JERRY_ITERATOR_TYPE_NONE;
|
|
} /* jerry_iterator_type */
|
|
|
|
/**
|
|
* Check if the specified feature is enabled.
|
|
*
|
|
* @return true - if the specified feature is enabled,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_feature_enabled (const jerry_feature_t feature) /**< feature to check */
|
|
{
|
|
JERRY_ASSERT (feature < JERRY_FEATURE__COUNT);
|
|
|
|
return (false
|
|
#if JERRY_CPOINTER_32_BIT
|
|
|| feature == JERRY_FEATURE_CPOINTER_32_BIT
|
|
#endif /* JERRY_CPOINTER_32_BIT */
|
|
#if JERRY_ERROR_MESSAGES
|
|
|| feature == JERRY_FEATURE_ERROR_MESSAGES
|
|
#endif /* JERRY_ERROR_MESSAGES */
|
|
#if JERRY_PARSER
|
|
|| feature == JERRY_FEATURE_JS_PARSER
|
|
#endif /* JERRY_PARSER */
|
|
#if JERRY_MEM_STATS
|
|
|| feature == JERRY_FEATURE_HEAP_STATS
|
|
#endif /* JERRY_MEM_STATS */
|
|
#if JERRY_PARSER_DUMP_BYTE_CODE
|
|
|| feature == JERRY_FEATURE_PARSER_DUMP
|
|
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */
|
|
#if JERRY_REGEXP_DUMP_BYTE_CODE
|
|
|| feature == JERRY_FEATURE_REGEXP_DUMP
|
|
#endif /* JERRY_REGEXP_DUMP_BYTE_CODE */
|
|
#if JERRY_SNAPSHOT_SAVE
|
|
|| feature == JERRY_FEATURE_SNAPSHOT_SAVE
|
|
#endif /* JERRY_SNAPSHOT_SAVE */
|
|
#if JERRY_SNAPSHOT_EXEC
|
|
|| feature == JERRY_FEATURE_SNAPSHOT_EXEC
|
|
#endif /* JERRY_SNAPSHOT_EXEC */
|
|
#if JERRY_DEBUGGER
|
|
|| feature == JERRY_FEATURE_DEBUGGER
|
|
#endif /* JERRY_DEBUGGER */
|
|
#if JERRY_VM_HALT
|
|
|| feature == JERRY_FEATURE_VM_EXEC_STOP
|
|
#endif /* JERRY_VM_HALT */
|
|
#if JERRY_VM_THROW
|
|
|| feature == JERRY_FEATURE_VM_THROW
|
|
#endif /* JERRY_VM_THROW */
|
|
#if JERRY_BUILTIN_JSON
|
|
|| feature == JERRY_FEATURE_JSON
|
|
#endif /* JERRY_BUILTIN_JSON */
|
|
#if JERRY_ESNEXT
|
|
|| feature == JERRY_FEATURE_PROMISE || feature == JERRY_FEATURE_SYMBOL
|
|
#endif /* JERRY_ESNEXT */
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
|| feature == JERRY_FEATURE_TYPEDARRAY
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
#if JERRY_BUILTIN_DATAVIEW
|
|
|| feature == JERRY_FEATURE_DATAVIEW
|
|
#endif /* JERRY_BUILTIN_DATAVIEW */
|
|
#if JERRY_BUILTIN_PROXY
|
|
|| feature == JERRY_FEATURE_PROXY
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
#if JERRY_BUILTIN_DATE
|
|
|| feature == JERRY_FEATURE_DATE
|
|
#endif /* JERRY_BUILTIN_DATE */
|
|
#if JERRY_BUILTIN_REGEXP
|
|
|| feature == JERRY_FEATURE_REGEXP
|
|
#endif /* JERRY_BUILTIN_REGEXP */
|
|
#if JERRY_LINE_INFO
|
|
|| feature == JERRY_FEATURE_LINE_INFO
|
|
#endif /* JERRY_LINE_INFO */
|
|
#if JERRY_LOGGING
|
|
|| feature == JERRY_FEATURE_LOGGING
|
|
#endif /* JERRY_LOGGING */
|
|
#if JERRY_BUILTIN_GLOBAL_THIS
|
|
|| feature == JERRY_FEATURE_GLOBAL_THIS
|
|
#endif /* JERRY_BUILTIN_GLOBAL_THIS */
|
|
#if JERRY_BUILTIN_CONTAINER
|
|
|| feature == JERRY_FEATURE_MAP || feature == JERRY_FEATURE_SET || feature == JERRY_FEATURE_WEAKMAP
|
|
|| feature == JERRY_FEATURE_WEAKSET
|
|
#endif /* JERRY_BUILTIN_CONTAINER */
|
|
#if JERRY_BUILTIN_WEAKREF
|
|
|| feature == JERRY_FEATURE_WEAKREF
|
|
#endif /* JERRY_BUILTIN_WEAKREF */
|
|
#if JERRY_BUILTIN_BIGINT
|
|
|| feature == JERRY_FEATURE_BIGINT
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
#if JERRY_BUILTIN_REALMS
|
|
|| feature == JERRY_FEATURE_REALM
|
|
#endif /* JERRY_BUILTIN_REALMS */
|
|
#if JERRY_PROMISE_CALLBACK
|
|
|| feature == JERRY_FEATURE_PROMISE_CALLBACK
|
|
#endif /* JERRY_PROMISE_CALLBACK */
|
|
#if JERRY_MODULE_SYSTEM
|
|
|| feature == JERRY_FEATURE_MODULE
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
#if JERRY_FUNCTION_TO_STRING
|
|
|| feature == JERRY_FEATURE_FUNCTION_TO_STRING
|
|
#endif /* JERRY_FUNCTION_TO_STRING */
|
|
);
|
|
} /* jerry_feature_enabled */
|
|
|
|
/**
|
|
* Perform binary operation on the given operands (==, ===, <, >, etc.).
|
|
*
|
|
* @return error - if argument has an error flag or operation is unsuccessful or unsupported
|
|
* true/false - the result of the binary operation on the given operands otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_binary_op (jerry_binary_op_t operation, /**< operation */
|
|
const jerry_value_t lhs, /**< first operand */
|
|
const jerry_value_t rhs) /**< second operand */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (lhs) || ecma_is_value_exception (rhs))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
switch (operation)
|
|
{
|
|
case JERRY_BIN_OP_EQUAL:
|
|
{
|
|
return jerry_return (ecma_op_abstract_equality_compare (lhs, rhs));
|
|
}
|
|
case JERRY_BIN_OP_STRICT_EQUAL:
|
|
{
|
|
return ecma_make_boolean_value (ecma_op_strict_equality_compare (lhs, rhs));
|
|
}
|
|
case JERRY_BIN_OP_LESS:
|
|
{
|
|
return jerry_return (opfunc_relation (lhs, rhs, true, false));
|
|
}
|
|
case JERRY_BIN_OP_LESS_EQUAL:
|
|
{
|
|
return jerry_return (opfunc_relation (lhs, rhs, false, true));
|
|
}
|
|
case JERRY_BIN_OP_GREATER:
|
|
{
|
|
return jerry_return (opfunc_relation (lhs, rhs, false, false));
|
|
}
|
|
case JERRY_BIN_OP_GREATER_EQUAL:
|
|
{
|
|
return jerry_return (opfunc_relation (lhs, rhs, true, true));
|
|
}
|
|
case JERRY_BIN_OP_INSTANCEOF:
|
|
{
|
|
if (!ecma_is_value_object (lhs) || !ecma_op_is_callable (rhs))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_object_t *proto_obj_p = ecma_get_object_from_value (rhs);
|
|
return jerry_return (ecma_op_object_has_instance (proto_obj_p, lhs));
|
|
}
|
|
case JERRY_BIN_OP_ADD:
|
|
{
|
|
return jerry_return (opfunc_addition (lhs, rhs));
|
|
}
|
|
case JERRY_BIN_OP_SUB:
|
|
case JERRY_BIN_OP_MUL:
|
|
case JERRY_BIN_OP_DIV:
|
|
case JERRY_BIN_OP_REM:
|
|
{
|
|
return jerry_return (do_number_arithmetic (operation - ECMA_NUMBER_ARITHMETIC_OP_API_OFFSET, lhs, rhs));
|
|
}
|
|
default:
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_UNSUPPORTED_BINARY_OPERATION));
|
|
}
|
|
}
|
|
} /* jerry_binary_op */
|
|
|
|
/**
|
|
* Create an abort value containing the argument value. If the second argument is true
|
|
* the function will take ownership ofthe input value, otherwise the value will be copied.
|
|
*
|
|
* @return api abort value
|
|
*/
|
|
jerry_value_t
|
|
jerry_throw_abort (jerry_value_t value, /**< api value */
|
|
bool take_ownership) /**< release api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
|
|
{
|
|
/* This is a rare case so it is optimized for
|
|
* binary size rather than performance. */
|
|
if (jerry_value_is_abort (value))
|
|
{
|
|
return take_ownership ? value : jerry_value_copy (value);
|
|
}
|
|
|
|
value = jerry_exception_value (value, take_ownership);
|
|
take_ownership = true;
|
|
}
|
|
|
|
if (!take_ownership)
|
|
{
|
|
value = ecma_copy_value (value);
|
|
}
|
|
|
|
return ecma_create_exception (value, ECMA_ERROR_API_FLAG_ABORT);
|
|
} /* jerry_throw_abort */
|
|
|
|
/**
|
|
* Create an exception value containing the argument value. If the second argument is true
|
|
* the function will take ownership ofthe input value, otherwise the value will be copied.
|
|
*
|
|
* @return exception value
|
|
*/
|
|
jerry_value_t
|
|
jerry_throw_value (jerry_value_t value, /**< value */
|
|
bool take_ownership) /**< take ownership of the value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
|
|
{
|
|
/* This is a rare case so it is optimized for
|
|
* binary size rather than performance. */
|
|
if (!jerry_value_is_abort (value))
|
|
{
|
|
return take_ownership ? value : jerry_value_copy (value);
|
|
}
|
|
|
|
value = jerry_exception_value (value, take_ownership);
|
|
take_ownership = true;
|
|
}
|
|
|
|
if (!take_ownership)
|
|
{
|
|
value = ecma_copy_value (value);
|
|
}
|
|
|
|
return ecma_create_exception (value, ECMA_ERROR_API_FLAG_NONE);
|
|
} /* jerry_throw_value */
|
|
|
|
/**
|
|
* Get the value contained in an exception. If the second argument is true
|
|
* it will release the argument exception value in the process.
|
|
*
|
|
* @return value in exception
|
|
*/
|
|
jerry_value_t
|
|
jerry_exception_value (jerry_value_t value, /**< api value */
|
|
bool free_exception) /**< release api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_exception (value))
|
|
{
|
|
return free_exception ? value : ecma_copy_value (value);
|
|
}
|
|
|
|
jerry_value_t ret_val = jerry_value_copy (ecma_get_extended_primitive_from_value (value)->u.value);
|
|
|
|
if (free_exception)
|
|
{
|
|
jerry_value_free (value);
|
|
}
|
|
return ret_val;
|
|
} /* jerry_exception_value */
|
|
|
|
/**
|
|
* Set new decorator callback for Error objects. The decorator can
|
|
* create or update any properties of the newly created Error object.
|
|
*/
|
|
void
|
|
jerry_error_on_created (jerry_error_object_created_cb_t callback, /**< new callback */
|
|
void *user_p) /**< user pointer passed to the callback */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
JERRY_CONTEXT (error_object_created_callback_p) = callback;
|
|
JERRY_CONTEXT (error_object_created_callback_user_p) = user_p;
|
|
} /* jerry_error_on_created */
|
|
|
|
/**
|
|
* When JERRY_VM_THROW is enabled, the callback passed to this
|
|
* function is called when an error is thrown in ECMAScript code.
|
|
*/
|
|
void
|
|
jerry_on_throw (jerry_throw_cb_t callback, /**< callback which is called on throws */
|
|
void *user_p) /**< pointer passed to the function */
|
|
{
|
|
#if JERRY_VM_THROW
|
|
JERRY_CONTEXT (vm_throw_callback_p) = callback;
|
|
JERRY_CONTEXT (vm_throw_callback_user_p) = user_p;
|
|
#else /* !JERRY_VM_THROW */
|
|
JERRY_UNUSED (callback);
|
|
JERRY_UNUSED (user_p);
|
|
#endif /* JERRY_VM_THROW */
|
|
} /* jerry_on_throw */
|
|
|
|
/**
|
|
* Checks whether the callback set by jerry_on_throw captured the error
|
|
*
|
|
* @return true, if the vm throw callback captured the error
|
|
* false, otherwise
|
|
*/
|
|
bool
|
|
jerry_exception_is_captured (const jerry_value_t value) /**< exception value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_VM_THROW
|
|
if (!ecma_is_value_exception (value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_extended_primitive_t *error_ref_p = ecma_get_extended_primitive_from_value (value);
|
|
|
|
return (error_ref_p->refs_and_type & ECMA_ERROR_API_FLAG_THROW_CAPTURED) != 0;
|
|
#else /* !JERRY_VM_THROW */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_VM_THROW */
|
|
} /* jerry_exception_is_captured */
|
|
|
|
/**
|
|
* Sets whether the callback set by jerry_on_throw should capture the exception or not
|
|
*/
|
|
void
|
|
jerry_exception_allow_capture (jerry_value_t value, /**< exception value */
|
|
bool should_capture) /**< callback should capture this error */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_VM_THROW
|
|
if (!ecma_is_value_exception (value))
|
|
{
|
|
return;
|
|
}
|
|
|
|
ecma_extended_primitive_t *error_ref_p = ecma_get_extended_primitive_from_value (value);
|
|
|
|
if (should_capture)
|
|
{
|
|
error_ref_p->refs_and_type &= ~(uint32_t) ECMA_ERROR_API_FLAG_THROW_CAPTURED;
|
|
return;
|
|
}
|
|
|
|
error_ref_p->refs_and_type |= ECMA_ERROR_API_FLAG_THROW_CAPTURED;
|
|
#else /* !JERRY_VM_THROW */
|
|
JERRY_UNUSED (value);
|
|
JERRY_UNUSED (should_capture);
|
|
#endif /* JERRY_VM_THROW */
|
|
} /* jerry_exception_allow_capture */
|
|
|
|
/**
|
|
* Check if the given value is an Error object.
|
|
*
|
|
* @return true - if it is an Error object
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_error (const jerry_value_t value) /**< api value */
|
|
{
|
|
return ecma_is_value_object (value)
|
|
&& ecma_object_class_is (ecma_get_object_from_value (value), ECMA_OBJECT_CLASS_ERROR);
|
|
} /* jerry_value_is_error */
|
|
|
|
/**
|
|
* Return the type of the Error object if possible.
|
|
*
|
|
* @return one of the jerry_error_t value as the type of the Error object
|
|
* JERRY_ERROR_NONE - if the input value is not an Error object
|
|
*/
|
|
jerry_error_t
|
|
jerry_error_type (jerry_value_t value) /**< api value */
|
|
{
|
|
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
|
|
{
|
|
value = ecma_get_extended_primitive_from_value (value)->u.value;
|
|
}
|
|
|
|
if (!ecma_is_value_object (value))
|
|
{
|
|
return JERRY_ERROR_NONE;
|
|
}
|
|
|
|
ecma_object_t *object_p = ecma_get_object_from_value (value);
|
|
/* TODO(check if error object) */
|
|
jerry_error_t error_type = ecma_get_error_type (object_p);
|
|
|
|
return (jerry_error_t) error_type;
|
|
} /* jerry_error_type */
|
|
|
|
/**
|
|
* Get number from the specified value as a double.
|
|
*
|
|
* @return stored number as double
|
|
*/
|
|
double
|
|
jerry_value_as_number (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_number (value))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return (double) ecma_get_number_from_value (value);
|
|
} /* jerry_value_as_number */
|
|
|
|
/**
|
|
* Call ToBoolean operation on the api value.
|
|
*
|
|
* @return true - if the logical value is true
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_to_boolean (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ecma_op_to_boolean (value);
|
|
} /* jerry_value_to_boolean */
|
|
|
|
/**
|
|
* Call ToNumber operation on the api value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return converted number value - if success
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_value_to_number (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
ecma_number_t num;
|
|
ecma_value_t ret_value = ecma_op_to_number (value, &num);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (ret_value))
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
return ecma_make_number_value (num);
|
|
} /* jerry_value_to_number */
|
|
|
|
/**
|
|
* Call ToObject operation on the api value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return converted object value - if success
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_value_to_object (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
return jerry_return (ecma_op_to_object (value));
|
|
} /* jerry_value_to_object */
|
|
|
|
/**
|
|
* Call ToPrimitive operation on the api value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return converted primitive value - if success
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_value_to_primitive (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
return jerry_return (ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_NO));
|
|
} /* jerry_value_to_primitive */
|
|
|
|
/**
|
|
* Call the ToString ecma builtin operation on the api value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return converted string value - if success
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_value_to_string (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
ecma_string_t *str_p = ecma_op_to_string (value);
|
|
if (JERRY_UNLIKELY (str_p == NULL))
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
return ecma_make_string_value (str_p);
|
|
} /* jerry_value_to_string */
|
|
|
|
/**
|
|
* Call the BigInt constructor ecma builtin operation on the api value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return BigInt value - if success
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_value_to_bigint (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_BIGINT
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
return jerry_return (ecma_bigint_to_bigint (value, true));
|
|
#else /* !JERRY_BUILTIN_BIGINT */
|
|
JERRY_UNUSED (value);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_BIGINT_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
} /* jerry_value_to_bigint */
|
|
|
|
/**
|
|
* Convert any number to integer number.
|
|
*
|
|
* Note:
|
|
* For non-number values 0 is returned.
|
|
*
|
|
* @return integer representation of the number.
|
|
*/
|
|
double
|
|
jerry_value_as_integer (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_number (value))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
double number = ecma_get_number_from_value (value);
|
|
|
|
if (ecma_number_is_nan (number))
|
|
{
|
|
return ECMA_NUMBER_ZERO;
|
|
}
|
|
|
|
if (ecma_number_is_zero (number) || ecma_number_is_infinity (number))
|
|
{
|
|
return number;
|
|
}
|
|
|
|
ecma_number_t floor_fabs = (ecma_number_t) floor (fabs (number));
|
|
|
|
return ecma_number_is_negative (number) ? -floor_fabs : floor_fabs;
|
|
} /* jerry_value_as_integer */
|
|
|
|
/**
|
|
* Convert any number to int32 number.
|
|
*
|
|
* Note:
|
|
* For non-number values 0 is returned.
|
|
*
|
|
* @return int32 representation of the number.
|
|
*/
|
|
int32_t
|
|
jerry_value_as_int32 (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_number (value))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return ecma_number_to_int32 (ecma_get_number_from_value (value));
|
|
} /* jerry_value_as_int32 */
|
|
|
|
/**
|
|
* Convert any number to uint32 number.
|
|
*
|
|
* Note:
|
|
* For non-number values 0 is returned.
|
|
*
|
|
* @return uint32 representation of the number.
|
|
*/
|
|
uint32_t
|
|
jerry_value_as_uint32 (const jerry_value_t value) /**< input value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_number (value))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return ecma_number_to_uint32 (ecma_get_number_from_value (value));
|
|
} /* jerry_value_as_uint32 */
|
|
|
|
/**
|
|
* Take additional ownership over the argument value.
|
|
* The value will be copied by reference when possible, changes made to the new value will be reflected
|
|
* in the original.
|
|
*
|
|
* @return copied value
|
|
*/
|
|
jerry_value_t
|
|
jerry_value_copy (const jerry_value_t value) /**< value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
|
|
{
|
|
ecma_ref_extended_primitive (ecma_get_extended_primitive_from_value (value));
|
|
return value;
|
|
}
|
|
|
|
return ecma_copy_value (value);
|
|
} /* jerry_value_copy */
|
|
|
|
/**
|
|
* Release ownership of the argument value
|
|
*/
|
|
void
|
|
jerry_value_free (jerry_value_t value) /**< value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (JERRY_UNLIKELY (ecma_is_value_exception (value)))
|
|
{
|
|
ecma_deref_exception (ecma_get_extended_primitive_from_value (value));
|
|
return;
|
|
}
|
|
|
|
ecma_free_value (value);
|
|
} /* jerry_value_free */
|
|
|
|
/**
|
|
* Create an array object value
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the constructed array object
|
|
*/
|
|
jerry_value_t
|
|
jerry_array (jerry_length_t length) /**< length of array */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
ecma_object_t *array_p = ecma_op_new_array_object (length);
|
|
return ecma_make_object_value (array_p);
|
|
} /* jerry_array */
|
|
|
|
/**
|
|
* Create a jerry_value_t representing a boolean value from the given boolean parameter.
|
|
*
|
|
* @return value of the created boolean
|
|
*/
|
|
jerry_value_t
|
|
jerry_boolean (bool value) /**< bool value from which a jerry_value_t will be created */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_make_boolean_value (value);
|
|
} /* jerry_boolean */
|
|
|
|
/**
|
|
* Create an Error object with the provided string value as the error message.
|
|
* If the message value is not a string, the created error will not have a message property.
|
|
*
|
|
* @return Error object
|
|
*/
|
|
jerry_value_t
|
|
jerry_error (jerry_error_t error_type, /**< type of error */
|
|
const jerry_value_t message) /**< message of the error */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
ecma_string_t *message_p = NULL;
|
|
if (ecma_is_value_string (message))
|
|
{
|
|
message_p = ecma_get_string_from_value (message);
|
|
}
|
|
|
|
ecma_object_t *error_object_p = ecma_new_standard_error ((jerry_error_t) error_type, message_p);
|
|
|
|
return ecma_make_object_value (error_object_p);
|
|
} /* jerry_error */
|
|
|
|
/**
|
|
* Create an Error object with a zero-terminated string as a message. If the message string is NULL, the created error
|
|
* will not have a message property.
|
|
*
|
|
* @return Error object
|
|
*/
|
|
jerry_value_t
|
|
jerry_error_sz (jerry_error_t error_type, /**< type of error */
|
|
const char *message_p) /**< value of 'message' property
|
|
* of constructed error object */
|
|
{
|
|
jerry_value_t message = ECMA_VALUE_UNDEFINED;
|
|
|
|
if (message_p != NULL)
|
|
{
|
|
message = jerry_string_sz (message_p);
|
|
}
|
|
|
|
ecma_value_t error = jerry_error (error_type, message);
|
|
ecma_free_value (message);
|
|
|
|
return error;
|
|
} /* jerry_error_sz */
|
|
|
|
/**
|
|
* Create an exception by constructing an Error object with the specified type and the provided string value as the
|
|
* error message. If the message value is not a string, the created error will not have a message property.
|
|
*
|
|
* @return exception value
|
|
*/
|
|
jerry_value_t
|
|
jerry_throw (jerry_error_t error_type, /**< type of error */
|
|
const jerry_value_t message) /**< message value */
|
|
{
|
|
return jerry_throw_value (jerry_error (error_type, message), true);
|
|
} /* jerry_throw */
|
|
|
|
/**
|
|
* Create an exception by constructing an Error object with the specified type and the provided zero-terminated ASCII
|
|
* string as the error message. If the message string is NULL, the created error will not have a message property.
|
|
*
|
|
* @return exception value
|
|
*/
|
|
jerry_value_t
|
|
jerry_throw_sz (jerry_error_t error_type, /**< type of error */
|
|
const char *message_p) /**< value of 'message' property
|
|
* of constructed error object */
|
|
{
|
|
return jerry_throw_value (jerry_error_sz (error_type, message_p), true);
|
|
} /* jerry_throw_sz */
|
|
|
|
/**
|
|
* Create an external function object
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the constructed function object
|
|
*/
|
|
jerry_value_t
|
|
jerry_function_external (jerry_external_handler_t handler) /**< native handler
|
|
* for the function */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
ecma_object_t *func_obj_p = ecma_op_create_external_function_object (handler);
|
|
return ecma_make_object_value (func_obj_p);
|
|
} /* jerry_function_external */
|
|
|
|
/**
|
|
* Creates a jerry_value_t representing a number value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return jerry_value_t created from the given double argument.
|
|
*/
|
|
jerry_value_t
|
|
jerry_number (double value) /**< double value from which a jerry_value_t will be created */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_make_number_value ((ecma_number_t) value);
|
|
} /* jerry_number */
|
|
|
|
/**
|
|
* Creates a jerry_value_t representing a positive or negative infinity value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return jerry_value_t representing an infinity value.
|
|
*/
|
|
jerry_value_t
|
|
jerry_infinity (bool sign) /**< true for negative Infinity
|
|
* false for positive Infinity */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_make_number_value (ecma_number_make_infinity (sign));
|
|
} /* jerry_infinity */
|
|
|
|
/**
|
|
* Creates a jerry_value_t representing a not-a-number value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return jerry_value_t representing a not-a-number value.
|
|
*/
|
|
jerry_value_t
|
|
jerry_nan (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_make_nan_value ();
|
|
} /* jerry_nan */
|
|
|
|
/**
|
|
* Creates a jerry_value_t representing an undefined value.
|
|
*
|
|
* @return value of undefined
|
|
*/
|
|
jerry_value_t
|
|
jerry_undefined (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ECMA_VALUE_UNDEFINED;
|
|
} /* jerry_undefined */
|
|
|
|
/**
|
|
* Creates and returns a jerry_value_t with type null object.
|
|
*
|
|
* @return jerry_value_t representing null
|
|
*/
|
|
jerry_value_t
|
|
jerry_null (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ECMA_VALUE_NULL;
|
|
} /* jerry_null */
|
|
|
|
/**
|
|
* Create new JavaScript object, like with new Object().
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the created object
|
|
*/
|
|
jerry_value_t
|
|
jerry_object (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_make_object_value (ecma_op_create_object_object_noarg ());
|
|
} /* jerry_object */
|
|
|
|
/**
|
|
* Create an empty Promise object which can be resolved/rejected later
|
|
* by calling jerry_promise_resolve or jerry_promise_reject.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the created object
|
|
*/
|
|
jerry_value_t
|
|
jerry_promise (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
return jerry_return (ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_VALUE_UNDEFINED, NULL));
|
|
#else /* !JERRY_ESNEXT */
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROMISE_NOT_SUPPORTED));
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_promise */
|
|
|
|
/**
|
|
* Create a new Proxy object with the given target and handler
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the created Proxy object
|
|
*/
|
|
jerry_value_t
|
|
jerry_proxy (const jerry_value_t target, /**< target argument */
|
|
const jerry_value_t handler) /**< handler argument */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (target) || ecma_is_value_exception (handler))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
ecma_object_t *proxy_p = ecma_proxy_create (target, handler, 0);
|
|
|
|
if (proxy_p == NULL)
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
return ecma_make_object_value (proxy_p);
|
|
#else /* !JERRY_BUILTIN_PROXY */
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROXY_IS_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
} /* jerry_proxy */
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
|
|
JERRY_STATIC_ASSERT ((int) JERRY_PROXY_SKIP_RESULT_VALIDATION == (int) ECMA_PROXY_SKIP_RESULT_VALIDATION,
|
|
jerry_and_ecma_proxy_skip_result_validation_must_be_equal);
|
|
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
/**
|
|
* Create a new Proxy object with the given target, handler, and special options
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the created Proxy object
|
|
*/
|
|
jerry_value_t
|
|
jerry_proxy_custom (const jerry_value_t target, /**< target argument */
|
|
const jerry_value_t handler, /**< handler argument */
|
|
uint32_t flags) /**< jerry_proxy_custom_behavior_t option bits */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (target) || ecma_is_value_exception (handler))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
flags &= JERRY_PROXY_SKIP_RESULT_VALIDATION;
|
|
|
|
ecma_object_t *proxy_p = ecma_proxy_create (target, handler, flags);
|
|
|
|
if (proxy_p == NULL)
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
return ecma_make_object_value (proxy_p);
|
|
#else /* !JERRY_BUILTIN_PROXY */
|
|
JERRY_UNUSED (flags);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROXY_IS_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
} /* jerry_proxy_custom */
|
|
|
|
/**
|
|
* Create string value from the input zero-terminated ASCII string.
|
|
*
|
|
* @return created string
|
|
*/
|
|
jerry_value_t
|
|
jerry_string_sz (const char *str_p) /**< pointer to string */
|
|
{
|
|
const jerry_char_t *data_p = (const jerry_char_t *) str_p;
|
|
return jerry_string (data_p, lit_zt_utf8_string_size (data_p), JERRY_ENCODING_CESU8);
|
|
} /* jerry_string_sz */
|
|
|
|
/**
|
|
* Create a string value from the input buffer using the specified encoding.
|
|
* The content of the buffer is assumed to be valid in the specified encoding, it's the callers responsibility to
|
|
* validate the input.
|
|
*
|
|
* See also: jerry_validate_string
|
|
*
|
|
* @return created string
|
|
*/
|
|
jerry_value_t
|
|
jerry_string (const jerry_char_t *buffer_p, /**< pointer to buffer */
|
|
jerry_size_t buffer_size, /**< buffer size */
|
|
jerry_encoding_t encoding) /**< buffer encoding */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
ecma_string_t *ecma_str_p = NULL;
|
|
JERRY_ASSERT (jerry_validate_string (buffer_p, buffer_size, encoding));
|
|
|
|
switch (encoding)
|
|
{
|
|
case JERRY_ENCODING_CESU8:
|
|
{
|
|
ecma_str_p = ecma_new_ecma_string_from_utf8 (buffer_p, buffer_size);
|
|
break;
|
|
}
|
|
case JERRY_ENCODING_UTF8:
|
|
{
|
|
ecma_str_p = ecma_new_ecma_string_from_utf8_converted_to_cesu8 (buffer_p, buffer_size);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INVALID_ENCODING));
|
|
}
|
|
}
|
|
|
|
return ecma_make_string_value (ecma_str_p);
|
|
} /* jerry_string */
|
|
|
|
/**
|
|
* Create external string from input zero-terminated ASCII string.
|
|
*
|
|
* @return created external string
|
|
*/
|
|
jerry_value_t
|
|
jerry_string_external_sz (const char *str_p, /**< pointer to string */
|
|
void *user_p) /**< user pointer passed to the callback when the string is freed */
|
|
{
|
|
const jerry_char_t *data_p = (const jerry_char_t *) str_p;
|
|
return jerry_string_external (data_p, lit_zt_utf8_string_size (data_p), user_p);
|
|
} /* jerry_string_external_sz */
|
|
|
|
/**
|
|
* Create external string from a valid CESU-8 encoded string.
|
|
* The content of the buffer is assumed be encoded correctly, it's the callers responsibility to
|
|
* validate the input.
|
|
*
|
|
* See also: jerry_validate_string
|
|
*
|
|
* @return created external string
|
|
*/
|
|
jerry_value_t
|
|
jerry_string_external (const jerry_char_t *buffer_p, /**< pointer to string */
|
|
jerry_size_t buffer_size, /**< string size */
|
|
void *user_p) /**< user pointer passed to the callback when the string is freed */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
JERRY_ASSERT (jerry_validate_string (buffer_p, buffer_size, JERRY_ENCODING_CESU8));
|
|
ecma_string_t *ecma_str_p = ecma_new_ecma_external_string_from_cesu8 (buffer_p, buffer_size, user_p);
|
|
return ecma_make_string_value (ecma_str_p);
|
|
} /* jerry_string_external_sz_sz */
|
|
|
|
/**
|
|
* Create symbol with a description value
|
|
*
|
|
* Note: The given argument is converted to string. This operation can throw an exception.
|
|
*
|
|
* @return created symbol,
|
|
* or thrown exception
|
|
*/
|
|
jerry_value_t
|
|
jerry_symbol_with_description (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
#if JERRY_ESNEXT
|
|
return jerry_return (ecma_op_create_symbol (&value, 1));
|
|
#else /* !JERRY_ESNEXT */
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SYMBOL_NOT_SUPPORTED));
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_symbol_with_description */
|
|
|
|
/**
|
|
* Create BigInt from a sequence of uint64 digits.
|
|
*
|
|
* Note: This operation can throw an exception.
|
|
*
|
|
* @return created bigint,
|
|
* or thrown exception
|
|
*/
|
|
jerry_value_t
|
|
jerry_bigint (const uint64_t *digits_p, /**< BigInt digits (lowest digit first) */
|
|
uint32_t digit_count, /**< number of BigInt digits */
|
|
bool sign) /**< sign bit, true if the result should be negative */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_BIGINT
|
|
return jerry_return (ecma_bigint_create_from_digits (digits_p, digit_count, sign));
|
|
#else /* !JERRY_BUILTIN_BIGINT */
|
|
JERRY_UNUSED (digits_p);
|
|
JERRY_UNUSED (digit_count);
|
|
JERRY_UNUSED (sign);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_BIGINT_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
} /* jerry_bigint */
|
|
|
|
/**
|
|
* Creates a RegExp object with the given ASCII pattern and flags.
|
|
*
|
|
* @return value of the constructed RegExp object.
|
|
*/
|
|
jerry_value_t
|
|
jerry_regexp_sz (const char *pattern_p, /**< RegExp pattern as zero-terminated ASCII string */
|
|
uint16_t flags) /**< RegExp flags */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
jerry_value_t pattern = jerry_string_sz (pattern_p);
|
|
jerry_value_t result = jerry_regexp (pattern, flags);
|
|
|
|
jerry_value_free (pattern);
|
|
return jerry_return (result);
|
|
} /* jerry_regexp_sz */
|
|
|
|
/**
|
|
* Creates a RegExp object with the given pattern and flags.
|
|
*
|
|
* @return value of the constructed RegExp object.
|
|
*/
|
|
jerry_value_t
|
|
jerry_regexp (const jerry_value_t pattern, /**< pattern string */
|
|
uint16_t flags) /**< RegExp flags */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_REGEXP
|
|
if (!ecma_is_value_string (pattern))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL);
|
|
|
|
if (JERRY_UNLIKELY (regexp_obj_p == NULL))
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
jerry_value_t result = ecma_op_create_regexp_with_flags (regexp_obj_p, pattern, flags);
|
|
|
|
return jerry_return (result);
|
|
|
|
#else /* !JERRY_BUILTIN_REGEXP */
|
|
JERRY_UNUSED (pattern);
|
|
JERRY_UNUSED (flags);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_REGEXP_IS_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_REGEXP */
|
|
} /* jerry_regexp */
|
|
|
|
/**
|
|
* Creates a new realm (global object).
|
|
*
|
|
* @return new realm object
|
|
*/
|
|
jerry_value_t
|
|
jerry_realm (void)
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_REALMS
|
|
ecma_global_object_t *global_object_p = ecma_builtin_create_global_object ();
|
|
return ecma_make_object_value ((ecma_object_t *) global_object_p);
|
|
#else /* !JERRY_BUILTIN_REALMS */
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_REALMS_ARE_DISABLED));
|
|
#endif /* JERRY_BUILTIN_REALMS */
|
|
} /* jerry_realm */
|
|
|
|
/**
|
|
* Get length of an array object
|
|
*
|
|
* Note:
|
|
* Returns 0, if the value parameter is not an array object.
|
|
*
|
|
* @return length of the given array
|
|
*/
|
|
jerry_length_t
|
|
jerry_array_length (const jerry_value_t value) /**< api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!jerry_value_is_object (value))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ecma_object_t *object_p = ecma_get_object_from_value (value);
|
|
|
|
if (JERRY_LIKELY (ecma_get_object_base_type (object_p) == ECMA_OBJECT_BASE_TYPE_ARRAY))
|
|
{
|
|
return ecma_array_get_length (object_p);
|
|
}
|
|
|
|
return 0;
|
|
} /* jerry_array_length */
|
|
|
|
/**
|
|
* Get the size of a string value in the specified encoding.
|
|
*
|
|
* @return number of bytes required by the string,
|
|
* 0 - if value is not a string
|
|
*/
|
|
jerry_size_t
|
|
jerry_string_size (const jerry_value_t value, /**< input string */
|
|
jerry_encoding_t encoding) /**< encoding */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_string (value))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
switch (encoding)
|
|
{
|
|
case JERRY_ENCODING_CESU8:
|
|
{
|
|
return ecma_string_get_size (ecma_get_string_from_value (value));
|
|
}
|
|
case JERRY_ENCODING_UTF8:
|
|
{
|
|
return ecma_string_get_utf8_size (ecma_get_string_from_value (value));
|
|
}
|
|
default:
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
} /* jerry_string_size */
|
|
|
|
/**
|
|
* Get length of a string value
|
|
*
|
|
* @return number of characters in the string
|
|
* 0 - if value is not a string
|
|
*/
|
|
jerry_length_t
|
|
jerry_string_length (const jerry_value_t value) /**< input string */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_string (value))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return ecma_string_get_length (ecma_get_string_from_value (value));
|
|
} /* jerry_string_length */
|
|
|
|
/**
|
|
* Copy the characters of a string into the specified buffer using the specified encoding. The string is truncated to
|
|
* fit the buffer. If the value is not a string, nothing will be copied to the buffer.
|
|
*
|
|
* @return number of bytes copied to the buffer
|
|
*/
|
|
jerry_size_t
|
|
jerry_string_to_buffer (const jerry_value_t value, /**< input string value */
|
|
jerry_encoding_t encoding, /**< output encoding */
|
|
jerry_char_t *buffer_p, /**< [out] output characters buffer */
|
|
jerry_size_t buffer_size) /**< size of output buffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_string (value) || buffer_p == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ecma_string_t *str_p = ecma_get_string_from_value (value);
|
|
|
|
return ecma_string_copy_to_buffer (str_p, (lit_utf8_byte_t *) buffer_p, buffer_size, encoding);
|
|
} /* jerry_string_to_char_buffer */
|
|
|
|
/**
|
|
* Create a substring of the input string value.
|
|
* Return an empty string if input value is not a string.
|
|
*
|
|
* @param value the input string value
|
|
* @param start start position of the substring
|
|
* @param end end position of the substring
|
|
*
|
|
* @return created string
|
|
*/
|
|
jerry_value_t
|
|
jerry_string_substr (const jerry_value_t value, jerry_length_t start, jerry_length_t end)
|
|
{
|
|
if (!ecma_is_value_string (value))
|
|
{
|
|
return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
|
|
}
|
|
|
|
return ecma_make_string_value (ecma_string_substr (ecma_get_string_from_value (value), start, end));
|
|
} /* jerry_string_substr */
|
|
|
|
/**
|
|
* Iterate over the input string value in the specified encoding, visiting each unit of the encoded string once. If
|
|
* the input value is not a string, the function will do nothing.
|
|
*
|
|
* @param value the input string value
|
|
* @param callback callback function called for each byte of the encoded string.
|
|
* @param encoding the requested encoding for the string
|
|
* @param user_p User pointer passed to the callback function
|
|
*/
|
|
void
|
|
jerry_string_iterate (const jerry_value_t value,
|
|
jerry_encoding_t encoding,
|
|
jerry_string_iterate_cb_t callback,
|
|
void *user_p)
|
|
{
|
|
if (!ecma_is_value_string (value))
|
|
{
|
|
return;
|
|
}
|
|
|
|
ecma_string_t *str_p = ecma_get_string_from_value (value);
|
|
ECMA_STRING_TO_UTF8_STRING (str_p, buffer_p, buffer_size);
|
|
|
|
const lit_utf8_byte_t *current_p = buffer_p;
|
|
const lit_utf8_byte_t *end_p = buffer_p + buffer_size;
|
|
|
|
switch (encoding)
|
|
{
|
|
case JERRY_ENCODING_UTF8:
|
|
{
|
|
while (current_p < end_p)
|
|
{
|
|
if (JERRY_UNLIKELY (*current_p >= LIT_UTF8_3_BYTE_MARKER))
|
|
{
|
|
lit_code_point_t cp;
|
|
lit_utf8_size_t read_size = lit_read_code_point_from_cesu8 (current_p, end_p, &cp);
|
|
|
|
lit_utf8_byte_t bytes[LIT_UTF8_MAX_BYTES_IN_CODE_POINT];
|
|
lit_utf8_size_t encoded_size = lit_code_point_to_utf8 (cp, bytes);
|
|
|
|
for (uint32_t i = 0; i < encoded_size; i++)
|
|
{
|
|
callback (bytes[i], user_p);
|
|
}
|
|
|
|
current_p += read_size;
|
|
continue;
|
|
}
|
|
|
|
callback (*current_p++, user_p);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case JERRY_ENCODING_CESU8:
|
|
{
|
|
while (current_p < end_p)
|
|
{
|
|
callback (*current_p++, user_p);
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size);
|
|
} /* jerry_string_iterate */
|
|
|
|
/**
|
|
* Sets the global callback which is called when an external string is freed.
|
|
*/
|
|
void
|
|
jerry_string_external_on_free (jerry_external_string_free_cb_t callback) /**< free callback */
|
|
{
|
|
JERRY_CONTEXT (external_string_free_callback_p) = callback;
|
|
} /* jerry_string_external_on_free */
|
|
|
|
/**
|
|
* Returns the user pointer assigned to an external string.
|
|
*
|
|
* @return user pointer, if value is an external string
|
|
* NULL, otherwise
|
|
*/
|
|
void *
|
|
jerry_string_user_ptr (const jerry_value_t value, /**< string value */
|
|
bool *is_external) /**< [out] true - if value is an external string,
|
|
* false - otherwise */
|
|
{
|
|
if (is_external != NULL)
|
|
{
|
|
*is_external = false;
|
|
}
|
|
|
|
if (!ecma_is_value_string (value))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ecma_string_t *string_p = ecma_get_string_from_value (value);
|
|
|
|
if (ECMA_IS_DIRECT_STRING (string_p)
|
|
|| ECMA_STRING_GET_CONTAINER (string_p) != ECMA_STRING_CONTAINER_LONG_OR_EXTERNAL_STRING)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ecma_long_string_t *long_string_p = (ecma_long_string_t *) string_p;
|
|
|
|
if (long_string_p->string_p == ECMA_LONG_STRING_BUFFER_START (long_string_p))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (is_external != NULL)
|
|
{
|
|
*is_external = true;
|
|
}
|
|
|
|
return ((ecma_external_string_t *) string_p)->user_p;
|
|
} /* jerry_string_user_ptr */
|
|
|
|
/**
|
|
* Checks whether the object or it's prototype objects have the given property.
|
|
*
|
|
* @return raised error - if the operation fail
|
|
* true/false API value - depend on whether the property exists
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_has (const jerry_value_t object, /**< object value */
|
|
const jerry_value_t key) /**< property name (string value) */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return ECMA_VALUE_FALSE;
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key);
|
|
|
|
return jerry_return (ecma_op_object_has_property (obj_p, prop_name_p));
|
|
} /* jerry_object_has */
|
|
|
|
/**
|
|
* Checks whether the object or it's prototype objects have the given property.
|
|
*
|
|
* @return raised error - if the operation fail
|
|
* true/false API value - depend on whether the property exists
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_has_sz (const jerry_value_t object, /**< object value */
|
|
const char *key_p) /**< property key */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
jerry_value_t key_str = jerry_string_sz (key_p);
|
|
jerry_value_t result = jerry_object_has (object, key_str);
|
|
ecma_free_value (key_str);
|
|
|
|
return result;
|
|
} /* jerry_object_has */
|
|
|
|
/**
|
|
* Checks whether the object has the given property.
|
|
*
|
|
* @return ECMA_VALUE_ERROR - if the operation raises error
|
|
* ECMA_VALUE_{TRUE, FALSE} - based on whether the property exists
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_has_own (const jerry_value_t object, /**< object value */
|
|
const jerry_value_t key) /**< property name (string value) */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return ECMA_VALUE_FALSE;
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key);
|
|
|
|
return jerry_return (ecma_op_object_has_own_property (obj_p, prop_name_p));
|
|
} /* jerry_has_own_property */
|
|
|
|
/**
|
|
* Checks whether the object has the given internal property.
|
|
*
|
|
* @return true - if the internal property exists
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_object_has_internal (const jerry_value_t object, /**< object value */
|
|
const jerry_value_t key) /**< property name value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
|
|
ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL);
|
|
|
|
if (ecma_op_object_is_fast_array (obj_p))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p);
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
|
|
property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (key));
|
|
|
|
return property_p != NULL;
|
|
} /* jerry_object_has_internal */
|
|
|
|
/**
|
|
* Delete a property from an object.
|
|
*
|
|
* @return boolean value - wether the property was deleted successfully
|
|
* exception - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_delete (jerry_value_t object, /**< object value */
|
|
const jerry_value_t key) /**< property name (string value) */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ecma_op_object_delete (ecma_get_object_from_value (object), ecma_get_prop_name_from_value (key), false);
|
|
} /* jerry_object_delete */
|
|
|
|
/**
|
|
* Delete a property from an object.
|
|
*
|
|
* @return boolean value - wether the property was deleted successfully
|
|
* exception - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_delete_sz (jerry_value_t object, /**< object value */
|
|
const char *key_p) /**< property key */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
jerry_value_t key_str = jerry_string_sz (key_p);
|
|
jerry_value_t result = jerry_object_delete (object, key_str);
|
|
ecma_free_value (key_str);
|
|
|
|
return result;
|
|
} /* jerry_object_delete */
|
|
|
|
/**
|
|
* Delete indexed property from the specified object.
|
|
*
|
|
* @return boolean value - wether the property was deleted successfully
|
|
* false - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_delete_index (jerry_value_t object, /**< object value */
|
|
uint32_t index) /**< index to be written */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_string_t *str_idx_p = ecma_new_ecma_string_from_uint32 (index);
|
|
ecma_value_t ret_value = ecma_op_object_delete (ecma_get_object_from_value (object), str_idx_p, false);
|
|
ecma_deref_ecma_string (str_idx_p);
|
|
|
|
return ret_value;
|
|
} /* jerry_object_delete_index */
|
|
|
|
/**
|
|
* Delete an internal property from an object.
|
|
*
|
|
* @return true - if property was deleted successfully
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_object_delete_internal (jerry_value_t object, /**< object value */
|
|
const jerry_value_t key) /**< property name value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
|
|
ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL);
|
|
|
|
if (ecma_op_object_is_fast_array (obj_p))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p);
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
|
|
property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (key));
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
ecma_delete_property (internal_object_p, ECMA_PROPERTY_VALUE_PTR (property_p));
|
|
|
|
return true;
|
|
} /* jerry_object_delete_internal */
|
|
|
|
/**
|
|
* Get value of a property to the specified object with the given name.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the property - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_get (const jerry_value_t object, /**< object value */
|
|
const jerry_value_t key) /**< property name (string value) */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
jerry_value_t ret_value =
|
|
ecma_op_object_get (ecma_get_object_from_value (object), ecma_get_prop_name_from_value (key));
|
|
return jerry_return (ret_value);
|
|
} /* jerry_object_get */
|
|
|
|
/**
|
|
* Get value of a property to the specified object with the given name.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the property - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_get_sz (const jerry_value_t object, /**< object value */
|
|
const char *key_p) /**< property key */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
jerry_value_t key_str = jerry_string_sz (key_p);
|
|
jerry_value_t result = jerry_object_get (object, key_str);
|
|
ecma_free_value (key_str);
|
|
|
|
return result;
|
|
} /* jerry_object_get */
|
|
|
|
/**
|
|
* Get value by an index from the specified object.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the property specified by the index - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_get_index (const jerry_value_t object, /**< object value */
|
|
uint32_t index) /**< index to be written */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_value_t ret_value = ecma_op_object_get_by_index (ecma_get_object_from_value (object), index);
|
|
|
|
return jerry_return (ret_value);
|
|
} /* jerry_object_get_index */
|
|
|
|
/**
|
|
* Get the own property value of an object with the given name.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the property - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_find_own (const jerry_value_t object, /**< object value */
|
|
const jerry_value_t key, /**< property name (string value) */
|
|
const jerry_value_t receiver, /**< receiver object value */
|
|
bool *found_p) /**< [out] true, if the property is found
|
|
* or object is a Proxy object, false otherwise */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (found_p != NULL)
|
|
{
|
|
*found_p = false;
|
|
}
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key) || !ecma_is_value_object (receiver))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_object_t *object_p = ecma_get_object_from_value (object);
|
|
ecma_string_t *property_name_p = ecma_get_prop_name_from_value (key);
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (ECMA_OBJECT_IS_PROXY (object_p))
|
|
{
|
|
if (found_p != NULL)
|
|
{
|
|
*found_p = true;
|
|
}
|
|
|
|
return jerry_return (ecma_proxy_object_get (object_p, property_name_p, receiver));
|
|
}
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
ecma_value_t ret_value = ecma_op_object_find_own (receiver, object_p, property_name_p);
|
|
|
|
if (ecma_is_value_found (ret_value))
|
|
{
|
|
if (found_p != NULL)
|
|
{
|
|
*found_p = true;
|
|
}
|
|
|
|
return jerry_return (ret_value);
|
|
}
|
|
|
|
return ECMA_VALUE_UNDEFINED;
|
|
} /* jerry_object_find_own */
|
|
|
|
/**
|
|
* Get value of an internal property to the specified object with the given name.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return value of the internal property - if the internal property exists
|
|
* undefined value - if the internal does not property exists
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_get_internal (const jerry_value_t object, /**< object value */
|
|
const jerry_value_t key) /**< property name value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
|
|
ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL);
|
|
|
|
if (ecma_op_object_is_fast_array (obj_p))
|
|
{
|
|
return jerry_return (ECMA_VALUE_UNDEFINED);
|
|
}
|
|
|
|
ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p);
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
return jerry_return (ECMA_VALUE_UNDEFINED);
|
|
}
|
|
|
|
ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
|
|
property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (key));
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
return jerry_return (ECMA_VALUE_UNDEFINED);
|
|
}
|
|
|
|
return jerry_return (ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value));
|
|
} /* jerry_object_get_internal */
|
|
|
|
/**
|
|
* Set a property to the specified object with the given name.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return true value - if the operation was successful
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_set (jerry_value_t object, /**< object value */
|
|
const jerry_value_t key, /**< property name (string value) */
|
|
const jerry_value_t value) /**< value to set */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value) || !ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
return jerry_return (
|
|
ecma_op_object_put (ecma_get_object_from_value (object), ecma_get_prop_name_from_value (key), value, true));
|
|
} /* jerry_object_set */
|
|
|
|
/**
|
|
* Set a property to the specified object with the given name.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return true value - if the operation was successful
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_set_sz (jerry_value_t object, /**< object value */
|
|
const char *key_p, /**< property key */
|
|
const jerry_value_t value) /**< value to set */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
jerry_value_t key_str = jerry_string_sz (key_p);
|
|
jerry_value_t result = jerry_object_set (object, key_str, value);
|
|
ecma_free_value (key_str);
|
|
|
|
return result;
|
|
} /* jerry_object_set */
|
|
|
|
/**
|
|
* Set indexed value in the specified object
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return true value - if the operation was successful
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_set_index (jerry_value_t object, /**< object value */
|
|
uint32_t index, /**< index to be written */
|
|
const jerry_value_t value) /**< value to set */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value) || !ecma_is_value_object (object))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_value_t ret_value = ecma_op_object_put_by_index (ecma_get_object_from_value (object), index, value, true);
|
|
|
|
return jerry_return (ret_value);
|
|
} /* jerry_object_set_index */
|
|
|
|
/**
|
|
* Set an internal property to the specified object with the given name.
|
|
*
|
|
* Note:
|
|
* - the property cannot be accessed from the JavaScript context, only from the public API
|
|
* - returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return true value - if the operation was successful
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
bool
|
|
jerry_object_set_internal (jerry_value_t object, /**< object value */
|
|
const jerry_value_t key, /**< property name value */
|
|
const jerry_value_t value) /**< value to set */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (value) || !ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
|
|
ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL);
|
|
|
|
if (ecma_op_object_is_fast_array (obj_p))
|
|
{
|
|
ecma_fast_array_convert_to_normal (obj_p);
|
|
}
|
|
|
|
ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p);
|
|
ecma_object_t *internal_object_p;
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
ecma_property_value_t *value_p =
|
|
ecma_create_named_data_property (obj_p, internal_string_p, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL);
|
|
|
|
internal_object_p = ecma_create_object (NULL, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS);
|
|
{
|
|
ecma_extended_object_t *container_p = (ecma_extended_object_t *) internal_object_p;
|
|
container_p->u.cls.type = ECMA_OBJECT_CLASS_INTERNAL_OBJECT;
|
|
}
|
|
|
|
value_p->value = ecma_make_object_value (internal_object_p);
|
|
ecma_deref_object (internal_object_p);
|
|
}
|
|
else
|
|
{
|
|
internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
|
|
}
|
|
|
|
ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key);
|
|
property_p = ecma_find_named_property (internal_object_p, prop_name_p);
|
|
|
|
if (property_p == NULL)
|
|
{
|
|
ecma_property_value_t *value_p = ecma_create_named_data_property (internal_object_p,
|
|
prop_name_p,
|
|
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
|
|
NULL);
|
|
|
|
value_p->value = ecma_copy_value_if_not_object (value);
|
|
}
|
|
else
|
|
{
|
|
ecma_named_data_property_assign_value (internal_object_p, ECMA_PROPERTY_VALUE_PTR (property_p), value);
|
|
}
|
|
|
|
return true;
|
|
} /* jerry_object_set_internal */
|
|
|
|
/**
|
|
* Construct empty property descriptor, i.e.:
|
|
* property descriptor with all is_defined flags set to false and the rest - to default value.
|
|
*
|
|
* @return empty property descriptor
|
|
*/
|
|
jerry_property_descriptor_t
|
|
jerry_property_descriptor (void)
|
|
{
|
|
jerry_property_descriptor_t prop_desc;
|
|
|
|
prop_desc.flags = JERRY_PROP_NO_OPTS;
|
|
prop_desc.value = ECMA_VALUE_UNDEFINED;
|
|
prop_desc.getter = ECMA_VALUE_UNDEFINED;
|
|
prop_desc.setter = ECMA_VALUE_UNDEFINED;
|
|
|
|
return prop_desc;
|
|
} /* jerry_property_descriptor */
|
|
|
|
/**
|
|
* Convert a ecma_property_descriptor_t to a jerry_property_descriptor_t
|
|
*
|
|
* if error occurs the property descriptor's value field is filled with ECMA_VALUE_ERROR
|
|
*
|
|
* @return jerry_property_descriptor_t
|
|
*/
|
|
static jerry_property_descriptor_t
|
|
jerry_property_descriptor_from_ecma (const ecma_property_descriptor_t *prop_desc_p) /**<[out] property_descriptor */
|
|
{
|
|
jerry_property_descriptor_t prop_desc = jerry_property_descriptor ();
|
|
|
|
prop_desc.flags = prop_desc_p->flags;
|
|
|
|
if (prop_desc.flags & (JERRY_PROP_IS_VALUE_DEFINED))
|
|
{
|
|
prop_desc.value = prop_desc_p->value;
|
|
}
|
|
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_GET_DEFINED)
|
|
{
|
|
prop_desc.getter = ECMA_VALUE_NULL;
|
|
|
|
if (prop_desc_p->get_p != NULL)
|
|
{
|
|
prop_desc.getter = ecma_make_object_value (prop_desc_p->get_p);
|
|
JERRY_ASSERT (ecma_op_is_callable (prop_desc.getter));
|
|
}
|
|
}
|
|
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_SET_DEFINED)
|
|
{
|
|
prop_desc.setter = ECMA_VALUE_NULL;
|
|
|
|
if (prop_desc_p->set_p != NULL)
|
|
{
|
|
prop_desc.setter = ecma_make_object_value (prop_desc_p->set_p);
|
|
JERRY_ASSERT (ecma_op_is_callable (prop_desc.setter));
|
|
}
|
|
}
|
|
|
|
return prop_desc;
|
|
} /* jerry_property_descriptor_from_ecma */
|
|
|
|
/**
|
|
* Convert a jerry_property_descriptor_t to a ecma_property_descriptor_t
|
|
*
|
|
* Note:
|
|
* if error occurs the property descriptor's value field
|
|
* is set to ECMA_VALUE_ERROR, but no error is thrown
|
|
*
|
|
* @return ecma_property_descriptor_t
|
|
*/
|
|
static ecma_property_descriptor_t
|
|
jerry_property_descriptor_to_ecma (const jerry_property_descriptor_t *prop_desc_p) /**< input property_descriptor */
|
|
{
|
|
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
|
|
|
|
prop_desc.flags = prop_desc_p->flags;
|
|
|
|
/* Copy data property info. */
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_VALUE_DEFINED)
|
|
{
|
|
if (ecma_is_value_exception (prop_desc_p->value)
|
|
|| (prop_desc_p->flags & (JERRY_PROP_IS_GET_DEFINED | JERRY_PROP_IS_SET_DEFINED)))
|
|
{
|
|
prop_desc.value = ECMA_VALUE_ERROR;
|
|
return prop_desc;
|
|
}
|
|
|
|
prop_desc.value = prop_desc_p->value;
|
|
}
|
|
|
|
/* Copy accessor property info. */
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_GET_DEFINED)
|
|
{
|
|
ecma_value_t getter = prop_desc_p->getter;
|
|
|
|
if (ecma_is_value_exception (getter))
|
|
{
|
|
prop_desc.value = ECMA_VALUE_ERROR;
|
|
return prop_desc;
|
|
}
|
|
|
|
if (ecma_op_is_callable (getter))
|
|
{
|
|
prop_desc.get_p = ecma_get_object_from_value (getter);
|
|
}
|
|
else if (!ecma_is_value_null (getter))
|
|
{
|
|
prop_desc.value = ECMA_VALUE_ERROR;
|
|
return prop_desc;
|
|
}
|
|
}
|
|
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_SET_DEFINED)
|
|
{
|
|
ecma_value_t setter = prop_desc_p->setter;
|
|
|
|
if (ecma_is_value_exception (setter))
|
|
{
|
|
prop_desc.value = ECMA_VALUE_ERROR;
|
|
return prop_desc;
|
|
}
|
|
|
|
if (ecma_op_is_callable (setter))
|
|
{
|
|
prop_desc.set_p = ecma_get_object_from_value (setter);
|
|
}
|
|
else if (!ecma_is_value_null (setter))
|
|
{
|
|
prop_desc.value = ECMA_VALUE_ERROR;
|
|
return prop_desc;
|
|
}
|
|
}
|
|
|
|
const uint16_t configurable_mask = JERRY_PROP_IS_CONFIGURABLE | JERRY_PROP_IS_CONFIGURABLE_DEFINED;
|
|
const uint16_t enumerable_mask = JERRY_PROP_IS_ENUMERABLE | JERRY_PROP_IS_ENUMERABLE_DEFINED;
|
|
const uint16_t writable_mask = JERRY_PROP_IS_WRITABLE | JERRY_PROP_IS_WRITABLE_DEFINED;
|
|
|
|
if ((prop_desc_p->flags & configurable_mask) == JERRY_PROP_IS_CONFIGURABLE
|
|
|| (prop_desc_p->flags & enumerable_mask) == JERRY_PROP_IS_ENUMERABLE
|
|
|| (prop_desc_p->flags & writable_mask) == JERRY_PROP_IS_WRITABLE)
|
|
{
|
|
prop_desc.value = ECMA_VALUE_ERROR;
|
|
return prop_desc;
|
|
}
|
|
|
|
prop_desc.flags |= (uint16_t) (prop_desc_p->flags | JERRY_PROP_SHOULD_THROW);
|
|
|
|
return prop_desc;
|
|
} /* jerry_property_descriptor_to_ecma */
|
|
|
|
/** Helper function to return false value or error depending on the given flag.
|
|
*
|
|
* @return value marked with error flag - if is_throw is true
|
|
* false value - otherwise
|
|
*/
|
|
static jerry_value_t
|
|
jerry_type_error_or_false (ecma_error_msg_t msg, /**< message */
|
|
uint16_t flags) /**< property descriptor flags */
|
|
{
|
|
if (!(flags & JERRY_PROP_SHOULD_THROW))
|
|
{
|
|
return ECMA_VALUE_FALSE;
|
|
}
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (msg));
|
|
} /* jerry_type_error_or_false */
|
|
|
|
/**
|
|
* Define a property to the specified object with the given name.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return true value - if the operation was successful
|
|
* false value - if the property cannot be defined and JERRY_PROP_SHOULD_THROW is not set
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_define_own_prop (jerry_value_t object, /**< object value */
|
|
const jerry_value_t key, /**< property name (string value) */
|
|
const jerry_property_descriptor_t *prop_desc_p) /**< property descriptor */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return jerry_type_error_or_false (ECMA_ERR_WRONG_ARGS_MSG, prop_desc_p->flags);
|
|
}
|
|
|
|
if (prop_desc_p->flags & (JERRY_PROP_IS_WRITABLE_DEFINED | JERRY_PROP_IS_VALUE_DEFINED)
|
|
&& prop_desc_p->flags & (JERRY_PROP_IS_GET_DEFINED | JERRY_PROP_IS_SET_DEFINED))
|
|
{
|
|
return jerry_type_error_or_false (ECMA_ERR_WRONG_ARGS_MSG, prop_desc_p->flags);
|
|
}
|
|
|
|
ecma_property_descriptor_t prop_desc = jerry_property_descriptor_to_ecma (prop_desc_p);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (prop_desc.value))
|
|
{
|
|
return jerry_type_error_or_false (ECMA_ERR_WRONG_ARGS_MSG, prop_desc_p->flags);
|
|
}
|
|
|
|
return jerry_return (ecma_op_object_define_own_property (ecma_get_object_from_value (object),
|
|
ecma_get_prop_name_from_value (key),
|
|
&prop_desc));
|
|
} /* jerry_object_define_own_prop */
|
|
|
|
/**
|
|
* Construct property descriptor from specified property.
|
|
*
|
|
* @return true - if success, the prop_desc_p fields contains the property info
|
|
* false - otherwise, the prop_desc_p is unchanged
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_get_own_prop (const jerry_value_t object, /**< object value */
|
|
const jerry_value_t key, /**< property name (string value) */
|
|
jerry_property_descriptor_t *prop_desc_p) /**< property descriptor */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || !ecma_is_value_prop_name (key))
|
|
{
|
|
return ECMA_VALUE_FALSE;
|
|
}
|
|
|
|
ecma_property_descriptor_t prop_desc;
|
|
|
|
ecma_value_t status = ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (object),
|
|
ecma_get_prop_name_from_value (key),
|
|
&prop_desc);
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (ECMA_IS_VALUE_ERROR (status))
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
if (!ecma_is_value_true (status))
|
|
{
|
|
return ECMA_VALUE_FALSE;
|
|
}
|
|
|
|
/* The flags are always filled in the returned descriptor. */
|
|
JERRY_ASSERT (
|
|
(prop_desc.flags & JERRY_PROP_IS_CONFIGURABLE_DEFINED) && (prop_desc.flags & JERRY_PROP_IS_ENUMERABLE_DEFINED)
|
|
&& ((prop_desc.flags & JERRY_PROP_IS_WRITABLE_DEFINED) || !(prop_desc.flags & JERRY_PROP_IS_VALUE_DEFINED)));
|
|
|
|
prop_desc_p->flags = prop_desc.flags;
|
|
prop_desc_p->value = ECMA_VALUE_UNDEFINED;
|
|
prop_desc_p->getter = ECMA_VALUE_UNDEFINED;
|
|
prop_desc_p->setter = ECMA_VALUE_UNDEFINED;
|
|
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_VALUE_DEFINED)
|
|
{
|
|
prop_desc_p->value = prop_desc.value;
|
|
}
|
|
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_GET_DEFINED)
|
|
{
|
|
if (prop_desc.get_p != NULL)
|
|
{
|
|
prop_desc_p->getter = ecma_make_object_value (prop_desc.get_p);
|
|
}
|
|
else
|
|
{
|
|
prop_desc_p->getter = ECMA_VALUE_NULL;
|
|
}
|
|
}
|
|
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_SET_DEFINED)
|
|
{
|
|
if (prop_desc.set_p != NULL)
|
|
{
|
|
prop_desc_p->setter = ecma_make_object_value (prop_desc.set_p);
|
|
}
|
|
else
|
|
{
|
|
prop_desc_p->setter = ECMA_VALUE_NULL;
|
|
}
|
|
}
|
|
|
|
return ECMA_VALUE_TRUE;
|
|
} /* jerry_object_get_own_prop */
|
|
|
|
/**
|
|
* Free fields of property descriptor (setter, getter and value).
|
|
*/
|
|
void
|
|
jerry_property_descriptor_free (jerry_property_descriptor_t *prop_desc_p) /**< property descriptor */
|
|
{
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_VALUE_DEFINED)
|
|
{
|
|
jerry_value_free (prop_desc_p->value);
|
|
}
|
|
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_GET_DEFINED)
|
|
{
|
|
jerry_value_free (prop_desc_p->getter);
|
|
}
|
|
|
|
if (prop_desc_p->flags & JERRY_PROP_IS_SET_DEFINED)
|
|
{
|
|
jerry_value_free (prop_desc_p->setter);
|
|
}
|
|
} /* jerry_property_descriptor_free */
|
|
|
|
/**
|
|
* Call function specified by a function value
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
* error flag must not be set for any arguments of this function.
|
|
*
|
|
* @return returned jerry value of the called function
|
|
*/
|
|
jerry_value_t
|
|
jerry_call (const jerry_value_t func_object, /**< function object to call */
|
|
const jerry_value_t this_value, /**< object for 'this' binding */
|
|
const jerry_value_t *args_p, /**< function's call arguments */
|
|
jerry_size_t args_count) /**< number of the arguments */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_exception (this_value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
for (jerry_size_t i = 0; i < args_count; i++)
|
|
{
|
|
if (ecma_is_value_exception (args_p[i]))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
}
|
|
|
|
return jerry_return (ecma_op_function_validated_call (func_object, this_value, args_p, args_count));
|
|
} /* jerry_call */
|
|
|
|
/**
|
|
* Construct object value invoking specified function value as a constructor
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
* error flag must not be set for any arguments of this function.
|
|
*
|
|
* @return returned jerry value of the invoked constructor
|
|
*/
|
|
jerry_value_t
|
|
jerry_construct (const jerry_value_t func_object, /**< function object to call */
|
|
const jerry_value_t *args_p, /**< function's call arguments
|
|
* (NULL if arguments number is zero) */
|
|
jerry_size_t args_count) /**< number of the arguments */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!jerry_value_is_constructor (func_object))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
for (jerry_size_t i = 0; i < args_count; i++)
|
|
{
|
|
if (ecma_is_value_exception (args_p[i]))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
}
|
|
|
|
return jerry_return (ecma_op_function_construct (ecma_get_object_from_value (func_object),
|
|
ecma_get_object_from_value (func_object),
|
|
args_p,
|
|
args_count));
|
|
} /* jerry_construct */
|
|
|
|
/**
|
|
* Get keys of the specified object value
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return array object value - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_keys (const jerry_value_t object) /**< object value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_collection_t *prop_names =
|
|
ecma_op_object_get_enumerable_property_names (ecma_get_object_from_value (object), ECMA_ENUMERABLE_PROPERTY_KEYS);
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (JERRY_UNLIKELY (prop_names == NULL))
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
return ecma_op_new_array_object_from_collection (prop_names, false);
|
|
} /* jerry_object_keys */
|
|
|
|
/**
|
|
* Get the prototype of the specified object
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return prototype object or null value - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_proto (const jerry_value_t object) /**< object value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (ECMA_OBJECT_IS_PROXY (obj_p))
|
|
{
|
|
return jerry_return (ecma_proxy_object_get_prototype_of (obj_p));
|
|
}
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
if (obj_p->u2.prototype_cp == JMEM_CP_NULL)
|
|
{
|
|
return ECMA_VALUE_NULL;
|
|
}
|
|
|
|
ecma_object_t *proto_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_p->u2.prototype_cp);
|
|
ecma_ref_object (proto_obj_p);
|
|
|
|
return ecma_make_object_value (proto_obj_p);
|
|
} /* jerry_object_proto */
|
|
|
|
/**
|
|
* Set the prototype of the specified object
|
|
*
|
|
* @return true value - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_set_proto (jerry_value_t object, /**< object value */
|
|
const jerry_value_t proto) /**< prototype object value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object) || ecma_is_value_exception (proto)
|
|
|| (!ecma_is_value_object (proto) && !ecma_is_value_null (proto)))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (ECMA_OBJECT_IS_PROXY (obj_p))
|
|
{
|
|
return jerry_return (ecma_proxy_object_set_prototype_of (obj_p, proto));
|
|
}
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
return ecma_op_ordinary_object_set_prototype_of (obj_p, proto);
|
|
} /* jerry_object_set_proto */
|
|
|
|
/**
|
|
* Utility to check if a given object can be used for the foreach api calls.
|
|
*
|
|
* Some objects/classes uses extra internal objects to correctly store data.
|
|
* These extre object should never be exposed externally to the API user.
|
|
*
|
|
* @returns true - if the user can access the object in the callback.
|
|
* false - if the object is an internal object which should no be accessed by the user.
|
|
*/
|
|
static bool
|
|
jerry_object_is_valid_foreach (ecma_object_t *object_p) /**< object to test */
|
|
{
|
|
if (ecma_is_lexical_environment (object_p))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_object_type_t object_type = ecma_get_object_type (object_p);
|
|
|
|
if (object_type == ECMA_OBJECT_TYPE_CLASS)
|
|
{
|
|
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
|
|
switch (ext_object_p->u.cls.type)
|
|
{
|
|
/* An object's internal property object should not be iterable by foreach. */
|
|
case ECMA_OBJECT_CLASS_INTERNAL_OBJECT:
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
} /* jerry_object_is_valid_foreach */
|
|
|
|
/**
|
|
* Traverse objects.
|
|
*
|
|
* @return true - traversal was interrupted by the callback.
|
|
* false - otherwise - traversal visited all objects.
|
|
*/
|
|
bool
|
|
jerry_foreach_live_object (jerry_foreach_live_object_cb_t callback, /**< function pointer of the iterator function */
|
|
void *user_data_p) /**< pointer to user data */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
JERRY_ASSERT (callback != NULL);
|
|
|
|
jmem_cpointer_t iter_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
|
|
|
|
while (iter_cp != JMEM_CP_NULL)
|
|
{
|
|
ecma_object_t *iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, iter_cp);
|
|
|
|
if (jerry_object_is_valid_foreach (iter_p) && !callback (ecma_make_object_value (iter_p), user_data_p))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
iter_cp = iter_p->gc_next_cp;
|
|
}
|
|
|
|
return false;
|
|
} /* jerry_foreach_live_object */
|
|
|
|
/**
|
|
* Traverse objects having a given native type info.
|
|
*
|
|
* @return true - traversal was interrupted by the callback.
|
|
* false - otherwise - traversal visited all objects.
|
|
*/
|
|
bool
|
|
jerry_foreach_live_object_with_info (const jerry_object_native_info_t *native_info_p, /**< the type info
|
|
* of the native pointer */
|
|
jerry_foreach_live_object_with_info_cb_t callback, /**< function to apply for
|
|
* each matching object */
|
|
void *user_data_p) /**< pointer to user data */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
JERRY_ASSERT (native_info_p != NULL);
|
|
JERRY_ASSERT (callback != NULL);
|
|
|
|
ecma_native_pointer_t *native_pointer_p;
|
|
|
|
jmem_cpointer_t iter_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
|
|
|
|
while (iter_cp != JMEM_CP_NULL)
|
|
{
|
|
ecma_object_t *iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, iter_cp);
|
|
|
|
if (jerry_object_is_valid_foreach (iter_p))
|
|
{
|
|
native_pointer_p = ecma_get_native_pointer_value (iter_p, (void *) native_info_p);
|
|
if (native_pointer_p && !callback (ecma_make_object_value (iter_p), native_pointer_p->native_p, user_data_p))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
iter_cp = iter_p->gc_next_cp;
|
|
}
|
|
|
|
return false;
|
|
} /* jerry_foreach_live_object_with_info */
|
|
|
|
/**
|
|
* Get native pointer and its type information, associated with the given native type info.
|
|
*
|
|
* Note:
|
|
* If native pointer is present, its type information is returned in out_native_pointer_p
|
|
*
|
|
* @return found native pointer,
|
|
* or NULL
|
|
*/
|
|
void *
|
|
jerry_object_get_native_ptr (const jerry_value_t object, /**< object to get native pointer from */
|
|
const jerry_object_native_info_t *native_info_p) /**< the type info
|
|
* of the native pointer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
ecma_native_pointer_t *native_pointer_p = ecma_get_native_pointer_value (obj_p, (void *) native_info_p);
|
|
|
|
if (native_pointer_p == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return native_pointer_p->native_p;
|
|
} /* jerry_object_get_native_ptr */
|
|
|
|
/**
|
|
* Set native pointer and an optional type info for the specified object.
|
|
*
|
|
*
|
|
* Note:
|
|
* If native pointer was already set for the object, its value is updated.
|
|
*
|
|
* Note:
|
|
* If a non-NULL free callback is specified in the native type info,
|
|
* it will be called by the garbage collector when the object is freed.
|
|
* Referred values by this method must have at least 1 reference. (Correct API usage satisfies this condition)
|
|
* The type info always overwrites the previous value, so passing
|
|
* a NULL value deletes the current type info.
|
|
*/
|
|
void
|
|
jerry_object_set_native_ptr (jerry_value_t object, /**< object to set native pointer in */
|
|
const jerry_object_native_info_t *native_info_p, /**< object's native type info */
|
|
void *native_pointer_p) /**< native pointer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_object (object))
|
|
{
|
|
ecma_object_t *object_p = ecma_get_object_from_value (object);
|
|
|
|
ecma_create_native_pointer_property (object_p, native_pointer_p, native_info_p);
|
|
}
|
|
} /* jerry_object_set_native_ptr */
|
|
|
|
/**
|
|
* Checks wether the argument object has a native poitner set for the specified native type info.
|
|
*
|
|
* @return true if the native pointer has been set,
|
|
* false otherwise
|
|
*/
|
|
bool
|
|
jerry_object_has_native_ptr (const jerry_value_t object, /**< object to set native pointer in */
|
|
const jerry_object_native_info_t *native_info_p) /**< object's native type info */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
ecma_native_pointer_t *native_pointer_p = ecma_get_native_pointer_value (obj_p, (void *) native_info_p);
|
|
|
|
return native_pointer_p != NULL;
|
|
} /* jerry_object_has_native_ptr */
|
|
|
|
/**
|
|
* Delete the previously set native pointer by the native type info from the specified object.
|
|
*
|
|
* Note:
|
|
* If the specified object has no matching native pointer for the given native type info
|
|
* the function has no effect.
|
|
*
|
|
* Note:
|
|
* This operation cannot throw an exception.
|
|
*
|
|
* @return true - if the native pointer has been deleted succesfully
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_object_delete_native_ptr (jerry_value_t object, /**< object to delete native pointer from */
|
|
const jerry_object_native_info_t *native_info_p) /**< object's native type info */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (ecma_is_value_object (object))
|
|
{
|
|
ecma_object_t *object_p = ecma_get_object_from_value (object);
|
|
|
|
return ecma_delete_native_pointer_property (object_p, (void *) native_info_p);
|
|
}
|
|
|
|
return false;
|
|
} /* jerry_object_delete_native_ptr */
|
|
|
|
/**
|
|
* Initialize the references stored in a buffer pointed by a native pointer.
|
|
* The references are initialized to undefined.
|
|
*/
|
|
void
|
|
jerry_native_ptr_init (void *native_pointer_p, /**< a valid non-NULL pointer to a native buffer */
|
|
const jerry_object_native_info_t *native_info_p) /**< the type info of
|
|
* the native pointer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (native_pointer_p == NULL || native_info_p == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ecma_value_t *value_p = (ecma_value_t *) (((uint8_t *) native_pointer_p) + native_info_p->offset_of_references);
|
|
ecma_value_t *end_p = value_p + native_info_p->number_of_references;
|
|
|
|
while (value_p < end_p)
|
|
{
|
|
*value_p++ = ECMA_VALUE_UNDEFINED;
|
|
}
|
|
} /* jerry_native_ptr_init */
|
|
|
|
/**
|
|
* Release the value references after a buffer pointed by a native pointer
|
|
* is not attached to an object anymore. All references are set to undefined
|
|
* similar to jerry_native_ptr_init.
|
|
*/
|
|
void
|
|
jerry_native_ptr_free (void *native_pointer_p, /**< a valid non-NULL pointer to a native buffer */
|
|
const jerry_object_native_info_t *native_info_p) /**< the type info of
|
|
* the native pointer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (native_pointer_p == NULL || native_info_p == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ecma_value_t *value_p = (ecma_value_t *) (((uint8_t *) native_pointer_p) + native_info_p->offset_of_references);
|
|
ecma_value_t *end_p = value_p + native_info_p->number_of_references;
|
|
|
|
while (value_p < end_p)
|
|
{
|
|
ecma_free_value_if_not_object (*value_p);
|
|
*value_p++ = ECMA_VALUE_UNDEFINED;
|
|
}
|
|
} /* jerry_native_ptr_free */
|
|
|
|
/**
|
|
* Updates a value reference inside the area specified by the number_of_references and
|
|
* offset_of_references fields in its corresponding jerry_object_native_info_t data.
|
|
* The area must be part of a buffer which is currently assigned to an object.
|
|
*
|
|
* Note:
|
|
* Error references are not supported, they are replaced by undefined values.
|
|
*/
|
|
void
|
|
jerry_native_ptr_set (jerry_value_t *reference_p, /**< a valid non-NULL pointer to
|
|
* a reference in a native buffer. */
|
|
const jerry_value_t value) /**< new value of the reference */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (reference_p == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ecma_free_value_if_not_object (*reference_p);
|
|
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
*reference_p = ECMA_VALUE_UNDEFINED;
|
|
return;
|
|
}
|
|
|
|
*reference_p = ecma_copy_value_if_not_object (value);
|
|
} /* jerry_native_ptr_set */
|
|
|
|
/**
|
|
* Applies the given function to the every property in the object.
|
|
*
|
|
* @return true - if object fields traversal was performed successfully, i.e.:
|
|
* - no unhandled exceptions were thrown in object fields traversal;
|
|
* - object fields traversal was stopped on callback that returned false;
|
|
* false - otherwise,
|
|
* if getter of field threw a exception or unhandled exceptions were thrown during traversal;
|
|
*/
|
|
bool
|
|
jerry_object_foreach (const jerry_value_t object, /**< object value */
|
|
jerry_object_property_foreach_cb_t foreach_p, /**< foreach function */
|
|
void *user_data_p) /**< user data for foreach function */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_object_t *object_p = ecma_get_object_from_value (object);
|
|
ecma_collection_t *names_p = ecma_op_object_enumerate (object_p);
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (names_p == NULL)
|
|
{
|
|
// TODO: Due to Proxies the return value must be changed to jerry_value_t on next release
|
|
jcontext_release_exception ();
|
|
return false;
|
|
}
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
ecma_value_t *buffer_p = names_p->buffer_p;
|
|
|
|
ecma_value_t property_value = ECMA_VALUE_EMPTY;
|
|
|
|
bool continuous = true;
|
|
|
|
for (uint32_t i = 0; continuous && (i < names_p->item_count); i++)
|
|
{
|
|
ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]);
|
|
|
|
property_value = ecma_op_object_get (object_p, property_name_p);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (property_value))
|
|
{
|
|
break;
|
|
}
|
|
|
|
continuous = foreach_p (buffer_p[i], property_value, user_data_p);
|
|
ecma_free_value (property_value);
|
|
}
|
|
|
|
ecma_collection_free (names_p);
|
|
|
|
if (!ECMA_IS_VALUE_ERROR (property_value))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
jcontext_release_exception ();
|
|
return false;
|
|
} /* jerry_object_foreach */
|
|
|
|
/**
|
|
* Gets the property keys for the given object using the selected filters.
|
|
*
|
|
* @return array containing the filtered property keys in successful operation
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_object_property_names (const jerry_value_t object, /**< object */
|
|
jerry_property_filter_t filter) /**< property filter options */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
if (!ecma_is_value_object (object))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (object);
|
|
ecma_object_t *obj_iter_p = obj_p;
|
|
ecma_collection_t *result_p = ecma_new_collection ();
|
|
|
|
ecma_ref_object (obj_iter_p);
|
|
|
|
while (true)
|
|
{
|
|
/* Step 1. Get Object.[[OwnKeys]] */
|
|
ecma_collection_t *prop_names_p = ecma_op_object_own_property_keys (obj_iter_p, filter);
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (prop_names_p == NULL)
|
|
{
|
|
ecma_deref_object (obj_iter_p);
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
for (uint32_t i = 0; i < prop_names_p->item_count; i++)
|
|
{
|
|
ecma_value_t key = prop_names_p->buffer_p[i];
|
|
ecma_string_t *key_p = ecma_get_prop_name_from_value (key);
|
|
uint32_t index = ecma_string_get_array_index (key_p);
|
|
|
|
/* Step 2. Filter by key type */
|
|
if (filter
|
|
& (JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS | JERRY_PROPERTY_FILTER_EXCLUDE_SYMBOLS
|
|
| JERRY_PROPERTY_FILTER_EXCLUDE_INTEGER_INDICES))
|
|
{
|
|
if (ecma_is_value_symbol (key))
|
|
{
|
|
if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_SYMBOLS)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (index != ECMA_STRING_NOT_ARRAY_INDEX)
|
|
{
|
|
if ((filter & JERRY_PROPERTY_FILTER_EXCLUDE_INTEGER_INDICES)
|
|
|| ((filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS)
|
|
&& !(filter & JERRY_PROPERTY_FILTER_INTEGER_INDICES_AS_NUMBER)))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (filter & JERRY_PROPERTY_FILTER_EXCLUDE_STRINGS)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Step 3. Filter property attributes */
|
|
if (filter
|
|
& (JERRY_PROPERTY_FILTER_EXCLUDE_NON_CONFIGURABLE | JERRY_PROPERTY_FILTER_EXCLUDE_NON_ENUMERABLE
|
|
| JERRY_PROPERTY_FILTER_EXCLUDE_NON_WRITABLE))
|
|
{
|
|
ecma_property_descriptor_t prop_desc;
|
|
ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_iter_p, key_p, &prop_desc);
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (ECMA_IS_VALUE_ERROR (status))
|
|
{
|
|
ecma_collection_free (prop_names_p);
|
|
ecma_collection_free (result_p);
|
|
ecma_deref_object (obj_iter_p);
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
JERRY_ASSERT (ecma_is_value_true (status));
|
|
uint16_t flags = prop_desc.flags;
|
|
ecma_free_property_descriptor (&prop_desc);
|
|
|
|
if ((!(flags & JERRY_PROP_IS_CONFIGURABLE) && (filter & JERRY_PROPERTY_FILTER_EXCLUDE_NON_CONFIGURABLE))
|
|
|| (!(flags & JERRY_PROP_IS_ENUMERABLE) && (filter & JERRY_PROPERTY_FILTER_EXCLUDE_NON_ENUMERABLE))
|
|
|| (!(flags & JERRY_PROP_IS_WRITABLE) && (filter & JERRY_PROPERTY_FILTER_EXCLUDE_NON_WRITABLE)))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (index != ECMA_STRING_NOT_ARRAY_INDEX && (filter & JERRY_PROPERTY_FILTER_INTEGER_INDICES_AS_NUMBER))
|
|
{
|
|
ecma_deref_ecma_string (key_p);
|
|
key = ecma_make_uint32_value (index);
|
|
}
|
|
else
|
|
{
|
|
ecma_ref_ecma_string (key_p);
|
|
}
|
|
|
|
if ((filter & JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN) && obj_iter_p != obj_p)
|
|
{
|
|
uint32_t duplicate_idx = 0;
|
|
while (duplicate_idx < result_p->item_count)
|
|
{
|
|
ecma_value_t value = result_p->buffer_p[duplicate_idx];
|
|
JERRY_ASSERT (ecma_is_value_prop_name (value) || ecma_is_value_number (value));
|
|
if (JERRY_UNLIKELY (ecma_is_value_number (value)))
|
|
{
|
|
if (ecma_get_number_from_value (value) == ecma_get_number_from_value (key))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else if (ecma_compare_ecma_strings (ecma_get_prop_name_from_value (value), key_p))
|
|
{
|
|
break;
|
|
}
|
|
|
|
duplicate_idx++;
|
|
}
|
|
|
|
if (duplicate_idx == result_p->item_count)
|
|
{
|
|
ecma_collection_push_back (result_p, key);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ecma_collection_push_back (result_p, key);
|
|
}
|
|
}
|
|
|
|
ecma_collection_free (prop_names_p);
|
|
|
|
/* Step 4: Traverse prototype chain */
|
|
|
|
if ((filter & JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN) != JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ecma_object_t *proto_p = ecma_op_object_get_prototype_of (obj_iter_p);
|
|
|
|
if (proto_p == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ecma_deref_object (obj_iter_p);
|
|
|
|
if (JERRY_UNLIKELY (proto_p == ECMA_OBJECT_POINTER_ERROR))
|
|
{
|
|
ecma_collection_free (result_p);
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
obj_iter_p = proto_p;
|
|
}
|
|
|
|
ecma_deref_object (obj_iter_p);
|
|
|
|
return ecma_op_new_array_object_from_collection (result_p, false);
|
|
} /* jerry_object_property_names */
|
|
|
|
/**
|
|
* FromPropertyDescriptor abstract operation.
|
|
*
|
|
* @return new jerry_value_t - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_property_descriptor_to_object (const jerry_property_descriptor_t *src_prop_desc_p) /**< property descriptor */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
ecma_property_descriptor_t prop_desc = jerry_property_descriptor_to_ecma (src_prop_desc_p);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (prop_desc.value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_object_t *desc_obj_p = ecma_op_from_property_descriptor (&prop_desc);
|
|
|
|
return ecma_make_object_value (desc_obj_p);
|
|
} /* jerry_property_descriptor_to_object */
|
|
|
|
/**
|
|
* ToPropertyDescriptor abstract operation.
|
|
*
|
|
* @return true - if the conversion is successful
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_property_descriptor_from_object (const jerry_value_t object, /**< object value */
|
|
jerry_property_descriptor_t *out_prop_desc_p) /**< [out] filled property
|
|
* descriptor if return value is
|
|
* true, unmodified otherwise */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
ecma_property_descriptor_t prop_desc;
|
|
jerry_value_t result = ecma_op_to_property_descriptor (object, &prop_desc);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (result))
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
JERRY_ASSERT (result == ECMA_VALUE_EMPTY);
|
|
|
|
*out_prop_desc_p = jerry_property_descriptor_from_ecma (&prop_desc);
|
|
return ECMA_VALUE_TRUE;
|
|
} /* jerry_property_descriptor_from_object */
|
|
|
|
/**
|
|
* Resolve a promise value with an argument.
|
|
*
|
|
* @return undefined - if success,
|
|
* exception - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_promise_resolve (jerry_value_t promise, /**< the promise value */
|
|
const jerry_value_t argument) /**< the argument */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
if (!jerry_value_is_promise (promise))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
if (ecma_is_value_exception (argument))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
return ecma_fulfill_promise_with_checks (promise, argument);
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (promise);
|
|
JERRY_UNUSED (argument);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROMISE_NOT_SUPPORTED));
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_promise_resolve */
|
|
|
|
/**
|
|
* Reject a promise value with an argument.
|
|
*
|
|
* @return undefined - if success,
|
|
* exception - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_promise_reject (jerry_value_t promise, /**< the promise value */
|
|
const jerry_value_t argument) /**< the argument */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
if (!jerry_value_is_promise (promise))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
if (ecma_is_value_exception (argument))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
return ecma_reject_promise_with_checks (promise, argument);
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (promise);
|
|
JERRY_UNUSED (argument);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROMISE_NOT_SUPPORTED));
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_promise_reject */
|
|
|
|
/**
|
|
* Get the result of a promise.
|
|
*
|
|
* @return - Promise result
|
|
* - Type error if the promise support was not enabled or the input was not a promise object
|
|
*/
|
|
jerry_value_t
|
|
jerry_promise_result (const jerry_value_t promise) /**< promise object to get the result from */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
if (!jerry_value_is_promise (promise))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
return ecma_promise_get_result (ecma_get_object_from_value (promise));
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (promise);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PROMISE_NOT_SUPPORTED));
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_promise_result */
|
|
|
|
/**
|
|
* Get the state of a promise object.
|
|
*
|
|
* @return - the state of the promise (one of the jerry_promise_state_t enum values)
|
|
* - JERRY_PROMISE_STATE_NONE is only returned if the input is not a promise object
|
|
* or the promise support was not enabled.
|
|
*/
|
|
jerry_promise_state_t
|
|
jerry_promise_state (const jerry_value_t promise) /**< promise object to get the state from */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
if (!jerry_value_is_promise (promise))
|
|
{
|
|
return JERRY_PROMISE_STATE_NONE;
|
|
}
|
|
|
|
uint16_t flags = ecma_promise_get_flags (ecma_get_object_from_value (promise));
|
|
flags &= (ECMA_PROMISE_IS_PENDING | ECMA_PROMISE_IS_FULFILLED);
|
|
|
|
return (flags ? flags : JERRY_PROMISE_STATE_REJECTED);
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (promise);
|
|
return JERRY_PROMISE_STATE_NONE;
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_promise_state */
|
|
|
|
/**
|
|
* Sets a callback for tracking Promise and async operations.
|
|
*
|
|
* Note:
|
|
* the previous callback is overwritten
|
|
*/
|
|
void
|
|
jerry_promise_on_event (jerry_promise_event_filter_t filters, /**< combination of event filters */
|
|
jerry_promise_event_cb_t callback, /**< notification callback */
|
|
void *user_p) /**< user pointer passed to the callback */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT && JERRY_PROMISE_CALLBACK
|
|
if (filters == JERRY_PROMISE_EVENT_FILTER_DISABLE || callback == NULL)
|
|
{
|
|
JERRY_CONTEXT (promise_callback_filters) = JERRY_PROMISE_EVENT_FILTER_DISABLE;
|
|
return;
|
|
}
|
|
|
|
JERRY_CONTEXT (promise_callback_filters) = (uint32_t) filters;
|
|
JERRY_CONTEXT (promise_callback) = callback;
|
|
JERRY_CONTEXT (promise_callback_user_p) = user_p;
|
|
#else /* !JERRY_ESNEXT && !JERRY_PROMISE_CALLBACK */
|
|
JERRY_UNUSED (filters);
|
|
JERRY_UNUSED (callback);
|
|
JERRY_UNUSED (user_p);
|
|
#endif /* JERRY_ESNEXT && JERRY_PROMISE_CALLBACK */
|
|
} /* jerry_promise_on_event */
|
|
|
|
/**
|
|
* Get the well-knwon symbol represented by the given `symbol` enum value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return undefined value - if invalid well-known symbol was requested
|
|
* well-known symbol value - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_symbol (jerry_well_known_symbol_t symbol) /**< jerry_well_known_symbol_t enum value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
lit_magic_string_id_t id = (lit_magic_string_id_t) (LIT_GLOBAL_SYMBOL__FIRST + symbol);
|
|
|
|
if (!LIT_IS_GLOBAL_SYMBOL (id))
|
|
{
|
|
return ECMA_VALUE_UNDEFINED;
|
|
}
|
|
|
|
return ecma_make_symbol_value (ecma_op_get_global_symbol (id));
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (symbol);
|
|
|
|
return ECMA_VALUE_UNDEFINED;
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_symbol */
|
|
|
|
/**
|
|
* Returns the description internal property of a symbol.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return string or undefined value containing the symbol's description - if success
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_symbol_description (const jerry_value_t symbol) /**< symbol value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
if (!ecma_is_value_symbol (symbol))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
/* Note: This operation cannot throw an error */
|
|
return ecma_copy_value (ecma_get_symbol_description (ecma_get_symbol_from_value (symbol)));
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (symbol);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SYMBOL_NOT_SUPPORTED));
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_symbol_description */
|
|
|
|
/**
|
|
* Call the SymbolDescriptiveString ecma builtin operation on the symbol value.
|
|
*
|
|
* Note:
|
|
* returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
*
|
|
* @return string value containing the symbol's descriptive string - if success
|
|
* thrown error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_symbol_descriptive_string (const jerry_value_t symbol) /**< symbol value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_ESNEXT
|
|
if (!ecma_is_value_symbol (symbol))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
/* Note: This operation cannot throw an error */
|
|
return ecma_get_symbol_descriptive_string (symbol);
|
|
#else /* !JERRY_ESNEXT */
|
|
JERRY_UNUSED (symbol);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SYMBOL_NOT_SUPPORTED));
|
|
#endif /* JERRY_ESNEXT */
|
|
} /* jerry_symbol_descriptive_string */
|
|
|
|
/**
|
|
* Get the number of uint64 digits of a BigInt value
|
|
*
|
|
* @return number of uint64 digits
|
|
*/
|
|
uint32_t
|
|
jerry_bigint_digit_count (const jerry_value_t value) /**< BigInt value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_BIGINT
|
|
if (!ecma_is_value_bigint (value))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return ecma_bigint_get_size_in_digits (value);
|
|
#else /* !JERRY_BUILTIN_BIGINT */
|
|
JERRY_UNUSED (value);
|
|
return 0;
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
} /* jerry_bigint_digit_count */
|
|
|
|
/**
|
|
* Get the uint64 digits of a BigInt value (lowest digit first)
|
|
*/
|
|
void
|
|
jerry_bigint_to_digits (const jerry_value_t value, /**< BigInt value */
|
|
uint64_t *digits_p, /**< [out] buffer for digits */
|
|
uint32_t digit_count, /**< buffer size in digits */
|
|
bool *sign_p) /**< [out] sign of BigInt */
|
|
{
|
|
#if JERRY_BUILTIN_BIGINT
|
|
if (!ecma_is_value_bigint (value))
|
|
{
|
|
if (sign_p != NULL)
|
|
{
|
|
*sign_p = false;
|
|
}
|
|
memset (digits_p, 0, digit_count * sizeof (uint64_t));
|
|
}
|
|
|
|
ecma_bigint_get_digits_and_sign (value, digits_p, digit_count, sign_p);
|
|
#else /* !JERRY_BUILTIN_BIGINT */
|
|
JERRY_UNUSED (value);
|
|
|
|
if (sign_p != NULL)
|
|
{
|
|
*sign_p = false;
|
|
}
|
|
memset (digits_p, 0, digit_count * sizeof (uint64_t));
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
} /* jerry_bigint_to_digits */
|
|
|
|
/**
|
|
* Get the target object of a Proxy object
|
|
*
|
|
* @return type error - if proxy_value is not a Proxy object
|
|
* target object - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_proxy_target (const jerry_value_t proxy_value) /**< proxy value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (ecma_is_value_object (proxy_value))
|
|
{
|
|
ecma_object_t *object_p = ecma_get_object_from_value (proxy_value);
|
|
|
|
if (ECMA_OBJECT_IS_PROXY (object_p))
|
|
{
|
|
ecma_proxy_object_t *proxy_object_p = (ecma_proxy_object_t *) object_p;
|
|
|
|
if (!ecma_is_value_null (proxy_object_p->target))
|
|
{
|
|
ecma_ref_object (ecma_get_object_from_value (proxy_object_p->target));
|
|
}
|
|
return proxy_object_p->target;
|
|
}
|
|
}
|
|
#else /* !JERRY_BUILTIN_PROXY */
|
|
JERRY_UNUSED (proxy_value);
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_ARGUMENT_IS_NOT_A_PROXY));
|
|
} /* jerry_proxy_target */
|
|
|
|
/**
|
|
* Get the handler object of a Proxy object
|
|
*
|
|
* @return type error - if proxy_value is not a Proxy object
|
|
* handler object - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_proxy_handler (const jerry_value_t proxy_value) /**< proxy value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_PROXY
|
|
if (ecma_is_value_object (proxy_value))
|
|
{
|
|
ecma_object_t *object_p = ecma_get_object_from_value (proxy_value);
|
|
|
|
if (ECMA_OBJECT_IS_PROXY (object_p))
|
|
{
|
|
ecma_proxy_object_t *proxy_object_p = (ecma_proxy_object_t *) object_p;
|
|
|
|
if (!ecma_is_value_null (proxy_object_p->handler))
|
|
{
|
|
ecma_ref_object (ecma_get_object_from_value (proxy_object_p->handler));
|
|
}
|
|
return proxy_object_p->handler;
|
|
}
|
|
}
|
|
#else /* !JERRY_BUILTIN_PROXY */
|
|
JERRY_UNUSED (proxy_value);
|
|
#endif /* JERRY_BUILTIN_PROXY */
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_ARGUMENT_IS_NOT_A_PROXY));
|
|
} /* jerry_proxy_handler */
|
|
|
|
/**
|
|
* Validate string buffer for the specified encoding
|
|
*
|
|
* @return true - if string is well-formed
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_validate_string (const jerry_char_t *buffer_p, /**< string buffer */
|
|
jerry_size_t buffer_size, /**< buffer size */
|
|
jerry_encoding_t encoding) /**< buffer encoding */
|
|
{
|
|
switch (encoding)
|
|
{
|
|
case JERRY_ENCODING_CESU8:
|
|
{
|
|
return lit_is_valid_cesu8_string (buffer_p, buffer_size);
|
|
}
|
|
case JERRY_ENCODING_UTF8:
|
|
{
|
|
return lit_is_valid_utf8_string (buffer_p, buffer_size, true);
|
|
}
|
|
default:
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
} /* jerry_validate_string */
|
|
|
|
/**
|
|
* Set the log level of the engine.
|
|
*
|
|
* Log messages with lower significance than the current log level will be ignored by `jerry_log`.
|
|
*
|
|
* @param level: requested log level
|
|
*/
|
|
void
|
|
jerry_log_set_level (jerry_log_level_t level)
|
|
{
|
|
JERRY_CONTEXT (log_level) = level;
|
|
} /* jerry_log_set_level */
|
|
|
|
/**
|
|
* Log buffer size
|
|
*/
|
|
#define JERRY_LOG_BUFFER_SIZE 64
|
|
|
|
/**
|
|
* Log a zero-terminated string message.
|
|
*
|
|
* @param str_p: message
|
|
*/
|
|
static void
|
|
jerry_log_string (const char *str_p)
|
|
{
|
|
jerry_port_log (str_p);
|
|
|
|
#if JERRY_DEBUGGER
|
|
if (jerry_debugger_is_connected ())
|
|
{
|
|
jerry_debugger_send_string (JERRY_DEBUGGER_OUTPUT_RESULT,
|
|
JERRY_DEBUGGER_OUTPUT_LOG,
|
|
(const uint8_t *) str_p,
|
|
strlen (str_p));
|
|
}
|
|
#endif /* JERRY_DEBUGGER */
|
|
} /* jerry_log_string */
|
|
|
|
/**
|
|
* Log an unsigned number.
|
|
*
|
|
* @param num: number
|
|
* @param buffer_p: buffer used to construct the number string
|
|
*/
|
|
static void
|
|
jerry_log_unsigned (unsigned int num, char *buffer_p)
|
|
{
|
|
char *cursor_p = buffer_p + JERRY_LOG_BUFFER_SIZE;
|
|
*(--cursor_p) = '\0';
|
|
|
|
while (num > 0)
|
|
{
|
|
*(--cursor_p) = (char) ((num % 10) + '0');
|
|
num /= 10;
|
|
}
|
|
|
|
jerry_log_string (cursor_p);
|
|
} /* jerry_log_unsigned */
|
|
|
|
/**
|
|
* Log a zero-terminated formatted message with the specified log level.
|
|
*
|
|
* Supported format specifiers:
|
|
* %s: zero-terminated string
|
|
* %c: character
|
|
* %u: unsigned int
|
|
*
|
|
* @param format_p: format string
|
|
* @param level: message log level
|
|
*/
|
|
void
|
|
jerry_log (jerry_log_level_t level, const char *format_p, ...)
|
|
{
|
|
if (level > JERRY_CONTEXT (log_level))
|
|
{
|
|
return;
|
|
}
|
|
|
|
va_list vl;
|
|
char buffer_p[JERRY_LOG_BUFFER_SIZE];
|
|
uint32_t buffer_index = 0;
|
|
const char *cursor_p = format_p;
|
|
va_start (vl, format_p);
|
|
|
|
while (*cursor_p != '\0')
|
|
{
|
|
if (*cursor_p == '%' || buffer_index > JERRY_LOG_BUFFER_SIZE - 2)
|
|
{
|
|
buffer_p[buffer_index] = '\0';
|
|
jerry_log_string (buffer_p);
|
|
buffer_index = 0;
|
|
}
|
|
|
|
if (*cursor_p != '%')
|
|
{
|
|
buffer_p[buffer_index++] = *cursor_p++;
|
|
continue;
|
|
}
|
|
|
|
++cursor_p;
|
|
|
|
if (*cursor_p == '\0')
|
|
{
|
|
buffer_p[buffer_index++] = '%';
|
|
break;
|
|
}
|
|
|
|
switch (*cursor_p++)
|
|
{
|
|
case 's':
|
|
{
|
|
jerry_log_string (va_arg (vl, char *));
|
|
break;
|
|
}
|
|
case 'c':
|
|
{
|
|
/* Arguments of types narrower than int are promoted to int for variadic functions */
|
|
buffer_p[buffer_index++] = (char) va_arg (vl, int);
|
|
break;
|
|
}
|
|
case 'u':
|
|
{
|
|
/* The buffer is always flushed before a substitution, and can be reused to print the number. */
|
|
jerry_log_unsigned (va_arg (vl, unsigned int), buffer_p);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
buffer_p[buffer_index++] = '%';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (buffer_index > 0)
|
|
{
|
|
buffer_p[buffer_index] = '\0';
|
|
jerry_log_string (buffer_p);
|
|
}
|
|
|
|
va_end (vl);
|
|
} /* jerry_log */
|
|
|
|
/**
|
|
* Allocate memory on the engine's heap.
|
|
*
|
|
* Note:
|
|
* This function may take away memory from the executed JavaScript code.
|
|
* If any other dynamic memory allocation API is available (e.g., libc
|
|
* malloc), it should be used instead.
|
|
*
|
|
* @return allocated memory on success
|
|
* NULL otherwise
|
|
*/
|
|
void *
|
|
jerry_heap_alloc (jerry_size_t size) /**< size of the memory block */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return jmem_heap_alloc_block_null_on_error (size);
|
|
} /* jerry_heap_alloc */
|
|
|
|
/**
|
|
* Free memory allocated on the engine's heap.
|
|
*/
|
|
void
|
|
jerry_heap_free (void *mem_p, /**< value returned by jerry_heap_alloc */
|
|
jerry_size_t size) /**< same size as passed to jerry_heap_alloc */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
jmem_heap_free_block (mem_p, size);
|
|
} /* jerry_heap_free */
|
|
|
|
/**
|
|
* When JERRY_VM_HALT is enabled, the callback passed to this function
|
|
* is periodically called with the user_p argument. If interval is greater
|
|
* than 1, the callback is only called at every interval ticks.
|
|
*/
|
|
void
|
|
jerry_halt_handler (uint32_t interval, /**< interval of the function call */
|
|
jerry_halt_cb_t callback, /**< periodically called user function */
|
|
void *user_p) /**< pointer passed to the function */
|
|
{
|
|
#if JERRY_VM_HALT
|
|
if (interval == 0)
|
|
{
|
|
interval = 1;
|
|
}
|
|
|
|
JERRY_CONTEXT (vm_exec_stop_frequency) = interval;
|
|
JERRY_CONTEXT (vm_exec_stop_counter) = interval;
|
|
JERRY_CONTEXT (vm_exec_stop_cb) = callback;
|
|
JERRY_CONTEXT (vm_exec_stop_user_p) = user_p;
|
|
#else /* !JERRY_VM_HALT */
|
|
JERRY_UNUSED (interval);
|
|
JERRY_UNUSED (callback);
|
|
JERRY_UNUSED (user_p);
|
|
#endif /* JERRY_VM_HALT */
|
|
} /* jerry_halt_handler */
|
|
|
|
/**
|
|
* Get backtrace. The backtrace is an array of strings where
|
|
* each string contains the position of the corresponding frame.
|
|
* The array length is zero if the backtrace is not available.
|
|
*
|
|
* @return array value
|
|
*/
|
|
jerry_value_t
|
|
jerry_backtrace (uint32_t max_depth) /**< depth limit of the backtrace */
|
|
{
|
|
return vm_get_backtrace (max_depth);
|
|
} /* jerry_backtrace */
|
|
|
|
/**
|
|
* Low-level function to capture each backtrace frame.
|
|
* The captured frame data is passed to a callback function.
|
|
*/
|
|
void
|
|
jerry_backtrace_capture (jerry_backtrace_cb_t callback, /**< callback function */
|
|
void *user_p) /**< user pointer passed to the callback function */
|
|
{
|
|
jerry_frame_t frame;
|
|
vm_frame_ctx_t *context_p = JERRY_CONTEXT (vm_top_context_p);
|
|
|
|
while (context_p != NULL)
|
|
{
|
|
frame.context_p = context_p;
|
|
frame.frame_type = JERRY_BACKTRACE_FRAME_JS;
|
|
|
|
if (!callback (&frame, user_p))
|
|
{
|
|
return;
|
|
}
|
|
|
|
context_p = context_p->prev_context_p;
|
|
}
|
|
} /* jerry_backtrace */
|
|
|
|
/**
|
|
* Returns with the type of the backtrace frame.
|
|
*
|
|
* @return frame type listed in jerry_frame_type_t
|
|
*/
|
|
jerry_frame_type_t
|
|
jerry_frame_type (const jerry_frame_t *frame_p) /**< frame pointer */
|
|
{
|
|
return (jerry_frame_type_t) frame_p->frame_type;
|
|
} /* jerry_frame_type */
|
|
|
|
/**
|
|
* Initialize and return with the location private field of a backtrace frame.
|
|
*
|
|
* @return pointer to the location private field - if the location is available,
|
|
* NULL - otherwise
|
|
*/
|
|
const jerry_frame_location_t *
|
|
jerry_frame_location (jerry_frame_t *frame_p) /**< frame pointer */
|
|
{
|
|
JERRY_UNUSED (frame_p);
|
|
|
|
#if JERRY_LINE_INFO
|
|
if (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS)
|
|
{
|
|
vm_frame_ctx_t *context_p = frame_p->context_p;
|
|
const ecma_compiled_code_t *bytecode_header_p = context_p->shared_p->bytecode_header_p;
|
|
|
|
if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_LINE_INFO))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
frame_p->location.source_name = ecma_get_source_name (bytecode_header_p);
|
|
|
|
ecma_line_info_get (ecma_compiled_code_get_line_info (bytecode_header_p),
|
|
(uint32_t) (context_p->byte_code_p - context_p->byte_code_start_p),
|
|
&frame_p->location);
|
|
|
|
return &frame_p->location;
|
|
}
|
|
#endif /* JERRY_LINE_INFO */
|
|
|
|
return NULL;
|
|
} /* jerry_frame_location */
|
|
|
|
/**
|
|
* Initialize and return with the called function private field of a backtrace frame.
|
|
* The backtrace frame is created for running the code bound to this function.
|
|
*
|
|
* @return pointer to the called function - if the function is available,
|
|
* NULL - otherwise
|
|
*/
|
|
const jerry_value_t *
|
|
jerry_frame_callee (jerry_frame_t *frame_p) /**< frame pointer */
|
|
{
|
|
if (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS)
|
|
{
|
|
vm_frame_ctx_t *context_p = frame_p->context_p;
|
|
|
|
if (context_p->shared_p->function_object_p != NULL)
|
|
{
|
|
frame_p->function = ecma_make_object_value (context_p->shared_p->function_object_p);
|
|
return &frame_p->function;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
} /* jerry_frame_callee */
|
|
|
|
/**
|
|
* Initialize and return with the 'this' binding private field of a backtrace frame.
|
|
* The 'this' binding is a hidden value passed to the called function. As for arrow
|
|
* functions, the 'this' binding is assigned at function creation.
|
|
*
|
|
* @return pointer to the 'this' binding - if the binding is available,
|
|
* NULL - otherwise
|
|
*/
|
|
const jerry_value_t *
|
|
jerry_frame_this (jerry_frame_t *frame_p) /**< frame pointer */
|
|
{
|
|
if (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS)
|
|
{
|
|
frame_p->this_binding = frame_p->context_p->this_binding;
|
|
return &frame_p->this_binding;
|
|
}
|
|
|
|
return NULL;
|
|
} /* jerry_frame_this */
|
|
|
|
/**
|
|
* Returns true, if the code bound to the backtrace frame is strict mode code.
|
|
*
|
|
* @return true - if strict mode code is bound to the frame,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_frame_is_strict (jerry_frame_t *frame_p) /**< frame pointer */
|
|
{
|
|
return (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS
|
|
&& (frame_p->context_p->status_flags & VM_FRAME_CTX_IS_STRICT) != 0);
|
|
} /* jerry_frame_is_strict */
|
|
|
|
/**
|
|
* Get the source name (usually a file name) of the currently executed script or the given function object
|
|
*
|
|
* Note: returned value must be freed with jerry_value_free, when it is no longer needed
|
|
*
|
|
* @return JS string constructed from
|
|
* - the currently executed function object's source name, if the given value is undefined
|
|
* - source name of the function object, if the given value is a function object
|
|
* - "<anonymous>", otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_source_name (const jerry_value_t value) /**< jerry api value */
|
|
{
|
|
#if JERRY_SOURCE_NAME
|
|
if (ecma_is_value_undefined (value) && JERRY_CONTEXT (vm_top_context_p) != NULL)
|
|
{
|
|
return ecma_copy_value (ecma_get_source_name (JERRY_CONTEXT (vm_top_context_p)->shared_p->bytecode_header_p));
|
|
}
|
|
|
|
ecma_value_t script_value = ecma_script_get_from_value (value);
|
|
|
|
if (script_value == JMEM_CP_NULL)
|
|
{
|
|
return ecma_make_magic_string_value (LIT_MAGIC_STRING_SOURCE_NAME_ANON);
|
|
}
|
|
|
|
const cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
|
|
|
|
return ecma_copy_value (script_p->source_name);
|
|
#else /* !JERRY_SOURCE_NAME */
|
|
JERRY_UNUSED (value);
|
|
return ecma_make_magic_string_value (LIT_MAGIC_STRING_SOURCE_NAME_ANON);
|
|
#endif /* JERRY_SOURCE_NAME */
|
|
} /* jerry_source_name */
|
|
|
|
/**
|
|
* Returns the user value assigned to a script / module / function.
|
|
*
|
|
* Note:
|
|
* This value is usually set by the parser when
|
|
* the JERRY_PARSE_HAS_USER_VALUE flag is passed.
|
|
*
|
|
* @return user value
|
|
*/
|
|
jerry_value_t
|
|
jerry_source_user_value (const jerry_value_t value) /**< jerry api value */
|
|
{
|
|
ecma_value_t script_value = ecma_script_get_from_value (value);
|
|
|
|
if (script_value == JMEM_CP_NULL)
|
|
{
|
|
return ECMA_VALUE_UNDEFINED;
|
|
}
|
|
|
|
const cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
|
|
|
|
if (!(script_p->refs_and_type & CBC_SCRIPT_HAS_USER_VALUE))
|
|
{
|
|
return ECMA_VALUE_UNDEFINED;
|
|
}
|
|
|
|
return ecma_copy_value (CBC_SCRIPT_GET_USER_VALUE (script_p));
|
|
} /* jerry_source_user_value */
|
|
|
|
/**
|
|
* Checks whether an ECMAScript code is compiled by eval
|
|
* like (eval, new Function, jerry_eval, etc.) command.
|
|
*
|
|
* @return true, if code is compiled by eval like command
|
|
* false, otherwise
|
|
*/
|
|
bool
|
|
jerry_function_is_dynamic (const jerry_value_t value) /**< jerry api value */
|
|
{
|
|
ecma_value_t script_value = ecma_script_get_from_value (value);
|
|
|
|
if (script_value == JMEM_CP_NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const cbc_script_t *script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
|
|
|
|
return (script_p->refs_and_type & CBC_SCRIPT_IS_EVAL_CODE) != 0;
|
|
} /* jerry_function_is_dynamic */
|
|
|
|
/**
|
|
* Returns a newly created source info structure corresponding to the passed script/module/function.
|
|
*
|
|
* @return a newly created source info, if at least one field is available, NULL otherwise
|
|
*/
|
|
jerry_source_info_t *
|
|
jerry_source_info (const jerry_value_t value) /**< jerry api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_FUNCTION_TO_STRING
|
|
if (!ecma_is_value_object (value))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
jerry_source_info_t source_info;
|
|
|
|
source_info.enabled_fields = 0;
|
|
source_info.source_code = ECMA_VALUE_UNDEFINED;
|
|
source_info.function_arguments = ECMA_VALUE_UNDEFINED;
|
|
source_info.source_range_start = 0;
|
|
source_info.source_range_length = 0;
|
|
|
|
ecma_object_t *object_p = ecma_get_object_from_value (value);
|
|
cbc_script_t *script_p = NULL;
|
|
|
|
while (true)
|
|
{
|
|
switch (ecma_get_object_type (object_p))
|
|
{
|
|
case ECMA_OBJECT_TYPE_CLASS:
|
|
{
|
|
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
|
|
const ecma_compiled_code_t *bytecode_p = NULL;
|
|
|
|
if (ext_object_p->u.cls.type == ECMA_OBJECT_CLASS_SCRIPT)
|
|
{
|
|
bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_object_p->u.cls.u3.value);
|
|
}
|
|
#if JERRY_MODULE_SYSTEM
|
|
else if (ext_object_p->u.cls.type == ECMA_OBJECT_CLASS_MODULE)
|
|
{
|
|
ecma_module_t *module_p = (ecma_module_t *) object_p;
|
|
|
|
if (!(module_p->header.u.cls.u2.module_flags & ECMA_MODULE_IS_NATIVE))
|
|
{
|
|
bytecode_p = module_p->u.compiled_code_p;
|
|
}
|
|
}
|
|
#endif /* JERRY_MODULE_SYSTEM */
|
|
|
|
if (bytecode_p == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ecma_value_t script_value = ((cbc_uint8_arguments_t *) bytecode_p)->script_value;
|
|
script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
|
|
break;
|
|
}
|
|
case ECMA_OBJECT_TYPE_FUNCTION:
|
|
{
|
|
const ecma_compiled_code_t *bytecode_p;
|
|
bytecode_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p);
|
|
|
|
ecma_value_t script_value = ((cbc_uint8_arguments_t *) bytecode_p)->script_value;
|
|
script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
|
|
|
|
if (bytecode_p->status_flags & CBC_CODE_FLAGS_HAS_EXTENDED_INFO)
|
|
{
|
|
uint8_t *extended_info_p = ecma_compiled_code_resolve_extended_info (bytecode_p);
|
|
uint8_t extended_info = *extended_info_p;
|
|
|
|
#if JERRY_ESNEXT
|
|
if (extended_info & CBC_EXTENDED_CODE_FLAGS_HAS_ARGUMENT_LENGTH)
|
|
{
|
|
ecma_extended_info_decode_vlq (&extended_info_p);
|
|
}
|
|
#endif /* JERRY_ESNEXT */
|
|
|
|
if (extended_info & CBC_EXTENDED_CODE_FLAGS_SOURCE_CODE_IN_ARGUMENTS)
|
|
{
|
|
ecma_value_t function_arguments = CBC_SCRIPT_GET_FUNCTION_ARGUMENTS (script_p, script_p->refs_and_type);
|
|
|
|
ecma_ref_ecma_string (ecma_get_string_from_value (function_arguments));
|
|
|
|
source_info.enabled_fields |= JERRY_SOURCE_INFO_HAS_SOURCE_CODE;
|
|
source_info.source_code = function_arguments;
|
|
script_p = NULL;
|
|
}
|
|
|
|
source_info.enabled_fields |= JERRY_SOURCE_INFO_HAS_SOURCE_RANGE;
|
|
source_info.source_range_start = ecma_extended_info_decode_vlq (&extended_info_p);
|
|
source_info.source_range_length = ecma_extended_info_decode_vlq (&extended_info_p);
|
|
}
|
|
|
|
JERRY_ASSERT (script_p != NULL || (source_info.enabled_fields & JERRY_SOURCE_INFO_HAS_SOURCE_CODE));
|
|
|
|
if (source_info.enabled_fields == 0 && (script_p->refs_and_type & CBC_SCRIPT_HAS_FUNCTION_ARGUMENTS))
|
|
{
|
|
ecma_value_t function_arguments = CBC_SCRIPT_GET_FUNCTION_ARGUMENTS (script_p, script_p->refs_and_type);
|
|
|
|
ecma_ref_ecma_string (ecma_get_string_from_value (function_arguments));
|
|
|
|
source_info.enabled_fields |= JERRY_SOURCE_INFO_HAS_FUNCTION_ARGUMENTS;
|
|
source_info.function_arguments = function_arguments;
|
|
}
|
|
break;
|
|
}
|
|
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
|
|
{
|
|
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
|
|
|
|
object_p =
|
|
ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, ext_object_p->u.bound_function.target_function);
|
|
continue;
|
|
}
|
|
#if JERRY_ESNEXT
|
|
case ECMA_OBJECT_TYPE_CONSTRUCTOR_FUNCTION:
|
|
{
|
|
ecma_value_t script_value = ((ecma_extended_object_t *) object_p)->u.constructor_function.script_value;
|
|
script_p = ECMA_GET_INTERNAL_VALUE_POINTER (cbc_script_t, script_value);
|
|
break;
|
|
}
|
|
#endif /* JERRY_ESNEXT */
|
|
default:
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
jerry_source_info_t *source_info_p = jmem_heap_alloc_block_null_on_error (sizeof (jerry_source_info_t));
|
|
|
|
if (source_info_p == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (script_p != NULL)
|
|
{
|
|
ecma_ref_ecma_string (ecma_get_string_from_value (script_p->source_code));
|
|
|
|
source_info.enabled_fields |= JERRY_SOURCE_INFO_HAS_SOURCE_CODE;
|
|
source_info.source_code = script_p->source_code;
|
|
}
|
|
|
|
JERRY_ASSERT (source_info.enabled_fields != 0);
|
|
|
|
*source_info_p = source_info;
|
|
return source_info_p;
|
|
#else /* !JERRY_FUNCTION_TO_STRING */
|
|
JERRY_UNUSED (value);
|
|
return NULL;
|
|
#endif /* JERRY_FUNCTION_TO_STRING */
|
|
} /* jerry_source_info */
|
|
|
|
/**
|
|
* Frees the the source info structure returned by jerry_source_info.
|
|
*/
|
|
void
|
|
jerry_source_info_free (jerry_source_info_t *source_info_p) /**< source info block */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_FUNCTION_TO_STRING
|
|
if (source_info_p != NULL)
|
|
{
|
|
ecma_free_value (source_info_p->source_code);
|
|
ecma_free_value (source_info_p->function_arguments);
|
|
jmem_heap_free_block (source_info_p, sizeof (jerry_source_info_t));
|
|
}
|
|
#else /* !JERRY_FUNCTION_TO_STRING */
|
|
JERRY_UNUSED (source_info_p);
|
|
#endif /* JERRY_FUNCTION_TO_STRING */
|
|
} /* jerry_source_info_free */
|
|
|
|
/**
|
|
* Replaces the currently active realm with another realm.
|
|
*
|
|
* The replacement should be temporary, and the original realm must be
|
|
* restored after the tasks are completed. During the replacement, the
|
|
* realm must be referenced by the application (i.e. the gc must not
|
|
* reclaim it). This is also true to the returned previously active
|
|
* realm, so there is no need to free the value after the restoration.
|
|
*
|
|
* @return previous realm value - if the passed value is a realm
|
|
* exception - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_set_realm (jerry_value_t realm_value) /**< jerry api value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_REALMS
|
|
if (ecma_is_value_object (realm_value))
|
|
{
|
|
ecma_object_t *object_p = ecma_get_object_from_value (realm_value);
|
|
|
|
if (ecma_builtin_is_global (object_p))
|
|
{
|
|
ecma_global_object_t *previous_global_object_p = JERRY_CONTEXT (global_object_p);
|
|
JERRY_CONTEXT (global_object_p) = (ecma_global_object_t *) object_p;
|
|
return ecma_make_object_value ((ecma_object_t *) previous_global_object_p);
|
|
}
|
|
}
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PASSED_ARGUMENT_IS_NOT_A_REALM));
|
|
#else /* !JERRY_BUILTIN_REALMS */
|
|
JERRY_UNUSED (realm_value);
|
|
return jerry_throw_sz (JERRY_ERROR_REFERENCE, ecma_get_error_msg (ECMA_ERR_REALM_IS_NOT_AVAILABLE));
|
|
#endif /* JERRY_BUILTIN_REALMS */
|
|
} /* jerry_set_realm */
|
|
|
|
/**
|
|
* Gets the 'this' binding of a realm
|
|
*
|
|
* @return type error - if realm_value is not a realm
|
|
* this value - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_realm_this (jerry_value_t realm) /**< realm value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_REALMS
|
|
if (ecma_is_value_object (realm))
|
|
{
|
|
ecma_object_t *object_p = ecma_get_object_from_value (realm);
|
|
|
|
if (ecma_builtin_is_global (object_p))
|
|
{
|
|
ecma_global_object_t *global_object_p = (ecma_global_object_t *) object_p;
|
|
|
|
ecma_ref_object (ecma_get_object_from_value (global_object_p->this_binding));
|
|
return global_object_p->this_binding;
|
|
}
|
|
}
|
|
|
|
#else /* !JERRY_BUILTIN_REALMS */
|
|
ecma_object_t *global_object_p = ecma_builtin_get_global ();
|
|
|
|
if (realm == ecma_make_object_value (global_object_p))
|
|
{
|
|
ecma_ref_object (global_object_p);
|
|
return realm;
|
|
}
|
|
#endif /* JERRY_BUILTIN_REALMS */
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_PASSED_ARGUMENT_IS_NOT_A_REALM));
|
|
} /* jerry_realm_this */
|
|
|
|
/**
|
|
* Sets the 'this' binding of a realm
|
|
*
|
|
* This function must be called before executing any script on the realm.
|
|
* Otherwise the operation is undefined.
|
|
*
|
|
* @return type error - if realm_value is not a realm or this_value is not object
|
|
* true - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_realm_set_this (jerry_value_t realm, /**< realm value */
|
|
jerry_value_t this_value) /**< this value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_REALMS
|
|
if (!ecma_is_value_object (this_value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SECOND_ARGUMENT_MUST_BE_AN_OBJECT));
|
|
}
|
|
|
|
if (ecma_is_value_object (realm))
|
|
{
|
|
ecma_object_t *object_p = ecma_get_object_from_value (realm);
|
|
|
|
if (ecma_builtin_is_global (object_p))
|
|
{
|
|
ecma_global_object_t *global_object_p = (ecma_global_object_t *) object_p;
|
|
global_object_p->this_binding = this_value;
|
|
|
|
ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL, ecma_get_object_from_value (this_value));
|
|
|
|
ECMA_SET_NON_NULL_POINTER (global_object_p->global_env_cp, global_lex_env_p);
|
|
#if JERRY_ESNEXT
|
|
global_object_p->global_scope_cp = global_object_p->global_env_cp;
|
|
#endif /* JERRY_ESNEXT */
|
|
ecma_deref_object (global_lex_env_p);
|
|
return ECMA_VALUE_TRUE;
|
|
}
|
|
}
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_FIRST_ARGUMENT_IS_NOT_A_REALM));
|
|
#else /* !JERRY_BUILTIN_REALMS */
|
|
JERRY_UNUSED (realm);
|
|
JERRY_UNUSED (this_value);
|
|
return jerry_throw_sz (JERRY_ERROR_REFERENCE, ecma_get_error_msg (ECMA_ERR_REALM_IS_NOT_AVAILABLE));
|
|
#endif /* JERRY_BUILTIN_REALMS */
|
|
} /* jerry_realm_set_this */
|
|
|
|
/**
|
|
* Check if the given value is an ArrayBuffer object.
|
|
*
|
|
* @return true - if it is an ArrayBuffer object
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_arraybuffer (const jerry_value_t value) /**< value to check if it is an ArrayBuffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
return ecma_is_arraybuffer (value);
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_value_is_arraybuffer */
|
|
|
|
/**
|
|
* Creates an ArrayBuffer object with the given length (size).
|
|
*
|
|
* Notes:
|
|
* * the length is specified in bytes.
|
|
* * returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
* * if the typed arrays are disabled this will return a TypeError.
|
|
*
|
|
* @return value of the constructed ArrayBuffer object
|
|
*/
|
|
jerry_value_t
|
|
jerry_arraybuffer (const jerry_length_t size) /**< size of the backing store allocated
|
|
* for the array buffer in bytes */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
return jerry_return (ecma_make_object_value (ecma_arraybuffer_new_object (size)));
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (size);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_arraybuffer */
|
|
|
|
/**
|
|
* Creates an ArrayBuffer object with user specified buffer.
|
|
*
|
|
* Notes:
|
|
* * the size is specified in bytes.
|
|
* * the buffer passed should be at least the specified bytes big.
|
|
* * if the typed arrays are disabled this will return a TypeError.
|
|
* * if the size is zero or buffer_p is a null pointer this will return an empty ArrayBuffer.
|
|
*
|
|
* @return value of the newly constructed array buffer object
|
|
*/
|
|
jerry_value_t
|
|
jerry_arraybuffer_external (uint8_t *buffer_p, /**< the backing store used by the array buffer object */
|
|
jerry_length_t size, /**< size of the buffer in bytes */
|
|
void *user_p) /**< user pointer assigned to the array buffer object */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
ecma_object_t *arraybuffer_p;
|
|
|
|
if (JERRY_UNLIKELY (size == 0))
|
|
{
|
|
arraybuffer_p = ecma_arraybuffer_new_object (0);
|
|
}
|
|
else
|
|
{
|
|
arraybuffer_p = ecma_arraybuffer_create_object_with_buffer (ECMA_OBJECT_CLASS_ARRAY_BUFFER, size);
|
|
|
|
ecma_arraybuffer_pointer_t *arraybuffer_pointer_p = (ecma_arraybuffer_pointer_t *) arraybuffer_p;
|
|
arraybuffer_pointer_p->arraybuffer_user_p = user_p;
|
|
|
|
if (buffer_p != NULL)
|
|
{
|
|
arraybuffer_pointer_p->extended_object.u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED;
|
|
arraybuffer_pointer_p->buffer_p = buffer_p;
|
|
}
|
|
}
|
|
|
|
return jerry_return (ecma_make_object_value (arraybuffer_p));
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (size);
|
|
JERRY_UNUSED (buffer_p);
|
|
JERRY_UNUSED (user_p);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_arraybuffer_external */
|
|
|
|
/**
|
|
* Check if the given value is a SharedArrayBuffer object.
|
|
*
|
|
* @return true - if it is a SharedArrayBuffer object
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_shared_arraybuffer (const jerry_value_t value) /**< value to check if it is a SharedArrayBuffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
return ecma_is_shared_arraybuffer (value);
|
|
} /* jerry_value_is_shared_arraybuffer */
|
|
|
|
/**
|
|
* Creates a SharedArrayBuffer object with the given length (size).
|
|
*
|
|
* Notes:
|
|
* * the length is specified in bytes.
|
|
* * returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
* * if the typed arrays are disabled this will return a TypeError.
|
|
*
|
|
* @return value of the constructed SharedArrayBuffer object
|
|
*/
|
|
jerry_value_t
|
|
jerry_shared_arraybuffer (jerry_length_t size) /**< size of the backing store allocated
|
|
* for the shared array buffer in bytes */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_SHAREDARRAYBUFFER
|
|
return jerry_return (ecma_make_object_value (ecma_shared_arraybuffer_new_object (size)));
|
|
#else /* !JERRY_BUILTIN_SHAREDARRAYBUFFER */
|
|
JERRY_UNUSED (size);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SHARED_ARRAYBUFFER_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */
|
|
} /* jerry_shared_arraybuffer */
|
|
|
|
/**
|
|
* Creates a SharedArrayBuffer object with user specified buffer.
|
|
*
|
|
* Notes:
|
|
* * the size is specified in bytes.
|
|
* * the buffer passed should be at least the specified bytes big.
|
|
* * if the typed arrays are disabled this will return a TypeError.
|
|
* * if the size is zero or buffer_p is a null pointer this will return an empty SharedArrayBuffer.
|
|
*
|
|
* @return value of the newly constructed shared array buffer object
|
|
*/
|
|
jerry_value_t
|
|
jerry_shared_arraybuffer_external (uint8_t *buffer_p, /**< the backing store used by the
|
|
* shared array buffer object */
|
|
jerry_length_t size, /**< size of the buffer in bytes */
|
|
void *user_p) /**< user pointer assigned to the
|
|
* shared array buffer object */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_SHAREDARRAYBUFFER
|
|
ecma_object_t *shared_arraybuffer_p;
|
|
|
|
if (JERRY_UNLIKELY (size == 0))
|
|
{
|
|
shared_arraybuffer_p = ecma_shared_arraybuffer_new_object (0);
|
|
}
|
|
else
|
|
{
|
|
shared_arraybuffer_p = ecma_arraybuffer_create_object_with_buffer (ECMA_OBJECT_CLASS_SHARED_ARRAY_BUFFER, size);
|
|
|
|
ecma_arraybuffer_pointer_t *shared_arraybuffer_pointer_p = (ecma_arraybuffer_pointer_t *) shared_arraybuffer_p;
|
|
shared_arraybuffer_pointer_p->arraybuffer_user_p = user_p;
|
|
|
|
if (buffer_p != NULL)
|
|
{
|
|
shared_arraybuffer_pointer_p->extended_object.u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED;
|
|
shared_arraybuffer_pointer_p->buffer_p = buffer_p;
|
|
}
|
|
}
|
|
|
|
return ecma_make_object_value (shared_arraybuffer_p);
|
|
#else /* !JERRY_BUILTIN_SHAREDARRAYBUFFER */
|
|
JERRY_UNUSED (size);
|
|
JERRY_UNUSED (buffer_p);
|
|
JERRY_UNUSED (user_p);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_SHARED_ARRAYBUFFER_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */
|
|
} /* jerry_shared_arraybuffer_external */
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
|
|
/**
|
|
* Allocate a backing store for an array buffer, ignores allocation fails.
|
|
*
|
|
* @return true on success,
|
|
* false otherwise
|
|
*/
|
|
static bool
|
|
jerry_arraybuffer_allocate_buffer_no_throw (ecma_object_t *arraybuffer_p) /**< ArrayBuffer object */
|
|
{
|
|
JERRY_ASSERT (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED));
|
|
|
|
if (ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_DETACHED)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ecma_arraybuffer_allocate_buffer (arraybuffer_p) != ECMA_VALUE_ERROR;
|
|
} /* jerry_arraybuffer_allocate_buffer_no_throw */
|
|
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
|
|
/**
|
|
* Copy bytes into the ArrayBuffer or SharedArrayBuffer from a buffer.
|
|
*
|
|
* Note:
|
|
* * returns 0, if the passed object is not an ArrayBuffer or SharedArrayBuffer
|
|
*
|
|
* @return number of bytes copied into the ArrayBuffer or SharedArrayBuffer.
|
|
*/
|
|
jerry_length_t
|
|
jerry_arraybuffer_write (jerry_value_t value, /**< target ArrayBuffer or SharedArrayBuffer */
|
|
jerry_length_t offset, /**< start offset of the ArrayBuffer */
|
|
const uint8_t *buf_p, /**< buffer to copy from */
|
|
jerry_length_t buf_size) /**< number of bytes to copy from the buffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (!(ecma_is_arraybuffer (value) || ecma_is_shared_arraybuffer (value)))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value);
|
|
|
|
if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)
|
|
&& !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
jerry_length_t length = ecma_arraybuffer_get_length (arraybuffer_p);
|
|
|
|
if (offset >= length)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
jerry_length_t copy_count = JERRY_MIN (length - offset, buf_size);
|
|
|
|
if (copy_count > 0)
|
|
{
|
|
lit_utf8_byte_t *buffer_p = ecma_arraybuffer_get_buffer (arraybuffer_p);
|
|
|
|
memcpy ((void *) (buffer_p + offset), (void *) buf_p, copy_count);
|
|
}
|
|
|
|
return copy_count;
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
JERRY_UNUSED (offset);
|
|
JERRY_UNUSED (buf_p);
|
|
JERRY_UNUSED (buf_size);
|
|
return 0;
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_arraybuffer_write */
|
|
|
|
/**
|
|
* Copy bytes from a buffer into an ArrayBuffer or SharedArrayBuffer.
|
|
*
|
|
* Note:
|
|
* * if the object passed is not an ArrayBuffer or SharedArrayBuffer will return 0.
|
|
*
|
|
* @return number of bytes read from the ArrayBuffer.
|
|
*/
|
|
jerry_length_t
|
|
jerry_arraybuffer_read (const jerry_value_t value, /**< ArrayBuffer or SharedArrayBuffer to read from */
|
|
jerry_length_t offset, /**< start offset of the ArrayBuffer or SharedArrayBuffer */
|
|
uint8_t *buf_p, /**< destination buffer to copy to */
|
|
jerry_length_t buf_size) /**< number of bytes to copy into the buffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (!(ecma_is_arraybuffer (value) || ecma_is_shared_arraybuffer (value)))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value);
|
|
|
|
if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)
|
|
&& !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
jerry_length_t length = ecma_arraybuffer_get_length (arraybuffer_p);
|
|
|
|
if (offset >= length)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
jerry_length_t copy_count = JERRY_MIN (length - offset, buf_size);
|
|
|
|
if (copy_count > 0)
|
|
{
|
|
lit_utf8_byte_t *buffer_p = ecma_arraybuffer_get_buffer (arraybuffer_p);
|
|
|
|
memcpy ((void *) buf_p, (void *) (buffer_p + offset), copy_count);
|
|
}
|
|
|
|
return copy_count;
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
JERRY_UNUSED (offset);
|
|
JERRY_UNUSED (buf_p);
|
|
JERRY_UNUSED (buf_size);
|
|
return 0;
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_arraybuffer_read */
|
|
|
|
/**
|
|
* Get the length (size) of the ArrayBuffer or SharedArrayBuffer in bytes.
|
|
*
|
|
* Note:
|
|
* This is the 'byteLength' property of an ArrayBuffer or SharedArrayBuffer.
|
|
*
|
|
* @return the length of the ArrayBuffer in bytes.
|
|
*/
|
|
jerry_length_t
|
|
jerry_arraybuffer_size (const jerry_value_t value) /**< ArrayBuffer or SharedArrayBuffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (ecma_is_arraybuffer (value) || ecma_is_shared_arraybuffer (value))
|
|
{
|
|
ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value);
|
|
return ecma_arraybuffer_get_length (arraybuffer_p);
|
|
}
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
return 0;
|
|
} /* jerry_arraybuffer_size */
|
|
|
|
/**
|
|
* Get a pointer for the start of the ArrayBuffer.
|
|
*
|
|
* Note:
|
|
* * This is a high-risk operation as the bounds are not checked
|
|
* when accessing the pointer elements.
|
|
*
|
|
* @return pointer to the back-buffer of the ArrayBuffer.
|
|
* pointer is NULL if:
|
|
* - the parameter is not an ArrayBuffer
|
|
* - an external ArrayBuffer has been detached
|
|
*/
|
|
uint8_t *
|
|
jerry_arraybuffer_data (const jerry_value_t array_buffer) /**< Array Buffer to use */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (!(ecma_is_arraybuffer (array_buffer) || ecma_is_shared_arraybuffer (array_buffer)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ecma_object_t *arraybuffer_p = ecma_get_object_from_value (array_buffer);
|
|
|
|
if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)
|
|
&& !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return (uint8_t *) ecma_arraybuffer_get_buffer (arraybuffer_p);
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (array_buffer);
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
|
|
return NULL;
|
|
} /* jerry_arraybuffer_data */
|
|
|
|
/**
|
|
* Get if the ArrayBuffer is detachable.
|
|
*
|
|
* @return boolean value - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
bool
|
|
jerry_arraybuffer_is_detachable (const jerry_value_t value) /**< ArrayBuffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (ecma_is_arraybuffer (value))
|
|
{
|
|
ecma_object_t *buffer_p = ecma_get_object_from_value (value);
|
|
return !ecma_arraybuffer_is_detached (buffer_p);
|
|
}
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
return false;
|
|
} /* jerry_arraybuffer_is_detachable */
|
|
|
|
/**
|
|
* Detach the underlying data block from ArrayBuffer and set its bytelength to 0.
|
|
*
|
|
* Note: if the ArrayBuffer has a separate data buffer, the free callback set by
|
|
* jerry_arraybuffer_set_allocation_callbacks is called for this buffer
|
|
*
|
|
* @return null value - if success
|
|
* value marked with error flag - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_arraybuffer_detach (jerry_value_t value) /**< ArrayBuffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (ecma_is_arraybuffer (value))
|
|
{
|
|
ecma_object_t *buffer_p = ecma_get_object_from_value (value);
|
|
if (ecma_arraybuffer_detach (buffer_p))
|
|
{
|
|
return ECMA_VALUE_NULL;
|
|
}
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_ARRAY_BUFFER_DETACHED));
|
|
}
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_EXPECTED_AN_ARRAYBUFFER));
|
|
} /* jerry_arraybuffer_detach */
|
|
|
|
/**
|
|
* Checks whether a buffer is currently allocated for an array buffer or typed array.
|
|
*
|
|
* @return true, if a buffer is allocated for an array buffer or typed array
|
|
* false, otherwise
|
|
*/
|
|
bool
|
|
jerry_arraybuffer_has_buffer (const jerry_value_t value) /**< array buffer or typed array value */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (!ecma_is_value_object (value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ecma_object_t *object_p = ecma_get_object_from_value (value);
|
|
|
|
if (ecma_object_is_typedarray (object_p))
|
|
{
|
|
object_p = ecma_typedarray_get_arraybuffer (object_p);
|
|
}
|
|
else if (!(ecma_object_class_is (object_p, ECMA_OBJECT_CLASS_ARRAY_BUFFER)
|
|
|| ecma_object_is_shared_arraybuffer (object_p)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return (ECMA_ARRAYBUFFER_GET_FLAGS (object_p) & ECMA_ARRAYBUFFER_ALLOCATED) != 0;
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_arraybuffer_has_buffer */
|
|
|
|
/**
|
|
* Array buffers which size is less or equal than the limit passed to this function are allocated in
|
|
* a single memory block. The allocator callbacks set by jerry_arraybuffer_set_allocation_callbacks
|
|
* are not called for these array buffers. The default limit is 256 bytes.
|
|
*/
|
|
void
|
|
jerry_arraybuffer_heap_allocation_limit (jerry_length_t allocation_limit) /**< maximum size of
|
|
* compact allocation */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
JERRY_CONTEXT (arraybuffer_compact_allocation_limit) = allocation_limit;
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (allocation_limit);
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_arraybuffer_heap_allocation_limit */
|
|
|
|
/**
|
|
* Set callbacks for allocating and freeing backing stores for array buffer objects.
|
|
*/
|
|
void
|
|
jerry_arraybuffer_allocator (jerry_arraybuffer_allocate_cb_t allocate_callback, /**< callback for allocating
|
|
* array buffer memory */
|
|
jerry_arraybuffer_free_cb_t free_callback, /**< callback for freeing
|
|
* array buffer memory */
|
|
void *user_p) /**< user pointer passed to the callbacks */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
JERRY_CONTEXT (arraybuffer_allocate_callback) = allocate_callback;
|
|
JERRY_CONTEXT (arraybuffer_free_callback) = free_callback;
|
|
JERRY_CONTEXT (arraybuffer_allocate_callback_user_p) = user_p;
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (allocate_callback);
|
|
JERRY_UNUSED (free_callback);
|
|
JERRY_UNUSED (user_p);
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_arraybuffer_allocator */
|
|
|
|
/**
|
|
* DataView related functions
|
|
*/
|
|
|
|
/**
|
|
* Creates a DataView object with the given ArrayBuffer, ByteOffset and ByteLength arguments.
|
|
*
|
|
* Notes:
|
|
* * returned value must be freed with jerry_value_free, when it is no longer needed.
|
|
* * if the DataView bulitin is disabled this will return a TypeError.
|
|
*
|
|
* @return value of the constructed DataView object - if success
|
|
* created error - otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_dataview (const jerry_value_t array_buffer, /**< arraybuffer to create DataView from */
|
|
jerry_length_t byte_offset, /**< offset in bytes, to the first byte in the buffer */
|
|
jerry_length_t byte_length) /**< number of elements in the byte array */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_DATAVIEW
|
|
if (ecma_is_value_exception (array_buffer))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_value_t arguments_p[3] = { array_buffer,
|
|
ecma_make_uint32_value (byte_offset),
|
|
ecma_make_uint32_value (byte_length) };
|
|
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p);
|
|
if (old_new_target_p == NULL)
|
|
{
|
|
JERRY_CONTEXT (current_new_target_p) = ecma_builtin_get (ECMA_BUILTIN_ID_DATAVIEW);
|
|
}
|
|
|
|
ecma_value_t dataview_value = ecma_op_dataview_create (arguments_p, 3);
|
|
JERRY_CONTEXT (current_new_target_p) = old_new_target_p;
|
|
return jerry_return (dataview_value);
|
|
#else /* !JERRY_BUILTIN_DATAVIEW */
|
|
JERRY_UNUSED (array_buffer);
|
|
JERRY_UNUSED (byte_offset);
|
|
JERRY_UNUSED (byte_length);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_DATA_VIEW_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_DATAVIEW */
|
|
} /* jerry_dataview */
|
|
|
|
/**
|
|
* Check if the given value is a DataView object.
|
|
*
|
|
* @return true - if it is a DataView object
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_dataview (const jerry_value_t value) /**< value to check if it is a DataView object */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_DATAVIEW
|
|
return ecma_is_dataview (value);
|
|
#else /* !JERRY_BUILTIN_DATAVIEW */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_BUILTIN_DATAVIEW */
|
|
} /* jerry_value_is_dataview */
|
|
|
|
/**
|
|
* Get the underlying ArrayBuffer from a DataView.
|
|
*
|
|
* Additionally the byteLength and byteOffset properties are also returned
|
|
* which were specified when the DataView was created.
|
|
*
|
|
* Note:
|
|
* the returned value must be freed with a jerry_value_free call
|
|
*
|
|
* @return ArrayBuffer of a DataView
|
|
* TypeError if the object is not a DataView.
|
|
*/
|
|
jerry_value_t
|
|
jerry_dataview_buffer (const jerry_value_t value, /**< DataView to get the arraybuffer from */
|
|
jerry_length_t *byte_offset, /**< [out] byteOffset property */
|
|
jerry_length_t *byte_length) /**< [out] byteLength property */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_DATAVIEW
|
|
if (ecma_is_value_exception (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
|
|
ecma_dataview_object_t *dataview_p = ecma_op_dataview_get_object (value);
|
|
|
|
if (JERRY_UNLIKELY (dataview_p == NULL))
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
if (byte_offset != NULL)
|
|
{
|
|
*byte_offset = dataview_p->byte_offset;
|
|
}
|
|
|
|
if (byte_length != NULL)
|
|
{
|
|
*byte_length = dataview_p->header.u.cls.u3.length;
|
|
}
|
|
|
|
ecma_object_t *arraybuffer_p = dataview_p->buffer_p;
|
|
ecma_ref_object (arraybuffer_p);
|
|
|
|
return ecma_make_object_value (arraybuffer_p);
|
|
#else /* !JERRY_BUILTIN_DATAVIEW */
|
|
JERRY_UNUSED (value);
|
|
JERRY_UNUSED (byte_offset);
|
|
JERRY_UNUSED (byte_length);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_DATA_VIEW_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_DATAVIEW */
|
|
} /* jerry_dataview_buffer */
|
|
|
|
/**
|
|
* TypedArray related functions
|
|
*/
|
|
|
|
/**
|
|
* Check if the given value is a TypedArray object.
|
|
*
|
|
* @return true - if it is a TypedArray object
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_value_is_typedarray (const jerry_value_t value) /**< value to check if it is a TypedArray */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
return ecma_is_typedarray (value);
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
return false;
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_value_is_typedarray */
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
/**
|
|
* TypedArray mapping type
|
|
*/
|
|
typedef struct
|
|
{
|
|
jerry_typedarray_type_t api_type; /**< api type */
|
|
ecma_builtin_id_t prototype_id; /**< prototype ID */
|
|
ecma_typedarray_type_t id; /**< typedArray ID */
|
|
uint8_t element_size_shift; /**< element size shift */
|
|
} jerry_typedarray_mapping_t;
|
|
|
|
/**
|
|
* List of TypedArray mappings
|
|
*/
|
|
static jerry_typedarray_mapping_t jerry_typedarray_mappings[] = {
|
|
#define TYPEDARRAY_ENTRY(NAME, LIT_NAME, SIZE_SHIFT) \
|
|
{ \
|
|
JERRY_TYPEDARRAY_##NAME, ECMA_BUILTIN_ID_##NAME##ARRAY_PROTOTYPE, ECMA_##LIT_NAME##_ARRAY, SIZE_SHIFT \
|
|
}
|
|
|
|
TYPEDARRAY_ENTRY (UINT8, UINT8, 0), TYPEDARRAY_ENTRY (UINT8CLAMPED, UINT8_CLAMPED, 0),
|
|
TYPEDARRAY_ENTRY (INT8, INT8, 0), TYPEDARRAY_ENTRY (UINT16, UINT16, 1),
|
|
TYPEDARRAY_ENTRY (INT16, INT16, 1), TYPEDARRAY_ENTRY (UINT32, UINT32, 2),
|
|
TYPEDARRAY_ENTRY (INT32, INT32, 2), TYPEDARRAY_ENTRY (FLOAT32, FLOAT32, 2),
|
|
#if JERRY_NUMBER_TYPE_FLOAT64
|
|
TYPEDARRAY_ENTRY (FLOAT64, FLOAT64, 3),
|
|
#endif /* JERRY_NUMBER_TYPE_FLOAT64 */
|
|
#if JERRY_BUILTIN_BIGINT
|
|
TYPEDARRAY_ENTRY (BIGINT64, BIGINT64, 3), TYPEDARRAY_ENTRY (BIGUINT64, BIGUINT64, 3),
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
#undef TYPEDARRAY_ENTRY
|
|
};
|
|
|
|
/**
|
|
* Helper function to get the TypedArray prototype, typedArray id, and element size shift
|
|
* information.
|
|
*
|
|
* @return true - if the TypedArray information was found
|
|
* false - if there is no such TypedArray type
|
|
*/
|
|
static bool
|
|
jerry_typedarray_find_by_type (jerry_typedarray_type_t type_name, /**< type of the TypedArray */
|
|
ecma_builtin_id_t *prototype_id, /**< [out] found prototype object id */
|
|
ecma_typedarray_type_t *id, /**< [out] found typedArray id */
|
|
uint8_t *element_size_shift) /**< [out] found element size shift value */
|
|
{
|
|
JERRY_ASSERT (prototype_id != NULL);
|
|
JERRY_ASSERT (id != NULL);
|
|
JERRY_ASSERT (element_size_shift != NULL);
|
|
|
|
for (uint32_t i = 0; i < sizeof (jerry_typedarray_mappings) / sizeof (jerry_typedarray_mappings[0]); i++)
|
|
{
|
|
if (type_name == jerry_typedarray_mappings[i].api_type)
|
|
{
|
|
*prototype_id = jerry_typedarray_mappings[i].prototype_id;
|
|
*id = jerry_typedarray_mappings[i].id;
|
|
*element_size_shift = jerry_typedarray_mappings[i].element_size_shift;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} /* jerry_typedarray_find_by_type */
|
|
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
|
|
/**
|
|
* Create a TypedArray object with a given type and length.
|
|
*
|
|
* Notes:
|
|
* * returns TypeError if an incorrect type (type_name) is specified.
|
|
* * byteOffset property will be set to 0.
|
|
* * byteLength property will be a multiple of the length parameter (based on the type).
|
|
*
|
|
* @return - new TypedArray object
|
|
*/
|
|
jerry_value_t
|
|
jerry_typedarray (jerry_typedarray_type_t type_name, /**< type of TypedArray to create */
|
|
jerry_length_t length) /**< element count of the new TypedArray */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
ecma_builtin_id_t prototype_id = 0;
|
|
ecma_typedarray_type_t id = 0;
|
|
uint8_t element_size_shift = 0;
|
|
|
|
if (!jerry_typedarray_find_by_type (type_name, &prototype_id, &id, &element_size_shift))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_FOR_TYPEDARRAY));
|
|
}
|
|
|
|
ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id);
|
|
|
|
ecma_value_t array_value =
|
|
ecma_typedarray_create_object_with_length (length, NULL, prototype_obj_p, element_size_shift, id);
|
|
|
|
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (array_value));
|
|
|
|
return array_value;
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (type_name);
|
|
JERRY_UNUSED (length);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_typedarray */
|
|
|
|
/**
|
|
* Create a TypedArray object using the given arraybuffer and size information.
|
|
*
|
|
* Notes:
|
|
* * returns TypeError if an incorrect type (type_name) is specified.
|
|
* * this is the 'new %TypedArray%(arraybuffer, byteOffset, length)' equivalent call.
|
|
*
|
|
* @return - new TypedArray object
|
|
*/
|
|
jerry_value_t
|
|
jerry_typedarray_with_buffer_span (jerry_typedarray_type_t type, /**< type of TypedArray to create */
|
|
const jerry_value_t arraybuffer, /**< ArrayBuffer to use */
|
|
jerry_length_t byte_offset, /**< offset for the ArrayBuffer */
|
|
jerry_length_t length) /**< number of elements to use from ArrayBuffer */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (ecma_is_value_exception (arraybuffer))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
ecma_builtin_id_t prototype_id = 0;
|
|
ecma_typedarray_type_t id = 0;
|
|
uint8_t element_size_shift = 0;
|
|
|
|
if (!jerry_typedarray_find_by_type (type, &prototype_id, &id, &element_size_shift))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_FOR_TYPEDARRAY));
|
|
}
|
|
|
|
if (!ecma_is_arraybuffer (arraybuffer))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_ARGUMENT_NOT_ARRAY_BUFFER));
|
|
}
|
|
|
|
ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id);
|
|
ecma_value_t arguments_p[3] = { arraybuffer, ecma_make_uint32_value (byte_offset), ecma_make_uint32_value (length) };
|
|
|
|
ecma_value_t array_value = ecma_op_create_typedarray (arguments_p, 3, prototype_obj_p, element_size_shift, id);
|
|
ecma_free_value (arguments_p[1]);
|
|
ecma_free_value (arguments_p[2]);
|
|
|
|
return jerry_return (array_value);
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (type);
|
|
JERRY_UNUSED (arraybuffer);
|
|
JERRY_UNUSED (byte_offset);
|
|
JERRY_UNUSED (length);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_typedarray_with_buffer_span */
|
|
|
|
/**
|
|
* Create a TypedArray object using the given arraybuffer and size information.
|
|
*
|
|
* Notes:
|
|
* * returns TypeError if an incorrect type (type_name) is specified.
|
|
* * this is the 'new %TypedArray%(arraybuffer)' equivalent call.
|
|
*
|
|
* @return - new TypedArray object
|
|
*/
|
|
jerry_value_t
|
|
jerry_typedarray_with_buffer (jerry_typedarray_type_t type, /**< type of TypedArray to create */
|
|
const jerry_value_t arraybuffer) /**< ArrayBuffer to use */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (ecma_is_value_exception (arraybuffer))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
jerry_length_t byte_length = jerry_arraybuffer_size (arraybuffer);
|
|
return jerry_typedarray_with_buffer_span (type, arraybuffer, 0, byte_length);
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (type);
|
|
JERRY_UNUSED (arraybuffer);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_typedarray_with_buffer */
|
|
|
|
/**
|
|
* Get the type of the TypedArray.
|
|
*
|
|
* @return - type of the TypedArray
|
|
* - JERRY_TYPEDARRAY_INVALID if the argument is not a TypedArray
|
|
*/
|
|
jerry_typedarray_type_t
|
|
jerry_typedarray_type (const jerry_value_t value) /**< object to get the TypedArray type */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (!ecma_is_typedarray (value))
|
|
{
|
|
return JERRY_TYPEDARRAY_INVALID;
|
|
}
|
|
|
|
ecma_object_t *array_p = ecma_get_object_from_value (value);
|
|
ecma_typedarray_type_t class_type = ecma_get_typedarray_id (array_p);
|
|
|
|
for (uint32_t i = 0; i < sizeof (jerry_typedarray_mappings) / sizeof (jerry_typedarray_mappings[0]); i++)
|
|
{
|
|
if (class_type == jerry_typedarray_mappings[i].id)
|
|
{
|
|
return jerry_typedarray_mappings[i].api_type;
|
|
}
|
|
}
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
|
|
return JERRY_TYPEDARRAY_INVALID;
|
|
} /* jerry_typedarray_type */
|
|
|
|
/**
|
|
* Get the element count of the TypedArray.
|
|
*
|
|
* @return length of the TypedArray.
|
|
*/
|
|
jerry_length_t
|
|
jerry_typedarray_length (const jerry_value_t value) /**< TypedArray to query */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (ecma_is_typedarray (value))
|
|
{
|
|
ecma_object_t *array_p = ecma_get_object_from_value (value);
|
|
return ecma_typedarray_get_length (array_p);
|
|
}
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
|
|
return 0;
|
|
} /* jerry_typedarray_length */
|
|
|
|
/**
|
|
* Get the underlying ArrayBuffer from a TypedArray.
|
|
*
|
|
* Additionally the byteLength and byteOffset properties are also returned
|
|
* which were specified when the TypedArray was created.
|
|
*
|
|
* Note:
|
|
* the returned value must be freed with a jerry_value_free call
|
|
*
|
|
* @return ArrayBuffer of a TypedArray
|
|
* TypeError if the object is not a TypedArray.
|
|
*/
|
|
jerry_value_t
|
|
jerry_typedarray_buffer (const jerry_value_t value, /**< TypedArray to get the arraybuffer from */
|
|
jerry_length_t *byte_offset, /**< [out] byteOffset property */
|
|
jerry_length_t *byte_length) /**< [out] byteLength property */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_TYPEDARRAY
|
|
if (!ecma_is_typedarray (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_OBJECT_IS_NOT_A_TYPEDARRAY));
|
|
}
|
|
|
|
ecma_object_t *array_p = ecma_get_object_from_value (value);
|
|
uint8_t shift = ecma_typedarray_get_element_size_shift (array_p);
|
|
|
|
if (byte_length != NULL)
|
|
{
|
|
*byte_length = (jerry_length_t) (ecma_typedarray_get_length (array_p) << shift);
|
|
}
|
|
|
|
if (byte_offset != NULL)
|
|
{
|
|
*byte_offset = (jerry_length_t) ecma_typedarray_get_offset (array_p);
|
|
}
|
|
|
|
ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (array_p);
|
|
ecma_ref_object (arraybuffer_p);
|
|
return jerry_return (ecma_make_object_value (arraybuffer_p));
|
|
#else /* !JERRY_BUILTIN_TYPEDARRAY */
|
|
JERRY_UNUSED (value);
|
|
JERRY_UNUSED (byte_length);
|
|
JERRY_UNUSED (byte_offset);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_TYPED_ARRAY_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_TYPEDARRAY */
|
|
} /* jerry_typedarray_buffer */
|
|
|
|
/**
|
|
* Parse the given input buffer as a JSON string. The behaviour is equivalent with the "JSON.parse(string)" JS
|
|
* call. The input buffer can be encoded as either cesu-8 or utf-8, but it is the callers responsibility to make sure
|
|
* the encoding is valid.
|
|
*
|
|
*
|
|
* @return object value, or exception
|
|
*/
|
|
jerry_value_t
|
|
jerry_json_parse (const jerry_char_t *string_p, /**< json string */
|
|
jerry_size_t string_size) /**< json string size */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_JSON
|
|
ecma_value_t ret_value = ecma_builtin_json_parse_buffer (string_p, string_size);
|
|
|
|
if (ecma_is_value_undefined (ret_value))
|
|
{
|
|
ret_value = jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_JSON_STRING_PARSE_ERROR));
|
|
}
|
|
|
|
return jerry_return (ret_value);
|
|
#else /* !JERRY_BUILTIN_JSON */
|
|
JERRY_UNUSED (string_p);
|
|
JERRY_UNUSED (string_size);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_JSON_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_JSON */
|
|
} /* jerry_json_parse */
|
|
|
|
/**
|
|
* Create a JSON string from a JavaScript value.
|
|
*
|
|
* The behaviour is equivalent with the "JSON.stringify(input_value)" JS call.
|
|
*
|
|
* Note:
|
|
* The returned value must be freed with jerry_value_free,
|
|
*
|
|
* @return - jerry_value_t containing a JSON string.
|
|
* - Error value if there was a problem during the stringification.
|
|
*/
|
|
jerry_value_t
|
|
jerry_json_stringify (const jerry_value_t input_value) /**< a value to stringify */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
#if JERRY_BUILTIN_JSON
|
|
if (ecma_is_value_exception (input_value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
|
|
ecma_value_t ret_value = ecma_builtin_json_stringify_no_opts (input_value);
|
|
|
|
if (ecma_is_value_undefined (ret_value))
|
|
{
|
|
ret_value = jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_JSON_STRINGIFY_ERROR));
|
|
}
|
|
|
|
return jerry_return (ret_value);
|
|
#else /* JERRY_BUILTIN_JSON */
|
|
JERRY_UNUSED (input_value);
|
|
|
|
return jerry_throw_sz (JERRY_ERROR_SYNTAX, ecma_get_error_msg (ECMA_ERR_JSON_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_JSON */
|
|
} /* jerry_json_stringify */
|
|
|
|
/**
|
|
* Create a container type specified in jerry_container_type_t.
|
|
* The container can be created with a list of arguments, which will be passed to the container constructor to be
|
|
* inserted to the container.
|
|
*
|
|
* Note:
|
|
* The returned value must be freed with jerry_value_free
|
|
* @return jerry_value_t representing a container with the given type.
|
|
*/
|
|
jerry_value_t
|
|
jerry_container (jerry_container_type_t container_type, /**< Type of the container */
|
|
const jerry_value_t *arguments_list_p, /**< arguments list */
|
|
jerry_length_t arguments_list_len) /**< Length of arguments list */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_CONTAINER
|
|
for (jerry_length_t i = 0; i < arguments_list_len; i++)
|
|
{
|
|
if (ecma_is_value_exception (arguments_list_p[i]))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_VALUE_MSG));
|
|
}
|
|
}
|
|
|
|
lit_magic_string_id_t lit_id;
|
|
ecma_builtin_id_t proto_id;
|
|
ecma_builtin_id_t ctor_id;
|
|
|
|
switch (container_type)
|
|
{
|
|
case JERRY_CONTAINER_TYPE_MAP:
|
|
{
|
|
lit_id = LIT_MAGIC_STRING_MAP_UL;
|
|
proto_id = ECMA_BUILTIN_ID_MAP_PROTOTYPE;
|
|
ctor_id = ECMA_BUILTIN_ID_MAP;
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_TYPE_SET:
|
|
{
|
|
lit_id = LIT_MAGIC_STRING_SET_UL;
|
|
proto_id = ECMA_BUILTIN_ID_SET_PROTOTYPE;
|
|
ctor_id = ECMA_BUILTIN_ID_SET;
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_TYPE_WEAKMAP:
|
|
{
|
|
lit_id = LIT_MAGIC_STRING_WEAKMAP_UL;
|
|
proto_id = ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE;
|
|
ctor_id = ECMA_BUILTIN_ID_WEAKMAP;
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_TYPE_WEAKSET:
|
|
{
|
|
lit_id = LIT_MAGIC_STRING_WEAKSET_UL;
|
|
proto_id = ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE;
|
|
ctor_id = ECMA_BUILTIN_ID_WEAKSET;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INVALID_CONTAINER_TYPE));
|
|
}
|
|
}
|
|
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target_p);
|
|
|
|
if (old_new_target_p == NULL)
|
|
{
|
|
JERRY_CONTEXT (current_new_target_p) = ecma_builtin_get (ctor_id);
|
|
}
|
|
|
|
ecma_value_t container_value = ecma_op_container_create (arguments_list_p, arguments_list_len, lit_id, proto_id);
|
|
|
|
JERRY_CONTEXT (current_new_target_p) = old_new_target_p;
|
|
return jerry_return (container_value);
|
|
#else /* !JERRY_BUILTIN_CONTAINER */
|
|
JERRY_UNUSED (arguments_list_p);
|
|
JERRY_UNUSED (arguments_list_len);
|
|
JERRY_UNUSED (container_type);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_CONTAINER */
|
|
} /* jerry_container */
|
|
|
|
/**
|
|
* Get the type of the given container object.
|
|
*
|
|
* @return Corresponding type to the given container object.
|
|
*/
|
|
jerry_container_type_t
|
|
jerry_container_type (const jerry_value_t value) /**< the container object */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_CONTAINER
|
|
if (ecma_is_value_object (value))
|
|
{
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
|
|
|
if (ecma_object_class_is (obj_p, ECMA_OBJECT_CLASS_CONTAINER))
|
|
{
|
|
switch (((ecma_extended_object_t *) obj_p)->u.cls.u2.container_id)
|
|
{
|
|
case LIT_MAGIC_STRING_MAP_UL:
|
|
{
|
|
return JERRY_CONTAINER_TYPE_MAP;
|
|
}
|
|
case LIT_MAGIC_STRING_SET_UL:
|
|
{
|
|
return JERRY_CONTAINER_TYPE_SET;
|
|
}
|
|
case LIT_MAGIC_STRING_WEAKMAP_UL:
|
|
{
|
|
return JERRY_CONTAINER_TYPE_WEAKMAP;
|
|
}
|
|
case LIT_MAGIC_STRING_WEAKSET_UL:
|
|
{
|
|
return JERRY_CONTAINER_TYPE_WEAKSET;
|
|
}
|
|
default:
|
|
{
|
|
return JERRY_CONTAINER_TYPE_INVALID;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#else /* !JERRY_BUILTIN_CONTAINER */
|
|
JERRY_UNUSED (value);
|
|
#endif /* JERRY_BUILTIN_CONTAINER */
|
|
return JERRY_CONTAINER_TYPE_INVALID;
|
|
} /* jerry_container_type */
|
|
|
|
/**
|
|
* Return a new array containing elements from a Container or a Container Iterator.
|
|
* Sets the boolean input value to `true` if the container object has key/value pairs.
|
|
*
|
|
* Note:
|
|
* the returned value must be freed with a jerry_value_free call
|
|
*
|
|
* @return an array of items for maps/sets or their iterators, error otherwise
|
|
*/
|
|
jerry_value_t
|
|
jerry_container_to_array (const jerry_value_t value, /**< the container or iterator object */
|
|
bool *is_key_value_p) /**< [out] is key-value structure */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
|
|
#if JERRY_BUILTIN_CONTAINER
|
|
if (!ecma_is_value_object (value))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NEEDED));
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
|
|
|
if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_CLASS)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NEEDED));
|
|
}
|
|
|
|
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
|
|
|
|
uint32_t entry_count;
|
|
uint8_t entry_size;
|
|
|
|
uint32_t index = 0;
|
|
uint8_t iterator_kind = ECMA_ITERATOR__COUNT;
|
|
ecma_value_t *start_p;
|
|
|
|
*is_key_value_p = false;
|
|
|
|
if (ext_obj_p->u.cls.type == ECMA_OBJECT_CLASS_MAP_ITERATOR
|
|
|| ext_obj_p->u.cls.type == ECMA_OBJECT_CLASS_SET_ITERATOR)
|
|
{
|
|
ecma_value_t iterated_value = ext_obj_p->u.cls.u3.iterated_value;
|
|
|
|
if (ecma_is_value_empty (iterated_value))
|
|
{
|
|
return ecma_op_new_array_object_from_collection (ecma_new_collection (), false);
|
|
}
|
|
|
|
ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) (ecma_get_object_from_value (iterated_value));
|
|
|
|
ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, map_object_p->u.cls.u3.value);
|
|
entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
|
|
index = ext_obj_p->u.cls.u2.iterator_index;
|
|
|
|
entry_size = ecma_op_container_entry_size (map_object_p->u.cls.u2.container_id);
|
|
start_p = ECMA_CONTAINER_START (container_p);
|
|
|
|
iterator_kind = ext_obj_p->u.cls.u1.iterator_kind;
|
|
}
|
|
else if (jerry_container_type (value) != JERRY_CONTAINER_TYPE_INVALID)
|
|
{
|
|
ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, ext_obj_p->u.cls.u3.value);
|
|
entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
|
|
entry_size = ecma_op_container_entry_size (ext_obj_p->u.cls.u2.container_id);
|
|
|
|
index = 0;
|
|
iterator_kind = ECMA_ITERATOR_KEYS;
|
|
start_p = ECMA_CONTAINER_START (container_p);
|
|
|
|
if (ext_obj_p->u.cls.u2.container_id == LIT_MAGIC_STRING_MAP_UL
|
|
|| ext_obj_p->u.cls.u2.container_id == LIT_MAGIC_STRING_WEAKMAP_UL)
|
|
{
|
|
iterator_kind = ECMA_ITERATOR_ENTRIES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NEEDED));
|
|
}
|
|
|
|
*is_key_value_p = (iterator_kind == ECMA_ITERATOR_ENTRIES);
|
|
ecma_collection_t *collection_buffer = ecma_new_collection ();
|
|
|
|
for (uint32_t i = index; i < entry_count; i += entry_size)
|
|
{
|
|
ecma_value_t *entry_p = start_p + i;
|
|
|
|
if (ecma_is_value_empty (*entry_p))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (iterator_kind != ECMA_ITERATOR_VALUES)
|
|
{
|
|
ecma_collection_push_back (collection_buffer, ecma_copy_value_if_not_object (entry_p[0]));
|
|
}
|
|
|
|
if (iterator_kind != ECMA_ITERATOR_KEYS)
|
|
{
|
|
ecma_collection_push_back (collection_buffer, ecma_copy_value_if_not_object (entry_p[1]));
|
|
}
|
|
}
|
|
return ecma_op_new_array_object_from_collection (collection_buffer, false);
|
|
#else /* !JERRY_BUILTIN_CONTAINER */
|
|
JERRY_UNUSED (value);
|
|
JERRY_UNUSED (is_key_value_p);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_CONTAINER */
|
|
} /* jerry_container_to_array */
|
|
|
|
/**
|
|
* Perform container operation on the given operands (add, get, set, has, delete, size, clear).
|
|
*
|
|
* @return error - if argument is invalid or operation is unsuccessful or unsupported
|
|
* result of the container operation - otherwise.
|
|
*/
|
|
jerry_value_t
|
|
jerry_container_op (jerry_container_op_t operation, /**< container operation */
|
|
jerry_value_t container, /**< container */
|
|
const jerry_value_t *arguments, /**< list of arguments */
|
|
uint32_t arguments_number) /**< number of arguments */
|
|
{
|
|
jerry_assert_api_enabled ();
|
|
#if JERRY_BUILTIN_CONTAINER
|
|
if (!ecma_is_value_object (container))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_IS_NOT_AN_OBJECT));
|
|
}
|
|
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (container);
|
|
|
|
if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_CLASS)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_IS_NOT_A_CONTAINER_OBJECT));
|
|
}
|
|
uint16_t type = ((ecma_extended_object_t *) obj_p)->u.cls.u2.container_id;
|
|
ecma_extended_object_t *container_object_p = ecma_op_container_get_object (container, type);
|
|
|
|
if (container_object_p == NULL)
|
|
{
|
|
return ecma_create_exception_from_context ();
|
|
}
|
|
|
|
switch (operation)
|
|
{
|
|
case JERRY_CONTAINER_OP_ADD:
|
|
case JERRY_CONTAINER_OP_DELETE:
|
|
case JERRY_CONTAINER_OP_GET:
|
|
case JERRY_CONTAINER_OP_HAS:
|
|
{
|
|
if (arguments_number != 1 || ecma_is_value_exception (arguments[0]))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_OP_SET:
|
|
{
|
|
if (arguments_number != 2 || ecma_is_value_exception (arguments[0]) || ecma_is_value_exception (arguments[1]))
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_OP_CLEAR:
|
|
case JERRY_CONTAINER_OP_SIZE:
|
|
{
|
|
if (arguments_number != 0)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_WRONG_ARGS_MSG));
|
|
}
|
|
}
|
|
|
|
jerry_value_t result;
|
|
|
|
switch (operation)
|
|
{
|
|
case JERRY_CONTAINER_OP_ADD:
|
|
{
|
|
if (type == LIT_MAGIC_STRING_MAP_UL || type == LIT_MAGIC_STRING_WEAKMAP_UL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_CALL));
|
|
}
|
|
result = ecma_op_container_set (container_object_p, arguments[0], arguments[0], type);
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_OP_GET:
|
|
{
|
|
if (type == LIT_MAGIC_STRING_SET_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_CALL));
|
|
}
|
|
result = ecma_op_container_get (container_object_p, arguments[0], type);
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_OP_SET:
|
|
{
|
|
if (type == LIT_MAGIC_STRING_SET_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_CALL));
|
|
}
|
|
result = ecma_op_container_set (container_object_p, arguments[0], arguments[1], type);
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_OP_HAS:
|
|
{
|
|
result = ecma_op_container_has (container_object_p, arguments[0], type);
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_OP_DELETE:
|
|
{
|
|
if (type == LIT_MAGIC_STRING_WEAKMAP_UL || type == LIT_MAGIC_STRING_WEAKSET_UL)
|
|
{
|
|
result = ecma_op_container_delete_weak (container_object_p, arguments[0], type);
|
|
break;
|
|
}
|
|
result = ecma_op_container_delete (container_object_p, arguments[0], type);
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_OP_SIZE:
|
|
{
|
|
result = ecma_op_container_size (container_object_p);
|
|
break;
|
|
}
|
|
case JERRY_CONTAINER_OP_CLEAR:
|
|
{
|
|
if (type == LIT_MAGIC_STRING_WEAKSET_UL || type == LIT_MAGIC_STRING_WEAKMAP_UL)
|
|
{
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_INCORRECT_TYPE_CALL));
|
|
}
|
|
result = ecma_op_container_clear (container_object_p);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
result = jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_UNSUPPORTED_CONTAINER_OPERATION));
|
|
break;
|
|
}
|
|
}
|
|
return jerry_return (result);
|
|
#else /* !JERRY_BUILTIN_CONTAINER */
|
|
JERRY_UNUSED (operation);
|
|
JERRY_UNUSED (container);
|
|
JERRY_UNUSED (arguments);
|
|
JERRY_UNUSED (arguments_number);
|
|
return jerry_throw_sz (JERRY_ERROR_TYPE, ecma_get_error_msg (ECMA_ERR_CONTAINER_NOT_SUPPORTED));
|
|
#endif /* JERRY_BUILTIN_CONTAINER */
|
|
} /* jerry_container_op */
|
|
|
|
/**
|
|
* @}
|
|
*/
|