[njs] Syntax error messages are more verbose and have line number.
Igor Sysoev
igor at sysoev.ru
Wed Jul 13 12:28:13 UTC 2016
details: http://hg.nginx.org/njs/rev/07d2be75a7db
branches:
changeset: 120:07d2be75a7db
user: Igor Sysoev <igor at sysoev.ru>
date: Wed Jul 13 13:56:12 2016 +0300
description:
Syntax error messages are more verbose and have line number.
diffstat:
njs/njs_builtin.c | 2 +
njs/njs_generator.c | 66 +++++++++++--
njs/njs_lexer.c | 23 ++++-
njs/njs_nonrecursive_parser.c | 2 +-
njs/njs_parser.c | 187 ++++++++++++++++++++++++++++++++---------
njs/njs_parser.h | 16 +++
njs/njs_parser_expression.c | 35 ++++++-
njs/njs_regexp.c | 89 +++++++++++++++----
njs/njs_regexp.h | 3 +-
njs/njs_string.c | 60 +------------
njs/njs_string.h | 2 -
njs/njs_vm.c | 24 +++++-
njs/njs_vm.h | 7 +-
njs/njscript.c | 3 +-
njs/test/njs_unit_test.c | 100 +++++++++++++++++-----
15 files changed, 442 insertions(+), 177 deletions(-)
diffs (truncated from 1568 to 1000 lines):
diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_builtin.c
--- a/njs/njs_builtin.c Mon Jul 11 15:24:29 2016 +0300
+++ b/njs/njs_builtin.c Wed Jul 13 13:56:12 2016 +0300
@@ -19,6 +19,8 @@
#include <njs_object.h>
#include <njs_array.h>
#include <njs_function.h>
+#include <njs_variable.h>
+#include <njs_parser.h>
#include <njs_regexp.h>
#include <njs_date.h>
#include <njs_math.h>
diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_generator.c
--- a/njs/njs_generator.c Mon Jul 11 15:24:29 2016 +0300
+++ b/njs/njs_generator.c Wed Jul 13 13:56:12 2016 +0300
@@ -20,6 +20,13 @@
#include <njs_variable.h>
#include <njs_parser.h>
#include <string.h>
+#include <stdio.h>
+
+
+typedef enum {
+ NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE = 0,
+ NJS_GENERATOR_ERROR_ILLEGAL_BREAK,
+} njs_generator_error_t;
static nxt_int_t njs_generator(njs_vm_t *vm, njs_parser_t *parser,
@@ -117,6 +124,8 @@ static nxt_noinline nxt_int_t njs_genera
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 nxt_int_t njs_generator_error(njs_vm_t *vm, njs_parser_node_t *node,
+ njs_generator_error_t err);
static const nxt_str_t no_label = { 0, NULL };
@@ -1067,19 +1076,20 @@ njs_generate_continue_statement(njs_vm_t
{
njs_vmcode_jump_t *jump;
njs_parser_patch_t *patch;
-
- if (parser->block == NULL) {
- vm->exception = &njs_exception_syntax_error;
- return NXT_ERROR;
+ njs_parser_block_t *block;
+
+ for (block = parser->block; block != NULL; block = block->next) {
+ if (block->type == NJS_PARSER_LOOP) {
+ goto found;
+ }
}
+ return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE);
+
+found:
+
/* TODO: LABEL */
- if (parser->block->type != NJS_PARSER_LOOP) {
- vm->exception = &njs_exception_syntax_error;
- return NXT_ERROR;
- }
-
patch = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_patch_t));
if (nxt_fast_path(patch != NULL)) {
@@ -1105,12 +1115,20 @@ njs_generate_break_statement(njs_vm_t *v
{
njs_vmcode_jump_t *jump;
njs_parser_patch_t *patch;
-
- if (parser->block == NULL) {
- vm->exception = &njs_exception_syntax_error;
- return NXT_ERROR;
+ njs_parser_block_t *block;
+
+ for (block = parser->block; block != NULL; block = block->next) {
+ if (block->type == NJS_PARSER_LOOP
+ || block->type == NJS_PARSER_SWITCH)
+ {
+ goto found;
+ }
}
+ return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_BREAK);
+
+found:
+
/* TODO: LABEL: loop and switch may have label, block must have label. */
patch = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_patch_t));
@@ -2466,3 +2484,25 @@ njs_generator_is_constant(njs_parser_nod
return (node->token >= NJS_TOKEN_FIRST_CONST
&& node->token <= NJS_TOKEN_LAST_CONST);
}
+
+
+static nxt_int_t
+njs_generator_error(njs_vm_t *vm, njs_parser_node_t *node,
+ njs_generator_error_t err)
+{
+ uint32_t size;
+ const char *msg;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
+
+ static const char *errors[] = {
+ "SyntaxError: Illegal continue statement in %u",
+ "SyntaxError: Illegal break statement in %u",
+ };
+
+ msg = errors[err];
+
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ msg, node->token_line);
+
+ return njs_vm_throw_exception(vm, buf, size);
+}
diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_lexer.c
--- a/njs/njs_lexer.c Mon Jul 11 15:24:29 2016 +0300
+++ b/njs/njs_lexer.c Wed Jul 13 13:56:12 2016 +0300
@@ -47,7 +47,7 @@ static const uint8_t njs_tokens[256] n
NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL,
/* \t */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_SPACE,
/* \n */ NJS_TOKEN_LINE_END, NJS_TOKEN_ILLEGAL,
- /* \r */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_LINE_END,
+ /* \r */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_SPACE,
NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL,
/* 0x10 */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL,
@@ -300,6 +300,8 @@ njs_lexer_next_token(njs_lexer_t *lexer)
njs_token_t token;
const njs_lexer_multi_t *multi;
+ lexer->text.data = lexer->start;
+
while (lexer->start < lexer->end) {
c = *lexer->start++;
@@ -308,6 +310,7 @@ njs_lexer_next_token(njs_lexer_t *lexer)
switch (token) {
case NJS_TOKEN_SPACE:
+ lexer->text.data = lexer->start;
continue;
case NJS_TOKEN_LETTER:
@@ -396,6 +399,10 @@ njs_lexer_next_token(njs_lexer_t *lexer)
goto multi;
case NJS_TOKEN_LINE_END:
+ lexer->line++;
+
+ /* Fall through. */
+
case NJS_TOKEN_BITWISE_NOT:
case NJS_TOKEN_OPEN_PARENTHESIS:
case NJS_TOKEN_CLOSE_PARENTHESIS:
@@ -408,6 +415,7 @@ njs_lexer_next_token(njs_lexer_t *lexer)
case NJS_TOKEN_COLON:
case NJS_TOKEN_SEMICOLON:
case NJS_TOKEN_CONDITIONAL:
+ lexer->text.len = lexer->start - lexer->text.data;
return token;
default: /* NJS_TOKEN_ILLEGAL */
@@ -449,6 +457,7 @@ njs_lexer_word(njs_lexer_t *lexer, u_cha
0x00, 0x00, 0x00, 0x00, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
};
+ lexer->token_line = lexer->line;
lexer->key_hash = nxt_djb_hash_add(NXT_DJB_HASH_INIT, c);
lexer->text.data = lexer->start - 1;
@@ -489,7 +498,7 @@ njs_lexer_string(njs_lexer_t *lexer, u_c
if (c == '\\') {
if (p == lexer->end) {
- return NJS_TOKEN_ILLEGAL;
+ break;
}
p++;
@@ -510,7 +519,10 @@ njs_lexer_string(njs_lexer_t *lexer, u_c
}
}
- return NJS_TOKEN_ILLEGAL;
+ lexer->text.data--;
+ lexer->text.len = p - lexer->text.data;
+
+ return NJS_TOKEN_UNTERMINATED_STRING;
}
@@ -590,7 +602,8 @@ njs_lexer_multi(njs_lexer_t *lexer, njs_
lexer->start++;
if (multi->count == 0) {
- return multi->token;
+ token = multi->token;
+ break;
}
return njs_lexer_multi(lexer, multi->token, multi->count,
@@ -603,6 +616,8 @@ njs_lexer_multi(njs_lexer_t *lexer, njs_
} while (n != 0);
}
+ lexer->text.len = lexer->start - lexer->text.data;
+
return token;
}
diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_nonrecursive_parser.c
--- a/njs/njs_nonrecursive_parser.c Mon Jul 11 15:24:29 2016 +0300
+++ b/njs/njs_nonrecursive_parser.c Wed Jul 13 13:56:12 2016 +0300
@@ -16,9 +16,9 @@
#include <njs_vm.h>
#include <njs_number.h>
#include <njs_object.h>
-#include <njs_regexp.h>
#include <njs_variable.h>
#include <njs_parser.h>
+#include <njs_regexp.h>
#include <string.h>
diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_parser.c
--- a/njs/njs_parser.c Mon Jul 11 15:24:29 2016 +0300
+++ b/njs/njs_parser.c Wed Jul 13 13:56:12 2016 +0300
@@ -18,10 +18,11 @@
#include <njs_string.h>
#include <njs_object.h>
#include <njs_function.h>
-#include <njs_regexp.h>
#include <njs_variable.h>
#include <njs_parser.h>
+#include <njs_regexp.h>
#include <string.h>
+#include <stdio.h>
/*
@@ -52,18 +53,22 @@ static njs_token_t njs_parser_var_statem
static njs_token_t njs_parser_if_statement(njs_vm_t *vm, njs_parser_t *parser);
static njs_token_t njs_parser_switch_statement(njs_vm_t *vm,
njs_parser_t *parser);
+static njs_token_t njs_parser_duplicate_default_branch(njs_vm_t *vm,
+ njs_parser_t *parser);
static njs_token_t njs_parser_while_statement(njs_vm_t *vm,
njs_parser_t *parser);
static njs_token_t njs_parser_do_while_statement(njs_vm_t *vm,
njs_parser_t *parser);
static njs_token_t njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser);
static njs_token_t njs_parser_for_in_statement(njs_vm_t *vm,
- njs_parser_t *parser, njs_token_t token);
+ njs_parser_t *parser, nxt_str_t *name, njs_token_t token);
static njs_token_t njs_parser_continue_statement(njs_vm_t *vm,
njs_parser_t *parser);
static njs_token_t njs_parser_break_statement(njs_vm_t *vm,
njs_parser_t *parser);
static njs_token_t njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser);
+static njs_token_t njs_parser_missing_catch_or_finally(njs_vm_t *vm,
+ njs_parser_t *parser);
static njs_token_t njs_parser_try_block(njs_vm_t *vm, njs_parser_t *parser);
static njs_token_t njs_parser_throw_statement(njs_vm_t *vm,
njs_parser_t *parser);
@@ -78,7 +83,9 @@ static njs_token_t njs_parser_object(njs
static njs_token_t njs_parser_array(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *obj);
static njs_token_t njs_parser_escape_string_create(njs_vm_t *vm,
- njs_value_t *value);
+ njs_parser_t *parser, njs_value_t *value);
+static njs_token_t njs_parser_unexpected_token(njs_vm_t *vm,
+ njs_parser_t *parser, njs_token_t token);
njs_parser_node_t *
@@ -154,7 +161,7 @@ njs_parser_statement_chain(njs_vm_t *vm,
}
} else if (vm->exception == NULL) {
- vm->exception = &njs_exception_syntax_error;
+ (void) njs_parser_unexpected_token(vm, parser, token);
}
return token;
@@ -269,14 +276,14 @@ njs_parser_block(njs_vm_t *vm, njs_parse
nxt_inline njs_token_t
-njs_parser_match(njs_parser_t *parser, njs_token_t token,
+njs_parser_match(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token,
njs_token_t match)
{
if (nxt_fast_path(token == match)) {
return njs_parser_token(parser);
}
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_unexpected_token(vm, parser, token);
}
@@ -303,7 +310,7 @@ njs_parser_function_declaration(njs_vm_t
}
if (token != NJS_TOKEN_NAME) {
- return NJS_TOKEN_ERROR;
+ return NJS_TOKEN_ILLEGAL;
}
var = njs_parser_variable(vm, parser, &level);
@@ -463,7 +470,7 @@ njs_parser_function_lambda(njs_vm_t *vm,
parser = lambda->u.parser;
- token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -640,12 +647,9 @@ njs_parser_var_statement(njs_vm_t *vm, n
}
if (token != NJS_TOKEN_NAME) {
- /* TODO: message. */
return NJS_TOKEN_ILLEGAL;
}
- nxt_thread_log_debug("JS: %V", &parser->lexer->text);
-
var = njs_parser_variable(vm, parser, &level);
if (nxt_slow_path(var == NULL)) {
return NJS_TOKEN_ERROR;
@@ -802,7 +806,7 @@ njs_parser_switch_statement(njs_vm_t *vm
swtch->left = parser->node;
last = &swtch->right;
- token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_BRACE);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_BRACE);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -841,8 +845,7 @@ njs_parser_switch_statement(njs_vm_t *vm
} else {
if (dflt != NULL) {
- /* A duplicate "default" branch. */
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_duplicate_default_branch(vm, parser);
}
branch = node;
@@ -858,7 +861,7 @@ njs_parser_switch_statement(njs_vm_t *vm
*last = branch;
last = &branch->left;
- token = njs_parser_match(parser, token, NJS_TOKEN_COLON);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -888,6 +891,22 @@ njs_parser_switch_statement(njs_vm_t *vm
static njs_token_t
+njs_parser_duplicate_default_branch(njs_vm_t *vm, njs_parser_t *parser)
+{
+ uint32_t size;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
+
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ "SyntaxError: More than one default clause "
+ "in switch statement in %u", parser->lexer->line);
+
+ (void) njs_vm_throw_exception(vm, buf, size);
+
+ return NJS_TOKEN_ILLEGAL;
+}
+
+
+static njs_token_t
njs_parser_while_statement(njs_vm_t *vm, njs_parser_t *parser)
{
njs_token_t token;
@@ -954,7 +973,7 @@ njs_parser_do_while_statement(njs_vm_t *
node = njs_parser_node_alloc(vm);
if (nxt_slow_path(node == NULL)) {
- return NJS_TOKEN_ILLEGAL;
+ return NJS_TOKEN_ERROR;
}
node->token = NJS_TOKEN_DO;
@@ -970,6 +989,7 @@ njs_parser_do_while_statement(njs_vm_t *
static njs_token_t
njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser)
{
+ nxt_str_t name;
njs_token_t token;
njs_parser_node_t *node, *init, *condition, *update, *cond, *body;
@@ -984,12 +1004,13 @@ njs_parser_for_statement(njs_vm_t *vm, n
return token;
}
- token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
if (token != NJS_TOKEN_SEMICOLON) {
+ name = parser->lexer->text;
token = njs_parser_expression(vm, parser, token);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
@@ -999,11 +1020,11 @@ njs_parser_for_statement(njs_vm_t *vm, n
init = parser->node;
if (init->token == NJS_TOKEN_IN) {
- return njs_parser_for_in_statement(vm, parser, token);
+ return njs_parser_for_in_statement(vm, parser, &name, token);
}
}
- token = njs_parser_match(parser, token, NJS_TOKEN_SEMICOLON);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_SEMICOLON);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -1018,7 +1039,7 @@ njs_parser_for_statement(njs_vm_t *vm, n
condition = parser->node;
}
- token = njs_parser_match(parser, token, NJS_TOKEN_SEMICOLON);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_SEMICOLON);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -1033,7 +1054,7 @@ njs_parser_for_statement(njs_vm_t *vm, n
update = parser->node;
}
- token = njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -1076,14 +1097,23 @@ njs_parser_for_statement(njs_vm_t *vm, n
static njs_token_t
-njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser,
+njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name,
njs_token_t token)
{
+ uint32_t size;
njs_parser_node_t *node;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
node = parser->node->left;
if (node->token != NJS_TOKEN_NAME) {
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ "ReferenceError: Invalid left-hand side \"%.*s\" "
+ "in for-in statement in %u",
+ (int) name->len, name->data, parser->lexer->line);
+
+ (void) njs_vm_throw_exception(vm, buf, size);
+
return NJS_TOKEN_ILLEGAL;
}
@@ -1097,7 +1127,7 @@ njs_parser_for_in_statement(njs_vm_t *vm
node->token = NJS_TOKEN_FOR_IN;
node->left = parser->node;
- token = njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -1127,6 +1157,7 @@ njs_parser_continue_statement(njs_vm_t *
}
node->token = NJS_TOKEN_CONTINUE;
+ node->token_line = parser->lexer->token_line;
parser->node = node;
parser->code_size += sizeof(njs_vmcode_jump_t);
@@ -1161,6 +1192,7 @@ njs_parser_break_statement(njs_vm_t *vm,
}
node->token = NJS_TOKEN_BREAK;
+ node->token_line = parser->lexer->token_line;
parser->node = node;
parser->code_size += sizeof(njs_vmcode_jump_t);
@@ -1214,7 +1246,7 @@ njs_parser_try_statement(njs_vm_t *vm, n
return token;
}
- token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -1223,8 +1255,6 @@ njs_parser_try_statement(njs_vm_t *vm, n
return NJS_TOKEN_ILLEGAL;
}
- nxt_thread_log_debug("CATCH: %V", &parser->lexer->text);
-
catch = njs_parser_node_alloc(vm);
if (nxt_slow_path(catch == NULL)) {
return NJS_TOKEN_ERROR;
@@ -1297,8 +1327,7 @@ njs_parser_try_statement(njs_vm_t *vm, n
}
if (try->right == NULL) {
- /* TODO: message */
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_missing_catch_or_finally(vm, parser);
}
parser->node = try;
@@ -1309,6 +1338,22 @@ njs_parser_try_statement(njs_vm_t *vm, n
static njs_token_t
+njs_parser_missing_catch_or_finally(njs_vm_t *vm, njs_parser_t *parser)
+{
+ uint32_t size;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
+
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ "SyntaxError: Missing catch or finally after try in %u",
+ parser->lexer->line);
+
+ (void) njs_vm_throw_exception(vm, buf, size);
+
+ return NJS_TOKEN_ILLEGAL;
+}
+
+
+static njs_token_t
njs_parser_try_block(njs_vm_t *vm, njs_parser_t *parser)
{
njs_token_t token;
@@ -1366,7 +1411,7 @@ njs_parser_grouping_expression(njs_vm_t
return token;
}
- token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -1376,7 +1421,7 @@ njs_parser_grouping_expression(njs_vm_t
return token;
}
- return njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
+ return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
}
@@ -1435,7 +1480,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa
return token;
}
- return njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
+ return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
}
if (token == NJS_TOKEN_FUNCTION) {
@@ -1534,9 +1579,9 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa
return token;
case NJS_TOKEN_DIVISION:
- ret = njs_regexp_literal(vm, parser, &node->u.value);
- if (nxt_slow_path(ret != NXT_OK)) {
- return NJS_TOKEN_ILLEGAL;
+ token = njs_regexp_literal(vm, parser, &node->u.value);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
}
nxt_thread_log_debug("REGEX: '%V'", &parser->lexer->text);
@@ -1561,13 +1606,17 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa
nxt_thread_log_debug("JS: '%V'", &parser->lexer->text);
- ret = njs_parser_escape_string_create(vm, &node->u.value);
+ ret = njs_parser_escape_string_create(vm, parser, &node->u.value);
if (nxt_slow_path(ret != NJS_TOKEN_STRING)) {
return ret;
}
break;
+ case NJS_TOKEN_UNTERMINATED_STRING:
+ return njs_parser_error(vm, parser,
+ NJS_PARSER_ERROR_UNTERMINATED_STRING);
+
case NJS_TOKEN_NUMBER:
nxt_thread_log_debug("JS: %f", parser->lexer->number);
@@ -1652,8 +1701,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa
return njs_parser_builtin_function(vm, parser, node);
default:
- vm->exception = &njs_exception_syntax_error;
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_unexpected_token(vm, parser, token);
}
parser->node = node;
@@ -1769,7 +1817,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars
return token;
}
- token = njs_parser_match(parser, token, NJS_TOKEN_COLON);
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
@@ -1944,7 +1992,8 @@ njs_parser_string_create(njs_vm_t *vm, n
static njs_token_t
-njs_parser_escape_string_create(njs_vm_t *vm, njs_value_t *value)
+njs_parser_escape_string_create(njs_vm_t *vm, njs_parser_t *parser,
+ njs_value_t *value)
{
u_char c, *p, *start, *dst, *src, *end, *hex_end;
size_t size, length, hex_length, skip;
@@ -1962,8 +2011,8 @@ njs_parser_escape_string_create(njs_vm_t
size = 0;
length = 0;
- src = vm->parser->lexer->text.data;
- end = src + vm->parser->lexer->text.len;
+ src = parser->lexer->text.data;
+ end = src + parser->lexer->text.len;
while (src < end) {
c = *src++;
@@ -1995,7 +2044,8 @@ njs_parser_escape_string_create(njs_vm_t
}
if (hex_length == 0 || hex_length > 6) {
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_error(vm, parser,
+ NJS_PARSER_ERROR_UNICODE);
}
skip = 1;
@@ -2070,12 +2120,12 @@ njs_parser_escape_string_create(njs_vm_t
hex_end = src + hex_length;
if (hex_end > end) {
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE);
}
u = njs_number_radix_parse(src, hex_end, 16, 1);
if (nxt_slow_path(u < 0)) {
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE);
}
src = hex_end + skip;
@@ -2154,3 +2204,52 @@ njs_parser_has_side_effect(njs_parser_no
return side_effect;
}
+
+
+static njs_token_t
+njs_parser_unexpected_token(njs_vm_t *vm, njs_parser_t *parser,
+ njs_token_t token)
+{
+ uint32_t size;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
+
+ if (token != NJS_TOKEN_END) {
+ return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNEXPECTED_TOKEN);
+ }
+
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ "SyntaxError: Unexpected end of input in %u",
+ parser->lexer->line);
+
+ (void) njs_vm_throw_exception(vm, buf, size);
+
+ return NJS_TOKEN_ILLEGAL;
+}
+
+
+njs_token_t
+njs_parser_error(njs_vm_t *vm, njs_parser_t *parser, njs_parser_error_t err)
+{
+ uint32_t size;
+ njs_lexer_t *lexer;
+ const char *msg;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
+
+ static const char *errors[] = {
+ "SyntaxError: Unexpected token \"%.*s\" in %u",
+ "SyntaxError: Unterminated string \"%.*s\" in %u",
+ "SyntaxError: Invalid Unicode code point \"%.*s\" in %u",
+ "SyntaxError: Unterminated RegExp \"%.*s\" in %u",
+ "SyntaxError: Invalid RegExp flags \"%.*s\" in %u",
+ };
+
+ msg = errors[err];
+ lexer = parser->lexer;
+
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ msg, (int) lexer->text.len, lexer->text.data, lexer->line);
+
+ (void) njs_vm_throw_exception(vm, buf, size);
+
+ return NJS_TOKEN_ILLEGAL;
+}
diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_parser.h
--- a/njs/njs_parser.h Mon Jul 11 15:24:29 2016 +0300
+++ b/njs/njs_parser.h Wed Jul 13 13:56:12 2016 +0300
@@ -117,6 +117,7 @@ typedef enum {
#define NJS_TOKEN_LAST_CONST NJS_TOKEN_STRING
NJS_TOKEN_ESCAPE_STRING,
+ NJS_TOKEN_UNTERMINATED_STRING,
NJS_TOKEN_NAME,
NJS_TOKEN_OBJECT,
@@ -191,6 +192,9 @@ typedef struct {
uint8_t property; /* 1 bit */
uint32_t key_hash;
+ uint32_t token_line;
+ uint32_t line;
+
nxt_str_t text;
double number;
@@ -224,6 +228,7 @@ struct njs_parser_node_s {
njs_lvalue_state_t lvalue:2; /* 2 bits */
uint8_t ctor:1; /* 1 bit */
uint8_t temporary; /* 1 bit */
+ uint32_t token_line;
union {
uint32_t length;
@@ -313,6 +318,15 @@ struct njs_parser_s {
};
+typedef enum {
+ NJS_PARSER_ERROR_UNEXPECTED_TOKEN = 0,
+ NJS_PARSER_ERROR_UNTERMINATED_STRING,
+ NJS_PARSER_ERROR_UNICODE,
+ NJS_PARSER_ERROR_UNTERMINATED_REGEXP,
+ NJS_PARSER_ERROR_REGEXP_FLAGS,
+} njs_parser_error_t;
+
+
njs_token_t njs_lexer_token(njs_lexer_t *lexer);
nxt_int_t njs_lexer_keywords_init(nxt_mem_cache_pool_t *mcp,
nxt_lvlhsh_t *hash);
@@ -339,6 +353,8 @@ njs_token_t njs_parser_token(njs_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);
nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node);
+njs_token_t njs_parser_error(njs_vm_t *vm, njs_parser_t *parser,
+ njs_parser_error_t err);
nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node);
diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_parser_expression.c
--- a/njs/njs_parser_expression.c Mon Jul 11 15:24:29 2016 +0300
+++ b/njs/njs_parser_expression.c Wed Jul 13 13:56:12 2016 +0300
@@ -9,6 +9,7 @@
#include <nxt_clang.h>
#include <nxt_alignment.h>
#include <nxt_stub.h>
+#include <nxt_utf8.h>
#include <nxt_array.h>
#include <nxt_lvlhsh.h>
#include <nxt_random.h>
@@ -16,11 +17,13 @@
#include <njscript.h>
#include <njs_vm.h>
#include <njs_number.h>
+#include <njs_string.h>
#include <njs_object.h>
#include <njs_function.h>
#include <njs_variable.h>
#include <njs_parser.h>
#include <string.h>
+#include <stdio.h>
typedef struct {
@@ -71,6 +74,8 @@ static njs_token_t njs_parser_property_e
njs_parser_t *parser, njs_token_t token);
static njs_token_t njs_parser_property_brackets(njs_vm_t *vm,
njs_parser_t *parser, njs_token_t token);
+static njs_token_t njs_parser_invalid_lvalue(njs_vm_t *vm,
+ njs_parser_t *parser, const char* operation);
static const njs_parser_expression_t
@@ -288,8 +293,7 @@ njs_parser_var_expression(njs_vm_t *vm,
node = parser->node;
if (node->lvalue == NJS_LVALUE_NONE) {
- nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required");
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_invalid_lvalue(vm, parser, "assignment");
}
pending = NULL;
@@ -434,8 +438,7 @@ njs_parser_assignment_expression(njs_vm_
node = parser->node;
if (node->lvalue == NJS_LVALUE_NONE) {
- nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required");
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_invalid_lvalue(vm, parser, "assignment");
}
pending = NULL;
@@ -807,8 +810,7 @@ njs_parser_inc_dec_expression(njs_vm_t *
}
if (parser->node->lvalue == NJS_LVALUE_NONE) {
- nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required");
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_invalid_lvalue(vm, parser, "prefix operation");
}
node = njs_parser_node_alloc(vm);
@@ -860,8 +862,7 @@ njs_parser_post_inc_dec_expression(njs_v
}
if (parser->node->lvalue == NJS_LVALUE_NONE) {
- nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required");
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_invalid_lvalue(vm, parser, "postfix operation");
}
node = njs_parser_node_alloc(vm);
@@ -1142,3 +1143,21 @@ njs_parser_arguments(njs_vm_t *vm, njs_p
return token;
}
+
+
+static njs_token_t
+njs_parser_invalid_lvalue(njs_vm_t *vm, njs_parser_t *parser,
+ const char *operation)
+{
+ uint32_t size;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
+
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ "ReferenceError: Invalid left-hand side in %s in %u",
+ operation, parser->lexer->line);
+
+ (void) njs_vm_throw_exception(vm, buf, size);
+
+ return NJS_TOKEN_ILLEGAL;
+
+}
diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_regexp.c
--- a/njs/njs_regexp.c Mon Jul 11 15:24:29 2016 +0300
+++ b/njs/njs_regexp.c Wed Jul 13 13:56:12 2016 +0300
@@ -24,11 +24,12 @@
#include <njs_object_hash.h>
#include <njs_array.h>
#include <njs_function.h>
+#include <njs_variable.h>
+#include <njs_parser.h>
#include <njs_regexp.h>
#include <njs_regexp_pattern.h>
-#include <njs_variable.h>
-#include <njs_parser.h>
#include <string.h>
+#include <stdio.h>
static void *njs_regexp_malloc(size_t size, void *memory_data);
@@ -133,7 +134,7 @@ njs_regexp_constructor(njs_vm_t *vm, njs
}
-nxt_int_t
+njs_token_t
njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value)
{
u_char *p;
@@ -154,11 +155,15 @@ njs_regexp_literal(njs_vm_t *vm, njs_par
lexer->text.data = lexer->start;
lexer->text.len = p - lexer->text.data;
p++;
+ lexer->start = p;
flags = njs_regexp_flags(&p, lexer->end, 0);
if (nxt_slow_path(flags < 0)) {
- return NXT_ERROR;
+ lexer->text.data = lexer->start;
+ lexer->text.len = p - lexer->text.data;
+ return njs_parser_error(vm, parser,
+ NJS_PARSER_ERROR_REGEXP_FLAGS);
}
lexer->start = p;
@@ -166,16 +171,19 @@ njs_regexp_literal(njs_vm_t *vm, njs_par
pattern = njs_regexp_pattern_create(vm, lexer->text.data,
lexer->text.len, flags);
if (nxt_slow_path(pattern == NULL)) {
- return NXT_ERROR;
+ return NJS_TOKEN_ILLEGAL;
}
value->data.u.data = pattern;
- return NXT_OK;
+ return NJS_TOKEN_REGEXP;
}
}
- return NXT_ERROR;
+ lexer->text.data = lexer->start - 1;
+ lexer->text.len = p - lexer->text.data;
+
+ return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNTERMINATED_REGEXP);
}
@@ -203,16 +211,28 @@ njs_regexp_flags(u_char **start, u_char
flag = NJS_REGEXP_MULTILINE;
break;
- default:
- if (bound) {
- return NJS_REGEXP_INVALID_FLAG;
+ case ';':
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case ',':
+ case ')':
+ case ']':
+ case '}':
+ case '.':
+ if (!bound) {
+ goto done;
}
- goto done;
+ /* Fall through. */
+
+ default:
+ goto invalid;
}
if (nxt_slow_path((flags & flag) != 0)) {
- return NJS_REGEXP_INVALID_FLAG;
+ goto invalid;
}
flags |= flag;
@@ -223,6 +243,12 @@ done:
*start = p;
return flags;
+
+invalid:
+
+ *start = p + 1;
+
+ return NJS_REGEXP_INVALID_FLAG;
}
@@ -298,10 +324,7 @@ njs_regexp_pattern_create(njs_vm_t *vm,
if (nxt_fast_path(ret >= 0)) {
if (nxt_slow_path((u_int) ret != pattern->ncaptures)) {
- nxt_thread_log_error(NXT_LOG_ERR, "numbers of captures in byte "
- "and UTF-8 versions of RegExp \"%s\" vary: %d vs %d",
More information about the nginx-devel
mailing list