variables are not supported anymore.
njs/njs_string.h \
njs/njs_object.h \
njs/njs_function.h \
+ njs/njs_variable.h \
njs/njs_parser.h \
njs/njs_parser.c \
njs/njs_number.h \
njs/njs_object.h \
njs/njs_function.h \
+ njs/njs_variable.h \
njs/njs_parser.h \
njs/njs_parser_expression.c \
njs/njs_string.h \
njs/njs_object.h \
njs/njs_function.h \
+ njs/njs_variable.h \
njs/njs_parser.h \
njs/njs_generator.c \
{ njs_vmcode_move, sizeof(njs_vmcode_move_t),
nxt_string("MOVE ") },
- { njs_vmcode_validate, sizeof(njs_vmcode_validate_t),
- nxt_string("VALIDATE ") },
{ njs_vmcode_throw, sizeof(njs_vmcode_throw_t),
nxt_string("THROW ") },
#if (NXT_DEBUG)
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = NULL;
#endif
- frame->prev_local = vm->scopes[NJS_SCOPE_LOCAL];
- vm->scopes[NJS_SCOPE_LOCAL] = frame->local;
+ frame->prev_local = vm->scopes[NJS_SCOPE_FUNCTION];
+ vm->scopes[NJS_SCOPE_FUNCTION] = frame->local;
return NJS_APPLIED;
}
njs_parser_node_t *node);
static nxt_int_t njs_generate_builtin_object(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node);
-static nxt_int_t njs_generate_variable(njs_parser_t *parser,
+static nxt_int_t njs_generate_variable(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node);
+static nxt_int_t njs_generate_var_statement(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node);
static nxt_int_t njs_generate_if_statement(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node);
njs_parser_t *parser, njs_parser_node_t *node);
static nxt_int_t njs_generate_2addr_operation(njs_vm_t *vm,
njs_parser_t *parser, njs_parser_node_t *node);
+static nxt_int_t njs_generate_typeof_operation(njs_vm_t *vm,
+ njs_parser_t *parser, njs_parser_node_t *node);
static nxt_int_t njs_generate_inc_dec_operation(njs_vm_t *vm,
njs_parser_t *parser, njs_parser_node_t *node, nxt_bool_t post);
static nxt_int_t njs_generate_function_declaration(njs_vm_t *vm,
static nxt_noinline njs_index_t njs_generator_dest_index(njs_vm_t *vm,
njs_parser_t *parser, njs_parser_node_t *node);
static nxt_noinline njs_index_t
- njs_generator_object_dest_index(njs_parser_t *parser,
+ njs_generator_object_dest_index(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node);
-static njs_index_t njs_generator_node_temp_index_get(njs_parser_t *parser,
- njs_parser_node_t *node);
-static nxt_noinline njs_index_t
- njs_generator_temp_index_get(njs_parser_t *parser);
+static njs_index_t njs_generator_node_temp_index_get(njs_vm_t *vm,
+ njs_parser_t *parser, njs_parser_node_t *node);
+static nxt_noinline njs_index_t njs_generator_temp_index_get(njs_vm_t *vm,
+ njs_parser_t *parser, njs_parser_node_t *node);
static nxt_noinline nxt_int_t
njs_generator_children_indexes_release(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node);
njs_parser_t *parser, njs_parser_node_t *node);
static nxt_noinline nxt_int_t njs_generator_index_release(njs_vm_t *vm,
njs_parser_t *parser, njs_index_t index);
-nxt_inline nxt_bool_t njs_generator_is_constant(njs_parser_node_t *node);
static const nxt_str_t no_label = { 0, NULL };
switch (node->token) {
+ case NJS_TOKEN_VAR:
+ return njs_generate_var_statement(vm, parser, node);
+
case NJS_TOKEN_IF:
return njs_generate_if_statement(vm, parser, node);
case NJS_TOKEN_DELETE:
case NJS_TOKEN_VOID:
- case NJS_TOKEN_TYPEOF:
case NJS_TOKEN_UNARY_PLUS:
case NJS_TOKEN_UNARY_NEGATION:
case NJS_TOKEN_LOGICAL_NOT:
case NJS_TOKEN_BITWISE_NOT:
return njs_generate_2addr_operation(vm, parser, node);
+ case NJS_TOKEN_TYPEOF:
+ return njs_generate_typeof_operation(vm, parser, node);
+
case NJS_TOKEN_INCREMENT:
case NJS_TOKEN_DECREMENT:
return njs_generate_inc_dec_operation(vm, parser, node, 0);
static nxt_int_t
njs_generate_name(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
{
+ njs_variable_t *var;
njs_vmcode_object_copy_t *copy;
- if (node->u.variable->function) {
+ var = njs_variable_get(vm, node, NJS_NAME_REFERENCE);
+ if (nxt_slow_path(var == NULL)) {
+ return NXT_ERROR;
+ }
+
+ if (var->type == NJS_VARIABLE_FUNCTION) {
node->index = njs_generator_dest_index(vm, parser, node);
if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
copy->code.operands = NJS_VMCODE_2OPERANDS;
copy->code.retval = NJS_VMCODE_RETVAL;
copy->retval = node->index;
- copy->object = node->u.variable->index;
+ copy->object = var->index;
return NXT_OK;
}
- return njs_generate_variable(parser, node);
+ return njs_generate_variable(vm, parser, node);
}
njs_index_t index;
njs_vmcode_object_copy_t *copy;
- index = node->index;
+ index = njs_variable_index(vm, node, NJS_NAME_REFERENCE);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
node->index = njs_generator_dest_index(vm, parser, node);
if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
static nxt_int_t
-njs_generate_variable(njs_parser_t *parser, njs_parser_node_t *node)
+njs_generate_variable(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node)
+{
+ njs_index_t index;
+
+ index = njs_variable_index(vm, node, NJS_NAME_REFERENCE);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ node->index = index;
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
+njs_generate_var_statement(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node)
{
- njs_value_t *value;
- njs_vmcode_validate_t *validate;
+ nxt_int_t ret;
+ njs_index_t index;
+ njs_parser_node_t *lvalue, *expr;
+ njs_vmcode_move_t *move;
- node->index = node->u.variable->index;
+ lvalue = node->left;
- if (node->state == NJS_VARIABLE_NORMAL
- && node->u.variable->state < NJS_VARIABLE_SET)
- {
- njs_generate_code(parser, njs_vmcode_validate_t, validate);
- validate->code.operation = njs_vmcode_validate;
- validate->code.operands = NJS_VMCODE_NO_OPERAND;
- validate->code.retval = NJS_VMCODE_NO_RETVAL;
- validate->index = node->index;
+ index = njs_variable_index(vm, lvalue, NJS_NAME_DECLARATION);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ lvalue->index = index;
+
+ expr = node->right;
- value = njs_variable_value(parser, node->index);
- njs_set_invalid(value);
+ if (expr == NULL) {
+ /* Variable is only declared. */
+ return NXT_OK;
+ }
+
+ expr->dest = lvalue;
+
+ ret = njs_generator(vm, parser, expr);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+
+ /*
+ * lvalue and expression indexes are equal if the expression is an
+ * empty object or expression result is stored directly in variable.
+ */
+ if (lvalue->index != expr->index) {
+ njs_generate_code(parser, njs_vmcode_move_t, move);
+ move->code.operation = njs_vmcode_move;
+ move->code.operands = NJS_VMCODE_2OPERANDS;
+ move->code.retval = NJS_VMCODE_RETVAL;
+ move->dst = lvalue->index;
+ move->src = expr->index;
}
+ node->index = expr->index;
+ node->temporary = expr->temporary;
+
return NXT_OK;
}
index = expr->index;
if (!expr->temporary) {
- index = njs_generator_temp_index_get(parser);
+ index = njs_generator_temp_index_get(vm, parser, swtch);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
njs_generate_code(parser, njs_vmcode_move_t, move);
move->code.operation = njs_vmcode_move;
prop_foreach->code.retval = NJS_VMCODE_RETVAL;
prop_foreach->object = foreach->right->index;
- index = njs_generator_temp_index_get(parser);
+ index = njs_generator_temp_index_get(vm, parser, foreach->right);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
prop_foreach->next = index;
/* The loop body. */
njs_generate_assignment(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- nxt_int_t ret;
- njs_value_t *value;
- njs_parser_node_t *lvalue, *expr, *object, *property;
- njs_vmcode_move_t *move;
- njs_vmcode_prop_set_t *prop_set;
+ nxt_int_t ret;
+ njs_index_t index;
+ njs_parser_node_t *lvalue, *expr, *object, *property;
+ njs_vmcode_move_t *move;
+ njs_vmcode_prop_set_t *prop_set;
lvalue = node->left;
expr = node->right;
if (lvalue->token == NJS_TOKEN_NAME) {
- lvalue->index = lvalue->u.variable->index;
-
- /* Use a constant value is stored as variable initial value. */
-
- if (njs_generator_is_constant(expr)) {
-
- ret = njs_generator(vm, parser, expr);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
- }
-
- if (lvalue->state == NJS_VARIABLE_FIRST_ASSIGNMENT) {
- value = njs_variable_value(parser, lvalue->index);
- *value = expr->u.value;
- node->index = expr->index;
-
- return NXT_OK;
- }
+ index = njs_variable_index(vm, lvalue, NJS_NAME_REFERENCE);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
}
+ lvalue->index = index;
+
expr->dest = lvalue;
ret = njs_generator(vm, parser, expr);
move->code.operands = NJS_VMCODE_2OPERANDS;
move->code.retval = NJS_VMCODE_RETVAL;
move->src = object->index;
- move->dst = njs_generator_node_temp_index_get(parser, object);
+
+ index = njs_generator_node_temp_index_get(vm, parser, object);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ move->dst = index;
}
if (property->token == NJS_TOKEN_NAME) {
move->code.operands = NJS_VMCODE_2OPERANDS;
move->code.retval = NJS_VMCODE_RETVAL;
move->src = property->index;
- move->dst = njs_generator_node_temp_index_get(parser, property);
+
+ index = njs_generator_node_temp_index_get(vm, parser, property);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ move->dst = index;
}
}
lvalue = node->left;
if (lvalue->token == NJS_TOKEN_NAME) {
- ret = njs_generate_variable(parser, lvalue);
+ ret = njs_generate_variable(vm, parser, lvalue);
if (nxt_slow_path(ret != NXT_OK)) {
return ret;
}
move->code.retval = NJS_VMCODE_RETVAL;
move->src = lvalue->index;
- index = njs_generator_temp_index_get(parser);
+ index = njs_generator_temp_index_get(vm, parser, expr);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
move->dst = index;
}
return ret;
}
+ index = njs_generator_node_temp_index_get(vm, parser, node);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
njs_generate_code(parser, njs_vmcode_prop_get_t, prop_get);
prop_get->code.operation = njs_vmcode_property_get;
prop_get->code.operands = NJS_VMCODE_3OPERANDS;
prop_get->code.retval = NJS_VMCODE_RETVAL;
- prop_get->value = njs_generator_node_temp_index_get(parser, node);
+ prop_get->value = index;
prop_get->object = object->index;
prop_get->property = property->index;
{
njs_vmcode_object_t *object;
- node->index = njs_generator_object_dest_index(parser, node);
+ node->index = njs_generator_object_dest_index(vm, parser, node);
+ if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
njs_generate_code(parser, njs_vmcode_object_t, object);
object->code.operation = njs_vmcode_object;
object->code.retval = NJS_VMCODE_RETVAL;
object->retval = node->index;
- if (node->left == NULL) {
- return NXT_OK;
- }
-
/* Initialize object. */
-
return njs_generator(vm, parser, node->left);
}
{
njs_vmcode_array_t *array;
- node->index = njs_generator_object_dest_index(parser, node);
+ node->index = njs_generator_object_dest_index(vm, parser, node);
+ if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
njs_generate_code(parser, njs_vmcode_array_t, array);
array->code.operation = njs_vmcode_array;
ret = njs_generate_function_scope(vm, lambda, node);
- if (nxt_fast_path(ret == NXT_OK)) {
- njs_generate_code(parser, njs_vmcode_function_t, function);
- function->code.operation = njs_vmcode_function;
- function->code.operands = NJS_VMCODE_1OPERAND;
- function->code.retval = NJS_VMCODE_RETVAL;
- function->lambda = lambda;
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+
+ njs_generate_code(parser, njs_vmcode_function_t, function);
+ function->code.operation = njs_vmcode_function;
+ function->code.operands = NJS_VMCODE_1OPERAND;
+ function->code.retval = NJS_VMCODE_RETVAL;
+ function->lambda = lambda;
- node->index = njs_generator_object_dest_index(parser, node);
- function->retval = node->index;
+ node->index = njs_generator_object_dest_index(vm, parser, node);
+ if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
}
- return ret;
+ function->retval = node->index;
+
+ return NXT_OK;
}
{
njs_vmcode_regexp_t *regexp;
- node->index = njs_generator_object_dest_index(parser, node);
+ node->index = njs_generator_object_dest_index(vm, parser, node);
+ if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
njs_generate_code(parser, njs_vmcode_regexp_t, regexp);
regexp->code.operation = njs_vmcode_regexp;
njs_parser_node_t *node)
{
nxt_int_t ret;
+ njs_index_t index;
njs_parser_node_t *left, *right;
njs_vmcode_move_t *move;
njs_vmcode_3addr_t *code;
move->code.operands = NJS_VMCODE_2OPERANDS;
move->code.retval = NJS_VMCODE_RETVAL;
move->src = left->index;
- move->dst = njs_generator_node_temp_index_get(parser, left);
+
+ index = njs_generator_node_temp_index_get(vm, parser, left);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ move->dst = index;
}
}
}
+static nxt_int_t
+njs_generate_typeof_operation(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node)
+{
+ nxt_int_t ret;
+ njs_index_t index;
+ njs_parser_node_t *expr;
+ njs_vmcode_2addr_t *code;
+
+ expr = node->left;
+
+ if (expr->token == NJS_TOKEN_NAME) {
+ index = njs_variable_index(vm, expr, NJS_NAME_TYPEOF);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ expr->index = index;
+
+ } else {
+ ret = njs_generator(vm, parser, node->left);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+ }
+
+ njs_generate_code(parser, njs_vmcode_2addr_t, code);
+ code->code.operation = node->u.operation;
+ code->code.operands = NJS_VMCODE_2OPERANDS;
+ code->code.retval = NJS_VMCODE_RETVAL;
+ code->src = node->left->index;
+
+ node->index = njs_generator_dest_index(vm, parser, node);
+ if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+ return node->index;
+ }
+
+ code->dst = node->index;
+
+ nxt_thread_log_debug("CODE2 %p, %p", code->dst, code->src);
+
+ return NXT_OK;
+}
+
+
static nxt_int_t
njs_generate_inc_dec_operation(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node, nxt_bool_t post)
if (lvalue->token == NJS_TOKEN_NAME) {
- ret = njs_generate_variable(parser, lvalue);
+ ret = njs_generate_variable(vm, parser, lvalue);
if (nxt_slow_path(ret != NXT_OK)) {
return ret;
}
}
}
- dest_index = njs_generator_node_temp_index_get(parser, node);
+ dest_index = njs_generator_node_temp_index_get(vm, parser, node);
found:
- index = post ? njs_generator_temp_index_get(parser) : dest_index;
+ index = post ? njs_generator_temp_index_get(vm, parser, node) : dest_index;
+
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
njs_generate_code(parser, njs_vmcode_prop_get_t, prop_get);
prop_get->code.operation = njs_vmcode_property_get;
njs_generate_function_declaration(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- nxt_int_t ret;
- njs_value_t *value;
-
- value = njs_variable_value(parser, node->index);
-
- ret = njs_generate_function_scope(vm, value->data.u.function->u.lambda,
- node);
+ njs_function_lambda_t *lambda;
- if (nxt_fast_path(ret == NXT_OK)) {
- node->u.value = *value;
- }
+ lambda = node->u.value.data.u.function->u.lambda;
- return ret;
+ return njs_generate_function_scope(vm, lambda, node);
}
nxt_int_t
njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
{
- u_char *p;
- size_t code_size, size;
- uintptr_t scope_size;
- nxt_uint_t n;
- njs_value_t *value;
- njs_vm_code_t *code;
+ u_char *p;
+ size_t code_size, size;
+ uintptr_t scope_size;
+ nxt_uint_t n;
+ njs_value_t *value;
+ njs_vm_code_t *code;
+ njs_parser_scope_t *scope;
p = nxt_mem_cache_alloc(vm->mem_cache_pool, parser->code_size);
if (nxt_slow_path(p == NULL)) {
return NXT_ERROR;
}
+ scope = node->scope;
+
code_size = parser->code_end - parser->code_start;
nxt_thread_log_debug("SCOPE CODE SIZE: %uz %uz",
return NXT_ERROR;
}
- scope_size = parser->index[parser->scope - NJS_INDEX_CACHE]
- - parser->scope_offset;
+ scope_size = njs_offset(scope->next_index);
+
+ if (scope->type == NJS_SCOPE_GLOBAL) {
+ scope_size -= NJS_INDEX_GLOBAL_OFFSET;
+ }
parser->local_scope = nxt_mem_cache_alloc(vm->mem_cache_pool, scope_size);
if (nxt_slow_path(parser->local_scope == NULL)) {
parser->scope_size = scope_size;
- size = parser->scope_values->items * sizeof(njs_value_t);
+ size = scope->values->items * sizeof(njs_value_t);
nxt_thread_log_debug("SCOPE SIZE: %uz %uz", size, scope_size);
- p = memcpy(parser->local_scope, parser->scope_values->start, size);
+ p = memcpy(parser->local_scope, scope->values->start, size);
value = (njs_value_t *) (p + size);
for (n = scope_size - size; n != 0; n -= sizeof(njs_value_t)) {
njs_generate_function_call(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- nxt_int_t ret;
+ njs_ret_t ret;
njs_parser_node_t *name;
njs_vmcode_function_frame_t *func;
name = node->left;
} else {
- /* njs_generate_variable() always returns NXT_OK. */
- (void) njs_generate_variable(parser, node);
+ ret = njs_generate_variable(vm, parser, node);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
name = node;
}
njs_parser_node_t *node)
{
nxt_int_t ret;
- njs_index_t index;
+ njs_index_t index, catch_index;
njs_vmcode_catch_t *catch;
njs_vmcode_finally_t *finally;
njs_vmcode_try_end_t *try_end, *catch_end;
try_start->code.operands = NJS_VMCODE_2OPERANDS;
try_start->code.retval = NJS_VMCODE_NO_RETVAL;
- index = njs_generator_temp_index_get(parser);
+ index = njs_generator_temp_index_get(vm, parser, node);
+ if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
+ }
+
try_start->value = index;
ret = njs_generator(vm, parser, node->left);
if (node->token == NJS_TOKEN_CATCH) {
/* A "try/catch" case. */
- ret = njs_generator(vm, parser, node->left);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
+ catch_index = njs_variable_index(vm, node->left, NJS_NAME_DECLARATION);
+ if (nxt_slow_path(catch_index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
}
njs_generate_code(parser, njs_vmcode_catch_t, catch);
catch->code.operands = NJS_VMCODE_2OPERANDS;
catch->code.retval = NJS_VMCODE_NO_RETVAL;
catch->offset = sizeof(njs_vmcode_catch_t);
- catch->exception = node->left->index;
+ catch->exception = catch_index;
ret = njs_generator(vm, parser, node->right);
if (nxt_slow_path(ret != NXT_OK)) {
if (node->left != NULL) {
/* A try/catch/finally case. */
- ret = njs_generator(vm, parser, node->left->left);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
+ catch_index = njs_variable_index(vm, node->left->left,
+ NJS_NAME_DECLARATION);
+ if (nxt_slow_path(catch_index == NJS_INDEX_ERROR)) {
+ return NXT_ERROR;
}
njs_generate_code(parser, njs_vmcode_catch_t, catch);
catch->code.operation = njs_vmcode_catch;
catch->code.operands = NJS_VMCODE_2OPERANDS;
catch->code.retval = NJS_VMCODE_NO_RETVAL;
- catch->exception = node->left->left->index;
+ catch->exception = catch_index;
ret = njs_generator(vm, parser, node->left->right);
if (nxt_slow_path(ret != NXT_OK)) {
return dest->index;
}
- return njs_generator_node_temp_index_get(parser, node);
+ return njs_generator_node_temp_index_get(vm, parser, node);
}
static nxt_noinline njs_index_t
-njs_generator_object_dest_index(njs_parser_t *parser, njs_parser_node_t *node)
+njs_generator_object_dest_index(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node)
{
njs_index_t index;
njs_parser_node_t *dest;
}
}
- return njs_generator_node_temp_index_get(parser, node);
+ return njs_generator_node_temp_index_get(vm, parser, node);
}
static njs_index_t
-njs_generator_node_temp_index_get(njs_parser_t *parser, njs_parser_node_t *node)
+njs_generator_node_temp_index_get(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node)
{
node->temporary = 1;
- node->index = njs_generator_temp_index_get(parser);
+ node->index = njs_generator_temp_index_get(vm, parser, node);
return node->index;
}
static nxt_noinline njs_index_t
-njs_generator_temp_index_get(njs_parser_t *parser)
+njs_generator_temp_index_get(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node)
{
- nxt_uint_t n;
- njs_index_t index, *last;
- nxt_array_t *cache;
+ nxt_array_t *cache;
+ njs_value_t *value;
+ njs_index_t index, *last;
+ njs_parser_scope_t *scope;
cache = parser->index_cache;
return *last;
}
- /* Skip absolute and propery scopes. */
- n = parser->scope - NJS_INDEX_CACHE;
+ scope = node->scope;
+
+ while (scope->type == NJS_SCOPE_BLOCK) {
+ scope = scope->parent;
+ }
- index = parser->index[n];
- parser->index[n] += sizeof(njs_value_t);
+ value = nxt_array_add(scope->values, &njs_array_mem_proto,
+ vm->mem_cache_pool);
+ if (nxt_slow_path(value == NULL)) {
+ return NJS_INDEX_ERROR;
+ }
- index |= parser->scope;
+ *value = njs_value_invalid;
- nxt_thread_log_debug("GET %p", index);
+ index = scope->next_index;
+ scope->next_index += sizeof(njs_value_t);
return index;
}
return NXT_ERROR;
}
-
-
-nxt_inline nxt_bool_t
-njs_generator_is_constant(njs_parser_node_t *node)
-{
- return (node->token >= NJS_TOKEN_FIRST_CONST
- && node->token <= NJS_TOKEN_LAST_CONST);
-}
* is treated as a single expiression.
*/
+static njs_ret_t njs_parser_scope_begin(njs_vm_t *vm, njs_parser_t *parser,
+ njs_scope_t type);
+static void njs_parser_scope_end(njs_vm_t *vm, njs_parser_t *parser);
static njs_token_t njs_parser_statement_chain(njs_vm_t *vm,
njs_parser_t *parser, njs_token_t token);
static njs_token_t njs_parser_statement(njs_vm_t *vm, njs_parser_t *parser,
njs_token_t token);
-static njs_token_t njs_parser_block(njs_vm_t *vm, njs_parser_t *parser);
+static njs_token_t njs_parser_block_statement(njs_vm_t *vm,
+ njs_parser_t *parser);
static njs_token_t njs_parser_function_declaration(njs_vm_t *vm,
njs_parser_t *parser);
static njs_parser_t *njs_parser_function_create(njs_vm_t *vm,
njs_parser_node_t *
njs_parser(njs_vm_t *vm, njs_parser_t *parser)
{
+ njs_ret_t ret;
njs_token_t token;
njs_parser_node_t *node;
+ ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_GLOBAL);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NULL;
+ }
+
token = njs_parser_token(parser);
while (token != NJS_TOKEN_END) {
if (node != NULL && node->right != NULL) {
if (node->right->token == NJS_TOKEN_FUNCTION) {
node->token = NJS_TOKEN_CALL;
+ node->scope = parser->scope;
return node;
}
}
node->token = NJS_TOKEN_END;
+ node->scope = parser->scope;
return node;
}
+static njs_ret_t
+njs_parser_scope_begin(njs_vm_t *vm, njs_parser_t *parser, njs_scope_t type)
+{
+ nxt_array_t *values;
+ njs_parser_scope_t *scope, *parent;
+
+ scope = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_scope_t));
+ if (nxt_slow_path(scope == NULL)) {
+ return NXT_ERROR;
+ }
+
+ scope->type = type;
+
+ if (type == NJS_SCOPE_GLOBAL) {
+ type += NJS_INDEX_GLOBAL_OFFSET;
+ }
+
+ scope->next_index = type;
+
+ scope->inclusive = 0;
+ nxt_lvlhsh_init(&scope->variables);
+
+ values = NULL;
+
+ if (scope->type < NJS_SCOPE_BLOCK) {
+ values = nxt_array_create(4, sizeof(njs_value_t), &njs_array_mem_proto,
+ vm->mem_cache_pool);
+ if (nxt_slow_path(values == NULL)) {
+ return NXT_ERROR;
+ }
+ }
+
+ scope->values = values;
+
+ parent = parser->scope;
+
+ if (parent != NULL) {
+ parent->inclusive++;
+ }
+
+ scope->parent = parent;
+ parser->scope = scope;
+
+ return NXT_OK;
+}
+
+
+static void
+njs_parser_scope_end(njs_vm_t *vm, njs_parser_t *parser)
+{
+ njs_parser_scope_t *scope, *parent;
+
+ scope = parser->scope;
+
+ parent = scope->parent;
+
+#if 0
+ if (scope->inclusive == 0
+ && scope->type == NJS_SCOPE_BLOCK
+ && nxt_lvlhsh_is_empty(&scope->variables))
+ {
+ parent->inclusive--;
+
+ nxt_mem_cache_free(vm->mem_cache_pool, scope);
+ }
+#endif
+
+ parser->scope = parent;
+}
+
+
static njs_token_t
njs_parser_statement_chain(njs_vm_t *vm, njs_parser_t *parser,
njs_token_t token)
return njs_parser_token(parser);
case NJS_TOKEN_OPEN_BRACE:
- return njs_parser_block(vm, parser);
+ return njs_parser_block_statement(vm, parser);
case NJS_TOKEN_CLOSE_BRACE:
parser->node = NULL;
static njs_token_t
-njs_parser_block(njs_vm_t *vm, njs_parser_t *parser)
+njs_parser_block_statement(njs_vm_t *vm, njs_parser_t *parser)
{
+ njs_ret_t ret;
njs_token_t token;
token = njs_parser_token(parser);
parser->node = NULL;
+ ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_BLOCK);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NJS_TOKEN_ERROR;
+ }
+
while (token != NJS_TOKEN_CLOSE_BRACE) {
token = njs_parser_statement_chain(vm, parser, token);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
}
}
+ njs_parser_scope_end(vm, parser);
+
return njs_parser_token(parser);
}
njs_parser_function_declaration(njs_vm_t *vm, njs_parser_t *parser)
{
njs_token_t token;
- njs_value_t *value;
njs_variable_t *var;
njs_function_t *function;
njs_parser_node_t *node;
return NJS_TOKEN_ILLEGAL;
}
- var = njs_parser_name_alloc(vm, parser);
+ var = njs_variable_add(vm, parser, NJS_VARIABLE_FUNCTION);
if (nxt_slow_path(var == NULL)) {
return NJS_TOKEN_ERROR;
}
- var->state = NJS_VARIABLE_DECLARED;
- var->function = 1;
- node->index = var->index;
-
token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
return NJS_TOKEN_ERROR;
}
- value = njs_variable_value(parser, node->index);
- value->data.u.function = function;
- value->type = NJS_FUNCTION;
- value->data.truth = 1;
+ var->value.data.u.function = function;
+ var->value.type = NJS_FUNCTION;
+ var->value.data.truth = 1;
+
+ node->u.value = var->value;
parser = njs_parser_function_create(vm, parser);
if (nxt_slow_path(parser == NULL)) {
function->u.lambda->u.parser = parser;
- return njs_parser_function_lambda(vm, function->u.lambda, token);
+ token = njs_parser_function_lambda(vm, function->u.lambda, token);
+
+ vm->parser = parser->parent;
+
+ return token;
}
static njs_token_t
njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser)
{
- nxt_uint_t level;
+ njs_ret_t ret;
njs_token_t token;
- njs_index_t index;
- njs_value_t *value;
njs_variable_t *var;
njs_function_t *function;
njs_parser_node_t *node;
}
node->token = NJS_TOKEN_FUNCTION_EXPRESSION;
+ node->scope = parser->scope;
parser->node = node;
parser->code_size += sizeof(njs_vmcode_function_t);
return token;
}
+ /*
+ * An optional function expression name is stored
+ * in intermediate shim scope.
+ */
+ ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_SHIM);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NJS_TOKEN_ERROR;
+ }
+
if (token == NJS_TOKEN_NAME) {
- var = njs_parser_variable(vm, parser, &level);
+ var = njs_variable_add(vm, parser, NJS_VARIABLE_SHIM);
if (nxt_slow_path(var == NULL)) {
return NJS_TOKEN_ERROR;
}
- var->state = NJS_VARIABLE_DECLARED;
-
token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
- index = var->index;
- value = njs_variable_value(parser, index);
-
function = njs_function_alloc(vm);
if (nxt_slow_path(function == NULL)) {
return NJS_TOKEN_ERROR;
}
- value->data.u.function = function;
- value->type = NJS_FUNCTION;
- value->data.truth = 1;
+ var->value.data.u.function = function;
+ var->value.type = NJS_FUNCTION;
+ var->value.data.truth = 1;
+
lambda = function->u.lambda;
} else {
node->u.value.data.u.lambda = lambda;
lambda->u.parser = parser;
- return njs_parser_function_lambda(vm, lambda, token);
+ token = njs_parser_function_lambda(vm, lambda, token);
+
+ njs_parser_scope_end(vm, parser);
+
+ vm->parser = parser->parent;
+
+ return token;
}
static njs_parser_t *
njs_parser_function_create(njs_vm_t *vm, njs_parser_t *parent)
{
- nxt_array_t *values, *arguments;
njs_parser_t *parser;
parser = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_parser_t));
}
parser->parent = parent;
+ parser->scope = parent->scope;
parser->lexer = parent->lexer;
vm->parser = parser;
- arguments = nxt_array_create(4, sizeof(njs_variable_t),
- &njs_array_mem_proto, vm->mem_cache_pool);
- if (nxt_slow_path(arguments == NULL)) {
- return NULL;
- }
-
- parser->arguments = arguments;
-
- values = nxt_array_create(4, sizeof(njs_value_t), &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(values == NULL)) {
- return NULL;
- }
-
- parser->scope_values = values;
- parser->scope = NJS_SCOPE_LOCAL;
-
return parser;
}
njs_parser_function_lambda(njs_vm_t *vm, njs_function_lambda_t *lambda,
njs_token_t token)
{
- nxt_str_t *name;
+ njs_ret_t ret;
njs_index_t index;
njs_parser_t *parser;
njs_variable_t *arg;
parser = lambda->u.parser;
+ ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_FUNCTION);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NJS_TOKEN_ERROR;
+ }
+
token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
return NJS_TOKEN_ERROR;
}
- arg = nxt_array_add(parser->arguments, &njs_array_mem_proto,
- vm->mem_cache_pool);
+ arg = njs_variable_add(vm, parser, NJS_VARIABLE_VAR);
if (nxt_slow_path(arg == NULL)) {
return NJS_TOKEN_ERROR;
}
- name = &parser->lexer->text;
+ arg->index = index;
+ index += sizeof(njs_value_t);
- arg->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->length);
- if (nxt_slow_path(arg->name_start == NULL)) {
+ ret = njs_name_copy(vm, &arg->name, &parser->lexer->text);
+ if (nxt_slow_path(ret != NXT_OK)) {
return NJS_TOKEN_ERROR;
}
- memcpy(arg->name_start, name->start, name->length);
- arg->name_len = name->length;
-
- arg->state = NJS_VARIABLE_DECLARED;
- arg->index = index;
- index += sizeof(njs_value_t);
-
token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
return NJS_TOKEN_ERROR;
}
- token = njs_parser_block(vm, parser);
+ token = njs_parser_token(parser);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
+
+ parser->node = NULL;
+
+ while (token != NJS_TOKEN_CLOSE_BRACE) {
+ token = njs_parser_statement_chain(vm, parser, token);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
+ }
+
+ token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
}
parser->parent->node->right = parser->node;
- vm->parser = parser->parent;
+ parser->node->scope = parser->scope;
+
+ njs_parser_scope_end(vm, parser);
return token;
}
njs_token_t token;
njs_parser_node_t *node;
- if (parser->scope == NJS_SCOPE_GLOBAL) {
+ if (parser->scope->type == NJS_SCOPE_GLOBAL) {
nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
"SyntaxError: Illegal return statement");
static njs_token_t
njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser)
{
- nxt_bool_t first;
- nxt_uint_t level;
+ njs_ret_t ret;
njs_token_t token;
njs_variable_t *var;
- njs_parser_node_t *left, *stmt, *name, *assign;
+ njs_parser_node_t *left, *stmt, *name, *assign, *expr;
parser->node = NULL;
left = NULL;
return NJS_TOKEN_ILLEGAL;
}
- var = njs_parser_variable(vm, parser, &level);
+ var = njs_variable_add(vm, parser, NJS_VARIABLE_VAR);
if (nxt_slow_path(var == NULL)) {
return NJS_TOKEN_ERROR;
}
- first = (var->state == NJS_VARIABLE_CREATED);
+ name = njs_parser_node_alloc(vm);
+ if (nxt_slow_path(name == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
+
+ name->token = NJS_TOKEN_NAME;
- var->state = NJS_VARIABLE_DECLARED;
+ ret = njs_variable_reference(vm, parser, name);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NJS_TOKEN_ERROR;
+ }
token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
+ expr = NULL;
+
if (token == NJS_TOKEN_ASSIGNMENT) {
token = njs_parser_token(parser);
return token;
}
- name = njs_parser_node_alloc(vm);
- if (nxt_slow_path(name == NULL)) {
- return NJS_TOKEN_ERROR;
- }
-
- name->token = NJS_TOKEN_NAME;
- name->u.variable = var;
-
- if (first) {
- name->state = NJS_VARIABLE_FIRST_ASSIGNMENT;
- }
+ expr = parser->node;
+ }
- assign = njs_parser_node_alloc(vm);
- if (nxt_slow_path(assign == NULL)) {
- return NJS_TOKEN_ERROR;
- }
+ assign = njs_parser_node_alloc(vm);
+ if (nxt_slow_path(assign == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
- assign->token = NJS_TOKEN_ASSIGNMENT;
- assign->u.operation = njs_vmcode_move;
- assign->left = name;
- assign->right = parser->node;
+ assign->token = NJS_TOKEN_VAR;
+ assign->u.operation = njs_vmcode_move;
+ assign->left = name;
+ assign->right = expr;
- stmt = njs_parser_node_alloc(vm);
- if (nxt_slow_path(stmt == NULL)) {
- return NJS_TOKEN_ERROR;
- }
+ stmt = njs_parser_node_alloc(vm);
+ if (nxt_slow_path(stmt == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
- stmt->token = NJS_TOKEN_STATEMENT;
- stmt->left = left;
- stmt->right = assign;
- parser->node = stmt;
- parser->code_size += sizeof(njs_vmcode_2addr_t);
+ stmt->token = NJS_TOKEN_STATEMENT;
+ stmt->left = left;
+ stmt->right = assign;
+ parser->node = stmt;
+ parser->code_size += sizeof(njs_vmcode_2addr_t);
- left = stmt;
- }
+ left = stmt;
} while (token == NJS_TOKEN_COMMA);
}
swtch->token = NJS_TOKEN_SWITCH;
+ swtch->scope = parser->scope;
swtch->left = parser->node;
last = &swtch->right;
return NJS_TOKEN_ILLEGAL;
}
- node->u.variable->state = NJS_VARIABLE_DECLARED;
-
node = njs_parser_node_alloc(vm);
if (nxt_slow_path(node == NULL)) {
return NJS_TOKEN_ERROR;
static njs_token_t
njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser)
{
- nxt_uint_t level;
+ njs_ret_t ret;
njs_token_t token;
njs_variable_t *var;
njs_parser_node_t *node, *try, *catch;
}
try->token = NJS_TOKEN_TRY;
+ try->scope = parser->scope;
try->left = parser->node;
parser->code_size += sizeof(njs_vmcode_try_start_t)
+ sizeof(njs_vmcode_try_end_t);
catch->token = NJS_TOKEN_CATCH;
try->right = catch;
- var = njs_parser_variable(vm, parser, &level);
- if (nxt_slow_path(var == NULL)) {
+ /*
+ * The "catch" clause creates a block scope for single variable
+ * which receives exception value.
+ */
+ ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_BLOCK);
+ if (nxt_slow_path(ret != NXT_OK)) {
return NJS_TOKEN_ERROR;
}
- var->state = NJS_VARIABLE_DECLARED;
+ var = njs_variable_add(vm, parser, NJS_VARIABLE_LET);
+ if (nxt_slow_path(var == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
node = njs_parser_node_alloc(vm);
if (nxt_slow_path(node == NULL)) {
}
node->token = NJS_TOKEN_NAME;
- node->u.variable = var;
+
+ ret = njs_variable_reference(vm, parser, node);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NJS_TOKEN_ERROR;
+ }
catch->left = node;
catch->right = parser->node;
- /* TODO: remove variable from scope. */
+ njs_parser_scope_end(vm, parser);
}
if (token == NJS_TOKEN_FINALLY) {
njs_token_t token;
token = njs_parser_token(parser);
-
- if (nxt_fast_path(token == NJS_TOKEN_OPEN_BRACE)) {
- parser->node = NULL;
- return njs_parser_block(vm, parser);
+ if (nxt_slow_path(token != NJS_TOKEN_OPEN_BRACE)) {
+ return NJS_TOKEN_ILLEGAL;
}
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_block_statement(vm, parser);
}
njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
{
double num;
- nxt_int_t ret;
- nxt_uint_t level;
+ njs_ret_t ret;
njs_extern_t *ext;
- njs_variable_t *var;
njs_parser_node_t *node;
if (token == NJS_TOKEN_OPEN_PARENTHESIS) {
break;
}
- var = njs_parser_variable(vm, parser, &level);
- if (nxt_slow_path(var == NULL)) {
+ ret = njs_variable_reference(vm, parser, node);
+ if (nxt_slow_path(ret != NXT_OK)) {
return NJS_TOKEN_ERROR;
}
- switch (var->state) {
-
- case NJS_VARIABLE_CREATED:
- var->state = NJS_VARIABLE_PENDING;
- parser->code_size += sizeof(njs_vmcode_1addr_t);
- break;
-
- case NJS_VARIABLE_PENDING:
- var->state = NJS_VARIABLE_USED;
- parser->code_size += sizeof(njs_vmcode_1addr_t);
- break;
-
- case NJS_VARIABLE_USED:
- parser->code_size += sizeof(njs_vmcode_1addr_t);
- break;
-
- case NJS_VARIABLE_SET:
- case NJS_VARIABLE_DECLARED:
- break;
- }
-
parser->code_size += sizeof(njs_vmcode_object_copy_t);
- node->u.variable = var;
break;
case NJS_TOKEN_OPEN_BRACE:
node->token = NJS_TOKEN_OBJECT;
+ node->scope = parser->scope;
nxt_thread_log_debug("JS: OBJECT");
case NJS_TOKEN_OPEN_BRACKET:
node->token = NJS_TOKEN_ARRAY;
+ node->scope = parser->scope;
nxt_thread_log_debug("JS: ARRAY");
nxt_thread_log_debug("REGEX: '%V'", &parser->lexer->text);
node->token = NJS_TOKEN_REGEXP;
+ node->scope = parser->scope;
parser->code_size += sizeof(njs_vmcode_regexp_t);
break;
case NJS_TOKEN_THIS:
nxt_thread_log_debug("JS: this");
- if (parser->scope != NJS_SCOPE_GLOBAL) {
+ if (parser->scope->type != NJS_SCOPE_GLOBAL) {
node->index = NJS_INDEX_THIS;
break;
}
njs_parser_builtin_object(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- nxt_uint_t index, level;
- njs_value_t *value;
+ njs_ret_t ret;
+ nxt_uint_t index;
njs_variable_t *var;
- var = njs_parser_variable(vm, parser, &level);
+ var = njs_builtin_add(vm, parser);
if (nxt_slow_path(var == NULL)) {
return NJS_TOKEN_ERROR;
}
- var->state = NJS_VARIABLE_DECLARED;
- node->index = var->index;
+ /* TODO: once */
+ index = node->token - NJS_TOKEN_FIRST_OBJECT;
+ var->value.data.u.object = &vm->shared->objects[index];
+ var->value.type = NJS_OBJECT;
+ var->value.data.truth = 1;
- value = njs_variable_value(parser, node->index);
+ ret = njs_variable_reference(vm, parser, node);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NJS_TOKEN_ERROR;
+ }
- index = node->token - NJS_TOKEN_FIRST_OBJECT;
- value->data.u.object = &vm->shared->objects[index];
- value->type = NJS_OBJECT;
- value->data.truth = 1;
+ node->scope = parser->scope;
parser->node = node;
parser->code_size += sizeof(njs_vmcode_object_copy_t);
njs_parser_builtin_function(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
- nxt_uint_t index, level;
- njs_value_t *value;
+ njs_ret_t ret;
+ nxt_uint_t index;
njs_variable_t *var;
- var = njs_parser_variable(vm, parser, &level);
+ var = njs_builtin_add(vm, parser);
if (nxt_slow_path(var == NULL)) {
return NJS_TOKEN_ERROR;
}
- var->state = NJS_VARIABLE_DECLARED;
- node->index = var->index;
+ /* TODO: once */
+ index = node->token - NJS_TOKEN_FIRST_FUNCTION;
+ var->value.data.u.function = &vm->shared->functions[index];
+ var->value.type = NJS_FUNCTION;
+ var->value.data.truth = 1;
- value = njs_variable_value(parser, node->index);
+ ret = njs_variable_reference(vm, parser, node);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NJS_TOKEN_ERROR;
+ }
- index = node->token - NJS_TOKEN_FIRST_FUNCTION;
- value->data.u.function = &vm->shared->functions[index];
- value->type = NJS_FUNCTION;
- value->data.truth = 1;
+ node->scope = parser->scope;
parser->node = node;
parser->code_size += sizeof(njs_vmcode_object_copy_t);
} njs_lexer_t;
-typedef enum {
- NJS_VARIABLE_NORMAL = 0,
- NJS_VARIABLE_FIRST_ASSIGNMENT,
- NJS_VARIABLE_ASSIGNMENT,
- NJS_VARIABLE_TYPEOF,
-} njs_variable_node_state_t;
-
-
#define njs_parser_is_lvalue(node) \
((node)->token == NJS_TOKEN_NAME || (node)->token == NJS_TOKEN_PROPERTY)
+typedef struct njs_parser_scope_s njs_parser_scope_t;
+
+struct njs_parser_scope_s {
+ nxt_array_t *values; /* Array of njs_value_t. */
+
+ nxt_lvlhsh_t variables;
+ njs_parser_scope_t *parent;
+ njs_index_t next_index;
+ uint32_t inclusive;
+ njs_scope_t type:8;
+};
+
+
typedef struct njs_parser_node_s njs_parser_node_t;
struct njs_parser_node_s {
njs_token_t token:16;
- njs_variable_node_state_t state:2; /* 2 bits */
uint8_t ctor:1; /* 1 bit */
uint8_t temporary; /* 1 bit */
uint32_t token_line;
+ uint32_t variable_name_hash;
union {
uint32_t length;
- njs_vmcode_operation_t operation;
+ nxt_str_t variable_name;
njs_value_t value;
- njs_variable_t *variable;
+ njs_vmcode_operation_t operation;
njs_parser_node_t *object;
njs_extern_t *external;
} u;
njs_index_t index;
+ /*
+ * The scope points to
+ * in global and function node: global or function scopes;
+ * in variable node: a scope where variable was referenced;
+ * in operation node: a scope to allocate indexes for temporary values.
+ */
+ njs_parser_scope_t *scope;
+
njs_parser_node_t *left;
njs_parser_node_t *right;
njs_parser_node_t *dest;
NJS_PARSER_SWITCH,
} njs_parser_block_type_t;
+
typedef struct njs_parser_block_s njs_parser_block_t;
struct njs_parser_block_s {
njs_lexer_t *lexer;
njs_parser_node_t *node;
- /* Vector of njs_variable_t. */
- nxt_array_t *arguments;
njs_parser_block_t *block;
- nxt_lvlhsh_t variables_hash;
+ njs_parser_scope_t *scope;
nxt_array_t *index_cache;
njs_index_t index[NJS_SCOPES - NJS_INDEX_CACHE];
- nxt_array_t *scope_values;
-
- uint8_t scope; /* 4 bits */
uint8_t branch; /* 1 bit */
/* Parsing Function() or eval(). */
njs_token_t njs_parser_token(njs_parser_t *parser);
nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value);
njs_index_t njs_parser_index(njs_parser_t *parser, uint32_t scope);
+njs_ret_t njs_variable_reference(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node);
+njs_variable_t *njs_variable_get(njs_vm_t *vm, njs_parser_node_t *node,
+ njs_name_reference_t reference);
+njs_index_t njs_variable_index(njs_vm_t *vm, njs_parser_node_t *node,
+ njs_name_reference_t reference);
nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node);
u_char *njs_parser_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
u_char *start);
njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
{
size_t size;
- njs_parser_node_t *node, *pending;
+ njs_parser_node_t *node;
njs_vmcode_operation_t operation;
token = njs_parser_conditional_expression(vm, parser, token);
node = parser->node;
- if (parser->node->token != NJS_TOKEN_NAME) {
+ if (!njs_parser_is_lvalue(parser->node)) {
nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
"ReferenceError: Invalid left-hand side in assignment");
return NJS_TOKEN_ILLEGAL;
}
- pending = NULL;
-
- if (node->token == NJS_TOKEN_NAME) {
- node->state = NJS_VARIABLE_ASSIGNMENT;
-
- if (node->u.variable->state == NJS_VARIABLE_PENDING) {
- pending = node;
- }
- }
-
node = njs_parser_node_alloc(vm);
if (nxt_slow_path(node == NULL)) {
return NJS_TOKEN_ERROR;
node->token = token;
node->u.operation = operation;
+ node->scope = parser->scope;
node->left = parser->node;
parser->code_size += size;
node->right = parser->node;
parser->node = node;
-
- if (pending != NULL
- && pending->u.variable->state == NJS_VARIABLE_PENDING)
- {
- pending->u.variable->state = NJS_VARIABLE_SET;
- parser->code_size -= sizeof(njs_vmcode_1addr_t);
-
- if (!parser->branch) {
- pending->state = NJS_VARIABLE_FIRST_ASSIGNMENT;
- }
- }
}
}
njs_token_t token)
{
size_t size;
- njs_parser_node_t *node, *pending;
+ njs_parser_node_t *node;
njs_vmcode_operation_t operation;
token = njs_parser_conditional_expression(vm, parser, token);
return NJS_TOKEN_ILLEGAL;
}
- pending = NULL;
-
- if (node->token == NJS_TOKEN_NAME) {
-
- if (token == NJS_TOKEN_ASSIGNMENT) {
- node->state = NJS_VARIABLE_ASSIGNMENT;
-
- if (node->u.variable->state == NJS_VARIABLE_PENDING) {
- pending = node;
- }
-
- } else if (node->u.variable->state == NJS_VARIABLE_PENDING) {
- node->u.variable->state = NJS_VARIABLE_USED;
- }
- }
-
node = njs_parser_node_alloc(vm);
if (nxt_slow_path(node == NULL)) {
return NJS_TOKEN_ERROR;
node->token = token;
node->u.operation = operation;
+ node->scope = parser->scope;
node->left = parser->node;
token = njs_parser_token(parser);
}
parser->code_size += size;
-
- if (pending != NULL
- && pending->u.variable->state == NJS_VARIABLE_PENDING)
- {
- pending->u.variable->state = NJS_VARIABLE_SET;
-
- if (!parser->branch) {
- pending->state = NJS_VARIABLE_FIRST_ASSIGNMENT;
- }
- }
}
}
}
cond->token = NJS_TOKEN_CONDITIONAL;
+ cond->scope = parser->scope;
cond->left = parser->node;
node = njs_parser_node_alloc(vm);
node->token = token;
node->u.operation = op->operation;
+ node->scope = parser->scope;
node->left = parser->node;
node->left->dest = node;
node->token = token;
node->u.operation = njs_vmcode_exponentiation;
+ node->scope = parser->scope;
node->left = parser->node;
node->left->dest = node;
}
}
- if (token == NJS_TOKEN_TYPEOF && parser->node->token == NJS_TOKEN_NAME) {
- parser->node->state = NJS_VARIABLE_TYPEOF;
- }
-
node = njs_parser_node_alloc(vm);
if (nxt_slow_path(node == NULL)) {
return NJS_TOKEN_ERROR;
node->token = token;
node->u.operation = operation;
+ node->scope = parser->scope;
node->left = parser->node;
node->left->dest = node;
parser->node = node;
node->token = token;
node->u.operation = operation;
+ node->scope = parser->scope;
node->left = parser->node;
parser->node = node;
node->token = token;
node->u.operation = operation;
+ node->scope = parser->scope;
node->left = parser->node;
parser->node = node;
case NJS_TOKEN_NAME:
func = node;
func->token = NJS_TOKEN_FUNCTION_CALL;
+ func->scope = parser->scope;
parser->code_size += sizeof(njs_vmcode_function_frame_t)
+ sizeof(njs_vmcode_function_call_t);
break;
}
func->token = NJS_TOKEN_METHOD_CALL;
+ func->scope = parser->scope;
func->left = node;
parser->code_size += sizeof(njs_vmcode_method_frame_t)
+ sizeof(njs_vmcode_function_call_t);
}
func->token = NJS_TOKEN_FUNCTION_CALL;
+ func->scope = parser->scope;
func->left = node;
parser->code_size += sizeof(njs_vmcode_function_frame_t)
+ sizeof(njs_vmcode_function_call_t);
}
func->token = NJS_TOKEN_METHOD_CALL;
+ func->scope = parser->scope;
func->left = node;
parser->code_size += sizeof(njs_vmcode_method_frame_t)
+ sizeof(njs_vmcode_function_call_t);
}
func->token = NJS_TOKEN_FUNCTION_CALL;
+ func->scope = parser->scope;
func->left = node;
parser->code_size += sizeof(njs_vmcode_function_frame_t)
+ sizeof(njs_vmcode_function_call_t);
node->token = NJS_TOKEN_PROPERTY;
node->u.operation = njs_vmcode_property_get;
+ node->scope = parser->scope;
node->left = parser->node;
if (token == NJS_TOKEN_DOT) {
#include <string.h>
-static njs_variable_t *njs_variable_alloc(njs_vm_t *vm,
- njs_parser_t *parser, nxt_str_t *name);
+static njs_variable_t *njs_variable_alloc(njs_vm_t *vm, nxt_str_t *name,
+ njs_variable_type_t type);
static nxt_int_t
var = data;
- if (lhq->key.length == var->name_len
- && memcmp(var->name_start, lhq->key.start, lhq->key.length) == 0)
- {
+ if (nxt_strstr_eq(&lhq->key, &var->name)) {
return NXT_OK;
}
njs_variable_t *
-njs_parser_name_alloc(njs_vm_t *vm, njs_parser_t *parser)
+njs_builtin_add(njs_vm_t *vm, njs_parser_t *parser)
{
nxt_int_t ret;
njs_variable_t *var;
+ njs_parser_scope_t *scope;
nxt_lvlhsh_query_t lhq;
- var = njs_variable_alloc(vm, parser, &parser->lexer->text);
+ lhq.key_hash = parser->lexer->key_hash;
+ lhq.key = parser->lexer->text;
+ lhq.proto = &njs_variables_hash_proto;
+
+ scope = parser->scope;
+
+ while (scope->type != NJS_SCOPE_GLOBAL) {
+ scope = scope->parent;
+ }
+
+ if (nxt_lvlhsh_find(&scope->variables, &lhq) == NXT_OK) {
+ var = lhq.value;
+
+ return var;
+ }
+
+ var = njs_variable_alloc(vm, &lhq.key, NJS_VARIABLE_VAR);
if (nxt_slow_path(var == NULL)) {
- return NULL;
+ return var;
}
- lhq.key_hash = parser->lexer->key_hash;
- lhq.key = parser->lexer->text;
lhq.replace = 0;
lhq.value = var;
- lhq.proto = &njs_variables_hash_proto;
lhq.pool = vm->mem_cache_pool;
- ret = nxt_lvlhsh_insert(&parser->variables_hash, &lhq);
+ ret = nxt_lvlhsh_insert(&scope->variables, &lhq);
if (nxt_fast_path(ret == NXT_OK)) {
return var;
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Duplicate declaration \"%.*s\"",
- (int) parser->lexer->text.length, parser->lexer->text.start);
+ nxt_mem_cache_free(vm->mem_cache_pool, var->name.start);
+ nxt_mem_cache_free(vm->mem_cache_pool, var);
return NULL;
}
njs_variable_t *
-njs_parser_variable(njs_vm_t *vm, njs_parser_t *parser, nxt_uint_t *level)
+njs_variable_add(njs_vm_t *vm, njs_parser_t *parser, njs_variable_type_t type)
{
nxt_int_t ret;
- nxt_uint_t n;
- njs_parser_t *scope;
njs_variable_t *var;
+ njs_parser_scope_t *scope;
nxt_lvlhsh_query_t lhq;
- *level = 0;
-
lhq.key_hash = parser->lexer->key_hash;
lhq.key = parser->lexer->text;
lhq.proto = &njs_variables_hash_proto;
- scope = parser;
+ scope = parser->scope;
- do {
- var = scope->arguments->start;
- n = scope->arguments->items;
+ if (type >= NJS_VARIABLE_VAR) {
+ /*
+ * A "var" and "function" declarations are
+ * stored in function or global scope.
+ */
+ while (scope->type == NJS_SCOPE_BLOCK) {
+ scope = scope->parent;
+ }
+ }
+
+ var = njs_variable_alloc(vm, &lhq.key, type);
+ if (nxt_slow_path(var == NULL)) {
+ return var;
+ }
+
+ lhq.replace = 0;
+ lhq.value = var;
+ lhq.pool = vm->mem_cache_pool;
+
+ ret = nxt_lvlhsh_insert(&scope->variables, &lhq);
+
+ if (nxt_fast_path(ret == NXT_OK)) {
+ return var;
+ }
+
+ nxt_mem_cache_free(vm->mem_cache_pool, var->name.start);
+ nxt_mem_cache_free(vm->mem_cache_pool, var);
+
+ if (ret == NXT_ERROR) {
+ return NULL;
+ }
+
+ /* ret == NXT_DECLINED. */
+
+ nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+ "SyntaxError: Identifier \"%.*s\" has already been declared",
+ (int) lhq.key.length, lhq.key.start);
- while (n != 0) {
- if (lhq.key.length == var->name_len
- && memcmp(var->name_start, lhq.key.start, lhq.key.length) == 0)
- {
- return var;
+ return NULL;
+}
+
+
+njs_ret_t
+njs_variable_reference(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_node_t *node)
+{
+ njs_ret_t ret;
+
+ ret = njs_name_copy(vm, &node->u.variable_name, &parser->lexer->text);
+
+ if (nxt_fast_path(ret == NXT_OK)) {
+ node->variable_name_hash = parser->lexer->key_hash;
+ node->scope = parser->scope;
+ }
+
+ return ret;
+}
+
+
+njs_variable_t *
+njs_variable_get(njs_vm_t *vm, njs_parser_node_t *node,
+ njs_name_reference_t reference)
+{
+ nxt_int_t ret;
+ nxt_array_t *values;
+ njs_index_t index;
+ njs_value_t *value;
+ njs_variable_t *var;
+ njs_parser_scope_t *scope, *parent, *inclusive;
+ nxt_lvlhsh_query_t lhq;
+ const njs_value_t *initial;
+
+ lhq.key_hash = node->variable_name_hash;
+ lhq.key = node->u.variable_name;
+ lhq.proto = &njs_variables_hash_proto;
+
+ inclusive = NULL;
+ scope = node->scope;
+
+ for ( ;; ) {
+ if (nxt_lvlhsh_find(&scope->variables, &lhq) == NXT_OK) {
+ var = lhq.value;
+
+ if (scope->type == NJS_SCOPE_SHIM) {
+ scope = inclusive;
+
+ } else {
+ /*
+ * Variables declared in a block with "let" or "const"
+ * keywords are actually stored in function or global scope.
+ */
+ while (scope->type == NJS_SCOPE_BLOCK) {
+ scope = scope->parent;
+ }
}
- var++;
- n--;
- }
+ initial = &njs_value_void;
- if (nxt_lvlhsh_find(&scope->variables_hash, &lhq) == NXT_OK) {
- return lhq.value;
+ goto found;
}
- scope = scope->parent;
- (*level)++;
+ parent = scope->parent;
- } while (scope != NULL);
+ if (parent == NULL) {
+ /* A global scope. */
+ break;
+ }
- *level = 0;
+ inclusive = scope;
+ scope = parent;
+ }
- if (nxt_lvlhsh_find(&vm->variables_hash, &lhq) == NXT_OK) {
- return lhq.value;
+ if (reference != NJS_NAME_TYPEOF) {
+ goto not_found;
}
- var = njs_variable_alloc(vm, parser, &parser->lexer->text);
+ /* Add variable referenced by typeof to the global scope. */
+
+ var = njs_variable_alloc(vm, &lhq.key, NJS_VARIABLE_TYPEOF);
if (nxt_slow_path(var == NULL)) {
return NULL;
}
lhq.value = var;
lhq.pool = vm->mem_cache_pool;
- ret = nxt_lvlhsh_insert(&parser->variables_hash, &lhq);
+ ret = nxt_lvlhsh_insert(&scope->variables, &lhq);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NULL;
+ }
+
+ initial = &njs_value_invalid;
+
+found:
+
+ if (reference == NJS_NAME_REFERENCE && var->type == NJS_VARIABLE_TYPEOF) {
+ goto not_found;
+ }
+
+ index = var->index;
+
+ if (index != NJS_INDEX_NONE) {
+ node->index = index;
+ return var;
+ }
+
+ if (reference == NJS_NAME_REFERENCE && var->type <= NJS_VARIABLE_LET) {
+ goto not_found;
+ }
+
+ values = scope->values;
+
+ if (values == NULL) {
+ values = nxt_array_create(4, sizeof(njs_value_t), &njs_array_mem_proto,
+ vm->mem_cache_pool);
+ if (nxt_slow_path(values == NULL)) {
+ return NULL;
+ }
+
+ scope->values = values;
+ }
+
+ value = nxt_array_add(values, &njs_array_mem_proto, vm->mem_cache_pool);
+ if (nxt_slow_path(value == NULL)) {
+ return NULL;
+ }
+
+ if (njs_is_object(&var->value)) {
+ *value = var->value;
+
+ } else {
+ *value = *initial;
+ }
+
+ index = scope->next_index;
+ scope->next_index += sizeof(njs_value_t);
+
+ var->index = index;
+ node->index = index;
+
+ return var;
+
+not_found:
+
+ nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+ "ReferenceError: \"%.*s\" is not defined",
+ (int) lhq.key.length, lhq.key.start);
+
+ return NULL;
+}
+
+
+njs_index_t
+njs_variable_index(njs_vm_t *vm, njs_parser_node_t *node,
+ njs_name_reference_t reference)
+{
+ njs_variable_t *var;
+
+ var = njs_variable_get(vm, node, reference);
+
+ if (nxt_fast_path(var != NULL)) {
+ return var->index;
+ }
+
+ return NJS_INDEX_ERROR;
+}
+
+
+static njs_variable_t *
+njs_variable_alloc(njs_vm_t *vm, nxt_str_t *name, njs_variable_type_t type)
+{
+ njs_ret_t ret;
+ njs_variable_t *var;
+
+ var = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_variable_t));
+ if (nxt_slow_path(var == NULL)) {
+ return NULL;
+ }
+
+ var->type = type;
+
+ ret = njs_name_copy(vm, &var->name, name);
if (nxt_fast_path(ret == NXT_OK)) {
return var;
}
+ nxt_mem_cache_free(vm->mem_cache_pool, var);
+
return NULL;
}
+njs_ret_t
+njs_name_copy(njs_vm_t *vm, nxt_str_t *dst, nxt_str_t *src)
+{
+ dst->length = src->length;
+
+ dst->start = nxt_mem_cache_alloc(vm->mem_cache_pool, src->length);
+
+ if (nxt_slow_path(dst->start != NULL)) {
+ (void) memcpy(dst->start, src->start, src->length);
+
+ return NXT_OK;
+ }
+
+ return NXT_ERROR;
+}
+
+
nxt_str_t *
njs_vm_export_functions(njs_vm_t *vm)
{
value = njs_global_variable_value(vm, var);
if (njs_is_function(value) && !value->data.u.function->native) {
- ex->length = var->name_len;
- ex->start = var->name_start;
+ *ex = var->name;
ex++;
}
}
return NULL;
}
-
-
-static njs_variable_t *
-njs_variable_alloc(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name)
-{
- njs_value_t *value;
- njs_variable_t *var;
-
- var = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_variable_t));
-
- if (nxt_fast_path(var != NULL)) {
- var->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->length);
-
- if (nxt_fast_path(var->name_start != NULL)) {
-
- memcpy(var->name_start, name->start, name->length);
- var->name_len = name->length;
-
- value = nxt_array_add(parser->scope_values, &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_fast_path(value != NULL)) {
- *value = njs_value_void;
- var->index = njs_parser_index(parser, parser->scope);
- return var;
- }
- }
- }
-
- return NULL;
-}
-
-
-njs_value_t *
-njs_variable_value(njs_parser_t *parser, njs_index_t index)
-{
- u_char *scope;
-
- scope = parser->scope_values->start;
-
- return (njs_value_t *) (scope + (njs_offset(index) - parser->scope_offset));
-}
typedef enum {
- NJS_VARIABLE_CREATED = 0,
- NJS_VARIABLE_PENDING,
- NJS_VARIABLE_USED,
- NJS_VARIABLE_SET,
- NJS_VARIABLE_DECLARED,
-} njs_variable_state_t;
+ NJS_VARIABLE_CONST = 0,
+ NJS_VARIABLE_LET,
+ NJS_VARIABLE_TYPEOF,
+ NJS_VARIABLE_SHIM,
+ NJS_VARIABLE_VAR,
+ NJS_VARIABLE_FUNCTION,
+} njs_variable_type_t;
+
+
+typedef enum {
+ NJS_NAME_REFERENCE = 0,
+ NJS_NAME_DECLARATION,
+ NJS_NAME_TYPEOF,
+} njs_name_reference_t;
typedef struct {
- u_char *name_start;
- uint16_t name_len;
- njs_variable_state_t state:8; /* 3 bits */
- uint8_t function; /* 1 bit */
+ nxt_str_t name;
+ njs_variable_type_t type:8; /* 3 bits */
njs_index_t index;
+ njs_value_t value;
} njs_variable_t;
+ njs_offset((var)->index) - NJS_INDEX_GLOBAL_OFFSET)
+njs_variable_t *njs_builtin_add(njs_vm_t *vm, njs_parser_t *parser);
+njs_variable_t *njs_variable_add(njs_vm_t *vm, njs_parser_t *parser,
+ njs_variable_type_t type);
+njs_ret_t njs_name_copy(njs_vm_t *vm, nxt_str_t *dst, nxt_str_t *src);
-njs_variable_t *njs_parser_name_alloc(njs_vm_t *vm, njs_parser_t *parser);
-njs_variable_t *njs_parser_variable(njs_vm_t *vm, njs_parser_t *parser,
- nxt_uint_t *level);
-njs_value_t *njs_variable_value(njs_parser_t *parser, njs_index_t index);
nxt_str_t *njs_vm_export_functions(njs_vm_t *vm);
const njs_value_t njs_value_true = njs_value(NJS_BOOLEAN, 1, 1.0);
const njs_value_t njs_value_zero = njs_value(NJS_NUMBER, 0, 0.0);
const njs_value_t njs_value_nan = njs_value(NJS_NUMBER, 0, NAN);
+const njs_value_t njs_value_invalid = njs_value(NJS_INVALID, 0, 0.0);
const njs_value_t njs_string_empty = njs_string("");
vm->frame = previous;
- /* GC: NJS_SCOPE_ARGUMENTS and NJS_SCOPE_LOCAL. */
+ /* GC: NJS_SCOPE_ARGUMENTS and NJS_SCOPE_FUNCTION. */
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = previous->arguments;
- vm->scopes[NJS_SCOPE_LOCAL] = frame->prev_local;
+ vm->scopes[NJS_SCOPE_FUNCTION] = frame->prev_local;
vm->scopes[NJS_SCOPE_ARGUMENTS] = frame->prev_arguments;
if (frame->native.size != 0) {
}
-njs_ret_t
-njs_vmcode_validate(njs_vm_t *vm, njs_value_t *invld, njs_value_t *index)
-{
- njs_value_t *value;
-
- value = njs_vmcode_operand(vm, index);
-
- if (nxt_fast_path(njs_is_valid(value))) {
- return sizeof(njs_vmcode_validate_t);
- }
-
- vm->exception = &njs_exception_reference_error;
-
- return NXT_ERROR;
-}
-
-
njs_ret_t
njs_vmcode_jump(njs_vm_t *vm, njs_value_t *invld, njs_value_t *offset)
{
vm->frame = previous;
vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = previous->arguments;
- vm->scopes[NJS_SCOPE_LOCAL] = frame->prev_local;
+ vm->scopes[NJS_SCOPE_FUNCTION] = frame->prev_local;
args = vm->scopes[NJS_SCOPE_ARGUMENTS];
vm->scopes[NJS_SCOPE_ARGUMENTS] = frame->prev_arguments;
} njs_vmcode_3addr_t;
-typedef struct {
- njs_vmcode_t code;
- njs_index_t index;
-} njs_vmcode_validate_t;
-
-
typedef struct {
njs_vmcode_t code;
njs_index_t dst;
typedef enum {
NJS_SCOPE_ABSOLUTE = 0,
- NJS_SCOPE_LOCAL,
NJS_SCOPE_GLOBAL,
+ NJS_SCOPE_FUNCTION,
NJS_SCOPE_CALLEE_ARGUMENTS,
NJS_SCOPE_ARGUMENTS,
NJS_SCOPE_CLOSURE,
NJS_SCOPE_PARENT_LOCAL,
NJS_SCOPE_PARENT_ARGUMENTS,
NJS_SCOPE_PARENT_CLOSURE,
+ /*
+ * The block and shim scopes are not really VM scopes.
+ * They used only on parsing phase.
+ */
+ NJS_SCOPE_BLOCK = 16,
+ NJS_SCOPE_SHIM = 17,
} njs_scope_t;
#define NJS_SCOPE_SHIFT 4
#define NJS_SCOPE_MASK ((uintptr_t) ((1 << NJS_SCOPE_SHIFT) - 1))
-#define NJS_INDEX_CACHE NJS_SCOPE_LOCAL
+#define NJS_INDEX_CACHE NJS_SCOPE_GLOBAL
#define NJS_INDEX_NONE ((njs_index_t) 0)
#define NJS_INDEX_ERROR ((njs_index_t) -1)
njs_value_t *val2);
njs_ret_t njs_vmcode_move(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld);
-njs_ret_t njs_vmcode_validate(njs_vm_t *vm, njs_value_t *invld,
- njs_value_t *index);
njs_ret_t njs_vmcode_jump(njs_vm_t *vm, njs_value_t *invld,
njs_value_t *offset);
extern const njs_value_t njs_value_true;
extern const njs_value_t njs_value_zero;
extern const njs_value_t njs_value_nan;
+extern const njs_value_t njs_value_invalid;
extern const njs_value_t njs_string_empty;
extern const njs_value_t njs_string_comma;
{
nxt_int_t ret;
njs_lexer_t *lexer;
- njs_value_t *value;
njs_parser_t *parser;
njs_parser_node_t *node;
lexer->keywords_hash = vm->shared->keywords_hash;
parser->code_size = sizeof(njs_vmcode_stop_t);
- parser->scope = NJS_SCOPE_GLOBAL;
parser->scope_offset = NJS_INDEX_GLOBAL_OFFSET;
parser->index[NJS_SCOPE_GLOBAL - NJS_INDEX_CACHE] = NJS_INDEX_GLOBAL_OFFSET;
- parser->scope_values = nxt_array_create(4, sizeof(njs_value_t),
- &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(parser->scope_values == NULL)) {
- return NJS_ERROR;
- }
-
- /* Empty array to minimize tests in njs_parser_variable(). */
- parser->arguments = nxt_array_create(0, sizeof(njs_variable_t),
- &njs_array_mem_proto,
- vm->mem_cache_pool);
- if (nxt_slow_path(parser->arguments == NULL)) {
- return NJS_TOKEN_ERROR;
- }
-
node = njs_parser(vm, parser);
if (nxt_slow_path(node == NULL)) {
return NJS_ERROR;
if (function != NULL) {
if (node->token == NJS_TOKEN_CALL) {
- value = njs_variable_value(parser, node->right->index);
- *function = value->data.u.function;
+ *function = node->right->u.value.data.u.function;
} else {
*function = NULL;
vm->global_scope = parser->local_scope;
vm->scope_size = parser->scope_size;
- vm->variables_hash = parser->variables_hash;
vm->parser = NULL;
nxt_string("undefined") },
{ nxt_string("function f(){} function f(){}"),
- nxt_string("SyntaxError: Duplicate declaration \"f\" in 1") },
+ nxt_string("SyntaxError: Identifier \"f\" has already been declared in 1") },
{ nxt_string("var f = 1; function f() {}"),
- nxt_string("SyntaxError: Duplicate declaration \"f\" in 1") },
+ nxt_string("SyntaxError: Identifier \"f\" has already been declared in 1") },
{ nxt_string("f() = 1"),
nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") },
{ nxt_string("false && (true || true)"),
nxt_string("false") },
- { nxt_string("a = true; a = -~!a"),
+ { nxt_string("var a = true; a = -~!a"),
nxt_string("1") },
{ nxt_string("12 & 6"),
{ nxt_string("NaN ^ 65536"),
nxt_string("65536") },
- { nxt_string("x = '1'; +x + 2"),
+ { nxt_string("var x = '1'; +x + 2"),
nxt_string("3") },
/* Weird things. */
/**/
- { nxt_string("a = 1 ? 2 : 3"),
+ { nxt_string("var a; a = 1 ? 2 : 3"),
nxt_string("2") },
- { nxt_string("a = 1 ? 2 : 3 ? 4 : 5"),
+ { nxt_string("var a; a = 1 ? 2 : 3 ? 4 : 5"),
nxt_string("2") },
- { nxt_string("a = 0 ? 2 : 3 ? 4 : 5"),
+ { nxt_string("var a; a = 0 ? 2 : 3 ? 4 : 5"),
nxt_string("4") },
{ nxt_string("0 ? 2 ? 3 : 4 : 5"),
{ nxt_string("(1 ? 0 : 3) ? 4 : 5"),
nxt_string("5") },
- { nxt_string("a = (1 + 2) ? 2 ? 3 + 4 : 5 : 6"),
+ { nxt_string("var a; a = (1 + 2) ? 2 ? 3 + 4 : 5 : 6"),
nxt_string("7") },
- { nxt_string("a = (1 ? 2 : 3) + 4"),
+ { nxt_string("var a; a = (1 ? 2 : 3) + 4"),
nxt_string("6") },
- { nxt_string("a = 1 ? b = 2 + 4 : b = 3"),
+ { nxt_string("var a, b; a = 1 ? b = 2 + 4 : b = 3"),
nxt_string("6") },
- { nxt_string("a = 1 ? [1,2] : []"),
+ { nxt_string("var a; a = 1 ? [1,2] : []"),
nxt_string("1,2") },
/**/
/**/
- { nxt_string("a = 2; b = ++a + ++a; a + ' ' + b"),
+ { nxt_string("var a, b; a = 2; b = ++a + ++a; a + ' ' + b"),
nxt_string("4 7") },
- { nxt_string("a = 2; b = a++ + a++; a + ' ' + b"),
+ { nxt_string("var a, b; a = 2; b = a++ + a++; a + ' ' + b"),
nxt_string("4 5") },
- { nxt_string("a = b = 7; a +' '+ b"),
+ { nxt_string("var a, b; a = b = 7; a +' '+ b"),
nxt_string("7 7") },
- { nxt_string("a = b = c = 5; a +' '+ b +' '+ c"),
+ { nxt_string("var a, b, c; a = b = c = 5; a +' '+ b +' '+ c"),
nxt_string("5 5 5") },
- { nxt_string("a = b = (c = 5) + 2; a +' '+ b +' '+ c"),
+ { nxt_string("var a, b, c; a = b = (c = 5) + 2; a +' '+ b +' '+ c"),
nxt_string("7 7 5") },
{ nxt_string("1, 2 + 5, 3"),
nxt_string("3") },
- { nxt_string("a = 1 /* YES */\n b = a + 2 \n \n + 1 \n + 3"),
+ { nxt_string("var a, b; a = 1 /* YES */\n b = a + 2 \n \n + 1 \n + 3"),
nxt_string("7") },
- { nxt_string("a = 1 // YES \n b = a + 2 \n \n + 1 \n + 3"),
+ { nxt_string("var a, b; a = 1 // YES \n b = a + 2 \n \n + 1 \n + 3"),
nxt_string("7") },
- { nxt_string("a = 0; ++ \n a"),
+ { nxt_string("var a; a = 0; ++ \n a"),
nxt_string("1") },
{ nxt_string("a = 0; a \n ++"),
nxt_string("SyntaxError: Unexpected end of input in 2") },
- { nxt_string("a = 1 ? 2 \n : 3"),
+ { nxt_string("var a; a = 1 ? 2 \n : 3"),
nxt_string("2") },
- { nxt_string("a = 0 / 0; b = 1 / 0; c = -1 / 0; a +' '+ b +' '+ c"),
+ { nxt_string("var a, b, c;"
+ "a = 0 / 0; b = 1 / 0; c = -1 / 0; a +' '+ b +' '+ c"),
nxt_string("NaN Infinity -Infinity") },
- { nxt_string("a = (b = 7) + 5; var c; a +' '+ b +' '+ c"),
+ { nxt_string("var a, b; a = (b = 7) + 5; var c; a +' '+ b +' '+ c"),
nxt_string("12 7 undefined") },
{ nxt_string("var a, b = 1, c; a +' '+ b +' '+ c"),
{ nxt_string("var a = 1, b = a + 1; a +' '+ b"),
nxt_string("1 2") },
- { nxt_string("a = a = 1"),
+ { nxt_string("var a; a = a = 1"),
nxt_string("1") },
{ nxt_string("var a = 1, \n b; a +' '+ b"),
nxt_string("1 undefined") },
- { nxt_string("a = b + 1; var b; a +' '+ b"),
+ { nxt_string("var a; a = b + 1; var b; a +' '+ b"),
nxt_string("NaN undefined") },
{ nxt_string("var a += 1"),
{ nxt_string("var a = a + 1"),
nxt_string("undefined") },
- { nxt_string("a = b + 1; var b = 1; a +' '+ b"),
+ { nxt_string("var a; a = b + 1; var b = 1; a +' '+ b"),
nxt_string("NaN 1") },
- { nxt_string("(a) = 1"),
+ { nxt_string("var a; (a) = 1"),
nxt_string("1") },
{ nxt_string("a"),
- nxt_string("ReferenceError") },
+ nxt_string("ReferenceError: \"a\" is not defined in 1") },
{ nxt_string("a + a"),
- nxt_string("ReferenceError") },
+ nxt_string("ReferenceError: \"a\" is not defined in 1") },
{ nxt_string("a = b + 1"),
- nxt_string("ReferenceError") },
+ nxt_string("ReferenceError: \"a\" is not defined in 1") },
{ nxt_string("a = a + 1"),
- nxt_string("ReferenceError") },
+ nxt_string("ReferenceError: \"a\" is not defined in 1") },
{ nxt_string("a += 1"),
- nxt_string("ReferenceError") },
+ nxt_string("ReferenceError: \"a\" is not defined in 1") },
{ nxt_string("a += 1; var a = 2"),
nxt_string("undefined") },
{ nxt_string("var a = 1; a += (a = 2)"),
nxt_string("3") },
- { nxt_string("var a = b = 1; a +' '+ b"),
+ { nxt_string("var a = b = 1; var b; a +' '+ b"),
nxt_string("1 1") },
{ nxt_string("var a \n if (!a) a = 3; a"),
{ nxt_string("for ( ;null; ) { continue }"),
nxt_string("undefined") },
- { nxt_string("for (i = 0; i < 100; i++) if (i > 9) continue; i"),
+ { nxt_string("var i; for (i = 0; i < 100; i++) if (i > 9) continue; i"),
nxt_string("100") },
- { nxt_string("var a = []; for (i in a) continue"),
+ { nxt_string("var a = [], i; for (i in a) continue"),
nxt_string("undefined") },
- { nxt_string("var a = []; for (i in a) continue;"),
+ { nxt_string("var a = [], i; for (i in a) continue;"),
nxt_string("undefined") },
- { nxt_string("var a = []; for (i in a) { continue }"),
+ { nxt_string("var a = [], i; for (i in a) { continue }"),
nxt_string("undefined") },
- { nxt_string("var a = [1,2,3,4,5]; var s = 0;"
+ { nxt_string("var a = [1,2,3,4,5]; var s = 0, i;"
"for (i in a) { if (a[i] > 4) continue; else s += a[i] } s"),
nxt_string("10") },
- { nxt_string("var a = [1,2,3,4,5]; var s = 0;"
+ { nxt_string("var a = [1,2,3,4,5]; var s = 0, i;"
"for (i in a) { if (a[i] > 4) continue; s += a[i] } s"),
nxt_string("10") },
{ nxt_string("for ( ;; ) { break }"),
nxt_string("undefined") },
- { nxt_string("for (i = 0; i < 100; i++) if (i > 9) break; i"),
+ { nxt_string("var i; for (i = 0; i < 100; i++) if (i > 9) break; i"),
nxt_string("10") },
- { nxt_string("var a = []; for (i in a) break"),
+ { nxt_string("var a = [], i; for (i in a) break"),
nxt_string("undefined") },
- { nxt_string("var a = []; for (i in a) break;"),
+ { nxt_string("var a = [], i; for (i in a) break;"),
nxt_string("undefined") },
- { nxt_string("var a = []; for (i in a) { break }"),
+ { nxt_string("var a = [], i; for (i in a) { break }"),
nxt_string("undefined") },
- { nxt_string("var a = [1,2,3,4,5]; var s = 0;"
+ { nxt_string("var a = [1,2,3,4,5]; var s = 0, i;"
"for (i in a) { if (a[i] > 4) break; else s += a[i] } s"),
nxt_string("10") },
- { nxt_string("var a = [1,2,3,4,5]; var s = 0;"
+ { nxt_string("var a = [1,2,3,4,5]; var s = 0, i;"
"for (i in a) { if (a[i] > 4) break; s += a[i] } s"),
nxt_string("10") },
- { nxt_string("var a = [1,2,3,4,5]; var s = 0;"
+ { nxt_string("var a = [1,2,3,4,5]; var s = 0, i;"
"for (i in a) if (a[i] > 4) break; s += a[i] } s"),
nxt_string("5") },
/**/
- { nxt_string("for (i = 0; i < 10; i++) { i += 1 } i"),
+ { nxt_string("var i; for (i = 0; i < 10; i++) { i += 1 } i"),
nxt_string("10") },
/* Factorial. */
- { nxt_string("n = 5; f = 1; while (n--) f *= n + 1; f"),
+ { nxt_string("var n = 5, f = 1; while (n--) f *= n + 1; f"),
nxt_string("120") },
- { nxt_string("n = 5; f = 1; while (n) { f *= n; n-- } f"),
+ { nxt_string("var n = 5, f = 1; while (n) { f *= n; n-- } f"),
nxt_string("120") },
/* Fibonacci. */
- { nxt_string("var n = 50, x;"
+ { nxt_string("var n = 50, x, i, j, k;"
"for(i=0,j=1,k=0; k<n; i=j,j=x,k++ ){ x=i+j } x"),
nxt_string("20365011074") },
{ nxt_string("3 + 'abc' + 'def' + null + true + false + undefined"),
nxt_string("3abcdefnulltruefalseundefined") },
- { nxt_string("a = 0; do a++; while (a < 5) if (a == 5) a = 7.33 \n"
+ { nxt_string("var a = 0; do a++; while (a < 5) if (a == 5) a = 7.33 \n"
"else a = 8; while (a < 10) a++; a"),
nxt_string("10.33") },
{ nxt_string("typeof a"),
nxt_string("undefined") },
+ { nxt_string("typeof a; var a"),
+ nxt_string("undefined") },
+
+ { nxt_string("typeof a; var a; a"),
+ nxt_string("undefined") },
+
+ { nxt_string("var a = 5; typeof a"),
+ nxt_string("number") },
+
{ nxt_string("typeof a; a"),
- nxt_string("ReferenceError") },
+ nxt_string("ReferenceError: \"a\" is not defined in 1") },
{ nxt_string("typeof a; a = 1"),
- nxt_string("1") },
+ nxt_string("ReferenceError: \"a\" is not defined in 1") },
/**/
{ nxt_string("++null"),
nxt_string("ReferenceError: Invalid left-hand side in prefix operation in 1") },
- { nxt_string("var a; b = a; a = 1; a +' '+ b"),
+ { nxt_string("var a, b; b = a; a = 1; a +' '+ b"),
nxt_string("1 undefined") },
{ nxt_string("a = 1"),
- nxt_string("1") },
+ nxt_string("ReferenceError: \"a\" is not defined in 1") },
- { nxt_string("a; a = 1; a"),
- nxt_string("ReferenceError") },
+ { nxt_string("var a; a = 1; a"),
+ nxt_string("1") },
- { nxt_string("a = {}; typeof a +' '+ a"),
+ { nxt_string("var a = {}; typeof a +' '+ a"),
nxt_string("object [object Object]") },
- { nxt_string("a = {}; a.b"),
+ { nxt_string("var a = {}; a.b"),
nxt_string("undefined") },
- { nxt_string("a = {}; a.b = 1 + 2; a.b"),
+ { nxt_string("var a = {}; a.b = 1 + 2; a.b"),
nxt_string("3") },
- { nxt_string("a = {}; a['b']"),
+ { nxt_string("var a = {}; a['b']"),
nxt_string("undefined") },
- { nxt_string("a = {}; a.b.c"),
+ { nxt_string("var a = {}; a.b.c"),
nxt_string("TypeError") },
{ nxt_string("'a'.b = 1"),
nxt_string("TypeError") },
- { nxt_string("a = {}; a.b = 1; a.b"),
+ { nxt_string("var a = {}; a.b = 1; a.b"),
nxt_string("1") },
- { nxt_string("a = {}; a.b = 1; a.b += 2"),
+ { nxt_string("var a = {}; a.b = 1; a.b += 2"),
nxt_string("3") },
- { nxt_string("a = {}; a.b = 1; a.b += a.b"),
+ { nxt_string("var a = {}; a.b = 1; a.b += a.b"),
nxt_string("2") },
- { nxt_string("a = {}; a.b = 1; x = {}; x.b = 3; a.b += (x.b = 2)"),
+ { nxt_string("var a = {}; a.b = 1; var x = {}; x.b = 3; a.b += (x.b = 2)"),
nxt_string("3") },
- { nxt_string("a = {}; a.b = 1; a.b += (a.b = 2)"),
+ { nxt_string("var a = {}; a.b = 1; a.b += (a.b = 2)"),
nxt_string("3") },
- { nxt_string("a = {}; a.b += 1"),
+ { nxt_string("var a = {}; a.b += 1"),
nxt_string("NaN") },
- { nxt_string("a = 1; b = 2; a = b += 1"),
+ { nxt_string("var a = 1; var b = 2; a = b += 1"),
nxt_string("3") },
- { nxt_string("a = 1; b = { x:2 }; a = b.x += 1"),
+ { nxt_string("var a = 1; var b = { x:2 }; a = b.x += 1"),
nxt_string("3") },
- { nxt_string("a = 1; b = { x:2 }; a = b.x += (a = 1)"),
+ { nxt_string("var a = 1; var b = { x:2 }; a = b.x += (a = 1)"),
nxt_string("3") },
- { nxt_string("a = undefined; a.b++; a.b"),
+ { nxt_string("var a = undefined; a.b++; a.b"),
nxt_string("TypeError") },
- { nxt_string("a = null; a.b++; a.b"),
+ { nxt_string("var a = null; a.b++; a.b"),
nxt_string("TypeError") },
- { nxt_string("a = true; a.b++; a.b"),
+ { nxt_string("var a = true; a.b++; a.b"),
nxt_string("TypeError") },
- { nxt_string("a = 1; a.b++; a.b"),
+ { nxt_string("var a = 1; a.b++; a.b"),
nxt_string("TypeError") },
{ nxt_string("var n = 1, o = { p: n += 1 }; o.p"),
nxt_string("2") },
- { nxt_string("a = {}; a.b = {}; a.b.c = 1; a.b['c']"),
+ { nxt_string("var a = {}; a.b = {}; a.b.c = 1; a.b['c']"),
nxt_string("1") },
- { nxt_string("a = {}; a.b = {}; a.b.c = 1; a['b']['c']"),
+ { nxt_string("var a = {}; a.b = {}; a.b.c = 1; a['b']['c']"),
nxt_string("1") },
- { nxt_string("a = {}; a.b = {}; c = 'd'; a.b.d = 1; a['b'][c]"),
+ { nxt_string("var a = {}; a.b = {}; var c = 'd'; a.b.d = 1; a['b'][c]"),
nxt_string("1") },
- { nxt_string("a = {}; a.b = 1; c = a.b++; a.b +' '+ c"),
+ { nxt_string("var a = {}; a.b = 1; var c = a.b++; a.b +' '+ c"),
nxt_string("2 1") },
- { nxt_string("a = 2; a.b = 1; c = a.b++; a +' '+ a.b +' '+ c"),
+ { nxt_string("var a = 2; a.b = 1; var c = a.b++; a +' '+ a.b +' '+ c"),
nxt_string("TypeError") },
- { nxt_string("x = { a: 1 }; x.a"),
+ { nxt_string("var x = { a: 1 }; x.a"),
nxt_string("1") },
- { nxt_string("a = { x:1 }; b = { y:2 }; a.x = b.y; a.x"),
+ { nxt_string("var a = { x:1 }; var b = { y:2 }; a.x = b.y; a.x"),
nxt_string("2") },
- { nxt_string("a = { x:1 }; b = { y:2 }; c = a.x = b.y; c"),
+ { nxt_string("var a = { x:1 }; var b = { y:2 }; var c; c = a.x = b.y"),
nxt_string("2") },
- { nxt_string("a = { x:1 }; b = { y:2 }; a.x = b.y"),
+ { nxt_string("var a = { x:1 }; var b = { y:2 }; var c = a.x = b.y; c"),
nxt_string("2") },
- { nxt_string("a = { x:1 }; b = a.x = 1 + 2; a.x +' '+ b"),
+ { nxt_string("var a = { x:1 }; var b = { y:2 }; a.x = b.y"),
+ nxt_string("2") },
+
+ { nxt_string("var a = { x:1 }; var b = a.x = 1 + 2; a.x +' '+ b"),
nxt_string("3 3") },
- { nxt_string("a = { x:1 }; b = { y:2 }; c = {}; c.x = a.x = b.y; c.x"),
+ { nxt_string("var a = { x:1 }; var b = { y:2 }; var c = {};"
+ "c.x = a.x = b.y; c.x"),
nxt_string("2") },
- { nxt_string("y = 2; x = { a:1, b: y + 5, c:3 }; x.a +' '+ x.b +' '+ x.c"),
+ { nxt_string("var y = 2, x = { a:1, b: y + 5, c:3 };"
+ "x.a +' '+ x.b +' '+ x.c"),
nxt_string("1 7 3") },
- { nxt_string("x = { a: 1, b: { a:2, c:5 } }; x.a +' '+ x.b.a +' '+ x.b.c"),
+ { nxt_string("var x = { a: 1, b: { a:2, c:5 } };"
+ "x.a +' '+ x.b.a +' '+ x.b.c"),
nxt_string("1 2 5") },
- { nxt_string("var y = 5; x = { a:y }; x.a"),
+ { nxt_string("var y = 5, x = { a:y }; x.a"),
nxt_string("5") },
- { nxt_string("x = { a: 1; b: 2 }"),
+ { nxt_string("var x = { a: 1; b: 2 }"),
nxt_string("SyntaxError: Unexpected token \";\" in 1") },
- { nxt_string("x = { a: 1, b: x.a }"),
- nxt_string("ReferenceError") },
+ { nxt_string("var x = { a: 1, b: x.a }"),
+ nxt_string("TypeError") },
- { nxt_string("a = { b: 2 }; a.b += 1"),
+ { nxt_string("var a = { b: 2 }; a.b += 1"),
nxt_string("3") },
- { nxt_string("o = {a:1}; c = o; o.a = o = {b:5};"
+ { nxt_string("var o = {a:1}, c = o; o.a = o = {b:5};"
"o.a +' '+ o.b +' '+ c.a.b"),
nxt_string("undefined 5 5") },
- { nxt_string("y = { a: 2 }; x = { a: 1, b: y.a }; x.a +' '+ x.b"),
+ { nxt_string("var y = { a: 2 }, x = { a: 1, b: y.a }; x.a +' '+ x.b"),
nxt_string("1 2") },
- { nxt_string("y = { a: 1 }; x = { a: y.a++, b: y.a++ }\n"
+ { nxt_string("var y = { a: 1 }, x = { a: y.a++, b: y.a++ }\n"
"x.a +' '+ x.b +' '+ y.a"),
nxt_string("1 2 3") },
- { nxt_string("var a=''; var o = {a:1, b:2};"
+ { nxt_string("var a='', o = {a:1, b:2}, p;"
"for (p in o) { a += p +':'+ o[p] +',' } a"),
nxt_string("a:1,b:2,") },
- { nxt_string("x = { a: 1 }; b = delete x.a; x.a +' '+ b"),
+ { nxt_string("var x = { a: 1 }, b = delete x.a; x.a +' '+ b"),
nxt_string("undefined true") },
{ nxt_string("delete null"),
{ nxt_string("delete a"),
nxt_string("SyntaxError: Delete of an unqualified identifier in 1") },
- { nxt_string("a = 1; delete a"),
+ { nxt_string("var a = 1; delete a"),
nxt_string("SyntaxError: Delete of an unqualified identifier in 1") },
{ nxt_string("function f(){} delete f"),
nxt_string("SyntaxError: Delete of an unqualified identifier in 1") },
- { nxt_string("a = { x:1 }; ('x' in a) +' '+ (1 in a)"),
+ { nxt_string("var a = { x:1 }; ('x' in a) +' '+ (1 in a)"),
nxt_string("true false") },
{ nxt_string("delete --[][1]"),
nxt_string("true") },
- { nxt_string("a = {}; 1 in a"),
+ { nxt_string("var a = {}; 1 in a"),
nxt_string("false") },
- { nxt_string("a = 1; 1 in a"),
+ { nxt_string("var a = 1; 1 in a"),
nxt_string("TypeError") },
- { nxt_string("a = true; 1 in a"),
+ { nxt_string("var a = true; 1 in a"),
nxt_string("TypeError") },
{ nxt_string("var n = { toString: function() { return 'a' } };"
{ nxt_string("3 * [5,7]"),
nxt_string("NaN") },
- { nxt_string("a = [ 1, 2, 3 ]; a[0] + a[1] + a[2]"),
+ { nxt_string("var a = [ 1, 2, 3 ]; a[0] + a[1] + a[2]"),
nxt_string("6") },
{ nxt_string("var n = 1, a = [ n += 1 ]; a"),
nxt_string("2") },
- { nxt_string("a = [ 1, 2; 3 ]; a[0] + a[1] + a[2]"),
+ { nxt_string("var a = [ 1, 2; 3 ]; a[0] + a[1] + a[2]"),
nxt_string("SyntaxError: Unexpected token \";\" in 1") },
- { nxt_string("a = [ 1, 2, 3 ]; a[0] +' '+ a[1] +' '+ a[2] +' '+ a[3]"),
+ { nxt_string("var a = [ 1, 2, 3 ]; a[0] +' '+ a[1] +' '+ a[2] +' '+ a[3]"),
nxt_string("1 2 3 undefined") },
{ nxt_string("[] - 2"),
{ nxt_string("[[[1]]] - 2"),
nxt_string("-1") },
- { nxt_string("a = []; a - 2"),
+ { nxt_string("var a = []; a - 2"),
nxt_string("-2") },
- { nxt_string("a = [1]; a - 2"),
+ { nxt_string("var a = [1]; a - 2"),
nxt_string("-1") },
- { nxt_string("a = []; a[0] = 1; a - 2"),
+ { nxt_string("var a = []; a[0] = 1; a - 2"),
nxt_string("-1") },
{ nxt_string("[] + 2 + 3"),
{ nxt_string("[1] + 2 + 3"),
nxt_string("123") },
- { nxt_string("a = []; a + 2 + 3"),
+ { nxt_string("var a = []; a + 2 + 3"),
nxt_string("23") },
- { nxt_string("a = [1]; a + 2 + 3"),
+ { nxt_string("var a = [1]; a + 2 + 3"),
nxt_string("123") },
- { nxt_string("a = [1,2]; i = 0; a[i++] += a[0] = 5 + i; a[0] +' '+ a[1]"),
+ { nxt_string("var a = [1,2], i = 0; a[i++] += a[0] = 5 + i;"
+ "a[0] +' '+ a[1]"),
nxt_string("7 2") },
- { nxt_string("a = []; a[0] = 1; a + 2 + 3"),
+ { nxt_string("var a = []; a[0] = 1; a + 2 + 3"),
nxt_string("123") },
- { nxt_string("a = []; a['0'] = 1; a + 2 + 3"),
+ { nxt_string("var a = []; a['0'] = 1; a + 2 + 3"),
nxt_string("123") },
- { nxt_string("a = []; a[2] = 1; a[2]"),
+ { nxt_string("var a = []; a[2] = 1; a[2]"),
nxt_string("1") },
- { nxt_string("a = [1, 2]; 1 in a"),
+ { nxt_string("var a = [1, 2]; 1 in a"),
nxt_string("true") },
- { nxt_string("a = [1, 2]; 2 in a"),
+ { nxt_string("var a = [1, 2]; 2 in a"),
nxt_string("false") },
- { nxt_string("a = [1, 2]; delete a[0]; 0 in a"),
+ { nxt_string("var a = [1, 2]; delete a[0]; 0 in a"),
nxt_string("false") },
{ nxt_string("var a = [ function(a) {return a + 1} ]; a[0](5)"),
nxt_string("6") },
- { nxt_string("var s = '', a = [5,1,2];"
+ { nxt_string("var s = '', a = [5,1,2], i;"
"a[null] = null;"
"a[undefined] = 'defined';"
"a[false] = false;"
{ nxt_string("[1,2].length"),
nxt_string("2") },
- { nxt_string("a = [1,2]; a.length"),
+ { nxt_string("var a = [1,2]; a.length"),
nxt_string("2") },
- { nxt_string("a = [1,2,3]; a.join()"),
+ { nxt_string("var a = [1,2,3]; a.join()"),
nxt_string("1,2,3") },
- { nxt_string("a = [1,2,3]; a.join(':')"),
+ { nxt_string("var a = [1,2,3]; a.join(':')"),
nxt_string("1:2:3") },
- { nxt_string("a = []; a[5] = 5; a.join()"),
+ { nxt_string("var a = []; a[5] = 5; a.join()"),
nxt_string(",,,,,5") },
{ nxt_string("var a = [,null,undefined,false,true,0,1]; a.join()"),
"[o].join()"),
nxt_string("undefined") },
- { nxt_string("a = []; a[5] = 5; a"),
+ { nxt_string("var a = []; a[5] = 5; a"),
nxt_string(",,,,,5") },
- { nxt_string("a = []; a.concat([])"),
+ { nxt_string("var a = []; a.concat([])"),
nxt_string("") },
{ nxt_string("var s = { toString: function() { return 'S' } };"
/* Array.toString(). */
- { nxt_string("a = [1,2,3]; a.join = 'NO';"
+ { nxt_string("var a = [1,2,3]; a.join = 'NO';"
"Object.prototype.toString = function () { return 'A' }; a"),
nxt_string("[object Array]") },
{ nxt_string("Array.isArray([])"),
nxt_string("true") },
- { nxt_string("a = [1,2,3]; a.concat(4, [5, 6, 7], 8)"),
+ { nxt_string("var a = [1,2,3]; a.concat(4, [5, 6, 7], 8)"),
nxt_string("1,2,3,4,5,6,7,8") },
- { nxt_string("a = []; a[100] = a.length; a[100] +' '+ a.length"),
+ { nxt_string("var a = []; a[100] = a.length; a[100] +' '+ a.length"),
nxt_string("0 101") },
- { nxt_string("a = [1,2]; a[100] = 100; a[100] +' '+ a.length"),
+ { nxt_string("var a = [1,2]; a[100] = 100; a[100] +' '+ a.length"),
nxt_string("100 101") },
{ nxt_string("Array.prototype.slice(1)"),
{ nxt_string("[0,1,2,3,4].slice(6,7)"),
nxt_string("") },
- { nxt_string("a = [1,2,3,4,5]; b = a.slice(3); b[0] +' '+ b[1] +' '+ b[2]"),
+ { nxt_string("var a = [1,2,3,4,5], b = a.slice(3);"
+ "b[0] +' '+ b[1] +' '+ b[2]"),
nxt_string("4 5 undefined") },
- { nxt_string("a = [1,2]; a.pop() +' '+ a.length +' '+ a"),
+ { nxt_string("var a = [1,2]; a.pop() +' '+ a.length +' '+ a"),
nxt_string("2 1 1") },
- { nxt_string("a = [1,2]; len = a.push(3); len +' '+ a.pop() +' '+ a"),
+ { nxt_string("var a = [1,2], len = a.push(3); len +' '+ a.pop() +' '+ a"),
nxt_string("3 3 1,2") },
- { nxt_string("a = [1,2]; len = a.push(3,4,5); len +' '+ a.pop() +' '+ a"),
+ { nxt_string("var a = [1,2], len = a.push(3,4,5);"
+ "len +' '+ a.pop() +' '+ a"),
nxt_string("5 5 1,2,3,4") },
- { nxt_string("a = [1,2,3]; a.shift() +' '+ a[0] +' '+ a.length"),
+ { nxt_string("var a = [1,2,3]; a.shift() +' '+ a[0] +' '+ a.length"),
nxt_string("1 2 2") },
- { nxt_string("a = [1,2]; len = a.unshift(3);"
+ { nxt_string("var a = [1,2], len = a.unshift(3);"
"len +' '+ a +' '+ a.shift()"),
nxt_string("3 3,1,2 3") },
- { nxt_string("a = [1,2]; len = a.unshift(3,4,5);"
+ { nxt_string("var a = [1,2], len = a.unshift(3,4,5);"
"len +' '+ a +' '+ a.shift()"),
nxt_string("5 3,4,5,1,2 3") },
{ nxt_string("'囲碁織'.toUTF8().length"),
nxt_string("9") },
- { nxt_string("a = 'abc'; a.length"),
+ { nxt_string("var a = 'abc'; a.length"),
nxt_string("3") },
- { nxt_string("a = 'abc'; a['length']"),
+ { nxt_string("var a = 'abc'; a['length']"),
nxt_string("3") },
- { nxt_string("a = 'абв'; a.length"),
+ { nxt_string("var a = 'абв'; a.length"),
nxt_string("3") },
- { nxt_string("a = 'abc' + 'абв'; a.length"),
+ { nxt_string("var a = 'abc' + 'абв'; a.length"),
nxt_string("6") },
- { nxt_string("a = 'abc' + 1 + 'абв'; a +' '+ a.length"),
+ { nxt_string("var a = 'abc' + 1 + 'абв'; a +' '+ a.length"),
nxt_string("abc1абв 7") },
- { nxt_string("a = 1; a.length"),
+ { nxt_string("var a = 1; a.length"),
nxt_string("undefined") },
- { nxt_string("a = 'abc'; a.concat('абв', 123)"),
+ { nxt_string("var a = 'abc'; a.concat('абв', 123)"),
nxt_string("abcабв123") },
{ nxt_string("''.concat.call(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)"),
{ nxt_string("'\\u00CE\\u00B1'.toBytes() === 'α'"),
nxt_string("false") },
- { nxt_string("b = '\\u00C2\\u00B6'.toBytes(); u = b.fromUTF8();"
+ { nxt_string("var b = '\\u00C2\\u00B6'.toBytes(), u = b.fromUTF8();"
"b.length +' '+ b +' '+ u.length +' '+ u"),
nxt_string("2 ¶ 1 ¶") },
{ nxt_string("'α'.toUTF8()[0]"),
nxt_string("\xCE") },
- { nxt_string("a = 'a'.toBytes() + 'α'; a + a.length"),
+ { nxt_string("var a = 'a'.toBytes() + 'α'; a + a.length"),
nxt_string("aα3") },
- { nxt_string("a = 'µ§±®'.toBytes(); a"),
+ { nxt_string("var a = 'µ§±®'.toBytes(); a"),
nxt_string("\xB5\xA7\xB1\xAE") },
- { nxt_string("a = 'µ§±®'.toBytes(2); a"),
+ { nxt_string("var a = 'µ§±®'.toBytes(2); a"),
nxt_string("\xB1\xAE") },
- { nxt_string("a = 'µ§±®'.toBytes(1,3); a"),
+ { nxt_string("var a = 'µ§±®'.toBytes(1,3); a"),
nxt_string("\xA7\xB1") },
- { nxt_string("a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes()"),
+ { nxt_string("var a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes()"),
nxt_string("µ§±®") },
- { nxt_string("a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes(2)"),
+ { nxt_string("var a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes(2)"),
nxt_string("±®") },
- { nxt_string("a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes(1, 3)"),
+ { nxt_string("var a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes(1, 3)"),
nxt_string("§±") },
- { nxt_string("a = 'abcdefgh'; a.substr(3, 15)"),
+ { nxt_string("var a = 'abcdefgh'; a.substr(3, 15)"),
nxt_string("defgh") },
{ nxt_string("'abcdefgh'.substr(3, 15)"),
{ nxt_string("'abc'.charCodeAt(3)"),
nxt_string("NaN") },
- { nxt_string("a = 'abcdef'; a.3"),
+ { nxt_string("var a = 'abcdef'; a.3"),
nxt_string("SyntaxError: Unexpected token \"3\" in 1") },
{ nxt_string("'abcdef'[3]"),
{ nxt_string("'abcdef'[8]"),
nxt_string("undefined") },
- { nxt_string("a = 'abcdef'; b = 1 + 2; a[b]"),
+ { nxt_string("var a = 'abcdef', b = 1 + 2; a[b]"),
nxt_string("d") },
/**/
{ nxt_string("typeof $r"),
nxt_string("undefined") },
- { nxt_string("a = $r.uri; s = a.fromUTF8(); s.length +' '+ s"),
+ { nxt_string("var a = $r.uri, s = a.fromUTF8(); s.length +' '+ s"),
nxt_string("3 АБВ") },
- { nxt_string("a = $r.uri; s = a.fromUTF8(2); s.length +' '+ s"),
+ { nxt_string("var a = $r.uri, s = a.fromUTF8(2); s.length +' '+ s"),
nxt_string("2 БВ") },
- { nxt_string("a = $r.uri; s = a.fromUTF8(2, 4); s.length +' '+ s"),
+ { nxt_string("var a = $r.uri, s = a.fromUTF8(2, 4); s.length +' '+ s"),
nxt_string("1 Б") },
- { nxt_string("a = $r.uri; a +' '+ a.length +' '+ a"),
+ { nxt_string("var a = $r.uri; a +' '+ a.length +' '+ a"),
nxt_string("АБВ 6 АБВ") },
- { nxt_string("$r.uri = 'αβγ'; a = $r.uri; a.length +' '+ a"),
+ { nxt_string("$r.uri = 'αβγ'; var a = $r.uri; a.length +' '+ a"),
nxt_string("6 αβγ") },
{ nxt_string("$r.uri.length +' '+ $r.uri"),
{ nxt_string("$r.uri = $r.uri.substr(2); $r.uri.length +' '+ $r.uri"),
nxt_string("4 БВ") },
- { nxt_string("a = $r.host; a +' '+ a.length +' '+ a"),
+ { nxt_string("var a = $r.host; a +' '+ a.length +' '+ a"),
nxt_string("АБВГДЕЁЖЗИЙ 22 АБВГДЕЁЖЗИЙ") },
- { nxt_string("a = $r.host; a.substr(2, 2)"),
+ { nxt_string("var a = $r.host; a.substr(2, 2)"),
nxt_string("Б") },
- { nxt_string("a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
+ { nxt_string("var a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
nxt_string("User-Agent|АБВ 17 User-Agent|АБВ") },
- { nxt_string("var a='';"
+ { nxt_string("var a='', p;"
"for (p in $r.header) { a += p +':'+ $r.header[p] +',' }"
"a"),
nxt_string("01:01|АБВ,02:02|АБВ,03:03|АБВ,") },
{ nxt_string("$r.some_method('YES')"),
nxt_string("АБВ") },
- { nxt_string("for (p in $r.some_method);"),
+ { nxt_string("var p; for (p in $r.some_method);"),
nxt_string("undefined") },
{ nxt_string("'uri' in $r"),
{ nxt_string("'abcdef'.substr(2, 4).charAt(2)"),
nxt_string("e") },
- { nxt_string("a = 'abcdef'.substr(2, 4).charAt(2).length"),
+ { nxt_string("var a = 'abcdef'.substr(2, 4).charAt(2).length; a"),
nxt_string("1") },
- { nxt_string("a = 'abcdef'.substr(2, 4).charAt(2) + '1234'"),
+ { nxt_string("var a = 'abcdef'.substr(2, 4).charAt(2) + '1234'; a"),
nxt_string("e1234") },
- { nxt_string("a = ('abcdef'.substr(2, 5 * 2 - 6).charAt(2) + '1234')"
- " .length"),
+ { nxt_string("var a = ('abcdef'.substr(2, 5 * 2 - 6).charAt(2) + '1234')"
+ " .length; a"),
nxt_string("5") },
{ nxt_string("String.fromCharCode('_')"),
nxt_string("αβγ") },
{ nxt_string("(function() {"
+ " var n;"
" for (n = 0; n <= 1114111; n++) {"
" if (String.fromCharCode(n).charCodeAt(0) !== n)"
" return n;"
"})()"),
nxt_string("-1") },
- { nxt_string("a = 'abcdef'; function f(a) {"
+ { nxt_string("var a = 'abcdef'; function f(a) {"
"return a.slice(a.indexOf('cd')) } f(a)"),
nxt_string("cdef") },
- { nxt_string("a = 'abcdef'; a.slice(a.indexOf('cd'))"),
+ { nxt_string("var a = 'abcdef'; a.slice(a.indexOf('cd'))"),
nxt_string("cdef") },
{ nxt_string("'abcdef'.indexOf('de', 2)"),
{ nxt_string("'абв'.toUpperCase()"),
nxt_string("АБВ") },
- { nxt_string("var a = [];"
+ { nxt_string("var a = [], code;"
"for (code = 0; code <= 1114111; code++) {"
" var s = String.fromCharCode(code);"
" var n = s.toUpperCase();"
"} a"),
nxt_string("181,305,383,453,456,459,498,837,962,976,977,981,982,1008,1009,1013,7835,8126") },
- { nxt_string("var a = [];"
+ { nxt_string("var a = [], code;"
"for (code = 0; code <= 1114111; code++) {"
" var s = String.fromCharCode(code);"
" var n = s.toLowerCase();"
{ nxt_string("function f(){return\n1} f()"),
nxt_string("undefined") },
- { nxt_string("function f(a) { return a + 1 } b = f(2)"),
+ { nxt_string("function f(a) { return a + 1 } var b = f(2); b"),
nxt_string("3") },
- { nxt_string("f = function(a) { a *= 2; return a }; f(10)"),
+ { nxt_string("var f = function(a) { a *= 2; return a }; f(10)"),
nxt_string("20") },
{ nxt_string("var f = function b(a) { a *= 2; return a }; f(10)"),
nxt_string("20") },
{ nxt_string("var f = function b(a) { a *= 2; return a }; b(10)"),
- nxt_string("ReferenceError") },
+ nxt_string("ReferenceError: \"b\" is not defined in 1") },
- { nxt_string("var f = function(a) { a *= 2; return a }; f(10)"),
+ { nxt_string("var f; f = function(a) { a *= 2; return a }; f(10)"),
nxt_string("20") },
- { nxt_string("f = function b(a) { a *= 2; return a }; b(10)"),
- nxt_string("ReferenceError") },
-
- { nxt_string("f = function b(a) { a *= 2; return a }; f(10)"),
+ { nxt_string("var f; f = function b(a) { a *= 2; return a }; f(10)"),
nxt_string("20") },
- { nxt_string("f = a = function(a) { a *= 2; return a }; f(10)"),
+ { nxt_string("var a, f = a = function(a) { a *= 2; return a }; f(10)"),
nxt_string("20") },
- { nxt_string("f = a = function(a) { a *= 2; return a }; a(10)"),
+ { nxt_string("var a, f = a = function(a) { a *= 2; return a }; a(10)"),
nxt_string("20") },
{ nxt_string("var f = function b(a) { a *= 2; return a } = 5"),
{ nxt_string("function a() { return { x:2} }; var b = a(); b.x"),
nxt_string("2") },
- { nxt_string("a = {}; function f(a) { return a + 1 } a.b = f(2); a.b"),
+ { nxt_string("var a = {}; function f(a) { return a + 1 } a.b = f(2); a.b"),
nxt_string("3") },
{ nxt_string("(function(x) { return x + 1 })(2)"),
{ nxt_string("(function(x) { return x + 1 }(2))"),
nxt_string("3") },
- { nxt_string("a = function() { return 1 }(); a"),
+ { nxt_string("var a = function() { return 1 }(); a"),
nxt_string("1") },
- { nxt_string("a = (function() { return 1 })(); a"),
+ { nxt_string("var a = (function() { return 1 })(); a"),
nxt_string("1") },
- { nxt_string("a = (function(a) { return a + 1 })(2); a"),
+ { nxt_string("var a = (function(a) { return a + 1 })(2); a"),
nxt_string("3") },
- { nxt_string("a = (function(a) { return a + 1 }(2)); a"),
+ { nxt_string("var a = (function(a) { return a + 1 }(2)); a"),
nxt_string("3") },
- { nxt_string("a = +function(a) { return a + 1 }(2); a"),
+ { nxt_string("var a = +function(a) { return a + 1 }(2); a"),
nxt_string("3") },
- { nxt_string("a = -function(a) { return a + 1 }(2); a"),
+ { nxt_string("var a = -function(a) { return a + 1 }(2); a"),
nxt_string("-3") },
- { nxt_string("a = !function(a) { return a + 1 }(2); a"),
+ { nxt_string("var a = !function(a) { return a + 1 }(2); a"),
nxt_string("false") },
- { nxt_string("a = ~function(a) { return a + 1 }(2); a"),
+ { nxt_string("var a = ~function(a) { return a + 1 }(2); a"),
nxt_string("-4") },
- { nxt_string("a = void function(a) { return a + 1 }(2); a"),
+ { nxt_string("var a = void function(a) { return a + 1 }(2); a"),
nxt_string("undefined") },
- { nxt_string("a = true && function(a) { return a + 1 }(2); a"),
+ { nxt_string("var a = true && function(a) { return a + 1 }(2); a"),
nxt_string("3") },
- { nxt_string("a = 0, function(a) { return a + 1 }(2); a"),
+ { nxt_string("var a; a = 0, function(a) { return a + 1 }(2); a"),
nxt_string("0") },
- { nxt_string("a = (0, function(a) { return a + 1 }(2)); a"),
+ { nxt_string("var a = (0, function(a) { return a + 1 }(2)); a"),
nxt_string("3") },
{ nxt_string("var a = 0, function(a) { return a + 1 }(2); a"),
{ nxt_string("var a = +function f(a) { return a + 1 }(2);"
"var b = f(5); a"),
- nxt_string("ReferenceError") },
+ nxt_string("ReferenceError: \"f\" is not defined in 1") },
{ nxt_string("var o = { f: function(a) { return a * 2 } }; o.f(5)"),
nxt_string("10") },
nxt_string("01") },
{ nxt_string("function f(a) { return this+a };"
- "o = { g: function (f, a, b) { return f.call(a, b) } };"
+ "var o = { g: function (f, a, b) { return f.call(a, b) } };"
"o.g(f, '0', 1)"),
nxt_string("01") },
"o.__proto__ === F.prototype"),
nxt_string("true") },
- { nxt_string("f = { F: function(){} }; o = new f.F();"
+ { nxt_string("var f = { F: function(){} }; var o = new f.F();"
"o.__proto__ === f.F.prototype"),
nxt_string("true") },
nxt_string("3 5") },
{ nxt_string("function a() { return function(x) { return x + 1 } }"
- "b = a(); b(2)"),
+ "var b = a(); b(2)"),
nxt_string("3") },
+ /* Scopes. */
+
+ { nxt_string("function f(x) { a = x } var a; f(5); a"),
+ nxt_string("5") },
+
+ { nxt_string("function f(x) { var a = x } var a = 2; f(5); a"),
+ nxt_string("2") },
+
+ { nxt_string("function f(a) { return a } var a = '2'; a + f(5)"),
+ nxt_string("25") },
+
/* RegExp. */
{ nxt_string("/./x"),
printf("\"%.*s\"\n",
(int) njs_test[i].script.length, njs_test[i].script.start);
+ fflush(stdout);
vm = njs_vm_create(mcp, &shared, &externals);
if (vm == NULL) {