Skip to content

Commit 40c5751

Browse files
Support for shorthand object literal notation.
JerryScript-DCO-1.0-Signed-off-by: Anthony Calandra [email protected]
1 parent 25f1718 commit 40c5751

File tree

7 files changed

+293
-36
lines changed

7 files changed

+293
-36
lines changed

jerry-core/parser/js/js-lexer.c

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,45 @@ static const keyword_string_t * const keyword_string_list[9] =
448448
#undef LEXER_KEYWORD
449449
#undef LEXER_KEYWORD_END
450450

451+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
452+
/**
453+
* Checks if current identifier is a keyword or reserved word.
454+
*
455+
* @return true - if the current identifier is a keyword or reserved word
456+
* false - otherwise
457+
*/
458+
bool
459+
lexer_is_identifier_keyword (parser_context_t *context_p) /**< context */
460+
{
461+
lexer_lit_location_t *literal_p = &context_p->token.lit_location;
462+
463+
JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL);
464+
JERRY_ASSERT (literal_p->length <= PARSER_MAXIMUM_IDENT_LENGTH);
465+
466+
if (literal_p->has_escape || literal_p->length < 2 || literal_p->length > 10)
467+
{
468+
return false;
469+
}
470+
471+
const keyword_string_t *keyword_p = keyword_string_list[literal_p->length - 2];
472+
473+
do
474+
{
475+
if (literal_p->char_p[0] == keyword_p->keyword_p[0]
476+
&& literal_p->char_p[1] == keyword_p->keyword_p[1]
477+
&& memcmp (literal_p->char_p, keyword_p->keyword_p, literal_p->length) == 0)
478+
{
479+
return true;
480+
}
481+
482+
keyword_p++;
483+
}
484+
while (keyword_p->type != LEXER_EOS);
485+
486+
return false;
487+
} /* lexer_is_identifier_keyword */
488+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
489+
451490
/**
452491
* Parse identifier.
453492
*/
@@ -1326,7 +1365,7 @@ lexer_check_colon (parser_context_t *context_p) /**< context */
13261365
&& context_p->source_p[0] == (uint8_t) LIT_CHAR_COLON);
13271366
} /* lexer_check_colon */
13281367

1329-
#ifndef CONFIG_DISABLE_ES2015_CLASS
1368+
#if !defined (CONFIG_DISABLE_ES2015_CLASS) || !defined (CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER)
13301369
/**
13311370
* Checks whether the next token is a left parenthesis.
13321371
*
@@ -1343,7 +1382,7 @@ lexer_check_left_paren (parser_context_t *context_p) /**< context */
13431382
return (context_p->source_p < context_p->source_end_p
13441383
&& context_p->source_p[0] == (uint8_t) LIT_CHAR_LEFT_PAREN);
13451384
} /* lexer_check_left_paren */
1346-
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
1385+
#endif /* !CONFIG_DISABLE_ES2015_CLASS || !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
13471386

13481387
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
13491388

@@ -2271,6 +2310,7 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
22712310
#ifndef CONFIG_DISABLE_ES2015_CLASS
22722311
int is_class_method = ((ident_opts & LEXER_OBJ_IDENT_CLASS_METHOD)
22732312
&& !(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS)
2313+
&& !(ident_opts & LEXER_OBJ_IDENT_OBJ_METHOD)
22742314
&& (context_p->token.type != LEXER_KEYW_STATIC));
22752315
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
22762316

@@ -2290,8 +2330,18 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
22902330
{
22912331
lexer_skip_spaces (context_p);
22922332

2293-
if (context_p->source_p < context_p->source_end_p
2294-
&& context_p->source_p[0] != LIT_CHAR_COLON)
2333+
bool not_end_of_literal = (context_p->source_p < context_p->source_end_p
2334+
&& context_p->source_p[0] != LIT_CHAR_COLON);
2335+
2336+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
2337+
not_end_of_literal = (not_end_of_literal
2338+
&& context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE
2339+
&& context_p->source_p[0] != LIT_CHAR_COMMA
2340+
/* Shorthand notation allows methods named `get` and allows getters. */
2341+
&& !lexer_check_left_paren (context_p));
2342+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
2343+
2344+
if (not_end_of_literal)
22952345
{
22962346
if (lexer_compare_raw_identifier_to_current (context_p, "get", 3))
22972347
{
@@ -2346,6 +2396,12 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
23462396
context_p->column++;
23472397
return;
23482398
}
2399+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
2400+
else if (context_p->source_p[0] == LIT_CHAR_LEFT_PAREN)
2401+
{
2402+
create_literal_object = true;
2403+
}
2404+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
23492405
else
23502406
{
23512407
const uint8_t *char_p = context_p->source_p;
@@ -2365,6 +2421,16 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
23652421
}
23662422
}
23672423

2424+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
2425+
if (!(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS)
2426+
&& (ident_opts & LEXER_OBJ_IDENT_OBJ_METHOD)
2427+
&& context_p->source_p[0] == LIT_CHAR_LEFT_PAREN)
2428+
{
2429+
context_p->token.type = LEXER_PROPERTY_METHOD;
2430+
return;
2431+
}
2432+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
2433+
23682434
if (create_literal_object)
23692435
{
23702436
#ifndef CONFIG_DISABLE_ES2015_CLASS

jerry-core/parser/js/js-lexer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ typedef enum
147147
LEXER_EXPRESSION_START, /**< expression start */
148148
LEXER_PROPERTY_GETTER, /**< property getter function */
149149
LEXER_PROPERTY_SETTER, /**< property setter function */
150+
LEXER_PROPERTY_METHOD, /**< property method (ES6+) */
150151
LEXER_COMMA_SEP_LIST, /**< comma separated bracketed expression list */
151152
LEXER_SCAN_SWITCH, /**< special value for switch pre-scan */
152153
LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */
@@ -216,6 +217,7 @@ typedef enum
216217
LEXER_OBJ_IDENT_NO_OPTS = (1u << 0), /**< no options */
217218
LEXER_OBJ_IDENT_ONLY_IDENTIFIERS = (1u << 1), /**< only identifiers are accepted */
218219
LEXER_OBJ_IDENT_CLASS_METHOD = (1u << 2), /**< expect identifier inside a class body */
220+
LEXER_OBJ_IDENT_OBJ_METHOD = (1u << 3), /**< expect method identifier inside object */
219221
} lexer_obj_ident_opts_t;
220222

221223
/**

jerry-core/parser/js/js-parser-expr.c

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ parser_parse_array_literal (parser_context_t *context_p) /**< context */
260260
}
261261
} /* parser_parse_array_literal */
262262

263-
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
264263
/**
265264
* Object literal item types.
266265
*/
@@ -357,7 +356,6 @@ parser_append_object_literal_item (parser_context_t *context_p, /**< context */
357356
context_p->stack_top_uint8 = PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS;
358357
}
359358
} /* parser_append_object_literal_item */
360-
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
361359

362360
#ifndef CONFIG_DISABLE_ES2015_CLASS
363361

@@ -649,41 +647,58 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */
649647

650648
while (true)
651649
{
650+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
651+
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_OBJ_METHOD);
652+
#else /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
652653
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_NO_OPTS);
654+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
653655

654656
if (context_p->token.type == LEXER_RIGHT_BRACE)
655657
{
656658
break;
657659
}
658660

659-
if (context_p->token.type == LEXER_PROPERTY_GETTER
660-
|| context_p->token.type == LEXER_PROPERTY_SETTER)
661+
bool token_type_is_method = (context_p->token.type == LEXER_PROPERTY_GETTER
662+
|| context_p->token.type == LEXER_PROPERTY_SETTER);
663+
664+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
665+
token_type_is_method = token_type_is_method || context_p->token.type == LEXER_PROPERTY_METHOD;
666+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
667+
668+
if (token_type_is_method)
661669
{
662670
uint32_t status_flags;
663-
cbc_ext_opcode_t opcode;
671+
uint16_t opcode;
664672
uint16_t literal_index, function_literal_index;
665-
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
666673
parser_object_literal_item_types_t item_type;
667-
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
674+
lexer_token_type_t token_type = context_p->token.type;
668675

669-
if (context_p->token.type == LEXER_PROPERTY_GETTER)
676+
if (token_type == LEXER_PROPERTY_GETTER)
670677
{
671678
status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_GETTER;
672-
opcode = CBC_EXT_SET_GETTER;
673-
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
679+
opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_GETTER);
674680
item_type = PARSER_OBJECT_PROPERTY_GETTER;
675-
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
676681
}
677-
else
682+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
683+
else if (token_type == LEXER_PROPERTY_METHOD)
684+
{
685+
status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_FUNC_EXPRESSION;
686+
opcode = CBC_SET_LITERAL_PROPERTY;
687+
item_type = PARSER_OBJECT_PROPERTY_VALUE;
688+
}
689+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
690+
else /* token_type == LEXER_PROPERTY_SETTER */
678691
{
679692
status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_SETTER;
680-
opcode = CBC_EXT_SET_SETTER;
681-
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
693+
opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_SETTER);
682694
item_type = PARSER_OBJECT_PROPERTY_SETTER;
683-
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
684695
}
685696

697+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
698+
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJ_METHOD);
699+
#else /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
686700
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
701+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
687702

688703
/* This assignment is a nop for computed getters/setters. */
689704
literal_index = context_p->lit_object.index;
@@ -694,6 +709,11 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */
694709
opcode = ((opcode == CBC_EXT_SET_GETTER) ? CBC_EXT_SET_COMPUTED_GETTER
695710
: CBC_EXT_SET_COMPUTED_SETTER);
696711
}
712+
713+
if (opcode == CBC_SET_LITERAL_PROPERTY)
714+
{
715+
parser_append_object_literal_item (context_p, literal_index, item_type);
716+
}
697717
#else /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
698718
parser_append_object_literal_item (context_p, literal_index, item_type);
699719
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
@@ -706,14 +726,21 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */
706726
{
707727
literal_index = function_literal_index;
708728
}
729+
/* Property methods aren't extended opcodes, so swap the values here. */
730+
else if (opcode == CBC_SET_LITERAL_PROPERTY)
731+
{
732+
literal_index ^= function_literal_index;
733+
function_literal_index ^= literal_index;
734+
literal_index ^= function_literal_index;
735+
}
709736
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
710737

711738
parser_emit_cbc_literal (context_p,
712739
CBC_PUSH_LITERAL,
713740
literal_index);
714741

715742
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
716-
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode);
743+
context_p->last_cbc_opcode = opcode;
717744
context_p->last_cbc.value = function_literal_index;
718745

719746
lexer_next_token (context_p);
@@ -751,13 +778,35 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */
751778
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
752779

753780
lexer_next_token (context_p);
754-
if (context_p->token.type != LEXER_COLON)
781+
782+
if (context_p->token.type == LEXER_COLON)
755783
{
756-
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
784+
lexer_next_token (context_p);
785+
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
757786
}
787+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
788+
else if (context_p->token.type == LEXER_COMMA
789+
|| context_p->token.type == LEXER_RIGHT_BRACE)
790+
{
791+
// TODO somehow clean this up -- is it possible to parse and check for keywords by this step?
792+
lexer_lit_location_t prop_name_literal = context_p->token.lit_location;
758793

759-
lexer_next_token (context_p);
760-
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
794+
if (prop_name_literal.type != LEXER_IDENT_LITERAL || lexer_is_identifier_keyword (context_p))
795+
{
796+
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
797+
}
798+
799+
lexer_construct_literal_object (context_p,
800+
&context_p->token.lit_location,
801+
context_p->token.lit_location.type);
802+
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
803+
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
804+
}
805+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
806+
else
807+
{
808+
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
809+
}
761810

762811
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
763812
{

jerry-core/parser/js/js-parser-internal.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,10 +433,15 @@ void parser_set_continues_to_current_position (parser_context_t *context_p, pars
433433

434434
/* Lexer functions */
435435

436+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
437+
bool lexer_is_identifier_keyword (parser_context_t *context_p);
438+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
436439
void lexer_next_token (parser_context_t *context_p);
437440
bool lexer_check_colon (parser_context_t *context_p);
438-
#ifndef CONFIG_DISABLE_ES2015_CLASS
441+
#if !defined (CONFIG_DISABLE_ES2015_CLASS) || !defined (CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER)
439442
bool lexer_check_left_paren (parser_context_t *context_p);
443+
#endif /* !CONFIG_DISABLE_ES2015_CLASS || !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
444+
#ifndef CONFIG_DISABLE_ES2015_CLASS
440445
void lexer_skip_empty_statements (parser_context_t *context_p);
441446
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
442447
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION

jerry-core/parser/js/js-parser-scanner.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -763,16 +763,16 @@ parser_scan_until (parser_context_t *context_p, /**< context */
763763
}
764764
case SCAN_MODE_FUNCTION_ARGUMENTS:
765765
{
766+
const bool correct_stack_top = (stack_top == SCAN_STACK_BLOCK_STATEMENT
767+
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
766768
#ifndef CONFIG_DISABLE_ES2015_CLASS
767-
JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT
768-
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
769-
|| stack_top == SCAN_STACK_CLASS
770-
|| stack_top == SCAN_STACK_BLOCK_PROPERTY);
771-
#else /* CONFIG_DISABLE_ES2015_CLASS */
772-
JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT
773-
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
774-
|| stack_top == SCAN_STACK_BLOCK_PROPERTY);
769+
|| stack_top == SCAN_STACK_CLASS
775770
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
771+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZERS
772+
|| stack_top == SCAN_STACK_OBJECT_LITERAL
773+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZERS */
774+
|| stack_top == SCAN_STACK_BLOCK_PROPERTY);
775+
JERRY_ASSERT (correct_stack_top);
776776

777777
if (context_p->token.type == LEXER_LITERAL
778778
&& (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
@@ -834,15 +834,25 @@ parser_scan_until (parser_context_t *context_p, /**< context */
834834
}
835835

836836
if (context_p->token.type == LEXER_PROPERTY_GETTER
837-
|| context_p->token.type == LEXER_PROPERTY_SETTER)
837+
|| context_p->token.type == LEXER_PROPERTY_SETTER
838+
|| context_p->token.type == LEXER_PROPERTY_METHOD)
838839
{
839840
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY);
840841
mode = SCAN_MODE_FUNCTION_ARGUMENTS;
841842
break;
842843
}
843844

844845
lexer_next_token (context_p);
845-
if (context_p->token.type != LEXER_COLON)
846+
847+
bool not_end_of_property_name = context_p->token.type != LEXER_COLON;
848+
849+
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
850+
not_end_of_property_name = (not_end_of_property_name
851+
&& context_p->token.type != LEXER_RIGHT_BRACE
852+
&& context_p->token.type != LEXER_COMMA);
853+
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
854+
855+
if (not_end_of_property_name)
846856
{
847857
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
848858
}

jerry-core/profiles/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,4 @@ In JerryScript all of the features are enabled by default, so an empty profile f
9696
* `CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN`:
9797
Disable the [ArrayBuffer](http://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer-objects) and [TypedArray](http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects) built-ins.
9898
* `CONFIG_DISABLE_ES2015`: Disable all of the implemented [ECMAScript2015 features](http://www.ecma-international.org/ecma-262/6.0/).
99-
(equivalent to `CONFIG_DISABLE_ES2015_ARROW_FUNCTION`, `CONFIG_DISABLE_ES2015_BUILTIN`, `CONFIG_DISABLE_ES2015_CLASS`, `CONFIG_DISABLE_ES2015_PROMISE_BUILTIN`, `CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS`, and `CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN`).
99+
(equivalent to `CONFIG_DISABLE_ES2015_ARROW_FUNCTION`, `CONFIG_DISABLE_ES2015_BUILTIN`, `CONFIG_DISABLE_ES2015_CLASS`, `CONFIG_DISABLE_ES2015_PROMISE_BUILTIN`, `CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS`, `CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN`, and `CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER`).

0 commit comments

Comments
 (0)