Add SyntaxErrors on parsing ObjectDeclarations.

This commit is contained in:
Ilmir Usmanov
2014-10-28 13:38:13 +04:00
parent fc751b0f15
commit 4735570b31
7 changed files with 253 additions and 92 deletions
+1 -1
View File
@@ -21,7 +21,7 @@
/* Length-prefixed or "pascal" string. */
typedef struct
{
ecma_char_t *str;
const ecma_char_t *str;
ecma_length_t length;
}
lp_string;
+5
View File
@@ -218,6 +218,11 @@ do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT(NAME,
#define STACK_DECR_ELEMENT(NAME, I) \
do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT(NAME, I) - 1)); } while (0)
#define STACK_ITERATE(NAME, FUNC, FROM) \
do { for (NAME##_stack_data_type i = FROM; i < NAME.current; i++) { \
FUNC (STACK_ELEMENT (NAME, i)); \
} } while (0)
#define STACK_ITERATE_VARG(NAME, FUNC, FROM, ...) \
do { for (NAME##_stack_data_type i = FROM; i < NAME.current; i++) { \
FUNC (STACK_ELEMENT (NAME, i), __VA_ARGS__); \
+2 -1
View File
@@ -177,7 +177,7 @@ add_current_token_to_string_cache (void)
}
__strncpy ((char *) (strings_cache + strings_cache_used_size), token_start, res.length);
res.str = strings_cache + strings_cache_used_size;
res.str[res.length] = '\0';
(strings_cache + strings_cache_used_size)[res.length] = '\0';
strings_cache_used_size = (size_t) (((size_t) res.length + 1) * sizeof (ecma_char_t) + strings_cache_used_size);
return res;
}
@@ -788,6 +788,7 @@ parse_number (void)
c = LA (0);
if (is_fp && c == '.')
{
FIXME (/* This is wrong: 1..toString (). */)
PARSE_ERROR ("Integer literal shall not contain more than one dot character", buffer - buffer_start);
}
if (is_exp && (c == 'e' || c == 'E'))
+198 -90
View File
@@ -50,6 +50,29 @@ typedef struct
}
intrinsic_dumper;
typedef enum
{
PROP_DATA,
PROP_SET,
PROP_GET,
VARG
}
prop_type;
typedef struct
{
lp_string str;
bool was_num;
}
allocatable_string;
typedef struct
{
prop_type type;
allocatable_string str;
}
prop_as_str_or_varg;
#define NESTING_ITERATIONAL 1
#define NESTING_SWITCH 2
#define NESTING_FUNCTION 3
@@ -174,6 +197,18 @@ enum
};
STATIC_STACK (rewritable_break, uint8_t, uint16_t)
enum
{
strings_global_size
};
STATIC_STACK (strings, uint8_t, allocatable_string)
enum
{
props_global_size
};
STATIC_STACK (props, uint8_t, prop_as_str_or_varg)
#ifndef JERRY_NDEBUG
#define STACK_CHECK_USAGE_LHS() \
JERRY_ASSERT (IDX.current == IDX_current + 1);
@@ -684,6 +719,84 @@ name_to_native_call_id (idx_t obj)
JERRY_UNREACHABLE ();
}
static void
free_allocatable_string (prop_as_str_or_varg p)
{
if (p.str.was_num)
{
mem_heap_free_block ((uint8_t *) p.str.str.str);
}
}
static allocatable_string
create_allocatable_string_from_num_uid (idx_t uid)
{
ecma_char_t *str = mem_heap_alloc_block (ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER * sizeof (ecma_char_t),
MEM_HEAP_ALLOC_SHORT_TERM);
ecma_number_to_zt_string (lexer_get_num_by_id (uid), str,
ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER * sizeof (ecma_char_t));
return (allocatable_string)
{
.was_num = true,
.str = (lp_string)
{
.length = ecma_zt_string_length (str),
.str = str
}
};
}
static allocatable_string
create_allocatable_string_from_literal (idx_t uid)
{
return (allocatable_string)
{
.was_num = false,
.str = lexer_get_string_by_id (uid)
};
}
static allocatable_string
create_allocatable_string_from_small_int (idx_t uid)
{
const uint8_t chars_need = 4; /* Max is 255. */
uint8_t index = 0;
ecma_char_t *str = mem_heap_alloc_block (chars_need * sizeof (ecma_char_t),
MEM_HEAP_ALLOC_SHORT_TERM);
if (uid >= 100)
{
str[index++] = (ecma_char_t) (uid/100 + '0');
uid %= 100;
}
if (uid >= 10)
{
str[index++] = (ecma_char_t) (uid/10 + '0');
}
str[index++] = (ecma_char_t) (uid%10 + '0');
str[index] = ECMA_CHAR_NULL;
return (allocatable_string)
{
.was_num = true,
.str = (lp_string)
{
.length = index,
.str = str
}
};
}
static prop_as_str_or_varg
create_prop_as_str_or_varg (allocatable_string str, prop_type type)
{
return (prop_as_str_or_varg)
{
.type = type,
.str = str
};
}
/* property_name
: Identifier
| StringLiteral
@@ -701,18 +814,21 @@ parse_property_name (void)
{
STACK_PUSH (IDX, next_temp_name ());
DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, token_data ());
STACK_PUSH (strings, create_allocatable_string_from_literal (token_data ()));
break;
}
case TOK_NUMBER:
{
STACK_PUSH (IDX, next_temp_name ());
DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_NUMBER, token_data ());
STACK_PUSH (strings, create_allocatable_string_from_num_uid (token_data ()));
break;
}
case TOK_SMALL_INT:
{
STACK_PUSH (IDX, next_temp_name ());
DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_SMALLINT, token_data ());
STACK_PUSH (strings, create_allocatable_string_from_small_int (token_data ()));
break;
}
default:
@@ -740,6 +856,9 @@ parse_property_name_and_value (void)
DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_DATA, STACK_HEAD(IDX, 2), STACK_HEAD(IDX, 1));
STACK_PUSH (props, create_prop_as_str_or_varg (STACK_TOP (strings), PROP_DATA));
STACK_DROP (strings, 1);
STACK_DROP (IDX, 2);
STACK_CHECK_USAGE (IDX);
}
@@ -793,6 +912,7 @@ parse_property_assignment (void)
STACK_DECLARE_USAGE (U16)
STACK_DECLARE_USAGE (toks)
STACK_DECLARE_USAGE (U8)
STACK_DECLARE_USAGE (strings)
if (!token_is (TOK_NAME))
{
@@ -814,6 +934,8 @@ parse_property_assignment (void)
STACK_DROP (toks, 1);
// name, lhs
parse_property_name (); // push name
STACK_PUSH (props, create_prop_as_str_or_varg (STACK_TOP (strings), PROP_GET));
STACK_DROP (strings, 1);
skip_newlines ();
parse_argument_list (AL_FUNC_EXPR, next_temp_name ()); // push lhs
@@ -859,6 +981,8 @@ parse_property_assignment (void)
STACK_DROP (toks, 1);
// name, lhs
parse_property_name (); // push name
STACK_PUSH (props, create_prop_as_str_or_varg (STACK_TOP (strings), PROP_SET));
STACK_DROP (strings, 1);
skip_newlines ();
parse_argument_list (AL_FUNC_EXPR, next_temp_name ()); // push lhs
@@ -895,6 +1019,7 @@ simple_prop:
parse_property_name_and_value ();
cleanup:
STACK_CHECK_USAGE (strings);
STACK_CHECK_USAGE (U8);
STACK_CHECK_USAGE (toks);
STACK_CHECK_USAGE (U16);
@@ -925,109 +1050,86 @@ check_for_eval_and_arguments_in_strict_mode (idx_t id)
}
}
static bool
find_assignment_to (opcode_counter_t from, idx_t tmp_id, opcode_t *res)
/* 13.1, 15.3.2 */
static void
check_for_syntax_errors_in_formal_param_list (uint8_t from)
{
JERRY_ASSERT (res != NULL);
JERRY_ASSERT (tmp_id >= lexer_get_reserved_ids_count ());
for (opcode_counter_t oc = from; oc > 0; oc = (opcode_counter_t) (oc - 1))
if (STACK_SIZE (props) - from < 2 || !parser_strict_mode ())
{
*res = deserialize_opcode (oc);
if (OPCODE_IS ((*res), assignment))
return;
}
for (uint8_t i = (uint8_t) (from + 1); i < STACK_SIZE (props); i = (uint8_t) (i + 1))
{
JERRY_ASSERT (STACK_ELEMENT (props, i).type == VARG);
for (uint8_t j = from; j < i; j = (uint8_t) (j + 1))
{
if (res->data.assignment.var_left == tmp_id)
if (lp_string_equal (STACK_ELEMENT (props, i).str.str, STACK_ELEMENT (props, j).str.str))
{
return true;
EMIT_ERROR_VARG ("Duplication of literal '%s' in FormalParameterList is not allowed in strict mode",
STACK_ELEMENT (props, j).str.str.str);
}
}
}
return false;
}
/* 11.1.5 */
static void
check_for_duplication_of_param (opcode_counter_t from, uint8_t metas_num)
check_for_syntax_errors_in_obj_decl (uint8_t from)
{
if (!parser_strict_mode () || metas_num < 2)
if (STACK_SIZE (props) - from < 2)
{
return;
}
STACK_DECLARE_USAGE (IDX);
STACK_DECLARE_USAGE (U8);
STACK_DECLARE_USAGE (ops);
STACK_PUSH (U8, 0); // seen metas
STACK_PUSH (U8, STACK_SIZE (IDX));
for (opcode_counter_t oc = from; oc < OPCODE_COUNTER (); oc = (opcode_counter_t) (oc + 1))
for (uint8_t i = (uint8_t) (from + 1); i < STACK_SIZE (props); i = (uint8_t) (i + 1))
{
STACK_PUSH (ops, deserialize_opcode (oc));
if (OPCODE_IS (STACK_TOP (ops), meta))
JERRY_ASSERT (STACK_ELEMENT (props, i).type == PROP_DATA
|| STACK_ELEMENT (props, i).type == PROP_GET
|| STACK_ELEMENT (props, i).type == PROP_SET);
for (uint8_t j = from; j < i; j = (uint8_t) (j + 1))
{
switch (STACK_TOP (ops).data.meta.type)
/*4*/
const lp_string previous = STACK_ELEMENT (props, j).str.str;
const prop_type prop_type_previous = STACK_ELEMENT (props, j).type;
const lp_string prop_id_desc = STACK_ELEMENT (props, i).str.str;
const prop_type prop_type_prop_id_desc = STACK_ELEMENT (props, i).type;
if (lp_string_equal (previous, prop_id_desc))
{
case OPCODE_META_TYPE_VARG:
/*a*/
if (parser_strict_mode () && prop_type_previous == PROP_DATA && prop_type_prop_id_desc == PROP_DATA)
{
for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (IDX); i = (uint8_t) (i + 1))
{
if (STACK_ELEMENT (IDX, i) == STACK_TOP (ops).data.meta.data_1)
{
JERRY_ASSERT (STACK_ELEMENT (IDX, i) < lexer_get_strings_count ());
EMIT_ERROR ("Duplication of identifier as parameter is not allowed in strict mode.");
}
}
STACK_PUSH (IDX, STACK_TOP (ops).data.meta.data_1);
STACK_INCR_HEAD (U8, 2);
break;
EMIT_ERROR_VARG ("Duplication of parameter name '%s' in ObjectDeclaration is not allowed in strict mode",
previous.str);
}
case OPCODE_META_TYPE_VARG_PROP_DATA:
/*b*/
if (prop_type_previous == PROP_DATA
&& (prop_type_prop_id_desc == PROP_SET || prop_type_prop_id_desc == PROP_GET))
{
opcode_t res;
if (find_assignment_to (oc, STACK_TOP (ops).data.meta.data_1, &res))
{
for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (IDX); i = (uint8_t) (i + 1))
{
if (STACK_ELEMENT (IDX, i) == res.data.assignment.value_right)
{
JERRY_ASSERT (STACK_ELEMENT (IDX, i) < lexer_get_strings_count ());
EMIT_ERROR ("Duplication of identifier as parameter is not allowed in strict mode.");
}
}
STACK_PUSH (IDX, res.data.assignment.value_right);
}
/* FALLTHRU. */
EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be both data and accessor",
previous.str);
}
case OPCODE_META_TYPE_THIS_ARG:
case OPCODE_META_TYPE_VARG_PROP_GETTER:
case OPCODE_META_TYPE_VARG_PROP_SETTER:
/*c*/
if (prop_type_prop_id_desc == PROP_DATA
&& (prop_type_previous == PROP_SET || prop_type_previous == PROP_GET))
{
STACK_INCR_HEAD (U8, 2);
break;
EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be both data and accessor",
previous.str);
}
default:
/*d*/
if ((prop_type_previous == PROP_SET && prop_type_prop_id_desc == PROP_SET)
|| (prop_type_previous == PROP_GET && prop_type_prop_id_desc == PROP_GET))
{
break;
EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be accessor of same type",
previous.str);
}
}
}
STACK_DROP (ops, 1);
if (STACK_HEAD (U8, 2) == metas_num)
{
break;
}
}
STACK_DROP (IDX, STACK_SIZE (IDX) - STACK_TOP (U8));
STACK_DROP (U8, 2);
STACK_CHECK_USAGE (ops);
STACK_CHECK_USAGE (U8);
STACK_CHECK_USAGE (IDX);
}
/** Parse list of identifiers, assigment expressions or properties, splitted by comma.
For each ALT dumps appropriate bytecode. Uses OBJ during dump if neccesary.
Returns temp var if expression has lhs, or 0 otherwise. */
Returns number of arguments. */
static uint8_t
parse_argument_list (argument_list_type alt, idx_t obj)
{
@@ -1038,38 +1140,35 @@ parse_argument_list (argument_list_type alt, idx_t obj)
STACK_DECLARE_USAGE (U16)
STACK_DECLARE_USAGE (IDX)
STACK_DECLARE_USAGE (temp_names)
uint8_t args_num = 0;
STACK_DECLARE_USAGE (props)
STACK_PUSH (U8, STACK_SIZE (props));
STACK_PUSH (U8, TOK_OPEN_PAREN);
STACK_PUSH (U8, TOK_CLOSE_PAREN);
STACK_PUSH (U8, 0);
STACK_PUSH (U16, OPCODE_COUNTER ());
switch (alt)
{
case AL_FUNC_DECL:
{
STACK_PUSH (U8, TOK_OPEN_PAREN); // Openning token;
STACK_PUSH (U8, TOK_CLOSE_PAREN); // Ending token;
DUMP_OPCODE_2 (func_decl_n, obj, INVALID_VALUE);
break;
}
case AL_FUNC_EXPR:
{
STACK_PUSH (U8, TOK_OPEN_PAREN);
STACK_PUSH (U8, TOK_CLOSE_PAREN);
STACK_PUSH (IDX, next_temp_name ());
DUMP_OPCODE_3 (func_expr_n, ID(1), obj, INVALID_VALUE);
break;
}
case AL_CONSTRUCT_EXPR:
{
STACK_PUSH (U8, TOK_OPEN_PAREN);
STACK_PUSH (U8, TOK_CLOSE_PAREN);
STACK_PUSH (IDX, next_temp_name ());
DUMP_OPCODE_3 (construct_n, ID(1), obj, INVALID_VALUE);
break;
}
case AL_CALL_EXPR:
{
STACK_PUSH (U8, TOK_OPEN_PAREN);
STACK_PUSH (U8, TOK_CLOSE_PAREN);
if (is_intrinsic (obj))
{
break;
@@ -1089,16 +1188,16 @@ parse_argument_list (argument_list_type alt, idx_t obj)
}
case AL_ARRAY_DECL:
{
STACK_PUSH (U8, TOK_OPEN_SQUARE);
STACK_PUSH (U8, TOK_CLOSE_SQUARE);
STACK_SET_HEAD (U8, 3, TOK_OPEN_SQUARE);
STACK_SET_HEAD (U8, 2, TOK_CLOSE_SQUARE);
STACK_PUSH (IDX, next_temp_name ());
DUMP_OPCODE_2 (array_decl, ID(1), INVALID_VALUE);
break;
}
case AL_OBJ_DECL:
{
STACK_PUSH (U8, TOK_OPEN_BRACE);
STACK_PUSH (U8, TOK_CLOSE_BRACE);
STACK_SET_HEAD (U8, 3, TOK_OPEN_BRACE);
STACK_SET_HEAD (U8, 2, TOK_CLOSE_BRACE);
STACK_PUSH (IDX, next_temp_name ());
DUMP_OPCODE_2 (obj_decl, ID(1), INVALID_VALUE);
break;
@@ -1109,8 +1208,6 @@ parse_argument_list (argument_list_type alt, idx_t obj)
}
}
STACK_PUSH (U8, 0);
current_token_must_be (STACK_HEAD (U8, 3));
switch (alt)
@@ -1140,6 +1237,9 @@ parse_argument_list (argument_list_type alt, idx_t obj)
{
current_token_must_be (TOK_NAME);
STACK_PUSH (IDX, token_data ());
STACK_PUSH (props,
create_prop_as_str_or_varg (create_allocatable_string_from_literal (token_data ()),
VARG));
check_for_eval_and_arguments_in_strict_mode (STACK_TOP (IDX));
break;
}
@@ -1206,13 +1306,13 @@ next:
{
case AL_FUNC_DECL:
{
check_for_duplication_of_param (STACK_TOP (U16), STACK_TOP (U8));
check_for_syntax_errors_in_formal_param_list (STACK_HEAD (U8, 4));
REWRITE_OPCODE_2 (STACK_TOP (U16), func_decl_n, obj, STACK_TOP (U8));
break;
}
case AL_FUNC_EXPR:
{
check_for_duplication_of_param (STACK_TOP (U16), STACK_TOP (U8));
check_for_syntax_errors_in_formal_param_list (STACK_HEAD (U8, 4));
REWRITE_OPCODE_3 (STACK_TOP (U16), func_expr_n, ID(1), obj, STACK_TOP (U8));
break;
}
@@ -1246,7 +1346,7 @@ next:
}
case AL_OBJ_DECL:
{
check_for_duplication_of_param (STACK_TOP (U16), STACK_TOP (U8));
check_for_syntax_errors_in_obj_decl (STACK_HEAD (U8, 4));
REWRITE_OPCODE_2 (STACK_TOP (U16), obj_decl, ID(1), STACK_TOP (U8));
break;
}
@@ -1256,11 +1356,15 @@ next:
}
}
args_num = STACK_TOP (U8);
const uint8_t args_num = STACK_TOP (U8);
STACK_DROP (U8, 3);
STACK_ITERATE (props, free_allocatable_string, STACK_HEAD (U8, 4));
STACK_DROP (props, (uint8_t) (STACK_SIZE (props) - STACK_HEAD (U8, 4)));
STACK_DROP (U8, 4);
STACK_DROP (U16, 1);
STACK_CHECK_USAGE (props);
STACK_CHECK_USAGE (U8);
STACK_CHECK_USAGE (U16);
STACK_CHECK_USAGE (temp_names);
@@ -4006,6 +4110,8 @@ parser_init (const char *source, size_t source_size, bool show_opcodes)
STACK_INIT (rewritable_break);
STACK_INIT (locs);
STACK_INIT (scopes);
STACK_INIT (props);
STACK_INIT (strings);
HASH_INIT (intrinsics, 1);
@@ -4066,6 +4172,8 @@ parser_free (void)
STACK_FREE (rewritable_break);
STACK_FREE (locs);
STACK_FREE (scopes);
STACK_FREE (props);
STACK_FREE (strings);
HASH_FREE (intrinsics);
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2014 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.
var a = {a:1, get a() {return 1}}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2014 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.
var a = {get a() {return undefined}, get a() {return undefined}}
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2014 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.
var a = {get a(){return undefined}, set a(b){}}
// var b = {if:0, else:1, try:2, catch:3, finally:4}