Parse functions directly (#2015)

This patch adds direct function source code parsing, which
is useful to avoid source code duplications. The patch
also improves the Function constructor.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2017-09-21 11:03:23 +02:00
committed by Dániel Bátyai
parent 7713d30702
commit 8d916a44f1
11 changed files with 427 additions and 244 deletions
+48 -11
View File
@@ -667,7 +667,7 @@ jerry_parse (const jerry_char_t *source_p,
bool is_strict);
```
- `source_p` - string, containing source code to parse. It must be a valid utf8 string.
- `source_p` - string, containing source code to parse (must be a valid UTF8 string).
- `source_size` - size of the string, in bytes.
- `is_strict` - defines strict mode.
- return value
@@ -706,8 +706,8 @@ main (void)
**Summary**
Parse script and construct an ECMAScript function. The lexical
environment is set to the global lexical environment. The name
(usually a file name) is also passed to this function which is
environment is set to the global lexical environment. The resource
name (usually a file name) is also passed to this function which is
used by the debugger to find the source code.
*Note*: The returned value must be freed with [jerry_release_value](#jerry_release_value) when it
@@ -717,25 +717,62 @@ is no longer needed.
```c
jerry_value_t
jerry_parse_named_resource (const jerry_char_t *name_p, /**< name (usually a file name) */
size_t name_length, /**< length of name */
jerry_parse_named_resource (const jerry_char_t *resource_name_p, /**< resource name (usually a file name) */
size_t resource_name_length, /**< length of resource name */
const jerry_char_t *source_p, /**< script source */
size_t source_size, /**< script source size */
bool is_strict) /**< strict mode */
{
```
- `name_p` - name, usually a file name
- `name_length` - size of the file name, in bytes
- `source_p` - string, containing source code to parse. It must be a valid UTF8 string
- `source_size` - size of the string, in bytes
- `is_strict` - defines strict mode
- `resource_name_p` - resource name, usually a file name (must be a valid UTF8 string).
- `resource_name_length` - size of the resource name, in bytes.
- `source_p` - string, containing source code to parse (must be a valid UTF8 string).
- `source_size` - size of the string, in bytes.
- `is_strict` - defines strict mode.
- return value
- function object value, if script was parsed successfully,
- thrown error, otherwise
This function is identical to [jerry_parse](#jerry_parse), except that an additional filename parameter has been added.
## jerry_parse_function
**Summary**
Parse function source code and construct an ECMAScript
function. The function arguments and function body are
passed as separated arguments. The lexical environment
is set to the global lexical environment. The resource
name (usually a file name) is also passed to this function
which is used by the debugger to find the source code.
*Note*: The returned value must be freed with [jerry_release_value](#jerry_release_value) when it
is no longer needed.
**Prototype**
```c
jerry_value_t
jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (usually a file name) */
size_t resource_name_length, /**< length of resource name */
const jerry_char_t *arg_list_p, /**< script source */
size_t arg_list_size, /**< script source size */
const jerry_char_t *source_p, /**< script source */
size_t source_size, /**< script source size */
bool is_strict) /**< strict mode */
```
- `resource_name_p` - resource name, usually a file name (must be a valid UTF8 string).
- `resource_name_length` - size of the resource name, in bytes.
- `arg_list_p` - argument list of the function (must be a valid UTF8 string).
- `arg_list_size` - size of the argument list, in bytes.
- `source_p` - string, containing source code to parse (must be a valid UTF8 string).
- `source_size` - size of the string, in bytes.
- `is_strict` - defines strict mode.
- return value
- function object value, if script was parsed successfully,
- thrown error, otherwise
## jerry_run
**Summary**
+6 -2
View File
@@ -479,7 +479,9 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
JMEM_ALIGNMENT);
globals.snapshot_error_occured = false;
parse_status = parser_parse_script (source_p,
parse_status = parser_parse_script (NULL,
0,
source_p,
source_size,
is_strict,
&bytecode_data_p);
@@ -900,7 +902,9 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
ecma_value_t parse_status;
ecma_compiled_code_t *bytecode_data_p;
parse_status = parser_parse_script (source_p,
parse_status = parser_parse_script (NULL,
0,
source_p,
source_size,
is_strict,
&bytecode_data_p);
+84 -10
View File
@@ -348,7 +348,9 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */
ecma_compiled_code_t *bytecode_data_p;
ecma_value_t parse_status;
parse_status = parser_parse_script (source_p,
parse_status = parser_parse_script (NULL,
0,
source_p,
source_size,
is_strict,
&bytecode_data_p);
@@ -385,28 +387,100 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */
* thrown error - otherwise
*/
jerry_value_t
jerry_parse_named_resource (const jerry_char_t *name_p, /**< name (usually a file name) */
size_t name_length, /**< length of name */
jerry_parse_named_resource (const jerry_char_t *resource_name_p, /**< resource name (usually a file name) */
size_t resource_name_length, /**< length of resource name */
const jerry_char_t *source_p, /**< script source */
size_t source_size, /**< script source size */
bool is_strict) /**< strict mode */
{
#ifdef JERRY_DEBUGGER
#if defined JERRY_DEBUGGER && defined JERRY_JS_PARSER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE_NAME,
JERRY_DEBUGGER_NO_SUBTYPE,
name_p,
name_length);
resource_name_p,
resource_name_length);
}
#else /* JERRY_DEBUGGER */
JERRY_UNUSED (name_p);
JERRY_UNUSED (name_length);
#endif /* JERRY_DEBUGGER */
#else /* !(JERRY_DEBUGGER && JERRY_JS_PARSER) */
JERRY_UNUSED (resource_name_p);
JERRY_UNUSED (resource_name_length);
#endif /* JERRY_DEBUGGER && JERRY_JS_PARSER */
return jerry_parse (source_p, source_size, is_strict);
} /* jerry_parse_named_resource */
/**
* Parse function and construct an EcmaScript function. The lexical
* environment is set to the global lexical environment.
*
* @return function object value - if script was parsed successfully,
* thrown error - otherwise
*/
jerry_value_t
jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (usually a file name) */
size_t resource_name_length, /**< length of resource name */
const jerry_char_t *arg_list_p, /**< script source */
size_t arg_list_size, /**< script source size */
const jerry_char_t *source_p, /**< script source */
size_t source_size, /**< script source size */
bool is_strict) /**< strict mode */
{
#if defined JERRY_DEBUGGER && defined JERRY_JS_PARSER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE_NAME,
JERRY_DEBUGGER_NO_SUBTYPE,
resource_name_p,
resource_name_length);
}
#else /* !(JERRY_DEBUGGER && JERRY_JS_PARSER) */
JERRY_UNUSED (resource_name_p);
JERRY_UNUSED (resource_name_length);
#endif /* JERRY_DEBUGGER && JERRY_JS_PARSER */
#if JERRY_JS_PARSER
jerry_assert_api_available ();
ecma_compiled_code_t *bytecode_data_p;
ecma_value_t parse_status;
if (arg_list_p == NULL)
{
/* Must not be a NULL value. */
arg_list_p = (const jerry_char_t *) "";
}
parse_status = parser_parse_script (arg_list_p,
arg_list_size,
source_p,
source_size,
is_strict,
&bytecode_data_p);
if (ECMA_IS_VALUE_ERROR (parse_status))
{
return parse_status;
}
ecma_free_value (parse_status);
ecma_object_t *lex_env_p = ecma_get_global_environment ();
ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p,
bytecode_data_p);
ecma_bytecode_deref (bytecode_data_p);
return ecma_make_object_value (func_obj_p);
#else /* !JERRY_JS_PARSER */
JERRY_UNUSED (arg_list_p);
JERRY_UNUSED (arg_list_size);
JERRY_UNUSED (source_p);
JERRY_UNUSED (source_size);
JERRY_UNUSED (is_strict);
return ecma_raise_syntax_error (ECMA_ERR_MSG ("The parser has been disabled."));
#endif /* JERRY_JS_PARSER */
} /* jerry_parse_function */
/**
* Run an EcmaScript function created by jerry_parse.
*
@@ -65,116 +65,53 @@ ecma_builtin_function_dispatch_call (const ecma_value_t *arguments_list_p, /**<
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_function_helper_get_function_expression (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
ecma_builtin_function_helper_get_function_arguments (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
ecma_string_t *left_parenthesis_str_p, *right_parenthesis_str_p;
ecma_string_t *left_brace_str_p, *right_brace_str_p;
ecma_string_t *comma_str_p;
ecma_string_t *function_kw_str_p, *empty_str_p;
ecma_string_t *expr_str_p, *concated_str_p;
left_parenthesis_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_LEFT_PARENTHESIS_CHAR);
right_parenthesis_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_RIGHT_PARENTHESIS_CHAR);
left_brace_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
right_brace_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);
comma_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR);
function_kw_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_FUNCTION);
empty_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY);
/* First, we only process the function arguments skipping the function body */
ecma_length_t number_of_function_args = (arguments_list_len == 0 ? 0 : arguments_list_len - 1);
expr_str_p = ecma_concat_ecma_strings (left_parenthesis_str_p, function_kw_str_p);
concated_str_p = ecma_concat_ecma_strings (expr_str_p, left_parenthesis_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
for (ecma_length_t idx = 0;
idx < number_of_function_args && ecma_is_value_empty (ret_value);
idx++)
if (arguments_list_len <= 1)
{
ECMA_TRY_CATCH (str_arg_value,
ecma_op_to_string (arguments_list_p[idx]),
ret_value);
ecma_string_t *str_p = ecma_get_string_from_value (str_arg_value);
concated_str_p = ecma_concat_ecma_strings (expr_str_p, str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
if (idx < number_of_function_args - 1)
{
concated_str_p = ecma_concat_ecma_strings (expr_str_p, comma_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
}
ECMA_FINALIZE (str_arg_value);
return ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY));
}
if (ecma_is_value_empty (ret_value))
ecma_value_t final_str = ecma_op_to_string (arguments_list_p[0]);
if (arguments_list_len == 2 || ECMA_IS_VALUE_ERROR (final_str))
{
concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_parenthesis_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
concated_str_p = ecma_concat_ecma_strings (expr_str_p, left_brace_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
if (arguments_list_len != 0)
{
ECMA_TRY_CATCH (str_arg_value,
ecma_op_to_string (arguments_list_p[arguments_list_len - 1]),
ret_value);
ecma_string_t *body_str_p = ecma_get_string_from_value (str_arg_value);
concated_str_p = ecma_concat_ecma_strings (expr_str_p, body_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
ECMA_FINALIZE (str_arg_value);
}
concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_brace_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_parenthesis_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
return final_str;
}
ecma_string_t *comma_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR);
for (ecma_length_t idx = 1; idx < arguments_list_len - 1; idx++)
{
ecma_value_t new_str = ecma_op_to_string (arguments_list_p[idx]);
if (ECMA_IS_VALUE_ERROR (new_str))
{
ecma_free_value (final_str);
/* Return with the error. */
final_str = new_str;
break;
}
ecma_string_t *final_str_p = ecma_get_string_from_value (final_str);
ecma_string_t *fragment_str_p = ecma_concat_ecma_strings (final_str_p, comma_str_p);
ecma_deref_ecma_string (final_str_p);
ecma_string_t *new_str_p = ecma_get_string_from_value (new_str);
final_str_p = ecma_concat_ecma_strings (fragment_str_p, new_str_p);
ecma_deref_ecma_string (new_str_p);
ecma_deref_ecma_string (fragment_str_p);
final_str = ecma_make_string_value (final_str_p);
}
ecma_deref_ecma_string (left_parenthesis_str_p);
ecma_deref_ecma_string (right_parenthesis_str_p);
ecma_deref_ecma_string (left_brace_str_p);
ecma_deref_ecma_string (right_brace_str_p);
ecma_deref_ecma_string (comma_str_p);
ecma_deref_ecma_string (function_kw_str_p);
ecma_deref_ecma_string (empty_str_p);
if (ecma_is_value_empty (ret_value))
{
ret_value = ecma_make_string_value (expr_str_p);
}
else
{
ecma_deref_ecma_string (expr_str_p);
}
return ret_value;
} /* ecma_builtin_function_helper_get_function_expression */
return final_str;
} /* ecma_builtin_function_helper_get_function_arguments */
/**
* Handle calling [[Construct]] of built-in Function object
@@ -190,18 +127,63 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p,
{
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
ecma_value_t arguments_value = ecma_builtin_function_helper_get_function_arguments (arguments_list_p,
arguments_list_len);
ECMA_TRY_CATCH (arguments_value,
ecma_builtin_function_helper_get_function_expression (arguments_list_p,
arguments_list_len),
ret_value);
if (ECMA_IS_VALUE_ERROR (arguments_value))
{
return arguments_value;
}
ecma_string_t *function_expression_p = ecma_get_string_from_value (arguments_value);
ecma_value_t function_body_value;
ret_value = ecma_op_eval (function_expression_p, false, false);
if (arguments_list_len > 0)
{
function_body_value = ecma_op_to_string (arguments_list_p[arguments_list_len - 1]);
ECMA_FINALIZE (arguments_value);
if (ECMA_IS_VALUE_ERROR (function_body_value))
{
ecma_free_value (arguments_value);
return function_body_value;
}
}
else
{
/* Very unlikely code path, not optimized. */
function_body_value = ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY));
}
ecma_string_t *arguments_str_p = ecma_get_string_from_value (arguments_value);
ecma_string_t *function_body_str_p = ecma_get_string_from_value (function_body_value);
ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size);
ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size);
ecma_compiled_code_t *bytecode_data_p;
ecma_value_t ret_value = parser_parse_script (arguments_buffer_p,
arguments_buffer_size,
function_body_buffer_p,
function_body_buffer_size,
false,
&bytecode_data_p);
if (!ECMA_IS_VALUE_ERROR (ret_value))
{
JERRY_ASSERT (ecma_is_value_true (ret_value));
ecma_object_t *func_obj_p = ecma_op_create_function_object (ecma_get_global_environment (),
bytecode_data_p);
ecma_bytecode_deref (bytecode_data_p);
ret_value = ecma_make_object_value (func_obj_p);
}
ECMA_FINALIZE_UTF8_STRING (function_body_buffer_p, function_body_buffer_size);
ECMA_FINALIZE_UTF8_STRING (arguments_buffer_p, arguments_buffer_size);
ecma_deref_ecma_string (arguments_str_p);
ecma_deref_ecma_string (function_body_str_p);
return ret_value;
} /* ecma_builtin_function_dispatch_construct */
+3 -1
View File
@@ -88,7 +88,9 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b
bool is_strict_call = (is_direct && is_called_from_strict_mode_code);
ecma_value_t parse_status = parser_parse_script (code_p,
ecma_value_t parse_status = parser_parse_script (NULL,
0,
code_p,
code_buffer_size,
is_strict_call,
&bytecode_data_p);
+4 -1
View File
@@ -255,8 +255,11 @@ bool jerry_get_memory_stats (jerry_heap_stats_t *out_stats_p);
*/
bool jerry_run_simple (const jerry_char_t *script_source_p, size_t script_source_size, jerry_init_flag_t flags);
jerry_value_t jerry_parse (const jerry_char_t *source_p, size_t source_size, bool is_strict);
jerry_value_t jerry_parse_named_resource (const jerry_char_t *name_p, size_t name_length,
jerry_value_t jerry_parse_named_resource (const jerry_char_t *resource_name_p, size_t resource_name_length,
const jerry_char_t *source_p, size_t source_size, bool is_strict);
jerry_value_t jerry_parse_function (const jerry_char_t *resource_name_p, size_t resource_name_length,
const jerry_char_t *arg_list_p, size_t arg_list_size,
const jerry_char_t *source_p, size_t source_size, bool is_strict);
jerry_value_t jerry_run (const jerry_value_t func_val);
jerry_value_t jerry_eval (const jerry_char_t *source_p, size_t source_size, bool is_strict);
+2 -2
View File
@@ -23,8 +23,6 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPACE_CHAR, " ")
#if !defined (CONFIG_DISABLE_JSON_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR, "\"")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LEFT_PARENTHESIS_CHAR, "(")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RIGHT_PARENTHESIS_CHAR, ")")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMMA_CHAR, ",")
#if !defined (CONFIG_DISABLE_NUMBER_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MINUS_CHAR, "-")
@@ -46,8 +44,10 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_G_CHAR, "g")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_I_CHAR, "i")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_M_CHAR, "m")
#endif
#if !defined (CONFIG_DISABLE_JSON_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LEFT_BRACE_CHAR, "{")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR, "}")
#endif
#if !defined (CONFIG_DISABLE_MATH_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PI_U, "PI")
#endif
-2
View File
@@ -26,8 +26,6 @@ LIT_MAGIC_STRING__EMPTY = ""
LIT_MAGIC_STRING_NEW_LINE_CHAR = "\n"
LIT_MAGIC_STRING_SPACE_CHAR = " "
LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR = "\""
LIT_MAGIC_STRING_LEFT_PARENTHESIS_CHAR = "("
LIT_MAGIC_STRING_RIGHT_PARENTHESIS_CHAR = ")"
LIT_MAGIC_STRING_COMMA_CHAR = ","
LIT_MAGIC_STRING_MINUS_CHAR = "-"
LIT_MAGIC_STRING_SLASH_CHAR = "/"
+158 -105
View File
@@ -40,7 +40,7 @@ parser_copy_identifiers (parser_context_t *context_p) /**< context */
{
parser_saved_context_t *parent_p = context_p->last_context_p;
if (parent_p == NULL || parent_p->prev_context_p == NULL)
if (parent_p == NULL || !(parent_p->status_flags & PARSER_IS_FUNCTION))
{
/* Return if this function is not a nested function. */
return;
@@ -1965,6 +1965,109 @@ parser_free_literals (parser_list_t *literal_pool_p) /**< literals */
parser_list_free (literal_pool_p);
} /* parser_free_literals */
/**
* Parse function arguments
*/
static void
parser_parse_function_arguments (parser_context_t *context_p, /**< context */
lexer_token_type_t end_type) /**< expected end type */
{
if (context_p->token.type == end_type)
{
return;
}
while (true)
{
uint16_t literal_count = context_p->literal_count;
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
LEXER_IDENT_LITERAL);
if (literal_count == context_p->literal_count
|| context_p->token.literal_is_reserved
|| context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY)
{
context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG;
}
if (context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS)
{
uint8_t literal_status_flags = context_p->lit_object.literal_p->status_flags;
literal_status_flags = (uint8_t) (literal_status_flags & ~LEXER_FLAG_NO_REG_STORE);
context_p->lit_object.literal_p->status_flags = literal_status_flags;
context_p->status_flags |= PARSER_ARGUMENTS_NOT_NEEDED;
context_p->status_flags &= ~(PARSER_LEXICAL_ENV_NEEDED | PARSER_ARGUMENTS_NEEDED);
}
if (context_p->literal_count == literal_count)
{
lexer_literal_t *literal_p;
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
}
literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
*literal_p = *context_p->lit_object.literal_p;
literal_p->status_flags &= LEXER_FLAG_SOURCE_PTR;
literal_p->status_flags |= LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_ARGUMENT;
context_p->literal_count++;
/* There cannot be references from the byte code to these literals
* since no byte code has been emitted yet. Therefore there is no
* need to set the index field. */
context_p->lit_object.literal_p->type = LEXER_UNUSED_LITERAL;
/* Only the LEXER_FLAG_FUNCTION_ARGUMENT flag is kept. */
context_p->lit_object.literal_p->status_flags &= LEXER_FLAG_FUNCTION_ARGUMENT;
context_p->lit_object.literal_p->u.char_p = NULL;
}
else
{
uint8_t lexer_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_ARGUMENT;
context_p->lit_object.literal_p->status_flags |= lexer_flags;
}
context_p->argument_count++;
if (context_p->argument_count >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
{
parser_raise_error (context_p, PARSER_ERR_REGISTER_LIMIT_REACHED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COMMA)
{
break;
}
lexer_next_token (context_p);
}
if (context_p->token.type != end_type)
{
parser_error_t error = ((end_type == LEXER_RIGHT_PAREN) ? PARSER_ERR_RIGHT_PAREN_EXPECTED
: PARSER_ERR_IDENTIFIER_EXPECTED);
parser_raise_error (context_p, error);
}
context_p->register_count = context_p->argument_count;
} /* parser_parse_function_arguments */
/**
* Parse and compile EcmaScript source code
*
@@ -1973,8 +2076,10 @@ parser_free_literals (parser_list_t *literal_pool_p) /**< literals */
* @return compiled code
*/
static ecma_compiled_code_t *
parser_parse_source (const uint8_t *source_p, /**< valid UTF-8 source code */
size_t size, /**< size of the source code */
parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
size_t arg_list_size, /**< size of function argument list */
const uint8_t *source_p, /**< valid UTF-8 source code */
size_t source_size, /**< size of the source code */
int strict_mode, /**< strict mode */
parser_error_location_t *error_location_p) /**< error location */
{
@@ -1989,7 +2094,19 @@ parser_parse_source (const uint8_t *source_p, /**< valid UTF-8 source code */
error_location_p->error = PARSER_ERR_NO_ERROR;
}
context.status_flags = PARSER_NO_REG_STORE | PARSER_LEXICAL_ENV_NEEDED | PARSER_ARGUMENTS_NOT_NEEDED;
if (arg_list_p == NULL)
{
context.status_flags = PARSER_NO_REG_STORE | PARSER_LEXICAL_ENV_NEEDED | PARSER_ARGUMENTS_NOT_NEEDED;
context.source_p = source_p;
context.source_end_p = source_p + source_size;
}
else
{
context.status_flags = PARSER_IS_FUNCTION;
context.source_p = arg_list_p;
context.source_end_p = arg_list_p + arg_list_size;
}
context.stack_depth = 0;
context.stack_limit = 0;
context.last_context_p = NULL;
@@ -2000,8 +2117,6 @@ parser_parse_source (const uint8_t *source_p, /**< valid UTF-8 source code */
context.status_flags |= PARSER_IS_STRICT;
}
context.source_p = source_p;
context.source_end_p = source_p + size;
context.line = 1;
context.column = 1;
@@ -2028,7 +2143,9 @@ parser_parse_source (const uint8_t *source_p, /**< valid UTF-8 source code */
if (context.is_show_opcodes)
{
JERRY_DEBUG_MSG ("\n--- Script parsing start ---\n\n");
JERRY_DEBUG_MSG ("\n--- %s parsing start ---\n\n",
(arg_list_p == NULL) ? "Script"
: "Function");
}
#endif /* PARSER_DUMP_BYTE_CODE */
@@ -2046,6 +2163,18 @@ parser_parse_source (const uint8_t *source_p, /**< valid UTF-8 source code */
* lexer_next_token() must be immediately called. */
lexer_next_token (&context);
if (arg_list_p != NULL)
{
parser_parse_function_arguments (&context, LEXER_EOS);
context.source_p = source_p;
context.source_end_p = source_p + source_size;
context.line = 1;
context.column = 1;
lexer_next_token (&context);
}
parser_parse_statements (&context);
/* When the parsing is successful, only the
@@ -2066,7 +2195,9 @@ parser_parse_source (const uint8_t *source_p, /**< valid UTF-8 source code */
#ifdef PARSER_DUMP_BYTE_CODE
if (context.is_show_opcodes)
{
JERRY_DEBUG_MSG ("\nScript parsing successfully completed. Total byte code size: %d bytes\n",
JERRY_DEBUG_MSG ("\n%s parsing successfully completed. Total byte code size: %d bytes\n",
(arg_list_p == NULL) ? "Script"
: "Function",
(int) context.total_byte_code_size);
}
#endif /* PARSER_DUMP_BYTE_CODE */
@@ -2100,7 +2231,9 @@ parser_parse_source (const uint8_t *source_p, /**< valid UTF-8 source code */
#ifdef PARSER_DUMP_BYTE_CODE
if (context.is_show_opcodes)
{
JERRY_DEBUG_MSG ("\n--- Script parsing end ---\n\n");
JERRY_DEBUG_MSG ("\n--- %s parsing end ---\n\n",
(arg_list_p == NULL) ? "Script"
: "Function");
}
#endif /* PARSER_DUMP_BYTE_CODE */
@@ -2241,99 +2374,9 @@ parser_parse_function (parser_context_t *context_p, /**< context */
lexer_next_token (context_p);
/* Argument parsing. */
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
while (true)
{
uint16_t literal_count = context_p->literal_count;
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
LEXER_IDENT_LITERAL);
if (literal_count == context_p->literal_count
|| context_p->token.literal_is_reserved
|| context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY)
{
context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG;
}
if (context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS)
{
uint8_t literal_status_flags = context_p->lit_object.literal_p->status_flags;
literal_status_flags = (uint8_t) (literal_status_flags & ~LEXER_FLAG_NO_REG_STORE);
context_p->lit_object.literal_p->status_flags = literal_status_flags;
context_p->status_flags |= PARSER_ARGUMENTS_NOT_NEEDED;
context_p->status_flags &= ~(PARSER_LEXICAL_ENV_NEEDED | PARSER_ARGUMENTS_NEEDED);
}
if (context_p->literal_count == literal_count)
{
lexer_literal_t *literal_p;
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
}
literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
*literal_p = *context_p->lit_object.literal_p;
literal_p->status_flags &= LEXER_FLAG_SOURCE_PTR;
literal_p->status_flags |= LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_ARGUMENT;
context_p->literal_count++;
/* There cannot be references from the byte code to these literals
* since no byte code has been emitted yet. Therefore there is no
* need to set the index field. */
context_p->lit_object.literal_p->type = LEXER_UNUSED_LITERAL;
/* Only the LEXER_FLAG_FUNCTION_ARGUMENT flag is kept. */
context_p->lit_object.literal_p->status_flags &= LEXER_FLAG_FUNCTION_ARGUMENT;
context_p->lit_object.literal_p->u.char_p = NULL;
}
else
{
uint8_t lexer_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_ARGUMENT;
context_p->lit_object.literal_p->status_flags |= lexer_flags;
}
context_p->argument_count++;
if (context_p->argument_count >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
{
parser_raise_error (context_p, PARSER_ERR_REGISTER_LIMIT_REACHED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COMMA)
{
break;
}
lexer_next_token (context_p);
}
}
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
parser_parse_function_arguments (context_p, LEXER_RIGHT_PAREN);
lexer_next_token (context_p);
context_p->register_count = context_p->argument_count;
if ((context_p->status_flags & PARSER_IS_PROPERTY_GETTER)
&& context_p->argument_count != 0)
{
@@ -2480,14 +2523,17 @@ parser_send_breakpoints (parser_context_t *context_p, /**< context */
* Parse EcamScript source code
*
* Note:
* if arg_list_p is not NULL, a function body is parsed
* returned value must be freed with ecma_free_value
*
* @return true - if success
* syntax error - otherwise
*/
ecma_value_t
parser_parse_script (const uint8_t *source_p, /**< source code */
size_t size, /**< size of the source code */
parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */
size_t arg_list_size, /**< size of function argument list */
const uint8_t *source_p, /**< source code */
size_t source_size, /**< size of the source code */
bool is_strict, /**< strict mode */
ecma_compiled_code_t **bytecode_data_p) /**< [out] JS bytecode */
{
@@ -2500,11 +2546,16 @@ parser_parse_script (const uint8_t *source_p, /**< source code */
jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE,
JERRY_DEBUGGER_NO_SUBTYPE,
source_p,
size);
source_size);
}
#endif /* JERRY_DEBUGGER */
*bytecode_data_p = parser_parse_source (source_p, size, is_strict, &parser_error);
*bytecode_data_p = parser_parse_source (arg_list_p,
arg_list_size,
source_p,
source_size,
is_strict,
&parser_error);
if (!*bytecode_data_p)
{
@@ -2547,8 +2598,10 @@ parser_parse_script (const uint8_t *source_p, /**< source code */
}
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
#else /* !JERRY_JS_PARSER */
JERRY_UNUSED (arg_list_p);
JERRY_UNUSED (arg_list_size);
JERRY_UNUSED (source_p);
JERRY_UNUSED (size);
JERRY_UNUSED (source_size);
JERRY_UNUSED (is_strict);
JERRY_UNUSED (bytecode_data_p);
+3 -2
View File
@@ -128,8 +128,9 @@ typedef struct
} parser_error_location_t;
/* Note: source must be a valid UTF-8 string */
ecma_value_t parser_parse_script (const uint8_t *source_p, size_t size, bool is_strict,
ecma_compiled_code_t **bytecode_data_p);
ecma_value_t parser_parse_script (const uint8_t *arg_list_p, size_t arg_list_size,
const uint8_t *source_p, size_t source_size,
bool is_strict, ecma_compiled_code_t **bytecode_data_p);
const char *parser_error_to_string (parser_error_t);
+29
View File
@@ -1032,6 +1032,35 @@ main (void)
TEST_ASSERT (number_val != number_val);
jerry_release_value (val_t);
/* Test: create function */
const char *func_resource = "unknown";
const char *func_arg_list = "a , b,c";
const char *func_src = " return 5 + a+\nb+c";
jerry_value_t func_val = jerry_parse_function ((const jerry_char_t *) func_resource,
strlen (func_resource),
(const jerry_char_t *) func_arg_list,
strlen (func_arg_list),
(const jerry_char_t *) func_src,
strlen (func_src),
false);
TEST_ASSERT (!jerry_value_has_error_flag (func_val));
jerry_value_t func_args[3] =
{
jerry_create_number (4),
jerry_create_number (6),
jerry_create_number (-2)
};
val_t = jerry_call_function (func_val, func_args[0], func_args, 3);
number_val = jerry_get_number_value (val_t);
TEST_ASSERT (number_val == 13.0);
jerry_release_value (val_t);
jerry_release_value (func_val);
jerry_cleanup ();
TEST_ASSERT (test_api_is_free_callback_was_called);