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:
Zoltan Herczeg
2019-09-17 17:28:11 +02:00
committed by Dániel Bátyai
parent 0eae2f6207
commit 40e63d1207
8 changed files with 177 additions and 48 deletions
-11
View File
@@ -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);
+21 -36
View File
@@ -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,
+2
View File
@@ -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;
+65 -1
View File
@@ -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 ($);
}
+52
View File
@@ -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);