njs_vm_exception() is removed and combined with njs_vm_retval().
vm->exception is removed either, exceptions are now stored in
vm->retval. It simplifies the client logic, because previously
njs_vm_exception() had to be called if njs_vm_retval() fails.
Additonally, stack traces are now appended to the retval if an exception
happens.
}
if (njs_vm_call(ctx->vm, func, ctx->args, 2) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"js exception: %*s", exception.length, exception.start);
}
if (njs_vm_call(ctx->vm, func, ctx->args, 2) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"js exception: %*s", exception.length, exception.start);
rc = njs_vm_compile(jlcf->vm, &start, end);
if (rc != NJS_OK) {
- njs_vm_exception(jlcf->vm, &text);
+ njs_vm_retval(jlcf->vm, &text);
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%*s, included",
}
if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %*s",
exception.length, exception.start);
ctx->buf = in->buf;
if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %*s",
exception.length, exception.start);
}
if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
"js exception: %*s", exception.length, exception.start);
rc = njs_vm_compile(jscf->vm, &start, end);
if (rc != NJS_OK) {
- njs_vm_exception(jscf->vm, &text);
+ njs_vm_retval(jscf->vm, &text);
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%*s, included",
static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options);
static nxt_int_t njs_process_script(njs_vm_t *vm, njs_opts_t *opts,
const nxt_str_t *script, nxt_str_t *out);
-static void njs_print_backtrace(nxt_array_t *backtrace);
static nxt_int_t njs_editline_init(njs_vm_t *vm);
static char **njs_completion_handler(const char *text, int start, int end);
static char *njs_completion_generator(const char *text, int state);
static nxt_int_t
njs_interactive_shell(njs_opts_t *opts, njs_vm_opt_t *vm_options)
{
- njs_vm_t *vm;
- nxt_int_t ret;
- nxt_str_t line, out;
- nxt_array_t *backtrace;
+ njs_vm_t *vm;
+ nxt_int_t ret;
+ nxt_str_t line, out;
vm = njs_vm_create(vm_options);
if (vm == NULL) {
printf("%.*s\n", (int) out.length, out.start);
- backtrace = njs_vm_backtrace(vm);
- if (backtrace != NULL) {
- njs_print_backtrace(backtrace);
- }
-
/* editline allocs a new buffer every time. */
free(line.start);
}
nxt_int_t ret;
nxt_str_t out, script;
struct stat sb;
- nxt_array_t *backtrace;
file = opts->file;
if (!opts->disassemble) {
printf("%.*s\n", (int) out.length, out.start);
-
- backtrace = njs_vm_backtrace(vm);
- if (backtrace != NULL) {
- njs_print_backtrace(backtrace);
- }
}
ret = NXT_OK;
}
ret = njs_vm_run(vm);
-
- if (ret == NXT_OK) {
- if (njs_vm_retval(vm, out) != NXT_OK) {
- return NXT_ERROR;
- }
-
- } else {
- njs_vm_exception(vm, out);
+ if (ret == NXT_AGAIN) {
+ return ret;
}
+ }
- } else {
- njs_vm_exception(vm, out);
+ if (njs_vm_retval(vm, out) != NXT_OK) {
+ return NXT_ERROR;
}
return NXT_OK;
}
-static void
-njs_print_backtrace(nxt_array_t *backtrace)
-{
- nxt_uint_t i;
- njs_backtrace_entry_t *be;
-
- be = backtrace->start;
-
- for (i = 0; i < backtrace->items; i++) {
- if (be[i].line != 0) {
- printf("at %.*s (:%d)\n", (int) be[i].name.length, be[i].name.start,
- be[i].line);
-
- } else {
- printf("at %.*s\n", (int) be[i].name.length, be[i].name.start);
- }
- }
-}
-
-
static nxt_int_t
njs_editline_init(njs_vm_t *vm)
{
size_t size;
va_list args;
nxt_int_t ret;
- njs_value_t string, *value;
+ njs_value_t string;
njs_object_t *error;
static char buf[256];
goto memory_error;
}
- value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t));
- if (nxt_slow_path(value == NULL)) {
- goto memory_error;
- }
-
- value->data.u.object = error;
- value->type = type;
- value->data.truth = 1;
-
- vm->exception = value;
+ vm->retval.data.u.object = error;
+ vm->retval.type = type;
+ vm->retval.data.truth = 1;
return;
static void
-njs_init_memory_error(njs_vm_t *vm)
+njs_set_memory_error(njs_vm_t *vm)
{
- njs_value_t *value;
njs_object_t *object;
njs_object_prototype_t *prototypes;
*/
object->extensible = 0;
- value = &vm->memory_error;
-
- value->data.type = NJS_OBJECT_INTERNAL_ERROR;
- value->data.truth = 1;
- value->data.u.number = NAN;
- value->data.u.object = object;
+ vm->retval.data.type = NJS_OBJECT_INTERNAL_ERROR;
+ vm->retval.data.truth = 1;
+ vm->retval.data.u.number = NAN;
+ vm->retval.data.u.object = object;
}
void
njs_exception_memory_error(njs_vm_t *vm)
{
- njs_init_memory_error(vm);
-
- vm->exception = &vm->memory_error;
+ njs_set_memory_error(vm);
}
njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused)
{
- njs_init_memory_error(vm);
-
- vm->retval = vm->memory_error;
+ njs_set_memory_error(vm);
return NXT_OK;
}
njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
{
+ njs_exception_internal_error(vm, "Not implemented", NULL);
+
return NXT_ERROR;
}
}
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Illegal continue statement");
+ njs_parser_syntax_error(vm, parser, "Illegal continue statement", NULL);
return NXT_ERROR;
}
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Illegal break statement");
+ njs_parser_syntax_error(vm, parser, "Illegal break statement", NULL);
return NXT_ERROR;
#include <njs_string.h>
#include <njs_object.h>
#include <njs_function.h>
+#include <njs_error.h>
#include <njs_variable.h>
#include <njs_parser.h>
#include <njs_regexp.h>
break;
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR, "SyntaxError: "
- "The maximum function nesting level is \"%d\"",
- NJS_MAX_NESTING);
+ njs_parser_syntax_error(vm, parser,
+ "The maximum function nesting "
+ "level is \"%d\"", NJS_MAX_NESTING);
return NXT_ERROR;
}
}
}
- } else if (vm->exception == NULL) {
+ } else if (!njs_is_error(&vm->retval)) {
(void) njs_parser_unexpected_token(vm, parser, token);
}
scope = scope->parent)
{
if (scope->type == NJS_SCOPE_GLOBAL) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Illegal return statement");
+ njs_parser_syntax_error(vm, parser, "Illegal return statement",
+ NULL);
return NXT_ERROR;
}
} else {
if (dflt != NULL) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: More than one default clause "
- "in switch statement");
+ njs_parser_syntax_error(vm, parser,
+ "More than one default clause "
+ "in switch statement", NULL);
return NJS_TOKEN_ILLEGAL;
}
node = parser->node->left;
if (node->token != NJS_TOKEN_NAME) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR, "ReferenceError: Invalid "
- "left-hand side \"%.*s\" in for-in statement",
- (int) name->length, name->start);
+ njs_parser_ref_error(vm, parser, "Invalid left-hand side \"%.*s\" "
+ "in for-in statement", (int) name->length,
+ name->start);
return NJS_TOKEN_ILLEGAL;
}
}
if (try->right == NULL) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Missing catch or finally after try");
+ njs_parser_syntax_error(vm, parser, "Missing catch or "
+ "finally after try", NULL);
return NJS_TOKEN_ILLEGAL;
}
break;
case NJS_TOKEN_UNTERMINATED_STRING:
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Unterminated string \"%.*s\"",
- (int) parser->lexer->text.length, parser->lexer->text.start);
+ njs_parser_syntax_error(vm, parser, "Unterminated string \"%.*s\"",
+ (int) parser->lexer->text.length,
+ parser->lexer->text.start);
return NJS_TOKEN_ILLEGAL;
invalid:
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Invalid Unicode code point \"%.*s\"",
- (int) parser->lexer->text.length, parser->lexer->text.start);
+ njs_parser_syntax_error(vm, parser, "Invalid Unicode code point \"%.*s\"",
+ (int) parser->lexer->text.length,
+ parser->lexer->text.start);
return NJS_TOKEN_ILLEGAL;
}
njs_token_t token)
{
if (token != NJS_TOKEN_END) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Unexpected token \"%.*s\"",
- (int) parser->lexer->text.length, parser->lexer->text.start);
+ njs_parser_syntax_error(vm, parser, "Unexpected token \"%.*s\"",
+ (int) parser->lexer->text.length,
+ parser->lexer->text.start);
} else {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Unexpected end of input");
+ njs_parser_syntax_error(vm, parser, "Unexpected end of input", NULL);
}
return NJS_TOKEN_ILLEGAL;
njs_parser_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
u_char *start)
{
- int n;
u_char *p;
- ssize_t size;
+ size_t size;
njs_vm_t *vm;
- p = start;
-
- if (td->level == NXT_LEVEL_CRIT) {
- size = sizeof("InternalError: ") - 1;
- memcpy(p, "InternalError: ", size);
- p = start + size;
- }
+ size = sizeof("InternalError: ") - 1;
+ memcpy(start, "InternalError: ", size);
+ p = start + size;
vm = trace->data;
p = trace->handler(trace, td, p);
if (vm->parser != NULL) {
- size = td->end - start;
+ njs_exception_internal_error(vm, "%s in %u", start,
+ vm->parser->lexer->line);
+ } else {
+ njs_exception_internal_error(vm, "%s", start);
+ }
- n = snprintf((char *) p, size, " in %u", vm->parser->lexer->line);
+ return p;
+}
- if (n < size) {
- p += n;
- }
- }
- njs_vm_throw_exception(vm, start, p - start);
+void
+njs_parser_syntax_error(njs_vm_t *vm, njs_parser_t *parser, const char* fmt,
+ ...)
+{
+ va_list args;
- return p;
+ static char buf[256];
+
+ va_start(args, fmt);
+ (void) vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ njs_exception_syntax_error(vm, "%s in %u", buf, parser->lexer->line);
+}
+
+
+void
+njs_parser_ref_error(njs_vm_t *vm, njs_parser_t *parser, const char* fmt,
+ ...)
+{
+ va_list args;
+
+ static char buf[256];
+
+ va_start(args, fmt);
+ (void) vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ njs_exception_ref_error(vm, "%s in %u", buf, parser->lexer->line);
}
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);
+void njs_parser_syntax_error(njs_vm_t *vm, njs_parser_t *parser,
+ const char* fmt, ...);
+void njs_parser_ref_error(njs_vm_t *vm, njs_parser_t *parser, const char* fmt,
+ ...);
nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node);
}
if (!njs_parser_is_lvalue(parser->node)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: Invalid left-hand side in assignment");
+ njs_parser_ref_error(vm, parser,
+ "Invalid left-hand side in assignment", NULL);
return NJS_TOKEN_ILLEGAL;
}
}
if (!njs_parser_is_lvalue(parser->node)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: Invalid left-hand side in assignment");
+ njs_parser_ref_error(vm, parser, "Invalid left-hand side "
+ "in assignment", NULL);
return NJS_TOKEN_ILLEGAL;
}
}
if (next == NJS_TOKEN_EXPONENTIATION) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Either left-hand side or entire exponentiation "
- "must be parenthesized");
+ njs_parser_syntax_error(vm, parser, "Either left-hand side or entire "
+ "exponentiation must be parenthesized");
return NJS_TOKEN_ILLEGAL;
}
case NJS_TOKEN_NAME:
case NJS_TOKEN_UNDEFINED:
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Delete of an unqualified identifier");
+ njs_parser_syntax_error(vm, parser,
+ "Delete of an unqualified identifier", NULL);
return NJS_TOKEN_ILLEGAL;
}
if (!njs_parser_is_lvalue(parser->node)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: Invalid left-hand side in prefix operation");
+ njs_parser_ref_error(vm, parser, "Invalid left-hand side "
+ "in prefix operation", NULL);
return NJS_TOKEN_ILLEGAL;
}
}
if (!njs_parser_is_lvalue(parser->node)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: Invalid left-hand side in postfix operation");
+ njs_parser_ref_error(vm, parser, "Invalid left-hand side "
+ "in postfix operation", NULL);
return NJS_TOKEN_ILLEGAL;
}
flags = njs_regexp_flags(&p, lexer->end, 0);
if (nxt_slow_path(flags < 0)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Invalid RegExp flags \"%.*s\"",
- p - lexer->start, lexer->start);
+ njs_parser_syntax_error(vm, parser,
+ "Invalid RegExp flags \"%.*s\"",
+ p - lexer->start, lexer->start);
return NJS_TOKEN_ILLEGAL;
}
}
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Unterminated RegExp \"%.*s\"",
- p - lexer->start - 1, lexer->start - 1);
+ njs_parser_syntax_error(vm, parser, "Unterminated RegExp \"%.*s\"",
+ p - lexer->start - 1, lexer->start - 1);
return NJS_TOKEN_ILLEGAL;
}
njs_regexp_compile_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
u_char *start)
{
- int n;
u_char *p;
- ssize_t size;
+ size_t size;
njs_vm_t *vm;
size = sizeof("SyntaxError: ") - 1;
vm = trace->data;
trace = trace->next;
- p = trace->handler(trace, td, p);
+ p = trace->handler(trace, td, start);
if (vm->parser != NULL) {
- size = td->end - start;
-
- n = snprintf((char *) p, size, " in %u", vm->parser->lexer->line);
+ njs_exception_syntax_error(vm, "%s in %u", start,
+ vm->parser->lexer->line);
- if (n < size) {
- p += n;
- }
+ } else {
+ njs_exception_syntax_error(vm, "%s", start);
}
- njs_vm_throw_exception(vm, start, p - start);
-
return p;
}
size_t size;
njs_vm_t *vm;
- size = sizeof("RegExpError: ") - 1;
- memcpy(start, "RegExpError: ", size);
+ size = sizeof("InternalError: ") - 1;
+ memcpy(start, "InternalError: ", size);
p = start + size;
vm = trace->data;
trace = trace->next;
p = trace->handler(trace, td, p);
- njs_vm_throw_exception(vm, start, p - start);
+ njs_exception_internal_error(vm, (const char *) start, NULL);
return p;
}
#include <njs_vm.h>
#include <njs_variable.h>
#include <njs_parser.h>
+#include <njs_error.h>
#include <string.h>
/* ret == NXT_DECLINED. */
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Identifier \"%.*s\" has already been declared",
- (int) lhq.key.length, lhq.key.start);
+ njs_parser_syntax_error(vm, parser, "Identifier \"%.*s\" "
+ "has already been declared",
+ (int) lhq.key.length, lhq.key.start);
return NULL;
}
index = (index >> NJS_SCOPE_SHIFT) + 1;
if (index > 255 || vs.scope->argument_closures == 0) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "InternalError: too many argument closures");
+ njs_exception_internal_error(vm, "too many argument closures",
+ NULL);
return NULL;
}
not_found:
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: \"%.*s\" is not defined",
- (int) vs.lhq.key.length, vs.lhq.key.start);
+ njs_parser_ref_error(vm, vm->parser, "\"%.*s\" is not defined",
+ (int) vs.lhq.key.length, vs.lhq.key.start);
return NULL;
}
}
-void
-njs_vm_throw_exception(njs_vm_t *vm, const u_char *buf, uint32_t size)
-{
- int32_t length;
- njs_value_t *value;
-
- value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t));
-
- if (nxt_fast_path(value != NULL)) {
- vm->exception = value;
-
- length = nxt_utf8_length(buf, size);
- length = (length >= 0) ? length : 0;
-
- (void) njs_string_new(vm, value, buf, size, length);
- }
-}
-
-
static njs_ret_t
njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame)
{
njs_native_frame_t *top_frame;
njs_frame_t *active_frame;
- const njs_value_t *exception;
-
nxt_lvlhsh_t externals_hash;
nxt_lvlhsh_t variables_hash;
nxt_lvlhsh_t values_hash;
* with the generic type NJS_OBJECT_INTERNAL_ERROR but its own prototype
* object NJS_PROTOTYPE_MEMORY_ERROR.
*/
- njs_value_t memory_error;
njs_object_t memory_error_object;
nxt_array_t *code; /* of njs_vm_code_t */
const njs_value_t *src);
void njs_number_set(njs_value_t *value, double num);
-void njs_vm_throw_exception(njs_vm_t *vm, const 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);
nxt_int_t njs_builtin_match_native_function(njs_vm_t *vm,
#include <njs_parser.h>
#include <njs_regexp.h>
#include <string.h>
+#include <stdio.h>
static nxt_int_t njs_vm_init(njs_vm_t *vm);
if (nxt_slow_path(ret != NXT_OK)) {
return NULL;
}
+
+ vm->retval = njs_value_void;
}
}
parser->code_size = sizeof(njs_vmcode_stop_t);
parser->scope_offset = NJS_INDEX_GLOBAL_OFFSET;
+ if (vm->backtrace != NULL) {
+ nxt_array_reset(vm->backtrace);
+ }
+
node = njs_parser(vm, parser, prev);
if (nxt_slow_path(node == NULL)) {
goto fail;
*/
vm->code = NULL;
- if (vm->backtrace != NULL) {
- nxt_array_reset(vm->backtrace);
- }
-
ret = njs_generate_scope(vm, parser, node);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
goto fail;
}
+ nvm->retval = njs_value_void;
+
return nvm;
}
vm->backtrace = backtrace;
}
- vm->retval = njs_value_void;
-
vm->trace.level = NXT_LEVEL_TRACE;
vm->trace.size = 2048;
vm->trace.handler = njs_parser_trace_handler;
nxt_thread_log_debug("RUN:");
+ if (vm->backtrace != NULL) {
+ nxt_array_reset(vm->backtrace);
+ }
+
ret = njs_vmcode_interpreter(vm);
if (nxt_slow_path(ret == NXT_AGAIN)) {
nxt_int_t
njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval)
{
- return njs_value_to_ext_string(vm, retval, &vm->retval);
-}
+ u_char *p, *start;
+ size_t len;
+ nxt_int_t ret;
+ nxt_uint_t i;
+ nxt_array_t *backtrace;
+ njs_backtrace_entry_t *be;
+ if (vm->top_frame == NULL) {
+ /* An exception was thrown during compilation. */
+
+ njs_vm_init(vm);
+ }
+
+ ret = njs_value_to_ext_string(vm, retval, &vm->retval);
+
+ if (ret != NXT_OK) {
+ /* retval evaluation threw an exception. */
-nxt_int_t
-njs_vm_exception(njs_vm_t *vm, nxt_str_t *retval)
-{
- if (vm->top_frame != NULL) {
vm->top_frame->trap_tries = 0;
+
+ ret = njs_value_to_ext_string(vm, retval, &vm->retval);
+ if (ret != NXT_OK) {
+ return ret;
+ }
+ }
+
+ backtrace = njs_vm_backtrace(vm);
+
+ if (backtrace != NULL) {
+
+ len = retval->length + 1;
+
+ be = backtrace->start;
+
+ for (i = 0; i < backtrace->items; i++) {
+ if (be[i].line != 0) {
+ len += sizeof(" at (:)\n") - 1 + 10 + be[i].name.length;
+
+ } else {
+ len += sizeof(" at (native)\n") - 1 + be[i].name.length;
+ }
+ }
+
+ p = nxt_mem_cache_alloc(vm->mem_cache_pool, len);
+ if (p == NULL) {
+ return NXT_ERROR;
+ }
+
+ start = p;
+
+ p = nxt_cpymem(p, retval->start, retval->length);
+ *p++ = '\n';
+
+ for (i = 0; i < backtrace->items; i++) {
+ if (be[i].line != 0) {
+ p += sprintf((char *) p, " at %.*s (:%u)\n",
+ (int) be[i].name.length, be[i].name.start,
+ be[i].line);
+
+ } else {
+ p += sprintf((char *) p, " at %.*s (native)\n",
+ (int) be[i].name.length, be[i].name.start);
+ }
+ }
+
+ retval->start = start;
+ retval->length = p - retval->start;
}
- return njs_value_to_ext_string(vm, retval, vm->exception);
+ return NXT_OK;
}
NXT_EXPORT njs_ret_t njs_vm_return_string(njs_vm_t *vm, u_char *start,
size_t size);
NXT_EXPORT nxt_int_t njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval);
-NXT_EXPORT nxt_int_t njs_vm_exception(njs_vm_t *vm, nxt_str_t *retval);
NXT_EXPORT nxt_array_t *njs_vm_backtrace(njs_vm_t *vm);
NXT_EXPORT void njs_disassembler(njs_vm_t *vm);
return NXT_ERROR;
}
- if (njs_vm_run(nvm) == NXT_OK) {
- if (njs_vm_retval(nvm, &s) != NXT_OK) {
- return NXT_ERROR;
- }
+ (void) njs_vm_run(nvm);
- } else {
- njs_vm_exception(nvm, &s);
+ if (njs_vm_retval(nvm, &s) != NXT_OK) {
+ return NXT_ERROR;
}
success = nxt_strstr_eq(result, &s);
{"console.help()\r\n"
"console.help()\r\nVM built-in objects:"}
}
+
+# Exception in njs_vm_retval()
+njs_test {
+ {"var o = { toString: function() { return [1] } }\r\n"
+ "undefined\r\n>> "}
+ {"o\r\n"
+ "TypeError"}
+}
+
+# Backtraces are reset between invocations
+njs_test {
+ {"JSON.parse(Error())\r\n"
+ "JSON.parse(Error())\r\nSyntaxError: Unexpected token at position 0*at JSON.parse (native)"}
+ {"JSON.parse(Error()\r\n"
+ "JSON.parse(Error()\r\nSyntaxError: Unexpected token \"\" in 1"}
+}
"function f(o) {return ff(o)}" ENTER
"f({})" ENTER),
nxt_string("TypeError\n"
- "at ff (:1)\n"
- "at f (:1)\n"
- "at main\n") },
+ " at ff (:1)\n"
+ " at f (:1)\n"
+ " at main (native)\n") },
{ nxt_string("function ff(o) {return o.a.a}" ENTER
"function f(o) {try {return ff(o)} "
"finally {return o.a.a}}" ENTER
"f({})" ENTER),
nxt_string("TypeError\n"
- "at f (:1)\n"
- "at main\n") },
+ " at f (:1)\n"
+ " at main (native)\n") },
{ nxt_string("function f(ff, o) {return ff(o)}" ENTER
"f(function (o) {return o.a.a}, {})" ENTER),
nxt_string("TypeError\n"
- "at anonymous (:1)\n"
- "at f (:1)\n"
- "at main\n") },
+ " at anonymous (:1)\n"
+ " at f (:1)\n"
+ " at main (native)\n") },
{ nxt_string("'str'.replace(/t/g,"
" function(m) {return m.a.a})" ENTER),
nxt_string("TypeError\n"
- "at anonymous (:1)\n"
- "at String.prototype.replace\n"
- "at main\n") },
+ " at anonymous (:1)\n"
+ " at String.prototype.replace (native)\n"
+ " at main (native)\n") },
{ nxt_string("function f(o) {return Object.keys(o)}" ENTER
"f()" ENTER),
nxt_string("TypeError\n"
- "at Object.keys\n"
- "at f (:1)\n"
- "at main\n") },
+ " at Object.keys (native)\n"
+ " at f (:1)\n"
+ " at main (native)\n") },
{ nxt_string("String.fromCharCode(3.14)" ENTER),
nxt_string("RangeError\n"
- "at String.fromCharCode\n"
- "at main\n") },
+ " at String.fromCharCode (native)\n"
+ " at main (native)\n") },
{ nxt_string("Math.log({}.a.a)" ENTER),
nxt_string("TypeError\n"
- "at Math.log\n"
- "at main\n") },
+ " at Math.log (native)\n"
+ " at main (native)\n") },
{ nxt_string("function f(o) {function f_in(o) {return o.a.a};"
" return f_in(o)}; f({})" ENTER),
nxt_string("TypeError\n"
- "at f_in (:1)\n"
- "at f (:1)\n"
- "at main\n") },
+ " at f_in (:1)\n"
+ " at f (:1)\n"
+ " at main (native)\n") },
{ nxt_string("function f(o) {var ff = function (o) {return o.a.a};"
" return ff(o)}; f({})" ENTER),
nxt_string("TypeError\n"
- "at anonymous (:1)\n"
- "at f (:1)\n"
- "at main\n") },
+ " at anonymous (:1)\n"
+ " at f (:1)\n"
+ " at main (native)\n") },
-};
+ /* Exception in njs_vm_retval() */
+ { nxt_string("var o = { toString: function() { return [1] } }" ENTER
+ "o" ENTER),
+ nxt_string("TypeError\n"
+ "at main\n") },
-static void njs_report_backtrace(nxt_array_t *backtrace, nxt_str_t *s);
+};
static nxt_int_t
nxt_str_t s;
nxt_uint_t i;
nxt_bool_t success;
- nxt_array_t *backtrace;
njs_vm_opt_t options;
nxt_mem_cache_pool_t *mcp;
njs_interactive_test_t *test;
}
}
- if (ret == NXT_OK) {
- if (njs_vm_retval(vm, &s) != NXT_OK) {
- goto fail;
- }
-
- } else {
- njs_vm_exception(vm, &s);
-
- backtrace = njs_vm_backtrace(vm);
- if (backtrace != NULL) {
- njs_report_backtrace(backtrace, &s);
- }
+ if (njs_vm_retval(vm, &s) != NXT_OK) {
+ return NXT_ERROR;
}
success = nxt_strstr_eq(&test->ret, &s);
}
-static void
-njs_report_backtrace(nxt_array_t *backtrace, nxt_str_t *s)
-{
- char *p;
- nxt_uint_t i;
- njs_backtrace_entry_t *be;
-
- static char buf[4096];
-
- p = buf + sprintf(buf, "%.*s\n", (int) s->length, s->start);
-
- be = backtrace->start;
- for (i = 0; i < backtrace->items; i++) {
- if (be[i].line != 0) {
- p += sprintf(p, "at %.*s (:%d)\n", (int) be[i].name.length,
- be[i].name.start, be[i].line);
-
- } else {
- p += sprintf(p, "at %.*s\n", (int) be[i].name.length,
- be[i].name.start);
- }
- }
-
- s->length = strlen(buf);
- s->start = (u_char *) buf;
-}
-
-
int nxt_cdecl
main(int argc, char **argv)
{
{ nxt_string("function f() { return 1\n 2 } f()"),
nxt_string("1") },
+ { nxt_string("function f() { return 1\n 2 } f()"),
+ nxt_string("1") },
+
{ nxt_string("function f(a) { if (a) return 'OK' } f(1)+f(0)"),
nxt_string("OKundefined") },
{ nxt_string("function x(a) { while (a < 2) a++; return a + 1 } x(1) "),
nxt_string("3") },
+ { nxt_string("(function(){(function(){(function(){(function(){"
+ "(function(){(function(){(function(){})})})})})})})"),
+ nxt_string("SyntaxError: The maximum function nesting level is \"5\" in 1") },
+
/* Recursive factorial. */
{ nxt_string("function f(a) {"
/* Exceptions. */
{ nxt_string("throw null"),
- nxt_string("") },
+ nxt_string("null") },
{ nxt_string("var a; try { throw null } catch (e) { a = e } a"),
nxt_string("null") },
{ nxt_string("var a; try { throw Error('e') } catch (e) { a = e.message } a"),
nxt_string("e") },
+ { nxt_string("var a; try { NaN.toString(NaN) } catch (e) { a = e.name } a"),
+ nxt_string("RangeError") },
+
{ nxt_string("try { throw null } catch (e) { throw e }"),
- nxt_string("") },
+ nxt_string("null") },
+
+ { nxt_string("try { throw Error('e') } catch (e) { throw Error(e.message + '2') }"),
+ nxt_string("Error: e2") },
{ nxt_string("try { throw null } catch (null) { throw e }"),
nxt_string("SyntaxError: Unexpected token \"null\" in 1") },
{ nxt_string("var a = 0; try { throw 3 }"
"catch (e) { throw e + 1 } finally { a++ }"),
- nxt_string("") },
+ nxt_string("4") },
{ nxt_string("var a = 0; try { throw 3 }"
"catch (e) { a = e } finally { throw a }"),
- nxt_string("") },
+ nxt_string("3") },
{ nxt_string("try { throw null } catch (e) { } finally { }"),
nxt_string("undefined") },
{ nxt_string("var a = 0; try { throw 3 }"
"catch (e) { throw 4 } finally { throw a }"),
- nxt_string("") },
+ nxt_string("0") },
{ nxt_string("var a = 0; try { a = 5 } finally { a++ } a"),
nxt_string("6") },
{ nxt_string("var a = 0; try { throw 5 } finally { a++ }"),
- nxt_string("") },
+ nxt_string("5") },
{ nxt_string("var a = 0; try { a = 5 } finally { throw 7 }"),
- nxt_string("") },
+ nxt_string("7") },
{ nxt_string("function f(a) {"
" if (a > 1) return f(a - 1);"
{ nxt_string("var o = { toString: function() { return 'OK' } }; 'o:' + o"),
nxt_string("o:OK") },
+ { nxt_string("var o = { toString: function() { return [1] } }; o"),
+ nxt_string("TypeError") },
+
{ nxt_string("var o = { toString: function() { return [1] } }; 'o:' + o"),
nxt_string("TypeError") },
nxt_string("true") },
{ nxt_string("eval()"),
- nxt_string("") },
+ nxt_string("InternalError: Not implemented") },
/* Math. */
ret = njs_vm_run(nvm);
- if (ret == NXT_OK) {
- if (njs_vm_retval(nvm, &s) != NXT_OK) {
- return NXT_ERROR;
- }
-
- } else {
- njs_vm_exception(nvm, &s);
+ if (njs_vm_retval(nvm, &s) != NXT_OK) {
+ return NXT_ERROR;
}
} else {
- njs_vm_exception(vm, &s);
+ if (njs_vm_retval(vm, &s) != NXT_OK) {
+ return NXT_ERROR;
+ }
+
nvm = NULL;
}