case NJS_TOKEN_VAR:
case NJS_TOKEN_LET:
+ case NJS_TOKEN_CONST:
return njs_generate_var_statement(vm, generator, node);
case NJS_TOKEN_IF:
return NJS_OK;
}
- if (var->type == NJS_VARIABLE_LET) {
+ if (var->type == NJS_VARIABLE_LET || var->type == NJS_VARIABLE_CONST) {
scope = njs_function_scope(node->scope);
if (scope->dest_disable) {
return NJS_OK;
}
- if (var->type == NJS_VARIABLE_LET) {
+ if (var->type == NJS_VARIABLE_LET || var->type == NJS_VARIABLE_CONST) {
scope = njs_function_scope(node->scope);
if ((!scope->dest_disable && njs_function_scope(var->scope) == scope)) {
if (expr == NULL) {
/* Variable is only declared. */
+
+ if (var->type == NJS_VARIABLE_CONST) {
+ njs_syntax_error(vm, "missing initializer in const declaration");
+ return NJS_ERROR;
+ }
+
if (var->type == NJS_VARIABLE_LET) {
ret = njs_generate_let(vm, generator, node, var);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_OK;
}
- if (var->type == NJS_VARIABLE_LET) {
+ if (var->type == NJS_VARIABLE_LET || var->type == NJS_VARIABLE_CONST) {
ret = njs_generate_wo_dest(vm, generator, expr);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
let = node->right;
- if (let->token_type != NJS_TOKEN_LET) {
+ if (let->token_type != NJS_TOKEN_LET
+ && let->token_type != NJS_TOKEN_CONST)
+ {
return NJS_OK;
}
goto statement;
}
- if (!var->init && var->type == NJS_VARIABLE_LET) {
+ if (!var->init && (var->type == NJS_VARIABLE_LET
+ || var->type == NJS_VARIABLE_CONST))
+ {
njs_generate_code(generator, njs_vmcode_variable_t, code,
NJS_VMCODE_INITIALIZATION_TEST, 0, right);
code->dst = right->index;
{
njs_int_t ret;
njs_index_t index, src;
+ njs_variable_t *var;
njs_parser_node_t *lvalue, *expr, *object, *property;
njs_vmcode_move_t *move;
+ njs_vmcode_variable_t *var_code;
njs_vmcode_prop_set_t *prop_set;
lvalue = node->left;
if (lvalue->token_type == NJS_TOKEN_NAME) {
ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION,
- NULL);
+ &var);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
+ if (var != NULL && var->type == NJS_VARIABLE_CONST) {
+ njs_generate_code(generator, njs_vmcode_variable_t, var_code,
+ NJS_VMCODE_ASSIGNMENT_ERROR, 0, node);
+ var_code->dst = var->index;
+
+ return NJS_OK;
+ }
+
expr->dest = lvalue;
ret = njs_generator(vm, generator, expr);
{
njs_int_t ret;
njs_index_t index, src;
+ njs_variable_t *var;
njs_parser_node_t *lvalue, *expr, *object, *property;
njs_vmcode_move_t *move;
njs_vmcode_3addr_t *code;
+ njs_vmcode_variable_t *var_code;
njs_vmcode_prop_get_t *prop_get;
njs_vmcode_prop_set_t *prop_set;
if (lvalue->token_type == NJS_TOKEN_NAME) {
ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION,
- NULL);
+ &var);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
+ if (var != NULL && var->type == NJS_VARIABLE_CONST) {
+ njs_generate_code(generator, njs_vmcode_variable_t, var_code,
+ NJS_VMCODE_ASSIGNMENT_ERROR, 0, node);
+ var_code->dst = var->index;
+
+ return NJS_OK;
+ }
+
index = lvalue->index;
expr = node->right;
{
njs_int_t ret;
njs_index_t index, dest_index;
+ njs_variable_t *var;
njs_parser_node_t *lvalue;
njs_vmcode_3addr_t *code;
+ njs_vmcode_variable_t *var_code;
njs_vmcode_prop_get_t *prop_get;
njs_vmcode_prop_set_t *prop_set;
if (lvalue->token_type == NJS_TOKEN_NAME) {
ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION,
- NULL);
+ &var);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
+ if (var != NULL && var->type == NJS_VARIABLE_CONST) {
+ njs_generate_code(generator, njs_vmcode_variable_t, var_code,
+ NJS_VMCODE_ASSIGNMENT_ERROR, 0, node);
+ var_code->dst = var->index;
+
+ return NJS_OK;
+ }
+
index = njs_generate_dest_index(vm, generator, node);
if (njs_slow_path(index == NJS_INDEX_ERROR)) {
return index;
{ njs_str("function static() {}"),
njs_str("SyntaxError: Unexpected token \"static\" in 1") },
+ { njs_str("var arr = [];"
+ "function fn(one) {"
+ " var x = one + 1;"
+ " let y = one + 2;"
+ " const u = one + 4;"
+ " {"
+ " {"
+ " let z = one + 3;"
+ " const v = one + 5;"
+ " function f() {"
+ " arr.push(one); arr.push(x);"
+ " arr.push(y); arr.push(z);"
+ " arr.push(u); arr.push(v);"
+ " }"
+ " f();"
+ " }"
+ " }"
+ "}"
+ "fn(1); arr"),
+ njs_str("1,2,3,4,5,6") },
+
/* Recursive factorial. */
{ njs_str("function f(a) {"
{ njs_str("function static() {}"),
njs_str("SyntaxError: Unexpected token \"static\" in 1") },
+
+ /* const */
+
+ { njs_str("const x"),
+ njs_str("SyntaxError: missing initializer in const declaration") },
+
+ { njs_str("const x = 1; x"),
+ njs_str("1") },
+
+ { njs_str("const x = 1; x = 1"),
+ njs_str("TypeError: assignment to constant variable") },
+
+ { njs_str("function abc() {const x}"),
+ njs_str("SyntaxError: missing initializer in const declaration") },
+
+ { njs_str("const x = [123]; x"),
+ njs_str("123") },
+
+ { njs_str("const x = () => x; x()"),
+ njs_str("[object Function]") },
+
+ { njs_str("const x = (() => x)()"),
+ njs_str("ReferenceError: cannot access to variable before initialization") },
+
+ { njs_str("x; const x = 123"),
+ njs_str("ReferenceError: cannot access to variable before initialization") },
+
+ { njs_str("const x = x + 123"),
+ njs_str("ReferenceError: cannot access to variable before initialization") },
+
+ { njs_str("const x; var x"),
+ njs_str("SyntaxError: \"x\" has already been declared in 1") },
+
+ { njs_str("const x; let x"),
+ njs_str("SyntaxError: \"x\" has already been declared in 1") },
+
+ { njs_str("let x; const x"),
+ njs_str("SyntaxError: \"x\" has already been declared in 1") },
+
+ { njs_str("const x = 1; function x() {}"),
+ njs_str("SyntaxError: \"x\" has already been declared in 1") },
+
+ { njs_str("function x() {} const x = 1"),
+ njs_str("SyntaxError: \"x\" has already been declared in 1") },
+
+ { njs_str("function x() {const x; var x}"),
+ njs_str("SyntaxError: \"x\" has already been declared in 1") },
+
+ { njs_str("function x() {var x; const x}"),
+ njs_str("SyntaxError: \"x\" has already been declared in 1") },
+
+ { njs_str("const x = function f() {const f = 1}"),
+ njs_str("undefined") },
+
+ { njs_str("let res; const x = 1;"
+ "{const x = 2; res = x}"
+ "[x, res]"),
+ njs_str("1,2") },
+
+ { njs_str("let res; const x = 1;"
+ "if (true) {const x = 2; res = x}"
+ "[x, res]"),
+ njs_str("1,2") },
+
+ { njs_str("function func() {return x}"
+ "const x = 123;"
+ "func()"),
+ njs_str("123") },
+
+ { njs_str("function func() {return x}"
+ "func();"
+ "const x = 123"),
+ njs_str("ReferenceError: cannot access to variable before initialization") },
+
+ { njs_str("function func() {return () => x}"
+ "const x = 123;"
+ "func()()"),
+ njs_str("123") },
+
+ { njs_str("function func() {return () => x++}"
+ "const x = 123;"
+ "func()()"),
+ njs_str("TypeError: assignment to constant variable") },
+
+ { njs_str("for (const i = 0; i < 1; i++) {}"),
+ njs_str("TypeError: assignment to constant variable") },
+
+ { njs_str("let res = [];"
+ "for (const n in [1,2,3]) {res.push(n)}"
+ "res"),
+ njs_str("0,1,2") },
+
+ { njs_str("let arr = [], res = [];"
+ ""
+ "for (const n in [1,2,3]) {"
+ " arr.push(() => n);"
+ "}"
+ ""
+ "for (let n in arr) {"
+ " res.push(arr[n]());"
+ "}"
+ "res"),
+ njs_str("0,1,2") },
+
+ { njs_str("let arr = [];"
+ ""
+ "for (const n in [1,2,3]) {"
+ " let n = 1;"
+ " arr.push(n);"
+ "}"
+ "arr"),
+ njs_str("1,1,1") },
+
+ { njs_str("for (const n in [1,2,3]) {"
+ " let n = n + 1;"
+ "}"),
+ njs_str("ReferenceError: cannot access to variable before initialization") },
+
+ { njs_str("for (const n in [1,2,3]) {}"
+ "n"),
+ njs_str("ReferenceError: \"n\" is not defined") },
+
+ { njs_str("for (const n in [1,n,3]) {}"),
+ njs_str("ReferenceError: cannot access to variable before initialization") },
+
+ { njs_str("(function() {"
+ "function f() {return x + 1}"
+ "function abc() {f()};"
+ "abc();"
+ "const x = 1;"
+ "}())"),
+ njs_str("ReferenceError: cannot access to variable before initialization") },
+
+ { njs_str("if (false) const x = 1"),
+ njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
+
+ { njs_str("while (false) const x = 1"),
+ njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
+
+ { njs_str("for (;;) const x = 1"),
+ njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
+
+ { njs_str("try {} catch (e) {const e = 1}"),
+ njs_str("SyntaxError: \"e\" has already been declared in 1") },
+
+ { njs_str("let arr = []; const x = 2;"
+ "switch(true) {default: const x = 1; arr.push(x)}"
+ "arr.push(x); arr"),
+ njs_str("1,2") },
+
+ { njs_str("let res;"
+ "switch(true) {case true: const x = 1; default: x = 2; res = x} res"),
+ njs_str("TypeError: assignment to constant variable") },
+
+ { njs_str("const null"),
+ njs_str("SyntaxError: Unexpected token \"null\" in 1") },
+
+ { njs_str("const continue"),
+ njs_str("SyntaxError: Unexpected token \"continue\" in 1") },
+
+ { njs_str("const undefined"),
+ njs_str("SyntaxError: \"undefined\" has already been declared in 1") },
+
+ { njs_str("const a = 1; globalThis.a"),
+ njs_str("undefined") },
+
+ { njs_str("if (false) {x = 2} else {x = 1} const x = 0"),
+ njs_str("ReferenceError: cannot access to variable before initialization") },
+
+ { njs_str("const const"),
+ njs_str("SyntaxError: Unexpected token \"const\" in 1") },
};