Non-local this is introduced to support arrow functions.
this is non-local when reference scope != first non-arrow
function scope.
nxt_string("OBJECT ") },
{ njs_vmcode_function, sizeof(njs_vmcode_function_t),
nxt_string("FUNCTION ") },
+ { njs_vmcode_this, sizeof(njs_vmcode_this_t),
+ nxt_string("THIS ") },
{ njs_vmcode_arguments, sizeof(njs_vmcode_arguments_t),
nxt_string("ARGUMENTS ") },
{ njs_vmcode_regexp, sizeof(njs_vmcode_regexp_t),
case NJS_TOKEN_NAME:
case NJS_TOKEN_ARGUMENTS:
+ case NJS_TOKEN_NON_LOCAL_THIS:
return njs_generate_name(vm, generator, node);
case NJS_TOKEN_GLOBAL_THIS:
njs_variable_t *var;
njs_vmcode_move_t *move;
nxt_lvlhsh_each_t lhe;
+ njs_vmcode_this_t *this;
njs_vmcode_arguments_t *arguments;
nxt_lvlhsh_each_init(&lhe, &njs_variables_hash_proto);
njs_generate_code_move(generator, move, var->index, index);
}
+ if (var->this_object) {
+ njs_generate_code(generator, njs_vmcode_this_t, this,
+ njs_vmcode_this, 1, 0);
+ this->dst = var->index;
+ }
+
if (var->arguments_object) {
njs_generate_code(generator, njs_vmcode_arguments_t, arguments,
njs_vmcode_arguments, 1, 0);
NJS_TOKEN_THROW,
NJS_TOKEN_THIS,
+ NJS_TOKEN_NON_LOCAL_THIS,
NJS_TOKEN_ARGUMENTS,
#define NJS_TOKEN_FIRST_OBJECT NJS_TOKEN_GLOBAL_THIS
}
+nxt_inline njs_parser_scope_t *
+njs_function_scope(njs_parser_scope_t *scope)
+{
+ while (scope->type != NJS_SCOPE_GLOBAL) {
+ if (scope->type == NJS_SCOPE_FUNCTION) {
+ return scope;
+ }
+
+ scope = scope->parent;
+ }
+
+ return NULL;
+}
+
+
extern const nxt_lvlhsh_proto_t njs_keyword_hash_proto;
while (scope->type != NJS_SCOPE_GLOBAL) {
if (scope->type == NJS_SCOPE_FUNCTION) {
- node->index = NJS_INDEX_THIS;
break;
}
scope = scope->parent;
}
- if (node->index == NJS_INDEX_THIS) {
+ if (scope->type != NJS_SCOPE_GLOBAL) {
+ if (njs_function_scope(scope)
+ == njs_function_scope(parser->scope))
+ {
+ node->index = NJS_INDEX_THIS;
+
+ } else {
+ node->token = NJS_TOKEN_NON_LOCAL_THIS;
+
+ node->token_line = token_line;
+
+ ret = njs_variable_reference(vm, parser->scope, node, name,
+ hash, NJS_REFERENCE);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NULL;
+ }
+
+ var = njs_variable_add(vm, parser->scope, name, hash,
+ NJS_VARIABLE_VAR);
+ if (nxt_slow_path(var == NULL)) {
+ return NULL;
+ }
+
+ var->this_object = 1;
+ }
+
break;
}
njs_variable_type_t type:8; /* 3 bits */
uint8_t argument;
+ uint8_t this_object;
uint8_t arguments_object;
njs_index_t index;
}
+njs_ret_t
+njs_vmcode_this(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+{
+ njs_frame_t *frame;
+ njs_value_t *value;
+ njs_vmcode_this_t *code;
+
+ frame = (njs_frame_t *) vm->active_frame;
+ code = (njs_vmcode_this_t *) vm->current;
+
+ value = njs_vmcode_operand(vm, code->dst);
+ *value = frame->native.arguments[0];
+
+ return sizeof(njs_vmcode_this_t);
+}
+
+
njs_ret_t
njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
{
} njs_vmcode_object_t;
+typedef struct {
+ njs_vmcode_t code;
+ njs_index_t dst;
+} njs_vmcode_this_t;
+
+
typedef struct {
njs_vmcode_t code;
njs_index_t dst;
njs_value_t *inlvd2);
njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *inlvd1,
njs_value_t *invld2);
+njs_ret_t njs_vmcode_this(njs_vm_t *vm, njs_value_t *inlvd1,
+ njs_value_t *invld2);
njs_ret_t njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *inlvd1,
njs_value_t *invld2);
njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *inlvd1,