Implement the core of let/const statement. (#3239)

This patch implements the core part of let/const statements. Redeclarations are correctly
detected and separate contexts are correctly created for these statements. Register
optimizations are also emplyed whenever possible.

Lots of features are still missing:
 - checking the var statements in eval
 - const are treated as lets
 - single statement checks are missing
 - export declarations are exported as vars, let/const export is not supported

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2019-10-25 18:08:10 +02:00 committed by Dániel Bátyai
parent 4b352758c1
commit 3d797b8836
33 changed files with 1997 additions and 217 deletions

View File

@ -30,7 +30,7 @@ extern "C"
/**
* Jerry snapshot format version.
*/
#define JERRY_SNAPSHOT_VERSION (25u)
#define JERRY_SNAPSHOT_VERSION (26u)
/**
* Flags for jerry_generate_snapshot and jerry_generate_function_snapshot.

View File

@ -192,6 +192,8 @@
#define PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION 3
/* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4
/* PARSER_BLOCK_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_BLOCK_CONTEXT_STACK_ALLOCATION 1
/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1
/* PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION must be <= 4 */
@ -244,6 +246,10 @@
VM_OC_PUSH_ELISON | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_STRICT_EQUAL, -1, \
VM_OC_BRANCH_IF_STRICT_EQUAL) \
CBC_OPCODE (CBC_PUSH_NULL, CBC_NO_FLAG, 1, \
VM_OC_PUSH_NULL | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_BLOCK_CREATE_CONTEXT, \
PARSER_BLOCK_CONTEXT_STACK_ALLOCATION, VM_OC_BLOCK_CREATE_CONTEXT) \
\
/* Basic opcodes. Note: These 4 opcodes must me in this order */ \
CBC_OPCODE (CBC_PUSH_LITERAL, CBC_HAS_LITERAL_ARG, 1, \
@ -260,8 +266,6 @@
VM_OC_PUSH_TRUE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_FALSE, CBC_NO_FLAG, 1, \
VM_OC_PUSH_FALSE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NULL, CBC_NO_FLAG, 1, \
VM_OC_PUSH_NULL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_THIS, CBC_NO_FLAG, 1, \
VM_OC_PUSH_THIS | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NUMBER_0, CBC_NO_FLAG, 1, \
@ -302,6 +306,10 @@
VM_OC_NONE) \
CBC_OPCODE (CBC_INIT_LOCAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_CREATE_VAR_FUNC, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT) \
CBC_OPCODE (CBC_SET_VAR_FUNC, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT) \
CBC_OPCODE (CBC_SET_BYTECODE_PTR, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_RETURN, CBC_NO_FLAG, -1, \
@ -508,8 +516,8 @@
VM_OC_SET_SETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \
CBC_FORWARD_BRANCH (CBC_EXT_TRY_CREATE_CONTEXT, PARSER_TRY_CONTEXT_STACK_ALLOCATION, \
VM_OC_TRY) \
CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \
VM_OC_THROW_REFERENCE_ERROR) \
CBC_OPCODE (CBC_EXT_TRY_CREATE_ENV, CBC_NO_FLAG, 0, \
VM_OC_BLOCK_CREATE_CONTEXT) \
CBC_FORWARD_BRANCH (CBC_EXT_CATCH, 1, \
VM_OC_CATCH) \
CBC_OPCODE (CBC_EXT_PUSH_UNDEFINED_BASE, CBC_NO_FLAG, 1, \
@ -554,6 +562,8 @@
VM_OC_SET_SETTER | VM_OC_GET_STACK_LITERAL) \
CBC_OPCODE (CBC_EXT_RESOLVE_BASE, CBC_NO_FLAG, 0, \
VM_OC_RESOLVE_BASE_FOR_CALL) \
CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \
VM_OC_THROW_REFERENCE_ERROR) \
\
/* Class opcodes */ \
CBC_OPCODE (CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR, CBC_NO_FLAG, 0, \

View File

@ -74,6 +74,9 @@ typedef enum
LEXER_FLAG_SOURCE_PTR = (1 << 2), /**< the literal is directly referenced in the source code
* (no need to allocate memory) */
LEXER_FLAG_LATE_INIT = (1 << 3), /**< initialize this variable after the byte code is freed */
#if ENABLED (JERRY_ES2015)
LEXER_FLAG_GLOBAL = (1 << 4), /**< this local identifier is not a let or const declaration */
#endif /* ENABLED (JERRY_ES2015) */
} lexer_literal_status_flags_t;
/**

View File

@ -1476,7 +1476,14 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */
{
scope_stack_p--;
if (scope_stack_p->map_from == literal_index)
#if ENABLED (JERRY_ES2015)
bool cond = (scope_stack_p->map_from == literal_index
&& scope_stack_p->map_to != PARSER_SCOPE_STACK_FUNC);
#else /* ENABLED (JERRY_ES2015) */
bool cond = (scope_stack_p->map_from == literal_index);
#endif /* ENABLED (JERRY_ES2015) */
if (cond)
{
JERRY_ASSERT (scope_stack_p->map_to >= PARSER_REGISTER_START
|| (literal_p->status_flags & LEXER_FLAG_USED));
@ -2322,7 +2329,7 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
context_p->token.literal_is_reserved = false;
context_p->token.lit_location.type = LEXER_IDENT_LITERAL;
context_p->token.lit_location.has_escape = false;
lexer_construct_literal_object (context_p, &lexer_default_literal, lexer_default_literal.type);
lexer_construct_literal_object (context_p, &lexer_default_literal, literal_type);
context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_CLASS_OR_FUNC);
return;
}

View File

@ -151,10 +151,6 @@ typedef enum
LEXER_COMMA_SEP_LIST, /**< comma separated bracketed expression list */
LEXER_SCAN_SWITCH, /**< special value for switch pre-scan */
LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */
#if ENABLED (JERRY_ES2015)
LEXER_FOR_IN_OF, /**< special value during for in/of statmenet scanning */
LEXER_LITERAL_OF, /**< 'of' literal */
#endif /* ENABLED (JERRY_ES2015) */
#if !ENABLED (JERRY_ES2015)
/* Future reserved words: these keywords
@ -164,6 +160,9 @@ typedef enum
LEXER_KEYW_CLASS, /**< class */
LEXER_KEYW_EXTENDS, /**< extends */
LEXER_KEYW_SUPER, /**< super */
#if ENABLED (JERRY_ES2015)
LEXER_KEYW_LET, /**< let */
#endif /* ENABLED (JERRY_ES2015) */
LEXER_KEYW_CONST, /**< const */
LEXER_KEYW_EXPORT, /**< export */
LEXER_KEYW_IMPORT, /**< import */
@ -190,25 +189,13 @@ typedef enum
LEXER_KEYW_PACKAGE, /**< package */
LEXER_KEYW_PROTECTED, /**< protected */
#if ENABLED (JERRY_ES2015)
/* Context dependent strict reserved words:
* See also: ECMA-262 v6, 11.6.2.1 */
#define LEXER_FIRST_CONTEXT_DEPENDENT_RESERVED_WORD LEXER_KEYW_STATIC
LEXER_KEYW_STATIC, /**< static */
#else /* !ENABLED (JERRY_ES2015) */
/* Context dependent strict reserved words:
* See also: ECMA-262 v6, 11.6.2.1 */
#define LEXER_FIRST_CONTEXT_DEPENDENT_RESERVED_WORD
#endif /* ENABLED (JERRY_ES2015) */
/* Context dependent future strict reserved words:
* See also: ECMA-262 v6, 11.6.2.1 */
#define LEXER_FIRST_CONTEXT_DEPENDENT_FUTURE_RESERVED_WORD LEXER_KEYW_LET
LEXER_KEYW_LET, /**< let */
LEXER_KEYW_YIELD, /**< yield */
#if !ENABLED (JERRY_ES2015)
LEXER_KEYW_STATIC, /**< static */
LEXER_KEYW_LET, /**< let */
#endif /* !ENABLED (JERRY_ES2015) */
LEXER_KEYW_YIELD, /**< yield */
LEXER_KEYW_STATIC, /**< static */
} lexer_token_type_t;
#define LEXER_NEWLINE_LS_PS_BYTE_1 0xe2

View File

@ -595,6 +595,14 @@ parser_parse_class (parser_context_t *context_p, /**< context */
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
#if ENABLED (JERRY_ES2015)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
}
#endif /* ENABLED (JERRY_ES2015) */
class_ident_index = context_p->lit_object.index;
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)

View File

@ -64,9 +64,10 @@ typedef enum
PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 15), /**< pending (unsent) breakpoint
* info is available */
#if ENABLED (JERRY_ES2015)
PARSER_FUNCTION_HAS_REST_PARAM = (1u << 16), /**< function has rest parameter */
PARSER_IS_ARROW_FUNCTION = (1u << 18), /**< an arrow function is parsed */
PARSER_ARROW_PARSE_ARGS = (1u << 19), /**< parse the argument list of an arrow function */
PARSER_INSIDE_BLOCK = (1u << 16), /**< script has a lexical environment for let and const */
PARSER_IS_ARROW_FUNCTION = (1u << 17), /**< an arrow function is parsed */
PARSER_ARROW_PARSE_ARGS = (1u << 18), /**< parse the argument list of an arrow function */
PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */
/* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed (this value must be kept in
* in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */
@ -371,8 +372,11 @@ typedef struct parser_saved_context_t
parser_mem_data_t literal_pool_data; /**< literal list */
parser_scope_stack *scope_stack_p; /**< scope stack */
uint16_t scope_stack_size; /**< size of scope stack */
uint16_t scope_stack_top; /**< current top of scope stack */
uint16_t scope_stack_reg_top; /**< current top register of scope stack */
uint16_t scope_stack_top; /**< preserved top of scope stack */
uint16_t scope_stack_reg_top; /**< preserved top register of scope stack */
#if ENABLED (JERRY_ES2015)
uint16_t scope_stack_global_end; /**< end of global declarations of a function */
#endif /* ENABLED (JERRY_ES2015) */
#ifndef JERRY_NDEBUG
uint16_t context_stack_depth; /**< current context stack depth */
@ -440,6 +444,9 @@ typedef struct
uint16_t scope_stack_size; /**< size of scope stack */
uint16_t scope_stack_top; /**< current top of scope stack */
uint16_t scope_stack_reg_top; /**< current top register of scope stack */
#if ENABLED (JERRY_ES2015)
uint16_t scope_stack_global_end; /**< end of global declarations of a function */
#endif /* ENABLED (JERRY_ES2015) */
uint8_t stack_top_uint8; /**< top byte stored on the stack */
#ifndef JERRY_NDEBUG
@ -615,10 +622,6 @@ void parser_parse_super_class_context_end (parser_context_t *context_p, bool is_
* @{
*/
void scanner_raise_error (parser_context_t *context_p);
void *scanner_malloc (parser_context_t *context_p, size_t size);
void scanner_free (void *ptr, size_t size);
void scanner_release_next (parser_context_t *context_p, size_t size);
void scanner_set_active (parser_context_t *context_p);
void scanner_release_active (parser_context_t *context_p, size_t size);
@ -627,6 +630,7 @@ void scanner_seek (parser_context_t *context_p);
void scanner_reverse_info_list (parser_context_t *context_p);
void scanner_cleanup (parser_context_t *context_p);
bool scanner_is_context_needed (parser_context_t *context_p);
void scanner_create_variables (parser_context_t *context_p, size_t size);
void scanner_get_location (scanner_location_t *location_p, parser_context_t *context_p);

View File

@ -438,7 +438,7 @@ parser_module_parse_import_clause (parser_context_t *context_p) /**< parser cont
ecma_string_t *import_name_p = NULL;
ecma_string_t *local_name_p = NULL;
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL);
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL);
uint16_t import_name_index = context_p->lit_object.index;
uint16_t local_name_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS;
@ -454,7 +454,7 @@ parser_module_parse_import_clause (parser_context_t *context_p) /**< parser cont
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL);
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL);
local_name_index = context_p->lit_object.index;

View File

@ -57,12 +57,18 @@ typedef enum
{
PARSER_STATEMENT_START,
PARSER_STATEMENT_BLOCK,
#if ENABLED (JERRY_ES2015)
PARSER_STATEMENT_BLOCK_CONTEXT,
#endif /* ENABLED (JERRY_ES2015) */
PARSER_STATEMENT_LABEL,
PARSER_STATEMENT_IF,
PARSER_STATEMENT_ELSE,
/* From switch -> for-in : break target statements */
PARSER_STATEMENT_SWITCH,
PARSER_STATEMENT_SWITCH_NO_DEFAULT,
#if ENABLED (JERRY_ES2015)
PARSER_STATEMENT_SWITCH_BLOCK_CONTEXT,
#endif /* ENABLED (JERRY_ES2015) */
/* From do-while -> for->in : continue target statements */
PARSER_STATEMENT_DO_WHILE,
PARSER_STATEMENT_WHILE,
@ -78,6 +84,40 @@ typedef enum
PARSER_STATEMENT_TRY,
} parser_statement_type_t;
#if !ENABLED (JERRY_ES2015)
/**
* Get the expected depth of a function call.
*/
#define JERRY_GET_EXPECTED_DEPTH(context_p) 0
#else /* ENABLED (JERRY_ES2015) */
/**
* Get the expected depth of a function call.
*/
#define JERRY_GET_EXPECTED_DEPTH(context_p) \
(((context_p)->status_flags & PARSER_INSIDE_BLOCK) ? PARSER_BLOCK_CONTEXT_STACK_ALLOCATION : 0)
/**
* Block statement.
*/
typedef struct
{
uint16_t scope_stack_top; /**< preserved top of scope stack */
uint16_t scope_stack_reg_top; /**< preserved top register of scope stack */
} parser_block_statement_t;
/**
* Context of block statement.
*/
typedef struct
{
parser_branch_t branch; /**< branch to the end */
} parser_block_context_t;
#endif /* !ENABLED (JERRY_ES2015) */
/**
* Loop statement.
*/
@ -110,6 +150,10 @@ typedef struct
{
parser_branch_t default_branch; /**< branch to the default case */
parser_branch_node_t *branch_list_p; /**< branches of case statements */
#if ENABLED (JERRY_ES2015)
uint16_t scope_stack_top; /**< preserved top of scope stack */
uint16_t scope_stack_reg_top; /**< preserved top register of scope stack */
#endif /* ENABLED (JERRY_ES2015) */
} parser_switch_statement_t;
/**
@ -190,8 +234,15 @@ parser_statement_length (uint8_t type) /**< type of statement */
{
static const uint8_t statement_lengths[] =
{
#if ENABLED (JERRY_ES2015)
/* PARSER_STATEMENT_BLOCK */
(uint8_t) (sizeof (parser_block_statement_t) + 1),
/* PARSER_STATEMENT_BLOCK_CONTEXT */
(uint8_t) (sizeof (parser_block_statement_t) + sizeof (parser_block_context_t) + 1),
#else /* !ENABLED (JERRY_ES2015) */
/* PARSER_STATEMENT_BLOCK */
1,
#endif /* ENABLED (JERRY_ES2015) */
/* PARSER_STATEMENT_LABEL */
(uint8_t) (sizeof (parser_label_statement_t) + 1),
/* PARSER_STATEMENT_IF */
@ -202,6 +253,10 @@ parser_statement_length (uint8_t type) /**< type of statement */
(uint8_t) (sizeof (parser_switch_statement_t) + sizeof (parser_loop_statement_t) + 1),
/* PARSER_STATEMENT_SWITCH_NO_DEFAULT */
(uint8_t) (sizeof (parser_switch_statement_t) + sizeof (parser_loop_statement_t) + 1),
#if ENABLED (JERRY_ES2015)
/* PARSER_STATEMENT_SWITCH_BLOCK_CONTEXT */
(uint8_t) (sizeof (parser_block_context_t) + 1),
#endif /* ENABLED (JERRY_ES2015) */
/* PARSER_STATEMENT_DO_WHILE */
(uint8_t) (sizeof (parser_do_while_statement_t) + sizeof (parser_loop_statement_t) + 1),
/* PARSER_STATEMENT_WHILE */
@ -293,7 +348,9 @@ parser_parse_enclosed_expr (parser_context_t *context_p) /**< context */
static void
parser_parse_var_statement (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_VAR);
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_VAR
|| context_p->token.type == LEXER_KEYW_LET
|| context_p->token.type == LEXER_KEYW_CONST);
while (true)
{
@ -313,6 +370,14 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
}
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
#if ENABLED (JERRY_ES2015)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
}
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
if (context_p->token.type == LEXER_ASSIGN)
@ -368,6 +433,14 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
#if ENABLED (JERRY_ES2015)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS)
{
context_p->status_flags |= PARSER_ARGUMENTS_NOT_NEEDED;
@ -1185,6 +1258,33 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
}
#if ENABLED (JERRY_ES2015)
switch_statement.scope_stack_top = context_p->scope_stack_top;
switch_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;
if (context_p->next_scanner_info_p->source_p == context_p->source_p - 1)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
if (scanner_is_context_needed (context_p))
{
parser_block_context_t block_context;
#ifndef JERRY_NDEBUG
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_forward_branch (context_p,
CBC_BLOCK_CREATE_CONTEXT,
&block_context.branch);
parser_stack_push (context_p, &block_context, sizeof (parser_block_context_t));
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_SWITCH_BLOCK_CONTEXT);
}
scanner_create_variables (context_p, sizeof (scanner_info_t));
}
#endif /* ENABLED (JERRY_ES2015) */
JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_SWITCH);
@ -1201,6 +1301,14 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
parser_emit_cbc (context_p, CBC_POP);
parser_flush_cbc (context_p);
#if ENABLED (JERRY_ES2015)
parser_block_statement_t block_statement;
block_statement.scope_stack_top = context_p->scope_stack_top;
block_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;
parser_stack_push (context_p, &block_statement, sizeof (parser_block_statement_t));
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
parser_stack_iterator_init (context_p, &context_p->last_statement);
return;
@ -1349,6 +1457,11 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
parser_stack_iterator_skip (&iterator, 1);
parser_stack_iterator_read (&iterator, &try_statement, sizeof (parser_try_statement_t));
#if ENABLED (JERRY_ES2015)
context_p->scope_stack_top = try_statement.scope_stack_top;
context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top;
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
if (try_statement.type == parser_finally_block)
@ -1368,8 +1481,10 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
if (try_statement.type == parser_catch_block)
{
#if !ENABLED (JERRY_ES2015)
context_p->scope_stack_top = try_statement.scope_stack_top;
context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top;
#endif /* !ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_KEYW_FINALLY)
{
@ -1423,12 +1538,18 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
bool block_found = false;
#endif /* !JERRY_NDEBUG */
if (context_p->next_scanner_info_p->source_p == context_p->source_p
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
#ifndef JERRY_NDEBUG
block_found = true;
#endif /* !JERRY_NDEBUG */
if (scanner_is_context_needed (context_p))
{
parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV);
}
scanner_create_variables (context_p, sizeof (scanner_info_t));
}
@ -1474,6 +1595,20 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
parser_emit_cbc_ext_forward_branch (context_p,
CBC_EXT_FINALLY,
&try_statement.branch);
#if ENABLED (JERRY_ES2015)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
if (scanner_is_context_needed (context_p))
{
parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV);
}
scanner_create_variables (context_p, sizeof (scanner_info_t));
}
#endif /* ENABLED (JERRY_ES2015) */
}
lexer_next_token (context_p);
@ -1585,6 +1720,9 @@ parser_parse_break_statement (parser_context_t *context_p) /**< context */
|| type == PARSER_STATEMENT_FOR_OF
#endif /* ENABLED (JERRY_ES2015) */
|| type == PARSER_STATEMENT_WITH
#if ENABLED (JERRY_ES2015)
|| type == PARSER_STATEMENT_BLOCK_CONTEXT
#endif /* ENABLED (JERRY_ES2015) */
|| type == PARSER_STATEMENT_TRY)
{
opcode = CBC_JUMP_FORWARD_EXIT_CONTEXT;
@ -1629,6 +1767,9 @@ parser_parse_break_statement (parser_context_t *context_p) /**< context */
|| type == PARSER_STATEMENT_FOR_OF
#endif /* ENABLED (JERRY_ES2015) */
|| type == PARSER_STATEMENT_WITH
#if ENABLED (JERRY_ES2015)
|| type == PARSER_STATEMENT_BLOCK_CONTEXT
#endif /* ENABLED (JERRY_ES2015) */
|| type == PARSER_STATEMENT_TRY)
{
opcode = CBC_JUMP_FORWARD_EXIT_CONTEXT;
@ -1723,6 +1864,9 @@ parser_parse_continue_statement (parser_context_t *context_p) /**< context */
#endif /* ENABLED (JERRY_ES2015) */
if (type == PARSER_STATEMENT_WITH
#if ENABLED (JERRY_ES2015)
|| type == PARSER_STATEMENT_BLOCK_CONTEXT
#endif /* ENABLED (JERRY_ES2015) */
|| type == PARSER_STATEMENT_TRY
|| for_in_of_was_seen)
{
@ -1782,6 +1926,9 @@ parser_parse_continue_statement (parser_context_t *context_p) /**< context */
}
if (type == PARSER_STATEMENT_WITH
#if ENABLED (JERRY_ES2015)
|| type == PARSER_STATEMENT_BLOCK_CONTEXT
#endif /* ENABLED (JERRY_ES2015) */
|| type == PARSER_STATEMENT_TRY)
{
opcode = CBC_JUMP_FORWARD_EXIT_CONTEXT;
@ -1993,6 +2140,10 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */
break;
}
case LEXER_KEYW_VAR:
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_LET:
case LEXER_KEYW_CONST:
#endif /* ENABLED (JERRY_ES2015) */
{
context_p->status_flags |= PARSER_MODULE_STORE_IDENT;
parser_parse_var_statement (context_p);
@ -2151,7 +2302,10 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
lexer_lit_location_t lit_location;
uint32_t status_flags = context_p->status_flags;
JERRY_ASSERT (context_p->stack_depth == 0);
JERRY_ASSERT (context_p->stack_depth == JERRY_GET_EXPECTED_DEPTH (context_p));
#ifndef JERRY_NDEBUG
JERRY_ASSERT (context_p->context_stack_depth == context_p->stack_depth);
#endif /* !JERRY_NDEBUG */
lit_location = context_p->token.lit_location;
@ -2246,6 +2400,8 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
&& context_p->token.type != LEXER_LEFT_BRACE
&& context_p->token.type != LEXER_RIGHT_BRACE
&& context_p->token.type != LEXER_KEYW_VAR
&& context_p->token.type != LEXER_KEYW_LET
&& context_p->token.type != LEXER_KEYW_CONST
&& context_p->token.type != LEXER_KEYW_FUNCTION
&& context_p->token.type != LEXER_KEYW_CASE
&& context_p->token.type != LEXER_KEYW_DEFAULT)
@ -2265,6 +2421,8 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
&& context_p->token.type != LEXER_LEFT_BRACE
&& context_p->token.type != LEXER_RIGHT_BRACE
&& context_p->token.type != LEXER_KEYW_VAR
&& context_p->token.type != LEXER_KEYW_LET
&& context_p->token.type != LEXER_KEYW_CONST
&& context_p->token.type != LEXER_KEYW_FUNCTION
&& context_p->token.type != LEXER_KEYW_CASE
&& context_p->token.type != LEXER_KEYW_DEFAULT)
@ -2301,13 +2459,49 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
case LEXER_LEFT_BRACE:
{
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
uint8_t block_type = PARSER_STATEMENT_BLOCK;
#if ENABLED (JERRY_ES2015)
parser_block_statement_t block_statement;
block_statement.scope_stack_top = context_p->scope_stack_top;
block_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
if (scanner_is_context_needed (context_p))
{
parser_block_context_t block_context;
#ifndef JERRY_NDEBUG
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_forward_branch (context_p,
CBC_BLOCK_CREATE_CONTEXT,
&block_context.branch);
parser_stack_push (context_p, &block_context, sizeof (parser_block_context_t));
block_type = PARSER_STATEMENT_BLOCK_CONTEXT;
}
scanner_create_variables (context_p, sizeof (scanner_info_t));
}
parser_stack_push (context_p, &block_statement, sizeof (parser_block_statement_t));
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, block_type);
parser_stack_iterator_init (context_p, &context_p->last_statement);
lexer_next_token (context_p);
continue;
}
case LEXER_KEYW_VAR:
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_LET:
case LEXER_KEYW_CONST:
#endif /* ENABLED (JERRY_ES2015) */
{
parser_parse_var_statement (context_p);
break;
@ -2409,6 +2603,23 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
CBC_EXT_TRY_CREATE_CONTEXT,
&try_statement.branch);
#if ENABLED (JERRY_ES2015)
try_statement.scope_stack_top = context_p->scope_stack_top;
try_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
if (scanner_is_context_needed (context_p))
{
parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV);
}
scanner_create_variables (context_p, sizeof (scanner_info_t));
}
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push (context_p, &try_statement, sizeof (parser_try_statement_t));
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_TRY);
parser_stack_iterator_init (context_p, &context_p->last_statement);
@ -2575,9 +2786,43 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
if (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK)
{
parser_stack_pop_uint8 (context_p);
#if ENABLED (JERRY_ES2015)
parser_block_statement_t block_statement;
parser_stack_pop (context_p, &block_statement, sizeof (parser_block_statement_t));
context_p->scope_stack_top = block_statement.scope_stack_top;
context_p->scope_stack_reg_top = block_statement.scope_stack_reg_top;
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_iterator_init (context_p, &context_p->last_statement);
lexer_next_token (context_p);
}
#if ENABLED (JERRY_ES2015)
else if (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_CONTEXT)
{
parser_block_statement_t block_statement;
parser_block_context_t block_context;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &block_statement, sizeof (parser_block_statement_t));
parser_stack_pop (context_p, &block_context, sizeof (parser_block_context_t));
context_p->scope_stack_top = block_statement.scope_stack_top;
context_p->scope_stack_reg_top = block_statement.scope_stack_reg_top;
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc (context_p, CBC_CONTEXT_END);
parser_set_branch_to_current_position (context_p, &block_context.branch);
parser_stack_iterator_init (context_p, &context_p->last_statement);
lexer_next_token (context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
else if (context_p->stack_top_uint8 == PARSER_STATEMENT_SWITCH
|| context_p->stack_top_uint8 == PARSER_STATEMENT_SWITCH_NO_DEFAULT)
{
@ -2590,6 +2835,11 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
parser_stack_pop (context_p, &switch_statement, sizeof (parser_switch_statement_t));
parser_stack_iterator_init (context_p, &context_p->last_statement);
#if ENABLED (JERRY_ES2015)
context_p->scope_stack_top = switch_statement.scope_stack_top;
context_p->scope_stack_reg_top = switch_statement.scope_stack_reg_top;
#endif /* ENABLED (JERRY_ES2015) */
JERRY_ASSERT (switch_statement.branch_list_p == NULL);
if (!has_default)
@ -2599,6 +2849,26 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
if (context_p->stack_top_uint8 == PARSER_STATEMENT_SWITCH_BLOCK_CONTEXT)
{
parser_block_context_t block_context;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &block_context, sizeof (parser_block_context_t));
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc (context_p, CBC_CONTEXT_END);
parser_set_branch_to_current_position (context_p, &block_context.branch);
parser_stack_iterator_init (context_p, &context_p->last_statement);
}
#endif /* ENABLED (JERRY_ES2015) */
}
else if (context_p->stack_top_uint8 == PARSER_STATEMENT_TRY)
{
@ -2762,9 +3032,9 @@ consume_last_statement:
}
}
JERRY_ASSERT (context_p->stack_depth == 0);
JERRY_ASSERT (context_p->stack_depth == JERRY_GET_EXPECTED_DEPTH (context_p));
#ifndef JERRY_NDEBUG
JERRY_ASSERT (context_p->context_stack_depth == 0);
JERRY_ASSERT (context_p->context_stack_depth == context_p->stack_depth);
#endif /* !JERRY_NDEBUG */
parser_stack_pop_uint8 (context_p);

View File

@ -1117,6 +1117,10 @@ parser_error_to_string (parser_error_t error) /**< error code */
{
return "Rest parameter may not have a default initializer.";
}
case PARSER_ERR_VARIABLE_REDECLARED:
{
return "Local variable is redeclared.";
}
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
case PARSER_ERR_FILE_NOT_FOUND:

View File

@ -1813,6 +1813,9 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
context.scope_stack_size = 0;
context.scope_stack_top = 0;
context.scope_stack_reg_top = 0;
#if ENABLED (JERRY_ES2015)
context.scope_stack_global_end = 0;
#endif /* ENABLED (JERRY_ES2015) */
#ifndef JERRY_NDEBUG
context.context_stack_depth = 0;
@ -1896,12 +1899,51 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
}
else
{
JERRY_ASSERT (context.next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
JERRY_ASSERT (context.next_scanner_info_p->source_p == source_p - 1
&& context.next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
scanner_create_variables (&context, sizeof (scanner_function_info_t));
#if ENABLED (JERRY_ES2015)
if (context.next_scanner_info_p->source_p == source_p)
{
JERRY_ASSERT (context.next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
if (scanner_is_context_needed (&context))
{
parser_branch_t branch;
#ifndef JERRY_NDEBUG
PARSER_PLUS_EQUAL_U16 (context.context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_forward_branch (&context,
CBC_BLOCK_CREATE_CONTEXT,
&branch);
parser_stack_push (&context, &branch, sizeof (parser_branch_t));
context.status_flags |= PARSER_INSIDE_BLOCK;
}
scanner_create_variables (&context, sizeof (scanner_info_t));
context.scope_stack_global_end = context.scope_stack_top;
}
#endif /* ENABLED (JERRY_ES2015) */
}
parser_parse_statements (&context);
#if ENABLED (JERRY_ES2015)
if (context.status_flags & PARSER_INSIDE_BLOCK)
{
parser_branch_t branch;
parser_stack_pop (&context, &branch, sizeof (parser_branch_t));
parser_emit_cbc (&context, CBC_CONTEXT_END);
parser_set_branch_to_current_position (&context, &branch);
parser_flush_cbc (&context);
}
#endif /* ENABLED (JERRY_ES2015) */
/* When the parsing is successful, only the
* dummy value can be remained on the stack. */
JERRY_ASSERT (context.stack_top_uint8 == CBC_MAXIMUM_BYTE_VALUE
@ -2022,6 +2064,9 @@ parser_save_context (parser_context_t *context_p, /**< context */
saved_context_p->scope_stack_size = context_p->scope_stack_size;
saved_context_p->scope_stack_top = context_p->scope_stack_top;
saved_context_p->scope_stack_reg_top = context_p->scope_stack_reg_top;
#if ENABLED (JERRY_ES2015)
saved_context_p->scope_stack_global_end = context_p->scope_stack_global_end;
#endif /* ENABLED (JERRY_ES2015) */
#ifndef JERRY_NDEBUG
saved_context_p->context_stack_depth = context_p->context_stack_depth;
@ -2046,6 +2091,9 @@ parser_save_context (parser_context_t *context_p, /**< context */
context_p->scope_stack_size = 0;
context_p->scope_stack_top = 0;
context_p->scope_stack_reg_top = 0;
#if ENABLED (JERRY_ES2015)
context_p->scope_stack_global_end = 0;
#endif /* ENABLED (JERRY_ES2015) */
#ifndef JERRY_NDEBUG
context_p->context_stack_depth = 0;
@ -2087,6 +2135,9 @@ parser_restore_context (parser_context_t *context_p, /**< context */
context_p->scope_stack_size = saved_context_p->scope_stack_size;
context_p->scope_stack_top = saved_context_p->scope_stack_top;
context_p->scope_stack_reg_top = saved_context_p->scope_stack_reg_top;
#if ENABLED (JERRY_ES2015)
context_p->scope_stack_global_end = saved_context_p->scope_stack_global_end;
#endif /* ENABLED (JERRY_ES2015) */
#ifndef JERRY_NDEBUG
context_p->context_stack_depth = saved_context_p->context_stack_depth;

View File

@ -112,6 +112,9 @@ typedef enum
PARSER_ERR_INVALID_RIGHT_SQUARE, /**< right square must terminate a block */
PARSER_ERR_DUPLICATED_LABEL, /**< duplicated label */
PARSER_ERR_OBJECT_PROPERTY_REDEFINED, /**< property of object literal redefined */
#if ENABLED (JERRY_ES2015)
PARSER_ERR_VARIABLE_REDECLARED, /**< a variable redeclared */
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015)
PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS, /**< multiple class constructor */

View File

@ -45,8 +45,28 @@ typedef enum
SCANNER_LITERAL_IS_VAR = (1 << 2), /**< literal is var */
SCANNER_LITERAL_IS_FUNC = (1 << 3), /**< literal is function */
SCANNER_LITERAL_NO_REG = (1 << 4), /**< literal cannot be stored in register */
#if ENABLED (JERRY_ES2015)
SCANNER_LITERAL_IS_LET = (1 << 5), /**< literal is let */
SCANNER_LITERAL_IS_CONST = (1 << 6), /**< literal is const */
#endif /* ENABLED (JERRY_ES2015) */
} scanner_literal_type_flags_t;
#if ENABLED (JERRY_ES2015)
/**
* Tells whether the literal is let or const declaration.
*/
#define SCANNER_LITERAL_IS_LET_OR_CONST (SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_IS_CONST)
#else /* !ENABLED (JERRY_ES2015) */
/**
* No literal is let or const declaration in ECMAScript 5.1.
*/
#define SCANNER_LITERAL_IS_LET_OR_CONST 0
#endif /* ENABLED (JERRY_ES2015) */
/**
* For statement descriptor.
*/
@ -112,6 +132,14 @@ struct scanner_context_t
scanner_info_t *end_arguments_p; /**< position of end arguments */
};
void scanner_raise_error (parser_context_t *context_p);
#if ENABLED (JERRY_ES2015)
void scanner_raise_redeclaration_error (parser_context_t *context_p);
#endif /* ENABLED (JERRY_ES2015) */
void *scanner_malloc (parser_context_t *context_p, size_t size);
void scanner_free (void *ptr, size_t size);
size_t scanner_get_stream_size (scanner_info_t *info_p, size_t size);
scanner_info_t *scanner_insert_info (parser_context_t *context_p, const uint8_t *source_p, size_t size);
scanner_info_t *scanner_insert_info_before (parser_context_t *context_p, const uint8_t *source_p,
@ -119,14 +147,22 @@ scanner_info_t *scanner_insert_info_before (parser_context_t *context_p, const u
scanner_literal_pool_t *scanner_push_literal_pool (parser_context_t *context_p, scanner_context_t *scanner_context_p,
uint16_t status_flags);
void scanner_pop_literal_pool (parser_context_t *context_p, scanner_context_t *scanner_context_p);
#if ENABLED (JERRY_ES2015)
void scanner_construct_global_block (parser_context_t *context_p, scanner_context_t *scanner_context_p);
#endif /* ENABLED (JERRY_ES2015) */
void scanner_filter_arguments (parser_context_t *context_p, scanner_context_t *scanner_context_p);
lexer_lit_location_t *scanner_add_custom_literal (parser_context_t *context_p, scanner_literal_pool_t *literal_pool_p,
const lexer_lit_location_t *literal_location_p);
lexer_lit_location_t *scanner_add_literal (parser_context_t *context_p, scanner_context_t *scanner_context_p);
void scanner_add_reference (parser_context_t *context_p, scanner_context_t *scanner_context_p);
void scanner_append_argument (parser_context_t *context_p, scanner_context_t *scanner_context_p);
#if ENABLED (JERRY_ES2015)
void scanner_detect_invalid_var (parser_context_t *context_p, scanner_context_t *scanner_context_p,
lexer_lit_location_t *var_literal_p);
#endif /* ENABLED (JERRY_ES2015) */
void scanner_detect_eval_call (parser_context_t *context_p, scanner_context_t *scanner_context_p);
/**
* @}
* @}

View File

@ -43,6 +43,22 @@ scanner_raise_error (parser_context_t *context_p) /**< context */
JERRY_ASSERT (0);
} /* scanner_raise_error */
#if ENABLED (JERRY_ES2015)
/**
* Raise a variable redeclaration error.
*/
void
scanner_raise_redeclaration_error (parser_context_t *context_p)
{
scanner_info_t *info_p = scanner_insert_info (context_p, context_p->source_p, sizeof (scanner_info_t));
info_p->type = SCANNER_TYPE_ERR_REDECLARED;
scanner_raise_error (context_p);
} /* scanner_raise_redeclaration_error */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Allocate memory for scanner.
*
@ -94,10 +110,17 @@ scanner_get_stream_size (scanner_info_t *info_p, /**< scanner info block */
{
switch (data_p[0] & SCANNER_STREAM_TYPE_MASK)
{
case SCANNER_STREAM_TYPE_VAR:
#if ENABLED (JERRY_ES2015)
case SCANNER_STREAM_TYPE_LET:
case SCANNER_STREAM_TYPE_CONST:
#endif /* ENABLED (JERRY_ES2015) */
case SCANNER_STREAM_TYPE_ARG:
case SCANNER_STREAM_TYPE_ARG_FUNC:
case SCANNER_STREAM_TYPE_VAR:
case SCANNER_STREAM_TYPE_FUNC:
#if ENABLED (JERRY_ES2015)
case SCANNER_STREAM_TYPE_VAR_FUNC:
#endif /* ENABLED (JERRY_ES2015) */
{
break;
}
@ -404,7 +427,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
{
search_arguments = false;
if (type & (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_FUNC))
if (type & (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET_OR_CONST))
{
arguments_required = false;
}
@ -416,8 +439,16 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
}
}
if (((type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)) && is_function)
|| (type & SCANNER_LITERAL_IS_LOCAL))
#if ENABLED (JERRY_ES2015)
if (is_function && (type & (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET)) == SCANNER_LITERAL_IS_FUNC)
{
type = (uint8_t) ((type & ~SCANNER_LITERAL_IS_FUNC) | SCANNER_LITERAL_IS_VAR);
literal_p->type = type;
}
#endif /* ENABLED (JERRY_ES2015) */
if ((is_function && (type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)))
|| (type & (SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_IS_LET_OR_CONST)))
{
JERRY_ASSERT (is_function || !(literal_p->type & SCANNER_LITERAL_IS_ARG));
@ -457,7 +488,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
prev_source_p = literal_p->char_p + literal_p->length;
if (is_function || !(type & SCANNER_LITERAL_IS_VAR))
if (is_function || !(type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC)))
{
continue;
}
@ -475,7 +506,15 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
literal_location_p->type |= SCANNER_LITERAL_NO_REG;
}
type = (type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC));
#if ENABLED (JERRY_ES2015)
if (literal_location_p->type & SCANNER_LITERAL_IS_LET_OR_CONST)
{
JERRY_ASSERT (!(type & SCANNER_LITERAL_IS_VAR));
type = 0;
}
#endif /* ENABLED (JERRY_ES2015) */
type = (uint8_t) (type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC));
JERRY_ASSERT (type == 0 || !is_function);
literal_location_p->type = (uint8_t) (literal_location_p->type | type);
@ -532,21 +571,17 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
data_p += sizeof (scanner_info_t);
JERRY_ASSERT (prev_literal_pool_p != NULL);
if (prev_literal_pool_p->no_declarations < no_declarations)
{
prev_literal_pool_p->no_declarations = (uint16_t) no_declarations;
}
}
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
prev_source_p = literal_pool_p->source_p - 1;
no_declarations = 0;
no_declarations = literal_pool_p->no_declarations;
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
{
if (JERRY_UNLIKELY (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK)
|| (!((literal_p->type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)) && is_function)
&& !(literal_p->type & SCANNER_LITERAL_IS_LOCAL)))
|| (!(is_function && (literal_p->type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)))
&& !(literal_p->type & (SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_IS_LET_OR_CONST))))
{
continue;
}
@ -575,6 +610,16 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
{
type = SCANNER_STREAM_TYPE_ARG;
}
#if ENABLED (JERRY_ES2015)
else if (literal_p->type & SCANNER_LITERAL_IS_LET)
{
type = SCANNER_STREAM_TYPE_LET;
}
else if (literal_p->type & SCANNER_LITERAL_IS_CONST)
{
type = SCANNER_STREAM_TYPE_CONST;
}
#endif /* ENABLED (JERRY_ES2015) */
if (literal_p->has_escape)
{
@ -624,12 +669,192 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
JERRY_ASSERT (((uint8_t *) info_p) + compressed_size == data_p + 1);
}
if (!is_function && prev_literal_pool_p->no_declarations < no_declarations)
{
prev_literal_pool_p->no_declarations = (uint16_t) no_declarations;
}
scanner_context_p->active_literal_pool_p = literal_pool_p->prev_p;
parser_list_free (&literal_pool_p->literal_pool);
scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t));
} /* scanner_pop_literal_pool */
#if ENABLED (JERRY_ES2015)
/**
* Extract certain (e.g. let/const) global declarations and construct a scanner info structure from them.
*/
void
scanner_construct_global_block (parser_context_t *context_p, /**< context */
scanner_context_t *scanner_context_p) /**< scanner context */
{
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
parser_list_iterator_t literal_iterator;
lexer_lit_location_t *literal_p;
bool no_reg = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_REG) != 0;
#if ENABLED (JERRY_DEBUGGER)
if (scanner_context_p->debugger_enabled)
{
/* When debugger is enabled, identifiers are not stored in registers. However,
* this does not affect 'eval' detection, so 'arguments' object is not created. */
no_reg = true;
}
#endif /* ENABLED (JERRY_DEBUGGER) */
JERRY_ASSERT (literal_pool_p->prev_p == NULL);
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
const uint8_t *prev_source_p = literal_pool_p->source_p;
size_t compressed_size = 1;
uint32_t no_declarations = literal_pool_p->no_declarations;
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
{
uint8_t type = literal_p->type;
if (JERRY_UNLIKELY (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK)
|| !(type & SCANNER_LITERAL_IS_LET_OR_CONST))
{
continue;
}
no_declarations++;
if (type & SCANNER_LITERAL_IS_FUNC)
{
JERRY_ASSERT (type & SCANNER_LITERAL_IS_LET);
no_declarations++;
type |= SCANNER_LITERAL_NO_REG;
literal_p->type = type;
}
else if (no_reg)
{
type |= SCANNER_LITERAL_NO_REG;
literal_p->type = type;
}
intptr_t diff = (intptr_t) (literal_p->char_p - prev_source_p);
if (diff >= 1 && diff <= UINT8_MAX)
{
compressed_size += 2 + 1;
}
else if (diff >= -UINT8_MAX && diff <= UINT16_MAX)
{
compressed_size += 2 + 2;
}
else
{
compressed_size += 2 + 1 + sizeof (const uint8_t *);
}
prev_source_p = literal_p->char_p + literal_p->length;
}
if (compressed_size <= 1)
{
return;
}
scanner_info_t *info_p;
compressed_size += sizeof (scanner_info_t);
info_p = scanner_insert_info (context_p, literal_pool_p->source_p + 1, compressed_size);
info_p->type = SCANNER_TYPE_BLOCK;
uint8_t *data_p = ((uint8_t *) info_p) + sizeof (scanner_info_t);
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
prev_source_p = literal_pool_p->source_p;
no_declarations = literal_pool_p->no_declarations;
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
{
if (JERRY_UNLIKELY (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK)
|| !(literal_p->type & SCANNER_LITERAL_IS_LET_OR_CONST))
{
continue;
}
no_declarations++;
uint8_t type = SCANNER_STREAM_TYPE_LET;
if (literal_p->type & SCANNER_LITERAL_IS_CONST)
{
type = SCANNER_STREAM_TYPE_CONST;
}
else if (literal_p->type & SCANNER_LITERAL_IS_FUNC)
{
type = SCANNER_STREAM_TYPE_VAR_FUNC;
no_declarations++;
}
if (literal_p->has_escape)
{
type |= SCANNER_STREAM_HAS_ESCAPE;
}
if (literal_p->type & SCANNER_LITERAL_NO_REG)
{
type |= SCANNER_STREAM_NO_REG;
}
literal_p->type = 0;
data_p[0] = type;
data_p[1] = (uint8_t) literal_p->length;
data_p += 3;
intptr_t diff = (intptr_t) (literal_p->char_p - prev_source_p);
if (diff >= 1 && diff <= UINT8_MAX)
{
data_p[-1] = (uint8_t) diff;
}
else if (diff >= -UINT8_MAX && diff <= UINT16_MAX)
{
if (diff < 0)
{
diff = -diff;
}
data_p[-3] |= SCANNER_STREAM_UINT16_DIFF;
data_p[-1] = (uint8_t) diff;
data_p[0] = (uint8_t) (diff >> 8);
data_p += 1;
}
else
{
data_p[-1] = 0;
memcpy (data_p, &literal_p->char_p, sizeof (const uint8_t *));
data_p += sizeof (const uint8_t *);
}
prev_source_p = literal_p->char_p + literal_p->length;
}
data_p[0] = SCANNER_STREAM_TYPE_END;
JERRY_ASSERT (((uint8_t *) info_p) + compressed_size == data_p + 1);
if (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK)
{
no_declarations = PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK;
}
literal_pool_p->no_declarations = (uint16_t) no_declarations;
} /* scanner_construct_global_block */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Filter out the arguments from a literal pool.
*/
@ -883,6 +1108,75 @@ scanner_detect_eval_call (parser_context_t *context_p, /**< context */
}
} /* scanner_detect_eval_call */
#if ENABLED (JERRY_ES2015)
/**
* Throws an error for invalid var statements.
*/
void
scanner_detect_invalid_var (parser_context_t *context_p, /**< context */
scanner_context_t *scanner_context_p, /**< scanner context */
lexer_lit_location_t *var_literal_p) /**< literal */
{
if (var_literal_p->type & (SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_IS_CONST)
&& !(var_literal_p->type & SCANNER_LITERAL_IS_FUNC))
{
scanner_raise_redeclaration_error (context_p);
}
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
const uint8_t *char_p = var_literal_p->char_p;
prop_length_t length = var_literal_p->length;
while (!(literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION))
{
literal_pool_p = literal_pool_p->prev_p;
parser_list_iterator_t literal_iterator;
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
lexer_lit_location_t *literal_p;
if (JERRY_LIKELY (!context_p->token.lit_location.has_escape))
{
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
{
if (literal_p->type & (SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_IS_CONST)
&& literal_p->length == length)
{
if (JERRY_LIKELY (!literal_p->has_escape))
{
if (memcmp (literal_p->char_p, char_p, length) == 0)
{
scanner_raise_redeclaration_error (context_p);
return;
}
}
else if (lexer_compare_identifiers (literal_p->char_p, char_p, length))
{
scanner_raise_redeclaration_error (context_p);
return;
}
}
}
}
else
{
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
{
if (literal_p->type & (SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_IS_CONST)
&& literal_p->length == length
&& lexer_compare_identifiers (literal_p->char_p, char_p, length))
{
scanner_raise_redeclaration_error (context_p);
return;
}
}
}
}
} /* scanner_detect_invalid_var */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Reverse the scanner info chain after the scanning is completed.
*/
@ -973,7 +1267,12 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
}
default:
{
#if ENABLED (JERRY_ES2015)
JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS
|| scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS);
#endif /* ENABLED (JERRY_ES2015) */
break;
}
}
@ -986,6 +1285,158 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
context_p->active_scanner_info_p = NULL;
} /* scanner_cleanup */
#if ENABLED (JERRY_ES2015)
/**
* Finds the literal id of a function if its target is a var declaration
*
* @return function id - if the target of a function is a var declaration,
* negative value - otherwise
*/
static int32_t
scanner_get_function_target (parser_context_t *context_p) /**< context */
{
uint16_t literal_index = context_p->lit_object.index;
parser_scope_stack *scope_stack_start_p = context_p->scope_stack_p;
parser_scope_stack *scope_stack_p = scope_stack_start_p + context_p->scope_stack_top;
while (scope_stack_p > scope_stack_start_p)
{
scope_stack_p--;
if (scope_stack_p->map_from == literal_index
&& scope_stack_p->map_to != PARSER_SCOPE_STACK_FUNC)
{
if ((scope_stack_p - scope_stack_start_p) >= context_p->scope_stack_global_end
|| !(context_p->lit_object.literal_p->status_flags & LEXER_FLAG_GLOBAL))
{
return -1;
}
return scope_stack_p->map_to;
}
}
return -1;
} /* scanner_get_function_target */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Checks whether a context needs to be created for a block.
*
* @return true - if context is needed,
* false - otherwise
*/
bool
scanner_is_context_needed (parser_context_t *context_p) /**< context */
{
scanner_info_t *info_p = context_p->next_scanner_info_p;
const uint8_t *data_p = ((const uint8_t *) info_p) + sizeof (scanner_info_t);
#if ENABLED (JERRY_ES2015)
lexer_lit_location_t literal;
#endif /* ENABLED (JERRY_ES2015) */
JERRY_ASSERT (info_p->type == SCANNER_TYPE_BLOCK);
uint32_t scope_stack_reg_top = context_p->scope_stack_reg_top;
#if ENABLED (JERRY_ES2015)
literal.char_p = info_p->source_p - 1;
#endif /* ENABLED (JERRY_ES2015) */
while (data_p[0] != SCANNER_STREAM_TYPE_END)
{
uint32_t type = data_p[0] & SCANNER_STREAM_TYPE_MASK;
#if ENABLED (JERRY_ES2015)
JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR
|| type == SCANNER_STREAM_TYPE_LET
|| type == SCANNER_STREAM_TYPE_CONST
|| type == SCANNER_STREAM_TYPE_FUNC
|| type == SCANNER_STREAM_TYPE_VAR_FUNC);
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR);
#endif /* ENABLED (JERRY_ES2015) */
size_t length;
if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF))
{
if (data_p[2] != 0)
{
#if ENABLED (JERRY_ES2015)
literal.char_p += data_p[2];
#endif /* ENABLED (JERRY_ES2015) */
length = 2 + 1;
}
else
{
#if ENABLED (JERRY_ES2015)
memcpy (&literal.char_p, data_p + 2 + 1, sizeof (const uint8_t *));
#endif /* ENABLED (JERRY_ES2015) */
length = 2 + 1 + sizeof (const uint8_t *);
}
}
else
{
#if ENABLED (JERRY_ES2015)
int32_t diff = ((int32_t) data_p[2]) | ((int32_t) data_p[3]) << 8;
if (diff <= UINT8_MAX)
{
diff = -diff;
}
literal.char_p += diff;
#endif /* ENABLED (JERRY_ES2015) */
length = 2 + 2;
}
#if ENABLED (JERRY_ES2015)
if (type == SCANNER_STREAM_TYPE_FUNC)
{
literal.length = data_p[1];
literal.type = LEXER_IDENT_LITERAL;
literal.has_escape = (data_p[0] & SCANNER_STREAM_HAS_ESCAPE) ? 1 : 0;
lexer_construct_literal_object (context_p, &literal, LEXER_NEW_IDENT_LITERAL);
if (scanner_get_function_target (context_p) >= 0)
{
literal.char_p += data_p[1];
data_p += length;
continue;
}
}
#endif /* ENABLED (JERRY_ES2015) */
if (!(data_p[0] & SCANNER_STREAM_NO_REG)
&& scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
{
scope_stack_reg_top++;
}
else
{
#if ENABLED (JERRY_ES2015)
if (type != SCANNER_STREAM_TYPE_VAR_FUNC)
{
return true;
}
#else /* !ENABLED (JERRY_ES2015) */
return true;
#endif /* ENABLED (JERRY_ES2015) */
}
#if ENABLED (JERRY_ES2015)
literal.char_p += data_p[1];
#endif /* ENABLED (JERRY_ES2015) */
data_p += length;
}
return false;
} /* scanner_is_context_needed */
/**
* Description of "arguments" literal string.
*/
@ -1111,64 +1562,124 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
lexer_construct_literal_object (context_p, &literal, LEXER_NEW_IDENT_LITERAL);
scope_stack_p->map_from = context_p->lit_object.index;
uint16_t map_to;
uint16_t func_init_opcode = CBC_INIT_LOCAL;
if (!(data_p[0] & SCANNER_STREAM_NO_REG)
&& scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
#if ENABLED (JERRY_ES2015)
if (info_type == SCANNER_TYPE_FUNCTION)
{
map_to = (uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top);
scope_stack_p->map_from = context_p->lit_object.index;
scope_stack_p->map_to = map_to;
scope_stack_reg_top++;
if (type != SCANNER_STREAM_TYPE_LET
&& type != SCANNER_STREAM_TYPE_CONST)
{
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_GLOBAL;
}
}
else
else if (type == SCANNER_STREAM_TYPE_FUNC)
{
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_USED;
map_to = context_p->lit_object.index;
int32_t target_id = scanner_get_function_target (context_p);
scope_stack_p->map_from = map_to;
scope_stack_p->map_to = map_to;
if (info_type == SCANNER_TYPE_FUNCTION)
if (target_id >= 0)
{
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
map_to = (uint16_t) target_id;
scope_stack_p->map_to = PARSER_SCOPE_STACK_FUNC;
func_init_opcode = CBC_SET_VAR_FUNC;
}
}
else if (type == SCANNER_STREAM_TYPE_VAR_FUNC)
{
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_GLOBAL;
}
#endif /* ENABLED (JERRY_ES2015) */
if (type == SCANNER_STREAM_TYPE_VAR)
if (func_init_opcode == CBC_INIT_LOCAL)
{
if (!(data_p[0] & SCANNER_STREAM_NO_REG)
&& scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
{
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
map_to = (uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top);
parser_emit_cbc_literal (context_p, CBC_CREATE_VAR, map_to);
scope_stack_p->map_to = map_to;
scope_stack_reg_top++;
#if ENABLED (JERRY_ES2015)
func_init_opcode = CBC_SET_VAR_FUNC;
#endif /* ENABLED (JERRY_ES2015) */
}
else if (type == SCANNER_STREAM_TYPE_ARG || type == SCANNER_STREAM_TYPE_ARG_FUNC)
else
{
if (type == SCANNER_STREAM_TYPE_ARG)
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_USED;
map_to = context_p->lit_object.index;
scope_stack_p->map_to = map_to;
if (info_type == SCANNER_TYPE_FUNCTION)
{
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
parser_emit_cbc_literal_value (context_p,
CBC_INIT_LOCAL,
(uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top),
map_to);
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
}
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
switch (type)
{
scope_stack_reg_top++;
case SCANNER_STREAM_TYPE_VAR:
{
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
parser_emit_cbc_literal (context_p, CBC_CREATE_VAR, map_to);
break;
}
#if ENABLED (JERRY_ES2015)
case SCANNER_STREAM_TYPE_LET:
case SCANNER_STREAM_TYPE_CONST:
{
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
/* FIXME: introduce CBC_CREATE_LET / CBC_CREATE_CONST. */
parser_emit_cbc_literal (context_p, CBC_CREATE_VAR, map_to);
break;
}
case SCANNER_STREAM_TYPE_VAR_FUNC:
{
if (context_p->status_flags & PARSER_INSIDE_BLOCK)
{
func_init_opcode = CBC_CREATE_VAR_FUNC;
}
break;
}
#endif /* ENABLED (JERRY_ES2015) */
case SCANNER_STREAM_TYPE_ARG:
{
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
parser_emit_cbc_literal_value (context_p,
CBC_INIT_LOCAL,
(uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top),
map_to);
/* FALLTHRU */
}
case SCANNER_STREAM_TYPE_ARG_FUNC:
{
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
{
scope_stack_reg_top++;
}
}
}
}
}
scope_stack_p++;
literal.char_p += data_p[1];
data_p += length;
if (type != SCANNER_STREAM_TYPE_ARG_FUNC && type != SCANNER_STREAM_TYPE_FUNC)
if (!SCANNER_STREAM_TYPE_IS_FUNCTION (type))
{
continue;
}
@ -1188,7 +1699,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
parser_emit_cbc_literal_value (context_p, CBC_INIT_LOCAL, context_p->literal_count, map_to);
parser_emit_cbc_literal_value (context_p, func_init_opcode, context_p->literal_count, map_to);
scope_stack_p->map_from = PARSER_SCOPE_STACK_FUNC;
scope_stack_p->map_to = context_p->literal_count;
@ -1222,6 +1733,13 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
context_p->scope_stack_reg_top = (uint16_t) scope_stack_reg_top;
#if ENABLED (JERRY_ES2015)
if (info_type == SCANNER_TYPE_FUNCTION)
{
context_p->scope_stack_global_end = context_p->scope_stack_top;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->register_count < scope_stack_reg_top)
{
context_p->register_count = (uint16_t) scope_stack_reg_top;

View File

@ -72,6 +72,10 @@ typedef enum
SCAN_STACK_WHILE_EXPRESSION, /**< expression part of "while" iterator */
SCAN_STACK_PAREN_EXPRESSION, /**< expression in brackets */
SCAN_STACK_STATEMENT_WITH_EXPR, /**< statement which starts with expression enclosed in brackets */
#if ENABLED (JERRY_ES2015)
SCAN_STACK_LET, /**< let statement */
SCAN_STACK_CONST, /**< const statement */
#endif /* ENABLED (JERRY_ES2015) */
/* The SCANNER_IS_FOR_START macro needs to be updated when the following constants are reordered. */
SCAN_STACK_VAR, /**< var statement */
SCAN_STACK_FOR_VAR_START, /**< start of "for" iterator with var statement */
@ -504,6 +508,10 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_VAR:
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_LET:
case SCAN_STACK_CONST:
#endif /* ENABLED (JERRY_ES2015) */
case SCAN_STACK_FOR_VAR_START:
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
@ -628,6 +636,10 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_VAR:
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_LET:
case SCAN_STACK_CONST:
#endif /* ENABLED (JERRY_ES2015) */
{
parser_stack_pop_uint8 (context_p);
return SCAN_KEEP_TOKEN;
@ -752,6 +764,12 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
break;
}
#if ENABLED (JERRY_ES2015)
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p - 1;
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_pop_uint8 (context_p);
scanner_switch_statement_t switch_statement = scanner_context_p->active_switch_statement;
@ -966,6 +984,14 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
}
case LEXER_LEFT_BRACE:
{
#if ENABLED (JERRY_ES2015)
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p,
scanner_context_p,
SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
return SCAN_NEXT_TOKEN;
@ -985,6 +1011,14 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
scanner_raise_error (context_p);
}
#if ENABLED (JERRY_ES2015)
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p,
scanner_context_p,
SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
parser_stack_push_uint8 (context_p, SCAN_STACK_TRY_STATEMENT);
return SCAN_NEXT_TOKEN;
@ -1081,6 +1115,20 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
parser_stack_push_uint8 (context_p, SCAN_STACK_VAR);
return SCAN_NEXT_TOKEN;
}
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_LET:
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
parser_stack_push_uint8 (context_p, SCAN_STACK_LET);
return SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_CONST:
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
parser_stack_push_uint8 (context_p, SCAN_STACK_CONST);
return SCAN_NEXT_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_KEYW_THROW:
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
@ -1164,7 +1212,18 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
}
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
#if ENABLED (JERRY_ES2015)
if (location_p->type & SCANNER_LITERAL_IS_LET_OR_CONST
&& !(location_p->type & SCANNER_LITERAL_IS_FUNC))
{
scanner_raise_redeclaration_error (context_p);
}
location_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET;
#else
location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
#endif /* ENABLED (JERRY_ES2015) */
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
@ -1182,8 +1241,22 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
scanner_raise_error (context_p);
}
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
location_p->type |= SCANNER_LITERAL_IS_VAR;
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p);
if (literal_p->type & (SCANNER_LITERAL_IS_ARG
| SCANNER_LITERAL_IS_LOCAL
| SCANNER_LITERAL_IS_VAR
| SCANNER_LITERAL_IS_LET_OR_CONST))
{
scanner_raise_redeclaration_error (context_p);
}
if (literal_p->type & SCANNER_LITERAL_IS_FUNC)
{
literal_p->type = (uint8_t) (literal_p->type & ~SCANNER_LITERAL_IS_FUNC);
}
literal_p->type |= SCANNER_LITERAL_IS_LET;
scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION;
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT);
@ -1339,7 +1412,17 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
#if ENABLED (JERRY_ES2015)
if (location_p->type & SCANNER_LITERAL_IS_LET_OR_CONST
&& !(location_p->type & SCANNER_LITERAL_IS_FUNC))
{
scanner_raise_redeclaration_error (context_p);
}
location_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET;
#else /* !ENABLED (JERRY_ES2015) */
location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
}
@ -1349,7 +1432,11 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
location_p = scanner_add_custom_literal (context_p,
scanner_context_p->active_literal_pool_p,
&lexer_default_literal);
#if ENABLED (JERRY_ES2015)
location_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET;
#else /* !ENABLED (JERRY_ES2015) */
location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
#endif /* ENABLED (JERRY_ES2015) */
}
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
@ -1478,6 +1565,26 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
return SCAN_NEXT_TOKEN;
}
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_KEYW_CLASS)
{
/* FIXME: classes should be let declarations. */
scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION;
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT);
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_raise_error (context_p);
}
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
location_p->type |= SCANNER_LITERAL_IS_VAR;
return SCAN_NEXT_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
scanner_context_p->mode = SCAN_MODE_STATEMENT;
return SCAN_KEEP_TOKEN;
}
@ -1566,10 +1673,17 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
break;
}
#if ENABLED (JERRY_ES2015)
if (context_p->stack_top_uint8 != SCAN_STACK_CLASS_STATEMENT)
{
scanner_pop_literal_pool (context_p, scanner_context_p);
}
#else /* !ENABLED (JERRY_ES2015) */
if (context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_STATEMENT)
{
scanner_pop_literal_pool (context_p, scanner_context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
terminator_found = true;
parser_stack_pop_uint8 (context_p);
@ -1640,6 +1754,10 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
scanner_context_p->active_switch_statement = switch_statement;
#if ENABLED (JERRY_ES2015)
scanner_pop_literal_pool (context_p, scanner_context_p);
#endif /* ENABLED (JERRY_ES2015) */
terminator_found = true;
lexer_next_token (context_p);
continue;
@ -1712,10 +1830,14 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
parser_stack_pop_uint8 (context_p);
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
scanner_pop_literal_pool (context_p, scanner_context_p);
#else /* !ENABLED (JERRY_ES2015) */
if (stack_top == SCAN_STACK_CATCH_STATEMENT)
{
scanner_pop_literal_pool (context_p, scanner_context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
/* A finally statement is optional after a try or catch statement. */
if (context_p->token.type == LEXER_KEYW_FINALLY)
@ -1727,6 +1849,14 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
scanner_raise_error (context_p);
}
#if ENABLED (JERRY_ES2015)
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p,
scanner_context_p,
SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
return SCAN_NEXT_TOKEN;
@ -1839,9 +1969,14 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
context_p->source_p = source_p;
context_p->source_end_p = source_end_p;
#if ENABLED (JERRY_ES2015)
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS;
#else /* !ENABLED (JERRY_DEBUGGER) */
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_NO_REG;
#endif /* ENABLED (JERRY_DEBUGGER) */
scanner_literal_pool_t *literal_pool_p = scanner_push_literal_pool (context_p, &scanner_context, status_flags);
literal_pool_p->source_p = source_p;
literal_pool_p->source_p = source_p - 1;
scanner_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT);
@ -2011,12 +2146,45 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
scanner_raise_error (context_p);
}
lexer_lit_location_t *location_p = scanner_add_literal (context_p, &scanner_context);
location_p->type |= SCANNER_LITERAL_IS_VAR;
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, &scanner_context);
#if ENABLED (JERRY_ES2015)
if (stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_CONST)
{
if (literal_p->type & (SCANNER_LITERAL_IS_ARG
| SCANNER_LITERAL_IS_LOCAL
| SCANNER_LITERAL_IS_VAR
| SCANNER_LITERAL_IS_LET_OR_CONST))
{
scanner_raise_redeclaration_error (context_p);
}
if (literal_p->type & SCANNER_LITERAL_IS_FUNC)
{
literal_p->type = (uint8_t) (literal_p->type & ~SCANNER_LITERAL_IS_FUNC);
}
if (stack_top == SCAN_STACK_LET)
{
literal_p->type |= SCANNER_LITERAL_IS_LET;
}
else
{
literal_p->type |= SCANNER_LITERAL_IS_CONST;
}
}
else if (!(literal_p->type & SCANNER_LITERAL_IS_VAR))
{
scanner_detect_invalid_var (context_p, &scanner_context, literal_p);
literal_p->type |= SCANNER_LITERAL_IS_VAR;
}
#else /* !ENABLED (JERRY_ES2015) */
literal_p->type |= SCANNER_LITERAL_IS_VAR;
#endif /* ENABLED (JERRY_ES2015) */
if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
{
location_p->type |= SCANNER_LITERAL_NO_REG;
literal_p->type |= SCANNER_LITERAL_NO_REG;
}
lexer_next_token (context_p);
@ -2048,7 +2216,11 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
continue;
}
#if ENABLED (JERRY_ES2015)
JERRY_ASSERT (stack_top == SCAN_STACK_VAR || stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_CONST);
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (stack_top == SCAN_STACK_VAR);
#endif /* ENABLED (JERRY_ES2015) */
scanner_context.mode = SCAN_MODE_STATEMENT_END;
parser_stack_pop_uint8 (context_p);
@ -2275,6 +2447,14 @@ scan_completed:
scanner_raise_error (context_p);
}
#if ENABLED (JERRY_ES2015)
if (arg_list_p == NULL)
{
scanner_construct_global_block (context_p, &scanner_context);
scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG;
}
#endif /* ENABLED (JERRY_ES2015) */
scanner_pop_literal_pool (context_p, &scanner_context);
#ifndef JERRY_NDEBUG
@ -2364,6 +2544,23 @@ scan_completed:
{
switch (data_p[0] & SCANNER_STREAM_TYPE_MASK)
{
case SCANNER_STREAM_TYPE_VAR:
{
JERRY_DEBUG_MSG (" VAR ");
break;
}
#if ENABLED (JERRY_ES2015)
case SCANNER_STREAM_TYPE_LET:
{
JERRY_DEBUG_MSG (" LET ");
break;
}
case SCANNER_STREAM_TYPE_CONST:
{
JERRY_DEBUG_MSG (" CONST ");
break;
}
#endif /* ENABLED (JERRY_ES2015) */
case SCANNER_STREAM_TYPE_ARG:
{
JERRY_DEBUG_MSG (" ARG ");
@ -2374,16 +2571,18 @@ scan_completed:
JERRY_DEBUG_MSG (" ARG_FUNC ");
break;
}
case SCANNER_STREAM_TYPE_VAR:
{
JERRY_DEBUG_MSG (" VAR ");
break;
}
case SCANNER_STREAM_TYPE_FUNC:
{
JERRY_DEBUG_MSG (" FUNC ");
break;
}
#if ENABLED (JERRY_ES2015)
case SCANNER_STREAM_TYPE_VAR_FUNC:
{
JERRY_DEBUG_MSG (" VAR_FUNC ");
break;
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
JERRY_ASSERT ((data_p[0] & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_HOLE);

View File

@ -44,6 +44,9 @@ typedef enum
#endif /* ENABLED (JERRY_ES2015) */
SCANNER_TYPE_SWITCH, /**< switch statement */
SCANNER_TYPE_CASE, /**< case statement */
#if ENABLED (JERRY_ES2015)
SCANNER_TYPE_ERR_REDECLARED, /**< syntax error: a variable is redeclared */
#endif /* ENABLED (JERRY_ES2015) */
} scanner_info_type_t;
/**
@ -127,6 +130,7 @@ typedef enum
SCANNER_STREAM_UINT16_DIFF = (1 << 7), /**< relative distance is between -256 and 65535 */
SCANNER_STREAM_HAS_ESCAPE = (1 << 6), /**< literal has escape */
SCANNER_STREAM_NO_REG = (1 << 5), /**< identifier cannot be stored in register */
/* Update SCANNER_STREAM_TYPE_MASK macro if more bits are added. */
} scanner_compressed_stream_flags_t;
/**
@ -136,10 +140,18 @@ typedef enum
{
SCANNER_STREAM_TYPE_END, /**< end of scanner data */
SCANNER_STREAM_TYPE_HOLE, /**< no name is assigned to this argument */
SCANNER_STREAM_TYPE_ARG, /**< argument declaration */
SCANNER_STREAM_TYPE_ARG_FUNC, /**< argument declaration which is later initialized with a function */
SCANNER_STREAM_TYPE_VAR, /**< var declaration */
SCANNER_STREAM_TYPE_FUNC, /**< function declaration */
#if ENABLED (JERRY_ES2015)
SCANNER_STREAM_TYPE_LET, /**< let declaration */
SCANNER_STREAM_TYPE_CONST, /**< const declaration */
#endif /* ENABLED (JERRY_ES2015) */
SCANNER_STREAM_TYPE_ARG, /**< argument declaration */
/* Function types should be at the end. See the SCANNER_STREAM_TYPE_IS_FUNCTION macro. */
SCANNER_STREAM_TYPE_ARG_FUNC, /**< argument declaration which is later initialized with a function */
SCANNER_STREAM_TYPE_FUNC, /**< local function declaration */
#if ENABLED (JERRY_ES2015)
SCANNER_STREAM_TYPE_VAR_FUNC, /**< var function declaration */
#endif /* ENABLED (JERRY_ES2015) */
} scanner_compressed_stream_types_t;
/**
@ -147,6 +159,11 @@ typedef enum
*/
#define SCANNER_STREAM_TYPE_MASK 0xf
/**
* Mask for decoding the type from the compressed stream.
*/
#define SCANNER_STREAM_TYPE_IS_FUNCTION(type) ((type) >= SCANNER_STREAM_TYPE_ARG_FUNC)
/**
* Constants for u8_arg flags in scanner_function_info_t.
*/

View File

@ -26,6 +26,8 @@
* @{
*/
JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_BLOCK_CONTEXT_STACK_ALLOCATION,
parser_with_context_stack_allocation_must_be_equal_to_parser_block_context_stack_allocation);
JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION,
parser_with_context_stack_allocation_must_be_equal_to_parser_super_class_context_stack_allocation);
@ -38,7 +40,17 @@ ecma_value_t *
vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
ecma_value_t *vm_stack_top_p) /**< current stack top */
{
switch (VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]))
ecma_value_t context_info = vm_stack_top_p[-1];
if (context_info & VM_CONTEXT_HAS_LEX_ENV)
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
}
switch (VM_GET_CONTEXT_TYPE (context_info))
{
case VM_CONTEXT_FINALLY_THROW:
case VM_CONTEXT_FINALLY_RETURN:
@ -66,16 +78,14 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
vm_stack_top_p -= size_diff;
/* FALLTHRU */
}
#if ENABLED (JERRY_ES2015)
case VM_CONTEXT_BLOCK:
#endif /* ENABLED (JERRY_ES2015) */
case VM_CONTEXT_WITH:
#if ENABLED (JERRY_ES2015)
case VM_CONTEXT_SUPER_CLASS:
#endif /* ENABLED (JERRY_ES2015) */
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION);
vm_stack_top_p -= PARSER_WITH_CONTEXT_STACK_ALLOCATION;
break;
@ -194,6 +204,16 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
return false;
}
#if ENABLED (JERRY_ES2015)
if (vm_stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
}
#endif /* ENABLED (JERRY_ES2015) */
byte_code_p = frame_ctx_p->byte_code_start_p + context_end;
if (context_type == VM_CONTEXT_TRY)
@ -232,10 +252,15 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
}
else
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
#if !ENABLED (JERRY_ES2015)
if (vm_stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
}
#endif /* !ENABLED (JERRY_ES2015) */
if (byte_code_p[0] == CBC_CONTEXT_END)
{

View File

@ -25,20 +25,46 @@
* @{
*/
#define VM_CREATE_CONTEXT(type, end_offset) ((ecma_value_t) ((type) | (end_offset) << 4))
#define VM_GET_CONTEXT_TYPE(value) ((vm_stack_context_type_t) ((value) & 0xf))
#define VM_GET_CONTEXT_END(value) ((value) >> 4)
/**
* Create context on the vm stack.
*/
#define VM_CREATE_CONTEXT(type, end_offset) ((ecma_value_t) ((type) | ((end_offset) << 6)))
/**
* Create context on the vm stack with environment.
*/
#define VM_CREATE_CONTEXT_WITH_ENV(type, end_offset) \
((ecma_value_t) ((type) | ((end_offset) << 6) | VM_CONTEXT_HAS_LEX_ENV))
/**
* Get type of a vm context.
*/
#define VM_GET_CONTEXT_TYPE(value) ((vm_stack_context_type_t) ((value) & 0x1f))
/**
* Get the end position of a vm context.
*/
#define VM_GET_CONTEXT_END(value) ((value) >> 6)
/**
* This flag is set if the context has a lexical environment.
*/
#define VM_CONTEXT_HAS_LEX_ENV 0x20
/**
* Context types for the vm stack.
*/
typedef enum
{
/* Update VM_CONTEXT_IS_FINALLY macro if the following three values are changed. */
VM_CONTEXT_FINALLY_JUMP, /**< finally context with a jump */
VM_CONTEXT_FINALLY_THROW, /**< finally context with a throw */
VM_CONTEXT_FINALLY_RETURN, /**< finally context with a return */
VM_CONTEXT_TRY, /**< try context */
VM_CONTEXT_CATCH, /**< catch context */
#if ENABLED (JERRY_ES2015)
VM_CONTEXT_BLOCK, /**< block context */
#endif /* ENABLED (JERRY_ES2015) */
VM_CONTEXT_WITH, /**< with context */
VM_CONTEXT_FOR_IN, /**< for-in context */
#if ENABLED (JERRY_ES2015)
@ -47,6 +73,12 @@ typedef enum
#endif /* ENABLED (JERRY_ES2015) */
} vm_stack_context_type_t;
/**
* Checks whether the context type is a finally type.
*/
#define VM_CONTEXT_IS_FINALLY(context_type) \
((context_type) <= VM_CONTEXT_FINALLY_RETURN)
ecma_value_t *vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, ecma_value_t *vm_stack_top_p);
bool vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, ecma_value_t **vm_stack_top_ref_p,
vm_stack_context_type_t finally_type, uint32_t search_limit);

View File

@ -835,35 +835,99 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]);
frame_ctx_p->registers_p[literal_index] = lit_value;
break;
}
else
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
vm_var_decl (frame_ctx_p, name_p);
ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (frame_ctx_p->lex_env_p,
name_p,
is_strict,
lit_value);
JERRY_ASSERT (ecma_is_value_boolean (put_value_result)
|| ecma_is_value_empty (put_value_result)
|| ECMA_IS_VALUE_ERROR (put_value_result));
if (ECMA_IS_VALUE_ERROR (put_value_result))
{
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_free_value (JERRY_CONTEXT (error_value));
}
vm_var_decl (frame_ctx_p, name_p);
ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (frame_ctx_p->lex_env_p,
name_p,
is_strict,
lit_value);
JERRY_ASSERT (ecma_is_value_boolean (put_value_result)
|| ecma_is_value_empty (put_value_result)
|| ECMA_IS_VALUE_ERROR (put_value_result));
if (ECMA_IS_VALUE_ERROR (put_value_result))
{
ecma_free_value (JERRY_CONTEXT (error_value));
}
if (value_index >= register_end)
{
ecma_free_value (lit_value);
}
if (value_index >= register_end)
{
ecma_free_value (lit_value);
}
break;
}
#if ENABLED (JERRY_ES2015)
case CBC_CREATE_VAR_FUNC:
case CBC_SET_VAR_FUNC:
{
uint8_t type = *byte_code_p;
uint32_t literal_index, value_index;
ecma_value_t lit_value;
byte_code_p++;
READ_LITERAL_INDEX (value_index);
READ_LITERAL_INDEX (literal_index);
JERRY_ASSERT (value_index != literal_index && value_index >= register_end);
lit_value = vm_construct_literal_object (frame_ctx_p,
literal_start_p[value_index]);
if (literal_index < register_end)
{
JERRY_ASSERT (type == CBC_SET_VAR_FUNC);
ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]);
frame_ctx_p->registers_p[literal_index] = lit_value;
break;
}
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
if (type == CBC_CREATE_VAR_FUNC)
{
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
if (!ecma_op_has_binding (lex_env_p, name_p))
{
const bool is_configurable_bindings = frame_ctx_p->is_eval_code;
ecma_value_t completion_value = ecma_op_create_mutable_binding (lex_env_p,
name_p,
is_configurable_bindings);
JERRY_ASSERT (ecma_is_value_empty (completion_value));
}
}
ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (lex_env_p,
name_p,
is_strict,
lit_value);
JERRY_ASSERT (ecma_is_value_boolean (put_value_result)
|| ecma_is_value_empty (put_value_result)
|| ECMA_IS_VALUE_ERROR (put_value_result));
if (ECMA_IS_VALUE_ERROR (put_value_result))
{
ecma_free_value (JERRY_CONTEXT (error_value));
}
ecma_free_value (lit_value);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_SNAPSHOT_EXEC)
case CBC_SET_BYTECODE_PTR:
{
@ -1364,7 +1428,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_SUPER_CLASS, branch_offset);
stack_top_p[-1] = VM_CREATE_CONTEXT_WITH_ENV (VM_CONTEXT_SUPER_CLASS, branch_offset);
frame_ctx_p->lex_env_p = super_env_p;
@ -2818,6 +2882,58 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
*stack_top_p++ = result;
goto free_both_values;
}
case VM_OC_BLOCK_CREATE_CONTEXT:
{
#if ENABLED (JERRY_ES2015)
ecma_value_t *stack_context_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth;
JERRY_ASSERT (stack_context_top_p == stack_top_p || stack_context_top_p == stack_top_p - 1);
if (byte_code_start_p[0] != CBC_EXT_OPCODE)
{
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
if (stack_context_top_p != stack_top_p)
{
/* Preserve the value of switch statement. */
stack_context_top_p[1] = stack_context_top_p[0];
}
stack_context_top_p[0] = VM_CREATE_CONTEXT_WITH_ENV (VM_CONTEXT_BLOCK, branch_offset);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_BLOCK_CONTEXT_STACK_ALLOCATION;
}
else
{
JERRY_ASSERT (byte_code_start_p[1] == CBC_EXT_TRY_CREATE_ENV);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_TRY
|| VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_CATCH
|| VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP
|| VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_THROW
|| VM_GET_CONTEXT_TYPE (stack_context_top_p[-1]) == VM_CONTEXT_FINALLY_RETURN);
JERRY_ASSERT (!(stack_context_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV));
stack_context_top_p[-1] |= VM_CONTEXT_HAS_LEX_ENV;
}
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-2]) == VM_CONTEXT_CATCH
&& !(stack_top_p[-2] & VM_CONTEXT_HAS_LEX_ENV));
stack_top_p[-2] |= VM_CONTEXT_HAS_LEX_ENV;
#endif /* ENABLED (JERRY_ES2015) */
frame_ctx_p->lex_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
#if ENABLED (JERRY_DEBUGGER)
frame_ctx_p->lex_env_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_NON_CLOSURE;
#endif /* ENABLED (JERRY_DEBUGGER) */
frame_ctx_p->byte_code_p = byte_code_p;
vm_init_loop (frame_ctx_p);
byte_code_p = frame_ctx_p->byte_code_p;
continue;
}
case VM_OC_WITH:
{
ecma_value_t value = *(--stack_top_p);
@ -2846,7 +2962,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_WITH_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_WITH, branch_offset);
stack_top_p[-1] = VM_CREATE_CONTEXT_WITH_ENV (VM_CONTEXT_WITH, branch_offset);
frame_ctx_p->lex_env_p = with_env_p;
continue;
@ -2872,7 +2988,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FOR_IN, branch_offset);
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FOR_IN, branch_offset);
ECMA_SET_INTERNAL_VALUE_ANY_POINTER (stack_top_p[-2], prop_names_p);
stack_top_p[-3] = 0;
stack_top_p[-4] = expr_obj_value;
@ -2972,7 +3088,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FOR_OF, branch_offset);
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FOR_OF, branch_offset);
stack_top_p[-2] = iterator_step;
stack_top_p[-3] = iterator;
@ -3032,7 +3148,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_TRY_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_TRY, branch_offset);
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_TRY, branch_offset);
continue;
}
case VM_OC_CATCH:
@ -3053,15 +3169,17 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_TRY
|| VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH);
if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH)
if (stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
stack_top_p[-1] &= (ecma_value_t) ~VM_CONTEXT_HAS_LEX_ENV;
}
stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FINALLY_JUMP, branch_offset);
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FINALLY_JUMP, branch_offset);
stack_top_p[-2] = (ecma_value_t) branch_offset;
continue;
}
@ -3069,59 +3187,64 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
switch (VM_GET_CONTEXT_TYPE (stack_top_p[-1]))
ecma_value_t context_type = VM_GET_CONTEXT_TYPE (stack_top_p[-1]);
if (!VM_CONTEXT_IS_FINALLY (context_type))
{
case VM_CONTEXT_FINALLY_JUMP:
{
uint32_t jump_target = stack_top_p[-2];
stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p);
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth,
PARSER_TRY_CONTEXT_STACK_ALLOCATION);
stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
continue;
}
if (vm_stack_find_finally (frame_ctx_p,
&stack_top_p,
VM_CONTEXT_FINALLY_JUMP,
jump_target))
{
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP);
byte_code_p = frame_ctx_p->byte_code_p;
stack_top_p[-2] = jump_target;
}
else
{
byte_code_p = frame_ctx_p->byte_code_start_p + jump_target;
}
break;
}
case VM_CONTEXT_FINALLY_THROW:
{
JERRY_CONTEXT (error_value) = stack_top_p[-2];
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
#if ENABLED (JERRY_ES2015)
if (stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)
{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
ecma_deref_object (lex_env_p);
}
#endif /* ENABLED (JERRY_ES2015) */
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth,
PARSER_TRY_CONTEXT_STACK_ALLOCATION);
stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
result = ECMA_VALUE_ERROR;
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth,
PARSER_TRY_CONTEXT_STACK_ALLOCATION);
stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
if (context_type == VM_CONTEXT_FINALLY_RETURN)
{
result = *stack_top_p;
goto error;
}
if (context_type == VM_CONTEXT_FINALLY_THROW)
{
JERRY_CONTEXT (error_value) = *stack_top_p;
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
result = ECMA_VALUE_ERROR;
#if ENABLED (JERRY_DEBUGGER)
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
#endif /* ENABLED (JERRY_DEBUGGER) */
goto error;
}
case VM_CONTEXT_FINALLY_RETURN:
{
result = stack_top_p[-2];
goto error;
}
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth,
PARSER_TRY_CONTEXT_STACK_ALLOCATION);
stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
goto error;
}
default:
{
stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p);
}
JERRY_ASSERT (context_type == VM_CONTEXT_FINALLY_JUMP);
uint32_t jump_target = *stack_top_p;
if (vm_stack_find_finally (frame_ctx_p,
&stack_top_p,
VM_CONTEXT_FINALLY_JUMP,
jump_target))
{
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_JUMP);
byte_code_p = frame_ctx_p->byte_code_p;
stack_top_p[-2] = jump_target;
}
else
{
byte_code_p = frame_ctx_p->byte_code_start_p + jump_target;
}
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
@ -3466,31 +3589,23 @@ error:
0))
{
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (!(stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV));
#if ENABLED (JERRY_DEBUGGER)
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
#endif /* ENABLED (JERRY_DEBUGGER) */
if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH)
{
*stack_top_p++ = JERRY_CONTEXT (error_value);
ecma_object_t *catch_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
#if ENABLED (JERRY_DEBUGGER)
catch_env_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_NON_CLOSURE;
#endif /* ENABLED (JERRY_DEBUGGER) */
frame_ctx_p->lex_env_p = catch_env_p;
vm_init_loop (frame_ctx_p);
}
else
{
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_THROW);
stack_top_p[-2] = JERRY_CONTEXT (error_value);
}
byte_code_p = frame_ctx_p->byte_code_p;
if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_THROW)
{
stack_top_p[-2] = JERRY_CONTEXT (error_value);
continue;
}
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH);
*stack_top_p++ = JERRY_CONTEXT (error_value);
continue;
}
}

View File

@ -202,6 +202,9 @@ typedef enum
VM_OC_RIGHT_SHIFT, /**< right shift */
VM_OC_UNS_RIGHT_SHIFT, /**< unsigned right shift */
#if ENABLED (JERRY_ES2015)
VM_OC_BLOCK_CREATE_CONTEXT, /**< create lexical environment for blocks enclosed in braces */
#endif /* ENABLED (JERRY_ES2015) */
VM_OC_WITH, /**< with */
VM_OC_FOR_IN_CREATE_CONTEXT, /**< for in create context */
VM_OC_FOR_IN_GET_NEXT, /**< get next */
@ -260,6 +263,7 @@ typedef enum
#endif /* !ENABLED (JERRY_LINE_INFO) */
#if !ENABLED (JERRY_ES2015)
VM_OC_SET_COMPUTED_PROPERTY = VM_OC_NONE, /**< set computed property is unused */
VM_OC_BLOCK_CREATE_CONTEXT = VM_OC_NONE, /**< create context for blocks enclosed in braces */
VM_OC_FOR_OF_CREATE_CONTEXT = VM_OC_NONE, /**< for of create context */
VM_OC_FOR_OF_GET_NEXT = VM_OC_NONE, /**< get next */

View File

@ -12,4 +12,4 @@
// See the License for the specific language governing permissions and
// limitations under the License.
var let = 1;
var package = 1;

View File

@ -0,0 +1,42 @@
/* 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.
*/
var a = 5;
var a = 6;
let b = 7;
assert (a === 6);
assert (this.a === 6);
assert (b === 7);
assert (this.b === undefined);
{
let c;
c = 8;
{
let c = 9;
assert (c === 9);
}
{
function c() { return 10 }
assert (c() === 10);
}
assert (c === 8);
}
assert (typeof c === "undefined");

View File

@ -0,0 +1,44 @@
/* 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.
*/
function check_syntax_error (code)
{
try {
eval (code);
assert (false);
} catch (e) {
assert (e instanceof SyntaxError);
}
}
check_syntax_error ("let a; let b; let a");
check_syntax_error ("let a, b, a");
check_syntax_error ("var a; let a;");
check_syntax_error ("var a; const a = 3;");
check_syntax_error ("let a; var a;");
check_syntax_error ("const a = 3; var x, y, a;");
check_syntax_error ("let a; { let b; { var a; } }");
check_syntax_error ("{ { var a = 4; } }; let a = 3");
check_syntax_error ("function a() {}; let a;");
check_syntax_error ("let a; function a() {};");
check_syntax_error ("{ { function a() {}; let a; } }");
check_syntax_error ("{ { let a; function a() {}; } }");
check_syntax_error ("let a = 1; const b = 5; const a = 2;");
check_syntax_error ("try {} catch (e) { let e; }");
check_syntax_error ("try {} catch (e) { const e = 1; }");
check_syntax_error ("let A; class A {}");
check_syntax_error ("const A; class A {}");
check_syntax_error ("class A {}; let A");
check_syntax_error ("class A {}; const A");

View File

@ -0,0 +1,68 @@
/* 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.
*/
var g = -1;
function f1() {
/* Function hoisted as var. */
assert (g === undefined);
{
assert (g() === 1);
{
assert (g() === 2);
function g() { return 2 };
}
function g() { return 1 };
assert (g() === 2);
}
assert (g() === 2);
}
f1();
function f2() {
/* Function hoisted as let. */
assert (g === -1);
{
let g = 1;
{
if (true)
{
assert (g() === 2);
if (true)
{
assert (g() === 2);
}
function g() { return 2 };
}
assert (g === 1);
}
assert (g === 1);
}
assert (g === -1);
}
f2();

View File

@ -0,0 +1,68 @@
/* 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.
*/
var g = -1;
function f1() {
/* Function hoisted as var. */
assert (g === undefined);
{
assert (g() === 1);
{
eval("assert (g() === 2)");
function g() { return 2 };
}
function g() { return 1 };
assert (g() === 2);
}
assert (g() === 2);
}
f1();
function f2() {
/* Function hoisted as let. */
assert (g === -1);
{
let g = 1;
{
if (true)
{
assert (g() === 2);
if (true)
{
eval("assert (g() === 2)");
}
function g() { return 2 };
}
assert (g === 1);
}
assert (g === 1);
}
assert (g === -1);
}
f2();

View File

@ -0,0 +1,35 @@
/* 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.
*/
let arr = [];
for (var a = 0; a < 10; a++)
{
let j = a;
var f;
{
f = function () { return j; }
let j = (a & 0x1) ? a + 10 : a + 100;
}
arr[j] = f;
}
for (var a = 0; a < 10; a++)
{
assert (arr[a]() == ((a & 0x1) ? a + 10 : a + 100))
}

View File

@ -0,0 +1,79 @@
/* 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.
*/
try {
let a = 1;
eval ("assert(a === 1)");
} catch (e) {
assert (false);
}
assert (typeof a === "undefined");
try {
let a = 2;
eval ("assert(a === 2)");
assert (typeof b === "undefined");
throw 3;
} catch (e) {
let b = e;
eval ("assert(b === 3)");
assert (typeof a === "undefined");
}
assert (typeof a === "undefined");
assert (typeof b === "undefined");
try {
let a = 4;
eval ("assert(a === 4)");
assert (typeof b === "undefined");
} finally {
let b = 5;
eval ("assert(b === 5)");
assert (typeof a === "undefined");
}
assert (typeof a === "undefined");
assert (typeof b === "undefined");
try {
let a = 6;
eval ("assert(a === 6)");
assert (typeof b === "undefined");
assert (typeof c === "undefined");
throw 7;
} catch (e) {
let b = e;
eval ("assert(b === 7)");
assert (typeof a === "undefined");
assert (typeof c === "undefined");
} finally {
let c = 8;
eval ("assert(c === 8)");
assert (typeof a === "undefined");
assert (typeof b === "undefined");
}
assert (typeof a === "undefined");
assert (typeof b === "undefined");
assert (typeof c === "undefined");

View File

@ -0,0 +1,68 @@
/* 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.
*/
assert (typeof f === "undefined");
function g() { return 6; }
switch (g()) {
case f():
let g = 9;
assert (g === 9);
function f() { return 6; }
break;
default:
assert (false);
}
assert (f() === 6);
switch (g()) {
case f() - 2:
let g = 9;
assert ((function() { return g + f(); })() === 17);
function f() { return 8; }
break;
default:
assert (false);
}
assert (f() === 8);
switch (g()) {
case g() * 2:
{
let g = 4;
assert (g == 4);
}
function g() { return 3; }
break;
default:
assert (false);
}
assert (g() === 3);

View File

@ -0,0 +1,58 @@
/* 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.
*/
assert (typeof A === "undefined");
{
class A {};
{
let A = 6;
assert (A === 6);
}
assert (typeof A === "function");
}
assert (typeof A === "undefined");
{
let A = 5;
{
{
class A {};
assert (typeof A === "function");
}
assert (A === 5);
}
}
assert (typeof A === "undefined");
{
let A = 5;
{
{
class A {};
eval ('assert (typeof A === "function")');
}
eval ('assert (A === 5)');
}
}

View File

@ -0,0 +1,25 @@
// 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.
function f() {
return 'foo';
}
assert ((function() {
if (1 === 0) {
function f() {
return 'bar';
}
}
return f();
})() === 'bar');

View File

@ -16,7 +16,7 @@ function f() {
return 'foo';
}
assert ((function() {
if (1 === 0) {
if (1 === 1) {
function f() {
return 'bar';
}

View File

@ -223,15 +223,15 @@ main (void)
/* Check the snapshot data. Unused bytes should be filled with zeroes */
const uint8_t expected_data[] =
{
0x4A, 0x52, 0x52, 0x59, 0x19, 0x00, 0x00, 0x00,
0x4A, 0x52, 0x52, 0x59, 0x1A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x03, 0x00, 0x01, 0x00, 0x21, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00,
0x28, 0x00, 0xB7, 0x45, 0x00, 0x00, 0x00, 0x00,
0x2C, 0x00, 0xBC, 0x4A, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x01, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00,
0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, 0x6E,
0x61, 0x70, 0x73, 0x68, 0x6F, 0x74,