Scanner rework. (#3038)

The scanner was an on-demand tool of the parser, which was triggered by certain
statements. After the rework, the scanner runs only once, and collects all information.
This information is passed to the parser.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2019-09-11 11:15:46 +02:00 committed by Dániel Bátyai
parent 6221b670d1
commit fbde788d1f
24 changed files with 2511 additions and 1471 deletions

View File

@ -1373,45 +1373,19 @@ lexer_check_next_character (parser_context_t *context_p, /**< context */
/**
* Checks whether the next token is a type used for detecting arrow functions.
*
* @return identified token type
* @return true if the next token is an arrow token
*/
lexer_token_type_t
bool
lexer_check_arrow (parser_context_t *context_p) /**< context */
{
lexer_skip_spaces (context_p);
context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
if (context_p->source_p < context_p->source_end_p)
{
switch (context_p->source_p[0])
{
case LIT_CHAR_COMMA:
{
return LEXER_COMMA;
}
case LIT_CHAR_RIGHT_PAREN:
{
return LEXER_RIGHT_PAREN;
}
case LIT_CHAR_EQUALS:
{
if (!(context_p->token.flags & LEXER_WAS_NEWLINE)
&& context_p->source_p + 1 < context_p->source_end_p
&& context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN)
{
return LEXER_ARROW;
}
break;
}
default:
{
break;
}
}
}
return LEXER_EOS;
return (!(context_p->token.flags & LEXER_WAS_NEWLINE)
&& context_p->source_p + 2 <= context_p->source_end_p
&& context_p->source_p[0] == (uint8_t) LIT_CHAR_EQUALS
&& context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN);
} /* lexer_check_arrow */
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
@ -2427,7 +2401,7 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
*/
void
lexer_scan_identifier (parser_context_t *context_p, /**< context */
bool property_name) /**< property name */
uint32_t ident_opts) /**< lexer_scan_ident_opts_t option bits */
{
lexer_skip_spaces (context_p);
context_p->token.line = context_p->line;
@ -2438,7 +2412,9 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */
{
lexer_parse_identifier (context_p, false);
if (property_name && context_p->token.lit_location.length == 3)
if ((ident_opts & LEXER_SCAN_IDENT_PROPERTY)
&& !(ident_opts & LEXER_SCAN_IDENT_NO_KEYW)
&& context_p->token.lit_location.length == 3)
{
lexer_skip_spaces (context_p);
@ -2458,7 +2434,7 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */
return;
}
if (property_name)
if (ident_opts & LEXER_SCAN_IDENT_PROPERTY)
{
lexer_next_token (context_p);

View File

@ -255,6 +255,16 @@ typedef enum
LEXER_OBJ_IDENT_CLASS_METHOD = (1u << 2), /**< expect identifier inside a class body */
} lexer_obj_ident_opts_t;
/**
* Lexer scan identifier parse options.
*/
typedef enum
{
LEXER_SCAN_IDENT_NO_OPTS = (1u << 0), /**< no options */
LEXER_SCAN_IDENT_PROPERTY = (1u << 1), /**< scan valid property names */
LEXER_SCAN_IDENT_NO_KEYW = (1u << 2), /**< don\t scan keywords (e.g. get/set) */
} lexer_scan_ident_opts_t;
/**
* Lexer literal object types.
*/

View File

@ -1041,79 +1041,6 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */
context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY;
} /* parser_parse_function_expression */
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
/**
* Checks whether the bracketed expression is an argument list of an arrow function.
*
* @return true - if an arrow function is found
* false - otherwise
*/
static bool
parser_check_arrow_function (parser_context_t *context_p) /**< context */
{
lexer_range_t range;
range.source_p = context_p->token.lit_location.char_p;
range.line = context_p->token.line;
range.column = context_p->token.column;
lexer_next_token (context_p);
bool is_arrow_function = true;
while (true)
{
if (context_p->token.type == LEXER_RIGHT_PAREN)
{
break;
}
if (context_p->token.type == LEXER_COMMA)
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_next_token (context_p);
continue;
}
}
is_arrow_function = false;
break;
}
if (is_arrow_function)
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_ARROW)
{
is_arrow_function = false;
}
}
context_p->source_p = range.source_p;
context_p->line = range.line;
context_p->column = range.column;
/* Re-parse the original identifier. */
lexer_next_token (context_p);
if (is_arrow_function)
{
parser_parse_function_expression (context_p,
PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | PARSER_ARROW_PARSE_ARGS);
return true;
}
return false;
} /* parser_check_arrow_function */
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS)
/**
@ -1247,6 +1174,13 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
* they are processed when their closing paren is reached. */
if (context_p->token.type == LEXER_LEFT_PAREN)
{
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW);
break;
}
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
(*grouping_level_p)++;
new_was_seen = 0;
}
@ -1283,33 +1217,12 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
case LEXER_LITERAL:
{
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
&& lexer_check_arrow (context_p))
{
switch (lexer_check_arrow (context_p))
{
case LEXER_COMMA:
case LEXER_RIGHT_PAREN:
{
if (context_p->stack_top_uint8 == LEXER_LEFT_PAREN
&& parser_check_arrow_function (context_p))
{
(*grouping_level_p)--;
parser_stack_pop_uint8 (context_p);
return;
}
break;
}
case LEXER_ARROW:
{
parser_parse_function_expression (context_p,
PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION);
return;
}
default:
{
break;
}
}
parser_parse_function_expression (context_p,
PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION);
return;
}
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
@ -1510,19 +1423,16 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
}
#endif /* ENABLED (JERRY_ES2015_CLASS) */
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
case LEXER_RIGHT_PAREN:
case LEXER_LEFT_PAREN:
{
if (context_p->stack_top_uint8 == LEXER_LEFT_PAREN
&& lexer_check_arrow (context_p) == LEXER_ARROW)
{
parser_parse_function_expression (context_p,
PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | PARSER_ARROW_PARSE_ARGS);
JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW);
scanner_release_next (context_p, sizeof (scanner_info_t));
(*grouping_level_p)--;
parser_stack_pop_uint8 (context_p);
return;
}
/* FALLTHRU */
lexer_next_token (context_p);
parser_parse_function_expression (context_p,
PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | PARSER_ARROW_PARSE_ARGS);
return;
}
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
default:

View File

@ -23,6 +23,7 @@
#include "js-parser.h"
#include "js-parser-limits.h"
#include "js-lexer.h"
#include "js-scanner.h"
#include "ecma-module.h"
@ -362,6 +363,10 @@ typedef struct
parser_line_counter_t line; /**< current line */
parser_line_counter_t column; /**< current column */
/* Scanner members. */
scanner_info_t *next_scanner_info_p; /**< next scanner info block */
scanner_info_t *active_scanner_info_p; /**< currently active scanner info block */
/* Compact byte code members. */
cbc_argument_t last_cbc; /**< argument of the last cbc */
uint16_t last_cbc_opcode; /**< opcode of the last cbc */
@ -507,11 +512,11 @@ bool lexer_check_next_character (parser_context_t *context_p, lit_utf8_byte_t ch
void lexer_skip_empty_statements (parser_context_t *context_p);
#endif /* ENABLED (JERRY_ES2015_CLASS) */
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
lexer_token_type_t lexer_check_arrow (parser_context_t *context_p);
bool lexer_check_arrow (parser_context_t *context_p);
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
void lexer_parse_string (parser_context_t *context_p);
void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type);
void lexer_scan_identifier (parser_context_t *context_p, bool property_name);
void lexer_scan_identifier (parser_context_t *context_p, uint32_t ident_opts);
ecma_char_t lexer_hex_to_character (parser_context_t *context_p, const uint8_t *source_p, int length);
void lexer_expect_object_literal_id (parser_context_t *context_p, uint32_t ident_opts);
void lexer_construct_literal_object (parser_context_t *context_p, lexer_lit_location_t *literal_p,
@ -549,7 +554,22 @@ void parser_parse_super_class_context_end (parser_context_t *context_p, bool is_
* @{
*/
void parser_scan_until (parser_context_t *context_p, lexer_range_t *range_p, lexer_token_type_t end_type);
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);
scanner_info_t *scanner_insert_info (parser_context_t *context_p, const uint8_t *source_p, 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);
void scanner_release_switch_cases (scanner_case_info_t *case_p);
void scanner_reverse_info_list (parser_context_t *context_p);
void scanner_cleanup (parser_context_t *context_p);
void scanner_get_location (scanner_location_t *location_p, parser_context_t *context_p);
void scanner_set_location (parser_context_t *context_p, scanner_location_t *location_p);
void scanner_scan_all (parser_context_t *context_p);
/**
* @}

View File

@ -52,8 +52,9 @@ parser_malloc (parser_context_t *context_p, /**< context */
/**
* Free memory allocated by parser_malloc.
*/
void parser_free (void *ptr, /**< pointer to free */
size_t size) /**< size of the memory block */
inline void JERRY_ATTR_ALWAYS_INLINE
parser_free (void *ptr, /**< pointer to free */
size_t size) /**< size of the memory block */
{
jmem_heap_free_block (ptr, size);
} /* parser_free */

File diff suppressed because it is too large Load Diff

View File

@ -133,7 +133,7 @@ typedef struct
typedef struct
{
parser_branch_t branch; /**< branch to the end */
lexer_range_t condition_range; /**< condition part */
scanner_location_t condition_location; /**< condition part */
uint32_t start_offset; /**< start byte code offset */
} parser_while_statement_t;
@ -143,8 +143,8 @@ typedef struct
typedef struct
{
parser_branch_t branch; /**< branch to the end */
lexer_range_t condition_range; /**< condition part */
lexer_range_t expression_range; /**< increase part */
scanner_location_t condition_location; /**< condition part */
scanner_location_t expression_location; /**< expression part */
uint32_t start_offset; /**< start byte code offset */
} parser_for_statement_t;
@ -155,18 +155,7 @@ typedef struct
{
parser_branch_t branch; /**< branch to the end */
uint32_t start_offset; /**< start byte code offset */
} parser_for_in_statement_t;
#if ENABLED (JERRY_ES2015_FOR_OF)
/**
* For-of statement.
*/
typedef struct
{
parser_branch_t branch; /**< branch to the end */
uint32_t start_offset; /**< start byte code offset */
} parser_for_of_statement_t;
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
} parser_for_in_of_statement_t;
/**
* With statement.
@ -225,10 +214,10 @@ parser_statement_length (uint8_t type) /**< type of statement */
/* PARSER_STATEMENT_FOR */
(uint8_t) (sizeof (parser_for_statement_t) + sizeof (parser_loop_statement_t) + 1),
/* PARSER_STATEMENT_FOR_IN */
(uint8_t) (sizeof (parser_for_in_statement_t) + sizeof (parser_loop_statement_t) + 1),
(uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
#if ENABLED (JERRY_ES2015_FOR_OF)
/* PARSER_STATEMENT_FOR_OF */
(uint8_t) (sizeof (parser_for_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
(uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
/* PARSER_STATEMENT_WITH */
(uint8_t) (sizeof (parser_with_statement_t) + 1),
@ -735,6 +724,12 @@ parser_parse_do_while_statement_end (parser_context_t *context_p) /**< context *
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
/* FIXME: These statements should not have scanner info. */
if (context_p->next_scanner_info_p->type == SCANNER_TYPE_WHILE)
{
scanner_release_next (context_p, sizeof (scanner_location_info_t));
}
parser_parse_enclosed_expr (context_p);
if (context_p->last_cbc_opcode != CBC_PUSH_FALSE)
@ -785,13 +780,28 @@ parser_parse_while_statement_start (parser_context_t *context_p) /**< context */
parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
}
JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p
|| context_p->next_scanner_info_p->type == SCANNER_TYPE_WHILE);
if (context_p->next_scanner_info_p->source_p != context_p->source_p)
{
/* The prescanner couldn't find the end of the while condition. */
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
JERRY_ASSERT (context_p->token.type != LEXER_RIGHT_PAREN);
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &while_statement.branch);
JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
while_statement.start_offset = context_p->byte_code_size;
/* The conditional part is processed at the end. */
parser_scan_until (context_p, &while_statement.condition_range, LEXER_RIGHT_PAREN);
while_statement.start_offset = context_p->byte_code_size;
scanner_get_location (&while_statement.condition_location, context_p);
scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
scanner_release_next (context_p, sizeof (scanner_location_info_t));
lexer_next_token (context_p);
loop.branch_list_p = NULL;
@ -811,7 +821,7 @@ parser_parse_while_statement_end (parser_context_t *context_p) /**< context */
parser_while_statement_t while_statement;
parser_loop_statement_t loop;
lexer_token_t current_token;
lexer_range_t range;
scanner_location_t location;
cbc_opcode_t opcode;
JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_WHILE);
@ -824,19 +834,19 @@ parser_parse_while_statement_end (parser_context_t *context_p) /**< context */
parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t));
parser_stack_iterator_read (&iterator, &while_statement, sizeof (parser_while_statement_t));
parser_save_range (context_p, &range, context_p->source_end_p);
scanner_get_location (&location, context_p);
current_token = context_p->token;
parser_set_branch_to_current_position (context_p, &while_statement.branch);
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
parser_set_range (context_p, &while_statement.condition_range);
scanner_set_location (context_p, &while_statement.condition_location);
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_EOS)
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION);
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
opcode = CBC_BRANCH_IF_TRUE_BACKWARD;
@ -857,7 +867,7 @@ parser_parse_while_statement_end (parser_context_t *context_p) /**< context */
parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, while_statement.start_offset);
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
parser_set_range (context_p, &range);
scanner_set_location (context_p, &location);
context_p->token = current_token;
} /* parser_parse_while_statement_end */
@ -914,7 +924,6 @@ static void
parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
{
parser_loop_statement_t loop;
lexer_range_t start_range;
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FOR);
lexer_next_token (context_p);
@ -924,18 +933,29 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
}
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
parser_for_in_of_statement_t for_in_of_statement;
scanner_location_t start_location;
lexer_range_t end_range;
#if ENABLED (JERRY_ES2015_FOR_OF)
lexer_token_type_t scan_token = LEXER_FOR_IN_OF;
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN
|| context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_OF);
bool is_for_in = (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN);
#else /* !ENABLED (JERRY_ES2015_FOR_OF) */
lexer_token_type_t scan_token = LEXER_KEYW_IN;
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN);
bool is_for_in = true;
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
parser_scan_until (context_p, &start_range, scan_token);
scanner_get_location (&start_location, context_p);
scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
/* The length of both 'in' and 'of' is two. */
const uint8_t *source_end_p = context_p->source_p - 2;
if (context_p->token.type == LEXER_KEYW_IN)
{
parser_for_in_statement_t for_in_statement;
lexer_range_t range;
scanner_release_next (context_p, sizeof (scanner_location_info_t));
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
@ -946,18 +966,23 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
}
#ifndef JERRY_NDEBUG
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION);
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth,
is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION
: PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_ext_forward_branch (context_p,
CBC_EXT_FOR_IN_CREATE_CONTEXT,
&for_in_statement.branch);
is_for_in ? CBC_EXT_FOR_IN_CREATE_CONTEXT
: CBC_EXT_FOR_OF_CREATE_CONTEXT,
&for_in_of_statement.branch);
JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
for_in_statement.start_offset = context_p->byte_code_size;
for_in_of_statement.start_offset = context_p->byte_code_size;
parser_save_range (context_p, &range, context_p->source_end_p);
parser_set_range (context_p, &start_range);
/* The expression parser must not read the 'in' or 'of' tokens. */
parser_save_range (context_p, &end_range, context_p->source_end_p);
scanner_set_location (context_p, &start_location);
context_p->source_end_p = source_end_p;
lexer_next_token (context_p);
if (context_p->token.type == LEXER_KEYW_VAR)
@ -986,7 +1011,8 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
parser_set_branch_to_current_position (context_p, &branch);
}
parser_emit_cbc_ext (context_p, CBC_EXT_FOR_IN_GET_NEXT);
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
: CBC_EXT_FOR_OF_GET_NEXT);
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
}
else
@ -1003,7 +1029,8 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
opcode = parser_check_left_hand_side_expression (context_p, opcode);
parser_emit_cbc_ext (context_p, CBC_EXT_FOR_IN_GET_NEXT);
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
: CBC_EXT_FOR_OF_GET_NEXT);
parser_flush_cbc (context_p);
context_p->last_cbc_opcode = opcode;
@ -1011,157 +1038,93 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
if (context_p->token.type != LEXER_EOS)
{
#if ENABLED (JERRY_ES2015_FOR_OF)
parser_raise_error (context_p, is_for_in ? PARSER_ERR_IN_EXPECTED : PARSER_ERR_OF_EXPECTED);
#else /* !ENABLED (JERRY_ES2015_FOR_OF) */
parser_raise_error (context_p, PARSER_ERR_IN_EXPECTED);
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
}
parser_flush_cbc (context_p);
parser_set_range (context_p, &range);
parser_set_range (context_p, &end_range);
lexer_next_token (context_p);
loop.branch_list_p = NULL;
parser_stack_push (context_p, &for_in_statement, sizeof (parser_for_in_statement_t));
parser_stack_push (context_p, &for_in_of_statement, sizeof (parser_for_in_of_statement_t));
parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_IN);
parser_stack_iterator_init (context_p, &context_p->last_statement);
}
#if ENABLED (JERRY_ES2015_FOR_OF)
else if (context_p->token.type == LEXER_LITERAL_OF)
parser_stack_push_uint8 (context_p, is_for_in ? PARSER_STATEMENT_FOR_IN
: PARSER_STATEMENT_FOR_OF);
#else /* !ENABLED (JERRY_ES2015_FOR_OF) */
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_IN);
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
parser_stack_iterator_init (context_p, &context_p->last_statement);
return;
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_SEMICOLON)
{
parser_for_of_statement_t for_of_statement;
lexer_range_t range;
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
#ifndef JERRY_NDEBUG
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_ext_forward_branch (context_p,
CBC_EXT_FOR_OF_CREATE_CONTEXT,
&for_of_statement.branch);
JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
for_of_statement.start_offset = context_p->byte_code_size;
parser_save_range (context_p, &range, context_p->source_end_p);
parser_set_range (context_p, &start_range);
lexer_next_token (context_p);
if (context_p->token.type == LEXER_KEYW_VAR)
{
uint16_t literal_index;
lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
literal_index = context_p->lit_object.index;
lexer_next_token (context_p);
if (context_p->token.type == LEXER_ASSIGN)
{
parser_branch_t branch;
/* Initialiser is never executed. */
parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &branch);
lexer_next_token (context_p);
parser_parse_expression (context_p,
PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA);
parser_set_branch_to_current_position (context_p, &branch);
}
parser_emit_cbc_ext (context_p, CBC_EXT_FOR_OF_GET_NEXT);
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
parser_parse_var_statement (context_p);
}
else
{
uint16_t opcode;
parser_parse_expression (context_p, PARSE_EXPR);
opcode = context_p->last_cbc_opcode;
/* The CBC_EXT_FOR_OF_CREATE_CONTEXT flushed the opcode combiner. */
JERRY_ASSERT (opcode != CBC_PUSH_TWO_LITERALS
&& opcode != CBC_PUSH_THREE_LITERALS);
opcode = parser_check_left_hand_side_expression (context_p, opcode);
parser_emit_cbc_ext (context_p, CBC_EXT_FOR_OF_GET_NEXT);
parser_flush_cbc (context_p);
context_p->last_cbc_opcode = opcode;
parser_parse_expression (context_p, PARSE_EXPR_STATEMENT);
}
if (context_p->token.type != LEXER_EOS)
{
parser_raise_error (context_p, PARSER_ERR_OF_EXPECTED);
}
parser_flush_cbc (context_p);
parser_set_range (context_p, &range);
lexer_next_token (context_p);
loop.branch_list_p = NULL;
parser_stack_push (context_p, &for_of_statement, sizeof (parser_for_of_statement_t));
parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_OF);
parser_stack_iterator_init (context_p, &context_p->last_statement);
}
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
else
{
parser_for_statement_t for_statement;
start_range.source_end_p = context_p->source_end_p;
parser_set_range (context_p, &start_range);
lexer_next_token (context_p);
if (context_p->token.type != LEXER_SEMICOLON)
{
if (context_p->token.type == LEXER_KEYW_VAR)
{
parser_parse_var_statement (context_p);
}
else
{
parser_parse_expression (context_p, PARSE_EXPR_STATEMENT);
}
parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
}
}
if (context_p->token.type != LEXER_SEMICOLON)
{
parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
}
JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p
|| context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR);
if (context_p->next_scanner_info_p->source_p != context_p->source_p
|| ((scanner_for_info_t *) context_p->next_scanner_info_p)->end_location.source_p == NULL)
{
/* The prescanner couldn't find the second semicolon or the closing paranthesis. */
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_SEMICOLON)
{
parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
}
parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &for_statement.branch);
JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
for_statement.start_offset = context_p->byte_code_size;
/* The conditional and expression parts are processed at the end. */
parser_scan_until (context_p, &for_statement.condition_range, LEXER_SEMICOLON);
parser_scan_until (context_p, &for_statement.expression_range, LEXER_RIGHT_PAREN);
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_STATEMENT);
loop.branch_list_p = NULL;
parser_stack_push (context_p, &for_statement, sizeof (parser_for_statement_t));
parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR);
parser_stack_iterator_init (context_p, &context_p->last_statement);
JERRY_ASSERT (context_p->token.type != LEXER_RIGHT_PAREN);
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
parser_for_statement_t for_statement;
scanner_for_info_t *for_info_p = (scanner_for_info_t *) context_p->next_scanner_info_p;
parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &for_statement.branch);
JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
for_statement.start_offset = context_p->byte_code_size;
scanner_get_location (&for_statement.condition_location, context_p);
for_statement.expression_location = for_info_p->expression_location;
scanner_set_location (context_p, &for_info_p->end_location);
scanner_release_next (context_p, sizeof (parser_for_statement_t));
lexer_next_token (context_p);
loop.branch_list_p = NULL;
parser_stack_push (context_p, &for_statement, sizeof (parser_for_statement_t));
parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR);
parser_stack_iterator_init (context_p, &context_p->last_statement);
} /* parser_parse_for_statement_start */
/**
@ -1173,7 +1136,7 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
parser_for_statement_t for_statement;
parser_loop_statement_t loop;
lexer_token_t current_token;
lexer_range_t range;
scanner_location_t location;
cbc_opcode_t opcode;
JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR);
@ -1186,36 +1149,36 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t));
parser_stack_iterator_read (&iterator, &for_statement, sizeof (parser_for_statement_t));
parser_save_range (context_p, &range, context_p->source_end_p);
scanner_get_location (&location, context_p);
current_token = context_p->token;
parser_set_range (context_p, &for_statement.expression_range);
scanner_set_location (context_p, &for_statement.expression_location);
lexer_next_token (context_p);
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
if (context_p->token.type != LEXER_EOS)
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_parse_expression (context_p, PARSE_EXPR_STATEMENT);
if (context_p->token.type != LEXER_EOS)
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION);
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
}
parser_set_branch_to_current_position (context_p, &for_statement.branch);
parser_set_range (context_p, &for_statement.condition_range);
scanner_set_location (context_p, &for_statement.condition_location);
lexer_next_token (context_p);
if (context_p->token.type != LEXER_EOS)
if (context_p->token.type != LEXER_SEMICOLON)
{
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_EOS)
if (context_p->token.type != LEXER_SEMICOLON)
{
parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION);
parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
}
opcode = CBC_BRANCH_IF_TRUE_BACKWARD;
@ -1241,7 +1204,7 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, for_statement.start_offset);
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
parser_set_range (context_p, &range);
scanner_set_location (context_p, &location);
context_p->token = current_token;
} /* parser_parse_for_statement_end */
@ -1254,11 +1217,10 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
parser_switch_statement_t switch_statement;
parser_loop_statement_t loop;
parser_stack_iterator_t iterator;
lexer_range_t switch_body_start;
lexer_range_t unused_range;
scanner_location_t start_location;
bool switch_case_was_found;
bool default_case_was_found;
parser_branch_node_t *cases_p = NULL;
parser_branch_node_t *case_branches_p = NULL;
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_SWITCH);
@ -1269,25 +1231,32 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
}
parser_save_range (context_p, &switch_body_start, context_p->source_end_p);
lexer_next_token (context_p);
JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_SWITCH);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
/* Unlikely case, but possible. */
parser_emit_cbc (context_p, CBC_POP);
parser_flush_cbc (context_p);
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
parser_stack_iterator_init (context_p, &context_p->last_statement);
return;
}
scanner_case_info_t *case_info_p = ((scanner_switch_info_t *) context_p->next_scanner_info_p)->case_p;
scanner_set_active (context_p);
if (context_p->token.type != LEXER_KEYW_CASE
&& context_p->token.type != LEXER_KEYW_DEFAULT)
if (case_info_p == NULL)
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
scanner_release_active (context_p, sizeof (scanner_switch_info_t));
parser_emit_cbc (context_p, CBC_POP);
parser_flush_cbc (context_p);
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
parser_stack_iterator_init (context_p, &context_p->last_statement);
return;
}
parser_raise_error (context_p, PARSER_ERR_INVALID_SWITCH);
}
scanner_get_location (&start_location, context_p);
/* The reason of using an iterator is error management. If an error
* occures, parser_free_jumps() free all data. However, the branches
* created by parser_emit_cbc_forward_branch_item() would not be freed.
@ -1311,78 +1280,76 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
uint32_t last_line_info_line = context_p->last_line_info_line;
#endif /* ENABLED (JERRY_LINE_INFO) */
while (true)
do
{
parser_scan_until (context_p, &unused_range, LEXER_KEYW_CASE);
scanner_set_location (context_p, &case_info_p->location);
case_info_p = case_info_p->next_p;
if (context_p->token.type == LEXER_KEYW_DEFAULT)
/* The last letter of case and default is 'e' and 't' respectively. */
JERRY_ASSERT (context_p->source_p[-1] == LIT_CHAR_LOWERCASE_E
|| context_p->source_p[-1] == LIT_CHAR_LOWERCASE_T);
bool is_default = context_p->source_p[-1] == LIT_CHAR_LOWERCASE_T;
lexer_next_token (context_p);
if (is_default)
{
if (default_case_was_found)
{
parser_raise_error (context_p, PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
default_case_was_found = true;
continue;
}
else if (context_p->token.type == LEXER_KEYW_CASE
|| context_p->token.type == LEXER_RIGHT_BRACE)
{
if (switch_case_was_found)
{
parser_branch_node_t *new_case_p;
uint16_t opcode = CBC_BRANCH_IF_STRICT_EQUAL;
if (context_p->token.type != LEXER_KEYW_CASE)
{
/* We don't duplicate the value for the last case. */
parser_emit_cbc (context_p, CBC_STRICT_EQUAL);
opcode = CBC_BRANCH_IF_TRUE_FORWARD;
}
new_case_p = parser_emit_cbc_forward_branch_item (context_p, opcode, NULL);
if (cases_p == NULL)
{
switch_statement.branch_list_p = new_case_p;
parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t));
}
else
{
cases_p->next_p = new_case_p;
}
cases_p = new_case_p;
}
/* End of switch statement. */
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
break;
}
lexer_next_token (context_p);
switch_case_was_found = true;
#if ENABLED (JERRY_LINE_INFO)
if (context_p->token.line != context_p->last_line_info_line)
{
parser_emit_line_info (context_p, context_p->token.line, true);
}
if (context_p->token.line != context_p->last_line_info_line)
{
parser_emit_line_info (context_p, context_p->token.line, true);
}
#endif /* ENABLED (JERRY_LINE_INFO) */
parser_parse_expression (context_p, PARSE_EXPR);
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
switch_case_was_found = true;
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
lexer_next_token (context_p);
uint16_t opcode = CBC_BRANCH_IF_STRICT_EQUAL;
if (case_info_p == NULL
|| (case_info_p->next_p == NULL && case_info_p->location.source_p[-1] == LIT_CHAR_LOWERCASE_T))
{
/* There are no more 'case' statements in the switch. */
parser_emit_cbc (context_p, CBC_STRICT_EQUAL);
opcode = CBC_BRANCH_IF_TRUE_FORWARD;
}
parser_branch_node_t *new_case_p = parser_emit_cbc_forward_branch_item (context_p, opcode, NULL);
if (case_branches_p == NULL)
{
switch_statement.branch_list_p = new_case_p;
parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t));
}
else
{
case_branches_p->next_p = new_case_p;
}
case_branches_p = new_case_p;
}
while (case_info_p != NULL);
JERRY_ASSERT (switch_case_was_found || default_case_was_found);
@ -1405,7 +1372,10 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
parser_stack_change_last_uint8 (context_p, PARSER_STATEMENT_SWITCH_NO_DEFAULT);
}
parser_set_range (context_p, &switch_body_start);
scanner_release_switch_cases (((scanner_switch_info_t *) context_p->active_scanner_info_p)->case_p);
scanner_release_active (context_p, sizeof (scanner_switch_info_t));
scanner_set_location (context_p, &start_location);
lexer_next_token (context_p);
} /* parser_parse_switch_statement_start */
@ -1569,7 +1539,6 @@ parser_parse_case_statement (parser_context_t *context_p) /**< context */
{
parser_stack_iterator_t iterator;
parser_switch_statement_t switch_statement;
lexer_range_t dummy_range;
parser_branch_node_t *branch_p;
if (context_p->stack_top_uint8 != PARSER_STATEMENT_SWITCH
@ -1578,7 +1547,20 @@ parser_parse_case_statement (parser_context_t *context_p) /**< context */
parser_raise_error (context_p, PARSER_ERR_CASE_NOT_IN_SWITCH);
}
parser_scan_until (context_p, &dummy_range, LEXER_COLON);
if (context_p->next_scanner_info_p->source_p != context_p->source_p)
{
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
JERRY_ASSERT (context_p->token.type != LEXER_COLON);
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CASE);
scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
scanner_release_next (context_p, sizeof (scanner_location_info_t));
lexer_next_token (context_p);
parser_stack_iterator_init (context_p, &iterator);
@ -2753,59 +2735,44 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
}
case PARSER_STATEMENT_FOR_IN:
{
parser_for_in_statement_t for_in_statement;
parser_loop_statement_t loop;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &loop, sizeof (parser_loop_statement_t));
parser_stack_pop (context_p, &for_in_statement, sizeof (parser_for_in_statement_t));
parser_stack_iterator_init (context_p, &context_p->last_statement);
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
parser_flush_cbc (context_p);
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_ext_backward_branch (context_p,
CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT,
for_in_statement.start_offset);
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
parser_set_branch_to_current_position (context_p, &for_in_statement.branch);
continue;
}
#if ENABLED (JERRY_ES2015_FOR_OF)
case PARSER_STATEMENT_FOR_OF:
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
{
parser_for_of_statement_t for_of_statement;
parser_for_in_of_statement_t for_in_of_statement;
parser_loop_statement_t loop;
#if ENABLED (JERRY_ES2015_FOR_OF)
bool is_for_in = (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR_IN);
#else
bool is_for_in = true;
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &loop, sizeof (parser_loop_statement_t));
parser_stack_pop (context_p, &for_of_statement, sizeof (parser_for_of_statement_t));
parser_stack_pop (context_p, &for_in_of_statement, sizeof (parser_for_in_of_statement_t));
parser_stack_iterator_init (context_p, &context_p->last_statement);
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
parser_flush_cbc (context_p);
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION
: PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth,
is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION
: PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_ext_backward_branch (context_p,
CBC_EXT_BRANCH_IF_FOR_OF_HAS_NEXT,
for_of_statement.start_offset);
is_for_in ? CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT
: CBC_EXT_BRANCH_IF_FOR_OF_HAS_NEXT,
for_in_of_statement.start_offset);
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
parser_set_branch_to_current_position (context_p, &for_of_statement.branch);
parser_set_branch_to_current_position (context_p, &for_in_of_statement.branch);
continue;
}
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
case PARSER_STATEMENT_WITH:
{

View File

@ -2393,8 +2393,6 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
if (arg_list_p == NULL)
{
context.status_flags = PARSER_NO_REG_STORE | PARSER_LEXICAL_ENV_NEEDED | PARSER_ARGUMENTS_NOT_NEEDED;
context.source_p = source_p;
context.source_end_p = source_p + source_size;
}
else
{
@ -2407,16 +2405,8 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
context.status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE;
}
#endif /* ENABLED (JERRY_DEBUGGER) */
context.source_p = arg_list_p;
context.source_end_p = arg_list_p + arg_list_size;
}
context.stack_depth = 0;
context.stack_limit = 0;
context.last_context_p = NULL;
context.last_statement.current_p = NULL;
context.status_flags |= parse_opts & PARSER_STRICT_MODE_MASK;
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
if (parse_opts & ECMA_PARSE_EVAL)
{
@ -2430,10 +2420,23 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
context.status_flags |= PARSER_GET_CLASS_PARSER_OPTS (parse_opts);
#endif /* ENABLED (JERRY_ES2015_CLASS) */
context.stack_depth = 0;
context.stack_limit = 0;
context.last_context_p = NULL;
context.last_statement.current_p = NULL;
context.status_flags |= parse_opts & PARSER_STRICT_MODE_MASK;
context.token.flags = 0;
context.line = 1;
context.column = 1;
scanner_info_t scanner_info_end;
scanner_info_end.next_p = NULL;
scanner_info_end.source_p = NULL;
scanner_info_end.type = SCANNER_TYPE_END;
context.next_scanner_info_p = &scanner_info_end;
context.active_scanner_info_p = NULL;
context.last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
context.argument_count = 0;
@ -2445,7 +2448,6 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
parser_list_init (&context.literal_pool,
sizeof (lexer_literal_t),
(uint32_t) ((128 - sizeof (void *)) / sizeof (lexer_literal_t)));
parser_stack_init (&context);
#ifndef JERRY_NDEBUG
context.context_stack_depth = 0;
@ -2463,6 +2465,42 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
}
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
context.source_p = source_p;
context.source_end_p = source_p + source_size;
context.line = 1;
context.column = 1;
scanner_scan_all (&context);
if (JERRY_UNLIKELY (context.error != PARSER_ERR_NO_ERROR))
{
JERRY_ASSERT (context.error == PARSER_ERR_OUT_OF_MEMORY);
if (error_location_p != NULL)
{
error_location_p->error = context.error;
error_location_p->line = context.token.line;
error_location_p->column = context.token.column;
}
return NULL;
}
if (arg_list_p == NULL)
{
context.source_p = source_p;
context.source_end_p = source_p + source_size;
}
else
{
context.source_p = arg_list_p;
context.source_end_p = arg_list_p + arg_list_size;
}
context.line = 1;
context.column = 1;
parser_stack_init (&context);
#if ENABLED (JERRY_DEBUGGER)
context.breakpoint_info_count = 0;
#endif /* ENABLED (JERRY_DEBUGGER) */
@ -2529,6 +2567,8 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
context.allocated_buffer_size);
}
scanner_cleanup (&context);
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
if (context.module_current_node_p != NULL
&& context.module_current_node_p->module_names_p != NULL)
@ -2881,12 +2921,14 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
/**
* Raise a parse error
* Raise a parse error.
*/
void
parser_raise_error (parser_context_t *context_p, /**< context */
parser_error_t error) /**< error code */
{
/* Must be compatible with the scanner because
* the lexer might throws errors during prescanning. */
parser_saved_context_t *saved_context_p = context_p->last_context_p;
while (saved_context_p != NULL)

View File

@ -0,0 +1,290 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "js-parser-internal.h"
#if ENABLED (JERRY_PARSER)
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_scanner Scanner
* @{
*/
/**
* Raise a scanner error.
*/
void
scanner_raise_error (parser_context_t *context_p) /**< context */
{
PARSER_THROW (context_p->try_buffer);
/* Should never been reached. */
JERRY_ASSERT (0);
} /* scanner_raise_error */
/**
* Allocate memory for scanner.
*
* @return allocated memory
*/
void *
scanner_malloc (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory block */
{
void *result;
JERRY_ASSERT (size > 0);
result = jmem_heap_alloc_block_null_on_error (size);
if (result == NULL)
{
scanner_cleanup (context_p);
/* This is the only error which specify its reason. */
context_p->error = PARSER_ERR_OUT_OF_MEMORY;
PARSER_THROW (context_p->try_buffer);
}
return result;
} /* scanner_malloc */
/**
* Free memory allocated by scanner_malloc.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_free (void *ptr, /**< pointer to free */
size_t size) /**< size of the memory block */
{
jmem_heap_free_block (ptr, size);
} /* scanner_free */
/**
* Insert a scanner info block into the scanner info chain.
*
* @return newly allocated scanner info
*/
scanner_info_t *
scanner_insert_info (parser_context_t *context_p, /**< context */
const uint8_t *source_p, /**< triggering position */
size_t size) /**< size of the memory block */
{
scanner_info_t *new_scanner_info_p = (scanner_info_t *) scanner_malloc (context_p, size);
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
scanner_info_t *prev_scanner_info_p = NULL;
JERRY_ASSERT (scanner_info_p != NULL);
new_scanner_info_p->source_p = source_p;
while (source_p < scanner_info_p->source_p)
{
prev_scanner_info_p = scanner_info_p;
scanner_info_p = scanner_info_p->next_p;
JERRY_ASSERT (scanner_info_p != NULL);
}
/* Multiple scanner info blocks cannot be assigned to the same position. */
JERRY_ASSERT (source_p != scanner_info_p->source_p);
new_scanner_info_p->next_p = scanner_info_p;
if (JERRY_LIKELY (prev_scanner_info_p == NULL))
{
context_p->next_scanner_info_p = new_scanner_info_p;
}
else
{
prev_scanner_info_p->next_p = new_scanner_info_p;
}
return new_scanner_info_p;
} /* scanner_insert_info */
/**
* Release the next scanner info.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_release_next (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory block */
{
scanner_info_t *next_p = context_p->next_scanner_info_p->next_p;
jmem_heap_free_block (context_p->next_scanner_info_p, size);
context_p->next_scanner_info_p = next_p;
} /* scanner_release_next */
/**
* Set the active scanner info to the next scanner info.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_set_active (parser_context_t *context_p)
{
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
context_p->next_scanner_info_p = scanner_info_p->next_p;
scanner_info_p->next_p = context_p->active_scanner_info_p;
context_p->active_scanner_info_p = scanner_info_p;
} /* scanner_set_active */
/**
* Release the active scanner info.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_release_active (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory block */
{
scanner_info_t *next_p = context_p->active_scanner_info_p->next_p;
jmem_heap_free_block (context_p->active_scanner_info_p, size);
context_p->active_scanner_info_p = next_p;
} /* scanner_release_active */
void
scanner_release_switch_cases (scanner_case_info_t *case_p) /**< case list */
{
while (case_p != NULL)
{
scanner_case_info_t *next_p = case_p->next_p;
jmem_heap_free_block (case_p, sizeof (scanner_case_info_t));
case_p = next_p;
}
} /* scanner_release_switch_cases */
/**
* Reverse the scanner info chain after the scanning is completed.
*/
void
scanner_reverse_info_list (parser_context_t *context_p) /**< context */
{
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
scanner_info_t *last_scanner_info_p = NULL;
if (scanner_info_p->type == SCANNER_TYPE_END)
{
return;
}
do
{
scanner_info_t *next_scanner_info_p = scanner_info_p->next_p;
scanner_info_p->next_p = last_scanner_info_p;
last_scanner_info_p = scanner_info_p;
scanner_info_p = next_scanner_info_p;
}
while (scanner_info_p->type != SCANNER_TYPE_END);
context_p->next_scanner_info_p->next_p = scanner_info_p;
context_p->next_scanner_info_p = last_scanner_info_p;
} /* scanner_reverse_info_list */
/**
* Release unused scanner info blocks.
* This should happen only if an error is occured.
*/
void
scanner_cleanup (parser_context_t *context_p) /**< context */
{
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
while (scanner_info_p != NULL)
{
scanner_info_t *next_scanner_info_p = scanner_info_p->next_p;
size_t size = sizeof (scanner_info_t);
switch (scanner_info_p->type)
{
case SCANNER_TYPE_END:
{
scanner_info_p = context_p->active_scanner_info_p;
continue;
}
case SCANNER_TYPE_WHILE:
case SCANNER_TYPE_FOR_IN:
#if ENABLED (JERRY_ES2015_FOR_OF)
case SCANNER_TYPE_FOR_OF:
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
case SCANNER_TYPE_CASE:
{
size = sizeof (scanner_location_info_t);
break;
}
case SCANNER_TYPE_FOR:
{
size = sizeof (scanner_for_info_t);
break;
}
case SCANNER_TYPE_SWITCH:
{
scanner_release_switch_cases (((scanner_switch_info_t *) scanner_info_p)->case_p);
size = sizeof (scanner_switch_info_t);
break;
}
default:
{
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_ARROW);
#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
JERRY_ASSERT (0);
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
break;
}
}
scanner_free (scanner_info_p, size);
scanner_info_p = next_scanner_info_p;
}
context_p->next_scanner_info_p = NULL;
context_p->active_scanner_info_p = NULL;
} /* scanner_cleanup */
/**
* Get location from context.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_get_location (scanner_location_t *location_p, /**< location */
parser_context_t *context_p) /**< context */
{
location_p->source_p = context_p->source_p;
location_p->line = context_p->line;
location_p->column = context_p->column;
} /* scanner_get_location */
/**
* Set context location.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_set_location (parser_context_t *context_p, /**< context */
scanner_location_t *location_p) /**< location */
{
context_p->source_p = location_p->source_p;
context_p->line = location_p->line;
context_p->column = location_p->column;
} /* scanner_set_location */
/**
* @}
* @}
* @}
*/
#endif /* ENABLED (JERRY_PARSER) */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
/* 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.
*/
#ifndef JS_SCANNER_H
#define JS_SCANNER_H
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_scanner Scanner
* @{
*/
/**
* Allowed types for scanner_info_t structures.
*/
typedef enum
{
SCANNER_TYPE_END, /**< mark the last info block */
SCANNER_TYPE_WHILE, /**< while statement */
SCANNER_TYPE_FOR, /**< for statement */
SCANNER_TYPE_FOR_IN, /**< for-in statement */
#if ENABLED (JERRY_ES2015_FOR_OF)
SCANNER_TYPE_FOR_OF, /**< for-of statement */
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
SCANNER_TYPE_SWITCH, /**< switch statement */
SCANNER_TYPE_CASE, /**< case statement */
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
SCANNER_TYPE_ARROW, /**< arrow function */
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
} scanner_info_type_t;
/**
* Source code location which can be used to change the position of parsing.
*/
typedef struct
{
const uint8_t *source_p; /**< next source byte */
parser_line_counter_t line; /**< token start line */
parser_line_counter_t column; /**< token start column */
} scanner_location_t;
/**
* Scanner info blocks which provides information for the parser.
*/
typedef struct scanner_info_t
{
struct scanner_info_t *next_p; /**< next info structure */
const uint8_t *source_p; /**< triggering position of this scanner info */
uint8_t type; /**< type of the scanner info */
} scanner_info_t;
/**
* Scanner info extended with a location.
*/
typedef struct
{
scanner_info_t info; /**< header */
scanner_location_t location; /**< location */
} scanner_location_info_t;
/**
* Scanner info for "for" statements.
*/
typedef struct
{
scanner_info_t info; /**< header */
scanner_location_t expression_location; /**< location of expression start */
scanner_location_t end_location; /**< location of expression end */
} scanner_for_info_t;
/**
* Case statement list for scanner_switch_info_t structure.
*/
typedef struct scanner_case_info_t
{
struct scanner_case_info_t *next_p; /**< next case statement info */
scanner_location_t location; /**< location of case statement */
} scanner_case_info_t;
/**
* Scanner info for "switch" statements.
*/
typedef struct
{
scanner_info_t info; /**< header */
scanner_case_info_t *case_p; /**< list of switch cases */
} scanner_switch_info_t;
/**
* @}
* @}
* @}
*/
#endif /* !JS_SCANNER_H */

View File

@ -125,6 +125,13 @@ default:
func = () =>
((([0,0,0])))
assert (func ().length == 3);
func = (a = 5, b = 7 * 2) => a + b;
assert (func() == 19);
assert (func(1) == 15);
func = (a = Math.cos(0)) => a;
assert (func() == 1);
}
must_throw ("var x => x;");
@ -136,6 +143,7 @@ must_throw ("(x,y,) => 0");
must_throw ("x\n => 0");
must_throw ("this => 0");
must_throw ("(true) => 0");
must_throw ("()\n=>5");
must_throw_strict ("(package) => 0");
must_throw_strict ("(package) => { return 5 }");
must_throw_strict ("(x,x,x) => 0");

View File

@ -39,3 +39,6 @@ assert (x === 42);
assert (f(1) === 1);
var dog = new Dog("Pluto")
assert(dog.speak() === "Pluto barks.")
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -18,3 +18,6 @@ export {aa,} from "module-export-01.js";
export {bb as b_, cc as c_} from "module-export-01.js";
export * from "module-export-01.js";
export default function () {return "default"};
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -24,3 +24,6 @@ export default class {
}
export * from "module-export-02.js"
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -15,3 +15,6 @@
export var x = 41
export default a = "str"
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -16,3 +16,6 @@
export * from "module-export-01.js";
export * from "module-export-04.js";
export default a = "str"
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -17,3 +17,6 @@ export {}
export {} from "module-export-01.js";
export {};
export {} from "module-export-04.js"
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -15,3 +15,6 @@
var y, z;
export default x = y = z = "default";
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -31,3 +31,6 @@ assert (mod.f("str") === "str")
var dog = new mod.Dog("Oddie")
assert (dog.speak() === "Oddie barks.")
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -22,3 +22,6 @@ assert (b_ === 5)
assert (c_(b_) === 10)
assert (mod.x === 42)
assert (Array.isArray(mod.d))
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -22,3 +22,6 @@ assert(i.incr() === 6);
assert (aa === "a");
assert (x === 42);
assert (c_(x) == 84);
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -17,3 +17,6 @@ import "module-import-01.js";
import "module-export-05.js";
import "module-export-06.js";
import "module-export-07.js";
// Pre-scanner regression test
for (var tmp in {}) ;

View File

@ -14,7 +14,7 @@
var src = "var a = 0; while(a) { switch(a) {";
/* The += operation has a longer opcode. */
for (var i = 0; i < 4000; i++)
for (var i = 0; i < 3500; i++)
src += "case " + i + ": a += a += a; break; ";
src += "} }";