Capture control verbs inside the conditional assertion of a conditional block.
This commit is contained in:
parent
d6faa55b91
commit
131209e22d
|
@ -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. */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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/
|
||||||
|
|
Loading…
Reference in New Issue