#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>
#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,
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 };
{
njs_vmcode_jump_t *jump;
njs_parser_patch_t *patch;
+ njs_parser_block_t *block;
- if (parser->block == NULL) {
- vm->exception = &njs_exception_syntax_error;
- return NXT_ERROR;
+ for (block = parser->block; block != NULL; block = block->next) {
+ if (block->type == NJS_PARSER_LOOP) {
+ goto found;
+ }
}
- /* TODO: LABEL */
+ return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE);
- if (parser->block->type != NJS_PARSER_LOOP) {
- vm->exception = &njs_exception_syntax_error;
- return NXT_ERROR;
- }
+found:
+
+ /* TODO: LABEL */
patch = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_patch_t));
{
njs_vmcode_jump_t *jump;
njs_parser_patch_t *patch;
+ njs_parser_block_t *block;
- if (parser->block == NULL) {
- vm->exception = &njs_exception_syntax_error;
- return NXT_ERROR;
+ 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));
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);
+}
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,
njs_token_t token;
const njs_lexer_multi_t *multi;
+ lexer->text.data = lexer->start;
+
while (lexer->start < lexer->end) {
c = *lexer->start++;
switch (token) {
case NJS_TOKEN_SPACE:
+ lexer->text.data = lexer->start;
continue;
case NJS_TOKEN_LETTER:
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:
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 */
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;
if (c == '\\') {
if (p == lexer->end) {
- return NJS_TOKEN_ILLEGAL;
+ break;
}
p++;
}
}
- return NJS_TOKEN_ILLEGAL;
+ lexer->text.data--;
+ lexer->text.len = p - lexer->text.data;
+
+ return NJS_TOKEN_UNTERMINATED_STRING;
}
lexer->start++;
if (multi->count == 0) {
- return multi->token;
+ token = multi->token;
+ break;
}
return njs_lexer_multi(lexer, multi->token, multi->count,
} while (n != 0);
}
+ lexer->text.len = lexer->start - lexer->text.data;
+
return token;
}
#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>
#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>
/*
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);
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 *
}
} else if (vm->exception == NULL) {
- vm->exception = &njs_exception_syntax_error;
+ (void) njs_parser_unexpected_token(vm, parser, token);
}
return token;
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);
}
}
if (token != NJS_TOKEN_NAME) {
- return NJS_TOKEN_ERROR;
+ return NJS_TOKEN_ILLEGAL;
}
var = njs_parser_variable(vm, parser, &level);
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;
}
}
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;
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;
}
} else {
if (dflt != NULL) {
- /* A duplicate "default" branch. */
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_duplicate_default_branch(vm, parser);
}
branch = node;
*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;
}
}
+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)
{
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;
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;
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)) {
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;
}
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;
}
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;
}
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;
}
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;
}
}
node->token = NJS_TOKEN_CONTINUE;
+ node->token_line = parser->lexer->token_line;
parser->node = node;
parser->code_size += sizeof(njs_vmcode_jump_t);
}
node->token = NJS_TOKEN_BREAK;
+ node->token_line = parser->lexer->token_line;
parser->node = node;
parser->code_size += sizeof(njs_vmcode_jump_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;
}
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;
}
if (try->right == NULL) {
- /* TODO: message */
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_missing_catch_or_finally(vm, parser);
}
parser->node = try;
}
+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)
{
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;
}
return token;
}
- return njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
+ return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
}
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) {
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);
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);
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;
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;
}
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;
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++;
}
if (hex_length == 0 || hex_length > 6) {
- return NJS_TOKEN_ILLEGAL;
+ return njs_parser_error(vm, parser,
+ NJS_PARSER_ERROR_UNICODE);
}
skip = 1;
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;
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;
+}
#define NJS_TOKEN_LAST_CONST NJS_TOKEN_STRING
NJS_TOKEN_ESCAPE_STRING,
+ NJS_TOKEN_UNTERMINATED_STRING,
NJS_TOKEN_NAME,
NJS_TOKEN_OBJECT,
uint8_t property; /* 1 bit */
uint32_t key_hash;
+ uint32_t token_line;
+ uint32_t line;
+
nxt_str_t text;
double number;
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;
};
+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);
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);
#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>
#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 {
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
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;
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;
}
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);
}
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);
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;
+
+}
#include <njs_object_hash.h>
#include <njs_array.h>
#include <njs_function.h>
-#include <njs_regexp.h>
-#include <njs_regexp_pattern.h>
#include <njs_variable.h>
#include <njs_parser.h>
+#include <njs_regexp.h>
+#include <njs_regexp_pattern.h>
#include <string.h>
+#include <stdio.h>
static void *njs_regexp_malloc(size_t size, void *memory_data);
}
-nxt_int_t
+njs_token_t
njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value)
{
u_char *p;
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;
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);
}
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;
*start = p;
return flags;
+
+invalid:
+
+ *start = p + 1;
+
+ return NJS_REGEXP_INVALID_FLAG;
}
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",
- &pattern->source[1], pattern->ncaptures, ret);
-
+ vm->exception = &njs_exception_internal_error;
nxt_mem_cache_free(vm->mem_cache_pool, pattern);
return NULL;
}
njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source,
int options)
{
+ uint32_t size;
nxt_int_t ret;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
/* Zero length means a zero-terminated string. */
ret = nxt_regex_compile(regex, source, 0, options, vm->regex_context);
return regex->ncaptures;
}
- return njs_string_exception(vm, NJS_SYNTAX_ERROR, vm->regex_context->error);
+ if (vm->parser != NULL) {
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ "SyntaxError: %s in %u",
+ vm->regex_context->error, vm->parser->lexer->line);
+
+ } else {
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ "SyntaxError: %s", vm->regex_context->error);
+ }
+
+ return njs_vm_throw_exception(vm, buf, size);
}
retval = &njs_value_true;
} else if (ret != NGX_REGEX_NOMATCH) {
- return njs_string_exception(vm, NJS_INTERNAL_ERROR,
- vm->regex_context->error);
+ return njs_regexp_match_error(vm);
}
}
if (nxt_slow_path(ret != NGX_REGEX_NOMATCH)) {
nxt_regex_match_data_free(match_data, vm->regex_context);
- return njs_string_exception(vm, NJS_INTERNAL_ERROR,
- vm->regex_context->error);
+ return njs_regexp_match_error(vm);
}
}
}
vm->exception = &njs_exception_internal_error;
+
return NXT_ERROR;
}
+njs_ret_t
+njs_regexp_match_error(njs_vm_t *vm)
+{
+ uint32_t size;
+ u_char buf[NJS_EXCEPTION_BUF_LENGTH];
+
+ size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
+ "RegExpError: %s", vm->regex_context->error);
+
+ return njs_vm_throw_exception(vm, buf, size);
+}
+
+
static const njs_object_prop_t njs_regexp_constructor_properties[] =
{
/* RegExp.name == "RegExp". */
njs_ret_t njs_regexp_init(njs_vm_t *vm);
njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused);
-nxt_int_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser,
+njs_token_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser,
njs_value_t *value);
njs_regexp_pattern_t *njs_regexp_pattern_create(njs_vm_t *vm,
u_char *string, size_t length, njs_regexp_flags_t flags);
njs_regexp_t *njs_regexp_alloc(njs_vm_t *vm, njs_regexp_pattern_t *pattern);
njs_ret_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused);
+njs_ret_t njs_regexp_match_error(njs_vm_t *vm);
extern const njs_object_init_t njs_regexp_constructor_init;
#include <njs_object_hash.h>
#include <njs_array.h>
#include <njs_function.h>
-#include <njs_regexp.h>
-#include <njs_regexp_pattern.h>
#include <njs_variable.h>
#include <njs_parser.h>
+#include <njs_regexp.h>
+#include <njs_regexp_pattern.h>
#include <string.h>
+#include <stdio.h>
static nxt_noinline void njs_string_slice_prop(njs_string_prop_t *string,
index = njs_string_index(&string, captures[0]);
} else if (ret != NGX_REGEX_NOMATCH) {
- return njs_string_exception(vm, NJS_INTERNAL_ERROR,
- vm->regex_context->error);
+ return njs_regexp_match_error(vm);
}
}
}
break;
} else {
- return njs_string_exception(vm, NJS_INTERNAL_ERROR,
- vm->regex_context->error);
+ return njs_regexp_match_error(vm);
}
} while (string.size > 0);
next = (u_char *) end + 1;
} else {
- return njs_string_exception(vm, NJS_INTERNAL_ERROR,
- vm->regex_context->error);
+ return njs_regexp_match_error(vm);
}
/* Empty split regexp. */
return (njs_index_t) value;
}
-
-
-nxt_int_t
-njs_string_exception(njs_vm_t *vm, njs_exception_error_t exception, u_char *msg)
-{
- u_char *p, *start;
- uint32_t msg_length, size, length;
- nxt_str_t *error;
- njs_value_t *value;
-
- static nxt_str_t errors[] = {
- nxt_string("SyntaxError: "),
- nxt_string("InternalError: "),
- };
-
- value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t));
- if (nxt_slow_path(value == NULL)) {
- return NXT_ERROR;
- }
-
- error = &errors[exception];
-
- msg_length = (msg != NULL) ? strlen((char *) msg) : 0;
- length = nxt_utf8_length(msg, msg_length);
-
- size = error->len + msg_length;
- length += error->len;
-
- start = njs_string_alloc(vm, value, size, length);
-
- if (nxt_fast_path(start != NULL)) {
- memcpy(start, error->data, error->len);
- p = start + error->len;
-
- memcpy(p, msg, msg_length);
-
- if (size != length && length >= NJS_STRING_MAP_OFFSET) {
- njs_string_offset_map_init(start, size);
- }
- }
-
- vm->exception = value;
-
- return NXT_ERROR;
-}
-
njs_index_t njs_value_index(njs_vm_t *vm, njs_parser_t *parser,
const njs_value_t *src);
-nxt_int_t njs_string_exception(njs_vm_t *vm, njs_exception_error_t exception,
- u_char *msg);
extern const njs_object_init_t njs_string_constructor_init;
extern const njs_object_init_t njs_string_prototype_init;
#include <nxt_clang.h>
#include <nxt_alignment.h>
#include <nxt_stub.h>
+#include <nxt_utf8.h>
#include <nxt_djb_hash.h>
#include <nxt_array.h>
#include <nxt_lvlhsh.h>
#include <njs_object_hash.h>
#include <njs_array.h>
#include <njs_function.h>
-#include <njs_regexp.h>
#include <njs_extern.h>
#include <njs_variable.h>
#include <njs_parser.h>
+#include <njs_regexp.h>
#include <string.h>
}
+njs_ret_t
+njs_vm_throw_exception(njs_vm_t *vm, u_char *buf, uint32_t size)
+{
+ uint32_t length;
+ njs_value_t *value;
+
+ value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t));
+ if (nxt_slow_path(value == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
+
+ vm->exception = value;
+
+ length = nxt_utf8_length(buf, size);
+
+ (void) njs_string_new(vm, value, buf, size, length);
+
+ return NXT_ERROR;
+}
+
+
void
njs_debug(njs_index_t index, njs_value_t *value)
{
};
-typedef enum {
- NJS_SYNTAX_ERROR = 0,
- NJS_INTERNAL_ERROR,
-} njs_exception_error_t;
+#define NJS_EXCEPTION_BUF_LENGTH 2048
nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm);
const njs_value_t *src);
void njs_number_set(njs_value_t *value, double num);
+njs_ret_t njs_vm_throw_exception(njs_vm_t *vm, u_char *buf, uint32_t size);
+
nxt_int_t njs_builtin_objects_create(njs_vm_t *vm);
nxt_int_t njs_builtin_objects_clone(njs_vm_t *vm);
#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>
parser->lexer = lexer;
lexer->start = *start;
lexer->end = end;
+ lexer->line = 1;
lexer->keywords_hash = vm->shared->keywords_hash;
parser->code_size = sizeof(njs_vmcode_stop_t);
nxt_string("undefined") },
{ nxt_string("var; a"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected token \";\" in 1") },
+
+ { nxt_string("var + a"),
+ nxt_string("SyntaxError: Unexpected token \"+\" in 1") },
{ nxt_string("var \n a \n = 1; a"),
nxt_string("1") },
nxt_string("1") },
{ nxt_string("a = 0; a \n ++"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected end of input in 2") },
{ nxt_string("a = 1 ? 2 \n : 3"),
nxt_string("2") },
nxt_string("NaN undefined") },
{ nxt_string("var a += 1"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected token \"+=\" in 1") },
{ nxt_string("var a = a + 1"),
nxt_string("undefined") },
{ nxt_string("var a = 3; if (true) if (false); else; a = 2; a"),
nxt_string("2") },
+ /* do while. */
+
+ { nxt_string("do { break } if (false)"),
+ nxt_string("SyntaxError: Unexpected token \"if\" in 1") },
+
+ /* for in. */
+
+ { nxt_string("for (null in undefined);"),
+ nxt_string("ReferenceError: Invalid left-hand side \"null\" in for-in statement in 1") },
+
/* switch. */
{ nxt_string("switch"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected end of input in 1") },
{ nxt_string("switch (1);"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected token \";\" in 1") },
+
+ { nxt_string("switch (1) { do { } while (1) }"),
+ nxt_string("SyntaxError: Unexpected token \"do\" in 1") },
{ nxt_string("switch (1) {}"),
nxt_string("undefined") },
{ nxt_string("switch (1) {default:;}"),
nxt_string("undefined") },
+ { nxt_string("switch (1) {default:; default:}"),
+ nxt_string("SyntaxError: More than one default clause in switch statement in 1") },
+
{ nxt_string("switch (1) {case 0:;}"),
nxt_string("undefined") },
/* continue. */
{ nxt_string("continue"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Illegal continue statement in 1") },
{ nxt_string("do continue while (false)"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected token \"while\" in 1") },
{ nxt_string("do continue; while (false)"),
nxt_string("undefined") },
/* break. */
{ nxt_string("break"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Illegal break statement in 1") },
{ nxt_string("do break while (true)"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected token \"while\" in 1") },
{ nxt_string("do break; while (true)"),
nxt_string("undefined") },
{ nxt_string("void 0"),
nxt_string("undefined") },
+ { nxt_string("null = 1"),
+ nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") },
+
{ nxt_string("undefined = 1"),
- nxt_string("SyntaxError") },
+ nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") },
+
+ { nxt_string("null++"),
+ nxt_string("ReferenceError: Invalid left-hand side in postfix operation 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("1 undefined") },
{ nxt_string("var y = 5; x = { a:y }; x.a"),
nxt_string("5") },
+ { nxt_string("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("3 * [5,7]"),
nxt_string("NaN") },
-
{ nxt_string("a = [ 1, 2, 3 ]; a[0] + a[1] + a[2]"),
nxt_string("6") },
+ { nxt_string("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("1 2 3 undefined") },
{ nxt_string("'a\\\r\nb'"),
nxt_string("ab") },
+ { nxt_string("'abcde"),
+ nxt_string("SyntaxError: Unterminated string \"'abcde\" in 1") },
+
+ { nxt_string("'\\"),
+ nxt_string("SyntaxError: Unterminated string \"'\\\" in 1") },
+
{ nxt_string("'\\'"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unterminated string \"'\\'\" in 1") },
{ nxt_string("'\\u03B1'"),
nxt_string("α") },
{ nxt_string("'\\u'"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Invalid Unicode code point \"\\u\" in 1") },
{ nxt_string("'\\u03B'"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Invalid Unicode code point \"\\u03B\" in 1") },
{ nxt_string("'\\u{61}\\u{3B1}\\u{20AC}'"),
nxt_string("aα€") },
{ nxt_string("'\\u'"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Invalid Unicode code point \"\\u\" in 1") },
{ nxt_string("'\\u{'"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Invalid Unicode code point \"\\u{\" in 1") },
{ nxt_string("'\\u{}'"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Invalid Unicode code point \"\\u{}\" in 1") },
{ nxt_string("'\\u{1234567}'"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Invalid Unicode code point \"\\u{1234567}\" in 1") },
{ nxt_string("'\\x61'"),
nxt_string("a") },
nxt_string("NaN") },
{ nxt_string("a = 'abcdef'; a.3"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected token \"3\" in 1") },
{ nxt_string("'abcdef'[3]"),
nxt_string("d") },
/* Functions. */
+ { nxt_string("function () { } f()"),
+ nxt_string("SyntaxError: Unexpected token \"(\" in 1") },
+
{ nxt_string("function f() { } f()"),
nxt_string("undefined") },
nxt_string("20") },
{ nxt_string("var f = function b(a) { a *= 2; return a } = 5"),
- nxt_string("SyntaxError") },
+ nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") },
{ nxt_string("function a() { return { x:2} }; var b = a(); b.x"),
nxt_string("2") },
nxt_string("3") },
{ nxt_string("var a = 0, function(a) { return a + 1 }(2); a"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected token \"function\" in 1") },
{ nxt_string("var a = (0, function(a) { return a + 1 }(2)); a"),
nxt_string("3") },
/* RegExp. */
+ { nxt_string("/./x"),
+ nxt_string("SyntaxError: Invalid RegExp flags \"x\" in 1") },
+
+ { nxt_string("/"),
+ nxt_string("SyntaxError: Unterminated RegExp \"/\" in 1") },
+
{ nxt_string("/(/.test('')"),
- nxt_string("SyntaxError: pcre_compile(\"(\") failed: missing )") },
+ nxt_string("SyntaxError: pcre_compile(\"(\") failed: missing ) in 1") },
{ nxt_string("/^$/.test('')"),
nxt_string("true") },
{ nxt_string("try { throw null } catch (e) { throw e }"),
nxt_string("") },
+ { nxt_string("try { throw null } catch (null) { throw e }"),
+ nxt_string("SyntaxError: Unexpected token \"null\" in 1") },
+
+ { nxt_string("try {}"),
+ nxt_string("SyntaxError: Missing catch or finally after try in 1") },
+
{ nxt_string("var a = 0; try { a = 5 }"
"catch (e) { a = 9 } finally { a++ } a"),
nxt_string("6") },
/* es5id: 8.2_A2 */
{ nxt_string("var null;"),
- nxt_string("SyntaxError") },
+ nxt_string("SyntaxError: Unexpected token \"null\" in 1") },
/* es5id: 8.2_A3 */