Repository: LadybirdBrowser/ladybird
File: Libraries/LibRegex/RegexByteCode.h (C/C++)

Code before:
            // FORK END                   |
            // REGEXP                     |
            // REPEAT _MAX_LOOP MAX-MIN   | if max > min
            // FORK END                   |
            // REGEXP                     |
            // LABEL END                  |
            // RESET _MAX_LOOP            |
            auto jump_kind = static_cast<ByteCodeValueType>(greedy ? OpCodeId::ForkStay : OpCodeId::ForkJump);
            if (maximum.value() > minimum) {
                new_bytecode.empend(jump_kind);
                new_bytecode.empend((ByteCodeValueType)0); // Placeholder for the jump target.
                auto pre_loop_fork_jump_index = new_bytecode.size();
                new_bytecode.extend(bytecode_to_repeat);
                auto repetitions = maximum.value() - minimum;
                auto fork_jump_address = new_bytecode.size();
                if (repetitions > 1) {
                    new_bytecode.empend((ByteCodeValueType)OpCodeId::Repeat);
                    new_bytecode.empend(bytecode_to_repeat.size() + 2);
                    new_bytecode.empend(static_cast<ByteCodeValueType>(repetitions - 1));
                    new_bytecode.empend(max_repetition_mark_id);
                    new_bytecode.empend(jump_kind);
                    new_bytecode.empend((ByteCodeValueType)0); // Placeholder for the jump target.
                    auto post_loop_fork_jump_index = new_bytecode.size();
                    new_bytecode.extend(bytecode_to_repeat);
                    fork_jump_address = new_bytecode.size();

                    new_bytecode[post_loop_fork_jump_index - 1] = (ByteCodeValueType)(fork_jump_address - post_loop_fork_jump_index);

                    new_bytecode.empend((ByteCodeValueType)OpCodeId::ResetRepeat);
                    new_bytecode.empend((ByteCodeValueType)max_repetition_mark_id);
                }
                new_bytecode[pre_loop_fork_jump_index - 1] = (ByteCodeValueType)(fork_jump_address - pre_loop_fork_jump_index);
            }
        } else {
            // no maximum value set, repeat finding if possible:
            // (REPEAT REGEXP MIN)
            // LABEL _START
            // CHECKPOINT _C
            // REGEXP
            // JUMP_NONEMPTY _C _START FORK

            // Note: This is only safe because REPEAT will leave one iteration outside (see repetition_n)
            auto checkpoint = s_next_checkpoint_serial_id++;
            new_bytecode.insert(new_bytecode.size() - bytecode_to_repeat.size(), (ByteCodeValueType)OpCodeId::Checkpoint);
            new_bytecode.insert(new_bytecode.size() - bytecode_to_repeat.size(), (ByteCodeValueType)checkpoint);

            auto jump_kind = static_cast<ByteCodeValueType>(greedy ? OpCodeId::ForkJump : OpCodeId::ForkStay);
            new_bytecode.empend((ByteCodeValueType)OpCodeId::JumpNonEmpty);
            new_bytecode.empend(-bytecode_to_repeat.size() - 4 - 2); // Jump to the last iteration
            new_bytecode.empend(checkpoint);                         // if _C is not empty.
            new_bytecode.empend(jump_kind);

Review comment (bug):
so we start at minimum length behind (-1+1), then run the assertion - failing which takes us back one more character to retry the assertion?

If so, what's the point of check step back? inc_stepback can't step back behind the start of the subject, so it should just fail no?


Code after:
            // SET_STEPBACK match_length(BODY)-1
            // LABEL _START
            // INC_STEPBACK
            // FORK_JUMP _BODY
            // CHECK_STEPBACK
            // JUMP _START
            // LABEL _BODY
            // REGEX BODY
            // CHECK_SAVED_POSITION
            // RESTORE
            auto body_length = lookaround_body.size();
            empend((ByteCodeValueType)OpCodeId::Save);
            empend((ByteCodeValueType)OpCodeId::SetStepBack);
            empend((ByteCodeValueType)match_length - 1);
            empend((ByteCodeValueType)OpCodeId::IncStepBack);
            empend((ByteCodeValueType)OpCodeId::ForkJump);
            empend((ByteCodeValueType)1 + 2); // JUMP to label _BODY
            empend((ByteCodeValueType)OpCodeId::CheckStepBack);
            empend((ByteCodeValueType)OpCodeId::Jump);
            empend((ByteCodeValueType)-6); // JUMP to label _START
            extend(move(lookaround_body));
            if (greedy_lookaround) {
                empend((ByteCodeValueType)OpCodeId::ForkJump);
                empend((ByteCodeValueType)(0 - 2 - body_length - 6));
            }
            empend((ByteCodeValueType)OpCodeId::CheckSavedPosition);
            empend((ByteCodeValueType)OpCodeId::Restore);
            return;
        }
        case LookAroundType::NegatedLookBehind: {
            // JUMP _A
            // LABEL _L
            // GOBACK match_length(BODY)
            // REGEXP BODY
            // FAIL
            // LABEL _A
            // SAVE
            // FORKJUMP _L
            // RESTORE
            auto body_length = lookaround_body.size();
            empend((ByteCodeValueType)OpCodeId::Jump);
            empend((ByteCodeValueType)body_length + 3); // JUMP to label _A
            empend((ByteCodeValueType)OpCodeId::GoBack);
            empend((ByteCodeValueType)match_length);
            extend(move(lookaround_body));
            empend((ByteCodeValueType)OpCodeId::FailForks);
            empend((ByteCodeValueType)OpCodeId::Save);
            empend((ByteCodeValueType)OpCodeId::ForkJump);
            empend((ByteCodeValueType) - (body_length + 6)); // JUMP to label _L
            empend((ByteCodeValueType)OpCodeId::Restore);
            return;