Support labelled statements.
Related issue: #52 JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
@@ -0,0 +1,295 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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 "jsp-label.h"
|
||||
#include "lexer.h"
|
||||
#include "opcodes-dumper.h"
|
||||
|
||||
/** \addtogroup jsparser ECMAScript parser
|
||||
* @{
|
||||
*
|
||||
* \addtogroup labels Jump labels
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stack, containing current label set
|
||||
*/
|
||||
jsp_label_t *label_set_p = NULL;
|
||||
|
||||
/**
|
||||
* Initialize jumps labels mechanism
|
||||
*/
|
||||
void
|
||||
jsp_label_init (void)
|
||||
{
|
||||
JERRY_ASSERT (label_set_p == NULL);
|
||||
} /* jsp_label_init */
|
||||
|
||||
/**
|
||||
* Finalize jumps labels mechanism
|
||||
*/
|
||||
void
|
||||
jsp_label_finalize (void)
|
||||
{
|
||||
JERRY_ASSERT (label_set_p == NULL);
|
||||
} /* jsp_label_finalize */
|
||||
|
||||
/**
|
||||
* Add label to the current label set
|
||||
*/
|
||||
void
|
||||
jsp_label_push (jsp_label_t *out_label_p, /**< out: place where label structure
|
||||
* should be initialized and
|
||||
* linked into label set stack */
|
||||
jsp_label_type_flag_t type_mask, /**< label's type mask */
|
||||
token id) /**< identifier of the label (TOK_NAME)
|
||||
* if mask includes JSP_LABEL_TYPE_NAMED,
|
||||
* or empty token - otherwise */
|
||||
{
|
||||
JERRY_ASSERT (out_label_p != NULL);
|
||||
|
||||
if (type_mask & JSP_LABEL_TYPE_NAMED)
|
||||
{
|
||||
JERRY_ASSERT (id.type == TOK_NAME);
|
||||
|
||||
JERRY_ASSERT (jsp_label_find (JSP_LABEL_TYPE_NAMED, id, NULL) == NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (id.type == TOK_EMPTY);
|
||||
}
|
||||
|
||||
out_label_p->type_mask = type_mask;
|
||||
out_label_p->id = id;
|
||||
out_label_p->continue_tgt_oc = MAX_OPCODES;
|
||||
out_label_p->breaks_list_oc = MAX_OPCODES;
|
||||
out_label_p->breaks_number = 0;
|
||||
out_label_p->continues_list_oc = MAX_OPCODES;
|
||||
out_label_p->continues_number = 0;
|
||||
out_label_p->next_label_p = label_set_p;
|
||||
out_label_p->is_nested_jumpable_border = false;
|
||||
|
||||
label_set_p = out_label_p;
|
||||
} /* jsp_label_push */
|
||||
|
||||
/**
|
||||
* Rewrite jumps to the label, if there any,
|
||||
* and remove it from the current label set
|
||||
*
|
||||
* @return the label should be on top of label set stack
|
||||
*/
|
||||
void
|
||||
jsp_label_rewrite_jumps_and_pop (jsp_label_t *label_p, /**< label to remove (should be on top of stack) */
|
||||
opcode_counter_t break_tgt_oc) /**< target opcode counter
|
||||
* for breaks on the label */
|
||||
{
|
||||
JERRY_ASSERT (label_p != NULL);
|
||||
JERRY_ASSERT (break_tgt_oc != MAX_OPCODES);
|
||||
JERRY_ASSERT (label_set_p == label_p);
|
||||
|
||||
/* Iterating jumps list, rewriting them */
|
||||
while (label_p->breaks_number--)
|
||||
{
|
||||
JERRY_ASSERT (label_p->breaks_list_oc != MAX_OPCODES);
|
||||
|
||||
label_p->breaks_list_oc = rewrite_simple_or_nested_jump_and_get_next (label_p->breaks_list_oc,
|
||||
break_tgt_oc);
|
||||
}
|
||||
while (label_p->continues_number--)
|
||||
{
|
||||
JERRY_ASSERT (label_p->continue_tgt_oc != MAX_OPCODES);
|
||||
JERRY_ASSERT (label_p->continues_list_oc != MAX_OPCODES);
|
||||
|
||||
label_p->continues_list_oc = rewrite_simple_or_nested_jump_and_get_next (label_p->continues_list_oc,
|
||||
label_p->continue_tgt_oc);
|
||||
}
|
||||
|
||||
label_set_p = label_set_p->next_label_p;
|
||||
} /* jsp_label_rewrite_jumps_and_pop */
|
||||
|
||||
/**
|
||||
* Find label with specified identifier
|
||||
*
|
||||
* @return if found, pointer to label descriptor,
|
||||
* otherwise - NULL.
|
||||
*/
|
||||
jsp_label_t*
|
||||
jsp_label_find (jsp_label_type_flag_t type_mask, /**< types to search for */
|
||||
token id, /**< identifier of the label (TOK_NAME)
|
||||
* if mask equals to JSP_LABEL_TYPE_NAMED,
|
||||
* or empty token - otherwise
|
||||
* (if so, mask should not include JSP_LABEL_TYPE_NAMED) */
|
||||
bool *out_is_simply_jumpable_p) /**< out: is the label currently
|
||||
* accessible with a simple jump */
|
||||
{
|
||||
bool is_search_named = (type_mask == JSP_LABEL_TYPE_NAMED);
|
||||
|
||||
if (is_search_named)
|
||||
{
|
||||
JERRY_ASSERT (id.type == TOK_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (!(type_mask & JSP_LABEL_TYPE_NAMED));
|
||||
JERRY_ASSERT (id.type == TOK_EMPTY);
|
||||
}
|
||||
|
||||
bool is_simply_jumpable = true;
|
||||
jsp_label_t *ret_label_p = NULL;
|
||||
|
||||
for (jsp_label_t *label_iter_p = label_set_p;
|
||||
label_iter_p != NULL;
|
||||
label_iter_p = label_iter_p->next_label_p)
|
||||
{
|
||||
if (label_iter_p->is_nested_jumpable_border)
|
||||
{
|
||||
is_simply_jumpable = false;
|
||||
}
|
||||
|
||||
bool is_named_label = (label_iter_p->type_mask & JSP_LABEL_TYPE_NAMED);
|
||||
if ((is_search_named
|
||||
&& is_named_label
|
||||
&& lexer_are_tokens_with_same_identifier (label_iter_p->id, id))
|
||||
|| (!is_search_named
|
||||
&& (type_mask & label_iter_p->type_mask)))
|
||||
{
|
||||
ret_label_p = label_iter_p;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_is_simply_jumpable_p != NULL)
|
||||
{
|
||||
*out_is_simply_jumpable_p = is_simply_jumpable;
|
||||
}
|
||||
|
||||
return ret_label_p;
|
||||
} /* jsp_label_find */
|
||||
|
||||
/**
|
||||
* Dump jump and register it in the specified label to be rewritten later (see also: jsp_label_rewrite_jumps_and_pop)
|
||||
*
|
||||
* Warning:
|
||||
* The dumped instruction should not be modified before it is rewritten, as its idx fields are used
|
||||
* to link jump instructions related to the label into singly linked list.
|
||||
*/
|
||||
void
|
||||
jsp_label_add_jump (jsp_label_t *label_p, /**< label to register jump for */
|
||||
bool is_simply_jumpable, /**< is the label currently
|
||||
* accessible with a simple jump */
|
||||
bool is_break) /**< type of jump - 'break' (true) or 'continue' (false) */
|
||||
{
|
||||
JERRY_ASSERT (label_p != NULL);
|
||||
|
||||
if (is_break)
|
||||
{
|
||||
label_p->breaks_list_oc = dump_simple_or_nested_jump_for_rewrite (is_simply_jumpable,
|
||||
label_p->breaks_list_oc);
|
||||
label_p->breaks_number++;
|
||||
}
|
||||
else
|
||||
{
|
||||
label_p->continues_list_oc = dump_simple_or_nested_jump_for_rewrite (is_simply_jumpable,
|
||||
label_p->continues_list_oc);
|
||||
label_p->continues_number++;
|
||||
}
|
||||
} /* jsp_label_add_jump */
|
||||
|
||||
/**
|
||||
* Setup target for 'continue' jumps,
|
||||
* associated with the labels, from innermost
|
||||
* to the specified label.
|
||||
*/
|
||||
void
|
||||
jsp_label_setup_continue_target (jsp_label_t *outermost_label_p, /**< the outermost label to setup target for */
|
||||
opcode_counter_t tgt_oc) /**< target */
|
||||
{
|
||||
/* There are no labels that could not be targeted with 'break' jumps */
|
||||
JERRY_ASSERT (tgt_oc != MAX_OPCODES);
|
||||
JERRY_ASSERT (outermost_label_p != NULL);
|
||||
|
||||
for (jsp_label_t *label_iter_p = label_set_p;
|
||||
label_iter_p != outermost_label_p->next_label_p;
|
||||
label_iter_p = label_iter_p->next_label_p)
|
||||
{
|
||||
JERRY_ASSERT (label_iter_p != NULL);
|
||||
JERRY_ASSERT (label_iter_p->continue_tgt_oc == MAX_OPCODES);
|
||||
|
||||
label_iter_p->continue_tgt_oc = tgt_oc;
|
||||
}
|
||||
} /* jsp_label_setup_continue_target */
|
||||
|
||||
/**
|
||||
* Mark current label, if any, as nested jumpable border
|
||||
*/
|
||||
void
|
||||
jsp_label_raise_nested_jumpable_border (void)
|
||||
{
|
||||
if (label_set_p != NULL)
|
||||
{
|
||||
JERRY_ASSERT (!label_set_p->is_nested_jumpable_border);
|
||||
label_set_p->is_nested_jumpable_border = true;
|
||||
}
|
||||
} /* jsp_label_raise_nested_jumpable_border */
|
||||
|
||||
/**
|
||||
* Unmark current label, if any, as nested jumpable border
|
||||
*/
|
||||
void
|
||||
jsp_label_remove_nested_jumpable_border (void)
|
||||
{
|
||||
if (label_set_p != NULL)
|
||||
{
|
||||
JERRY_ASSERT (label_set_p->is_nested_jumpable_border);
|
||||
label_set_p->is_nested_jumpable_border = false;
|
||||
}
|
||||
} /* jsp_label_remove_nested_jumpable_border */
|
||||
|
||||
/**
|
||||
* Mask current label set to restore it later, and start new label set
|
||||
*
|
||||
* @return pointer to masked label set's list of labels
|
||||
*/
|
||||
jsp_label_t*
|
||||
jsp_label_mask_set (void)
|
||||
{
|
||||
jsp_label_t *ret_p = label_set_p;
|
||||
|
||||
label_set_p = NULL;
|
||||
|
||||
return ret_p;
|
||||
} /* jsp_label_mask_set */
|
||||
|
||||
/**
|
||||
* Restore previously masked label set
|
||||
*
|
||||
* Note:
|
||||
* current label set should be empty
|
||||
*/
|
||||
void
|
||||
jsp_label_restore_set (jsp_label_t *masked_label_set_list_p) /**< list of labels of
|
||||
* a masked label set */
|
||||
{
|
||||
JERRY_ASSERT (label_set_p == NULL);
|
||||
|
||||
label_set_p = masked_label_set_list_p;
|
||||
} /* jsp_label_restore_set */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
@@ -0,0 +1,89 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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 JSP_LABEL_H
|
||||
#define JSP_LABEL_H
|
||||
|
||||
#include "lexer.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
/** \addtogroup jsparser ECMAScript parser
|
||||
* @{
|
||||
*
|
||||
* \addtogroup labels Jump labels
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Label types
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JSP_LABEL_TYPE_NAMED = (1 << 0), /**< label for breaks and continues with identifiers */
|
||||
JSP_LABEL_TYPE_UNNAMED_BREAKS = (1 << 1), /**< label for breaks without identifiers */
|
||||
JSP_LABEL_TYPE_UNNAMED_CONTINUES = (1 << 2) /**< label for continues without identifiers */
|
||||
} jsp_label_type_flag_t;
|
||||
|
||||
/**
|
||||
* Descriptor of a jump label (See also: ECMA-262 v5, 12.12, Labelled statements)
|
||||
*
|
||||
* Note:
|
||||
* Jump instructions with target identified by some specific label,
|
||||
* are linked into singly-linked list.
|
||||
*
|
||||
* Pointer to a next element of the list is represented with opcode counter.
|
||||
* stored in instructions linked into the list.
|
||||
*
|
||||
*/
|
||||
typedef struct jsp_label_t
|
||||
{
|
||||
jsp_label_type_flag_t type_mask; /**< label type mask */
|
||||
token id; /**< label name (TOK_NAME), if type is LABEL_NAMED */
|
||||
opcode_counter_t continue_tgt_oc; /**< target opcode counter for continues on the label */
|
||||
opcode_counter_t breaks_list_oc; /**< opcode counter of first 'break' instruction in the list
|
||||
* of instructions with the target identified by the label */
|
||||
opcode_counter_t breaks_number; /**< number of 'break' instructions in the list */
|
||||
opcode_counter_t continues_list_oc; /**< opcode counter of first 'continue' instruction in the list
|
||||
* of instructions with the target identified by the label */
|
||||
opcode_counter_t continues_number; /**< number of 'continue' instructions in the list */
|
||||
jsp_label_t *next_label_p; /**< next label in current label set stack */
|
||||
bool is_nested_jumpable_border : 1; /**< flag, indicating that this and outer labels
|
||||
* are not currently accessible with simple jumps,
|
||||
* and so should be targetted with nested jumps only */
|
||||
} jsp_label_t;
|
||||
|
||||
extern void jsp_label_init (void);
|
||||
extern void jsp_label_finalize (void);
|
||||
|
||||
extern void jsp_label_push (jsp_label_t *out_label_p, jsp_label_type_flag_t type_mask, token id);
|
||||
extern void jsp_label_rewrite_jumps_and_pop (jsp_label_t *label_p, opcode_counter_t break_tgt_oc);
|
||||
|
||||
extern jsp_label_t *jsp_label_find (jsp_label_type_flag_t type_mask, token id, bool *out_is_simply_jumpable_p);
|
||||
|
||||
extern void jsp_label_add_jump (jsp_label_t *label_p, bool is_simply_jumpable, bool is_break);
|
||||
extern void jsp_label_setup_continue_target (jsp_label_t *outermost_label_p, opcode_counter_t tgt_oc);
|
||||
|
||||
extern void jsp_label_raise_nested_jumpable_border (void);
|
||||
extern void jsp_label_remove_nested_jumpable_border (void);
|
||||
|
||||
extern jsp_label_t *jsp_label_mask_set (void);
|
||||
extern void jsp_label_restore_set (jsp_label_t *masked_label_set_list_p);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !JSP_LABEL_H */
|
||||
@@ -1596,6 +1596,26 @@ lexer_set_strict_mode (bool is_strict)
|
||||
strict_mode = is_strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the identifier tokens represent the same identifiers
|
||||
*
|
||||
* Note:
|
||||
* As all literals represent unique strings,
|
||||
* it is sufficient to just check if literal indices
|
||||
* in the tokens are equal.
|
||||
*
|
||||
* @return true / false
|
||||
*/
|
||||
bool
|
||||
lexer_are_tokens_with_same_identifier (token id1, /**< identifier token (TOK_NAME) */
|
||||
token id2) /**< identifier token (TOK_NAME) */
|
||||
{
|
||||
JERRY_ASSERT (id1.type == TOK_NAME);
|
||||
JERRY_ASSERT (id2.type == TOK_NAME);
|
||||
|
||||
return (id1.uid == id2.uid);
|
||||
} /* lexer_are_tokens_with_same_identifier */
|
||||
|
||||
void
|
||||
lexer_init (const char *source, size_t source_size, bool show_opcodes)
|
||||
{
|
||||
|
||||
@@ -163,6 +163,11 @@ typedef struct
|
||||
literal_index_t uid;
|
||||
} token;
|
||||
|
||||
/**
|
||||
* Initializer for empty token
|
||||
*/
|
||||
#define TOKEN_EMPTY_INITIALIZER {0, TOK_EMPTY, 0}
|
||||
|
||||
void lexer_init (const char *, size_t, bool);
|
||||
void lexer_free (void);
|
||||
|
||||
@@ -185,4 +190,6 @@ const char *lexer_token_type_to_string (token_type);
|
||||
|
||||
void lexer_set_strict_mode (bool);
|
||||
|
||||
extern bool lexer_are_tokens_with_same_identifier (token id1, token id2);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -76,30 +76,6 @@ enum
|
||||
};
|
||||
STATIC_STACK (prop_getters, op_meta)
|
||||
|
||||
enum
|
||||
{
|
||||
breaks_global_size
|
||||
};
|
||||
STATIC_STACK (breaks, opcode_counter_t)
|
||||
|
||||
enum
|
||||
{
|
||||
break_targets_global_size
|
||||
};
|
||||
STATIC_STACK (break_targets, opcode_counter_t)
|
||||
|
||||
enum
|
||||
{
|
||||
continues_global_size
|
||||
};
|
||||
STATIC_STACK (continues, opcode_counter_t)
|
||||
|
||||
enum
|
||||
{
|
||||
continue_targets_global_size
|
||||
};
|
||||
STATIC_STACK (continue_targets, opcode_counter_t)
|
||||
|
||||
enum
|
||||
{
|
||||
next_iterations_global_size
|
||||
@@ -2079,30 +2055,6 @@ dump_prop_setter_or_bitwise_or_res (operand res, operand op)
|
||||
return dump_prop_setter_or_triple_address_res (dump_bitwise_or, res, op);
|
||||
}
|
||||
|
||||
void
|
||||
start_collecting_breaks (void)
|
||||
{
|
||||
STACK_PUSH (U8, (uint8_t) STACK_SIZE (breaks));
|
||||
}
|
||||
|
||||
void
|
||||
start_collecting_continues (void)
|
||||
{
|
||||
STACK_PUSH (U8, (uint8_t) STACK_SIZE (continues));
|
||||
}
|
||||
|
||||
void
|
||||
dumper_set_break_target (void)
|
||||
{
|
||||
STACK_PUSH (break_targets, serializer_get_current_opcode_counter ());
|
||||
}
|
||||
|
||||
void
|
||||
dumper_set_continue_target (void)
|
||||
{
|
||||
STACK_PUSH (continue_targets, serializer_get_current_opcode_counter ());
|
||||
}
|
||||
|
||||
void
|
||||
dumper_set_next_interation_target (void)
|
||||
{
|
||||
@@ -2143,126 +2095,83 @@ dump_continue_iterations_check (operand op)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump template of 'jmp_break_continue' instruction.
|
||||
* Dump template of 'jmp_break_continue' or 'jmp_down' instruction (depending on is_simple_jump argument).
|
||||
*
|
||||
* Note:
|
||||
* the instruction's flags field is written later (see also: rewrite_breaks, rewrite_continues).
|
||||
* the instruction's flags field is written later (see also: rewrite_simple_or_nested_jump_get_next).
|
||||
*
|
||||
* @return position of dumped instruction
|
||||
*/
|
||||
void
|
||||
dump_break_continue_for_rewrite (bool is_break, /**< flag indicating whether 'break' should be dumped (true)
|
||||
* or 'continue' (false) */
|
||||
bool is_simple_jump) /**< flag indicating, whether simple jump
|
||||
* or 'jmp_break_continue' template should be dumped */
|
||||
opcode_counter_t
|
||||
dump_simple_or_nested_jump_for_rewrite (bool is_simple_jump, /**< flag indicating, whether simple jump
|
||||
* or 'jmp_break_continue' template should be dumped */
|
||||
opcode_counter_t next_jump_for_tgt_oc) /**< opcode counter of next
|
||||
* template targetted to
|
||||
* the same target - if any,
|
||||
* or MAX_OPCODES - otherwise */
|
||||
{
|
||||
if (is_break)
|
||||
{
|
||||
STACK_PUSH (breaks, serializer_get_current_opcode_counter ());
|
||||
}
|
||||
else
|
||||
{
|
||||
STACK_PUSH (continues, serializer_get_current_opcode_counter ());
|
||||
}
|
||||
idx_t id1, id2;
|
||||
split_opcode_counter (next_jump_for_tgt_oc, &id1, &id2);
|
||||
|
||||
opcode_t opcode;
|
||||
if (is_simple_jump)
|
||||
{
|
||||
opcode = getop_jmp_down (INVALID_VALUE, INVALID_VALUE);
|
||||
opcode = getop_jmp_down (id1, id2);
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode = getop_jmp_break_continue (INVALID_VALUE, INVALID_VALUE);
|
||||
opcode = getop_jmp_break_continue (id1, id2);
|
||||
}
|
||||
|
||||
opcode_counter_t ret = serializer_get_current_opcode_counter ();
|
||||
|
||||
serializer_dump_op_meta (create_op_meta_000 (opcode));
|
||||
} /* dump_break_continue_for_rewrite */
|
||||
|
||||
return ret;
|
||||
} /* dump_simple_or_nested_jump_for_rewrite */
|
||||
|
||||
/**
|
||||
* Write jump target positions into previously dumped templates of instructions
|
||||
* for currently processed set of 'break' statements.
|
||||
* Write jump target position into previously dumped template of jump (simple or nested) instruction
|
||||
*
|
||||
* See also:
|
||||
* dump_break_continue_for_rewrite
|
||||
* start_collecting_breaks
|
||||
* @return opcode counter value that was encoded in the jump before rewrite
|
||||
*/
|
||||
void
|
||||
rewrite_breaks (void)
|
||||
opcode_counter_t
|
||||
rewrite_simple_or_nested_jump_and_get_next (opcode_counter_t jump_oc, /**< position of jump to rewrite */
|
||||
opcode_counter_t target_oc) /**< the jump's target */
|
||||
{
|
||||
const opcode_counter_t break_target = STACK_TOP (break_targets);
|
||||
op_meta jump_op_meta = serializer_get_op_meta (jump_oc);
|
||||
|
||||
STACK_ITERATE (breaks, break_oc, STACK_TOP (U8))
|
||||
bool is_simple_jump = (jump_op_meta.op.op_idx == OPCODE (jmp_down));
|
||||
|
||||
JERRY_ASSERT (is_simple_jump
|
||||
|| (jump_op_meta.op.op_idx == OPCODE (jmp_break_continue)));
|
||||
|
||||
idx_t id1, id2, id1_prev, id2_prev;
|
||||
split_opcode_counter ((opcode_counter_t) (target_oc - jump_oc), &id1, &id2);
|
||||
|
||||
if (is_simple_jump)
|
||||
{
|
||||
idx_t id1, id2;
|
||||
split_opcode_counter ((opcode_counter_t) (break_target - break_oc), &id1, &id2);
|
||||
op_meta break_op_meta = serializer_get_op_meta (break_oc);
|
||||
id1_prev = jump_op_meta.op.data.jmp_down.opcode_1;
|
||||
id2_prev = jump_op_meta.op.data.jmp_down.opcode_2;
|
||||
|
||||
bool is_simple_jump = (break_op_meta.op.op_idx == OPCODE (jmp_down));
|
||||
|
||||
if (is_simple_jump)
|
||||
{
|
||||
break_op_meta.op.data.jmp_down.opcode_1 = id1;
|
||||
break_op_meta.op.data.jmp_down.opcode_2 = id2;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (break_op_meta.op.op_idx == OPCODE (jmp_break_continue));
|
||||
|
||||
break_op_meta.op.data.jmp_break_continue.opcode_1 = id1;
|
||||
break_op_meta.op.data.jmp_break_continue.opcode_2 = id2;
|
||||
}
|
||||
|
||||
serializer_rewrite_op_meta (break_oc, break_op_meta);
|
||||
jump_op_meta.op.data.jmp_down.opcode_1 = id1;
|
||||
jump_op_meta.op.data.jmp_down.opcode_2 = id2;
|
||||
}
|
||||
STACK_ITERATE_END ();
|
||||
|
||||
STACK_DROP (break_targets, 1);
|
||||
STACK_DROP (breaks, STACK_SIZE (breaks) - STACK_TOP (U8));
|
||||
STACK_DROP (U8, 1);
|
||||
} /* rewrite_breaks */
|
||||
|
||||
/**
|
||||
* Write jump target positions into previously dumped templates of instructions
|
||||
* for currently processed set of 'continue' statements.
|
||||
*
|
||||
* See also:
|
||||
* dump_break_continue_for_rewrite
|
||||
* start_collecting_continues
|
||||
*/
|
||||
void
|
||||
rewrite_continues (void)
|
||||
{
|
||||
const opcode_counter_t continue_target = STACK_TOP (continue_targets);
|
||||
|
||||
STACK_ITERATE (continues, continue_oc, STACK_TOP (U8))
|
||||
else
|
||||
{
|
||||
idx_t id1, id2;
|
||||
split_opcode_counter ((opcode_counter_t) (continue_target - continue_oc), &id1, &id2);
|
||||
op_meta continue_op_meta = serializer_get_op_meta (continue_oc);
|
||||
JERRY_ASSERT (jump_op_meta.op.op_idx == OPCODE (jmp_break_continue));
|
||||
|
||||
bool is_simple_jump = (continue_op_meta.op.op_idx == OPCODE (jmp_down));
|
||||
id1_prev = jump_op_meta.op.data.jmp_break_continue.opcode_1;
|
||||
id2_prev = jump_op_meta.op.data.jmp_break_continue.opcode_2;
|
||||
|
||||
if (is_simple_jump)
|
||||
{
|
||||
continue_op_meta.op.data.jmp_down.opcode_1 = id1;
|
||||
continue_op_meta.op.data.jmp_down.opcode_2 = id2;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (continue_op_meta.op.op_idx == OPCODE (jmp_break_continue));
|
||||
|
||||
continue_op_meta.op.data.jmp_break_continue.opcode_1 = id1;
|
||||
continue_op_meta.op.data.jmp_break_continue.opcode_2 = id2;
|
||||
}
|
||||
|
||||
serializer_rewrite_op_meta (continue_oc, continue_op_meta);
|
||||
jump_op_meta.op.data.jmp_break_continue.opcode_1 = id1;
|
||||
jump_op_meta.op.data.jmp_break_continue.opcode_2 = id2;
|
||||
}
|
||||
STACK_ITERATE_END ();
|
||||
|
||||
STACK_DROP (continue_targets, 1);
|
||||
STACK_DROP (continues, STACK_SIZE (continues) - STACK_TOP (U8));
|
||||
STACK_DROP (U8, 1);
|
||||
} /* rewrite_continues */
|
||||
serializer_rewrite_op_meta (jump_oc, jump_op_meta);
|
||||
|
||||
return calc_opcode_counter_from_idx_idx (id1_prev, id2_prev);
|
||||
} /* rewrite_simple_or_nested_jump_get_next */
|
||||
|
||||
void
|
||||
start_dumping_case_clauses (void)
|
||||
@@ -2576,10 +2485,6 @@ dumper_init (void)
|
||||
STACK_INIT (conditional_checks);
|
||||
STACK_INIT (jumps_to_end);
|
||||
STACK_INIT (prop_getters);
|
||||
STACK_INIT (breaks);
|
||||
STACK_INIT (continues);
|
||||
STACK_INIT (break_targets);
|
||||
STACK_INIT (continue_targets);
|
||||
STACK_INIT (next_iterations);
|
||||
STACK_INIT (case_clauses);
|
||||
STACK_INIT (catches);
|
||||
@@ -2600,10 +2505,6 @@ dumper_free (void)
|
||||
STACK_FREE (conditional_checks);
|
||||
STACK_FREE (jumps_to_end);
|
||||
STACK_FREE (prop_getters);
|
||||
STACK_FREE (breaks);
|
||||
STACK_FREE (continues);
|
||||
STACK_FREE (break_targets);
|
||||
STACK_FREE (continue_targets);
|
||||
STACK_FREE (next_iterations);
|
||||
STACK_FREE (case_clauses);
|
||||
STACK_FREE (catches);
|
||||
|
||||
@@ -178,14 +178,15 @@ operand dump_prop_setter_or_bitwise_and_res (operand, operand);
|
||||
operand dump_prop_setter_or_bitwise_xor_res (operand, operand);
|
||||
operand dump_prop_setter_or_bitwise_or_res (operand, operand);
|
||||
|
||||
void start_collecting_breaks (void);
|
||||
void start_collecting_continues (void);
|
||||
void dumper_set_break_target (void);
|
||||
void dumper_set_continue_target (void);
|
||||
void dumper_set_next_interation_target (void);
|
||||
void dump_break_continue_for_rewrite (bool is_break, bool is_simple_jump);
|
||||
void rewrite_continues (void);
|
||||
void rewrite_breaks (void);
|
||||
opcode_counter_t
|
||||
dump_simple_or_nested_jump_for_rewrite (bool is_simple_jump,
|
||||
opcode_counter_t next_jump_for_tg_oc);
|
||||
opcode_counter_t
|
||||
rewrite_simple_or_nested_jump_and_get_next (opcode_counter_t jump_oc,
|
||||
opcode_counter_t target_oc);
|
||||
void dump_continue_iterations_check (operand);
|
||||
|
||||
void start_dumping_case_clauses (void);
|
||||
|
||||
+168
-146
@@ -16,6 +16,7 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "jrt-libc-includes.h"
|
||||
#include "jsp-label.h"
|
||||
#include "parser.h"
|
||||
#include "opcodes.h"
|
||||
#include "serializer.h"
|
||||
@@ -82,7 +83,7 @@ STATIC_STACK (scopes, scopes_tree)
|
||||
#define OPCODE_IS(OP, ID) (OP.op_idx == __op__idx_##ID)
|
||||
|
||||
static operand parse_expression (bool);
|
||||
static void parse_statement (void);
|
||||
static void parse_statement (jsp_label_t *outermost_stmt_label_p);
|
||||
static operand parse_assignment_expression (bool);
|
||||
static void parse_source_element_list (bool);
|
||||
static operand parse_argument_list (varg_list_type, operand, uint8_t *, operand *);
|
||||
@@ -109,45 +110,6 @@ pop_nesting (nesting_t nesting_type) /**< type of current nesting */
|
||||
STACK_DROP (nestings, 1);
|
||||
} /* pop_nesting */
|
||||
|
||||
/**
|
||||
* Check that current nesting chain contains one of the specified 'inside' nesting types,
|
||||
* and there is no 'not_in' nesting between current nesting and the 'inside' nesting type
|
||||
* in the chain.
|
||||
*/
|
||||
static void
|
||||
must_be_inside_but_not_in (uint8_t not_in, /**< 'not_in' nesting type */
|
||||
uint8_t insides_count, /**< 'inside' nestings number */
|
||||
...) /**< 'inside' nestings list */
|
||||
{
|
||||
JERRY_ASSERT (STACK_SIZE (nestings) != 0);
|
||||
|
||||
va_list insides_list;
|
||||
va_start (insides_list, insides_count);
|
||||
uint8_t *insides = (uint8_t*) mem_heap_alloc_block (insides_count, MEM_HEAP_ALLOC_SHORT_TERM);
|
||||
for (uint8_t i = 0; i < insides_count; i++)
|
||||
{
|
||||
insides[i] = (uint8_t) va_arg (insides_list, int);
|
||||
}
|
||||
va_end (insides_list);
|
||||
|
||||
for (uint8_t i = (uint8_t) STACK_SIZE (nestings); i != 0; i--)
|
||||
{
|
||||
for (uint8_t j = 0; j < insides_count; j++)
|
||||
{
|
||||
if (insides[j] == STACK_ELEMENT (nestings, i - 1))
|
||||
{
|
||||
mem_heap_free_block (insides);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (STACK_ELEMENT (nestings, i - 1) == not_in)
|
||||
{
|
||||
EMIT_ERROR_VARG ("Shall not be inside a '%s' nesting", NESTING_TO_STRING (not_in));
|
||||
}
|
||||
}
|
||||
EMIT_ERROR ("Shall be inside a nesting");
|
||||
} /* must_be_inside_but_not_in */
|
||||
|
||||
static bool
|
||||
token_is (token_type tt)
|
||||
{
|
||||
@@ -344,9 +306,15 @@ parse_property_assignment (void)
|
||||
|
||||
token_after_newlines_must_be (TOK_OPEN_BRACE);
|
||||
skip_newlines ();
|
||||
|
||||
jsp_label_t *masked_label_set_p = jsp_label_mask_set ();
|
||||
|
||||
push_nesting (NESTING_FUNCTION);
|
||||
parse_source_element_list (false);
|
||||
pop_nesting (NESTING_FUNCTION);
|
||||
|
||||
jsp_label_restore_set (masked_label_set_p);
|
||||
|
||||
token_after_newlines_must_be (TOK_CLOSE_BRACE);
|
||||
|
||||
scopes_tree_set_strict_mode (STACK_TOP (scopes), is_strict);
|
||||
@@ -545,6 +513,8 @@ parse_function_declaration (void)
|
||||
|
||||
assert_keyword (KW_FUNCTION);
|
||||
|
||||
jsp_label_t *masked_label_set_p = jsp_label_mask_set ();
|
||||
|
||||
token_after_newlines_must_be (TOK_NAME);
|
||||
const operand name = literal_operand (token_data ());
|
||||
|
||||
@@ -560,6 +530,7 @@ parse_function_declaration (void)
|
||||
token_after_newlines_must_be (TOK_OPEN_BRACE);
|
||||
|
||||
skip_newlines ();
|
||||
|
||||
push_nesting (NESTING_FUNCTION);
|
||||
parse_source_element_list (false);
|
||||
pop_nesting (NESTING_FUNCTION);
|
||||
@@ -573,6 +544,8 @@ parse_function_declaration (void)
|
||||
serializer_set_scope (STACK_TOP (scopes));
|
||||
lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes)));
|
||||
|
||||
jsp_label_restore_set (masked_label_set_p);
|
||||
|
||||
STACK_CHECK_USAGE (scopes);
|
||||
STACK_CHECK_USAGE (nestings);
|
||||
}
|
||||
@@ -607,9 +580,16 @@ parse_function_expression (void)
|
||||
|
||||
token_after_newlines_must_be (TOK_OPEN_BRACE);
|
||||
skip_newlines ();
|
||||
|
||||
jsp_label_t *masked_label_set_p = jsp_label_mask_set ();
|
||||
|
||||
push_nesting (NESTING_FUNCTION);
|
||||
parse_source_element_list (false);
|
||||
pop_nesting (NESTING_FUNCTION);
|
||||
|
||||
jsp_label_restore_set (masked_label_set_p);
|
||||
|
||||
|
||||
next_token_must_be (TOK_CLOSE_BRACE);
|
||||
|
||||
dump_ret ();
|
||||
@@ -1693,27 +1673,10 @@ parse_variable_declaration_list (bool *several_decls)
|
||||
}
|
||||
|
||||
static void
|
||||
parse_plain_for (void)
|
||||
parse_plain_for (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
|
||||
* the statement (or NULL, if there are no named
|
||||
* labels associated with the statement) */
|
||||
{
|
||||
/* Represent loop like
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
body;
|
||||
}
|
||||
|
||||
as
|
||||
|
||||
assign i, 0
|
||||
jmp_down %cond
|
||||
%body
|
||||
body
|
||||
post_incr i
|
||||
%cond
|
||||
less_than i, 10
|
||||
is_true_jmp_up %body
|
||||
|
||||
*/
|
||||
|
||||
dump_jump_to_end_for_rewrite ();
|
||||
|
||||
// Skip till body
|
||||
@@ -1731,19 +1694,18 @@ parse_plain_for (void)
|
||||
skip_newlines ();
|
||||
}
|
||||
|
||||
start_collecting_continues ();
|
||||
start_collecting_breaks ();
|
||||
dumper_set_next_interation_target ();
|
||||
|
||||
// Parse body
|
||||
skip_newlines ();
|
||||
push_nesting (NESTING_ITERATIONAL);
|
||||
parse_statement ();
|
||||
parse_statement (NULL);
|
||||
pop_nesting (NESTING_ITERATIONAL);
|
||||
|
||||
const locus end_loc = tok.loc;
|
||||
|
||||
dumper_set_continue_target ();
|
||||
jsp_label_setup_continue_target (outermost_stmt_label_p,
|
||||
serializer_get_current_opcode_counter ());
|
||||
|
||||
lexer_seek (incr_loc);
|
||||
skip_token ();
|
||||
@@ -1766,10 +1728,6 @@ parse_plain_for (void)
|
||||
dump_continue_iterations_check (cond);
|
||||
}
|
||||
|
||||
dumper_set_break_target ();
|
||||
rewrite_breaks ();
|
||||
rewrite_continues ();
|
||||
|
||||
lexer_seek (end_loc);
|
||||
skip_token ();
|
||||
if (tok.type != TOK_CLOSE_BRACE)
|
||||
@@ -1779,8 +1737,12 @@ parse_plain_for (void)
|
||||
}
|
||||
|
||||
static void
|
||||
parse_for_in (void)
|
||||
parse_for_in (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
|
||||
* the statement (or NULL, if there are no named
|
||||
* labels associated with the statement) */
|
||||
{
|
||||
(void) outermost_stmt_label_p;
|
||||
|
||||
EMIT_SORRY ("'for in' loops are not supported yet");
|
||||
}
|
||||
|
||||
@@ -1805,7 +1767,9 @@ parse_for_in (void)
|
||||
;*/
|
||||
|
||||
static void
|
||||
parse_for_or_for_in_statement (void)
|
||||
parse_for_or_for_in_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
|
||||
* the statement (or NULL, if there are no named
|
||||
* labels associated with the statement) */
|
||||
{
|
||||
assert_keyword (KW_FOR);
|
||||
token_after_newlines_must_be (TOK_OPEN_PAREN);
|
||||
@@ -1813,7 +1777,7 @@ parse_for_or_for_in_statement (void)
|
||||
skip_newlines ();
|
||||
if (token_is (TOK_SEMICOLON))
|
||||
{
|
||||
parse_plain_for ();
|
||||
parse_plain_for (outermost_stmt_label_p);
|
||||
return;
|
||||
}
|
||||
/* Both for_statement_initialiser_part and for_in_statement_initialiser_part
|
||||
@@ -1826,7 +1790,7 @@ parse_for_or_for_in_statement (void)
|
||||
if (several_decls)
|
||||
{
|
||||
token_after_newlines_must_be (TOK_SEMICOLON);
|
||||
parse_plain_for ();
|
||||
parse_plain_for (outermost_stmt_label_p);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -1834,12 +1798,12 @@ parse_for_or_for_in_statement (void)
|
||||
skip_newlines ();
|
||||
if (token_is (TOK_SEMICOLON))
|
||||
{
|
||||
parse_plain_for ();
|
||||
parse_plain_for (outermost_stmt_label_p);
|
||||
return;
|
||||
}
|
||||
else if (is_keyword (KW_IN))
|
||||
{
|
||||
parse_for_in ();
|
||||
parse_for_in (outermost_stmt_label_p);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -1855,12 +1819,12 @@ parse_for_or_for_in_statement (void)
|
||||
skip_newlines ();
|
||||
if (token_is (TOK_SEMICOLON))
|
||||
{
|
||||
parse_plain_for ();
|
||||
parse_plain_for (outermost_stmt_label_p);
|
||||
return;
|
||||
}
|
||||
else if (is_keyword (KW_IN))
|
||||
{
|
||||
parse_for_in ();
|
||||
parse_for_in (outermost_stmt_label_p);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -1887,7 +1851,7 @@ parse_statement_list (void)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
parse_statement ();
|
||||
parse_statement (NULL);
|
||||
|
||||
skip_newlines ();
|
||||
while (token_is (TOK_SEMICOLON))
|
||||
@@ -1919,7 +1883,7 @@ parse_if_statement (void)
|
||||
dump_conditional_check_for_rewrite (cond);
|
||||
|
||||
skip_newlines ();
|
||||
parse_statement ();
|
||||
parse_statement (NULL);
|
||||
|
||||
skip_newlines ();
|
||||
if (is_keyword (KW_ELSE))
|
||||
@@ -1928,7 +1892,7 @@ parse_if_statement (void)
|
||||
rewrite_conditional_check ();
|
||||
|
||||
skip_newlines ();
|
||||
parse_statement ();
|
||||
parse_statement (NULL);
|
||||
|
||||
rewrite_jump_to_end ();
|
||||
}
|
||||
@@ -1943,37 +1907,34 @@ parse_if_statement (void)
|
||||
: 'do' LT!* statement LT!* 'while' LT!* '(' expression ')' (LT | ';')!
|
||||
; */
|
||||
static void
|
||||
parse_do_while_statement (void)
|
||||
parse_do_while_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
|
||||
* the statement (or NULL, if there are no named
|
||||
* labels associated with the statement) */
|
||||
{
|
||||
assert_keyword (KW_DO);
|
||||
|
||||
start_collecting_continues ();
|
||||
start_collecting_breaks ();
|
||||
|
||||
dumper_set_next_interation_target ();
|
||||
|
||||
skip_newlines ();
|
||||
push_nesting (NESTING_ITERATIONAL);
|
||||
parse_statement ();
|
||||
parse_statement (NULL);
|
||||
pop_nesting (NESTING_ITERATIONAL);
|
||||
|
||||
dumper_set_continue_target ();
|
||||
jsp_label_setup_continue_target (outermost_stmt_label_p,
|
||||
serializer_get_current_opcode_counter ());
|
||||
|
||||
token_after_newlines_must_be_keyword (KW_WHILE);
|
||||
const operand cond = parse_expression_inside_parens ();
|
||||
dump_continue_iterations_check (cond);
|
||||
|
||||
dumper_set_break_target ();
|
||||
|
||||
rewrite_breaks ();
|
||||
rewrite_continues ();
|
||||
}
|
||||
|
||||
/* while_statement
|
||||
: 'while' LT!* '(' LT!* expression LT!* ')' LT!* statement
|
||||
; */
|
||||
static void
|
||||
parse_while_statement (void)
|
||||
parse_while_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
|
||||
* the statement (or NULL, if there are no named
|
||||
* labels associated with the statement) */
|
||||
{
|
||||
assert_keyword (KW_WHILE);
|
||||
|
||||
@@ -1985,15 +1946,13 @@ parse_while_statement (void)
|
||||
|
||||
dumper_set_next_interation_target ();
|
||||
|
||||
start_collecting_continues ();
|
||||
start_collecting_breaks ();
|
||||
|
||||
skip_newlines ();
|
||||
push_nesting (NESTING_ITERATIONAL);
|
||||
parse_statement ();
|
||||
parse_statement (NULL);
|
||||
pop_nesting (NESTING_ITERATIONAL);
|
||||
|
||||
dumper_set_continue_target ();
|
||||
jsp_label_setup_continue_target (outermost_stmt_label_p,
|
||||
serializer_get_current_opcode_counter ());
|
||||
|
||||
rewrite_jump_to_end ();
|
||||
|
||||
@@ -2002,11 +1961,6 @@ parse_while_statement (void)
|
||||
const operand cond = parse_expression_inside_parens ();
|
||||
dump_continue_iterations_check (cond);
|
||||
|
||||
dumper_set_break_target ();
|
||||
|
||||
rewrite_breaks ();
|
||||
rewrite_continues ();
|
||||
|
||||
lexer_seek (end_loc);
|
||||
skip_token ();
|
||||
}
|
||||
@@ -2024,15 +1978,17 @@ parse_with_statement (void)
|
||||
}
|
||||
const operand expr = parse_expression_inside_parens ();
|
||||
|
||||
jsp_label_raise_nested_jumpable_border ();
|
||||
push_nesting (NESTING_WITH);
|
||||
|
||||
opcode_counter_t with_begin_oc = dump_with_for_rewrite (expr);
|
||||
skip_newlines ();
|
||||
parse_statement ();
|
||||
parse_statement (NULL);
|
||||
rewrite_with (with_begin_oc);
|
||||
dump_with_end ();
|
||||
|
||||
pop_nesting (NESTING_WITH);
|
||||
jsp_label_remove_nested_jumpable_border ();
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2106,7 +2062,11 @@ parse_switch_statement (void)
|
||||
lexer_seek (start_loc);
|
||||
next_token_must_be (TOK_OPEN_BRACE);
|
||||
|
||||
start_collecting_breaks ();
|
||||
jsp_label_t label;
|
||||
jsp_label_push (&label,
|
||||
JSP_LABEL_TYPE_UNNAMED_BREAKS,
|
||||
TOKEN_EMPTY_INITIALIZER);
|
||||
|
||||
push_nesting (NESTING_SWITCH);
|
||||
// Second, parse case clauses' bodies and rewrite jumps
|
||||
skip_newlines ();
|
||||
@@ -2144,8 +2104,9 @@ parse_switch_statement (void)
|
||||
skip_token ();
|
||||
pop_nesting (NESTING_SWITCH);
|
||||
|
||||
dumper_set_break_target ();
|
||||
rewrite_breaks ();
|
||||
jsp_label_rewrite_jumps_and_pop (&label,
|
||||
serializer_get_current_opcode_counter ());
|
||||
|
||||
finish_dumping_case_clauses ();
|
||||
}
|
||||
|
||||
@@ -2199,6 +2160,7 @@ parse_try_statement (void)
|
||||
{
|
||||
assert_keyword (KW_TRY);
|
||||
|
||||
jsp_label_raise_nested_jumpable_border ();
|
||||
push_nesting (NESTING_TRY);
|
||||
|
||||
dump_try_for_rewrite ();
|
||||
@@ -2237,6 +2199,7 @@ parse_try_statement (void)
|
||||
dump_end_try_catch_finally ();
|
||||
|
||||
pop_nesting (NESTING_TRY);
|
||||
jsp_label_remove_nested_jumpable_border ();
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2260,6 +2223,45 @@ insert_semicolon (void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iteration_statement
|
||||
* : do_while_statement
|
||||
* | while_statement
|
||||
* | for_statement
|
||||
* | for_in_statement
|
||||
* ;
|
||||
*/
|
||||
static void
|
||||
parse_iterational_statement (jsp_label_t *outermost_named_stmt_label_p) /**< outermost (first) named label,
|
||||
* corresponding to the statement
|
||||
* (or NULL, if there are no named
|
||||
* labels associated with the statement) */
|
||||
{
|
||||
jsp_label_t label;
|
||||
jsp_label_push (&label,
|
||||
(jsp_label_type_flag_t) (JSP_LABEL_TYPE_UNNAMED_BREAKS | JSP_LABEL_TYPE_UNNAMED_CONTINUES),
|
||||
TOKEN_EMPTY_INITIALIZER);
|
||||
|
||||
jsp_label_t *outermost_stmt_label_p = (outermost_named_stmt_label_p != NULL ? outermost_named_stmt_label_p : &label);
|
||||
|
||||
if (is_keyword (KW_DO))
|
||||
{
|
||||
parse_do_while_statement (outermost_stmt_label_p);
|
||||
}
|
||||
else if (is_keyword (KW_WHILE))
|
||||
{
|
||||
parse_while_statement (outermost_stmt_label_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (is_keyword (KW_FOR));
|
||||
parse_for_or_for_in_statement (outermost_stmt_label_p);
|
||||
}
|
||||
|
||||
jsp_label_rewrite_jumps_and_pop (&label,
|
||||
serializer_get_current_opcode_counter ());
|
||||
} /* parse_iterational_statement */
|
||||
|
||||
/* statement
|
||||
: statement_block
|
||||
| variable_statement
|
||||
@@ -2324,7 +2326,9 @@ insert_semicolon (void)
|
||||
: 'try' LT!* '{' LT!* statement_list LT!* '}' LT!* (finally_clause | catch_clause (LT!* finally_clause)?)
|
||||
;*/
|
||||
static void
|
||||
parse_statement (void)
|
||||
parse_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to the statement
|
||||
* (or NULL, if there are no named labels associated
|
||||
* with the statement) */
|
||||
{
|
||||
dumper_new_statement ();
|
||||
|
||||
@@ -2367,19 +2371,11 @@ parse_statement (void)
|
||||
parse_if_statement ();
|
||||
return;
|
||||
}
|
||||
if (is_keyword (KW_DO))
|
||||
if (is_keyword (KW_DO)
|
||||
|| is_keyword (KW_WHILE)
|
||||
|| is_keyword (KW_FOR))
|
||||
{
|
||||
parse_do_while_statement ();
|
||||
return;
|
||||
}
|
||||
if (is_keyword (KW_WHILE))
|
||||
{
|
||||
parse_while_statement ();
|
||||
return;
|
||||
}
|
||||
if (is_keyword (KW_FOR))
|
||||
{
|
||||
parse_for_or_for_in_statement ();
|
||||
parse_iterational_statement (outermost_stmt_label_p);
|
||||
return;
|
||||
}
|
||||
if (is_keyword (KW_CONTINUE)
|
||||
@@ -2392,39 +2388,48 @@ parse_statement (void)
|
||||
EMIT_ERROR ("Shall be inside a nesting");
|
||||
}
|
||||
|
||||
nesting_t topmost_nesting = STACK_ELEMENT (nestings, STACK_SIZE (nestings) - 1);
|
||||
skip_token ();
|
||||
|
||||
if (is_break)
|
||||
jsp_label_t *label_p;
|
||||
bool is_simply_jumpable = true;
|
||||
if (token_is (TOK_NAME))
|
||||
{
|
||||
must_be_inside_but_not_in (NESTING_FUNCTION,
|
||||
4,
|
||||
NESTING_ITERATIONAL,
|
||||
NESTING_SWITCH,
|
||||
NESTING_TRY,
|
||||
NESTING_WITH);
|
||||
/* break or continue on a label */
|
||||
label_p = jsp_label_find (JSP_LABEL_TYPE_NAMED, tok, &is_simply_jumpable);
|
||||
|
||||
if (label_p == NULL)
|
||||
{
|
||||
EMIT_ERROR ("Label not found");
|
||||
}
|
||||
}
|
||||
else if (is_break)
|
||||
{
|
||||
label_p = jsp_label_find (JSP_LABEL_TYPE_UNNAMED_BREAKS,
|
||||
TOKEN_EMPTY_INITIALIZER,
|
||||
&is_simply_jumpable);
|
||||
|
||||
if (label_p == NULL)
|
||||
{
|
||||
EMIT_ERROR ("No corresponding statement for the break");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
must_be_inside_but_not_in (NESTING_FUNCTION,
|
||||
3,
|
||||
NESTING_ITERATIONAL,
|
||||
NESTING_TRY,
|
||||
NESTING_WITH);
|
||||
JERRY_ASSERT (!is_break);
|
||||
|
||||
label_p = jsp_label_find (JSP_LABEL_TYPE_UNNAMED_CONTINUES,
|
||||
TOKEN_EMPTY_INITIALIZER,
|
||||
&is_simply_jumpable);
|
||||
|
||||
if (label_p == NULL)
|
||||
{
|
||||
EMIT_ERROR ("No corresponding statement for the continue");
|
||||
}
|
||||
}
|
||||
|
||||
if (topmost_nesting == NESTING_ITERATIONAL
|
||||
|| (topmost_nesting == NESTING_SWITCH && is_break))
|
||||
{
|
||||
dump_break_continue_for_rewrite (is_break, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (topmost_nesting == NESTING_TRY
|
||||
|| topmost_nesting == NESTING_WITH
|
||||
|| (topmost_nesting == NESTING_SWITCH && !is_break));
|
||||
JERRY_ASSERT (label_p != NULL);
|
||||
|
||||
dump_break_continue_for_rewrite (is_break, false);
|
||||
}
|
||||
jsp_label_add_jump (label_p, is_simply_jumpable, is_break);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -2473,8 +2478,21 @@ parse_statement (void)
|
||||
skip_newlines ();
|
||||
if (token_is (TOK_COLON))
|
||||
{
|
||||
// STMT_LABELLED;
|
||||
EMIT_SORRY ("Labelled statements are not supported yet");
|
||||
skip_newlines ();
|
||||
|
||||
jsp_label_t *label_p = jsp_label_find (JSP_LABEL_TYPE_NAMED, temp, NULL);
|
||||
if (label_p != NULL)
|
||||
{
|
||||
EMIT_ERROR ("Label is duplicated");
|
||||
}
|
||||
|
||||
jsp_label_t label;
|
||||
jsp_label_push (&label, JSP_LABEL_TYPE_NAMED, temp);
|
||||
|
||||
parse_statement (outermost_stmt_label_p != NULL ? outermost_stmt_label_p : &label);
|
||||
|
||||
jsp_label_rewrite_jumps_and_pop (&label,
|
||||
serializer_get_current_opcode_counter ());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2514,7 +2532,7 @@ parse_source_element (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
parse_statement ();
|
||||
parse_statement (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2866,11 +2884,15 @@ parser_init (const char *source, size_t source_size, bool show_opcodes)
|
||||
|
||||
STACK_INIT (nestings);
|
||||
STACK_INIT (scopes);
|
||||
|
||||
jsp_label_init ();
|
||||
}
|
||||
|
||||
void
|
||||
parser_free (void)
|
||||
{
|
||||
jsp_label_finalize ();
|
||||
|
||||
STACK_FREE (nestings);
|
||||
STACK_FREE (scopes);
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
a: for (var i = 0; i < 10; i++)
|
||||
{
|
||||
function f ()
|
||||
{
|
||||
for (var j = 0; n < 10; j++)
|
||||
{
|
||||
break a;
|
||||
}
|
||||
}
|
||||
|
||||
f ();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
a: a: for (var i = 0; i < 10; i++)
|
||||
{
|
||||
break a;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
//
|
||||
// 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 (var i = 0; i < 10; i++)
|
||||
{
|
||||
break a;
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
// Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
/* 1 */
|
||||
|
||||
a: a = 1;
|
||||
|
||||
str = '';
|
||||
|
||||
a: for (j = 0; j < 10; j++)
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
b: for (i = 0; i < 10; i++)
|
||||
{
|
||||
str += 'B';
|
||||
|
||||
break a;
|
||||
|
||||
str += 'C';
|
||||
}
|
||||
|
||||
str += 'D';
|
||||
}
|
||||
|
||||
assert (str === 'AB');
|
||||
|
||||
/* 2 */
|
||||
str = '';
|
||||
|
||||
a: for (j = 0; j < 5; j++)
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
b: for (i = 0; i < 5; i++)
|
||||
{
|
||||
str += 'B';
|
||||
|
||||
switch (1)
|
||||
{
|
||||
case 1:
|
||||
continue b;
|
||||
default:
|
||||
break b;
|
||||
}
|
||||
|
||||
str += 'C';
|
||||
}
|
||||
|
||||
str += 'D';
|
||||
}
|
||||
|
||||
assert (str === 'ABBBBBDABBBBBDABBBBBDABBBBBDABBBBBD');
|
||||
|
||||
/* 3 */
|
||||
str = '';
|
||||
|
||||
a: for (j = 0; j < 5; j++)
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
b: for (i = 0; i < 5; i++)
|
||||
{
|
||||
str += 'B';
|
||||
|
||||
switch (1)
|
||||
{
|
||||
case 1:
|
||||
continue a;
|
||||
}
|
||||
|
||||
str += 'C';
|
||||
}
|
||||
|
||||
str += 'D';
|
||||
}
|
||||
|
||||
assert (str === 'ABABABABAB');
|
||||
|
||||
/* 4 */
|
||||
str = '';
|
||||
|
||||
a: for (j = 0; j < 5; j++)
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
b: for (i = 0; i < 5; i++)
|
||||
{
|
||||
str += 'B';
|
||||
|
||||
switch (1)
|
||||
{
|
||||
case 1:
|
||||
break b;
|
||||
}
|
||||
|
||||
str += 'C';
|
||||
}
|
||||
|
||||
str += 'D';
|
||||
}
|
||||
|
||||
assert (str === 'ABDABDABDABDABD');
|
||||
|
||||
/* 5 */
|
||||
str = '';
|
||||
|
||||
a: for (j = 0; j < 5; j++)
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
b: for (i = 0; i < 5; i++)
|
||||
{
|
||||
str += 'B';
|
||||
|
||||
switch (1)
|
||||
{
|
||||
case 1:
|
||||
break a;
|
||||
}
|
||||
|
||||
str += 'C';
|
||||
}
|
||||
|
||||
str += 'D';
|
||||
}
|
||||
|
||||
assert (str === 'AB');
|
||||
|
||||
|
||||
/* 6 */
|
||||
str = '';
|
||||
|
||||
a: for (j = 0; j < 5; j++)
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
b: for (i = 0; i < 5; i++)
|
||||
{
|
||||
str += 'B';
|
||||
|
||||
with ({})
|
||||
{
|
||||
break b;
|
||||
}
|
||||
|
||||
str += 'C';
|
||||
}
|
||||
|
||||
str += 'D';
|
||||
}
|
||||
|
||||
assert (str === 'ABDABDABDABDABD');
|
||||
|
||||
/* 7 */
|
||||
str = '';
|
||||
|
||||
a: for (j = 0; j < 5; j++)
|
||||
{
|
||||
c:
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
b: for (i = 0; i < 5; i++)
|
||||
{
|
||||
str += 'B';
|
||||
|
||||
with ({})
|
||||
{
|
||||
break c;
|
||||
}
|
||||
|
||||
str += 'C';
|
||||
}
|
||||
|
||||
str += 'D';
|
||||
}
|
||||
}
|
||||
|
||||
assert (str === 'ABABABABAB');
|
||||
|
||||
/* 8 */
|
||||
|
||||
a: {
|
||||
function f ()
|
||||
{
|
||||
str = '';
|
||||
|
||||
a: for (i = 0; i < 5; i++)
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
str += 'B';
|
||||
|
||||
continue a;
|
||||
|
||||
str += 'C';
|
||||
}
|
||||
str += 'D';
|
||||
}
|
||||
|
||||
assert (str === 'ABABABABAB');
|
||||
}
|
||||
}
|
||||
|
||||
f ();
|
||||
|
||||
/* 9 */
|
||||
|
||||
str = '';
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
str += 'A';
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
str += '0';
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
str += '1';
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
str += '2';
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
str += '3';
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
str += '4';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
str += 'B';
|
||||
}
|
||||
|
||||
assert (str === 'A0BA1BA2BA3BA4B');
|
||||
|
||||
/* 10 */
|
||||
|
||||
str = '';
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
str += '[A]';
|
||||
|
||||
a:
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
str += '[B]';
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
str += '[0]';
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
str += '[1]';
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
str += '[1.1]';
|
||||
break a;
|
||||
}
|
||||
else
|
||||
{
|
||||
str += '[1.2]';
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
str += '[2]';
|
||||
continue a;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
str += '[3]';
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
str += '[4]';
|
||||
continue a;
|
||||
}
|
||||
}
|
||||
|
||||
str += '[C]';
|
||||
}
|
||||
|
||||
str += '[D]';
|
||||
}
|
||||
|
||||
assert (str === '[A][B][0][C][B][1][1.1][D]' +
|
||||
'[A][B][0][C][B][1][1.2][2][B][2][B][3][C][B][4][D]');
|
||||
Reference in New Issue
Block a user