Skip to content

Implement ES2015 class feature (part II.) #2439

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

Merged

Conversation

rerobika
Copy link
Member

@rerobika rerobika commented Jul 30, 2018

This patch is the second milestone of the implementation of this new language element.

Supported:

  • Single class inheritance
  • Functionality of 'super' keyword
  • Implicit constructor in class heritage
  • Specific behaviour while extending with the built-in 'Array' or '%TypedArray%' object
  • Abstract subclasses (Mix-ins)

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik [email protected]

@rerobika rerobika force-pushed the es2015_class_part_II branch 2 times, most recently from 3d8f738 to 9900717 Compare August 1, 2018 14:59
@@ -297,7 +297,9 @@ ecma_collection_iterator_next (ecma_value_t *iterator_p);
/* ecma-helpers.c */
ecma_object_t *ecma_create_object (ecma_object_t *prototype_object_p, size_t ext_object_size, ecma_object_type_t type);
ecma_object_t *ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p);
ecma_object_t *ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, ecma_object_t *binding_obj_p);
ecma_object_t *ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p,
ecma_object_t *binding_obj_p,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can keep this in the previous line.

@@ -72,6 +75,27 @@ ecma_builtin_global_object_eval (ecma_value_t this_arg, /**< this argument */
parse_opts |= ECMA_PARSE_STRICT_MODE;
}

#ifndef CONFIG_DISABLE_ES2015_CLASS
uint32_t super_call_opts = JERRY_CONTEXT (vm_top_context_p)->super_call_opts;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a simple global variable. Maybe combined with a direct_eval flag.

#ifndef CONFIG_DISABLE_ES2015_CLASS
if (JERRY_UNLIKELY (frame_ctx_p->super_call_opts & ECMA_SUPER_CALL_CONSTRUCTOR))
{
stack_top_p = (ecma_value_t *) ecma_op_function_set_construct_flag (stack_top_p);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would store these in local variables rather than manipulating globals. Just like is_direct_eval above.

{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);

return (property_p != NULL);
}
else
{
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
#ifndef CONFIG_DISABLE_ES2015_CLASS
JERRY_ASSERT (lex_env_type != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is an assert, use == twice.

@@ -16,6 +16,8 @@
#ifndef JS_LEXER_H
#define JS_LEXER_H

#include "lit-char-helpers.h"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather not include this here.

if (context_p->status_flags & PARSER_IS_ARROW_FUNCTION)
{
status_flags |= PARSER_IS_ARROW_FUNCTION;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, you can do this in a less complicated way:

const uint32_t inherited_flags = PARSER_CLASS_HAS_SUPER | PARSER_IS_ARROW_FUNCTION;
status_flags |= (context_p->status_flags & inherited_flags);

Why arrow function is inherited?

{
parser_parse_super_class_context_start (context_p);
}

/* Currently heritage is not supported so the next token must be left brace. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment still valid?

parser_emit_cbc (context_p, CBC_PUSH_THIS);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need this newline.

|| context_p->last_cbc_opcode == CBC_PUSH_PROP_THIS_LITERAL))
{
/* Invalid LeftHandSide expression. */
parser_raise_error (context_p, PARSER_ERR_INVALID_LEFT_HAND_SIDE_EXPRESSION);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ES6 standard is confusing for me. It allows f() = 5 lefthandside expressions, but says it is a ReferenceError during runtime.

For classes it has meaning: class A extends f() {} is ok.

@akosthekiss akosthekiss added the ES2015 Related to ES2015 features label Aug 17, 2018
@rerobika
Copy link
Member Author

@zherczeg Thanks for the review, I'm going to apply your suggestions.

@rerobika rerobika force-pushed the es2015_class_part_II branch 3 times, most recently from 3d9f3fc to d985517 Compare September 17, 2018 07:50
@rerobika
Copy link
Member Author

@zherczeg The patch is updated and ready for the review.

@@ -633,12 +637,56 @@ typedef enum
ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE = 13, /**< declarative lexical environment */
ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND = 14, /**< object-bound lexical environment
* with provideThis flag */
ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND = 15, /**< object-bound lexical environment
* with provided super reference */

ECMA_LEXICAL_ENVIRONMENT_TYPE_START = ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE, /**< first lexical
* environment type */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete one space before comment.

@@ -355,7 +354,7 @@ ecma_get_lex_env_binding_object (const ecma_object_t *object_p) /**< object-boun
{
JERRY_ASSERT (object_p != NULL);
JERRY_ASSERT (ecma_is_lexical_environment (object_p));
JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
JERRY_ASSERT (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use != in assert.

ecma_object_t *constructor_object_p = ecma_get_object_from_value (constructor_value);

ecma_value_t result = ecma_op_create_array_object (arguments_list_p,
arguments_list_len,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a space.

* @return the bytecode of the most general 'super'.
*/
static const ecma_compiled_code_t *
ecma_resolve_implicit_constructor_call (const ecma_compiled_code_t *bytecode_data_p, /**< byte-code data header */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets try to use bound functions.

@@ -59,6 +59,30 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical
return NULL;
} /* ecma_op_resolve_reference_base */


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this newline.

eval_parse_opts |= ECMA_PARSE_ARROW_FUNCTION;
}


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One newline.

{
this_value = frame_ctx_p->this_binding;
frame_ctx_p->super_call_opts &= (uint8_t) ~ECMA_HERITAGE_SUPER_PROP_CALL;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do this in the parser.

@rerobika rerobika force-pushed the es2015_class_part_II branch 3 times, most recently from 7c69ea4 to 8788c2a Compare September 21, 2018 13:28
@@ -170,6 +174,7 @@ enum
* ecma_op_object_find */
ECMA_VALUE_REGISTER_REF = ECMA_MAKE_VALUE (8), /**< register reference,
* a special "base" value for vm */
ECMA_VALUE_IMPLICIT_CALL = ECMA_MAKE_VALUE (9), /**< TODO */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo

ECMA_PARSE_DIRECT_EVAL = (1 << 1), /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */
ECMA_PARSE_HAS_SUPER = (1 << 2), /**< the current context has super reference */
ECMA_PARSE_CLASS_CONSTRUCTOR = (1 << 3), /**< the current context is a class constructor */
ECMA_PARSE_ARROW_FUNCTION = (1 << 4), /**< the current context is an arrow function */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this flag?

typedef enum
{
ECMA_HERITAGE_NO_OPTS = 0, /**< no speficied options are provided */
ECMA_HERITAGE_SUPER_CALLED = (1 << 1), /**< 'super ()' has been called in the current context */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using ECMA_OBJECT_FLAG_EXTENSIBLE?

is_treat_single_arg_as_length);

ecma_object_t *result_object_p = ecma_get_object_from_value (result);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less newline please.

JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_SUPER_CALL);

/* This flag is only used to force the call operation to VM_EXEC_SUPER_CALL
so it is no longer needed. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this comment.

goto error;
}

*stack_top_p++ = ecma_copy_value (ecma_op_get_super_this_binding (frame_ctx_p->lex_env_p));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class this binding

ecma_extended_object_t *current_ext_func_obj_p = (ecma_extended_object_t *) current_constructor_obj_p;

current_constructor_obj_p->type_flags_refs &= (uint16_t) ~ECMA_OBJECT_TYPE_MASK;
current_constructor_obj_p->type_flags_refs |= ECMA_OBJECT_TYPE_FUNCTION;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+= ECMA_OBJECT_TYPE_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION

}
case VM_OC_SUPER_PROP_REFERENCE:
{
JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this.

@rerobika rerobika force-pushed the es2015_class_part_II branch 4 times, most recently from ff1b5b2 to 0ea5c73 Compare September 27, 2018 09:54
@@ -82,12 +82,16 @@ typedef enum

/**
* Option flags for script parsing.
* NOTE: The enum members must be kept int sync with parser_general_flags_t
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"kept in"

ECMA_PARSE_DIRECT_EVAL = (1u << 1), /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */
ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 2), /**< the current context is a class constructor */
ECMA_PARSE_HAS_SUPER = (1u << 3), /**< the current context has super reference */
ECMA_PARSE_CLASS_STATIC_FUNCTION = (1u << 4), /**< the current context is a static class method */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ECMA_PARSE_HAS_STATIC_SUPER

ECMA_PARSE_DIRECT_EVAL = (1 << 1) /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */
ECMA_PARSE_STRICT_MODE = (1u << 0), /**< enable strict mode */
ECMA_PARSE_DIRECT_EVAL = (1u << 1), /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */
ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 2), /**< the current context is a class constructor */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a class constructor is being parsed.

/**
* Set JERRY_CONTEXT (status_flags) top 8 bits to the specified 'opts'.
*/
#define ECMA_SET_SUPER_EVAL_PARSER_OPTS(base, opts) \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "base" is unnecessary.

*/
ecma_value_t
ecma_op_create_array_object_by_constructor (const ecma_value_t *arguments_list_p, /**< list of arguments that
* are passed to Array constructor */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation is missing.

ecma_op_set_class_context (ecma_object_t *local_env_p, /**< local lexical enviroment */
ecma_value_t this_binding) /**< 'this' argument's value */
{
ecma_string_t *super_this_binding_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class_this_binding

/* Class opcodes */ \
CBC_OPCODE (CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR, CBC_NO_FLAG, 0, \
VM_OC_CLASS_HERITAGE) \
CBC_OPCODE (CBC_EXT_SUPER_EVAL, CBC_HAS_BYTE_ARG, 0, \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CBC_EXT_CLASS_EVAL

VM_OC_SUPER_CALL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_SUPER_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \
VM_OC_SUPER_CALL | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_EXT_PUSH_CLASS_CONSTRUCTOR, CBC_NO_FLAG, 1, \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move after CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR

ecma_value_t super_prototype_value = ecma_op_object_get_by_magic_id (super_class_p,
LIT_MAGIC_STRING_PROTOTYPE);

if (!ECMA_IS_VALUE_ERROR (super_prototype_value) && !ecma_is_value_undefined (super_prototype_value))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not object or null, throw an error.

@rerobika rerobika force-pushed the es2015_class_part_II branch from 0ea5c73 to 44729d4 Compare October 2, 2018 13:20
@rerobika
Copy link
Member Author

rerobika commented Oct 2, 2018

The patch is updated, depends on #2547.

@rerobika rerobika force-pushed the es2015_class_part_II branch 3 times, most recently from 3f86596 to 61be3d8 Compare October 4, 2018 10:06
@@ -76,18 +76,25 @@ typedef enum
ECMA_TYPE_DIRECT_STRING = 5, /**< directly encoded string values */
ECMA_TYPE_ERROR = 7, /**< pointer to description of an error reference (only supported by C API) */
ECMA_TYPE_POINTER = ECMA_TYPE_ERROR, /**< a generic aligned pointer */
#ifndef CONFIG_DISABLE_ES2015_CLASS
ECMA_TYPE_CLASS = ECMA_TYPE_ERROR, /**< special type for class contextes */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ECMA_TYPE_INACCESSIBLE_THIS

@@ -170,6 +177,7 @@ enum
* ecma_op_object_find */
ECMA_VALUE_REGISTER_REF = ECMA_MAKE_VALUE (8), /**< register reference,
* a special "base" value for vm */
ECMA_VALUE_IMPLICIT_CALL = ECMA_MAKE_VALUE (9), /**< special value for implicit constructor call */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: bound class constructors
ECMA_VALUE_IMPLICIT_CONSTRUCTOR


if (ecma_is_value_class (this_binding))
{
this_binding -= ECMA_TYPE_CLASS - ECMA_TYPE_OBJECT;;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double semicolon.

@@ -829,7 +1050,7 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
}

/* 8. */
ecma_value_t ret_value;
ecma_value_t ret_value = ECMA_VALUE_UNDEFINED;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this before the break statement.

@@ -46,6 +46,7 @@ typedef enum
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX, /**< [[Index]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_VALUE, /**< [[Values]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT, /**< [[RemainingElement]] property */
LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING, /**< the this binding of the class constructor */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use internal properties.

/**
* Offset between PARSER_CLASS_CONSTRUCTOR and ECMA_PARSE_CLASS_CONSTRUCTOR
*/
#define PARSER_CLASS_PARSE_OPTS_OFFSET 18
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(20-2)

@@ -69,6 +69,9 @@ typedef enum
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
#ifndef CONFIG_DISABLE_ES2015_CLASS
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment about PARSER_CLASS_PARSE_OPTS_OFFSET

@rerobika rerobika force-pushed the es2015_class_part_II branch 3 times, most recently from b94cce4 to b1bdb21 Compare October 5, 2018 09:54
Copy link
Member

@zherczeg zherczeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting very close.

ECMA_PARSE_STRICT_MODE = (1 << 0), /**< enable strict mode */
ECMA_PARSE_DIRECT_EVAL = (1 << 1) /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */
ECMA_PARSE_STRICT_MODE = (1u << 0), /**< enable strict mode */
ECMA_PARSE_DIRECT_EVAL = (1u << 1), /**< is eval called directly (ECMA-262 v5, 15.1.2.1.1) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: eval is called directly

@@ -131,6 +134,67 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of
return ecma_make_object_value (object_p);
} /* ecma_op_create_array_object */

#ifndef CONFIG_DISABLE_ES2015_CLASS
/**
* Array object creation operation according to the 'constructor' property.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: Array object creation with custom prototype.

case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p));
ret_value = ecma_op_function_construct (func_obj_p,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would pass the target_function here. Requires one less check after the recursive call.

uint32_t constructor_super = PARSER_CLASS_CONSTRUCTOR | PARSER_CLASS_HAS_SUPER;
bool is_constructor_super = (context_p->status_flags & constructor_super) == constructor_super;
#else /* CONFIG_DISABLE_ES2015_CLASS */
bool is_constructor_super = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do this nicely without introducing a variable?

JERRY_ASSERT ((status_flags & PARSER_IS_FUNCTION)
&& (status_flags & PARSER_IS_ARROW_FUNCTION));
parser_save_context (context_p, &saved_context);
#ifndef CONFIG_DISABLE_ES2015_CLASS
context_p->status_flags |= status_flags | PARSER_ARGUMENTS_NOT_NEEDED | class_has_super;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the uint32_t class_has_super = context_p->status_flags & PARSER_CLASS_HAS_SUPER; above.

Add context_p->status_flags |= context_p->status_flags & PARSER_CLASS_HAS_SUPER here if the line above is too long with this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you save the context you lose all of your status flags except the PARSER_IS_STRICT, so
context_p->status_flags |= context_p->status_flags & PARSER_CLASS_HAS_SUPER will never add the PARSER_CLASS_HAS_SUPER flag to the new context.

But we can combine our solutions like:

context_p->status_flags |= saved_context.status_flags & PARSER_CLASS_HAS_SUPER


ecma_free_value (result);

result = ecma_raise_type_error ("Class extends value is not a constructor or null.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Value provided by class extends is not an object or null.


frame_ctx_p->lex_env_p = super_env_p;
}
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the two code paths do not share code. Would it be a good idea to introduce two vm opcodes for them?

@@ -1573,6 +1937,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ecma_fast_free_value (block_result);
block_result = result;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this space is needed?

Copy link
Member

@akosthekiss akosthekiss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First set of comments. More may come, I couldn't review all parts of the change yet.

@@ -82,12 +82,16 @@ typedef enum

/**
* Option flags for script parsing.
* NOTE: The enum members must be kept in sync with parser_general_flags_t
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, notes are written in a slightly different way in the rest of the code base:

 *
 * Note:
 *      text here

@@ -109,7 +109,7 @@ struct jerry_context_t
ecma_value_t error_value; /**< currently thrown error value */
uint32_t lit_magic_string_ex_count; /**< external magic strings count */
uint32_t jerry_init_flags; /**< run-time configuration flags */
uint32_t status_flags; /**< run-time flags */
uint32_t status_flags; /**< run-time flags. NOTE: the top 8 bits are used for passing class parsing options */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That all-caps note is very 'loud'. I'd suggest simply "run-time flags (the top 8 bits are used for passing class parsing options)"

* Check whether the current magic string is internal magic string
*/
#define LIT_IS_INTERNAL_MAGIC_STRING(id) ((id) >= LIT_GC_MARK_REQUIRED_MAGIC_STRING__COUNT \
&& (id) < LIT_MAGIC_STRING__COUNT)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This second part of the predicate seems to be a safety check that usually goes into an assert to prevent being a performance hit. Cannot LIT_IS_INTERNAL_MAGIC_STRING only check for (id) >= LIT_GC_MARK_REQUIRED_MAGIC_STRING__COUNT? Callers of LIT_IS_INTERNAL_MAGIC_STRING can have a separate assert for (id) < LIT_MAGIC_STRING__COUNT, which will then be a no-op for release builds (or LIT_IS_INTERNAL_MAGIC_STRING can have a different version for debug/release builds, but I think there is no precedent for that in the code base).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not used by asserts. Live code should be fast.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akosthekiss Your insight is right about the safety check. The reason of this plus check is that this macro is only used in asserts.

case ECMA_PROPERTY_TYPE_INTERNAL:
    {
      JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC
                    && LIT_IS_INTERNAL_MAGIC_STRING (property_pair_p->names_cp[index]));
      break;
    }
    default:
    {
      JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);

      /* Must be a native pointer. */
      JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC
                    && LIT_IS_INTERNAL_MAGIC_STRING (name_cp));
      break;
    }

Anyway the property's type is the most significant attribute during the property processing we can not rely on this macro, it's only for safety check.
Therefore I think it's not necessary to modify this macro to support release builds.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is only used twice and both times in an assert, is a macro (that can be misused by mistake and thus become a performance hit) justified for this? Can't this check simply be incorporated into the two asserts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, you convinced me.

@@ -25,6 +25,10 @@
#include "jcontext.h"
#endif /* !CONFIG_DISABLE_ES2015_CLASS && (JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO) */

#ifndef CONFIG_DISABLE_ES2015_CLASS
#include "lit-char-helpers.h"
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note 1: lit-char-helpers.h is already included some lines above, guarded by CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS. These could be merged.

Note 2: But what's the point of conditional includes? What harm can the unconditional includes do? I see that other header inclusions are guarded, too, but don't really see why. I'd just write

#include "jcontext.h"
#include "lit-char-helpers.h"

If this causes any problems in this compilation unit in some configuration, then that signals quite a problem somewhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed the #ifdef guard terminology, but +1 for removing them.

@@ -68,7 +68,11 @@ typedef enum
PARSER_ARROW_PARSE_ARGS = (1u << 19), /**< parse the argument list of an arrow function */
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
#ifndef CONFIG_DISABLE_ES2015_CLASS
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed */
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed. NOTE: this value must be kept in
* in sync with ECMA_PARSE_CLASS_CONSTRUCTOR */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it only this enumerator that must be kept in sync with another enumerator? The newly added note at ecma_parse_opts_t mentions all enumerators in this enum. BTW, what does "in sync" mean in this case? See:

  ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 2), /**< a class constructor is being parsed */
  ECMA_PARSE_HAS_SUPER = (1u << 3), /**< the current context has super reference */
  ECMA_PARSE_HAS_STATIC_SUPER = (1u << 4), /**< the current context is a static class method */

vs

  PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed */
  PARSER_CLASS_HAS_SUPER = (1u << 21) /**< class has super reference */
  PARSER_CLASS_STATIC_FUNCTION = (1u << 22), /**< this function is a static class method */

The values are definitely not the same, and the enumerator names are also a bit 'out-of-sync'.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just found PARSER_CLASS_PARSE_OPTS_OFFSET. It should be referenced in the comment (or perhaps in a comment inserted before PARSER_CLASS_CONSTRUCTOR to emphasise that the following enumerators form a group and have to be treated together).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static asserts could be used to check this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reference in the comment is a good idea, static assert for the check is already available.

@@ -21,6 +21,8 @@
#include "jcontext.h"
#endif /* JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Also a conditional include. Not part of this PR but still not sure why.)

{
ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p;
frame_ctx_p->lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
ecma_deref_object (lex_env_p);

#ifndef CONFIG_DISABLE_ES2015_CLASS
JERRY_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this rather be a static assert? Both PARSER_WITH_CONTEXT_STACK_ALLOCATION and PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION are macro-defined constants in byte-code.h. (And PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION is not even macro-guarded. So either the (static?) assert should not be guarded or PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION should be macro-guarded.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can agree with that.

Copy link
Member

@akosthekiss akosthekiss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second set of comments. I got 20 of the 30 files covered now.

@@ -148,6 +148,9 @@ bool JERRY_ATTR_CONST ecma_is_value_true (ecma_value_t value);
bool JERRY_ATTR_CONST ecma_is_value_false (ecma_value_t value);
bool JERRY_ATTR_CONST ecma_is_value_found (ecma_value_t value);
bool JERRY_ATTR_CONST ecma_is_value_array_hole (ecma_value_t value);
#ifndef CONFIG_DISABLE_ES2015_CLASS
bool JERRY_ATTR_CONST ecma_is_value_class (ecma_value_t value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot find this function either implemented or used anywhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, it's a leftover code!

#include "jcontext.h"
#endif /* JERRY_ENABLE_LINE_INFO */
#endif /* defined (JERRY_ENABLE_LINE_INFO) || !defined (CONFIG_DISABLE_ES2015_CLASS) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet another conditional include. I still suggest dropping the guards.

@@ -22,6 +22,14 @@

#ifndef JERRY_DISABLE_JS_PARSER

JERRY_STATIC_ASSERT ((int) ECMA_PARSE_STRICT_MODE == (int) PARSER_IS_STRICT,
ecma_parse_strict_mode_and_parser_is_strict_are_equal);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK the wording of the static assert 'messages' should contain "must", "must be", "should be", "must not", etc. That's because "xxx_and_yyy_are_equal" is somewhat misleading. If the assert is triggered and this text is printed, it's not really clear what the cause of the error is. (The message could suggest that they are equal, while the real problem is that they aren't.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, I'll rename it.


#ifndef CONFIG_DISABLE_ES2015_CLASS
JERRY_STATIC_ASSERT ((ECMA_PARSE_CLASS_CONSTRUCTOR << PARSER_CLASS_PARSE_OPTS_OFFSET) == PARSER_CLASS_CONSTRUCTOR,
ecma_class_parse_options_can_be_shifted_to_ecma_general_flags);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same static assert message problem here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

must_throw ("class B extends A { constructor (a, b) { this.b = b} } \
var b = new B (1,2);");

must_throw ("class B extends A { constructor (a,b) { super.f() } } \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Args should be comma+space-separated. That one extra space is not a big price for readability. Also when calling a function (above, new B (1,2)). Throughout this file.

}

class B extends A {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this empty line needed?

}

var d = new D;
assert (Object.getPrototypeOf(d) == D.prototype);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, this test file is huge. The problem with that is that it's full with asserts and if this test fails, it becomes hard to find which part is problematic. I think it should be possible to split up this file into smaller ones that test fewer functionalities.

Copy link
Member Author

@rerobika rerobika Oct 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about splitting the tests file into:

  • class-inheritance-early-semantics.js (must throw part)
  • class-inheritance-main.js (core functionalities)
  • class-inheritance-builtin-extends.js(specific behaviour with Array / %Typedarray%)
  • class-inheritance-mixins.js (Mix-ins + bound functions)

(Also with the unified style)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good as a start.

@@ -68,7 +68,11 @@ typedef enum
PARSER_ARROW_PARSE_ARGS = (1u << 19), /**< parse the argument list of an arrow function */
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
#ifndef CONFIG_DISABLE_ES2015_CLASS
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed */
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed. NOTE: this value must be kept in
* in sync with ECMA_PARSE_CLASS_CONSTRUCTOR */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just found PARSER_CLASS_PARSE_OPTS_OFFSET. It should be referenced in the comment (or perhaps in a comment inserted before PARSER_CLASS_CONSTRUCTOR to emphasise that the following enumerators form a group and have to be treated together).

/**
* Mask for get class option bits from ecma_parse_opts_t
*/
#define PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK 0x1C
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a way to specify a static assert for this, otherwise this will become a fragile hard-coded constant.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still thinking on a proper static assert for this...

Copy link
Member

@akosthekiss akosthekiss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Third set of comments. Got through all files now.

@@ -24,6 +24,9 @@
#include "ecma-number-arithmetic.h"
#include "ecma-objects.h"
#include "ecma-objects-general.h"
#ifndef CONFIG_DISABLE_ES2015_CLASS
#include "ecma-function-object.h"
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conditional include, guards to be dropped.


ecma_deref_object (proto_p);

ecma_object_t *constructor_prototpye_object_p = ecma_get_object_from_value (constructor_prototype);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: constructor_prototpye_object_p -> constructor_prototype_object_p

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I didn't notice it.

ecma_free_value (obj_this);
return new_array;
}
#else /* CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_array = ecma_op_create_array_object (0, 0, false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's interesting that the old code never checks for error although ecma_op_create_array_object may raise errors. But only if length was invalid, which is known not to happen for the hard-coded params. A JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); might still have its place here to signal that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, an assert never hurts.

@@ -223,7 +223,18 @@ ecma_builtin_array_prototype_object_concat (ecma_value_t this_arg, /**< this arg
ret_value);

/* 2. */
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (0, 0, false, obj_p);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First argument is of type ecma_value_t *arguments_list_p, so NULL would be a better fit here instead of the 0. (The old code might also be improved.)

if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as

#ifndef CONFIG_DISABLE_ES2015_CLASS
        if ((context_p->status_flags & constructor_super) != constructor_super)
        {
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
          if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
          {
            context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL;
          }
#ifndef CONFIG_DISABLE_ES2015_CLASS
        }
#endif /* !CONFIG_DISABLE_ES2015_CLASS */

or

        if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
        {
#ifndef CONFIG_DISABLE_ES2015_CLASS
          if ((context_p->status_flags & constructor_super) != constructor_super)
          {
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
            context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL;
#ifndef CONFIG_DISABLE_ES2015_CLASS
          }
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
        }

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like such constructs. So hard to read.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I don't like copy-paste cloning. And the above pattern makes the code more future-proof in the sense that should we ever change the config macro infrastructure from #ifdef ENABLE/#ifndef DISABLE to #if 1 (i.e., making decisions not based on whether a macro is defined but based on its value) then the above pattern can be easily recognized and simplified into and if with a simple predicate:

if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL
    && (!CONFIG_ES2015_CLASS || (context_p->status_flags & constructor_super) != constructor_super))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the advantages/disadvantages of both styles. How about summoning @LaszloLango and @robertsipka to ask their opinions?

The question is:

#ifndef CONFIG_DISABLE_ES2015_XXX
  if (// New condition)
  {
    // New code path
  }
  else 
  {
    // Old code path
  }
#else /* CONFIG_DISABLE_ES2015_XXX */
  // Old code path
#endif /* !CONFIG_DISABLE_ES2015_XXX */

vs.

#ifndef CONFIG_DISABLE_ES2015_XXX
  if (// New condition)
  {
    // New code path
  }
  else
  {
#endif /* !CONFIG_DISABLE_ES2015_XXX */
    // Old code path
#ifndef CONFIG_DISABLE_ES2015_XXX
  }
#endif /* !CONFIG_DISABLE_ES2015_XXX */

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the second one without code duplication.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first one is easier to read, but eliminate the code duplication has priority (+1 for the second).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the answers, I'll use the 2nd style.

@@ -1970,22 +2036,59 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
}

lexer_next_token (context_p);

#ifndef CONFIG_DISABLE_ES2015_CLASS
uint32_t constructor_super = PARSER_CLASS_CONSTRUCTOR | PARSER_CLASS_HAS_SUPER;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this const so that it doesn't get modified by mistake, and move it before the switch so that it doesn't have to be defined multiple times (as around line 2194). Or make this something like a #define PARSER_CLASS_CONSTRUCTOR_SUPER (PARSER_CLASS_CONSTRUCTOR | PARSER_CLASS_HAS_SUPER) if the value is used multiple times, as in js-parser.c.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#define PARSER_CLASS_CONSTRUCTOR_SUPER (PARSER_CLASS_CONSTRUCTOR | PARSER_CLASS_HAS_SUPER) is a good idea.

@rerobika
Copy link
Member Author

rerobika commented Oct 9, 2018

@akosthekiss Thanks for the deep review. Let me apply a part of your suggestions first (I mean the trivial ones) then talk about the rest.

@rerobika rerobika force-pushed the es2015_class_part_II branch from 8b6584b to c54f440 Compare October 9, 2018 13:49
@rerobika
Copy link
Member Author

rerobika commented Oct 9, 2018

Patch is updated to see what have been resolved. Still working on it.

@rerobika rerobika force-pushed the es2015_class_part_II branch 4 times, most recently from f72e2f8 to 61b4070 Compare October 11, 2018 10:27
@rerobika
Copy link
Member Author

@akosthekiss The patch has been updated!

ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addition is not consistent with the previous approaches: there is no assertion check for no error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff does not show it but there was an already existing assert for it in the next line. Anyway, I move it up to the else/endif block.

ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

this.g = super.f;
this.h = this.f;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional that A and B are redefined over and over again in the same test file with slightly different content? All redefinitions seem to be potential test file splitting points.

must_throw ("class A extends { constructor () { super () } }");

class B extends A {
constructor (a,b) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add space after comma

}
}
var b = new B (1, 2);
assert (b.g ()()() === 5);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that these two checks could be merged. Constructors are the same (assert can be kept), object is instantiated the same way in both cases. Only the second g () has to be renamed (e.g., to h ()), and then this assert has to be rewritten as b.h ()()() === 5. If I get it right.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, let's merge them.


var b = new B ();
assert (b.f () === 1)
assert (b.g () === 2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

potential splitting point? (independent tests before and after)

}
}

new C ().foo ()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

potential splitting point?

@rerobika rerobika force-pushed the es2015_class_part_II branch from 61b4070 to fcebdfc Compare October 18, 2018 12:09
@rerobika
Copy link
Member Author

@akosthekiss Your suggestions have been applied!

class A {
constructor () {
this.a = 5;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strange indentation

assert (b.f === 5);
assert (b.length === 3);

class A extends Array {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the redefinition of A intentional here?


var b = new B ();
assert (b.f () === 1)
assert (b.g () === 2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

splitting point?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let it be.

@rerobika rerobika force-pushed the es2015_class_part_II branch from fcebdfc to a5d4211 Compare October 18, 2018 15:53

assert (D.a () === 6);

class A extends Array {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like a leftover in this test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Thanks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Thanks.

* limitations under the License.
*/

var g = Array.bind (0, 1, 2, 3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: why is this test file named "bounds"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason is that implicit class constructors are really similar to bound functions. But let's rename it only to -bound.js, hence it only includes one test case.

@rerobika rerobika force-pushed the es2015_class_part_II branch from a5d4211 to 481f83b Compare October 25, 2018 09:18
This patch is the second milestone of the implementation of this new language element.

Supported:
 - Single class inheritance
 - Functionality of 'super' keyword
 - Implicit constructor in class heritage
 - Specific behaviour while extending with the built-in 'Array' or '%TypedArray%' object
 - Abstract subclasses (Mix-ins)

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik [email protected]
@rerobika rerobika force-pushed the es2015_class_part_II branch from 481f83b to 7eac228 Compare October 25, 2018 11:31
@rerobika
Copy link
Member Author

@akosthekiss The PR is updated as you suggested.

Copy link
Member

@akosthekiss akosthekiss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. That was quite some work.

@akosthekiss akosthekiss merged commit d1860d0 into jerryscript-project:master Oct 25, 2018
kisbg pushed a commit to kisbg/jerryscript that referenced this pull request Nov 5, 2018
This patch is the second milestone of the implementation of this new language element.

Supported:
 - Single class inheritance
 - Functionality of 'super' keyword
 - Implicit constructor in class heritage
 - Specific behaviour while extending with the built-in 'Array' or '%TypedArray%' object
 - Abstract subclasses (Mix-ins)

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik [email protected]
kisbg pushed a commit to kisbg/jerryscript that referenced this pull request Nov 5, 2018
This patch is the second milestone of the implementation of this new language element.

Supported:
 - Single class inheritance
 - Functionality of 'super' keyword
 - Implicit constructor in class heritage
 - Specific behaviour while extending with the built-in 'Array' or '%TypedArray%' object
 - Abstract subclasses (Mix-ins)

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik [email protected]
kisbg pushed a commit to kisbg/jerryscript that referenced this pull request Nov 6, 2018
This patch is the second milestone of the implementation of this new language element.

Supported:
 - Single class inheritance
 - Functionality of 'super' keyword
 - Implicit constructor in class heritage
 - Specific behaviour while extending with the built-in 'Array' or '%TypedArray%' object
 - Abstract subclasses (Mix-ins)

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik [email protected]
legendecas added a commit to yodaos-project/ShadowNode that referenced this pull request Nov 29, 2018
@rerobika rerobika deleted the es2015_class_part_II branch February 28, 2019 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ES2015 Related to ES2015 features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants