Fix 'switch' bytecode generation. Remove __strtof. Fix opcodes pretty-printing.
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
#include "parse-error.h"
|
#include "parse-error.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "ecma-helpers.h"
|
||||||
|
|
||||||
static token saved_token, prev_token, sent_token;
|
static token saved_token, prev_token, sent_token;
|
||||||
static token empty_token =
|
static token empty_token =
|
||||||
@@ -804,16 +805,19 @@ parse_number (void)
|
|||||||
consume_char ();
|
consume_char ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tok_length = (size_t) (buffer - token_start);;
|
||||||
if (is_fp || is_exp)
|
if (is_fp || is_exp)
|
||||||
{
|
{
|
||||||
ecma_number_t res = __strtof (token_start, NULL);
|
ecma_char_t *temp = mem_heap_alloc_block ((size_t) (tok_length + 1), MEM_HEAP_ALLOC_SHORT_TERM);
|
||||||
|
__strncpy ((char *) temp, token_start, (size_t) (tok_length));
|
||||||
|
temp[tok_length] = '\0';
|
||||||
|
ecma_number_t res = ecma_zt_string_to_number (temp);
|
||||||
|
mem_heap_free_block (temp);
|
||||||
known_token = convert_seen_num_to_token (res);
|
known_token = convert_seen_num_to_token (res);
|
||||||
token_start = NULL;
|
token_start = NULL;
|
||||||
return known_token;
|
return known_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
tok_length = (size_t) (buffer - token_start);;
|
|
||||||
if (*token_start == '0' && tok_length != 1)
|
if (*token_start == '0' && tok_length != 1)
|
||||||
{
|
{
|
||||||
if (parser_strict_mode ())
|
if (parser_strict_mode ())
|
||||||
|
|||||||
+105
-97
@@ -2890,84 +2890,17 @@ parse_with_statement (void)
|
|||||||
STACK_CHECK_USAGE (IDX);
|
STACK_CHECK_USAGE (IDX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* case_clause
|
|
||||||
: 'case' LT!* expression LT!* ':' LT!* statement*
|
|
||||||
; */
|
|
||||||
static void
|
static void
|
||||||
parse_case_clause (void)
|
skip_case_clause_body (void)
|
||||||
{
|
{
|
||||||
STACK_DECLARE_USAGE (IDX)
|
while (!is_keyword (KW_CASE) && !is_keyword (KW_DEFAULT) && !token_is (TOK_CLOSE_BRACE))
|
||||||
|
|
||||||
assert_keyword (KW_CASE);
|
|
||||||
|
|
||||||
skip_newlines ();
|
|
||||||
parse_expression ();
|
|
||||||
token_after_newlines_must_be (TOK_COLON);
|
|
||||||
|
|
||||||
STACK_PUSH (IDX, next_temp_name ());
|
|
||||||
DUMP_OPCODE_3 (equal_value_type, ID (1), ID (2), ID (3));
|
|
||||||
STACK_PUSH (U16, OPCODE_COUNTER ());
|
|
||||||
DUMP_OPCODE_3 (is_false_jmp_down, ID (1), INVALID_VALUE, INVALID_VALUE);
|
|
||||||
STACK_SWAP (IDX);
|
|
||||||
STACK_DROP (IDX, 1);
|
|
||||||
|
|
||||||
skip_newlines ();
|
|
||||||
if (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT))
|
|
||||||
{
|
|
||||||
lexer_save_token (TOK ());
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parse_statement_list ();
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
STACK_CHECK_USAGE_LHS ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
skip_default_clause (void)
|
|
||||||
{
|
|
||||||
assert_keyword (KW_DEFAULT);
|
|
||||||
token_after_newlines_must_be (TOK_COLON);
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
skip_newlines ();
|
skip_newlines ();
|
||||||
if (is_keyword (KW_DEFAULT))
|
|
||||||
{
|
|
||||||
EMIT_ERROR ("Several 'default' clauses in sigle switch");
|
|
||||||
}
|
|
||||||
if (token_is (TOK_OPEN_BRACE))
|
if (token_is (TOK_OPEN_BRACE))
|
||||||
{
|
{
|
||||||
skip_braces ();
|
skip_braces ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!token_is (TOK_CLOSE_BRACE) && !is_keyword (KW_CASE));
|
|
||||||
lexer_save_token (TOK ());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* default_clause
|
|
||||||
: 'default' LT!* ':' LT!* statement*
|
|
||||||
; */
|
|
||||||
static void
|
|
||||||
parse_default_clause (void)
|
|
||||||
{
|
|
||||||
assert_keyword (KW_DEFAULT);
|
|
||||||
token_after_newlines_must_be (TOK_COLON);
|
|
||||||
skip_newlines ();
|
|
||||||
if (is_keyword (KW_CASE))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (is_keyword (KW_DEFAULT))
|
|
||||||
{
|
|
||||||
EMIT_ERROR ("Several 'default' clauses in sigle switch");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parse_statement_list ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* switch_statement
|
/* switch_statement
|
||||||
@@ -2976,7 +2909,10 @@ parse_default_clause (void)
|
|||||||
case_block
|
case_block
|
||||||
: '{' LT!* case_clause* LT!* '}'
|
: '{' LT!* case_clause* LT!* '}'
|
||||||
| '{' LT!* case_clause* LT!* default_clause LT!* case_clause* LT!* '}'
|
| '{' LT!* case_clause* LT!* default_clause LT!* case_clause* LT!* '}'
|
||||||
;*/
|
;
|
||||||
|
case_clause
|
||||||
|
: 'case' LT!* expression LT!* ':' LT!* statement*
|
||||||
|
; */
|
||||||
static void
|
static void
|
||||||
parse_switch_statement (void)
|
parse_switch_statement (void)
|
||||||
{
|
{
|
||||||
@@ -2988,56 +2924,128 @@ parse_switch_statement (void)
|
|||||||
|
|
||||||
assert_keyword (KW_SWITCH);
|
assert_keyword (KW_SWITCH);
|
||||||
|
|
||||||
STACK_PUSH (U8, 0); // was default
|
STACK_PUSH (U8, 0);
|
||||||
|
STACK_PUSH (U8, 0);
|
||||||
|
STACK_PUSH (U8, STACK_SIZE (IDX));
|
||||||
|
STACK_PUSH (U8, STACK_SIZE (U16));
|
||||||
STACK_PUSH (U8, STACK_SIZE (rewritable_break));
|
STACK_PUSH (U8, STACK_SIZE (rewritable_break));
|
||||||
|
|
||||||
parse_expression_inside_parens ();
|
parse_expression_inside_parens ();
|
||||||
token_after_newlines_must_be (TOK_OPEN_BRACE);
|
token_after_newlines_must_be (TOK_OPEN_BRACE);
|
||||||
push_nesting (NESTING_SWITCH);
|
|
||||||
|
#define SWITCH_EXPR() STACK_ELEMENT (IDX, STACK_HEAD (U8, 3))
|
||||||
|
#define CURRENT_JUMP() STACK_HEAD (U8, 4)
|
||||||
|
#define INCR_CURRENT_JUMP() STACK_INCR_HEAD (U8, 4)
|
||||||
|
#define WAS_DEFAULT() STACK_HEAD (U8, 5)
|
||||||
|
#define SET_WAS_DEFAULT(S) STACK_SET_HEAD (U8, 5, S);
|
||||||
|
|
||||||
|
STACK_PUSH (locs, TOK ().loc);
|
||||||
|
// Fisrt, generate table of jumps
|
||||||
skip_newlines ();
|
skip_newlines ();
|
||||||
while (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT))
|
while (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT))
|
||||||
{
|
{
|
||||||
if (is_keyword (KW_CASE))
|
if (is_keyword (KW_CASE))
|
||||||
{
|
{
|
||||||
parse_case_clause ();
|
NEXT (expression);
|
||||||
REWRITE_COND_JMP (STACK_TOP (U16), is_false_jmp_down, OPCODE_COUNTER () - STACK_TOP (U16));
|
next_token_must_be (TOK_COLON);
|
||||||
|
STACK_PUSH (IDX, next_temp_name ());
|
||||||
|
DUMP_OPCODE_3 (equal_value_type, ID (1), ID (2), SWITCH_EXPR ());
|
||||||
|
STACK_SWAP (IDX);
|
||||||
STACK_DROP (IDX, 1);
|
STACK_DROP (IDX, 1);
|
||||||
STACK_DROP (U16, 1);
|
STACK_PUSH (U16, OPCODE_COUNTER ());
|
||||||
|
DUMP_OPCODE_3 (is_true_jmp_down, STACK_TOP (IDX), INVALID_VALUE, INVALID_VALUE);
|
||||||
|
skip_newlines ();
|
||||||
|
skip_case_clause_body ();
|
||||||
}
|
}
|
||||||
else if (is_keyword (KW_DEFAULT))
|
else if (is_keyword (KW_DEFAULT))
|
||||||
{
|
{
|
||||||
STACK_SET_HEAD (U8, 2, 1);
|
SET_WAS_DEFAULT (1);
|
||||||
STACK_PUSH (locs, TOK ().loc);
|
token_after_newlines_must_be (TOK_COLON);
|
||||||
skip_default_clause ();
|
skip_newlines ();
|
||||||
|
skip_case_clause_body ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JERRY_UNREACHABLE ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_token_must_be (TOK_CLOSE_BRACE);
|
||||||
|
|
||||||
|
if (WAS_DEFAULT ())
|
||||||
|
{
|
||||||
|
STACK_PUSH (U16, OPCODE_COUNTER ());
|
||||||
|
DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer_seek (STACK_TOP (locs));
|
||||||
|
next_token_must_be (TOK_OPEN_BRACE);
|
||||||
|
|
||||||
|
push_nesting (NESTING_SWITCH);
|
||||||
|
// Second, parse case clauses' bodies and rewrite jumps
|
||||||
|
skip_newlines ();
|
||||||
|
while (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT))
|
||||||
|
{
|
||||||
|
if (is_keyword (KW_CASE))
|
||||||
|
{
|
||||||
|
while (!token_is (TOK_COLON))
|
||||||
|
{
|
||||||
|
skip_newlines ();
|
||||||
|
}
|
||||||
|
REWRITE_OPCODE_3 (STACK_ELEMENT (U16, STACK_HEAD (U8, 2) + CURRENT_JUMP ()),
|
||||||
|
is_true_jmp_down,
|
||||||
|
STACK_ELEMENT (IDX, STACK_HEAD (U8, 3) + CURRENT_JUMP () + 1),
|
||||||
|
(idx_t) ((OPCODE_COUNTER () - STACK_ELEMENT (
|
||||||
|
U16, STACK_HEAD (U8, 2) + CURRENT_JUMP ())) >> JERRY_BITSINBYTE),
|
||||||
|
(idx_t) ((OPCODE_COUNTER () - STACK_ELEMENT (
|
||||||
|
U16, STACK_HEAD (U8, 2) + CURRENT_JUMP ())) & ((1 << JERRY_BITSINBYTE) - 1)));
|
||||||
|
skip_newlines ();
|
||||||
|
if (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT))
|
||||||
|
{
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
parse_statement_list ();
|
||||||
|
}
|
||||||
|
else if (is_keyword (KW_DEFAULT))
|
||||||
|
{
|
||||||
|
token_after_newlines_must_be (TOK_COLON);
|
||||||
|
skip_newlines ();
|
||||||
|
if (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parse_statement_list ();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JERRY_UNREACHABLE ();
|
JERRY_UNREACHABLE ();
|
||||||
}
|
}
|
||||||
skip_newlines ();
|
skip_newlines ();
|
||||||
}
|
|
||||||
|
|
||||||
// if was default
|
next:
|
||||||
if (STACK_HEAD (U8, 2) == 1)
|
INCR_CURRENT_JUMP ();
|
||||||
{
|
|
||||||
STACK_PUSH (locs, TOK ().loc);
|
|
||||||
lexer_seek (STACK_HEAD (locs, 2));
|
|
||||||
skip_token ();
|
|
||||||
parse_default_clause ();
|
|
||||||
lexer_seek (STACK_TOP (locs));
|
|
||||||
STACK_DROP (locs, 2);
|
|
||||||
skip_token ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!token_is (TOK_CLOSE_BRACE))
|
|
||||||
{
|
|
||||||
EMIT_ERROR ("Expected '}' token");
|
|
||||||
}
|
}
|
||||||
|
current_token_must_be (TOK_CLOSE_BRACE);
|
||||||
|
skip_token ();
|
||||||
pop_nesting (NESTING_SWITCH);
|
pop_nesting (NESTING_SWITCH);
|
||||||
rewrite_rewritable_opcodes (REWRITABLE_BREAK, STACK_TOP (U8), OPCODE_COUNTER ());
|
|
||||||
|
|
||||||
STACK_DROP (IDX, 1);
|
// Finally, dump 'finally' jump
|
||||||
STACK_DROP (U8, 2);
|
if (WAS_DEFAULT ())
|
||||||
|
{
|
||||||
|
REWRITE_JMP (STACK_TOP (U16), jmp_down, OPCODE_COUNTER () - STACK_TOP (U16));
|
||||||
|
}
|
||||||
|
|
||||||
|
rewrite_rewritable_opcodes (REWRITABLE_BREAK, STACK_TOP (U8), OPCODE_COUNTER ());
|
||||||
|
STACK_DROP (U16, STACK_SIZE (U16) - STACK_HEAD (U8, 2));
|
||||||
|
STACK_DROP (IDX, STACK_SIZE (IDX) - STACK_HEAD (U8, 3));
|
||||||
|
STACK_DROP (U8, 5);
|
||||||
|
STACK_DROP (locs, 1);
|
||||||
|
|
||||||
|
#undef WAS_DEFAULT
|
||||||
|
#undef SET_WAS_DEFAULT
|
||||||
|
#undef CURRENT_JUMP
|
||||||
|
#undef INCR_CURRENT_JUMP
|
||||||
|
#undef SWITCH_EXPR
|
||||||
|
|
||||||
STACK_CHECK_USAGE (locs);
|
STACK_CHECK_USAGE (locs);
|
||||||
STACK_CHECK_USAGE (IDX);
|
STACK_CHECK_USAGE (IDX);
|
||||||
|
|||||||
@@ -59,14 +59,14 @@ serializer_dump_opcode (opcode_t opcode)
|
|||||||
{
|
{
|
||||||
JERRY_ASSERT (scopes_tree_opcodes_num (current_scope) < MAX_OPCODES);
|
JERRY_ASSERT (scopes_tree_opcodes_num (current_scope) < MAX_OPCODES);
|
||||||
|
|
||||||
|
scopes_tree_add_opcode (current_scope, opcode);
|
||||||
|
|
||||||
#ifdef JERRY_ENABLE_PP
|
#ifdef JERRY_ENABLE_PP
|
||||||
if (print_opcodes)
|
if (print_opcodes)
|
||||||
{
|
{
|
||||||
pp_opcode (scopes_tree_opcodes_num (current_scope), opcode, false);
|
pp_opcode ((opcode_counter_t) (scopes_tree_opcodes_num (current_scope) - 1), opcode, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
scopes_tree_add_opcode (current_scope, opcode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -284,16 +284,6 @@ __strncpy (char *dest, const char *src, size_t n)
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert the initial portion of the string pointed to by nptr to float representation. */
|
|
||||||
float
|
|
||||||
__strtof (const char *nptr, char **endptr)
|
|
||||||
{
|
|
||||||
(void) nptr;
|
|
||||||
(void) endptr;
|
|
||||||
|
|
||||||
JERRY_UNIMPLEMENTED ();
|
|
||||||
} /* __strtof */
|
|
||||||
|
|
||||||
/** Calculate the length of a string. */
|
/** Calculate the length of a string. */
|
||||||
size_t
|
size_t
|
||||||
__strlen (const char *s)
|
__strlen (const char *s)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ c = a * b;
|
|||||||
assert(c == 210);
|
assert(c == 210);
|
||||||
|
|
||||||
c = a / b;
|
c = a / b;
|
||||||
assert(c == 2.1);
|
assert(c >= 2.1 - 0.000001 && c <= 2.1 + 0.000001);
|
||||||
|
|
||||||
c = a % b;
|
c = a % b;
|
||||||
assert(c == 1);
|
assert(c == 1);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ assert( very_close_to_1_but_greater > 1.0 );
|
|||||||
assert( Math.log (very_close_to_1_but_greater) >= 0.0 );
|
assert( Math.log (very_close_to_1_but_greater) >= 0.0 );
|
||||||
assert( Math.log (very_close_to_1_but_greater) <= 0.000001 );
|
assert( Math.log (very_close_to_1_but_greater) <= 0.000001 );
|
||||||
|
|
||||||
var very_close_to_1_but_less = 0.9999999;
|
var very_close_to_1_but_less = 0.999999;
|
||||||
assert( very_close_to_1_but_less < 1.0 );
|
assert( very_close_to_1_but_less < 1.0 );
|
||||||
|
|
||||||
assert( Math.log (very_close_to_1_but_less) <= 0.0 );
|
assert( Math.log (very_close_to_1_but_less) <= 0.0 );
|
||||||
|
|||||||
@@ -47,3 +47,18 @@ switch (a) {
|
|||||||
case 3:
|
case 3:
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var counter = 0;
|
||||||
|
|
||||||
|
switch ("var") {
|
||||||
|
case "var":
|
||||||
|
counter++;
|
||||||
|
case "var1":
|
||||||
|
counter++;
|
||||||
|
case "var2":
|
||||||
|
counter++;
|
||||||
|
default:
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (counter === 4);
|
||||||
|
|||||||
Reference in New Issue
Block a user