]> git.kaiwu.me - njs.git/commitdiff
nxt_trace interface. nxt_regex, RegExp, and parser use it now.
authorIgor Sysoev <igor@sysoev.ru>
Thu, 4 Aug 2016 13:05:38 +0000 (16:05 +0300)
committerIgor Sysoev <igor@sysoev.ru>
Thu, 4 Aug 2016 13:05:38 +0000 (16:05 +0300)
17 files changed:
Makefile
njs/njs_generator.c
njs/njs_parser.c
njs/njs_parser.h
njs/njs_parser_expression.c
njs/njs_regexp.c
njs/njs_regexp.h
njs/njs_string.c
njs/njs_variable.c
njs/njs_vm.c
njs/njs_vm.h
njs/njscript.c
njs/test/njs_unit_test.c
nxt/Makefile
nxt/nxt_clang.h
nxt/nxt_pcre.c
nxt/nxt_regex.h

index b53baa0638353bafb136b96e731c5dc6c7a475d0..9bdf6848b62db18b6c7a927ae9062314157c1836 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -169,6 +169,7 @@ $(NXT_BUILDDIR)/njs_string.o: \
        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 @@ $(NXT_BUILDDIR)/njs_unit_test: \
                -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
index 3e2825a8b611ff6b86c33ac1111be36e7177df57..5f8fa52c2884d0d05eced6431a48a7c6ce614713 100644 (file)
 #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_generator_node_index_release(njs_vm_t *vm,
 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 *vm, njs_parser_t *parser,
         }
     }
 
-    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 *vm, njs_parser_t *parser,
         }
     }
 
-    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_node_t *node)
     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);
-}
index 0d2ebbd71f74eaac0e11cf165f449f3669c4d0c4..87159da3278d237e797ab726bf44d0e8b11aaf97 100644 (file)
@@ -54,8 +54,6 @@ static njs_token_t njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser);
 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_statement(njs_vm_t *vm,
 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, njs_parser_t *parser)
 
                } 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;
@@ -889,22 +889,6 @@ 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)
-{
-    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)
 {
@@ -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, njs_parser_t *parser)
     }
 
     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_parser_t *parser, njs_token_t token)
         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 *vm, njs_parser_t *parser,
                         }
 
                         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 *vm, njs_parser_t *parser,
             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 *vm, njs_parser_t *parser,
 
         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);
-    }
-
-    size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
-                    "SyntaxError: Unexpected end of input in %u",
-                    parser->lexer->line);
+        nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                  "SyntaxError: Unexpected token \"%.*s\"",
+                  (int) parser->lexer->text.length, parser->lexer->text.start);
 
-    (void) njs_vm_throw_exception(vm, buf, size);
+    } else {
+        nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
+                  "SyntaxError: Unexpected end of input");
+    }
 
     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];
+    int       n;
+    u_char    *p;
+    ssize_t   size;
+    njs_vm_t  *vm;
 
-    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",
-    };
+    p = start;
 
-    msg = errors[err];
-    lexer = parser->lexer;
+    if (td->level == NXT_LEVEL_CRIT) {
+        size = sizeof("InternalError: ") - 1;
+        memcpy(p, "InternalError: ", size);
+        p = start + size;
+    }
 
-    size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH,
-                    msg, (int) lexer->text.length, lexer->text.start,
-                    lexer->line);
+    vm = trace->data;
 
-    (void) njs_vm_throw_exception(vm, buf, size);
+    trace = trace->next;
+    p = trace->handler(trace, td, p);
 
-    return NJS_TOKEN_ILLEGAL;
+    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;
 }
index 3b35902f7f99aacba1aa468a2800f43500903014..312dfa64294c775fb7bd4bdffa507d40542becb8 100644 (file)
@@ -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_t *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);
 
index ee81964d8bacf81564a4f9138cde9d94608c8d66..00cf2ddab654c024c4a2895565c46580758c1e45 100644 (file)
@@ -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_expression(njs_vm_t *vm,
     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, njs_parser_t *parser, njs_token_t token)
         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_t *vm, njs_parser_t *parser,
         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 *vm, njs_parser_t *parser,
     }
 
     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_vm_t *vm, njs_parser_t *parser,
     }
 
     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_parser_t *parser,
 
     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;
-
-}
index 72568921f233fe3ff629ec72d3fc216911064065..d95d92d400e9494e4eca6962451aa58d45c13361 100644 (file)
@@ -39,6 +39,10 @@ static njs_regexp_flags_t njs_regexp_flags(u_char **start, u_char *end,
     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_parser_t *parser, njs_value_t *value)
             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_parser_t *parser, njs_value_t *value)
         }
     }
 
-    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, njs_value_t *args, nxt_uint_t nargs,
     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, njs_value_t *args, nxt_uint_t nargs,
             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, njs_value_t *args, nxt_uint_t nargs,
         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, njs_value_t *value, u_char *start,
 }
 
 
-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". */
index dbafdc978affa090237de28a8a5e5e78bd771e78..0b4bdf66d1786991a79b53677a993a5fce922f49 100644 (file)
@@ -39,10 +39,11 @@ 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);
+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;
index 2c43cbfef0c63b66f1c480fe51ca0ec3d0145db9..089312c645921f8846a16c750196b6c0b1554e1f 100644 (file)
@@ -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, njs_value_t *args, nxt_uint_t nargs,
         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, njs_value_t *args, nxt_uint_t nargs,
         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, njs_value_t *args, nxt_uint_t nargs,
                 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, njs_value_t *args, nxt_uint_t nargs,
             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, njs_value_t *args, nxt_uint_t nargs,
                     next = (u_char *) end + 1;
 
                 } else {
-                    return njs_regexp_match_error(vm);
+                    return NXT_ERROR;
                 }
 
                 /* Empty split regexp. */
index 5915b91a918d6a0bbd43ebed968a3d11a3045534..d7efff8a4ad88ebee4fe002bb1ec4d56f65d0809 100644 (file)
@@ -79,7 +79,9 @@ njs_parser_name_alloc(njs_vm_t *vm, njs_parser_t *parser)
         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;
 }
index 13791973d37cb122d86b1179b9284708faa37b8c..d3a477826f18a7e12a287f17f60d44352bbdce76 100644 (file)
@@ -3316,24 +3316,21 @@ njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval, njs_value_t *value,
 }
 
 
-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;
-    }
 
-    vm->exception = value;
+    if (nxt_fast_path(value != NULL)) {
+        vm->exception = value;
 
-    length = nxt_utf8_length(buf, size);
+        length = nxt_utf8_length(buf, size);
 
-    (void) njs_string_new(vm, value, buf, size, length);
-
-    return NXT_ERROR;
+        (void) njs_string_new(vm, value, buf, size, length);
+    }
 }
 
 
index 461b4caeecb1f95bda67a6471bbc3b37c7062f30..7f72bdfc06fcda7450f7ff8025bd0a8276b09167 100644 (file)
@@ -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_t *vm, nxt_str_t *dst,
     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);
index 48d5241d4e792077fbf6f97c0fafff59c6f1c4c9..0213ce8fa444d8d5e44478fc079b1f4d22717aa4 100644 (file)
@@ -155,6 +155,11 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp, njs_vm_shared_t **shared,
         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_pool_t *mcp, void **external)
             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;
     }
 
index 2056a3c061f9d829e61bc00076de06d3c0e8e77f..ed4fb41850ac8fa242690bfaf1c315e2688f3c2b 100644 (file)
@@ -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") },
 
index 4e0f4f9a9cc79d750c7b6022b94d116e502dd67b..2f2431ccbed80f065906d61b25e58dea7f0157c2 100644 (file)
@@ -12,6 +12,7 @@ $(NXT_BUILDDIR)/libnxt.a: \
        $(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_BUILDDIR)/libnxt.a: \
                $(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_BUILDDIR)/nxt_random.o: \
 $(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_BUILDDIR)/nxt_malloc.o: \
                -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 \
index d504a8602b9734d5abe39a136d60c85ace11bca9..af381adb74bd4d15014b5e0e1d089260baeec3f9 100644 (file)
@@ -8,6 +8,7 @@
 #define _NXT_CLANG_H_INCLUDED_
 
 
+#include <stdarg.h>
 #include <stddef.h>       /* offsetof(). */
 #include <unistd.h>       /* NULL. */
 
index a46d7a0a5d306fd71085afc6837e24e4f8b88833..45eef09a3fa3e9d6caf18af2b4e7ec1c2d75c451 100644 (file)
@@ -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 *source, size_t len,
     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_char *source, size_t len,
     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') {
-            (void) snprintf((char *) ctx->error, size,
-                            "pcre_compile(\"%s\") failed: %s at \"%s\"",
-                            pattern, errstr, error);
+            nxt_alert(ctx->trace, NXT_LEVEL_ERROR,
+                      "pcre_compile(\"%s\") failed: %s at \"%s\"",
+                      pattern, errstr, error);
+
         } else {
-            (void) snprintf((char *) ctx->error, size,
-                            "pcre_compile(\"%s\") failed: %s",
-                            pattern, errstr);
+            nxt_alert(ctx->trace, NXT_LEVEL_ERROR,
+                      "pcre_compile(\"%s\") failed: %s", pattern, errstr);
         }
 
         goto done;
@@ -106,16 +97,8 @@ nxt_regex_compile(nxt_regex_t *regex, u_char *source, size_t len,
     regex->extra = pcre_study(regex->code, 0, &errstr);
 
     if (nxt_slow_path(errstr != NULL)) {
-        size = sizeof("pcre_study(\"\") failed: ")
-               + strlen(pattern) + strlen(errstr);
-
-        ctx->error = ctx->private_malloc(size, ctx->memory_data);
-        if (nxt_slow_path(ctx->error == NULL)) {
-            goto done;
-        }
-
-        (void) snprintf((char *) ctx->error, size,
-                        "pcre_study(\"%s\") failed: %s", pattern, errstr);
+        nxt_alert(ctx->trace, NXT_LEVEL_ERROR,
+                  "pcre_study(\"%s\") failed: %s", pattern, errstr);
 
         goto done;
     }
@@ -124,17 +107,9 @@ nxt_regex_compile(nxt_regex_t *regex, u_char *source, size_t len,
                         &regex->ncaptures);
 
     if (nxt_slow_path(err < 0)) {
-        size = sizeof("pcre_fullinfo(\"\", PCRE_INFO_CAPTURECOUNT) failed: ")
-               + strlen(pattern) + sizeof("-2147483647");
-
-        ctx->error = ctx->private_malloc(size, ctx->memory_data);
-        if (nxt_slow_path(ctx->error == NULL)) {
-            goto done;
-        }
-
-        (void) snprintf((char *) ctx->error, size,
-                    "pcre_fullinfo(\"%s\", PCRE_INFO_CAPTURECOUNT) failed: %d",
-                    pattern, err);
+        nxt_alert(ctx->trace, NXT_LEVEL_ERROR,
+                  "pcre_fullinfo(\"%s\", PCRE_INFO_CAPTURECOUNT) failed: %d",
+                  pattern, err);
 
         goto done;
     }
@@ -229,8 +204,7 @@ nxt_int_t
 nxt_regex_match(nxt_regex_t *regex, u_char *subject, size_t len,
     nxt_regex_match_data_t *match_data, nxt_regex_context_t *ctx)
 {
-    int     ret;
-    size_t  size;
+    int  ret;
 
     ret = pcre_exec(regex->code, regex->extra, (char *) subject, len, 0, 0,
                     match_data->captures, match_data->ncaptures);
@@ -238,14 +212,7 @@ nxt_regex_match(nxt_regex_t *regex, u_char *subject, size_t len,
     /* PCRE_ERROR_NOMATCH is -1. */
 
     if (nxt_slow_path(ret < PCRE_ERROR_NOMATCH)) {
-        size = sizeof("pcre_exec() failed: ") + sizeof("-2147483647");
-
-        ctx->error = ctx->private_malloc(size, ctx->memory_data);
-
-        if (nxt_fast_path(ctx->error != NULL)) {
-            (void) snprintf((char *) ctx->error, size, "pcre_exec() failed: %d",
-                            ret);
-        }
+        nxt_alert(ctx->trace, NXT_LEVEL_ERROR, "pcre_exec() failed: %d", ret);
     }
 
     return ret;
@@ -255,5 +222,5 @@ nxt_regex_match(nxt_regex_t *regex, u_char *subject, size_t len,
 int *
 nxt_regex_captures(nxt_regex_match_data_t *match_data)
 {
-     return (match_data)->captures;
+     return match_data->captures;
 }
index 040c39a6d6bd5ae1d325a62ba11d2da5650a91af..674f1e22d1a41cbc7fcc43477deed1f0b877c89d 100644 (file)
@@ -20,7 +20,7 @@ typedef struct {
     nxt_pcre_malloc_t  private_malloc;
     nxt_pcre_free_t    private_free;
     void               *memory_data;
-    u_char             *error;
+    nxt_trace_t        *trace;
 } nxt_regex_context_t;