[njs] nxt_trace interface. nxt_regex, RegExp, and parser use it ...

Igor Sysoev igor at sysoev.ru
Thu Aug 4 13:06:21 UTC 2016


details:   http://hg.nginx.org/njs/rev/23598cfcfd15
branches:  
changeset: 140:23598cfcfd15
user:      Igor Sysoev <igor at sysoev.ru>
date:      Thu Aug 04 16:05:38 2016 +0300
description:
nxt_trace interface. nxt_regex, RegExp, and parser use it now.

diffstat:

 Makefile                    |    2 +
 njs/njs_generator.c         |   41 ++---------
 njs/njs_parser.c            |  158 +++++++++++++++++++------------------------
 njs/njs_parser.h            |   14 +---
 njs/njs_parser_expression.c |   37 +++------
 njs/njs_regexp.c            |  136 +++++++++++++++++++++++++++----------
 njs/njs_regexp.h            |    3 +-
 njs/njs_string.c            |   19 ++--
 njs/njs_variable.c          |    4 +-
 njs/njs_vm.c                |   19 ++---
 njs/njs_vm.h                |    7 +-
 njs/njscript.c              |   10 ++
 njs/test/njs_unit_test.c    |    3 +
 nxt/Makefile                |   15 ++++
 nxt/nxt_clang.h             |    1 +
 nxt/nxt_pcre.c              |   63 ++++-------------
 nxt/nxt_regex.h             |    2 +-
 17 files changed, 263 insertions(+), 271 deletions(-)

diffs (truncated from 1095 to 1000 lines):

diff -r 016339472304 -r 23598cfcfd15 Makefile
--- a/Makefile	Thu Aug 04 14:45:27 2016 +0300
+++ b/Makefile	Thu Aug 04 16:05:38 2016 +0300
@@ -169,6 +169,7 @@ dist:
 	njs/njs_object_hash.h \
 	njs/njs_array.h \
 	njs/njs_function.h \
+	njs/njs_regexp.h \
 	njs/njs_parser.h \
 	njs/njs_string.c \
 
@@ -404,6 +405,7 @@ dist:
 		-I$(NXT_LIB) -Injs \
 		njs/test/njs_unit_test.c \
 		$(NXT_BUILDDIR)/libnjs.a \
+		$(NXT_BUILDDIR)/libnxt.a \
 		-lm $(NXT_PCRE_LIB)
 
 include $(NXT_LIB)/Makefile
diff -r 016339472304 -r 23598cfcfd15 njs/njs_generator.c
--- a/njs/njs_generator.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_generator.c	Thu Aug 04 16:05:38 2016 +0300
@@ -21,13 +21,6 @@
 #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,
@@ -125,8 +118,6 @@ 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 };
@@ -1085,7 +1076,10 @@ njs_generate_continue_statement(njs_vm_t
         }
     }
 
-    return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE);
+    nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+              "SyntaxError: Illegal continue statement");
+
+    return NXT_ERROR;
 
 found:
 
@@ -1126,7 +1120,10 @@ njs_generate_break_statement(njs_vm_t *v
         }
     }
 
-    return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_BREAK);
+    nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+              "SyntaxError: Illegal break statement");
+
+    return NXT_ERROR;
 
 found:
 
@@ -2476,25 +2473,3 @@ 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 016339472304 -r 23598cfcfd15 njs/njs_parser.c
--- a/njs/njs_parser.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_parser.c	Thu Aug 04 16:05:38 2016 +0300
@@ -54,8 +54,6 @@ 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,
@@ -68,8 +66,6 @@ static njs_token_t njs_parser_continue_s
 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);
@@ -844,7 +840,11 @@ njs_parser_switch_statement(njs_vm_t *vm
 
                } else {
                     if (dflt != NULL) {
-                        return njs_parser_duplicate_default_branch(vm, parser);
+                        nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                                  "SyntaxError: More than one default clause "
+                                  "in switch statement");
+
+                        return NJS_TOKEN_ILLEGAL;
                     }
 
                     branch = node;
@@ -890,22 +890,6 @@ 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;
@@ -1099,19 +1083,14 @@ static njs_token_t
 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->length, name->start, parser->lexer->line);
-
-        (void) njs_vm_throw_exception(vm, buf, size);
+        nxt_alert(&vm->trace, NXT_LEVEL_ERROR, "ReferenceError: Invalid "
+                  "left-hand side \"%.*s\" in for-in statement",
+                  (int) name->length, name->start);
 
         return NJS_TOKEN_ILLEGAL;
     }
@@ -1326,29 +1305,15 @@ njs_parser_try_statement(njs_vm_t *vm, n
     }
 
     if (try->right == NULL) {
-        return njs_parser_missing_catch_or_finally(vm, parser);
+        nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                  "SyntaxError: Missing catch or finally after try");
+
+        return NJS_TOKEN_ILLEGAL;
     }
 
     parser->node = try;
 
     return token;
-
-}
-
-
-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;
 }
 
 
@@ -1612,8 +1577,11 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa
         break;
 
     case NJS_TOKEN_UNTERMINATED_STRING:
-        return njs_parser_error(vm, parser,
-                                NJS_PARSER_ERROR_UNTERMINATED_STRING);
+        nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                  "SyntaxError: Unterminated string \"%.*s\"",
+                  (int) parser->lexer->text.length, parser->lexer->text.start);
+
+        return NJS_TOKEN_ILLEGAL;
 
     case NJS_TOKEN_NUMBER:
         nxt_thread_log_debug("JS: %f", parser->lexer->number);
@@ -2042,8 +2010,7 @@ njs_parser_escape_string_create(njs_vm_t
                         }
 
                         if (hex_length == 0 || hex_length > 6) {
-                            return njs_parser_error(vm, parser,
-                                                    NJS_PARSER_ERROR_UNICODE);
+                            goto invalid;
                         }
 
                         skip = 1;
@@ -2118,12 +2085,12 @@ njs_parser_escape_string_create(njs_vm_t
             hex_end = src + hex_length;
 
             if (hex_end > end) {
-                return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE);
+                goto invalid;
             }
 
             u = njs_number_radix_parse(src, hex_end, 16, 1);
             if (nxt_slow_path(u < 0)) {
-                return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE);
+                goto invalid;
             }
 
             src = hex_end + skip;
@@ -2150,6 +2117,14 @@ njs_parser_escape_string_create(njs_vm_t
 
         dst = start;
     }
+
+invalid:
+
+    nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+              "SyntaxError: Invalid Unicode code point \"%.*s\"",
+              (int) parser->lexer->text.length, parser->lexer->text.start);
+
+    return NJS_TOKEN_ILLEGAL;
 }
 
 
@@ -2208,48 +2183,53 @@ 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);
+        nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                  "SyntaxError: 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");
     }
 
-    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)
+u_char *
+njs_parser_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
+    u_char *start)
 {
-    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",
-        "SyntaxError: Duplicate declaration \"%.*s\" in %u",
-    };
-
-    msg = errors[err];
-    lexer = parser->lexer;
-
-    size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
-                    msg, (int) lexer->text.length, lexer->text.start,
-                    lexer->line);
-
-    (void) njs_vm_throw_exception(vm, buf, size);
-
-    return NJS_TOKEN_ILLEGAL;
+    int       n;
+    u_char    *p;
+    ssize_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;
+    }
+
+    vm = trace->data;
+
+    trace = trace->next;
+    p = trace->handler(trace, td, p);
+
+    if (vm->parser != NULL) {
+        size = td->end - start;
+
+        n = snprintf((char *) p, size, " in %u", vm->parser->lexer->line);
+
+        if (n < size) {
+            p += n;
+        }
+    }
+
+    njs_vm_throw_exception(vm, start, p - start);
+
+    return p;
 }
diff -r 016339472304 -r 23598cfcfd15 njs/njs_parser.h
--- a/njs/njs_parser.h	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_parser.h	Thu Aug 04 16:05:38 2016 +0300
@@ -314,16 +314,6 @@ 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_DUPLICATE_DECLARATION,
-} 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);
@@ -350,8 +340,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);
+u_char *njs_parser_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
+    u_char *start);
 nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node);
 
diff -r 016339472304 -r 23598cfcfd15 njs/njs_parser_expression.c
--- a/njs/njs_parser_expression.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_parser_expression.c	Thu Aug 04 16:05:38 2016 +0300
@@ -24,7 +24,6 @@
 #include <njs_variable.h>
 #include <njs_parser.h>
 #include <string.h>
-#include <stdio.h>
 
 
 typedef struct {
@@ -75,8 +74,6 @@ 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
@@ -294,7 +291,9 @@ njs_parser_var_expression(njs_vm_t *vm, 
         node = parser->node;
 
         if (parser->node->token != NJS_TOKEN_NAME) {
-            return njs_parser_invalid_lvalue(vm, parser, "assignment");
+            nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                      "ReferenceError: Invalid left-hand side in assignment");
+            return NJS_TOKEN_ILLEGAL;
         }
 
         pending = NULL;
@@ -439,7 +438,9 @@ njs_parser_assignment_expression(njs_vm_
         node = parser->node;
 
         if (!njs_parser_is_lvalue(parser->node)) {
-            return njs_parser_invalid_lvalue(vm, parser, "assignment");
+            nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                      "ReferenceError: Invalid left-hand side in assignment");
+            return NJS_TOKEN_ILLEGAL;
         }
 
         pending = NULL;
@@ -811,7 +812,9 @@ njs_parser_inc_dec_expression(njs_vm_t *
     }
 
     if (!njs_parser_is_lvalue(parser->node)) {
-        return njs_parser_invalid_lvalue(vm, parser, "prefix operation");
+        nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                  "ReferenceError: Invalid left-hand side in prefix operation");
+        return NJS_TOKEN_ILLEGAL;
     }
 
     node = njs_parser_node_alloc(vm);
@@ -863,7 +866,9 @@ njs_parser_post_inc_dec_expression(njs_v
     }
 
     if (!njs_parser_is_lvalue(parser->node)) {
-        return njs_parser_invalid_lvalue(vm, parser, "postfix operation");
+        nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                "ReferenceError: Invalid left-hand side in postfix operation");
+        return NJS_TOKEN_ILLEGAL;
     }
 
     node = njs_parser_node_alloc(vm);
@@ -1143,21 +1148,3 @@ 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 016339472304 -r 23598cfcfd15 njs/njs_regexp.c
--- a/njs/njs_regexp.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_regexp.c	Thu Aug 04 16:05:38 2016 +0300
@@ -39,6 +39,10 @@ static njs_regexp_flags_t njs_regexp_fla
     nxt_bool_t bound);
 static int njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex,
     u_char *source, int options);
+static u_char *njs_regexp_compile_trace_handler(nxt_trace_t *trace,
+    nxt_trace_data_t *td, u_char *start);
+static u_char *njs_regexp_match_trace_handler(nxt_trace_t *trace,
+    nxt_trace_data_t *td, u_char *start);
 static njs_ret_t njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp,
     u_char *string, nxt_regex_match_data_t *match_data, nxt_uint_t utf8);
 static njs_ret_t njs_regexp_string_create(njs_vm_t *vm, njs_value_t *value,
@@ -59,6 +63,8 @@ njs_regexp_init(njs_vm_t *vm)
         return NXT_ERROR;
     }
 
+    vm->regex_context->trace = &vm->trace;
+
     return NXT_OK;
 }
 
@@ -161,10 +167,11 @@ njs_regexp_literal(njs_vm_t *vm, njs_par
             flags = njs_regexp_flags(&p, lexer->end, 0);
 
             if (nxt_slow_path(flags < 0)) {
-                lexer->text.start = lexer->start;
-                lexer->text.length = p - lexer->text.start;
-                return njs_parser_error(vm, parser,
-                                        NJS_PARSER_ERROR_REGEXP_FLAGS);
+                nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                          "SyntaxError: Invalid RegExp flags \"%.*s\"",
+                          p - lexer->start, lexer->start);
+
+                return NJS_TOKEN_ILLEGAL;
             }
 
             lexer->start = p;
@@ -181,10 +188,11 @@ njs_regexp_literal(njs_vm_t *vm, njs_par
         }
     }
 
-    lexer->text.start = lexer->start - 1;
-    lexer->text.length = p - lexer->text.start;
+    nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+              "SyntaxError: Unterminated RegExp \"%.*s\"",
+              p - lexer->start - 1, lexer->start - 1);
 
-    return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNTERMINATED_REGEXP);
+    return NJS_TOKEN_ILLEGAL;
 }
 
 
@@ -345,28 +353,97 @@ static int
 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];
+    nxt_int_t            ret;
+    nxt_trace_handler_t  handler;
+
+    handler = vm->trace.handler;
+    vm->trace.handler = njs_regexp_compile_trace_handler;
 
     /* Zero length means a zero-terminated string. */
     ret = nxt_regex_compile(regex, source, 0, options, vm->regex_context);
 
+    vm->trace.handler = handler;
+
     if (nxt_fast_path(ret == NXT_OK)) {
         return regex->ncaptures;
     }
 
+    return ret;
+}
+
+
+static u_char *
+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;
+    njs_vm_t  *vm;
+
+    size = sizeof("SyntaxError: ") - 1;
+    memcpy(start, "SyntaxError: ", size);
+    p = start + size;
+
+    vm = trace->data;
+
+    trace = trace->next;
+    p = trace->handler(trace, td, p);
+
     if (vm->parser != NULL) {
-        size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
-                        "SyntaxError: %s in %u",
-                        vm->regex_context->error, vm->parser->lexer->line);
+        size = td->end - start;
 
-    } else {
-        size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
-                        "SyntaxError: %s", vm->regex_context->error);
+        n = snprintf((char *) p, size, " in %u", vm->parser->lexer->line);
+
+        if (n < size) {
+            p += n;
+        }
     }
 
-    return njs_vm_throw_exception(vm, buf, size);
+    njs_vm_throw_exception(vm, start, p - start);
+
+    return p;
+}
+
+
+nxt_int_t
+njs_regexp_match(njs_vm_t *vm, nxt_regex_t *regex, u_char *subject, size_t len,
+    nxt_regex_match_data_t *match_data)
+{
+    nxt_int_t            ret;
+    nxt_trace_handler_t  handler;
+
+    handler = vm->trace.handler;
+    vm->trace.handler = njs_regexp_match_trace_handler;
+
+    ret = nxt_regex_match(regex, subject, len, match_data, vm->regex_context);
+
+    vm->trace.handler = handler;
+
+    return ret;
+}
+
+
+static u_char *
+njs_regexp_match_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
+    u_char *start)
+{
+    u_char    *p;
+    size_t    size;
+    njs_vm_t  *vm;
+
+    size = sizeof("RegExpError: ") - 1;
+    memcpy(start, "RegExpError: ", size);
+    p = start + size;
+
+    vm = trace->data;
+
+    trace = trace->next;
+    p = trace->handler(trace, td, p);
+
+    njs_vm_throw_exception(vm, start, p - start);
+
+    return p;
 }
 
 
@@ -517,13 +594,13 @@ njs_regexp_prototype_test(njs_vm_t *vm, 
     pattern = args[0].data.u.regexp->pattern;
 
     if (nxt_regex_is_valid(&pattern->regex[n])) {
-        ret = nxt_regex_match(&pattern->regex[n], string.start, string.size,
-                              vm->single_match_data, vm->regex_context);
+        ret = njs_regexp_match(vm, &pattern->regex[n], string.start,
+                               string.size, vm->single_match_data);
         if (ret >= 0) {
             retval = &njs_value_true;
 
         } else if (ret != NGX_REGEX_NOMATCH) {
-            return njs_regexp_match_error(vm);
+            return NXT_ERROR;
         }
     }
 
@@ -589,8 +666,8 @@ njs_regexp_prototype_exec(njs_vm_t *vm, 
             return NXT_ERROR;
         }
 
-        ret = nxt_regex_match(&pattern->regex[n], string.start, string.size,
-                              match_data, vm->regex_context);
+        ret = njs_regexp_match(vm, &pattern->regex[n], string.start,
+                               string.size, match_data);
         if (ret >= 0) {
             return njs_regexp_exec_result(vm, regexp, string.start, match_data,
                                           utf8);
@@ -599,7 +676,7 @@ njs_regexp_prototype_exec(njs_vm_t *vm, 
         if (nxt_slow_path(ret != NGX_REGEX_NOMATCH)) {
             nxt_regex_match_data_free(match_data, vm->regex_context);
 
-            return njs_regexp_match_error(vm);
+            return NXT_ERROR;
         }
     }
 
@@ -736,19 +813,6 @@ njs_regexp_string_create(njs_vm_t *vm, n
 }
 
 
-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". */
diff -r 016339472304 -r 23598cfcfd15 njs/njs_regexp.h
--- a/njs/njs_regexp.h	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_regexp.h	Thu Aug 04 16:05:38 2016 +0300
@@ -39,10 +39,11 @@ njs_token_t njs_regexp_literal(njs_vm_t 
     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);
+nxt_int_t njs_regexp_match(njs_vm_t *vm, nxt_regex_t *regex, u_char *subject,
+    size_t len, nxt_regex_match_data_t *match_data);
 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;
diff -r 016339472304 -r 23598cfcfd15 njs/njs_string.c
--- a/njs/njs_string.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_string.c	Thu Aug 04 16:05:38 2016 +0300
@@ -31,7 +31,6 @@
 #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,
@@ -1455,14 +1454,14 @@ njs_string_prototype_search(njs_vm_t *vm
         n = (string.length != 0);
 
         if (nxt_regex_is_valid(&pattern->regex[n])) {
-            ret = nxt_regex_match(&pattern->regex[n], string.start, string.size,
-                                  vm->single_match_data, vm->regex_context);
+            ret = njs_regexp_match(vm, &pattern->regex[n], string.start,
+                                   string.size, vm->single_match_data);
             if (ret >= 0) {
                 captures = nxt_regex_captures(vm->single_match_data);
                 index = njs_string_index(&string, captures[0]);
 
             } else if (ret != NGX_REGEX_NOMATCH) {
-                return njs_regexp_match_error(vm);
+                return NXT_ERROR;
             }
         }
     }
@@ -1555,8 +1554,8 @@ njs_string_prototype_match(njs_vm_t *vm,
         array = NULL;
 
         do {
-            ret = nxt_regex_match(&pattern->regex[n], string.start, string.size,
-                                  vm->single_match_data, vm->regex_context);
+            ret = njs_regexp_match(vm, &pattern->regex[n], string.start,
+                                   string.size, vm->single_match_data);
             if (ret >= 0) {
                 if (array != NULL) {
                     if (array->length == array->size) {
@@ -1617,7 +1616,7 @@ njs_string_prototype_match(njs_vm_t *vm,
                 break;
 
             } else {
-                return njs_regexp_match_error(vm);
+                return NXT_ERROR;
             }
 
         } while (string.size > 0);
@@ -1756,8 +1755,8 @@ njs_string_prototype_split(njs_vm_t *vm,
             end = string.start + string.size;
 
             do {
-                ret = nxt_regex_match(&pattern->regex[n], start, end - start,
-                                      vm->single_match_data, vm->regex_context);
+                ret = njs_regexp_match(vm, &pattern->regex[n], start,
+                                       end - start, vm->single_match_data);
                 if (ret >= 0) {
                     captures = nxt_regex_captures(vm->single_match_data);
 
@@ -1769,7 +1768,7 @@ njs_string_prototype_split(njs_vm_t *vm,
                     next = (u_char *) end + 1;
 
                 } else {
-                    return njs_regexp_match_error(vm);
+                    return NXT_ERROR;
                 }
 
                 /* Empty split regexp. */
diff -r 016339472304 -r 23598cfcfd15 njs/njs_variable.c
--- a/njs/njs_variable.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_variable.c	Thu Aug 04 16:05:38 2016 +0300
@@ -79,7 +79,9 @@ njs_parser_name_alloc(njs_vm_t *vm, njs_
         return var;
     }
 
-    (void) njs_parser_error(vm, parser, NJS_PARSER_ERROR_DUPLICATE_DECLARATION);
+    nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+              "SyntaxError: Duplicate declaration \"%.*s\"",
+              (int) parser->lexer->text.length, parser->lexer->text.start);
 
     return NULL;
 }
diff -r 016339472304 -r 23598cfcfd15 njs/njs_vm.c
--- a/njs/njs_vm.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_vm.c	Thu Aug 04 16:05:38 2016 +0300
@@ -3316,24 +3316,21 @@ njs_value_string_copy(njs_vm_t *vm, nxt_
 }
 
 
-njs_ret_t
+void
 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;
+
+    if (nxt_fast_path(value != NULL)) {
+        vm->exception = value;
+
+        length = nxt_utf8_length(buf, size);
+
+        (void) njs_string_new(vm, value, buf, size, length);
     }
-
-    vm->exception = value;
-
-    length = nxt_utf8_length(buf, size);
-
-    (void) njs_string_new(vm, value, buf, size, length);
-
-    return NXT_ERROR;
 }
 
 
diff -r 016339472304 -r 23598cfcfd15 njs/njs_vm.h
--- a/njs/njs_vm.h	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njs_vm.h	Thu Aug 04 16:05:38 2016 +0300
@@ -8,6 +8,7 @@
 #define _NJS_VM_H_INCLUDED_
 
 
+#include <nxt_trace.h>
 #include <nxt_regex.h>
 
 
@@ -799,6 +800,7 @@ struct njs_vm_s {
 
     nxt_array_t              *code;  /* of njs_vm_code_t */
 
+    nxt_trace_t              trace;
     nxt_random_t             random;
 };
 
@@ -827,9 +829,6 @@ struct njs_vm_shared_s {
 };
 
 
-#define NJS_EXCEPTION_BUF_LENGTH  2048
-
-
 nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm);
 
 void njs_value_retain(njs_value_t *value);
@@ -969,7 +968,7 @@ njs_ret_t njs_value_to_ext_string(njs_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);
+void 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);
diff -r 016339472304 -r 23598cfcfd15 njs/njscript.c
--- a/njs/njscript.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/njscript.c	Thu Aug 04 16:05:38 2016 +0300
@@ -155,6 +155,11 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp,
         if (externals != NULL) {
             vm->externals_hash = *externals;
         }
+
+        vm->trace.level = NXT_LEVEL_TRACE;
+        vm->trace.size = 2048;
+        vm->trace.handler = njs_parser_trace_handler;
+        vm->trace.data = vm;
     }
 
     return vm;
@@ -325,6 +330,11 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache
             goto fail;
         }
 
+        nvm->trace.level = NXT_LEVEL_TRACE;
+        nvm->trace.size = 2048;
+        nvm->trace.handler = njs_parser_trace_handler;
+        nvm->trace.data = nvm;
+
         return nvm;
     }
 
diff -r 016339472304 -r 23598cfcfd15 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/njs/test/njs_unit_test.c	Thu Aug 04 16:05:38 2016 +0300
@@ -3511,6 +3511,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("/(/.test('')"),
       nxt_string("SyntaxError: pcre_compile(\"(\") failed: missing ) in 1") },
 
+    { nxt_string("/+/.test('')"),
+      nxt_string("SyntaxError: pcre_compile(\"+\") failed: nothing to repeat at \"+\" in 1") },
+
     { nxt_string("/^$/.test('')"),
       nxt_string("true") },
 
diff -r 016339472304 -r 23598cfcfd15 nxt/Makefile
--- a/nxt/Makefile	Thu Aug 04 14:45:27 2016 +0300
+++ b/nxt/Makefile	Thu Aug 04 16:05:38 2016 +0300
@@ -12,6 +12,7 @@ NXT_LIB =	nxt
 	$(NXT_BUILDDIR)/nxt_random.o \
 	$(NXT_BUILDDIR)/nxt_pcre.o \
 	$(NXT_BUILDDIR)/nxt_malloc.o \
+	$(NXT_BUILDDIR)/nxt_trace.o \
 	$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 
 	ar -r -c $(NXT_BUILDDIR)/libnxt.a \
@@ -23,6 +24,7 @@ NXT_LIB =	nxt
 		$(NXT_BUILDDIR)/nxt_random.o \
 		$(NXT_BUILDDIR)/nxt_pcre.o \
 		$(NXT_BUILDDIR)/nxt_malloc.o \
+		$(NXT_BUILDDIR)/nxt_trace.o \
 		$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 
 $(NXT_BUILDDIR)/nxt_murmur_hash.o: \
@@ -111,6 +113,7 @@ NXT_LIB =	nxt
 $(NXT_BUILDDIR)/nxt_pcre.o: \
 	$(NXT_LIB)/nxt_types.h \
 	$(NXT_LIB)/nxt_clang.h \
+	$(NXT_LIB)/nxt_trace.h \
 	$(NXT_LIB)/nxt_regex.h \
 	$(NXT_LIB)/nxt_pcre.h \
 	$(NXT_LIB)/nxt_pcre.c \
@@ -130,6 +133,18 @@ NXT_LIB =	nxt
 		-I$(NXT_LIB) \
 		$(NXT_LIB)/nxt_malloc.c
 
+$(NXT_BUILDDIR)/nxt_trace.o: \
+	$(NXT_LIB)/nxt_auto_config.h \
+	$(NXT_LIB)/nxt_types.h \
+	$(NXT_LIB)/nxt_clang.h \
+	$(NXT_LIB)/nxt_malloc.h \
+	$(NXT_LIB)/nxt_trace.h \
+	$(NXT_LIB)/nxt_trace.c \
+
+	$(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_trace.o $(NXT_CFLAGS) \
+		-I$(NXT_LIB) \
+		$(NXT_LIB)/nxt_trace.c
+
 $(NXT_BUILDDIR)/nxt_mem_cache_pool.o: \
 	$(NXT_LIB)/nxt_types.h \
 	$(NXT_LIB)/nxt_clang.h \
diff -r 016339472304 -r 23598cfcfd15 nxt/nxt_clang.h
--- a/nxt/nxt_clang.h	Thu Aug 04 14:45:27 2016 +0300
+++ b/nxt/nxt_clang.h	Thu Aug 04 16:05:38 2016 +0300
@@ -8,6 +8,7 @@
 #define _NXT_CLANG_H_INCLUDED_
 
 
+#include <stdarg.h>
 #include <stddef.h>       /* offsetof(). */
 #include <unistd.h>       /* NULL. */
 
diff -r 016339472304 -r 23598cfcfd15 nxt/nxt_pcre.c
--- a/nxt/nxt_pcre.c	Thu Aug 04 14:45:27 2016 +0300
+++ b/nxt/nxt_pcre.c	Thu Aug 04 16:05:38 2016 +0300
@@ -7,9 +7,9 @@
 #include <nxt_types.h>
 #include <nxt_clang.h>
 #include <nxt_stub.h>
+#include <nxt_trace.h>
 #include <nxt_regex.h>
 #include <nxt_pcre.h>
-#include <stdio.h>
 #include <string.h>
 
 
@@ -53,7 +53,6 @@ nxt_regex_compile(nxt_regex_t *regex, u_
     char        *pattern, *error;
     void        *(*saved_malloc)(size_t size);
     void        (*saved_free)(void *p);
-    size_t      size;
     const char  *errstr;
 
     ret = NXT_ERROR;
@@ -82,22 +81,14 @@ nxt_regex_compile(nxt_regex_t *regex, u_
     if (nxt_slow_path(regex->code == NULL)) {
         error = pattern + erroff;
 
-        size = sizeof("pcre_compile(\"\") failed:  at \"\"")
-               + strlen(errstr) + strlen(error) * 2 + erroff;
-
-        ctx->error = ctx->private_malloc(size, ctx->memory_data);
-        if (nxt_slow_path(ctx->error == NULL)) {
-            goto done;
-        }
+        if (*error != '\0') {
+            nxt_alert(ctx->trace, NXT_LEVEL_ERROR,
+                      "pcre_compile(\"%s\") failed: %s at \"%s\"",
+                      pattern, errstr, error);
 
-        if (*error != '\0') {
-            (void) snprintf((char *) ctx->error, size,
-                            "pcre_compile(\"%s\") failed: %s at \"%s\"",



More information about the nginx-devel mailing list