Implement seeking in the pre-scanner info. (#3126)
After changing the lexing position, the current position of the scanner info must be moved as well. Fixes #3101 Fixes #3102 JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
committed by
Dániel Bátyai
parent
0eae2f6207
commit
40e63d1207
@@ -300,17 +300,6 @@ typedef struct
|
||||
uint8_t has_escape; /**< has escape sequences */
|
||||
} lexer_lit_location_t;
|
||||
|
||||
/**
|
||||
* Range of input string which processing is postponed.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const uint8_t *source_p; /**< next source byte */
|
||||
const uint8_t *source_end_p; /**< last source byte */
|
||||
parser_line_counter_t line; /**< token start line */
|
||||
parser_line_counter_t column; /**< token start column */
|
||||
} lexer_range_t;
|
||||
|
||||
/**
|
||||
* Lexer token.
|
||||
*/
|
||||
|
||||
@@ -369,6 +369,8 @@ typedef struct
|
||||
/* 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 */
|
||||
scanner_info_t *skipped_scanner_info_p; /**< next scanner info block */
|
||||
scanner_info_t *skipped_scanner_info_end_p; /**< currently active scanner info block */
|
||||
|
||||
/* Compact byte code members. */
|
||||
cbc_argument_t last_cbc; /**< argument of the last cbc */
|
||||
@@ -566,6 +568,7 @@ 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_seek (parser_context_t *context_p);
|
||||
void scanner_reverse_info_list (parser_context_t *context_p);
|
||||
void scanner_cleanup (parser_context_t *context_p);
|
||||
|
||||
|
||||
@@ -230,33 +230,6 @@ parser_statement_length (uint8_t type) /**< type of statement */
|
||||
return statement_lengths[type - PARSER_STATEMENT_BLOCK];
|
||||
} /* parser_statement_length */
|
||||
|
||||
/**
|
||||
* Initialize a range from the current location.
|
||||
*/
|
||||
static inline void
|
||||
parser_save_range (parser_context_t *context_p, /**< context */
|
||||
lexer_range_t *range_p, /**< destination range */
|
||||
const uint8_t *source_end_p) /**< source end */
|
||||
{
|
||||
range_p->source_p = context_p->source_p;
|
||||
range_p->source_end_p = source_end_p;
|
||||
range_p->line = context_p->line;
|
||||
range_p->column = context_p->column;
|
||||
} /* parser_save_range */
|
||||
|
||||
/**
|
||||
* Set the current location on the stack.
|
||||
*/
|
||||
static inline void
|
||||
parser_set_range (parser_context_t *context_p, /**< context */
|
||||
lexer_range_t *range_p) /**< destination range */
|
||||
{
|
||||
context_p->source_p = range_p->source_p;
|
||||
context_p->source_end_p = range_p->source_end_p;
|
||||
context_p->line = range_p->line;
|
||||
context_p->column = range_p->column;
|
||||
} /* parser_set_range */
|
||||
|
||||
/**
|
||||
* Initialize stack iterator.
|
||||
*/
|
||||
@@ -802,6 +775,7 @@ parser_parse_while_statement_start (parser_context_t *context_p) /**< context */
|
||||
|
||||
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));
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
|
||||
loop.branch_list_p = NULL;
|
||||
@@ -841,6 +815,7 @@ parser_parse_while_statement_end (parser_context_t *context_p) /**< context */
|
||||
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
|
||||
|
||||
scanner_set_location (context_p, &while_statement.condition_location);
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
|
||||
parser_parse_expression (context_p, PARSE_EXPR);
|
||||
@@ -868,6 +843,7 @@ parser_parse_while_statement_end (parser_context_t *context_p) /**< context */
|
||||
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
|
||||
|
||||
scanner_set_location (context_p, &location);
|
||||
scanner_seek (context_p);
|
||||
context_p->token = current_token;
|
||||
} /* parser_parse_while_statement_end */
|
||||
|
||||
@@ -936,8 +912,7 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
|
||||
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;
|
||||
scanner_location_t start_location, end_location;
|
||||
|
||||
#if ENABLED (JERRY_ES2015_FOR_OF)
|
||||
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN
|
||||
@@ -956,7 +931,7 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
|
||||
const uint8_t *source_end_p = context_p->source_p - 2;
|
||||
|
||||
scanner_release_next (context_p, sizeof (scanner_location_info_t));
|
||||
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
parser_parse_expression (context_p, PARSE_EXPR);
|
||||
|
||||
@@ -980,9 +955,12 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
|
||||
for_in_of_statement.start_offset = context_p->byte_code_size;
|
||||
|
||||
/* The expression parser must not read the 'in' or 'of' tokens. */
|
||||
parser_save_range (context_p, &end_range, context_p->source_end_p);
|
||||
scanner_get_location (&end_location, context_p);
|
||||
scanner_set_location (context_p, &start_location);
|
||||
|
||||
const uint8_t *original_source_end_p = context_p->source_end_p;
|
||||
context_p->source_end_p = source_end_p;
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type == LEXER_KEYW_VAR)
|
||||
@@ -1046,7 +1024,8 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
|
||||
}
|
||||
|
||||
parser_flush_cbc (context_p);
|
||||
parser_set_range (context_p, &end_range);
|
||||
scanner_set_location (context_p, &end_location);
|
||||
context_p->source_end_p = original_source_end_p;
|
||||
lexer_next_token (context_p);
|
||||
|
||||
loop.branch_list_p = NULL;
|
||||
@@ -1117,6 +1096,7 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
|
||||
|
||||
scanner_set_location (context_p, &for_info_p->end_location);
|
||||
scanner_release_next (context_p, sizeof (parser_for_statement_t));
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
|
||||
loop.branch_list_p = NULL;
|
||||
@@ -1153,6 +1133,7 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
|
||||
current_token = context_p->token;
|
||||
|
||||
scanner_set_location (context_p, &for_statement.expression_location);
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
|
||||
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
|
||||
@@ -1170,6 +1151,7 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
|
||||
parser_set_branch_to_current_position (context_p, &for_statement.branch);
|
||||
|
||||
scanner_set_location (context_p, &for_statement.condition_location);
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type != LEXER_SEMICOLON)
|
||||
@@ -1205,6 +1187,7 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
|
||||
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
|
||||
|
||||
scanner_set_location (context_p, &location);
|
||||
scanner_seek (context_p);
|
||||
context_p->token = current_token;
|
||||
} /* parser_parse_for_statement_end */
|
||||
|
||||
@@ -1283,9 +1266,9 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
|
||||
do
|
||||
{
|
||||
scanner_set_location (context_p, &case_info_p->location);
|
||||
scanner_seek (context_p);
|
||||
case_info_p = case_info_p->next_p;
|
||||
|
||||
|
||||
/* 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);
|
||||
@@ -1376,6 +1359,7 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
|
||||
scanner_release_active (context_p, sizeof (scanner_switch_info_t));
|
||||
|
||||
scanner_set_location (context_p, &start_location);
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
} /* parser_parse_switch_statement_start */
|
||||
|
||||
@@ -1561,6 +1545,7 @@ parser_parse_case_statement (parser_context_t *context_p) /**< context */
|
||||
|
||||
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));
|
||||
scanner_seek (context_p);
|
||||
lexer_next_token (context_p);
|
||||
|
||||
parser_stack_iterator_init (context_p, &iterator);
|
||||
@@ -1954,8 +1939,8 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */
|
||||
{
|
||||
case LEXER_KEYW_DEFAULT:
|
||||
{
|
||||
lexer_range_t range;
|
||||
parser_save_range (context_p, &range, context_p->source_end_p);
|
||||
scanner_location_t location;
|
||||
scanner_get_location (&location, context_p);
|
||||
|
||||
context_p->status_flags |= PARSER_MODULE_STORE_IDENT;
|
||||
|
||||
@@ -1973,7 +1958,7 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */
|
||||
else
|
||||
{
|
||||
/* Assignment expression */
|
||||
parser_set_range (context_p, &range);
|
||||
scanner_set_location (context_p, &location);
|
||||
|
||||
/* 15.2.3.5 Use the synthetic name '*default*' as the identifier. */
|
||||
lexer_construct_literal_object (context_p,
|
||||
|
||||
@@ -2436,6 +2436,8 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
|
||||
scanner_info_end.type = SCANNER_TYPE_END;
|
||||
context.next_scanner_info_p = &scanner_info_end;
|
||||
context.active_scanner_info_p = NULL;
|
||||
context.skipped_scanner_info_p = NULL;
|
||||
context.skipped_scanner_info_end_p = NULL;
|
||||
|
||||
context.last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ scanner_release_next (parser_context_t *context_p, /**< context */
|
||||
* 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_set_active (parser_context_t *context_p) /**< context */
|
||||
{
|
||||
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
|
||||
|
||||
@@ -156,6 +156,9 @@ scanner_release_active (parser_context_t *context_p, /**< context */
|
||||
context_p->active_scanner_info_p = next_p;
|
||||
} /* scanner_release_active */
|
||||
|
||||
/**
|
||||
* Release switch cases.
|
||||
*/
|
||||
void
|
||||
scanner_release_switch_cases (scanner_case_info_t *case_p) /**< case list */
|
||||
{
|
||||
@@ -168,6 +171,60 @@ scanner_release_switch_cases (scanner_case_info_t *case_p) /**< case list */
|
||||
}
|
||||
} /* scanner_release_switch_cases */
|
||||
|
||||
/**
|
||||
* Seek to correct position in the scanner info list.
|
||||
*/
|
||||
void
|
||||
scanner_seek (parser_context_t *context_p) /**< context */
|
||||
{
|
||||
const uint8_t *source_p = context_p->source_p;
|
||||
scanner_info_t *prev_p;
|
||||
|
||||
if (context_p->skipped_scanner_info_p != NULL)
|
||||
{
|
||||
JERRY_ASSERT (context_p->skipped_scanner_info_p->source_p != NULL);
|
||||
|
||||
context_p->skipped_scanner_info_end_p->next_p = context_p->next_scanner_info_p;
|
||||
|
||||
if (context_p->skipped_scanner_info_end_p->source_p <= source_p)
|
||||
{
|
||||
prev_p = context_p->skipped_scanner_info_end_p;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_p = context_p->skipped_scanner_info_p;
|
||||
|
||||
if (prev_p->source_p > source_p)
|
||||
{
|
||||
context_p->next_scanner_info_p = prev_p;
|
||||
context_p->skipped_scanner_info_p = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
context_p->skipped_scanner_info_p = prev_p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_p = context_p->next_scanner_info_p;
|
||||
|
||||
if (prev_p->source_p == NULL || prev_p->source_p > source_p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context_p->skipped_scanner_info_p = prev_p;
|
||||
}
|
||||
|
||||
while (prev_p->next_p->source_p != NULL && prev_p->next_p->source_p <= source_p)
|
||||
{
|
||||
prev_p = prev_p->next_p;
|
||||
}
|
||||
|
||||
context_p->skipped_scanner_info_end_p = prev_p;
|
||||
context_p->next_scanner_info_p = prev_p->next_p;
|
||||
} /* scanner_seek */
|
||||
|
||||
/**
|
||||
* Reverse the scanner info chain after the scanning is completed.
|
||||
*/
|
||||
@@ -203,6 +260,13 @@ scanner_reverse_info_list (parser_context_t *context_p) /**< context */
|
||||
void
|
||||
scanner_cleanup (parser_context_t *context_p) /**< context */
|
||||
{
|
||||
if (context_p->skipped_scanner_info_p != NULL)
|
||||
{
|
||||
context_p->skipped_scanner_info_end_p->next_p = context_p->next_scanner_info_p;
|
||||
context_p->next_scanner_info_p = context_p->skipped_scanner_info_p;
|
||||
context_p->skipped_scanner_info_p = NULL;
|
||||
}
|
||||
|
||||
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
|
||||
|
||||
while (scanner_info_p != NULL)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
for ( ; ; ( ) => 0) {
|
||||
for ( ; $; $) ;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
while ( $(($) => {}) ) {
|
||||
while ($);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright JS Foundation and other contributors, http://js.foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
var a = 0;
|
||||
var count = 0;
|
||||
while ( function() { while (++a < 0) ; } (), a < 4) {
|
||||
while (++count < 0) ;
|
||||
}
|
||||
assert(count == 3);
|
||||
|
||||
for (a = 0, count = 0; function() { while (++a < 0) ; } (), a < 4 ; ) {
|
||||
while (++count < 0) ;
|
||||
}
|
||||
assert(count == 3);
|
||||
|
||||
a = 0;
|
||||
count = 0;
|
||||
switch (100) {
|
||||
default:
|
||||
while (++a < 2) ;
|
||||
break;
|
||||
|
||||
case (function () { for (var a = 0; a <= 1; a++) count ++; return a; })():
|
||||
while (++a < 100) ;
|
||||
break;
|
||||
|
||||
case (function () { for (var a = 0; a <= 2; a++) count ++; return a; })():
|
||||
while (++a < 100) ;
|
||||
break;
|
||||
|
||||
case (function () { for (var a = 0; a <= 3; a++) count ++; return a; })():
|
||||
while (++a < 100) ;
|
||||
break;
|
||||
|
||||
case (function () { for (var a = 0; a <= 4; a++) count ++; return a; })():
|
||||
while (++a < 100) ;
|
||||
break;
|
||||
}
|
||||
|
||||
assert (count == 14);
|
||||
assert (a == 2);
|
||||
Reference in New Issue
Block a user