Implement ES2015 class feature (part II.) (#2439)

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 frobert@inf.u-szeged.hu
This commit is contained in:
Robert Fancsik 2018-10-25 16:00:48 +02:00 committed by Akos Kiss
parent e0e6363f85
commit d1860d0e34
54 changed files with 2543 additions and 199 deletions

View File

@ -195,7 +195,7 @@ ecma_gc_mark_property (ecma_property_pair_t *property_pair_p, /**< property pair
case ECMA_PROPERTY_TYPE_INTERNAL:
{
JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC
&& property_pair_p->names_cp[index] == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
&& property_pair_p->names_cp[index] >= LIT_FIRST_INTERNAL_MAGIC_STRING);
break;
}
default:

View File

@ -82,12 +82,19 @@ typedef enum
/**
* Option flags for script parsing.
* Note:
* The enum members must be kept in sync with parser_general_flags_t
*/
typedef enum
{
ECMA_PARSE_NO_OPTS = 0, /**< no options passed */
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), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */
/* These three status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 2), /**< a class constructor is being parsed (this value must be kept in
* in sync with PARSER_CLASS_CONSTRUCTOR) */
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 */
} ecma_parse_opts_t;
/**
@ -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_CONSTRUCTOR = ECMA_MAKE_VALUE (9), /**< special value for bound class constructors */
};
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32
@ -397,6 +405,12 @@ typedef enum
#define ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY(property_p) \
*(property_p) = (uint8_t) (*(property_p) + (ECMA_PROPERTY_TYPE_INTERNAL - ECMA_PROPERTY_TYPE_NAMEDDATA))
/**
* Convert internal property to data property.
*/
#define ECMA_CONVERT_INTERNAL_PROPERTY_TO_DATA_PROPERTY(property_p) \
*(property_p) = (uint8_t) (*(property_p) - (ECMA_PROPERTY_TYPE_INTERNAL - ECMA_PROPERTY_TYPE_NAMEDDATA))
/**
* Special property identifiers.
*/
@ -633,12 +647,42 @@ 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 */
ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND /**< maximum value */
* environment type */
ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND /**< maximum value */
} ecma_lexical_environment_type_t;
/**
* Offset for JERRY_CONTEXT (status_flags) top 8 bits.
*/
#define ECMA_SUPER_EVAL_OPTS_OFFSET (32 - 8)
/**
* Set JERRY_CONTEXT (status_flags) top 8 bits to the specified 'opts'.
*/
#define ECMA_SET_SUPER_EVAL_PARSER_OPTS(opts) \
do \
{ \
JERRY_CONTEXT (status_flags) |= ((uint32_t) opts << ECMA_SUPER_EVAL_OPTS_OFFSET) | ECMA_STATUS_DIRECT_EVAL; \
} while (0)
/**
* Get JERRY_CONTEXT (status_flags) top 8 bits.
*/
#define ECMA_GET_SUPER_EVAL_PARSER_OPTS() (JERRY_CONTEXT (status_flags) >> ECMA_SUPER_EVAL_OPTS_OFFSET)
/**
* Clear JERRY_CONTEXT (status_flags) top 8 bits.
*/
#define ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS() \
do \
{ \
JERRY_CONTEXT (status_flags) &= ((1 << ECMA_SUPER_EVAL_OPTS_OFFSET) - 1); \
} while (0)
/**
* Ecma object type mask for getting the object type.
*/

View File

@ -127,7 +127,7 @@ ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p) /**< outer
/**
* Create a object lexical environment with specified outer lexical environment
* (or NULL if the environment is not nested), binding object and provideThis flag.
* (or NULL if the environment is not nested), binding object and provided type flag.
*
* See also: ECMA-262 v5, 10.2.1.2
*
@ -137,16 +137,22 @@ ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p) /**< outer
*/
ecma_object_t *
ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, /**< outer lexical environment */
ecma_object_t *binding_obj_p) /**< binding object */
ecma_object_t *binding_obj_p, /**< binding object */
ecma_lexical_environment_type_t type) /**< type of the new lexical environment */
{
#ifndef CONFIG_DISABLE_ES2015_CLASS
JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND
|| type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
#else /* CONFIG_DISABLE_ES2015_CLASS */
JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
JERRY_ASSERT (binding_obj_p != NULL
&& !ecma_is_lexical_environment (binding_obj_p));
ecma_object_t *new_lexical_environment_p = ecma_alloc_object ();
uint16_t type = ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND;
new_lexical_environment_p->type_flags_refs = type;
new_lexical_environment_p->type_flags_refs = (uint16_t) (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | type);
ecma_init_gc_info (new_lexical_environment_p);
@ -355,7 +361,12 @@ 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));
#ifndef CONFIG_DISABLE_ES2015
JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND
|| ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
#else /* CONFIG_DISABLE_ES2015 */
JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
#endif /* !CONFIG_DISABLE_ES2015 */
return ECMA_GET_NON_NULL_POINTER (ecma_object_t,
object_p->property_list_or_bound_object_cp);
@ -766,7 +777,7 @@ ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to
/* Must be a native pointer. */
JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC
&& (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER));
&& name_cp >= LIT_FIRST_INTERNAL_MAGIC_STRING);
break;
}
}

View File

@ -293,7 +293,8 @@ 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,
ecma_lexical_environment_type_t type);
bool JERRY_ATTR_PURE ecma_is_lexical_environment (const ecma_object_t *object_p);
bool JERRY_ATTR_PURE ecma_get_object_extensible (const ecma_object_t *object_p);
void ecma_set_object_extensible (ecma_object_t *object_p, bool is_extensible);

View File

@ -223,7 +223,20 @@ ecma_builtin_array_prototype_object_concat (ecma_value_t this_arg, /**< this arg
ret_value);
/* 2. */
ecma_value_t new_array = ecma_op_create_array_object (0, 0, false);
#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 (NULL, 0, false, obj_p);
if (ECMA_IS_VALUE_ERROR (new_array))
{
ecma_free_value (obj_this);
return new_array;
}
#else /* CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
uint32_t new_length = 0;
@ -825,7 +838,20 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t this_arg, /**< 'this' ar
JERRY_ASSERT (start <= len && end <= len);
ecma_value_t new_array = ecma_op_create_array_object (0, 0, false);
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
if (ECMA_IS_VALUE_ERROR (new_array))
{
ecma_free_value (len_value);
ecma_free_value (obj_this);
return new_array;
}
#else /* CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
/* 9. */
@ -1178,7 +1204,20 @@ ecma_builtin_array_prototype_object_splice (ecma_value_t this_arg, /**< this arg
const uint32_t len = ecma_number_to_uint32 (len_number);
ecma_value_t new_array = ecma_op_create_array_object (0, 0, false);
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
if (ECMA_IS_VALUE_ERROR (new_array))
{
ecma_free_value (len_value);
ecma_free_value (obj_this);
return new_array;
}
#else /* CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
uint32_t start = 0;
@ -1973,8 +2012,20 @@ ecma_builtin_array_prototype_object_map (ecma_value_t this_arg, /**< this argume
/* 5. arg2 is simply used as T */
/* 6. */
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
if (ECMA_IS_VALUE_ERROR (new_array))
{
ecma_free_value (len_value);
ecma_free_value (obj_this);
return new_array;
}
#else /* CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
/* 7-8. */
@ -2080,8 +2131,20 @@ ecma_builtin_array_prototype_object_filter (ecma_value_t this_arg, /**< this arg
ecma_object_t *func_object_p;
/* 6. */
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
if (ECMA_IS_VALUE_ERROR (new_array))
{
ecma_free_value (len_value);
ecma_free_value (obj_this);
return new_array;
}
#else /* CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
/* We already checked that arg1 is callable, so it will always be an object. */

View File

@ -24,6 +24,7 @@
#include "ecma-number-arithmetic.h"
#include "ecma-objects.h"
#include "ecma-objects-general.h"
#include "ecma-function-object.h"
/** \addtogroup ecma ECMA
* @{
@ -43,14 +44,14 @@
*/
ecma_value_t
ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of arguments that
are passed to Array constructor */
* are passed to Array constructor */
ecma_length_t arguments_list_len, /**< length of the arguments' list */
bool is_treat_single_arg_as_length) /**< if the value is true,
arguments_list_len is 1
and single argument is Number,
then treat the single argument
as new Array's length rather
than as single item of the Array */
* arguments_list_len is 1
* and single argument is Number,
* then treat the single argument
* as new Array's length rather
* than as single item of the Array */
{
JERRY_ASSERT (arguments_list_len == 0
|| arguments_list_p != NULL);
@ -131,6 +132,68 @@ 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 with custom prototype.
*
* See also: ECMA-262 v6, 9.4.2.3
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
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 */
ecma_length_t arguments_list_len, /**< length of the arguments' list */
bool is_treat_single_arg_as_length, /**< if the value is true,
* arguments_list_len is 1
* and single argument is Number,
* then treat the single argument
* as new Array's length rather
* than as single item of the
* Array */
ecma_object_t *object_p) /**< The object from whom the new array object
* is being created */
{
ecma_value_t constructor_value = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_CONSTRUCTOR);
if (ECMA_IS_VALUE_ERROR (constructor_value)
|| !ecma_is_value_object (constructor_value)
|| !ecma_is_constructor (constructor_value))
{
ecma_free_value (constructor_value);
return ecma_raise_type_error (ECMA_ERR_MSG ("object.constructor is not a constructor."));
}
ecma_object_t *constructor_object_p = ecma_get_object_from_value (constructor_value);
ecma_value_t constructor_prototype = ecma_op_object_get_by_magic_id (constructor_object_p,
LIT_MAGIC_STRING_PROTOTYPE);
ecma_deref_object (constructor_object_p);
if (ECMA_IS_VALUE_ERROR (constructor_prototype))
{
return constructor_prototype;
}
ecma_value_t result = ecma_op_create_array_object (arguments_list_p,
arguments_list_len,
is_treat_single_arg_as_length);
if (ecma_is_value_object (constructor_prototype))
{
ecma_object_t *result_object_p = ecma_get_object_from_value (result);
ecma_object_t *constructor_prototpye_object_p = ecma_get_object_from_value (constructor_prototype);
ECMA_SET_POINTER (result_object_p->prototype_or_outer_reference_cp, constructor_prototpye_object_p);
}
ecma_free_value (constructor_prototype);
return result;
} /* ecma_op_create_array_object_by_constructor */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* Update the length of an array to a new length
*

View File

@ -43,6 +43,12 @@ ecma_value_t
ecma_op_create_array_object (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len,
bool is_treat_single_arg_as_length);
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_value_t
ecma_op_create_array_object_by_constructor (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len,
bool is_treat_single_arg_as_length, ecma_object_t *object_p);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t
ecma_op_array_object_set_length (ecma_object_t *object_p, ecma_value_t new_value, uint32_t flags);

View File

@ -22,10 +22,7 @@
#include "ecma-lex-env.h"
#include "js-parser.h"
#include "vm.h"
#ifdef JERRY_ENABLE_LINE_INFO
#include "jcontext.h"
#endif /* JERRY_ENABLE_LINE_INFO */
/** \addtogroup ecma ECMA
* @{
@ -98,6 +95,12 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b
JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
#endif /* JERRY_ENABLE_LINE_INFO */
#ifndef CONFIG_DISABLE_ES2015_CLASS
parse_opts |= ECMA_GET_SUPER_EVAL_PARSER_OPTS ();
ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS ();
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t parse_status = parser_parse_script (NULL,
0,
code_p,

View File

@ -453,12 +453,165 @@ ecma_op_function_has_construct_flag (const ecma_value_t *arguments_list_p) /**<
{
#ifndef CONFIG_DISABLE_ES2015_CLASS
return (((uintptr_t) arguments_list_p) & ECMA_CLASS_CONSTRUCT_FLAG);
#else
#else /* CONFIG_DISABLE_ES2015_CLASS */
JERRY_UNUSED (arguments_list_p);
return false;
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
} /* ecma_op_function_has_construct_flag */
#ifndef CONFIG_DISABLE_ES2015
/**
* Returns the closest declarative lexical enviroment to the super object bound lexical enviroment.
*
* @return the found lexical enviroment
*/
static ecma_object_t *
ecma_op_find_super_declerative_lex_env (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
{
JERRY_ASSERT (lex_env_p);
JERRY_ASSERT (ecma_op_resolve_super_reference_value (lex_env_p));
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) != ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
while (true)
{
ecma_object_t *lex_env_outer_p = ecma_get_lex_env_outer_reference (lex_env_p);
JERRY_ASSERT (lex_env_outer_p);
if (ecma_get_lex_env_type (lex_env_outer_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND)
{
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
return lex_env_p;
}
lex_env_p = lex_env_outer_p;
}
} /* ecma_op_find_super_declerative_lex_env */
/**
* Returns with the current class this_binding property
*
* @return NULL - if the property was not found
* the found property - otherwise
*/
static ecma_property_t *
ecma_op_get_class_this_binding_property (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
{
JERRY_ASSERT (lex_env_p);
JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p));
lex_env_p = ecma_op_find_super_declerative_lex_env (lex_env_p);
ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING);
return ecma_find_named_property (lex_env_p, name_p);
} /* ecma_op_get_class_this_binding_property */
/**
* Checks whether the 'super(...)' has been called.
*
* @return true - if the 'super (...)' has been called
* false - otherwise
*/
inline bool JERRY_ATTR_PURE
ecma_op_is_super_called (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
{
ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p);
JERRY_ASSERT (property_p);
return (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
} /* ecma_op_is_super_called */
/**
* Sets the value of 'super(...)' has been called.
*/
inline void
ecma_op_set_super_called (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
{
ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p);
JERRY_ASSERT (property_p);
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
ECMA_CONVERT_INTERNAL_PROPERTY_TO_DATA_PROPERTY (property_p);
} /* ecma_op_set_super_called */
/**
* Sets the class context this_binding value.
*/
void
ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, /**< starting lexical enviroment */
ecma_value_t this_binding) /**< 'this' argument's value */
{
JERRY_ASSERT (ecma_is_value_object (this_binding));
ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p);
ecma_property_value_t *value_p;
if (property_p)
{
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
}
else
{
ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING);
value_p = ecma_create_named_data_property (lex_env_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p);
ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p);
}
value_p->value = this_binding;
} /* ecma_op_set_class_this_binding */
/**
* Gets the class context this binding value.
*
* @return the class context this binding value
*/
ecma_value_t
ecma_op_get_class_this_binding (ecma_object_t *lex_env_p) /**< starting lexical enviroment */
{
ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p);
JERRY_ASSERT (property_p);
ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
JERRY_ASSERT (ecma_is_value_object (value_p->value));
return value_p->value;
} /* ecma_op_get_class_this_binding */
/**
* Dummy external function for implicit constructor call.
*
* @return ECMA_VALUE_ERROR - TypeError
*/
ecma_value_t
ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< the function itself */
const ecma_value_t this_val, /**< this_arg of the function */
const ecma_value_t args_p[], /**< argument list */
const ecma_length_t args_count) /**< argument number */
{
JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count);
return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
} /* ecma_op_function_implicit_constructor_handler_cb */
/**
* Sets the completion value [[Prototype]] based on the this_arg value
*/
void
ecma_op_set_class_prototype (ecma_value_t completion_value, /**< completion_value */
ecma_value_t this_arg) /**< this argument*/
{
JERRY_ASSERT (ecma_is_value_object (completion_value));
JERRY_ASSERT (ecma_is_value_object (this_arg));
ecma_object_t *completion_obj_p = ecma_get_object_from_value (completion_value);
ecma_object_t *prototype_obj_p = ecma_get_object_prototype (ecma_get_object_from_value (this_arg));
JERRY_ASSERT (prototype_obj_p);
ECMA_SET_POINTER (completion_obj_p->prototype_or_outer_reference_cp, prototype_obj_p);
} /* ecma_op_set_class_prototype */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* [[Call]] implementation for Function objects,
* created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION)
@ -484,6 +637,8 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
ecma_object_type_t func_type = ecma_get_object_type (func_obj_p);
JERRY_ASSERT (func_type == ECMA_OBJECT_TYPE_FUNCTION
|| func_type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION
|| func_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION
|| !ecma_op_function_has_construct_flag (arguments_list_p));
if (func_type == ECMA_OBJECT_TYPE_FUNCTION)
@ -507,21 +662,20 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
/* 8. */
ecma_value_t this_binding = this_arg_value;
bool free_this_binding = false;
bool is_strict;
bool is_no_lex_env;
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p);
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR &&
!ecma_op_function_has_construct_flag (arguments_list_p))
bool is_class_constructor = bytecode_data_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR;
if (is_class_constructor && !ecma_op_function_has_construct_flag (arguments_list_p))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false;
is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false;
bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false;
bool is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false;
/* 1. */
if (!is_strict)
@ -561,6 +715,12 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
arguments_list_len,
bytecode_data_p);
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (JERRY_UNLIKELY (is_class_constructor))
{
ecma_op_set_class_this_binding (local_env_p, this_binding);
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
ecma_value_t ret_value = vm_run (bytecode_data_p,
@ -658,7 +818,26 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
if (!ecma_is_value_integer_number (args_len_or_this))
{
this_arg_value = args_len_or_this;
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (JERRY_UNLIKELY (args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR))
{
if (!ecma_op_function_has_construct_flag (arguments_list_p))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
}
if (ecma_get_object_is_builtin (target_func_obj_p))
{
arguments_list_p = ecma_op_function_clear_construct_flag (arguments_list_p);
}
}
else
{
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
this_arg_value = args_len_or_this;
#ifndef CONFIG_DISABLE_ES2015_CLASS
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
args_length = 1;
}
else
@ -675,6 +854,11 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
continue;
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
arguments_list_p = ecma_op_function_clear_construct_flag (arguments_list_p);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p));
args_length--;
ecma_length_t merged_args_list_len = args_length + arguments_list_len;
@ -721,12 +905,13 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
JERRY_ASSERT (ecma_is_value_object (this_arg_value)
|| this_arg_value == ECMA_VALUE_UNDEFINED);
ecma_object_t *target_func_obj_p = NULL;
while (JERRY_UNLIKELY (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION))
{
/* 1-3. */
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
ecma_object_t *target_func_obj_p;
target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_function_p->u.bound_function.target_function);
@ -742,9 +927,15 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
JERRY_ASSERT (args_length > 0);
/* 5. */
if (args_length == 1)
{
/* 5. */
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR && ecma_is_value_undefined (this_arg_value))
{
break;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
func_obj_p = target_func_obj_p;
continue;
}
@ -787,9 +978,18 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
return ecma_raise_type_error (ECMA_ERR_MSG ("Built-in routines have no constructor."));
}
return ecma_builtin_dispatch_construct (func_obj_p,
arguments_list_p,
arguments_list_len);
ecma_value_t ret_value = ecma_builtin_dispatch_construct (func_obj_p,
arguments_list_p,
arguments_list_len);
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (!ecma_is_value_undefined (this_arg_value) && !ECMA_IS_VALUE_ERROR (ret_value))
{
ecma_op_set_class_prototype (ret_value, this_arg_value);
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
return ret_value;
}
ecma_object_t *new_this_obj_p = NULL;
@ -843,10 +1043,33 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
arguments_list_len);
break;
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p));
JERRY_ASSERT (target_func_obj_p != NULL);
ret_value = ecma_op_function_construct (target_func_obj_p,
this_arg_value,
arguments_list_p,
arguments_list_len);
break;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
default:
{
JERRY_ASSERT (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
if (ext_func_obj_p->u.external_handler_cb == ecma_op_function_implicit_constructor_handler_cb)
{
ret_value = ECMA_VALUE_UNDEFINED;
break;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ret_value = ecma_op_function_call (func_obj_p,
this_arg_value,
arguments_list_p,

View File

@ -46,6 +46,29 @@ ecma_op_create_external_function_object (ecma_external_handler_t handler_cb);
const ecma_compiled_code_t *
ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p);
#ifndef CONFIG_DISABLE_ES2015_CLASS
void
ecma_op_set_super_called (ecma_object_t *lex_env_p);
bool
ecma_op_is_super_called (ecma_object_t *lex_env_p);
void
ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, ecma_value_t this_binding);
ecma_value_t
ecma_op_get_class_this_binding (ecma_object_t *lex_env_p);
ecma_value_t
ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj,
const ecma_value_t this_val,
const ecma_value_t args_p[],
const ecma_length_t args_count);
void
ecma_op_set_class_prototype (ecma_value_t completion_value, ecma_value_t this_arg);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
const ecma_compiled_code_t *
ecma_op_arrow_function_get_compiled_code (ecma_arrow_function_t *arrow_function_p);

View File

@ -41,7 +41,9 @@ ecma_init_global_lex_env (void)
{
ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL);
JERRY_CONTEXT (ecma_global_lex_env_p) = ecma_create_object_lex_env (NULL, glob_obj_p);
JERRY_CONTEXT (ecma_global_lex_env_p) = ecma_create_object_lex_env (NULL,
glob_obj_p,
ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ecma_deref_object (glob_obj_p);
} /* ecma_init_global_lex_env */
@ -86,7 +88,9 @@ ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */
JERRY_ASSERT (lex_env_p != NULL
&& ecma_is_lexical_environment (lex_env_p));
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p);
if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
@ -94,7 +98,12 @@ ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */
}
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_THIS_OBJECT_BOUND
|| lex_env_type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
#else /* CONFIG_DISABLE_ES2015_CLASS */
JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);

View File

@ -59,6 +59,29 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical
return NULL;
} /* ecma_op_resolve_reference_base */
#ifndef CONFIG_DISABLE_ES2015_CLASS
/**
* Resolve super reference.
*
* @return value of the reference
*/
ecma_object_t *
ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p) /**< starting lexical environment */
{
while (true)
{
JERRY_ASSERT (lex_env_p != NULL);
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND)
{
return ecma_get_lex_env_binding_object (lex_env_p);
}
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
}
} /* ecma_op_resolve_super_reference_value */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* Resolve value corresponding to reference.
*
@ -72,7 +95,9 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical
while (lex_env_p != NULL)
{
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p);
if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
@ -81,10 +106,8 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical
return ecma_fast_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
}
}
else
else if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
{
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
#ifndef CONFIG_ECMA_LCACHE_DISABLE
@ -120,6 +143,14 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical
return prop_value;
}
}
else
{
#ifndef CONFIG_DISABLE_ES2015_CLASS
JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
#else /* CONFIG_DISABLE_ES2015_CLASS */
JERRY_UNREACHABLE ();
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
}

View File

@ -28,6 +28,9 @@
ecma_object_t *ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, ecma_string_t *name_p);
ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, ecma_string_t *name_p);
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_object_t *ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* @}

View File

@ -257,7 +257,7 @@ ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< leng
ecma_free_value (new_arraybuffer_p);
return ecma_make_object_value (object_p);
} /* !ecma_typedarray_create_object_with_length */
} /* ecma_typedarray_create_object_with_length */
/**
* Create a TypedArray object by given buffer, offset, and array_length
@ -984,6 +984,31 @@ ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p, /**< Typed
}
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_value_t constructor_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_CONSTRUCTOR);
if (ECMA_IS_VALUE_ERROR (constructor_value)
|| !ecma_is_value_object (constructor_value)
|| !ecma_is_constructor (constructor_value))
{
ecma_deref_object (proto_p);
ecma_free_value (constructor_value);
return ecma_raise_type_error (ECMA_ERR_MSG ("object.constructor is not a constructor."));
}
ecma_object_t *constructor_object_p = ecma_get_object_from_value (constructor_value);
ecma_value_t constructor_prototype = ecma_op_object_get_by_magic_id (constructor_object_p,
LIT_MAGIC_STRING_PROTOTYPE);
ecma_deref_object (constructor_object_p);
if (ECMA_IS_VALUE_ERROR (constructor_prototype))
{
ecma_deref_object (proto_p);
return constructor_prototype;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
ecma_value_t new_obj = ecma_typedarray_create_object_with_length (array_length,
proto_p,
element_size_shift,
@ -991,6 +1016,14 @@ ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p, /**< Typed
ecma_deref_object (proto_p);
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_object_t *constructor_prototype_object_p = ecma_get_object_from_value (constructor_prototype);
ecma_object_t *new_obj_p = ecma_get_object_from_value (new_obj);
ECMA_SET_POINTER (new_obj_p->prototype_or_outer_reference_cp, constructor_prototype_object_p);
ecma_deref_object (constructor_prototype_object_p);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
return new_obj;
} /* ecma_op_create_typedarray_with_type_and_length */

View File

@ -30,7 +30,7 @@ extern "C"
/**
* Jerry snapshot format version.
*/
#define JERRY_SNAPSHOT_VERSION (18u)
#define JERRY_SNAPSHOT_VERSION (19u)
/**
* Flags for jerry_generate_snapshot and jerry_generate_function_snapshot.

View File

@ -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 (the top 8 bits are used for passing class parsing options) */
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
uint8_t ecma_prop_hashmap_alloc_state; /**< property hashmap allocation state: 0-4,

View File

@ -151,4 +151,13 @@ void JERRY_ATTR_NORETURN jerry_fatal (jerry_fatal_code_t code);
#define JERRY_MIN(v1, v2) (((v1) < (v2)) ? (v1) : (v2))
#define JERRY_MAX(v1, v2) (((v1) < (v2)) ? (v2) : (v1))
/**
* Calculate the index of the first non-zero bit of a 32 bit integer value
*/
#define JERRY__LOG2_1(n) (((n) >= 2) ? 1 : 0)
#define JERRY__LOG2_2(n) (((n) >= 1 << 2) ? (2 + JERRY__LOG2_1 ((n) >> 2)) : JERRY__LOG2_1 (n))
#define JERRY__LOG2_4(n) (((n) >= 1 << 4) ? (4 + JERRY__LOG2_2 ((n) >> 4)) : JERRY__LOG2_2 (n))
#define JERRY__LOG2_8(n) (((n) >= 1 << 8) ? (8 + JERRY__LOG2_4 ((n) >> 8)) : JERRY__LOG2_4 (n))
#define JERRY_LOG2(n) (((n) >= 1 << 16) ? (16 + JERRY__LOG2_8 ((n) >> 16)) : JERRY__LOG2_8 (n))
#endif /* !JRT_H */

View File

@ -52,6 +52,9 @@ typedef enum
* deleted properties */
LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer info associated with an object */
LIT_FIRST_INTERNAL_MAGIC_STRING = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of internal
* magic strings */
LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING, /**< the this binding of the class constructor */
LIT_MAGIC_STRING__COUNT /**< number of magic strings */
} lit_magic_string_id_t;

View File

@ -64,13 +64,29 @@
#define CBC_HAS_POP_STACK_BYTE_ARG (CBC_HAS_BYTE_ARG | CBC_POP_STACK_BYTE_ARG)
#ifndef CONFIG_DISABLE_ES2015_CLASS
/**
* Checks whether the current opcode is a super constructor call
*/
#define CBC_SUPER_CALL_OPERATION(opcode) \
((opcode) >= PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL) \
&& (opcode) <= PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL_BLOCK))
#else /* CONFIG_DISABLE_ES2015_CLASS */
/**
* Checks whether the current opcode is a super constructor call
*/
#define CBC_SUPER_CALL_OPERATION(opcode) false
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/* Debug macro. */
#define CBC_ARGS_EQ(op, types) \
((cbc_flags[op] & CBC_ARG_TYPES) == (types))
/* Debug macro. */
#define CBC_SAME_ARGS(op1, op2) \
((cbc_flags[op1] & CBC_ARG_TYPES) == (cbc_flags[op2] & CBC_ARG_TYPES))
(CBC_SUPER_CALL_OPERATION (op1) ? ((cbc_ext_flags[PARSER_GET_EXT_OPCODE (op1)] & CBC_ARG_TYPES) \
== (cbc_ext_flags[PARSER_GET_EXT_OPCODE (op2)] & CBC_ARG_TYPES)) \
: ((cbc_flags[op1] & CBC_ARG_TYPES) == (cbc_flags[op2] & CBC_ARG_TYPES)))
#define CBC_UNARY_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, 0, \
@ -143,15 +159,14 @@
* Hence CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode)
* cannot be true for an opcode which has a result
*/
#define CBC_NO_RESULT_OPERATION(opcode) \
((opcode) >= CBC_PRE_INCR && (opcode) < CBC_END)
(((opcode) >= CBC_PRE_INCR && (opcode) < CBC_END) || CBC_SUPER_CALL_OPERATION ((opcode)))
#define CBC_NO_RESULT_BLOCK(opcode) \
((opcode) >= CBC_PRE_INCR && (opcode) < CBC_ASSIGN_ADD)
(((opcode) >= CBC_PRE_INCR && (opcode) < CBC_ASSIGN_ADD) || CBC_SUPER_CALL_OPERATION ((opcode)))
#define CBC_NO_RESULT_COMPOUND_ASSIGMENT(opcode) \
((opcode) >= CBC_ASSIGN_ADD && (opcode) < CBC_END)
((opcode) >= CBC_ASSIGN_ADD && (opcode) < CBC_END && !CBC_SUPER_CALL_OPERATION ((opcode)))
/**
* Branch instructions are organized in group of 8 opcodes.
@ -203,6 +218,8 @@
#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4
/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1
/* PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION 1
/* PARSER_TRY_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_TRY_CONTEXT_STACK_ALLOCATION 2
@ -537,6 +554,10 @@
VM_OC_PUSH_UNDEFINED_BASE | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_EXT_FINALLY, 0, \
VM_OC_FINALLY) \
CBC_OPCODE (CBC_EXT_CLASS_EXPR_CONTEXT_END, CBC_NO_FLAG, 0, \
VM_OC_CLASS_EXPR_CONTEXT_END) \
CBC_FORWARD_BRANCH (CBC_EXT_SUPER_CLASS_CREATE_CONTEXT, \
-1 + PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, VM_OC_CLASS_HERITAGE) \
\
/* Basic opcodes. */ \
CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0, CBC_HAS_LITERAL_ARG, 2, \
@ -570,6 +591,40 @@
CBC_OPCODE (CBC_EXT_SET_STATIC_COMPUTED_SETTER, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_SET_SETTER | VM_OC_GET_STACK_LITERAL) \
\
/* Class opcodes */ \
CBC_OPCODE (CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR, CBC_NO_FLAG, 0, \
VM_OC_CLASS_INHERITANCE) \
CBC_OPCODE (CBC_EXT_PUSH_CLASS_CONSTRUCTOR, CBC_NO_FLAG, 1, \
VM_OC_PUSH_CLASS_CONSTRUCTOR | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL, CBC_NO_FLAG, 0, \
VM_OC_PUSH_IMPL_CONSTRUCTOR) \
CBC_OPCODE (CBC_EXT_SET_CLASS_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_SET_CLASS_CONSTRUCTOR | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_CLASS_EVAL, CBC_HAS_BYTE_ARG, 0, \
VM_OC_CLASS_EVAL) \
CBC_OPCODE (CBC_EXT_SUPER_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \
VM_OC_SUPER_CALL) \
CBC_OPCODE (CBC_EXT_SUPER_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
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_CONSTRUCTOR_SUPER, CBC_NO_FLAG, 1, \
VM_OC_PUSH_CONSTRUCTOR_SUPER | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP, CBC_NO_FLAG, 1, \
VM_OC_PUSH_CONSTRUCTOR_SUPER | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_PUSH_SUPER, CBC_NO_FLAG, 1, \
VM_OC_PUSH_SUPER | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_PUSH_STATIC_SUPER, CBC_NO_FLAG, 1, \
VM_OC_PUSH_SUPER | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_THIS, CBC_NO_FLAG, 1, \
VM_OC_PUSH_CONSTRUCTOR_THIS | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_SUPER_PROP_CALL, CBC_NO_FLAG, 0, \
VM_OC_SUPER_PROP_REFERENCE) \
CBC_OPCODE (CBC_EXT_SUPER_PROP_ASSIGN, CBC_NO_FLAG, 0, \
VM_OC_SUPER_PROP_REFERENCE) \
CBC_OPCODE (CBC_EXT_CONSTRUCTOR_RETURN, CBC_NO_FLAG, -1, \
VM_OC_CONSTRUCTOR_RET | VM_OC_GET_STACK) \
\
/* Binary compound assignment opcodes with pushing the result. */ \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_ADD, \
ADD) \

View File

@ -352,11 +352,23 @@ static const keyword_string_t keyword_length_4[9] =
LEXER_KEYWORD_END ()
};
#ifndef CONFIG_DISABLE_ES2015
/**
* Number of keywords with 5 characters.
*/
#define KEYWORD_LENGTH_COUNT 11
#else /* CONFIG_DISABLE_ES2015 */
#define KEYWORD_LENGTH_COUNT 10
#endif /* !CONFIG_DISABLE_ES2015 */
/**
* Keywords with 5 characters.
*/
static const keyword_string_t keyword_length_5[10] =
static const keyword_string_t keyword_length_5[KEYWORD_LENGTH_COUNT] =
{
#ifndef CONFIG_DISABLE_ES2015
LEXER_KEYWORD ("await", LEXER_KEYW_AWAIT),
#endif /* !CONFIG_DISABLE_ES2015 */
LEXER_KEYWORD ("break", LEXER_KEYW_BREAK),
LEXER_KEYWORD ("catch", LEXER_KEYW_CATCH),
LEXER_KEYWORD ("class", LEXER_KEYW_CLASS),
@ -1310,40 +1322,22 @@ lexer_next_token (parser_context_t *context_p) /**< context */
#undef LEXER_TYPE_D_TOKEN
/**
* Checks whether the next token is a colon.
* Checks whether the next token is the specified character.
*
* @return true - if the next token is a colon
* @return true - if the next is the specified character
* false - otherwise
*/
bool
lexer_check_colon (parser_context_t *context_p) /**< context */
lexer_check_next_character (parser_context_t *context_p, /**< context */
lit_utf8_byte_t character) /**< specified character */
{
lexer_skip_spaces (context_p);
context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
return (context_p->source_p < context_p->source_end_p
&& context_p->source_p[0] == (uint8_t) LIT_CHAR_COLON);
} /* lexer_check_colon */
#ifndef CONFIG_DISABLE_ES2015_CLASS
/**
* Checks whether the next token is a left parenthesis.
*
* @return true - if the next token is a left parenthesis
* false - otherwise
*/
bool
lexer_check_left_paren (parser_context_t *context_p) /**< context */
{
lexer_skip_spaces (context_p);
context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
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 */
&& context_p->source_p[0] == (uint8_t) character);
} /* lexer_check_next_character */
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION

View File

@ -151,29 +151,59 @@ typedef enum
LEXER_SCAN_SWITCH, /**< special value for switch pre-scan */
LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */
#ifdef CONFIG_DISABLE_ES2015
/* Future reserved words: these keywords
* must form a group after all other keywords. */
#define LEXER_FIRST_FUTURE_RESERVED_WORD LEXER_KEYW_CLASS
#endif /* CONFIG_DISABLE_ES2015 */
LEXER_KEYW_CLASS, /**< class */
LEXER_KEYW_ENUM, /**< enum */
LEXER_KEYW_EXTENDS, /**< extends */
LEXER_KEYW_SUPER, /**< super */
LEXER_KEYW_CONST, /**< const */
LEXER_KEYW_EXPORT, /**< export */
LEXER_KEYW_IMPORT, /**< import */
#ifndef CONFIG_DISABLE_ES2015
/* Future reserved words: these keywords
* must form a group after all other keywords.
* Note:
* Tokens from LEXER_KEYW_CLASS to LEXER_KEYW_IMPORT
* are no longer future reserved words in ES2015. */
#define LEXER_FIRST_FUTURE_RESERVED_WORD LEXER_KEYW_ENUM
#endif /* !CONFIG_DISABLE_ES2015 */
LEXER_KEYW_ENUM, /**< enum */
#ifndef CONFIG_DISABLE_ES2015
LEXER_KEYW_AWAIT, /**< await */
#endif /* !CONFIG_DISABLE_ES2015 */
/* Future strict reserved words: these keywords
* must form a group after future reserved words. */
#define LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD LEXER_KEYW_IMPLEMENTS
LEXER_KEYW_IMPLEMENTS, /**< implements */
LEXER_KEYW_LET, /**< let */
LEXER_KEYW_PRIVATE, /**< private */
LEXER_KEYW_PUBLIC, /**< public */
LEXER_KEYW_YIELD, /**< yield */
LEXER_KEYW_INTERFACE, /**< interface */
LEXER_KEYW_PACKAGE, /**< package */
LEXER_KEYW_PROTECTED, /**< protected */
#ifndef CONFIG_DISABLE_ES2015
/* Context dependent strict reserved words:
* See also: ECMA-262 v6, 11.6.2.1 */
#define LEXER_FIRST_CONTEXT_DEPENDENT_RESERVED_WORD LEXER_KEYW_STATIC
LEXER_KEYW_STATIC, /**< static */
#else /* CONFIG_DISABLE_ES2015 */
/* Context dependent strict reserved words:
* See also: ECMA-262 v6, 11.6.2.1 */
#define LEXER_FIRST_CONTEXT_DEPENDENT_RESERVED_WORD
#endif /* !CONFIG_DISABLE_ES2015 */
/* Context dependent future strict reserved words:
* See also: ECMA-262 v6, 11.6.2.1 */
#define LEXER_FIRST_CONTEXT_DEPENDENT_FUTURE_RESERVED_WORD LEXER_KEYW_LET
LEXER_KEYW_LET, /**< let */
LEXER_KEYW_YIELD, /**< yield */
#ifdef CONFIG_DISABLE_ES2015
LEXER_KEYW_STATIC, /**< static */
#endif /* CONFIG_DISABLE_ES2015 */
} lexer_token_type_t;
#define LEXER_NEWLINE_LS_PS_BYTE_1 0xe2

View File

@ -15,15 +15,9 @@
#include "js-parser-internal.h"
#ifndef CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
#include "lit-char-helpers.h"
#endif /* !CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS */
#ifndef JERRY_DISABLE_JS_PARSER
#if !defined (CONFIG_DISABLE_ES2015_CLASS) && (defined (JERRY_DEBUGGER) || defined (JERRY_ENABLE_LINE_INFO))
#include "jcontext.h"
#endif /* !CONFIG_DISABLE_ES2015_CLASS && (JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO) */
#include "lit-char-helpers.h"
/** \addtogroup parser Parser
* @{
@ -369,19 +363,17 @@ parser_append_object_literal_item (parser_context_t *context_p, /**< context */
* Parse class as an object literal.
*/
static void
parser_parse_class_literal (parser_context_t *context_p, /**< context */
lexer_literal_t *constructor_literal_p) /**< constructor literal */
parser_parse_class_literal (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
JERRY_ASSERT (constructor_literal_p->type == LEXER_UNUSED_LITERAL);
parser_emit_cbc (context_p, CBC_CREATE_OBJECT);
bool is_static = false;
bool super_called = false;
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | (context_p->status_flags & PARSER_CLASS_HAS_SUPER);
while (true)
{
if (!is_static)
if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION))
{
lexer_skip_empty_statements (context_p);
}
@ -398,8 +390,8 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
uint16_t literal_index, function_literal_index;
bool is_getter = (context_p->token.type == LEXER_PROPERTY_GETTER);
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE;
status_flags |= (is_getter ? PARSER_IS_PROPERTY_GETTER : PARSER_IS_PROPERTY_SETTER);
uint32_t accessor_status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE;
accessor_status_flags |= (is_getter ? PARSER_IS_PROPERTY_GETTER : PARSER_IS_PROPERTY_SETTER);
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD | LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
literal_index = context_p->lit_object.index;
@ -410,13 +402,14 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
{
is_computed = true;
}
else if (!is_static && lexer_compare_raw_identifier_to_current (context_p, "constructor", 11))
else if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION)
&& lexer_compare_raw_identifier_to_current (context_p, "constructor", 11))
{
parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR);
}
parser_flush_cbc (context_p);
function_literal_index = lexer_construct_function_object (context_p, status_flags);
function_literal_index = lexer_construct_function_object (context_p, accessor_status_flags);
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
@ -425,6 +418,7 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
cbc_ext_opcode_t opcode;
bool is_static = (status_flags & PARSER_CLASS_STATIC_FUNCTION);
if (is_computed)
{
@ -454,28 +448,48 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
}
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode);
is_static = false;
status_flags &= (uint32_t) ~PARSER_CLASS_STATIC_FUNCTION;
continue;
}
if (!is_static && context_p->token.type == LEXER_CLASS_CONSTRUCTOR)
if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) && context_p->token.type == LEXER_CLASS_CONSTRUCTOR)
{
if (constructor_literal_p->type == LEXER_FUNCTION_LITERAL)
if (super_called)
{
/* 14.5.1 */
parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS);
}
else
{
super_called = true;
}
parser_flush_cbc (context_p);
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_CLASS_CONSTRUCTOR;
constructor_literal_p->u.bytecode_p = parser_parse_function (context_p, status_flags);
constructor_literal_p->type = LEXER_FUNCTION_LITERAL;
uint32_t constructor_status_flags = status_flags | PARSER_CLASS_CONSTRUCTOR;
if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
{
constructor_status_flags |= PARSER_LEXICAL_ENV_NEEDED;
}
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
}
lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
literal_p->type = LEXER_UNUSED_LITERAL;
literal_p->status_flags = 0;
literal_p->u.bytecode_p = parser_parse_function (context_p, constructor_status_flags);
literal_p->type = LEXER_FUNCTION_LITERAL;
parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), context_p->literal_count);
context_p->literal_count++;
continue;
}
if (!is_static && context_p->token.type == LEXER_KEYW_STATIC)
if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) && context_p->token.type == LEXER_KEYW_STATIC)
{
is_static = true;
status_flags |= PARSER_CLASS_STATIC_FUNCTION;
continue;
}
@ -485,7 +499,8 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
{
is_computed = true;
}
else if (is_static && lexer_compare_raw_identifier_to_current (context_p, "prototype", 9))
else if ((status_flags & PARSER_CLASS_STATIC_FUNCTION)
&& lexer_compare_raw_identifier_to_current (context_p, "prototype", 9))
{
parser_raise_error (context_p, PARSER_ERR_CLASS_STATIC_PROTOTYPE);
}
@ -493,7 +508,6 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
parser_flush_cbc (context_p);
uint16_t literal_index = context_p->lit_object.index;
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE;
uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags);
parser_emit_cbc_literal (context_p,
@ -504,11 +518,11 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
context_p->last_cbc.value = literal_index;
if (is_static)
if ((status_flags & PARSER_CLASS_STATIC_FUNCTION))
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (is_computed ? CBC_EXT_SET_STATIC_COMPUTED_PROPERTY_LITERAL
: CBC_EXT_SET_STATIC_PROPERTY_LITERAL);
is_static = false;
status_flags &= (uint32_t) ~PARSER_CLASS_STATIC_FUNCTION;
}
else
{
@ -517,14 +531,15 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
}
}
if (constructor_literal_p->type == LEXER_UNUSED_LITERAL)
if (!super_called && (context_p->status_flags & PARSER_CLASS_HAS_SUPER))
{
parser_flush_cbc (context_p);
constructor_literal_p->u.bytecode_p = parser_create_class_implicit_constructor (context_p);
constructor_literal_p->type = LEXER_FUNCTION_LITERAL;
parser_emit_cbc_ext (context_p, CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL);
}
JERRY_ASSERT (constructor_literal_p->type == LEXER_FUNCTION_LITERAL);
if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
{
parser_emit_cbc_ext (context_p, CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR);
}
} /* parser_parse_class_literal */
/**
@ -570,25 +585,17 @@ parser_parse_class (parser_context_t *context_p, /**< context */
}
}
/* Currently heritage is not supported so the next token must be left brace. */
if (context_p->token.type == LEXER_KEYW_EXTENDS)
{
parser_parse_super_class_context_start (context_p);
}
if (context_p->token.type != LEXER_LEFT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
}
/* Create an empty literal for class constructor. */
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
}
lexer_literal_t *constructor_literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
constructor_literal_p->type = LEXER_UNUSED_LITERAL;
constructor_literal_p->status_flags = 0;
parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, context_p->literal_count);
context_p->literal_count++;
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CLASS_CONSTRUCTOR);
bool is_strict = context_p->status_flags & PARSER_IS_STRICT;
@ -596,17 +603,7 @@ parser_parse_class (parser_context_t *context_p, /**< context */
context_p->status_flags |= PARSER_IS_STRICT;
/* ClassDeclaration is parsed. Continue with class body. */
parser_parse_class_literal (context_p, constructor_literal_p);
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
JERRY_DEBUGGER_NO_SUBTYPE,
constructor_literal_p->u.char_p,
constructor_literal_p->prop.length);
}
#endif /* JERRY_DEBUGGER */
parser_parse_class_literal (context_p);
JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE);
@ -621,6 +618,12 @@ parser_parse_class (parser_context_t *context_p, /**< context */
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, class_ident_index);
}
if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
{
parser_parse_super_class_context_end (context_p, is_statement);
context_p->status_flags &= (uint32_t) ~PARSER_CLASS_HAS_SUPER;
}
parser_flush_cbc (context_p);
if (!is_strict)
@ -1226,7 +1229,18 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
}
case LEXER_KEYW_THIS:
{
parser_emit_cbc (context_p, CBC_PUSH_THIS);
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
}
else
{
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
parser_emit_cbc (context_p, CBC_PUSH_THIS);
#ifndef CONFIG_DISABLE_ES2015_CLASS
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
break;
}
case LEXER_LIT_TRUE:
@ -1250,6 +1264,38 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
parser_parse_class (context_p, false);
return;
}
case LEXER_KEYW_SUPER:
{
if ((lexer_check_next_character (context_p, LIT_CHAR_DOT)
|| lexer_check_next_character (context_p, LIT_CHAR_LEFT_SQUARE))
&& context_p->status_flags & (PARSER_CLASS_HAS_SUPER | PARSER_IS_ARROW_FUNCTION))
{
if (!LEXER_IS_BINARY_OP_TOKEN (context_p->stack_top_uint8))
{
context_p->status_flags |= PARSER_CLASS_SUPER_PROP_REFERENCE;
}
if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR)
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP);
break;
}
bool is_static = context_p->status_flags & PARSER_CLASS_STATIC_FUNCTION;
parser_emit_cbc_ext (context_p, is_static ? CBC_EXT_PUSH_STATIC_SUPER : CBC_EXT_PUSH_SUPER);
break;
}
if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)
&& (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
&& (context_p->status_flags & (PARSER_IS_ARROW_FUNCTION | PARSER_CLASS_CONSTRUCTOR)))
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER);
break;
}
parser_raise_error (context_p, PARSER_ERR_UNEXPECTED_SUPER_REFERENCE);
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
case LEXER_RIGHT_PAREN:
@ -1393,6 +1439,12 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */
context_p->last_cbc_opcode = CBC_PUSH_PROP_THIS_LITERAL_REFERENCE;
opcode = CBC_CALL_PROP;
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER))
{
opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL);
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
else if ((context_p->status_flags & (PARSER_INSIDE_WITH | PARSER_RESOLVE_BASE_FOR_CALLS))
&& PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
@ -1452,9 +1504,30 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */
if (is_eval)
{
parser_emit_cbc (context_p, CBC_EVAL);
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
{
parser_flush_cbc (context_p);
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_CLASS_EVAL);
context_p->last_cbc.value = PARSER_GET_CLASS_ECMA_PARSE_OPTS (context_p->status_flags);
}
else
{
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
parser_emit_cbc (context_p, CBC_EVAL);
#ifndef CONFIG_DISABLE_ES2015_CLASS
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
if ((context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) && opcode == CBC_CALL_PROP)
{
parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_CALL);
context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
if (call_arguments == 0)
{
if (opcode == CBC_CALL)
@ -1687,6 +1760,14 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */
parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index);
parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_LITERAL);
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE)
{
parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_ASSIGN);
parser_flush_cbc (context_p);
}
context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE;
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
else
{

View File

@ -68,7 +68,12 @@ 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 */
/* These three status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed (this value must be kept in
* in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */
PARSER_CLASS_HAS_SUPER = (1u << 21), /**< class has super reference */
PARSER_CLASS_STATIC_FUNCTION = (1u << 22), /**< this function is a static class method */
PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 23), /**< super property call or assignment */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
} parser_general_flags_t;
@ -85,6 +90,54 @@ typedef enum
* CBC_PUSH_LITERAL instruction */
} parser_expression_flags_t;
/**
* Mask for strict mode code
*/
#define PARSER_STRICT_MODE_MASK 0x1
#ifndef CONFIG_DISABLE_ES2015_CLASS
/**
* Offset between PARSER_CLASS_CONSTRUCTOR and ECMA_PARSE_CLASS_CONSTRUCTOR
*/
#define PARSER_CLASS_PARSE_OPTS_OFFSET \
(JERRY_LOG2 (PARSER_CLASS_CONSTRUCTOR) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR))
/**
* Count of ecma_parse_opts_t class parsing options related bits
*/
#define PARSER_CLASS_PARSE_OPTS_COUNT \
(JERRY_LOG2 (ECMA_PARSE_HAS_STATIC_SUPER) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR))
/**
* Mask for get class option bits from ecma_parse_opts_t
*/
#define PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK \
(((1 << PARSER_CLASS_PARSE_OPTS_COUNT) - 1) << JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR))
/**
* Get class option bits from ecma_parse_opts_t
*/
#define PARSER_GET_CLASS_PARSER_OPTS(opts) \
(((opts) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK) << PARSER_CLASS_PARSE_OPTS_OFFSET)
/**
* Get class option bits from parser_general_flags_t
*/
#define PARSER_GET_CLASS_ECMA_PARSE_OPTS(opts) \
((uint16_t) (((opts) >> PARSER_CLASS_PARSE_OPTS_OFFSET) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK))
/**
* Class constructor with heritage context representing bits
*/
#define PARSER_CLASS_CONSTRUCTOR_SUPER (PARSER_CLASS_CONSTRUCTOR | PARSER_CLASS_HAS_SUPER)
/**
* Check the scope is a class constructor with heritage context
*/
#define PARSER_IS_CLASS_CONSTRUCTOR_SUPER(flag) \
(((flag) & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER)
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/* The maximum of PARSER_CBC_STREAM_PAGE_SIZE is 127. */
#define PARSER_CBC_STREAM_PAGE_SIZE \
((uint32_t) (64 - sizeof (void *)))
@ -434,9 +487,8 @@ void parser_set_continues_to_current_position (parser_context_t *context_p, pars
/* Lexer functions */
void lexer_next_token (parser_context_t *context_p);
bool lexer_check_colon (parser_context_t *context_p);
bool lexer_check_next_character (parser_context_t *context_p, lit_utf8_byte_t character);
#ifndef CONFIG_DISABLE_ES2015_CLASS
bool lexer_check_left_paren (parser_context_t *context_p);
void lexer_skip_empty_statements (parser_context_t *context_p);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
@ -469,6 +521,8 @@ bool lexer_compare_raw_identifier_to_current (parser_context_t *context_p, const
void parser_parse_expression (parser_context_t *context_p, int options);
#ifndef CONFIG_DISABLE_ES2015_CLASS
void parser_parse_class (parser_context_t *context_p, bool is_statement);
void parser_parse_super_class_context_start (parser_context_t *context_p);
void parser_parse_super_class_context_end (parser_context_t *context_p, bool is_statement);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
@ -501,9 +555,6 @@ ecma_compiled_code_t *parser_parse_function (parser_context_t *context_p, uint32
#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION
ecma_compiled_code_t *parser_parse_arrow_function (parser_context_t *context_p, uint32_t status_flags);
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
#ifndef CONFIG_DISABLE_ES2015_CLASS
ecma_compiled_code_t *parser_create_class_implicit_constructor (parser_context_t *context_p);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/* Error management. */

View File

@ -14,10 +14,7 @@
*/
#include "js-parser-internal.h"
#ifndef CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS
#include "lit-char-helpers.h"
#endif /* !CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS */
#ifndef JERRY_DISABLE_JS_PARSER
@ -75,6 +72,7 @@ typedef enum
#endif /* !CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS */
#ifndef CONFIG_DISABLE_ES2015_CLASS
SCAN_STACK_CLASS, /**< class language element */
SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
} scan_stack_modes_t;
@ -335,6 +333,9 @@ parser_scan_primary_expression_end (parser_context_t *context_p, /**< context */
if ((type == LEXER_RIGHT_SQUARE && stack_top == SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
|| (type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_PAREN_EXPRESSION)
#ifndef CONFIG_DISABLE_ES2015_CLASS
|| (type == LEXER_LEFT_BRACE && stack_top == SCAN_STACK_CLASS_EXTENDS)
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
|| (type == LEXER_RIGHT_BRACE && stack_top == SCAN_STACK_OBJECT_LITERAL))
{
parser_stack_pop_uint8 (context_p);
@ -345,6 +346,12 @@ parser_scan_primary_expression_end (parser_context_t *context_p, /**< context */
*mode = SCAN_MODE_ARROW_FUNCTION;
}
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (stack_top == SCAN_STACK_CLASS_EXTENDS)
{
*mode = SCAN_MODE_CLASS_METHOD;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
return false;
}
@ -699,8 +706,13 @@ parser_scan_until (parser_context_t *context_p, /**< context */
lexer_next_token (context_p);
}
/* Currently heritage is not supported so the next token must be left brace. */
if (context_p->token.type != LEXER_LEFT_BRACE)
if (context_p->token.type == LEXER_KEYW_EXTENDS)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXTENDS);
mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
else if (context_p->token.type != LEXER_LEFT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
}

View File

@ -16,10 +16,8 @@
#include "js-parser-internal.h"
#ifndef JERRY_DISABLE_JS_PARSER
#if defined (JERRY_DEBUGGER) || defined (JERRY_ENABLE_LINE_INFO)
#include "jcontext.h"
#endif /* JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO */
#include "lit-char-helpers.h"
/** \addtogroup parser Parser
* @{
@ -617,6 +615,68 @@ parser_parse_with_statement_end (parser_context_t *context_p) /**< context */
}
} /* parser_parse_with_statement_end */
#ifndef CONFIG_DISABLE_ES2015_CLASS
/**
* Parse super class context like a with statement (starting part).
*/
void
parser_parse_super_class_context_start (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXTENDS);
parser_with_statement_t with_statement;
lexer_next_token (context_p);
/* NOTE: Currently there is no proper way to check whether the currently parsed expression
is a valid lefthand-side expression or not, so we do not throw syntax error and parse
the class extending value as an expression. */
parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_NO_COMMA);
#ifndef JERRY_NDEBUG
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
context_p->status_flags |= PARSER_CLASS_HAS_SUPER;
parser_emit_cbc_ext_forward_branch (context_p,
CBC_EXT_SUPER_CLASS_CREATE_CONTEXT,
&with_statement.branch);
parser_stack_push (context_p, &with_statement, sizeof (parser_with_statement_t));
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_WITH);
} /* parser_parse_super_class_context_start */
/**
* Parse super class context like a with statement (ending part).
*/
void
parser_parse_super_class_context_end (parser_context_t *context_p, /**< context */
bool is_statement) /**< true - if class is parsed as a statement
* false - otherwise (as an expression) */
{
parser_with_statement_t with_statement;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &with_statement, sizeof (parser_with_statement_t));
parser_flush_cbc (context_p);
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
if (is_statement)
{
parser_emit_cbc (context_p, CBC_CONTEXT_END);
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_CLASS_EXPR_CONTEXT_END);
}
parser_set_branch_to_current_position (context_p, &with_statement.branch);
} /* parser_parse_super_class_context_end */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* Parse do-while statement (ending part).
*/
@ -1970,22 +2030,52 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
}
lexer_next_token (context_p);
if ((context_p->token.flags & LEXER_WAS_NEWLINE)
|| context_p->token.type == LEXER_SEMICOLON
|| context_p->token.type == LEXER_RIGHT_BRACE)
{
parser_emit_cbc (context_p, CBC_RETURN_WITH_BLOCK);
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
parser_emit_cbc (context_p, CBC_RETURN);
}
else
{
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
parser_emit_cbc (context_p, CBC_RETURN_WITH_BLOCK);
#ifndef CONFIG_DISABLE_ES2015_CLASS
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
break;
}
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
bool return_with_literal = (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
#ifndef CONFIG_DISABLE_ES2015_CLASS
return_with_literal &= !PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
if (return_with_literal)
{
context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL;
}
else
{
parser_emit_cbc (context_p, CBC_RETURN);
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
{
parser_emit_cbc_ext (context_p, CBC_EXT_CONSTRUCTOR_RETURN);
}
else
{
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
parser_emit_cbc (context_p, CBC_RETURN);
#ifndef CONFIG_DISABLE_ES2015_CLASS
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
}
break;
}
@ -2003,11 +2093,10 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
lexer_next_token (context_p);
break;
}
case LEXER_LITERAL:
{
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
&& lexer_check_colon (context_p))
&& lexer_check_next_character (context_p, LIT_CHAR_COLON))
{
parser_parse_label (context_p);
lexer_next_token (context_p);
@ -2087,6 +2176,15 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
#endif /* !JERRY_NDEBUG */
/* There is no lexer_next_token here, since the
* next token belongs to the parent context. */
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
parser_emit_cbc (context_p, CBC_RETURN);
parser_flush_cbc (context_p);
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
return;
}
parser_raise_error (context_p, PARSER_ERR_INVALID_RIGHT_SQUARE);

View File

@ -911,6 +911,10 @@ parser_error_to_string (parser_error_t error) /**< error code */
{
return "Classes may not have a static property called 'prototype'.";
}
case PARSER_ERR_UNEXPECTED_SUPER_REFERENCE:
{
return "Super is not allowed to be used here.";
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
case PARSER_ERR_LEFT_PAREN_EXPECTED:
{

View File

@ -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_must_be_equal_to_parser_is_strict);
#ifndef CONFIG_DISABLE_ES2015_CLASS
JERRY_STATIC_ASSERT ((ECMA_PARSE_CLASS_CONSTRUCTOR << PARSER_CLASS_PARSE_OPTS_OFFSET) == PARSER_CLASS_CONSTRUCTOR,
ecma_class_parse_options_must_be_able_to_be_shifted_to_ecma_general_flags);
#endif /* !CONFIG_DISABLE_ES2015 */
/** \addtogroup parser Parser
* @{
*
@ -1210,6 +1218,13 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code
}
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR)
{
JERRY_DEBUG_MSG (",constructor");
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
JERRY_DEBUG_MSG ("]\n");
JERRY_DEBUG_MSG (" Argument range end: %d\n", (int) argument_end);
@ -1546,6 +1561,13 @@ parser_post_processing (parser_context_t *context_p) /**< context */
PARSER_NEXT_BYTE (page_p, offset);
length++;
#ifndef CONFIG_DISABLE_ES2015_CLASS
if (ext_opcode == CBC_EXT_CONSTRUCTOR_RETURN)
{
last_opcode = CBC_RETURN;
}
#endif /* !CONFIG_DISABLE_ES2015 */
#ifdef JERRY_ENABLE_LINE_INFO
if (ext_opcode == CBC_EXT_LINE)
{
@ -2302,11 +2324,11 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
context.stack_limit = 0;
context.last_context_p = NULL;
context.last_statement.current_p = NULL;
context.status_flags |= parse_opts & PARSER_STRICT_MODE_MASK;
if (parse_opts & ECMA_PARSE_STRICT_MODE)
{
context.status_flags |= PARSER_IS_STRICT;
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
context.status_flags |= PARSER_GET_CLASS_PARSER_OPTS (parse_opts);
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
context.token.flags = 0;
context.line = 1;
@ -2525,38 +2547,6 @@ parser_restore_context (parser_context_t *context_p, /**< context */
#endif /* !JERRY_NDEBUG */
} /* parser_restore_context */
#ifndef CONFIG_DISABLE_ES2015_CLASS
/**
* Parse default constructor code
*
* @return compiled code
*/
ecma_compiled_code_t *
parser_create_class_implicit_constructor (parser_context_t *context_p) /**< context */
{
parser_saved_context_t saved_context;
parser_save_context (context_p, &saved_context);
#ifdef JERRY_DEBUGGER
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column))
{
/* This option has a high memory and performance costs,
* but it is necessary for executing eval operations by the debugger. */
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE;
}
#endif /* JERRY_DEBUGGER */
context_p->status_flags |= PARSER_CLASS_CONSTRUCTOR;
ecma_compiled_code_t *compiled_code_p = parser_post_processing (context_p);
parser_restore_context (context_p, &saved_context);
return compiled_code_p;
} /* parser_create_class_implicit_constructor */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* Parse function code
*
@ -2674,6 +2664,13 @@ parser_parse_function (parser_context_t *context_p, /**< context */
}
lexer_next_token (context_p);
#ifndef CONFIG_DISABLE_ES2015_CLASS
if ((context_p->status_flags & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER)
{
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
parser_parse_statements (context_p);
compiled_code_p = parser_post_processing (context_p);
@ -2713,6 +2710,9 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */
&& (status_flags & PARSER_IS_ARROW_FUNCTION));
parser_save_context (context_p, &saved_context);
context_p->status_flags |= status_flags | PARSER_ARGUMENTS_NOT_NEEDED;
#ifndef CONFIG_DISABLE_ES2015_CLASS
context_p->status_flags |= saved_context.status_flags & PARSER_CLASS_HAS_SUPER;
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)

View File

@ -83,6 +83,7 @@ typedef enum
PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS, /**< multiple class constructor */
PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR, /**< class constructor cannot be an accessor */
PARSER_ERR_CLASS_STATIC_PROTOTYPE, /**< static method name 'prototype' is not allowed */
PARSER_ERR_UNEXPECTED_SUPER_REFERENCE, /**< unexpected super keyword */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
PARSER_ERR_LEFT_PAREN_EXPECTED, /**< left paren expected */

View File

@ -26,6 +26,9 @@
* @{
*/
JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION,
parser_with_context_stack_allocation_must_be_equal_to_parser_super_class_context_stack_allocation);
/**
* Abort (finalize) the current stack context, and remove it.
*
@ -64,6 +67,9 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
/* FALLTHRU */
}
case VM_CONTEXT_WITH:
#ifndef CONFIG_DISABLE_ES2015_CLASS
case VM_CONTEXT_SUPER_CLASS:
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
{
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);

View File

@ -57,6 +57,9 @@ typedef enum
VM_CONTEXT_TRY, /**< try context */
VM_CONTEXT_CATCH, /**< catch context */
VM_CONTEXT_WITH, /**< with context */
#ifndef CONFIG_DISABLE_ES2015_CLASS
VM_CONTEXT_SUPER_CLASS, /**< super class context */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
VM_CONTEXT_FOR_IN, /**< for-in context */
} vm_stack_context_type_t;

View File

@ -382,6 +382,59 @@ vm_get_implicit_this_value (ecma_value_t *this_value_p) /**< [in,out] this value
return false;
} /* vm_get_implicit_this_value */
#ifndef CONFIG_DISABLE_ES2015_CLASS
/**
* 'super(...)' function call handler.
*/
static void
vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_SUPER_CALL);
JERRY_ASSERT (frame_ctx_p->byte_code_p[0] == CBC_EXT_OPCODE);
uint32_t arguments_list_len = frame_ctx_p->byte_code_p[2];
ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len;
ecma_value_t func_value = stack_top_p[-1];
ecma_value_t completion_value;
ecma_op_set_super_called (frame_ctx_p->lex_env_p);
ecma_value_t this_value = ecma_op_get_class_this_binding (frame_ctx_p->lex_env_p);
if (!ecma_is_constructor (func_value))
{
completion_value = ecma_raise_type_error ("Class extends value is not a constructor.");
}
else
{
completion_value = ecma_op_function_construct (ecma_get_object_from_value (func_value),
this_value,
stack_top_p,
arguments_list_len);
if (this_value != completion_value && ecma_is_value_object (completion_value))
{
ecma_op_set_class_prototype (completion_value, this_value);
ecma_op_set_class_this_binding (frame_ctx_p->lex_env_p, completion_value);
}
}
/* Free registers. */
for (uint32_t i = 0; i < arguments_list_len; i++)
{
ecma_fast_free_value (stack_top_p[i]);
}
ecma_free_value (stack_top_p[-1]);
stack_top_p[-1] = completion_value;
frame_ctx_p->stack_top_p = stack_top_p;
/* 'super (...)' call continues as a normal 'Function call' */
frame_ctx_p->call_operation = VM_EXEC_CALL;
} /* vm_super_call */
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
/**
* 'Function call' opcode handler.
*
@ -1186,6 +1239,313 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
*stack_top_p++ = result;
continue;
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
case VM_OC_SUPER_CALL:
{
if (frame_ctx_p->call_operation == VM_NO_EXEC_OP)
{
frame_ctx_p->call_operation = VM_EXEC_SUPER_CALL;
frame_ctx_p->byte_code_p = byte_code_start_p;
frame_ctx_p->stack_top_p = stack_top_p;
frame_ctx_p->call_block_result = block_result;
return ECMA_VALUE_UNDEFINED;
}
byte_code_p++;
frame_ctx_p->call_operation = VM_NO_EXEC_OP;
result = *(--stack_top_p);
block_result = frame_ctx_p->call_block_result;
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (result);
}
else if (opcode_data & VM_OC_PUT_STACK)
{
*stack_top_p++ = result;
}
else
{
ecma_fast_free_value (block_result);
block_result = result;
}
continue;
}
case VM_OC_CLASS_HERITAGE:
{
ecma_value_t super_value = *(--stack_top_p);
ecma_object_t *super_class_p;
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
if (ecma_is_value_null (super_value))
{
super_class_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL);
}
else
{
result = ecma_op_to_object (super_value);
ecma_free_value (super_value);
if (ECMA_IS_VALUE_ERROR (result) || !ecma_is_constructor (result))
{
if (ECMA_IS_VALUE_ERROR (result))
{
ecma_free_value (JERRY_CONTEXT (error_value));
}
ecma_free_value (result);
result = ecma_raise_type_error ("Value provided by class extends is not an object or null.");
goto error;
}
else
{
super_class_p = ecma_get_object_from_value (result);
}
}
ecma_object_t *super_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p,
super_class_p,
ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
ecma_deref_object (super_class_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_SUPER_CLASS, branch_offset);
frame_ctx_p->lex_env_p = super_env_p;
continue;
}
case VM_OC_CLASS_INHERITANCE:
{
ecma_value_t child_value = stack_top_p[-2];
ecma_value_t child_prototype_value = stack_top_p[-1];
ecma_object_t *child_class_p = ecma_get_object_from_value (child_value);
ecma_object_t *child_prototype_class_p = ecma_get_object_from_value (child_prototype_value);
ecma_property_value_t *prop_value_p;
prop_value_p = ecma_create_named_data_property (child_prototype_class_p,
ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR),
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
NULL);
ecma_named_data_property_assign_value (child_prototype_class_p, prop_value_p, child_value);
ecma_object_t *super_class_p = ecma_get_lex_env_binding_object (frame_ctx_p->lex_env_p);
if (ecma_get_object_prototype (super_class_p))
{
ecma_value_t super_prototype_value = ecma_op_object_get_by_magic_id (super_class_p,
LIT_MAGIC_STRING_PROTOTYPE);
if (ecma_get_object_type (super_class_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION
&& !ecma_is_value_object (super_prototype_value))
{
ecma_free_value (super_prototype_value);
result = ecma_raise_type_error (ECMA_ERR_MSG ("Class extends value does not have valid "
"prototype property."));
goto error;
}
if (!(ECMA_IS_VALUE_ERROR (super_prototype_value) || !ecma_is_value_object (super_prototype_value)))
{
ecma_object_t *super_prototype_class_p = ecma_get_object_from_value (super_prototype_value);
ECMA_SET_POINTER (child_prototype_class_p->prototype_or_outer_reference_cp, super_prototype_class_p);
ECMA_SET_POINTER (child_class_p->prototype_or_outer_reference_cp, super_class_p);
}
ecma_free_value (super_prototype_value);
}
continue;
}
case VM_OC_PUSH_CLASS_CONSTRUCTOR:
{
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
ecma_object_t *function_obj_p = ecma_create_object (prototype_obj_p,
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
ecma_deref_object (prototype_obj_p);
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) function_obj_p;
ext_func_obj_p->u.external_handler_cb = ecma_op_function_implicit_constructor_handler_cb;
*stack_top_p++ = ecma_make_object_value (function_obj_p);
continue;
}
case VM_OC_SET_CLASS_CONSTRUCTOR:
{
ecma_object_t *new_constructor_obj_p = ecma_get_object_from_value (left_value);
ecma_object_t *current_constructor_obj_p = ecma_get_object_from_value (stack_top_p[-2]);
ecma_extended_object_t *new_ext_func_obj_p = (ecma_extended_object_t *) new_constructor_obj_p;
ecma_extended_object_t *current_ext_func_obj_p = (ecma_extended_object_t *) current_constructor_obj_p;
uint16_t type_flags_refs = current_constructor_obj_p->type_flags_refs;
const int new_type = ECMA_OBJECT_TYPE_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION;
current_constructor_obj_p->type_flags_refs = (uint16_t) (type_flags_refs + new_type);
ecma_compiled_code_t *bytecode_p;
bytecode_p = (ecma_compiled_code_t *) ecma_op_function_get_compiled_code (new_ext_func_obj_p);
bytecode_p->status_flags |= CBC_CODE_FLAGS_CONSTRUCTOR;
ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_p);
ECMA_SET_INTERNAL_VALUE_POINTER (current_ext_func_obj_p->u.function.bytecode_cp,
bytecode_p);
ECMA_SET_INTERNAL_VALUE_POINTER (current_ext_func_obj_p->u.function.scope_cp,
ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_object_t,
new_ext_func_obj_p->u.function.scope_cp));
ecma_deref_object (new_constructor_obj_p);
continue;
}
case VM_OC_PUSH_IMPL_CONSTRUCTOR:
{
ecma_object_t *current_constructor_obj_p = ecma_get_object_from_value (stack_top_p[-2]);
uint16_t type_flags_refs = current_constructor_obj_p->type_flags_refs;
const int new_type = ECMA_OBJECT_TYPE_BOUND_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION;
current_constructor_obj_p->type_flags_refs = (uint16_t) (type_flags_refs + new_type);
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) current_constructor_obj_p;
ecma_object_t *super_obj_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p);
ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function,
super_obj_p);
ext_function_p->u.bound_function.args_len_or_this = ECMA_VALUE_IMPLICIT_CONSTRUCTOR;
continue;
}
case VM_OC_CLASS_EXPR_CONTEXT_END:
{
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p - 1);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-2]) == VM_CONTEXT_SUPER_CLASS);
stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p - 1);
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
stack_top_p++;
stack_top_p[-1] = *stack_top_p;
continue;
}
case VM_OC_CLASS_EVAL:
{
ECMA_SET_SUPER_EVAL_PARSER_OPTS (*byte_code_p++);
continue;
}
case VM_OC_PUSH_CONSTRUCTOR_SUPER:
{
JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE);
bool is_super_called = ecma_op_is_super_called (frame_ctx_p->lex_env_p);
if (byte_code_start_p[1] != CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP)
{
/* Calling super(...) */
if (is_super_called)
{
result = ecma_raise_reference_error (ECMA_ERR_MSG ("Super constructor may only be called once."));
goto error;
}
}
else if (!is_super_called)
{
/* Reference to super.method or super["method"] */
result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before "
"accessing 'super'."));
goto error;
}
/* FALLTHRU */
}
case VM_OC_PUSH_SUPER:
{
JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE);
if (byte_code_start_p[1] == CBC_EXT_PUSH_SUPER
|| byte_code_start_p[1] == CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP)
{
ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p);
ecma_value_t super_prototype = ecma_op_object_get_by_magic_id (super_class_p,
LIT_MAGIC_STRING_PROTOTYPE);
if (ECMA_IS_VALUE_ERROR (super_prototype))
{
result = super_prototype;
goto error;
}
*stack_top_p++ = super_prototype;
}
else
{
ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p);
*stack_top_p++ = ecma_fast_copy_value (ecma_make_object_value (super_class_p));
}
continue;
}
case VM_OC_PUSH_CONSTRUCTOR_THIS:
{
if (!ecma_op_is_super_called (frame_ctx_p->lex_env_p))
{
result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before "
"accessing 'this' or returning from it."));
goto error;
}
*stack_top_p++ = ecma_copy_value (ecma_op_get_class_this_binding (frame_ctx_p->lex_env_p));
continue;
}
case VM_OC_SUPER_PROP_REFERENCE:
{
const int index = (byte_code_start_p[1] == CBC_EXT_SUPER_PROP_ASSIGN) ? -1 : -3;
ecma_free_value (stack_top_p[index]);
stack_top_p[index] = ecma_copy_value (frame_ctx_p->this_binding);
continue;
}
case VM_OC_CONSTRUCTOR_RET:
{
result = left_value;
left_value = ECMA_VALUE_UNDEFINED;
if (!ecma_is_value_object (result))
{
if (ecma_is_value_undefined (result))
{
if (!ecma_op_is_super_called (frame_ctx_p->lex_env_p))
{
result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class "
"before returning from derived constructor"));
}
}
else
{
ecma_free_value (result);
result = ecma_raise_type_error (ECMA_ERR_MSG ("Derived constructors may only "
"return object or undefined."));
}
}
goto error;
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
case VM_OC_PUSH_ELISON:
{
*stack_top_p++ = ECMA_VALUE_ARRAY_HOLE;
@ -2365,7 +2725,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
object_p = ecma_get_object_from_value (result);
with_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, object_p);
with_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p,
object_p,
ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ecma_deref_object (object_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION);
@ -3060,6 +3422,12 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
{
opfunc_call (frame_ctx_p);
}
#ifndef CONFIG_DISABLE_ES2015_CLASS
else if (frame_ctx_p->call_operation == VM_EXEC_SUPER_CALL)
{
vm_super_call (frame_ctx_p);
}
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
else
{
JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_CONSTRUCT);

View File

@ -209,6 +209,21 @@ typedef enum
VM_OC_FINALLY, /**< finally */
VM_OC_CONTEXT_END, /**< context end */
VM_OC_JUMP_AND_EXIT_CONTEXT, /**< jump and exit context */
#ifndef CONFIG_DISABLE_ES2015_CLASS
VM_OC_CLASS_HERITAGE, /**< create a super class context */
VM_OC_CLASS_INHERITANCE, /**< inherit properties from the 'super' class */
VM_OC_PUSH_CLASS_CONSTRUCTOR, /**< push class constructor */
VM_OC_SET_CLASS_CONSTRUCTOR, /**< set class constructor to the given function literal */
VM_OC_PUSH_IMPL_CONSTRUCTOR, /**< create implicit class constructor */
VM_OC_CLASS_EXPR_CONTEXT_END, /**< class expression heritage context end */
VM_OC_CLASS_EVAL, /**< eval inside a class */
VM_OC_SUPER_CALL, /**< call the 'super' constructor */
VM_OC_SUPER_PROP_REFERENCE, /**< resolve super property reference */
VM_OC_PUSH_SUPER, /**< push resolvable super reference */
VM_OC_PUSH_CONSTRUCTOR_SUPER, /**< push 'super' inside a class constructor */
VM_OC_PUSH_CONSTRUCTOR_THIS, /**< push 'this' inside a class constructor */
VM_OC_CONSTRUCTOR_RET, /**< explicit return from a class constructor */
#endif /* !CONFIG_DISABLE_ES2015 */
#ifdef JERRY_DEBUGGER
VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */
VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */
@ -217,7 +232,7 @@ typedef enum
VM_OC_RESOURCE_NAME, /**< resource name of the current function */
VM_OC_LINE, /**< line number of the next statement */
#endif /* JERRY_ENABLE_LINE_INFO */
VM_OC_NONE, /**< a special opcode for */
VM_OC_NONE, /**< a special opcode for unsupported byte codes */
} vm_oc_types;
/**
@ -236,6 +251,21 @@ typedef enum
VM_OC_RESOURCE_NAME = VM_OC_NONE, /**< resource name of the current function is unused */
VM_OC_LINE = VM_OC_NONE, /**< line number of the next statement is unused */
#endif /* !JERRY_ENABLE_LINE_INFO */
#ifdef CONFIG_DISABLE_ES2015_CLASS
VM_OC_CLASS_HERITAGE = VM_OC_NONE, /**< create a super class context */
VM_OC_CLASS_INHERITANCE = VM_OC_NONE, /**< inherit properties from the 'super' class */
VM_OC_PUSH_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< push class constructor */
VM_OC_SET_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< set class constructor to the given function literal */
VM_OC_PUSH_IMPL_CONSTRUCTOR = VM_OC_NONE, /**< create implicit class constructor */
VM_OC_CLASS_EXPR_CONTEXT_END = VM_OC_NONE, /**< class expression heritage context end */
VM_OC_CLASS_EVAL = VM_OC_NONE, /**< eval inside a class */
VM_OC_SUPER_CALL = VM_OC_NONE, /**< call the 'super' constructor */
VM_OC_SUPER_PROP_REFERENCE = VM_OC_NONE, /**< resolve super property reference */
VM_OC_PUSH_SUPER = VM_OC_NONE, /**< push resolvable super reference */
VM_OC_PUSH_CONSTRUCTOR_SUPER = VM_OC_NONE, /**< push 'super' inside a class constructor */
VM_OC_PUSH_CONSTRUCTOR_THIS = VM_OC_NONE, /**< push 'this' inside a class constructor */
VM_OC_CONSTRUCTOR_RET = VM_OC_NONE, /**< explicit return from a class constructor */
#endif /* CONFIG_DISABLE_ES2015 */
VM_OC_UNUSED = VM_OC_NONE /**< placeholder if the list is empty */
} vm_oc_unused_types;
@ -315,6 +345,7 @@ typedef enum
{
VM_NO_EXEC_OP, /**< do nothing */
VM_EXEC_CALL, /**< invoke a function */
VM_EXEC_SUPER_CALL, /**< invoke a function through 'super' keyword */
VM_EXEC_CONSTRUCT, /**< construct a new object */
} vm_call_operation;

View File

@ -0,0 +1,28 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var g = Array.bind (0, 1, 2, 3)
g.prototype = Array.prototype;
class C extends g {}
class D extends C {
constructor () {
super (4, 5);
}
}
var d = new D;
assert (Object.getPrototypeOf (d) == D.prototype);

View File

@ -0,0 +1,116 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function isInstanceofArray (instance) {
assert (instance instanceof C);
assert (instance instanceof B);
assert (instance instanceof A);
assert (instance instanceof Array);
}
class A extends Array {
f () {
return 5;
}
}
class B extends A {
g () {
return eval ("eval ('super.f ()')");
}
}
class C extends B {
h () {
return eval ('super.g ()');
}
}
var c = new C (1, 2, 3, 4, 5, 6);
isInstanceofArray (c);
c.push (7);
assert (c.length === 7);
assert (c.f () === 5);
assert (c.g () === 5);
assert (c.h () === 5);
// Test built-in Array prototype methods
var mapped = c.map ((x) => x * 2);
isInstanceofArray (mapped);
for (var i = 0; i < mapped.length; i++) {
assert (mapped[i] == c[i] * 2);
}
var concated = c.concat (c);
isInstanceofArray (concated);
for (var i = 0; i < concated.length; i++) {
assert (concated[i] == c[i % (concated.length / 2)]);
}
var sliced = c.slice (c);
isInstanceofArray (sliced);
for (var i = 0; i < sliced.length; i++) {
assert (sliced[i] == c[i]);
}
var filtered = c.filter ((x) => x > 100);
isInstanceofArray (sliced);
assert (filtered.length === 0);
var spliced = c.splice (c.length - 1);
isInstanceofArray (spliced);
assert (spliced.length === 1);
assert (spliced[0] === 7);
c.constructor = 5;
try {
mapped = c.map ((x) => x * 2);
assert (false);
} catch (e) {
assert (e instanceof TypeError);
}
try {
concated = c.concat (c);
assert (false);
} catch (e) {
assert (e instanceof TypeError);
}
try {
sliced = c.slice (c);
assert (false);
} catch (e) {
assert (e instanceof TypeError);
}
try {
filtered = c.filter ((x) => x > 100);
assert (false);
} catch (e) {
assert (e instanceof TypeError);
}
try {
spliced = c.splice (0);
assert (false);
} catch (e) {
assert (e instanceof TypeError);
}

View File

@ -0,0 +1,74 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function isInstanceofTypedArray (instance) {
assert (instance instanceof C);
assert (instance instanceof B);
assert (instance instanceof A);
assert (instance instanceof Uint8Array);
}
class A extends Uint8Array {
f () {
return 5;
}
}
class B extends A {
g () {
return super.f ();
}
}
class C extends B {
h () {
return super.g ();
}
}
var c = new C ([1, 2, 3, 4, 5, 6]);
isInstanceofTypedArray (c);
assert (c.length === 6);
assert (c.f () === 5)
assert (c.g () === 5)
assert (c.h () === 5)
var mapped = c.map ((x) => x * 2);
isInstanceofTypedArray (mapped);
for (var i = 0; i < mapped.length; i++) {
assert (mapped[i] == c[i] * 2);
}
var filtered = c.filter ((x) => x > 100);
isInstanceofTypedArray (filtered);
assert (filtered.length === 0);
c.constructor = 5;
try {
mapped = c.map ((x) => x * 2);
assert (false);
} catch (e) {
assert (e instanceof TypeError)
}
try {
filtered = c.filter ((x) => x > 100);
assert (false);
} catch (e) {
assert (e instanceof TypeError)
}

View File

@ -0,0 +1,116 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Animal {
constructor (name) {
this.name = name;
}
hello () {
return "Hello I am " + this.name;
}
static speak () {
return "Animals roar.";
}
static explain () {
return "I can walk,";
}
whoAmI () {
return "I am an Animal.";
}
breath () {
return "I am breathing.";
}
get myName () {
return this.name;
}
set rename (name) {
this.name = name;
}
}
class Dog extends Animal {
constructor (name, barks) {
super (name);
this.barks = barks;
}
hello () {
return super.hello () + " and I can " + (this.barks ? "bark" : "not bark");
}
whoAmI () {
return "I am a Dog.";
}
static speak () {
return "Dogs bark.";
}
static explain () {
return super.explain () + " jump,";
}
bark () {
return this.barks ? "Woof" : "----";
}
}
class Doge extends Dog {
constructor (name, barks, awesomeness) {
super (name, barks);
this.awesomeness = awesomeness;
}
hello () {
return super.hello () + " and I'm " + (this.awesomeness > 9000 ? "super awesome" : "awesome") + ".";
}
whoAmI ( ) {
return "I am a Doge.";
}
static speak () {
return "Doges wow.";
}
static explain () {
return super.explain () + " dance.";
}
}
var doge = new Doge ("doggoe", true, 10000);
assert (doge.name === "doggoe");
doge.rename = "doggo";
assert (doge.myName === "doggo");
assert (doge.barks === true);
assert (doge.awesomeness === 10000);
assert (doge.hello () === "Hello I am doggo and I can bark and I'm super awesome.");
assert (doge.whoAmI () === "I am a Doge.");
assert (doge.breath () === "I am breathing.");
assert (doge.bark () === "Woof");
assert (Doge.speak () === "Doges wow.");
assert (Doge.explain () === "I can walk, jump, dance.");
assert (doge instanceof Animal);
assert (doge instanceof Dog);
assert (doge instanceof Doge);
assert (Dog.prototype.constructor === Dog)
assert (Doge.prototype.constructor === Doge)

View File

@ -0,0 +1,29 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A extends Array {
constructor () {
return null;
}
}
class B extends A { }
try {
new B;
assert (false);
} catch (e) {
assert (e instanceof TypeError);
}

View File

@ -0,0 +1,30 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A extends Array {
constructor () {
assert (false);
return null;
}
}
class B extends A {
constructor () {
return { o : 10 };
}
}
var b = new B;
assert (b.o === 10);

View File

@ -0,0 +1,50 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A extends Array {
constructor (a, b, c) {
eval ("eval ('super (a, b, c)')");
eval ("eval ('this.f = 5;')");
assert (this.h ()()() === 5);
return { o : 4 };
}
g () {
return function () {
return 5;
}
}
}
class B extends A {
constructor (a, b, c) {
eval ("eval ('super (a, b, c)')");
assert (this.f === undefined)
assert (this.o === 4)
this.k = 5;
return { o : 7 };
}
h () {
return super["g"];
}
}
var b = new B (1, 2, 3, 4);
assert (b.k === undefined);
assert (b.o === 7);
assert (b.h === undefined);
assert (b.g === undefined);

View File

@ -0,0 +1,32 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class C extends Array {
constructor (a, b) {
var a = eval ('super (arguments);');
}
}
class D extends C {
constructor () {
var a = eval ("eval ('super (1, 2);')");
return
}
}
var d = new D;
assert (JSON.stringify (d) === '[{"0":1,"1":2}]');
assert (d + "" === "[object Arguments]");
assert (d.length === 1);

View File

@ -0,0 +1,53 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A {
constructor () {
this.a = 5;
}
f () {
return 10;
}
super () {
this.super = 10;
return 15;
}
}
class B extends A {
constructor () {
super ();
assert (super.f === A.prototype.f);
super.f = 8;
assert (this.f === 8);
assert (super.f === A.prototype.f);
assert (this.a === 5);
super.a = 10;
assert (this.a === 10);
assert (super.super () === 15);
assert (this.super === 10);
super.super = 20;
assert (this.super === 20);
assert (super.super () === 15);
}
}
var b = new B;
assert (b.f === 8);
assert (b.a === 10);

View File

@ -0,0 +1,27 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A extends Array {
constructor () {
super ();
return;
}
};
var a = new A;
assert (a.length === 0);
assert (a instanceof Array);
assert (a instanceof A);
assert (JSON.stringify (a) === "[]");

View File

@ -0,0 +1,38 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class C {
static a () {
return 5;
}
}
class D extends C {
constructor () {
super ();
}
}
assert (D.a () === 5);
C.a = function () {
return 6;
}
assert (D.a () === 6);
C = 5;
assert (D.a () === 6);

View File

@ -0,0 +1,27 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A extends Array {
constructor (a, b, c) {
super (a, b);
this.f = 5;
}
}
class B extends A { }
var b = new B (1, 2, 3, 4);
assert (b.f === 5);
assert (b.length === 2);

View File

@ -0,0 +1,34 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A extends Array {
constructor (a, b, c) {
super (a, b);
this.f = 5;
}
}
class B extends A {
constructor (a, b, c) {
super (a, b);
this.g = super.f;
this.h = this.f;
}
}
var b = new B (1, 2, 3, 4);
assert (b.g === undefined);
assert (b.h === 5);
assert (b.length === 2);

View File

@ -0,0 +1,27 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A extends Array {
constructor (a, b, c) {
eval ("eval ('super (a, b, c)')");
eval ("eval ('this.f = 5;')");
}
}
class B extends A { }
var b = new B (1, 2, 3, 4);
assert (b.f === 5);
assert (b.length === 3);

View File

@ -0,0 +1,37 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class A extends Array {
constructor (a, b, c, d, e) {
eval ("eval ('super (a, b, c)')");
this.a = 6;
return new String ("foo");
}
f () {
return 5;
}
}
class B extends A {
constructor (a, b, c, d) {
eval ("eval ('super (a, b, c, d)')");
assert (super.f () === 5);
}
}
var a = new B (1, 2, 3, 4, 5, 6);
assert (a.a === undefined);
assert (a[0] + a[1] + a[2] === "foo");

View File

@ -0,0 +1,32 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class C extends Array {
constructor () {
var a = eval ('super (1, 2); 5');
assert (a === 5);
}
}
class D extends C {
constructor () {
var a = eval ("eval ('super (1, 2); 3')");
assert (a === 3);
}
}
var d = new D;
assert (JSON.stringify (d) === "[1,2]");

View File

@ -0,0 +1,85 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var A = Array;
var order = 0;
function f () {
order++;
return function () {
return A;
}
}
var B = class extends f ()() {
constructor () {
assert (++order === 2);
eval ("eval ('super (1, 2, 3, 4)')");
try {
super (1, 2, 3, 4, 5)
assert (false);
} catch (e) {
assert (e instanceof ReferenceError)
}
assert (this.g ()()()() === 10);
assert (eval ("eval ('this.g ()')()")()() === 10);
assert (eval ("eval ('this.g ()')")()()() === 10);
assert (eval ("eval ('this.g ()()()')")() === 10);
assert (eval ("eval ('this.g')")()()()() === 10);
this.push (5);
assert (this.length === 5)
eval ('this.push (6)');
assert (this.length === 6);
eval ("eval ('this.push (7)')");
this.j = 6;
return;
}
}
var C = class extends B {
g () {
return function () {
return () => {
return 10;
}
}
}
}
var D = class D extends C {
constructor () {
super ();
this.k = 5;
return
}
g () {
return eval ('super["g"]');
}
}
assert (order === 1);
var d = new D;
assert (d.length === 7);
assert (d.k === 5);
assert (d.j === 6);
assert (d instanceof D);
assert (d instanceof C);
assert (d instanceof B);
assert (d instanceof f ()());
assert (JSON.stringify (d) === "[1,2,3,4,5,6,7]");

View File

@ -0,0 +1,29 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var order = 0;
try {
var A = class extends null {
constructor () {
order++;
}
}
new A;
} catch (e) {
assert (order === 1);
assert (e instanceof ReferenceError);
}

View File

@ -0,0 +1,133 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function must_throw (str) {
try {
eval ("switch (1) { default: " + str + "}");
assert (false);
} catch (e) { }
try {
eval (str);
assert (false);
}
catch (e) { }
try {
eval ("'use strict'; switch (1) { default: " + str + "}");
assert (false);
} catch (e) { }
try {
eval ("'use strict'; " + str);
assert (false);
} catch (e) { }
}
class A {
constructor (a) {
this.a = a;
}
f () {
return 5;
}
}
must_throw ("class B extends 5 + 6 + 5 { constructor (a, b) { super (a) } }");
must_throw ("class B extends null { constructor () { super () } }; new B");
must_throw ("var o = { a : 5 }; \
class B extends Object.keys (o)[0] { constructor (a, b) { super (a) } } \
var b = new B (1, 2);");
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 () } } \
var b = new B (1, 2);");
must_throw ("class B extends A { constructor (a, b) { eval ('this.b = b') } } \
var b = new B (1, 2);");
must_throw ("class B extends A { constructor (a, b) { eval ('super.f ()') } } \
var b = new B (1, 2);");
must_throw ("class B extends A { constructor (a, b) { super (a); super (a); } } \
var b = new B (1, 2);");
must_throw ("class B extends A { constructor (a, b) { eval ('super (a)'); eval ('super (a)'); } } \
var b = new B (1, 2);");
must_throw ("class B extends A { constructor (a, b) { super (a) } g () { super (a) } } \
var b = new B (1, 2);");
must_throw ("class B extends A { constructor (a, b) { super (a) } g () { eval ('super (a)') } } \
var b = new B (1, 2); \
b.g ();");
must_throw ("class B extends A { constructor (a, b) { super (a) } g () { return function () { return super.f () } } } \
var b = new B (1, 2); \
b.g ()();");
must_throw ("class B extends A { constructor (a, b) { super (a) } \
g () { return function () { return eval ('super.f ()') } } } \
var b = new B (1, 2); \
b.g ()();");
must_throw ("class B extends A { constructor (a, b) { super (a) } \
g () { return function () { return eval (\"eval ('super.f ();')\") } } } \
var b = new B (1, 2); \
b.g ()();");
must_throw ("class A extends Array { constructor () { return 5; } }; new A");
must_throw ("class A extends Array { constructor () { return undefined; } }; new A");
must_throw ("class B extends undefined { }; new B;");
must_throw ("var A = class extends Array { . }");
must_throw ("class Array extends Array { }");
must_throw ("class A extends A { }");
must_throw ("class A extends { constructor () { super () } }");
class B extends A {
constructor (a, b) {
super (a);
assert (super.f () === 5);
}
g () {
return () => {
return super.f ();
}
}
h () {
return () => {
return () => {
return eval ('super.f ()');
}
}
}
}
var b = new B (1, 2);
assert (b.g ()() === 5);
assert (b.h ()()() === 5);

View File

@ -0,0 +1,38 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var calculatorMixin = Base => class extends Base {
f () {
return 1;
}
};
var randomizerMixin = Base => class extends Base {
g () {
return 2;
}
};
class A {
constructor () { }
}
class B extends calculatorMixin (randomizerMixin (A)) {
}
var b = new B ();
assert (b.f () === 1)
assert (b.g () === 2);

View File

@ -0,0 +1,50 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
order = 0;
var Mixin1 = (superclass) => class extends superclass {
foo () {
assert (order++ == 1)
if (super.foo) {
super.foo ();
}
}
};
var Mixin2 = (superclass) => class extends superclass {
foo () {
assert (order++ == 2)
if (super.foo) {
assert (super.foo () === 5);
}
}
};
class S {
foo () {
assert (order++ == 3)
return 5;
}
}
class C extends Mixin1 (Mixin2 (S)) {
foo () {
assert (order++ == 0)
super.foo ();
}
}
new C ().foo ()

View File

@ -223,7 +223,7 @@ main (void)
/* Check the snapshot data. Unused bytes should be filled with zeroes */
const uint8_t expected_data[] =
{
0x4A, 0x52, 0x52, 0x59, 0x12, 0x00, 0x00, 0x00,
0x4A, 0x52, 0x52, 0x59, 0x13, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,