Capture control verbs inside the conditional assertion of a conditional block.

This commit is contained in:
Zoltán Herczeg 2017-03-20 10:41:13 +00:00
parent d6faa55b91
commit 131209e22d
3 changed files with 52 additions and 49 deletions

View File

@ -411,10 +411,10 @@ typedef struct compiler_common {
BOOL has_then; BOOL has_then;
/* (*SKIP) or (*SKIP:arg) is found in lookbehind assertion. */ /* (*SKIP) or (*SKIP:arg) is found in lookbehind assertion. */
BOOL has_skip_in_assert_back; BOOL has_skip_in_assert_back;
/* Currently in recurse or negative assert. */ /* Quit is redirected by recurse, negative assertion, or positive assertion in conditional block. */
BOOL local_exit; BOOL local_quit_available;
/* Currently in a positive assert. */ /* Currently in a positive assertion. */
BOOL positive_assert; BOOL in_positive_assertion;
/* Newline control. */ /* Newline control. */
int nltype; int nltype;
sljit_u32 nlmax; sljit_u32 nlmax;
@ -444,7 +444,7 @@ typedef struct compiler_common {
recurse_entry *currententry; recurse_entry *currententry;
jump_list *partialmatch; jump_list *partialmatch;
jump_list *quit; jump_list *quit;
jump_list *positive_assert_quit; jump_list *positive_assertion_quit;
jump_list *forced_quit; jump_list *forced_quit;
jump_list *accept; jump_list *accept;
jump_list *calllimit; jump_list *calllimit;
@ -1661,11 +1661,11 @@ if (length > 0)
return stack_restore ? no_frame : no_stack; return stack_restore ? no_frame : no_stack;
} }
static void init_frame(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int stackpos, int stacktop, BOOL recursive) static void init_frame(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int stackpos, int stacktop)
{ {
DEFINE_COMPILER; DEFINE_COMPILER;
BOOL setsom_found = recursive; BOOL setsom_found = FALSE;
BOOL setmark_found = recursive; BOOL setmark_found = FALSE;
/* The last capture is a local variable even for recursions. */ /* The last capture is a local variable even for recursions. */
BOOL capture_last_found = FALSE; BOOL capture_last_found = FALSE;
int offset; int offset;
@ -1678,7 +1678,7 @@ stackpos = STACK(stackpos);
if (ccend == NULL) if (ccend == NULL)
{ {
ccend = bracketend(cc) - (1 + LINK_SIZE); ccend = bracketend(cc) - (1 + LINK_SIZE);
if (recursive || (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS)) if (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS)
cc = next_opcode(common, cc); cc = next_opcode(common, cc);
} }
@ -2104,7 +2104,8 @@ switch (type)
base_reg = STACK_TOP; base_reg = STACK_TOP;
break; break;
case recurse_swap_global: default:
SLJIT_ASSERT(type == recurse_swap_global);
from_sp = FALSE; from_sp = FALSE;
base_reg = TMP1; base_reg = TMP1;
break; break;
@ -7525,6 +7526,7 @@ static PCRE2_SPTR compile_assert_matchingpath(compiler_common *common, PCRE2_SPT
DEFINE_COMPILER; DEFINE_COMPILER;
int framesize; int framesize;
int extrasize; int extrasize;
BOOL local_quit_available = FALSE;
BOOL needs_control_head; BOOL needs_control_head;
int private_data_ptr; int private_data_ptr;
backtrack_common altbacktrack; backtrack_common altbacktrack;
@ -7535,13 +7537,13 @@ jump_list *tmp = NULL;
jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks; jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks;
jump_list **found; jump_list **found;
/* Saving previous accept variables. */ /* Saving previous accept variables. */
BOOL save_local_exit = common->local_exit; BOOL save_local_quit_available = common->local_quit_available;
BOOL save_positive_assert = common->positive_assert; BOOL save_in_positive_assertion = common->in_positive_assertion;
then_trap_backtrack *save_then_trap = common->then_trap; then_trap_backtrack *save_then_trap = common->then_trap;
struct sljit_label *save_quit_label = common->quit_label; struct sljit_label *save_quit_label = common->quit_label;
struct sljit_label *save_accept_label = common->accept_label; struct sljit_label *save_accept_label = common->accept_label;
jump_list *save_quit = common->quit; jump_list *save_quit = common->quit;
jump_list *save_positive_assert_quit = common->positive_assert_quit; jump_list *save_positive_assertion_quit = common->positive_assertion_quit;
jump_list *save_accept = common->accept; jump_list *save_accept = common->accept;
struct sljit_jump *jump; struct sljit_jump *jump;
struct sljit_jump *brajump = NULL; struct sljit_jump *brajump = NULL;
@ -7623,21 +7625,21 @@ else
else else
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize, FALSE); init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize);
} }
memset(&altbacktrack, 0, sizeof(backtrack_common)); memset(&altbacktrack, 0, sizeof(backtrack_common));
if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) if (conditional || (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT))
{ {
/* Negative assert is stronger than positive assert. */ /* Control verbs cannot escape from these asserts. */
common->local_exit = TRUE; local_quit_available = TRUE;
common->local_quit_available = TRUE;
common->quit_label = NULL; common->quit_label = NULL;
common->quit = NULL; common->quit = NULL;
common->positive_assert = FALSE;
} }
else
common->positive_assert = TRUE; common->in_positive_assertion = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK);
common->positive_assert_quit = NULL; common->positive_assertion_quit = NULL;
while (1) while (1)
{ {
@ -7653,16 +7655,16 @@ while (1)
compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack); compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
{ {
if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) if (local_quit_available)
{ {
common->local_exit = save_local_exit; common->local_quit_available = save_local_quit_available;
common->quit_label = save_quit_label; common->quit_label = save_quit_label;
common->quit = save_quit; common->quit = save_quit;
} }
common->positive_assert = save_positive_assert; common->in_positive_assertion = save_in_positive_assertion;
common->then_trap = save_then_trap; common->then_trap = save_then_trap;
common->accept_label = save_accept_label; common->accept_label = save_accept_label;
common->positive_assert_quit = save_positive_assert_quit; common->positive_assertion_quit = save_positive_assertion_quit;
common->accept = save_accept; common->accept = save_accept;
return NULL; return NULL;
} }
@ -7731,16 +7733,16 @@ while (1)
compile_backtrackingpath(common, altbacktrack.top); compile_backtrackingpath(common, altbacktrack.top);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
{ {
if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) if (local_quit_available)
{ {
common->local_exit = save_local_exit; common->local_quit_available = save_local_quit_available;
common->quit_label = save_quit_label; common->quit_label = save_quit_label;
common->quit = save_quit; common->quit = save_quit;
} }
common->positive_assert = save_positive_assert; common->in_positive_assertion = save_in_positive_assertion;
common->then_trap = save_then_trap; common->then_trap = save_then_trap;
common->accept_label = save_accept_label; common->accept_label = save_accept_label;
common->positive_assert_quit = save_positive_assert_quit; common->positive_assertion_quit = save_positive_assertion_quit;
common->accept = save_accept; common->accept = save_accept;
return NULL; return NULL;
} }
@ -7753,18 +7755,18 @@ while (1)
cc += GET(cc, 1); cc += GET(cc, 1);
} }
if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) if (local_quit_available)
{ {
SLJIT_ASSERT(common->positive_assert_quit == NULL); SLJIT_ASSERT(common->positive_assertion_quit == NULL);
/* Makes the check less complicated below. */ /* Makes the check less complicated below. */
common->positive_assert_quit = common->quit; common->positive_assertion_quit = common->quit;
} }
/* None of them matched. */ /* None of them matched. */
if (common->positive_assert_quit != NULL) if (common->positive_assertion_quit != NULL)
{ {
jump = JUMP(SLJIT_JUMP); jump = JUMP(SLJIT_JUMP);
set_jumps(common->positive_assert_quit, LABEL()); set_jumps(common->positive_assertion_quit, LABEL());
SLJIT_ASSERT(framesize != no_stack); SLJIT_ASSERT(framesize != no_stack);
if (framesize < 0) if (framesize < 0)
OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw)); OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw));
@ -7928,16 +7930,16 @@ else
} }
} }
if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) if (local_quit_available)
{ {
common->local_exit = save_local_exit; common->local_quit_available = save_local_quit_available;
common->quit_label = save_quit_label; common->quit_label = save_quit_label;
common->quit = save_quit; common->quit = save_quit;
} }
common->positive_assert = save_positive_assert; common->in_positive_assertion = save_in_positive_assertion;
common->then_trap = save_then_trap; common->then_trap = save_then_trap;
common->accept_label = save_accept_label; common->accept_label = save_accept_label;
common->positive_assert_quit = save_positive_assert_quit; common->positive_assertion_quit = save_positive_assertion_quit;
common->accept = save_accept; common->accept = save_accept;
return cc + 1 + LINK_SIZE; return cc + 1 + LINK_SIZE;
} }
@ -8314,7 +8316,7 @@ if (opcode == OP_ONCE)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
} }
init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1, FALSE); init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1);
} }
} }
else if (opcode == OP_CBRA || opcode == OP_SCBRA) else if (opcode == OP_CBRA || opcode == OP_SCBRA)
@ -8757,7 +8759,7 @@ else
stack++; stack++;
} }
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0);
init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize, FALSE); init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize);
stack -= 1 + (offset == 0); stack -= 1 + (offset == 0);
} }
@ -9560,7 +9562,7 @@ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 3), TMP2, 0);
size = BACKTRACK_AS(then_trap_backtrack)->framesize; size = BACKTRACK_AS(then_trap_backtrack)->framesize;
if (size >= 0) if (size >= 0)
init_frame(common, cc, ccend, size - 1, 0, FALSE); init_frame(common, cc, ccend, size - 1, 0);
} }
static void compile_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent) static void compile_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent)
@ -10678,15 +10680,16 @@ if (opcode == OP_THEN || opcode == OP_THEN_ARG)
add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP)); add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP));
return; return;
} }
else if (common->positive_assert) else if (!common->local_quit_available && common->in_positive_assertion)
{ {
add_jump(compiler, &common->positive_assert_quit, JUMP(SLJIT_JUMP)); add_jump(compiler, &common->positive_assertion_quit, JUMP(SLJIT_JUMP));
return; return;
} }
} }
if (common->local_exit) if (common->local_quit_available)
{ {
/* Abort match with a fail. */
if (common->quit_label == NULL) if (common->quit_label == NULL)
add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP));
else else
@ -10902,7 +10905,7 @@ while (current)
break; break;
case OP_COMMIT: case OP_COMMIT:
if (!common->local_exit) if (!common->local_quit_available)
OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
if (common->quit_label == NULL) if (common->quit_label == NULL)
add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP));
@ -11539,7 +11542,7 @@ common->fast_forward_bc_ptr = NULL;
common->fast_fail_start_ptr = 0; common->fast_fail_start_ptr = 0;
common->fast_fail_end_ptr = 0; common->fast_fail_end_ptr = 0;
common->currententry = common->entries; common->currententry = common->entries;
common->local_exit = TRUE; common->local_quit_available = TRUE;
quit_label = common->quit_label; quit_label = common->quit_label;
while (common->currententry != NULL) while (common->currententry != NULL)
{ {
@ -11556,7 +11559,7 @@ while (common->currententry != NULL)
flush_stubs(common); flush_stubs(common);
common->currententry = common->currententry->next; common->currententry = common->currententry->next;
} }
common->local_exit = FALSE; common->local_quit_available = FALSE;
common->quit_label = quit_label; common->quit_label = quit_label;
/* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */ /* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */

2
testdata/testinput2 vendored
View File

@ -3710,7 +3710,7 @@
bnn bnn
/(?(?=b(*SKIP)a)bn|bnn)/ /(?(?=b(*SKIP)a)bn|bnn)/
bnn\=no_jit bnn
/(?=b(*THEN)a|)bn|bnn/ /(?=b(*THEN)a|)bn|bnn/
bnn bnn

View File

@ -11820,7 +11820,7 @@ No match
0: bn 0: bn
/(?(?=b(*SKIP)a)bn|bnn)/ /(?(?=b(*SKIP)a)bn|bnn)/
bnn\=no_jit bnn
0: bnn 0: bnn
/(?=b(*THEN)a|)bn|bnn/ /(?=b(*THEN)a|)bn|bnn/