Skip to content

Commit 5f36037

Browse files
committed
Implement ES2015 class feature (part I.)
This patch is the first milestone of the implementation of this new language element. Currently supported: - Class statement - Class expression - Static methods JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik [email protected]
1 parent 86ecc81 commit 5f36037

File tree

16 files changed

+889
-2
lines changed

16 files changed

+889
-2
lines changed

jerry-core/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
*/
3838
#ifdef CONFIG_DISABLE_ES2015
3939
# define CONFIG_DISABLE_ES2015_ARROW_FUNCTION
40+
# define CONFIG_DISABLE_ES2015_CLASS
4041
# define CONFIG_DISABLE_ES2015_BUILTIN
4142
# define CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
4243
# define CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS

jerry-core/ecma/operations/ecma-function-object.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,13 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
448448

449449
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p);
450450

451+
#ifndef CONFIG_DISABLE_ES2015_CLASS
452+
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR && !JERRY_CONTEXT (class_invoked_with_new))
453+
{
454+
return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
455+
}
456+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
457+
451458
is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false;
452459
is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false;
453460

@@ -682,6 +689,10 @@ ecma_op_function_construct_simple_or_external (ecma_object_t *func_obj_p, /**< F
682689
* See also: ecma_object_get_class_name.
683690
*/
684691

692+
#ifndef CONFIG_DISABLE_ES2015_CLASS
693+
JERRY_CONTEXT (class_invoked_with_new) = true;
694+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
695+
685696
/* 8. */
686697
ECMA_TRY_CATCH (call_completion,
687698
ecma_op_function_call (func_obj_p,
@@ -690,6 +701,10 @@ ecma_op_function_construct_simple_or_external (ecma_object_t *func_obj_p, /**< F
690701
arguments_list_len),
691702
ret_value);
692703

704+
#ifndef CONFIG_DISABLE_ES2015_CLASS
705+
JERRY_CONTEXT (class_invoked_with_new) = false;
706+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
707+
693708
/* 9. */
694709
if (ecma_is_value_object (call_completion))
695710
{

jerry-core/jcontext/jcontext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ typedef struct
131131
#ifdef JMEM_STATS
132132
jmem_heap_stats_t jmem_heap_stats; /**< heap's memory usage statistics */
133133
#endif /* JMEM_STATS */
134+
#ifndef CONFIG_DISABLE_ES2015_CLASS
135+
bool class_invoked_with_new; /**< true if class invoked with 'new', false otherwise */
136+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
134137
} jerry_context_t;
135138

136139
#ifndef CONFIG_ECMA_LCACHE_DISABLE

jerry-core/parser/js/byte-code.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,12 @@
549549
VM_OC_RESOURCE_NAME) \
550550
CBC_OPCODE (CBC_EXT_LINE, CBC_NO_FLAG, 0, \
551551
VM_OC_LINE) \
552+
CBC_OPCODE (CBC_EXT_SET_UP_PROPERTY, CBC_HAS_LITERAL_ARG, -1, \
553+
VM_OC_SET_UP_PROPERTY | VM_OC_GET_STACK_LITERAL) \
554+
CBC_OPCODE (CBC_EXT_SET_UP_SETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
555+
VM_OC_SET_UP_SETTER | VM_OC_GET_LITERAL_LITERAL) \
556+
CBC_OPCODE (CBC_EXT_SET_UP_GETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
557+
VM_OC_SET_UP_GETTER | VM_OC_GET_LITERAL_LITERAL) \
552558
\
553559
/* Binary compound assignment opcodes with pushing the result. */ \
554560
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_ADD, \
@@ -665,6 +671,9 @@ typedef enum
665671
CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 7), /**< this function is an arrow function */
666672
CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 8), /**< this function is a static snapshot function */
667673
CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 9), /**< this function should be ignored by debugger */
674+
#ifndef CONFIG_DISABLE_ES2015_CLASS
675+
CBC_CODE_FLAGS_CLASS_CONSTRUCTOR = (1u << 10), /**< this function is a class constructor */
676+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
668677
} cbc_code_flags;
669678

670679
#define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1,

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

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,16 @@ static const keyword_string_t * const keyword_string_list[9] =
430430
#undef LEXER_KEYWORD
431431
#undef LEXER_KEYWORD_END
432432

433+
/**
434+
* This macro allows to parse future reserved strict words if the keyword is inside the class body.
435+
*/
436+
#ifndef CONFIG_DISABLE_ES2015_CLASS
437+
#define LEXER_INSIDE_CLASS (context_p->status_flags & PARSER_IS_CLASS)
438+
#else
439+
#define LEXER_INSIDE_CLASS false
440+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
441+
442+
433443
/**
434444
* Parse identifier.
435445
*/
@@ -531,7 +541,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
531541
{
532542
if (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD)
533543
{
534-
if (context_p->status_flags & PARSER_IS_STRICT)
544+
if (context_p->status_flags & PARSER_IS_STRICT && !LEXER_INSIDE_CLASS)
535545
{
536546
parser_raise_error (context_p, PARSER_ERR_STRICT_IDENT_NOT_ALLOWED);
537547
}
@@ -1939,6 +1949,16 @@ lexer_construct_function_object (parser_context_t *context_p, /**< context */
19391949
result_index = context_p->literal_count;
19401950
context_p->literal_count++;
19411951

1952+
#ifndef CONFIG_DISABLE_ES2015_CLASS
1953+
if ((extra_status_flags & PARSER_CLASS_IMPLICIT_CONSTRUCTOR) == PARSER_CLASS_IMPLICIT_CONSTRUCTOR)
1954+
{
1955+
literal_p->u.bytecode_p = parser_create_class_implicit_constructor (context_p, extra_status_flags);
1956+
literal_p->type = LEXER_FUNCTION_LITERAL;
1957+
1958+
return result_index;
1959+
}
1960+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
1961+
19421962
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
19431963
if (!(extra_status_flags & PARSER_IS_ARROW_FUNCTION))
19441964
{
@@ -2222,6 +2242,7 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
22222242
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
22232243
} /* lexer_expect_identifier */
22242244

2245+
#ifdef CONFIG_DISABLE_ES2015_CLASS
22252246
/**
22262247
* Description of "get" literal string.
22272248
*/
@@ -2238,6 +2259,8 @@ static const lexer_lit_location_t lexer_set_literal =
22382259
(const uint8_t *) "set", 3, LEXER_IDENT_LITERAL, false
22392260
};
22402261

2262+
#endif /* CONFIG_DISABLE_ES2015_CLASS */
2263+
22412264
/**
22422265
* Next token must be an identifier.
22432266
*/
@@ -2247,6 +2270,15 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
22472270
{
22482271
lexer_skip_spaces (context_p);
22492272

2273+
#ifndef CONFIG_DISABLE_ES2015_CLASS
2274+
/* Skip empty statements */
2275+
while (context_p->status_flags & PARSER_IS_CLASS && *context_p->source_p == LIT_CHAR_SEMICOLON)
2276+
{
2277+
lexer_next_token (context_p);
2278+
lexer_skip_spaces (context_p);
2279+
}
2280+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
2281+
22502282
context_p->token.line = context_p->line;
22512283
context_p->token.column = context_p->column;
22522284

@@ -2278,6 +2310,24 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
22782310
}
22792311
}
22802312
}
2313+
#ifndef CONFIG_DISABLE_ES2015_CLASS
2314+
if (!must_be_identifier
2315+
&& context_p->status_flags & PARSER_IS_CLASS
2316+
&& context_p->token.lit_location.length == 6)
2317+
{
2318+
lexer_skip_spaces (context_p);
2319+
2320+
if (context_p->source_p < context_p->source_end_p
2321+
&& context_p->source_p[0] != LIT_CHAR_COLON)
2322+
{
2323+
if (lexer_compare_identifier_to_current (context_p, &lexer_static_literal))
2324+
{
2325+
context_p->token.type = LEXER_KEYW_STATIC;
2326+
return;
2327+
}
2328+
}
2329+
}
2330+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
22812331

22822332
create_literal_object = true;
22832333
}
@@ -2313,6 +2363,15 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
23132363
}
23142364
}
23152365

2366+
#ifndef CONFIG_DISABLE_ES2015_CLASS
2367+
if (context_p->status_flags & PARSER_IS_CLASS
2368+
&& lexer_compare_identifier_to_current (context_p, &lexer_constructor_literal))
2369+
{
2370+
context_p->status_flags |= PARSER_CLASS_CONSTRUCTOR;
2371+
return;
2372+
}
2373+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
2374+
23162375
if (create_literal_object)
23172376
{
23182377
lexer_construct_literal_object (context_p,

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,48 @@ typedef struct
274274
uint8_t type; /**< literal object type */
275275
} lexer_lit_object_t;
276276

277+
#ifndef CONFIG_DISABLE_ES2015_CLASS
278+
/**
279+
* Description of "get" literal string.
280+
*/
281+
static const lexer_lit_location_t lexer_get_literal =
282+
{
283+
(const uint8_t *) "get", 3, LEXER_IDENT_LITERAL, false
284+
};
285+
286+
/**
287+
* Description of "set" literal string.
288+
*/
289+
static const lexer_lit_location_t lexer_set_literal =
290+
{
291+
(const uint8_t *) "set", 3, LEXER_IDENT_LITERAL, false
292+
};
293+
294+
/**
295+
* Description of "constructor" literal string.
296+
*/
297+
static const lexer_lit_location_t lexer_constructor_literal =
298+
{
299+
(const uint8_t *) "constructor", 11, LEXER_STRING_LITERAL, false
300+
};
301+
302+
/**
303+
* Description of "prototype" literal string.
304+
*/
305+
static const lexer_lit_location_t lexer_prototype_literal =
306+
{
307+
(const uint8_t *) "prototype", 9, LEXER_STRING_LITERAL, false
308+
};
309+
310+
/**
311+
* Description of "static" literal string.
312+
*/
313+
static const lexer_lit_location_t lexer_static_literal =
314+
{
315+
(const uint8_t *) "static", 6, LEXER_IDENT_LITERAL, false
316+
};
317+
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
318+
277319
/**
278320
* @}
279321
* @}

0 commit comments

Comments
 (0)