mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
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:
parent
6221b670d1
commit
fbde788d1f
@ -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);
|
||||
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@ -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
@ -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:
|
||||
{
|
||||
|
||||
@ -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)
|
||||
|
||||
290
jerry-core/parser/js/js-scanner-util.c
Normal file
290
jerry-core/parser/js/js-scanner-util.c
Normal 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) */
|
||||
1702
jerry-core/parser/js/js-scanner.c
Normal file
1702
jerry-core/parser/js/js-scanner.c
Normal file
File diff suppressed because it is too large
Load Diff
111
jerry-core/parser/js/js-scanner.h
Normal file
111
jerry-core/parser/js/js-scanner.h
Normal 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 */
|
||||
@ -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");
|
||||
|
||||
@ -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 {}) ;
|
||||
|
||||
@ -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 {}) ;
|
||||
|
||||
@ -24,3 +24,6 @@ export default class {
|
||||
}
|
||||
|
||||
export * from "module-export-02.js"
|
||||
|
||||
// Pre-scanner regression test
|
||||
for (var tmp in {}) ;
|
||||
|
||||
@ -15,3 +15,6 @@
|
||||
|
||||
export var x = 41
|
||||
export default a = "str"
|
||||
|
||||
// Pre-scanner regression test
|
||||
for (var tmp in {}) ;
|
||||
|
||||
@ -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 {}) ;
|
||||
|
||||
@ -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 {}) ;
|
||||
|
||||
@ -15,3 +15,6 @@
|
||||
|
||||
var y, z;
|
||||
export default x = y = z = "default";
|
||||
|
||||
// Pre-scanner regression test
|
||||
for (var tmp in {}) ;
|
||||
|
||||
@ -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 {}) ;
|
||||
|
||||
@ -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 {}) ;
|
||||
|
||||
@ -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 {}) ;
|
||||
|
||||
@ -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 {}) ;
|
||||
|
||||
@ -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 += "} }";
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user