Implement nullish coalescing operator (#3997)
JerryScript-DCO-1.0-Signed-off-by: bence gabor kis kisbg@inf.u-szeged.hu
This commit is contained in:
@@ -35,7 +35,7 @@
|
||||
/**
|
||||
* Maximum precedence for right-to-left binary operation evaluation.
|
||||
*/
|
||||
#define PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE 6
|
||||
#define PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE 7
|
||||
|
||||
/**
|
||||
* Precedence for ternary operation.
|
||||
@@ -45,12 +45,17 @@
|
||||
/**
|
||||
* Precedence for exponentiation operation.
|
||||
*/
|
||||
#define PARSER_RIGHT_TO_LEFT_ORDER_EXPONENTIATION 15
|
||||
#define PARSER_RIGHT_TO_LEFT_ORDER_EXPONENTIATION 16
|
||||
|
||||
/**
|
||||
* Value of grouping level increase and decrease.
|
||||
*/
|
||||
#define PARSER_GROUPING_LEVEL_INCREASE 2
|
||||
#define PARSER_GROUPING_LEVEL_INCREASE 4
|
||||
|
||||
/**
|
||||
* Represents whether logical expression was emitted in the current group expression.
|
||||
*/
|
||||
#define PARSER_GROUPING_LOGICAL_FOUND (1 << 1)
|
||||
|
||||
/**
|
||||
* Precedence of the binary tokens.
|
||||
@@ -60,21 +65,56 @@
|
||||
*/
|
||||
static const uint8_t parser_binary_precedence_table[] =
|
||||
{
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, /**< "=" */
|
||||
3, /**< "+=" */
|
||||
3, /**< "-=" */
|
||||
3, /**< "*=" */
|
||||
3, /**< "/=" */
|
||||
3, /**< "=" */
|
||||
3, /**< "<<=" */
|
||||
3, /**< ">>=" */
|
||||
3, /**< ">>>=" */
|
||||
3, /**< "&=" */
|
||||
3, /**< "|=" */
|
||||
3, /**< "^=" */
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
3,
|
||||
3, /**< "**=" */
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
4, 5, 6, 7, 8, 9, 10, 10, 10, 10,
|
||||
11, 11, 11, 11, 11, 11, 12, 12, 12,
|
||||
13, 13, 14, 14, 14,
|
||||
4, /**< "?"*/
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
15,
|
||||
5, /**< "??" */
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
6, /**< "||" */
|
||||
7, /**< "&&" */
|
||||
8, /**< "|" */
|
||||
9, /**< "^" */
|
||||
10, /**< "&" */
|
||||
11, /**< "==" */
|
||||
11, /**< "!=" */
|
||||
11, /**< "===" */
|
||||
11, /**< "!==" */
|
||||
12, /**< "<" */
|
||||
12, /**< ">" */
|
||||
12, /**< "<=" */
|
||||
12, /**< ">=" */
|
||||
12, /**< in */
|
||||
12, /**< instanceof */
|
||||
13, /**< "<<" */
|
||||
13, /**< ">>" */
|
||||
13, /**< ">>>" */
|
||||
14, /**< "+" */
|
||||
14, /**< "-" */
|
||||
15, /**< "*" */
|
||||
15, /**< "/" */
|
||||
15, /**< "%" */
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
16, /**< "**" */
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
};
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
JERRY_STATIC_ASSERT (sizeof (parser_binary_precedence_table) == 38,
|
||||
parser_binary_precedence_table_should_have_38_values_in_es2015);
|
||||
JERRY_STATIC_ASSERT (sizeof (parser_binary_precedence_table) == 39,
|
||||
parser_binary_precedence_table_should_have_39_values_in_es2015);
|
||||
#else /* !ENABLED (JERRY_ESNEXT) */
|
||||
JERRY_STATIC_ASSERT (sizeof (parser_binary_precedence_table) == 36,
|
||||
parser_binary_precedence_table_should_have_36_values_in_es51);
|
||||
@@ -2653,14 +2693,87 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**<
|
||||
return assign_opcode;
|
||||
} /* parser_append_binary_single_assignment_token */
|
||||
|
||||
/**
|
||||
* Check for invalid logical operator and nullish chaining
|
||||
*/
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
static void
|
||||
parser_check_invalid_logical_op (parser_context_t *context_p, /**< context */
|
||||
size_t grouping_level) /**< grouping_level */
|
||||
{
|
||||
parser_stack_iterator_t iterator;
|
||||
parser_stack_iterator_init (context_p, &iterator);
|
||||
bool logical_found = (grouping_level & PARSER_GROUPING_LOGICAL_FOUND) != 0;
|
||||
bool nullish_found = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint8_t token = parser_stack_iterator_read_uint8 (&iterator);
|
||||
|
||||
if (token == LEXER_EXPRESSION_START
|
||||
|| token == LEXER_LEFT_PAREN
|
||||
|| !LEXER_IS_BINARY_OP_TOKEN (token))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
parser_stack_iterator_skip (&iterator, sizeof (uint8_t));
|
||||
|
||||
if (token == LEXER_ASSIGN)
|
||||
{
|
||||
cbc_opcode_t opcode = (cbc_opcode_t) parser_stack_iterator_read_uint8 (&iterator);
|
||||
|
||||
if (cbc_flags[opcode] & CBC_HAS_LITERAL_ARG)
|
||||
{
|
||||
parser_stack_iterator_skip (&iterator, sizeof (uint16_t));
|
||||
}
|
||||
token = parser_stack_iterator_read_uint8 (&iterator);
|
||||
|
||||
if (token == LEXER_ASSIGN_GROUP_EXPR)
|
||||
{
|
||||
parser_stack_iterator_skip (&iterator, sizeof (uint8_t));
|
||||
}
|
||||
if (token == LEXER_ASSIGN_CONST)
|
||||
{
|
||||
parser_stack_iterator_skip (&iterator, sizeof (uint8_t));
|
||||
}
|
||||
}
|
||||
else if (token == LEXER_LOGICAL_OR || token == LEXER_LOGICAL_AND)
|
||||
{
|
||||
if (nullish_found)
|
||||
{
|
||||
parser_raise_error (context_p, PARSER_ERR_INVALID_NULLISH_COALESCING);
|
||||
}
|
||||
|
||||
parser_stack_iterator_skip (&iterator, sizeof (parser_branch_t));
|
||||
logical_found = true;
|
||||
}
|
||||
else if (token == LEXER_NULLISH_COALESCING)
|
||||
{
|
||||
if (logical_found)
|
||||
{
|
||||
parser_raise_error (context_p, PARSER_ERR_INVALID_NULLISH_COALESCING);
|
||||
}
|
||||
|
||||
parser_stack_iterator_skip (&iterator, sizeof (parser_branch_t));
|
||||
nullish_found = true;
|
||||
}
|
||||
}
|
||||
} /* parser_check_invalid_logical_op */
|
||||
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
/**
|
||||
* Append a binary token.
|
||||
*/
|
||||
static void
|
||||
parser_append_binary_token (parser_context_t *context_p) /**< context */
|
||||
parser_append_binary_token (parser_context_t *context_p, /**< context */
|
||||
size_t grouping_level) /**< grouping_level */
|
||||
{
|
||||
JERRY_ASSERT (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type));
|
||||
|
||||
#if !ENABLED (JERRY_ESNEXT)
|
||||
JERRY_UNUSED (grouping_level);
|
||||
#endif /* !ENABLED (JERRY_ESNEXT) */
|
||||
parser_push_result (context_p);
|
||||
|
||||
if (context_p->token.type == LEXER_ASSIGN)
|
||||
@@ -2715,7 +2828,25 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */
|
||||
|
||||
parser_emit_cbc_forward_branch (context_p, opcode, &branch);
|
||||
parser_stack_push (context_p, &branch, sizeof (parser_branch_t));
|
||||
parser_stack_push_uint8 (context_p, context_p->token.type);
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
parser_check_invalid_logical_op (context_p, grouping_level);
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
return;
|
||||
}
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
else if (context_p->token.type == LEXER_NULLISH_COALESCING)
|
||||
{
|
||||
parser_branch_t branch;
|
||||
|
||||
uint16_t opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_BRANCH_IF_NULLISH);
|
||||
parser_emit_cbc_forward_branch (context_p, opcode, &branch);
|
||||
parser_stack_push (context_p, &branch, sizeof (parser_branch_t));
|
||||
parser_stack_push_uint8 (context_p, context_p->token.type);
|
||||
parser_check_invalid_logical_op (context_p, grouping_level);
|
||||
return;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
parser_stack_push_uint8 (context_p, context_p->token.type);
|
||||
} /* parser_append_binary_token */
|
||||
@@ -2725,8 +2856,12 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */
|
||||
*/
|
||||
static void
|
||||
parser_process_binary_opcodes (parser_context_t *context_p, /**< context */
|
||||
uint8_t min_prec_treshold) /**< minimal precedence of tokens */
|
||||
uint8_t min_prec_treshold, /**< minimal precedence of tokens */
|
||||
size_t *grouping_level_p) /**< grouping level */
|
||||
{
|
||||
#if !ENABLED (JERRY_ESNEXT)
|
||||
JERRY_UNUSED (grouping_level_p);
|
||||
#endif /* !ENABLED (JERRY_ESNEXT) */
|
||||
while (true)
|
||||
{
|
||||
uint8_t token = context_p->stack_top_uint8;
|
||||
@@ -2843,8 +2978,22 @@ parser_process_binary_opcodes (parser_context_t *context_p, /**< context */
|
||||
parser_branch_t branch;
|
||||
parser_stack_pop (context_p, &branch, sizeof (parser_branch_t));
|
||||
parser_set_branch_to_current_position (context_p, &branch);
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
JERRY_ASSERT (grouping_level_p != NULL);
|
||||
*grouping_level_p |= PARSER_GROUPING_LOGICAL_FOUND;
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
continue;
|
||||
}
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
else if (token == LEXER_NULLISH_COALESCING)
|
||||
{
|
||||
parser_branch_t branch;
|
||||
parser_stack_pop (context_p, &branch, sizeof (parser_branch_t));
|
||||
parser_set_branch_to_current_position (context_p, &branch);
|
||||
continue;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
else
|
||||
{
|
||||
opcode = LEXER_BINARY_OP_TOKEN_TO_OPCODE (token);
|
||||
@@ -3054,7 +3203,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */
|
||||
parser_set_branch_to_current_position (context_p, &skip_init);
|
||||
}
|
||||
|
||||
parser_process_binary_opcodes (context_p, 0);
|
||||
parser_process_binary_opcodes (context_p, 0, NULL);
|
||||
|
||||
JERRY_ASSERT (context_p->stack_top_uint8 == LEXER_EXPRESSION_START);
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
@@ -3433,7 +3582,7 @@ parser_process_ternary_expression (parser_context_t *context_p) /**< context */
|
||||
* the result may come from the first branch. */
|
||||
parser_flush_cbc (context_p);
|
||||
|
||||
parser_process_binary_opcodes (context_p, 0);
|
||||
parser_process_binary_opcodes (context_p, 0, NULL);
|
||||
} /* parser_process_ternary_expression */
|
||||
|
||||
/**
|
||||
@@ -3477,6 +3626,12 @@ parser_process_group_expression (parser_context_t *context_p, /**< context */
|
||||
parser_push_result (context_p);
|
||||
parser_flush_cbc (context_p);
|
||||
}
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
else
|
||||
{
|
||||
*grouping_level_p &= (size_t) ~(PARSER_GROUPING_LOGICAL_FOUND);
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
lexer_next_token (context_p);
|
||||
@@ -3555,7 +3710,7 @@ parser_parse_expression (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
if (parser_parse_unary_expression (context_p, &grouping_level))
|
||||
{
|
||||
parser_process_binary_opcodes (context_p, 0);
|
||||
parser_process_binary_opcodes (context_p, 0, &grouping_level);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3592,9 +3747,8 @@ process_unary_expression:
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
}
|
||||
|
||||
parser_process_binary_opcodes (context_p, min_prec_treshold);
|
||||
parser_process_binary_opcodes (context_p, min_prec_treshold, &grouping_level);
|
||||
}
|
||||
|
||||
if (context_p->token.type == LEXER_RIGHT_PAREN
|
||||
&& (context_p->stack_top_uint8 == LEXER_LEFT_PAREN
|
||||
|| context_p->stack_top_uint8 == LEXER_COMMA_SEP_LIST))
|
||||
@@ -3622,7 +3776,7 @@ process_unary_expression:
|
||||
}
|
||||
else if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type))
|
||||
{
|
||||
parser_append_binary_token (context_p);
|
||||
parser_append_binary_token (context_p, grouping_level);
|
||||
lexer_next_token (context_p);
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user