-
Notifications
You must be signed in to change notification settings - Fork 684
[WIP] Support for shorthand object literal notation. #2432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -448,6 +448,45 @@ static const keyword_string_t * const keyword_string_list[9] = | |
#undef LEXER_KEYWORD | ||
#undef LEXER_KEYWORD_END | ||
|
||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
/** | ||
* Checks if current identifier is a keyword or reserved word. | ||
* | ||
* @return true - if the current identifier is a keyword or reserved word | ||
* false - otherwise | ||
*/ | ||
bool | ||
lexer_is_identifier_keyword (parser_context_t *context_p) /**< context */ | ||
{ | ||
lexer_lit_location_t *literal_p = &context_p->token.lit_location; | ||
|
||
JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL); | ||
JERRY_ASSERT (literal_p->length <= PARSER_MAXIMUM_IDENT_LENGTH); | ||
|
||
if (literal_p->has_escape || literal_p->length < 2 || literal_p->length > 10) | ||
{ | ||
return false; | ||
} | ||
|
||
const keyword_string_t *keyword_p = keyword_string_list[literal_p->length - 2]; | ||
|
||
do | ||
{ | ||
if (literal_p->char_p[0] == keyword_p->keyword_p[0] | ||
&& literal_p->char_p[1] == keyword_p->keyword_p[1] | ||
&& memcmp (literal_p->char_p, keyword_p->keyword_p, literal_p->length) == 0) | ||
{ | ||
return true; | ||
} | ||
|
||
keyword_p++; | ||
} | ||
while (keyword_p->type != LEXER_EOS); | ||
|
||
return false; | ||
} /* lexer_is_identifier_keyword */ | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
/** | ||
* Parse identifier. | ||
*/ | ||
|
@@ -1326,7 +1365,7 @@ lexer_check_colon (parser_context_t *context_p) /**< context */ | |
&& context_p->source_p[0] == (uint8_t) LIT_CHAR_COLON); | ||
} /* lexer_check_colon */ | ||
|
||
#ifndef CONFIG_DISABLE_ES2015_CLASS | ||
#if !defined (CONFIG_DISABLE_ES2015_CLASS) || !defined (CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER) | ||
/** | ||
* Checks whether the next token is a left parenthesis. | ||
* | ||
|
@@ -1343,7 +1382,7 @@ lexer_check_left_paren (parser_context_t *context_p) /**< context */ | |
return (context_p->source_p < context_p->source_end_p | ||
&& context_p->source_p[0] == (uint8_t) LIT_CHAR_LEFT_PAREN); | ||
} /* lexer_check_left_paren */ | ||
#endif /* !CONFIG_DISABLE_ES2015_CLASS */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you remove this check? Isn't this an ES6 feature? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It came from the ES6 classes pull request but I also use it for checking if we have a method (it checks to see if there is a left parenthesis after the identifier). If I keep the ifdef around it then if the user disables classes I won't have this function available. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean this shorthand notation isn/t an es6 feature? Then we might need to change the ifdef. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. I'm planning on adding computed properties at some point, so all these new language features to object initializers could fit nicely into this macro. |
||
#endif /* !CONFIG_DISABLE_ES2015_CLASS || !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION | ||
|
||
|
@@ -2271,6 +2310,7 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ | |
#ifndef CONFIG_DISABLE_ES2015_CLASS | ||
int is_class_method = ((ident_opts & LEXER_OBJ_IDENT_CLASS_METHOD) | ||
&& !(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) | ||
&& !(ident_opts & LEXER_OBJ_IDENT_OBJ_METHOD) | ||
&& (context_p->token.type != LEXER_KEYW_STATIC)); | ||
#endif /* !CONFIG_DISABLE_ES2015_CLASS */ | ||
|
||
|
@@ -2290,8 +2330,18 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ | |
{ | ||
lexer_skip_spaces (context_p); | ||
|
||
if (context_p->source_p < context_p->source_end_p | ||
&& context_p->source_p[0] != LIT_CHAR_COLON) | ||
bool not_end_of_literal = (context_p->source_p < context_p->source_end_p | ||
&& context_p->source_p[0] != LIT_CHAR_COLON); | ||
|
||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
not_end_of_literal = (not_end_of_literal | ||
&& context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE | ||
&& context_p->source_p[0] != LIT_CHAR_COMMA | ||
/* Shorthand notation allows methods named `get` and allows getters. */ | ||
&& !lexer_check_left_paren (context_p)); | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
if (not_end_of_literal) | ||
{ | ||
if (lexer_compare_raw_identifier_to_current (context_p, "get", 3)) | ||
{ | ||
|
@@ -2346,6 +2396,12 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ | |
context_p->column++; | ||
return; | ||
} | ||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
else if (context_p->source_p[0] == LIT_CHAR_LEFT_PAREN) | ||
{ | ||
create_literal_object = true; | ||
} | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
else | ||
{ | ||
const uint8_t *char_p = context_p->source_p; | ||
|
@@ -2365,6 +2421,16 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ | |
} | ||
} | ||
|
||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
if (!(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) | ||
&& (ident_opts & LEXER_OBJ_IDENT_OBJ_METHOD) | ||
&& context_p->source_p[0] == LIT_CHAR_LEFT_PAREN) | ||
{ | ||
context_p->token.type = LEXER_PROPERTY_METHOD; | ||
return; | ||
} | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
if (create_literal_object) | ||
{ | ||
#ifndef CONFIG_DISABLE_ES2015_CLASS | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -260,7 +260,6 @@ parser_parse_array_literal (parser_context_t *context_p) /**< context */ | |
} | ||
} /* parser_parse_array_literal */ | ||
|
||
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @zherczeg I noticed that everything in this macro were needed for my code so I removed the ifdefs here. I'm guessing this change in your computed properties PR was to save binary size? |
||
/** | ||
* Object literal item types. | ||
*/ | ||
|
@@ -357,7 +356,6 @@ parser_append_object_literal_item (parser_context_t *context_p, /**< context */ | |
context_p->stack_top_uint8 = PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS; | ||
} | ||
} /* parser_append_object_literal_item */ | ||
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
#ifndef CONFIG_DISABLE_ES2015_CLASS | ||
|
||
|
@@ -649,41 +647,58 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ | |
|
||
while (true) | ||
{ | ||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_OBJ_METHOD); | ||
#else /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_NO_OPTS); | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
if (context_p->token.type == LEXER_RIGHT_BRACE) | ||
{ | ||
break; | ||
} | ||
|
||
if (context_p->token.type == LEXER_PROPERTY_GETTER | ||
|| context_p->token.type == LEXER_PROPERTY_SETTER) | ||
bool token_type_is_method = (context_p->token.type == LEXER_PROPERTY_GETTER | ||
|| context_p->token.type == LEXER_PROPERTY_SETTER); | ||
|
||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
token_type_is_method = token_type_is_method || context_p->token.type == LEXER_PROPERTY_METHOD; | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
if (token_type_is_method) | ||
{ | ||
uint32_t status_flags; | ||
cbc_ext_opcode_t opcode; | ||
uint16_t opcode; | ||
uint16_t literal_index, function_literal_index; | ||
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
parser_object_literal_item_types_t item_type; | ||
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
lexer_token_type_t token_type = context_p->token.type; | ||
|
||
if (context_p->token.type == LEXER_PROPERTY_GETTER) | ||
if (token_type == LEXER_PROPERTY_GETTER) | ||
{ | ||
status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_GETTER; | ||
opcode = CBC_EXT_SET_GETTER; | ||
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_GETTER); | ||
item_type = PARSER_OBJECT_PROPERTY_GETTER; | ||
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
} | ||
else | ||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
else if (token_type == LEXER_PROPERTY_METHOD) | ||
{ | ||
status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_FUNC_EXPRESSION; | ||
opcode = CBC_SET_LITERAL_PROPERTY; | ||
item_type = PARSER_OBJECT_PROPERTY_VALUE; | ||
} | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
else /* token_type == LEXER_PROPERTY_SETTER */ | ||
{ | ||
status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_SETTER; | ||
opcode = CBC_EXT_SET_SETTER; | ||
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_SETTER); | ||
item_type = PARSER_OBJECT_PROPERTY_SETTER; | ||
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
} | ||
|
||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJ_METHOD); | ||
#else /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
/* This assignment is a nop for computed getters/setters. */ | ||
literal_index = context_p->lit_object.index; | ||
|
@@ -694,6 +709,11 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ | |
opcode = ((opcode == CBC_EXT_SET_GETTER) ? CBC_EXT_SET_COMPUTED_GETTER | ||
: CBC_EXT_SET_COMPUTED_SETTER); | ||
} | ||
|
||
if (opcode == CBC_SET_LITERAL_PROPERTY) | ||
{ | ||
parser_append_object_literal_item (context_p, literal_index, item_type); | ||
} | ||
#else /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
parser_append_object_literal_item (context_p, literal_index, item_type); | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
@@ -706,14 +726,21 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ | |
{ | ||
literal_index = function_literal_index; | ||
} | ||
/* Property methods aren't extended opcodes, so swap the values here. */ | ||
else if (opcode == CBC_SET_LITERAL_PROPERTY) | ||
{ | ||
literal_index ^= function_literal_index; | ||
function_literal_index ^= literal_index; | ||
literal_index ^= function_literal_index; | ||
} | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
parser_emit_cbc_literal (context_p, | ||
CBC_PUSH_LITERAL, | ||
literal_index); | ||
|
||
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); | ||
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode); | ||
context_p->last_cbc_opcode = opcode; | ||
context_p->last_cbc.value = function_literal_index; | ||
|
||
lexer_next_token (context_p); | ||
|
@@ -751,13 +778,35 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ | |
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
|
||
lexer_next_token (context_p); | ||
if (context_p->token.type != LEXER_COLON) | ||
|
||
if (context_p->token.type == LEXER_COLON) | ||
{ | ||
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); | ||
lexer_next_token (context_p); | ||
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); | ||
} | ||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER | ||
else if (context_p->token.type == LEXER_COMMA | ||
|| context_p->token.type == LEXER_RIGHT_BRACE) | ||
{ | ||
// TODO somehow clean this up -- is it possible to parse and check for keywords by this step? | ||
lexer_lit_location_t prop_name_literal = context_p->token.lit_location; | ||
|
||
lexer_next_token (context_p); | ||
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); | ||
if (prop_name_literal.type != LEXER_IDENT_LITERAL || lexer_is_identifier_keyword (context_p)) | ||
{ | ||
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); | ||
} | ||
|
||
lexer_construct_literal_object (context_p, | ||
&context_p->token.lit_location, | ||
context_p->token.lit_location.type); | ||
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); | ||
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); | ||
} | ||
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ | ||
else | ||
{ | ||
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); | ||
} | ||
|
||
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a similar code for this. It would be good to not duplicate that.
You need to be smart here, invent a way which can be effectively optimized by tail merging or just "reparse" the string or whatever.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My updated patch doesn't yet address this; still thinking on it.