Created
September 24, 2021 16:10
-
-
Save lexborisov/08dbde3d79f330b082fe1f3049212920 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User Alexander Borisov <alexander.borisov@nginx.com> | |
# Date 1632499826 -10800 | |
# Fri Sep 24 19:10:26 2021 +0300 | |
# Node ID 53c99c659d82d35e9b21d56c27954652fe404e51 | |
# Parent 6feba0e602eeaa963aaf878dc6aa84b8ce2a668e | |
Added default values support for function arguments. | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_disassembler.c | |
--- a/src/njs_disassembler.c Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_disassembler.c Fri Sep 24 19:10:26 2021 +0300 | |
@@ -159,6 +159,9 @@ static njs_code_name_t code_names[] = { | |
{ NJS_VMCODE_AWAIT, sizeof(njs_vmcode_await_t), | |
njs_str("AWAIT ") }, | |
+ | |
+ { NJS_VMCODE_DEFAULT_ARG, sizeof(njs_vmcode_default_arg_t), | |
+ njs_str("DEFAULT ARGUMENT") }, | |
}; | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_function.c | |
--- a/src/njs_function.c Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_function.c Fri Sep 24 19:10:26 2021 +0300 | |
@@ -1294,7 +1294,12 @@ njs_function_instance_length(njs_vm_t *v | |
function = (njs_function_t *) proto; | |
- njs_set_number(retval, function->args_count); | |
+ if (function->first_default != 0) { | |
+ njs_set_number(retval, function->first_default - 1); | |
+ | |
+ } else { | |
+ njs_set_number(retval, function->args_count); | |
+ } | |
return NJS_OK; | |
} | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_function.h | |
--- a/src/njs_function.h Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_function.h Fri Sep 24 19:10:26 2021 +0300 | |
@@ -20,6 +20,7 @@ struct njs_function_lambda_s { | |
njs_index_t self; | |
uint32_t nargs; | |
+ uint32_t first_default; | |
uint8_t ctor; /* 1 bit */ | |
uint8_t rest_parameters; /* 1 bit */ | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_generator.c | |
--- a/src/njs_generator.c Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_generator.c Fri Sep 24 19:10:26 2021 +0300 | |
@@ -281,7 +281,9 @@ static njs_int_t njs_generate_function_s | |
const njs_str_t *name, njs_uint_t depth); | |
static njs_int_t njs_generate_scope_end(njs_vm_t *vm, | |
njs_generator_t *generator, njs_parser_node_t *node); | |
-static int64_t njs_generate_lambda_variables(njs_vm_t *vm, | |
+static njs_int_t njs_generate_lambda_variables(njs_vm_t *vm, | |
+ njs_generator_t *generator, njs_parser_node_t *node); | |
+static njs_int_t njs_generate_lambda_variables_end(njs_vm_t *vm, | |
njs_generator_t *generator, njs_parser_node_t *node); | |
static njs_int_t njs_generate_return_statement(njs_vm_t *vm, | |
njs_generator_t *generator, njs_parser_node_t *node); | |
@@ -862,6 +864,11 @@ njs_generate_name(njs_vm_t *vm, njs_gene | |
NJS_VMCODE_NOT_INITIALIZED, 1, node); | |
variable->dst = node->index; | |
} | |
+ | |
+ } else if (var->argument && var->scope->in_args) { | |
+ njs_generate_code(generator, njs_vmcode_variable_t, variable, | |
+ NJS_VMCODE_NOT_INITIALIZED, 1, node); | |
+ variable->dst = node->index; | |
} | |
return njs_generator_stack_pop(vm, generator, NULL); | |
@@ -1881,7 +1888,7 @@ njs_generate_for_resolve_closure_cb(njs_ | |
njs_variable_t *var; | |
if (node->token_type == NJS_TOKEN_NAME) { | |
- var = njs_variable_resolve(vm, node); | |
+ var = njs_variable_resolve(vm, node, node->scope); | |
if (njs_fast_path(var != NULL)) { | |
closure = njs_variable_closure_test(node->scope, var->scope); | |
@@ -3609,6 +3616,7 @@ njs_generate_function_declaration(njs_vm | |
function->global = njs_function_scope(var->scope)->type == NJS_SCOPE_GLOBAL; | |
function->object.shared = 1; | |
function->args_count = lambda->nargs - lambda->rest_parameters; | |
+ function->first_default = lambda->first_default; | |
njs_set_function(&var->value, function); | |
@@ -3637,6 +3645,8 @@ njs_generate_function_scope(njs_vm_t *vm | |
node = node->right; | |
+ node->scope->lambda = lambda; | |
+ | |
code = njs_generate_scope(vm, &generator, node->scope, name); | |
if (njs_slow_path(code == NULL)) { | |
if (!njs_is_error(&vm->retval)) { | |
@@ -3672,7 +3682,6 @@ njs_generate_scope(njs_vm_t *vm, njs_gen | |
njs_parser_scope_t *scope, const njs_str_t *name) | |
{ | |
u_char *p; | |
- int64_t nargs; | |
njs_int_t ret; | |
njs_uint_t index; | |
njs_vm_code_t *code; | |
@@ -3688,11 +3697,6 @@ njs_generate_scope(njs_vm_t *vm, njs_gen | |
generator->code_start = p; | |
generator->code_end = p; | |
- nargs = njs_generate_lambda_variables(vm, generator, scope->top); | |
- if (njs_slow_path(nargs < NJS_OK)) { | |
- return NULL; | |
- } | |
- | |
if (vm->codes == NULL) { | |
vm->codes = njs_arr_create(vm->mem_pool, 4, sizeof(njs_vm_code_t)); | |
if (njs_slow_path(vm->codes == NULL)) { | |
@@ -3727,10 +3731,10 @@ njs_generate_scope(njs_vm_t *vm, njs_gen | |
scope->closures = generator->closures; | |
+ njs_generator_next(generator, njs_generate_lambda_variables, scope->top); | |
+ | |
njs_queue_init(&generator->stack); | |
- njs_generator_next(generator, njs_generate, scope->top); | |
- | |
ret = njs_generator_after(vm, generator, | |
njs_queue_first(&generator->stack), NULL, | |
njs_generate_scope_end, NULL, 0); | |
@@ -3738,6 +3742,13 @@ njs_generate_scope(njs_vm_t *vm, njs_gen | |
return NULL; | |
} | |
+ ret = njs_generator_after(vm, generator, | |
+ njs_queue_first(&generator->stack), scope->top, | |
+ njs_generate, NULL, 0); | |
+ if (njs_slow_path(ret != NJS_OK)) { | |
+ return NULL; | |
+ } | |
+ | |
do { | |
ret = generator->state(vm, generator, generator->node); | |
if (njs_slow_path(ret != NJS_OK)) { | |
@@ -3767,18 +3778,15 @@ njs_generate_scope_end(njs_vm_t *vm, njs | |
} | |
-static int64_t | |
+static njs_int_t | |
njs_generate_lambda_variables(njs_vm_t *vm, njs_generator_t *generator, | |
njs_parser_node_t *node) | |
{ | |
- int64_t nargs; | |
njs_variable_t *var; | |
njs_rbtree_node_t *rb_node; | |
njs_variable_node_t *var_node; | |
njs_vmcode_arguments_t *arguments; | |
- nargs = 0; | |
- | |
rb_node = njs_rbtree_min(&node->scope->variables); | |
while (njs_rbtree_is_there_successor(&node->scope->variables, rb_node)) { | |
@@ -3789,10 +3797,6 @@ njs_generate_lambda_variables(njs_vm_t * | |
break; | |
} | |
- if (var->argument) { | |
- nargs++; | |
- } | |
- | |
if (var->arguments_object) { | |
njs_generate_code(generator, njs_vmcode_arguments_t, arguments, | |
NJS_VMCODE_ARGUMENTS, 1, NULL); | |
@@ -3802,7 +3806,82 @@ njs_generate_lambda_variables(njs_vm_t * | |
rb_node = njs_rbtree_node_successor(&node->scope->variables, rb_node); | |
} | |
- return nargs; | |
+ node = node->scope->arguments; | |
+ | |
+ if (node == NULL) { | |
+ return njs_generator_stack_pop(vm, generator, NULL); | |
+ } | |
+ | |
+ return njs_generate_lambda_variables_end(vm, generator, node); | |
+} | |
+ | |
+ | |
+static njs_int_t | |
+njs_generate_lambda_variables_end(njs_vm_t *vm, njs_generator_t *generator, | |
+ njs_parser_node_t *node) | |
+{ | |
+ njs_variable_t *var; | |
+ njs_vmcode_move_t *move; | |
+ njs_parser_node_t *left; | |
+ njs_parser_scope_t *scope; | |
+ njs_vmcode_default_arg_t *default_arg; | |
+ | |
+ if (generator->context != NULL) { | |
+ left = generator->context; | |
+ scope = left->scope; | |
+ | |
+ scope->in_args = 0; | |
+ | |
+ var = njs_variable_reference(vm, left); | |
+ if (njs_slow_path(var == NULL)) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ var->init = 1; | |
+ | |
+ njs_generate_code_move(generator, move, var->index, left->right->index, | |
+ left); | |
+ | |
+ default_arg = njs_code_ptr(generator, njs_vmcode_default_arg_t, | |
+ scope->default_arg); | |
+ | |
+ default_arg->src = var->index; | |
+ default_arg->offset = njs_code_offset(generator, generator->code_end) | |
+ - scope->default_arg; | |
+ } else { | |
+ scope = node->scope; | |
+ } | |
+ | |
+ while (node != NULL) { | |
+ if (node->right != NULL) { | |
+ scope->default_arg = njs_code_offset(generator, | |
+ generator->code_end); | |
+ | |
+ scope->in_args = 1; | |
+ | |
+ njs_generate_code(generator, njs_vmcode_default_arg_t, default_arg, | |
+ NJS_VMCODE_DEFAULT_ARG, 0, node->right); | |
+ | |
+ njs_generator_next(generator, njs_generate, node->right); | |
+ | |
+ return njs_generator_after(vm, generator, | |
+ njs_queue_first(&generator->stack), | |
+ node->left, | |
+ njs_generate_lambda_variables_end, | |
+ node, 0); | |
+ } | |
+ | |
+ var = njs_variable_reference(vm, node); | |
+ if (njs_slow_path(var == NULL)) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ var->init = 1; | |
+ | |
+ node = node->left; | |
+ } | |
+ | |
+ return njs_generator_stack_pop(vm, generator, NULL); | |
} | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_parser.c | |
--- a/src/njs_parser.c Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_parser.c Fri Sep 24 19:10:26 2021 +0300 | |
@@ -399,6 +399,8 @@ static njs_int_t njs_parser_formal_param | |
njs_lexer_token_t *token, njs_queue_link_t *current); | |
static njs_int_t njs_parser_formal_parameters_after(njs_parser_t *parser, | |
njs_lexer_token_t *token, njs_queue_link_t *current); | |
+static njs_int_t njs_parser_formal_parameters_def_after(njs_parser_t *parser, | |
+ njs_lexer_token_t *token, njs_queue_link_t *current); | |
static njs_int_t njs_parser_arrow_function(njs_parser_t *parser, | |
njs_lexer_token_t *token, njs_queue_link_t *current); | |
@@ -4259,7 +4261,9 @@ static njs_int_t | |
njs_parser_match_arrow_expression(njs_parser_t *parser, | |
njs_lexer_token_t *token) | |
{ | |
- njs_bool_t rest_parameters; | |
+ njs_arr_t *stack; | |
+ njs_bool_t rest_parameters; | |
+ njs_token_type_t *type, need; | |
if (token->type == NJS_TOKEN_ASYNC) { | |
token = njs_lexer_peek_token(parser->lexer, token, 1); | |
@@ -4275,6 +4279,7 @@ njs_parser_match_arrow_expression(njs_pa | |
} | |
if (njs_lexer_token_is_binding_identifier(token)) { | |
+ stack = NULL; | |
goto arrow; | |
} | |
@@ -4283,8 +4288,15 @@ njs_parser_match_arrow_expression(njs_pa | |
return NJS_ERROR; | |
} | |
+ stack = njs_arr_create(parser->vm->mem_pool, 32, sizeof(njs_token_type_t)); | |
+ if (njs_slow_path(stack == NULL)) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
rest_parameters = 0; | |
+again: | |
+ | |
while (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) { | |
if (rest_parameters) { | |
@@ -4314,11 +4326,75 @@ njs_parser_match_arrow_expression(njs_pa | |
if (token == NULL) { | |
return NJS_ERROR; | |
} | |
+ | |
+ } else if (token->type == NJS_TOKEN_ASSIGNMENT) { | |
+ do { | |
+ token = njs_lexer_peek_token(parser->lexer, token, 0); | |
+ if (token == NULL) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ switch (token->type) { | |
+ case NJS_TOKEN_OPEN_BRACE: | |
+ need = NJS_TOKEN_CLOSE_BRACE; | |
+ break; | |
+ | |
+ case NJS_TOKEN_OPEN_BRACKET: | |
+ need = NJS_TOKEN_CLOSE_BRACKET; | |
+ break; | |
+ | |
+ case NJS_TOKEN_OPEN_PARENTHESIS: | |
+ need = NJS_TOKEN_CLOSE_PARENTHESIS; | |
+ break; | |
+ | |
+ case NJS_TOKEN_COMMA: | |
+ if (njs_arr_is_empty(stack)) { | |
+ token = njs_lexer_peek_token(parser->lexer, token, 0); | |
+ if (token == NULL) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ goto again; | |
+ } | |
+ | |
+ continue; | |
+ | |
+ case NJS_TOKEN_CLOSE_PARENTHESIS: | |
+ if (njs_arr_is_empty(stack)) { | |
+ goto arrow; | |
+ } | |
+ | |
+ /* Fall through. */ | |
+ | |
+ default: | |
+ if (!njs_arr_is_empty(stack)) { | |
+ type = njs_arr_last(stack); | |
+ | |
+ if (*type == token->type) { | |
+ (void) njs_arr_remove_last(stack); | |
+ } | |
+ } | |
+ | |
+ continue; | |
+ } | |
+ | |
+ type = njs_arr_add(stack); | |
+ if (njs_slow_path(type == NULL)) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ *type = need; | |
+ | |
+ } while (1); | |
} | |
} | |
arrow: | |
+ if (stack != NULL) { | |
+ njs_arr_destroy(stack); | |
+ } | |
+ | |
token = njs_lexer_peek_token(parser->lexer, token, 1); | |
if (token == NULL) { | |
return NJS_ERROR; | |
@@ -6921,8 +6997,10 @@ static njs_int_t | |
njs_parser_formal_parameters(njs_parser_t *parser, njs_lexer_token_t *token, | |
njs_queue_link_t *current) | |
{ | |
+ njs_int_t ret; | |
njs_variable_t *arg; | |
njs_rbtree_node_t *rb_node; | |
+ njs_parser_node_t *node, *name; | |
njs_variable_node_t var_node; | |
njs_function_lambda_t *lambda; | |
@@ -6975,24 +7053,70 @@ njs_parser_formal_parameters(njs_parser_ | |
arg->self = 0; | |
+ node = njs_parser_node_new(parser, NJS_TOKEN_NAME); | |
+ if (njs_slow_path(node == NULL)) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ ret = njs_parser_variable_reference(parser, parser->scope, node, | |
+ token->unique_id, | |
+ NJS_DECLARATION); | |
+ if (njs_slow_path(ret != NJS_OK)) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
} else { | |
- arg = njs_variable_add(parser, parser->scope, | |
- token->unique_id, NJS_VARIABLE_VAR); | |
+ node = njs_parser_variable_node(parser, token->unique_id, | |
+ NJS_VARIABLE_VAR, &arg); | |
+ if (njs_slow_path(node == NULL)) { | |
+ return NJS_ERROR; | |
+ } | |
} | |
if (arg == NULL) { | |
return NJS_ERROR; | |
} | |
+ if (parser->scope->arguments != NULL) { | |
+ name = parser->scope->arguments; | |
+ | |
+ while (name->left != NULL) { | |
+ name = name->left; | |
+ } | |
+ | |
+ name->left = node; | |
+ | |
+ } else { | |
+ parser->scope->arguments = node; | |
+ } | |
+ | |
arg->argument = 1; | |
lambda->nargs++; | |
- /* Crutch for temporary storage. */ | |
- parser->node = (njs_parser_node_t *) arg; | |
- | |
njs_lexer_consume_token(parser->lexer, 1); | |
+ token = njs_lexer_token(parser->lexer, 0); | |
+ if (token == NULL) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ if (token->type == NJS_TOKEN_ASSIGNMENT) { | |
+ njs_lexer_consume_token(parser->lexer, 1); | |
+ | |
+ njs_parser_next(parser, njs_parser_assignment_expression); | |
+ | |
+ parser->node = NULL; | |
+ node->right = parser->target; | |
+ | |
+ if (lambda->first_default == 0) { | |
+ lambda->first_default = lambda->nargs; | |
+ } | |
+ | |
+ return njs_parser_after(parser, current, node, 0, | |
+ njs_parser_formal_parameters_def_after); | |
+ } | |
+ | |
njs_parser_next(parser, njs_parser_formal_parameters_after); | |
break; | |
} | |
@@ -7030,6 +7154,26 @@ njs_parser_formal_parameters_after(njs_p | |
} | |
+static njs_int_t | |
+njs_parser_formal_parameters_def_after(njs_parser_t *parser, | |
+ njs_lexer_token_t *token, njs_queue_link_t *current) | |
+{ | |
+ njs_parser_node_t *node; | |
+ | |
+ if (parser->ret != NJS_OK) { | |
+ return njs_parser_failed(parser); | |
+ } | |
+ | |
+ node = parser->target; | |
+ parser->target = node->right; | |
+ node->right = parser->node; | |
+ | |
+ njs_parser_next(parser, njs_parser_formal_parameters_after); | |
+ | |
+ return NJS_OK; | |
+} | |
+ | |
+ | |
/* | |
* 14.2 Arrow Function Definitions | |
* | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_parser.h | |
--- a/src/njs_parser.h Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_parser.h Fri Sep 24 19:10:26 2021 +0300 | |
@@ -11,6 +11,7 @@ | |
struct njs_parser_scope_s { | |
njs_parser_node_t *top; | |
+ njs_parser_node_t *arguments; | |
njs_parser_scope_t *parent; | |
njs_rbtree_t variables; | |
@@ -20,8 +21,12 @@ struct njs_parser_scope_s { | |
njs_arr_t *closures; | |
njs_arr_t *declarations; | |
+ njs_function_lambda_t *lambda; | |
+ njs_jump_off_t default_arg; | |
+ | |
uint32_t temp; | |
uint32_t items; | |
+ uint32_t nargs; | |
njs_str_t cwd; | |
njs_str_t file; | |
@@ -119,7 +124,8 @@ njs_int_t njs_parser_module_lambda(njs_p | |
njs_lexer_token_t *token, njs_queue_link_t *current); | |
njs_bool_t njs_variable_closure_test(njs_parser_scope_t *root, | |
njs_parser_scope_t *scope); | |
-njs_variable_t *njs_variable_resolve(njs_vm_t *vm, njs_parser_node_t *node); | |
+njs_variable_t *njs_variable_resolve(njs_vm_t *vm, njs_parser_node_t *node, | |
+ njs_parser_scope_t *scope); | |
njs_index_t njs_variable_index(njs_vm_t *vm, njs_parser_node_t *node); | |
njs_bool_t njs_parser_has_side_effect(njs_parser_node_t *node); | |
njs_int_t njs_parser_variable_reference(njs_parser_t *parser, | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_value.h | |
--- a/src/njs_value.h Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_value.h Fri Sep 24 19:10:26 2021 +0300 | |
@@ -268,6 +268,7 @@ struct njs_function_s { | |
uint8_t args_offset; | |
uint8_t args_count:4; | |
+ uint8_t first_default:4; | |
uint8_t closure_copied:1; | |
uint8_t native:1; | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_variable.c | |
--- a/src/njs_variable.c Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_variable.c Fri Sep 24 19:10:26 2021 +0300 | |
@@ -406,15 +406,14 @@ njs_variable_closure_test(njs_parser_sco | |
njs_variable_t * | |
-njs_variable_resolve(njs_vm_t *vm, njs_parser_node_t *node) | |
+njs_variable_resolve(njs_vm_t *vm, njs_parser_node_t *node, | |
+ njs_parser_scope_t *scope) | |
{ | |
njs_rbtree_node_t *rb_node; | |
- njs_parser_scope_t *scope; | |
njs_variable_node_t var_node; | |
njs_variable_reference_t *ref; | |
ref = &node->u.reference; | |
- scope = node->scope; | |
var_node.key = ref->unique_id; | |
@@ -529,6 +528,7 @@ njs_variable_t * | |
njs_variable_reference(njs_vm_t *vm, njs_parser_node_t *node) | |
{ | |
njs_bool_t closure; | |
+ njs_variable_t *var; | |
njs_rbtree_node_t *rb_node; | |
njs_parser_scope_t *scope; | |
njs_parser_rbtree_node_t *parse_node, ref_node; | |
@@ -537,12 +537,28 @@ njs_variable_reference(njs_vm_t *vm, njs | |
ref = &node->u.reference; | |
scope = node->scope; | |
- if (ref->variable == NULL) { | |
- ref->variable = njs_variable_resolve(vm, node); | |
+ if (scope->in_args && node->token_type != NJS_TOKEN_THIS | |
+ && node->token_type != NJS_TOKEN_ARGUMENTS) | |
+ { | |
+ var = ref->variable; | |
+ | |
+ if (var == NULL) { | |
+ var = njs_variable_resolve(vm, node, scope); | |
+ if (njs_slow_path(var == NULL)) { | |
+ goto not_found; | |
+ } | |
+ | |
+ if (!var->argument && var->scope == scope) { | |
+ goto not_found; | |
+ } | |
+ | |
+ ref->variable = var; | |
+ } | |
+ | |
+ } else if (ref->variable == NULL) { | |
+ ref->variable = njs_variable_resolve(vm, node, scope); | |
if (njs_slow_path(ref->variable == NULL)) { | |
- ref->not_defined = 1; | |
- | |
- return NULL; | |
+ goto not_found; | |
} | |
} | |
@@ -578,6 +594,12 @@ njs_variable_reference(njs_vm_t *vm, njs | |
} | |
return ref->variable; | |
+ | |
+not_found: | |
+ | |
+ ref->not_defined = 1; | |
+ | |
+ return NULL; | |
} | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_vmcode.c | |
--- a/src/njs_vmcode.c Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_vmcode.c Fri Sep 24 19:10:26 2021 +0300 | |
@@ -106,6 +106,7 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c | |
njs_vmcode_test_jump_t *test_jump; | |
njs_vmcode_equal_jump_t *equal; | |
njs_vmcode_try_return_t *try_return; | |
+ njs_vmcode_default_arg_t *default_arg; | |
njs_vmcode_method_frame_t *method_frame; | |
njs_vmcode_function_copy_t *fcopy; | |
njs_vmcode_prop_accessor_t *accessor; | |
@@ -641,6 +642,20 @@ next: | |
ret = sizeof(njs_vmcode_move_arg_t); | |
break; | |
+ case NJS_VMCODE_DEFAULT_ARG: | |
+ default_arg = (njs_vmcode_default_arg_t *) pc; | |
+ | |
+ njs_vmcode_operand(vm, default_arg->src, value1); | |
+ | |
+ if (njs_is_defined(value1)) { | |
+ ret = default_arg->offset; | |
+ | |
+ } else { | |
+ ret = sizeof(njs_vmcode_default_arg_t); | |
+ } | |
+ | |
+ break; | |
+ | |
case NJS_VMCODE_STOP: | |
njs_vmcode_operand(vm, (njs_index_t) value2, value2); | |
vm->retval = *value2; | |
diff -r 6feba0e602ee -r 53c99c659d82 src/njs_vmcode.h | |
--- a/src/njs_vmcode.h Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/njs_vmcode.h Fri Sep 24 19:10:26 2021 +0300 | |
@@ -32,6 +32,7 @@ typedef uint8_t | |
enum { | |
NJS_VMCODE_MOVE_ARG = 0, | |
+ NJS_VMCODE_DEFAULT_ARG, | |
NJS_VMCODE_STOP, | |
NJS_VMCODE_JUMP, | |
NJS_VMCODE_PROPERTY_SET, | |
@@ -414,6 +415,13 @@ typedef struct { | |
typedef struct { | |
njs_vmcode_t code; | |
+ njs_index_t src; | |
+ njs_jump_off_t offset; | |
+} njs_vmcode_default_arg_t; | |
+ | |
+ | |
+typedef struct { | |
+ njs_vmcode_t code; | |
njs_value_t *function; | |
njs_index_t retval; | |
} njs_vmcode_function_copy_t; | |
diff -r 6feba0e602ee -r 53c99c659d82 src/test/njs_unit_test.c | |
--- a/src/test/njs_unit_test.c Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/src/test/njs_unit_test.c Fri Sep 24 19:10:26 2021 +0300 | |
@@ -20532,6 +20532,77 @@ static njs_unit_test_t njs_test[] = | |
{ njs_str("let name = 'af', x = {async [name]() {await Promise.resolve(1)}}; x.af"), | |
njs_str("[object AsyncFunction]") }, | |
+ | |
+ /* Default arguments in functions. */ | |
+ | |
+ { njs_str("function abc(a = 1, b = 2, c = 3) {return a + b + c} abc()"), | |
+ njs_str("6") }, | |
+ | |
+ { njs_str("function abc(a = 1, b = a + 2, c = b + 3) {return a + b + c} abc()"), | |
+ njs_str("10") }, | |
+ | |
+ { njs_str("function abc(a = 1, b, c = 3) {return a + b + c} abc(undefined, 10, 5)"), | |
+ njs_str("16") }, | |
+ | |
+ { njs_str("function abc(a = b, b = 2, c = 3) {return a + b + c} abc()"), | |
+ njs_str("ReferenceError: cannot access variable before initialization") }, | |
+ | |
+ { njs_str("function abc(a = 1, b, c) {} abc.length"), | |
+ njs_str("0") }, | |
+ | |
+ { njs_str("function abc(a, b = 2, c) {} abc.length"), | |
+ njs_str("1") }, | |
+ | |
+ { njs_str("function abc(a, b, c = 3) {} abc.length"), | |
+ njs_str("2") }, | |
+ | |
+ { njs_str("function abc(a = x) {let x = 1; return a + x} abc()"), | |
+ njs_str("ReferenceError: \"x\" is not defined") }, | |
+ | |
+ { njs_str("function abc(a = x) {let x = 1; return a + x} abc(1)"), | |
+ njs_str("2") }, | |
+ | |
+ { njs_str("function abc(a = a) {return a} abc()"), | |
+ njs_str("ReferenceError: cannot access variable before initialization") }, | |
+ | |
+ { njs_str("function abc(a = a) {return a} abc(1)"), | |
+ njs_str("1") }, | |
+ | |
+ { njs_str("function abc(a, b = a, c = b) {return a + b + c} abc(1)"), | |
+ njs_str("3") }, | |
+ | |
+ { njs_str("function abc(a = (() => a)()) {return a} abc()"), | |
+ njs_str("ReferenceError: cannot access variable before initialization") }, | |
+ | |
+ { njs_str("function abc(a = ((a = 1) => a)()) {return a} abc()"), | |
+ njs_str("1") }, | |
+ | |
+ { njs_str("let go = function (x = 100, y = 200) {return x + y};" | |
+ "function abc(a = go(undefined, 10)) {return a} abc()"), | |
+ njs_str("110") }, | |
+ | |
+ { njs_str("function abc(a = this.x) {return a} abc.call({x: 123})"), | |
+ njs_str("123") }, | |
+ | |
+ { njs_str("function abc(a, b = arguments[0], c = abc) {return [a, b, c]} abc.call({x: 1}, 1)"), | |
+ njs_str("1,1,[object Function]") }, | |
+ | |
+ { njs_str("let func = function x(x = 1) {return x}; func()"), | |
+ njs_str("1") }, | |
+ | |
+ { njs_str("let func = (a = (() => {return 1})(), b = 2) => {return a + b}; func()"), | |
+ njs_str("3") }, | |
+ | |
+ { njs_str("let func = (a = (async () => 1)()) => {return a}; func()"), | |
+ njs_str("[object Promise]") }, | |
+ | |
+ { njs_str("let afunc = async () => {let x = await new Promise((r) => r(123)); return x};" | |
+ "let func = (a = afunc()) => {return a}; func()"), | |
+ njs_str("[object Promise]") }, | |
+ | |
+ { njs_str("let afunc = async () => {let x = await 1; return x};" | |
+ "let func = (a = afunc) => {return a}; func()"), | |
+ njs_str("[object AsyncFunction]") }, | |
}; | |
diff -r 6feba0e602ee -r 53c99c659d82 test/js/async_await_dflt.js | |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | |
+++ b/test/js/async_await_dflt.js Fri Sep 24 19:10:26 2021 +0300 | |
@@ -0,0 +1,32 @@ | |
+function pr(x) { | |
+ return new Promise(resolve => {resolve(x)}) | |
+ .then(v => v).then(v => v); | |
+} | |
+ | |
+let stage = []; | |
+ | |
+async function f() { | |
+ let sum = 0; | |
+ | |
+ stage.push(2); | |
+ | |
+ const a1 = await pr(10); | |
+ | |
+ stage.push(4); | |
+ | |
+ const a2 = await pr(20); | |
+ | |
+ stage.push(5); | |
+ | |
+ return a1 + a2; | |
+} | |
+ | |
+stage.push(1); | |
+ | |
+function abc(a = f().then(v => {console.log(v, stage.join(", "))})) { | |
+ return a; | |
+} | |
+ | |
+abc().then(v => console.log("end")) | |
+ | |
+stage.push(3); | |
diff -r 6feba0e602ee -r 53c99c659d82 test/njs_expect_test.exp | |
--- a/test/njs_expect_test.exp Fri Sep 17 18:29:40 2021 +0000 | |
+++ b/test/njs_expect_test.exp Fri Sep 24 19:10:26 2021 +0300 | |
@@ -1176,3 +1176,7 @@ njs_run {"./test/js/async_await_try_reso | |
njs_run {"./test/js/async_await_many_call.js"} \ | |
"\\\['First: SUN MOON','Second: CAT MOUSE','Third: MAN WOMAN']" | |
+ | |
+njs_run {"./test/js/async_await_dflt.js"} \ | |
+"30 1, 2, 3, 4, 5 | |
+end" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment