class static block (initial patch by bnoordhuis)

This commit is contained in:
Fabrice Bellard 2024-01-02 16:10:43 +01:00
parent a8064b74fb
commit 16057644f3
3 changed files with 78 additions and 19 deletions

2
TODO
View file

@ -63,5 +63,5 @@ Optimization ideas:
Test262o: 0/11262 errors, 463 excluded Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
Result: 16/76783 errors, 1497 excluded, 8199 skipped Result: 16/76909 errors, 1497 excluded, 8136 skipped
Test262 commit: 6cbb6da9473c56d95358d8e679c5a6d2b4574efb Test262 commit: 6cbb6da9473c56d95358d8e679c5a6d2b4574efb

View file

@ -19688,6 +19688,7 @@ typedef enum JSParseFunctionEnum {
JS_PARSE_FUNC_GETTER, JS_PARSE_FUNC_GETTER,
JS_PARSE_FUNC_SETTER, JS_PARSE_FUNC_SETTER,
JS_PARSE_FUNC_METHOD, JS_PARSE_FUNC_METHOD,
JS_PARSE_FUNC_CLASS_STATIC_INIT,
JS_PARSE_FUNC_CLASS_CONSTRUCTOR, JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR, JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
} JSParseFunctionEnum; } JSParseFunctionEnum;
@ -20574,10 +20575,12 @@ static __exception int next_token(JSParseState *s)
(s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
(s->token.u.ident.atom == JS_ATOM_await && (s->token.u.ident.atom == JS_ATOM_await &&
(s->is_module || (s->is_module ||
(((s->cur_func->func_kind & JS_FUNC_ASYNC) || (s->cur_func->func_kind & JS_FUNC_ASYNC) ||
s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT ||
(s->cur_func->func_type == JS_PARSE_FUNC_ARROW && (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
!s->cur_func->in_function_body && s->cur_func->parent && !s->cur_func->in_function_body && s->cur_func->parent &&
(s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) { ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) ||
s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) {
if (ident_has_escape) { if (ident_has_escape) {
s->token.u.ident.is_reserved = TRUE; s->token.u.ident.is_reserved = TRUE;
s->token.val = TOK_IDENT; s->token.val = TOK_IDENT;
@ -22810,6 +22813,49 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
if (is_static) { if (is_static) {
if (next_token(s)) if (next_token(s))
goto fail; goto fail;
if (s->token.val == '{') {
ClassFieldsDef *cf = &class_fields[is_static];
JSFunctionDef *init;
if (!cf->fields_init_fd) {
if (emit_class_init_start(s, cf))
goto fail;
}
s->cur_func = cf->fields_init_fd;
/* XXX: could try to avoid creating a new function and
reuse 'fields_init_fd' with a specific 'var'
scope */
// stack is now: <empty>
if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT,
JS_FUNC_NORMAL, JS_ATOM_NULL,
s->token.ptr, s->token.line_num,
JS_PARSE_EXPORT_NONE, &init) < 0) {
goto fail;
}
// stack is now: fclosure
push_scope(s);
emit_op(s, OP_scope_get_var);
emit_atom(s, JS_ATOM_this);
emit_u16(s, 0);
// stack is now: fclosure this
/* XXX: should do it only once */
if (class_name != JS_ATOM_NULL) {
// TODO(bnoordhuis) pass as argument to init method?
emit_op(s, OP_dup);
emit_op(s, OP_scope_put_var_init);
emit_atom(s, class_name);
emit_u16(s, s->cur_func->scope_level);
}
emit_op(s, OP_swap);
// stack is now: this fclosure
emit_op(s, OP_call_method);
emit_u16(s, 0);
// stack is now: returnvalue
emit_op(s, OP_drop);
// stack is now: <empty>
pop_scope(s);
s->cur_func = s->cur_func->parent;
continue;
}
/* allow "static" field name */ /* allow "static" field name */
if (s->token.val == ';' || s->token.val == '=') { if (s->token.val == ';' || s->token.val == '=') {
is_static = FALSE; is_static = FALSE;
@ -26127,6 +26173,10 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
js_parse_error(s, "return not in a function"); js_parse_error(s, "return not in a function");
goto fail; goto fail;
} }
if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
js_parse_error(s, "return in a static initializer block");
goto fail;
}
if (next_token(s)) if (next_token(s))
goto fail; goto fail;
if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) { if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
@ -33278,8 +33328,9 @@ static __exception int js_parse_function_decl2(JSParseState *s,
func_type == JS_PARSE_FUNC_EXPR && func_type == JS_PARSE_FUNC_EXPR &&
(func_kind & JS_FUNC_GENERATOR)) || (func_kind & JS_FUNC_GENERATOR)) ||
(s->token.u.ident.atom == JS_ATOM_await && (s->token.u.ident.atom == JS_ATOM_await &&
func_type == JS_PARSE_FUNC_EXPR && ((func_type == JS_PARSE_FUNC_EXPR &&
(func_kind & JS_FUNC_ASYNC))) { (func_kind & JS_FUNC_ASYNC)) ||
func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) {
return js_parse_error_reserved_identifier(s); return js_parse_error_reserved_identifier(s);
} }
} }
@ -33373,7 +33424,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
func_type == JS_PARSE_FUNC_SETTER || func_type == JS_PARSE_FUNC_SETTER ||
func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR || func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR); func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW); fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW &&
func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT);
fd->has_this_binding = fd->has_arguments_binding; fd->has_this_binding = fd->has_arguments_binding;
fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR); fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
if (func_type == JS_PARSE_FUNC_ARROW) { if (func_type == JS_PARSE_FUNC_ARROW) {
@ -33381,6 +33433,11 @@ static __exception int js_parse_function_decl2(JSParseState *s,
fd->super_call_allowed = fd->parent->super_call_allowed; fd->super_call_allowed = fd->parent->super_call_allowed;
fd->super_allowed = fd->parent->super_allowed; fd->super_allowed = fd->parent->super_allowed;
fd->arguments_allowed = fd->parent->arguments_allowed; fd->arguments_allowed = fd->parent->arguments_allowed;
} else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
fd->new_target_allowed = TRUE; // although new.target === undefined
fd->super_call_allowed = FALSE;
fd->super_allowed = TRUE;
fd->arguments_allowed = FALSE;
} else { } else {
fd->new_target_allowed = TRUE; fd->new_target_allowed = TRUE;
fd->super_call_allowed = fd->is_derived_class_constructor; fd->super_call_allowed = fd->is_derived_class_constructor;
@ -33418,7 +33475,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (add_arg(ctx, fd, name) < 0) if (add_arg(ctx, fd, name) < 0)
goto fail; goto fail;
fd->defined_arg_count = 1; fd->defined_arg_count = 1;
} else { } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
if (s->token.val == '(') { if (s->token.val == '(') {
int skip_bits; int skip_bits;
/* if there is an '=' inside the parameter list, we /* if there is an '=' inside the parameter list, we
@ -33639,8 +33696,10 @@ static __exception int js_parse_function_decl2(JSParseState *s,
} }
} }
if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
if (js_parse_expect(s, '{')) if (js_parse_expect(s, '{'))
goto fail; goto fail;
}
if (js_parse_directives(s)) if (js_parse_directives(s))
goto fail; goto fail;

View file

@ -79,7 +79,7 @@ class-fields-private
class-fields-private-in=skip class-fields-private-in=skip
class-fields-public class-fields-public
class-methods-private class-methods-private
class-static-block=skip class-static-block
class-static-fields-private class-static-fields-private
class-static-fields-public class-static-fields-public
class-static-methods-private class-static-methods-private