# Path: luna/modules/patterns.py
# class StateMatch(State):
#     def __init__(self):
#         pass
# 
#     def clone(self, seen):
#         return StateMatch()
# 
# class StateChar(StateCharRange):
#     def __init__(self, c, out):
#         StateCharRange.__init__(self, c, c, out)
# 
# def find2(expr, string, start):
#     assert isinstance(start, int)
#     if start < 0:
#         start = len(string) + start
#         # if negative offset is bigger than length of string
#         # start at the beginning
#         if start < 0:
#             start = 0
#         start = int(start)
# 
#     found = False
#     i = start
#     while i < len(string):
#         match = False
#         valid = True
#         j = i
#         state = expr
#         backtrack = []
#         while valid and not match and (j < len(string) or len(backtrack) > 0):
#             if j >= len(string) and len(backtrack) > 0:
#                 state, j = backtrack.pop()
#             if isinstance(state, StateCharRange):
#                 if not state.match(string[j]):
#                     if len(backtrack) == 0:
#                         valid = False
#                     else:
#                         state, j = backtrack.pop()
#                 else:
#                     state = state.out
#                     j += 1
#             elif isinstance(state, StateMatch):
#                 match = True
#             elif isinstance(state, StateSplit):
#                 backtrack.append((state.out2, j))
#                 state = state.out
#             else:
#                 valid = False
#             if j == len(string):
#                 if (isinstance(state, StateMatch) or
#                         (isinstance(state, StateSplit) and
#                             isinstance(state.out2, StateMatch))):
#                     match = True
#         if match:
#             found = True
#             yield (i+1, j)
#             if j > i:
#                 i = j
#             else:
#                 i += 1
#         else:
#             i += 1
#     if not found:
#         yield (-1, -1)
# 
# class StateSplit(State):
#     def __init__(self, out, out2):
#         self.out = out
#         self.out2 = out2
# 
# class StateDot(StateCharRange):
#     def __init__(self, out):
#         StateCharRange.__init__(self, ' ', ' ', out)
# 
#     def match(self, c):
#         return True
# 
# class StateCharRange(State):
#     def __init__(self, c1, c2, out):
#         self.start = ord(c1)
#         self.stop = ord(c2)
#         self.out = out
# 
#     def match(self, c):
#         return ord(c) >= self.start and ord(c) <= self.stop
# 
# def compile_re(pattern, plain=False):
#     tokens = tokenize(pattern)
#     return tokens_to_expression(tokens)


import pytest
from luna.modules.patterns import (
    StateMatch, StateChar, find2, StateSplit, StateDot, StateCharRange,
    compile_re
)
    def test_star_2(self):
        expr = StateSplit(None, StateMatch())
        expr.out = StateChar('a', expr)
        result = find2(expr, 'aaaaaaaabacbca', 0)
        assert list(result) == [
            (1, 8), (9, 8), (10, 10), (11, 10), (12, 11), (13, 12), (14, 14)
        ]

    def test_star_between_chars_star_match_end(self):
        star = StateSplit(None, StateMatch())
        star.out = StateChar('b', star)
        expr = StateChar('a', star)
        result = find2(expr, 'acjjjabcabbbbb', 0)
        assert list(result) == [(1, 1), (6, 7), (9, 14)]

    def test_star_and_char_star_not_match_end(self):
        star = StateSplit(None, StateMatch())
        star.out = StateChar('b', star)
        expr = StateChar('a', star)
        result = find2(expr, 'acjjjabcabbbbbfoobr', 0)
        assert list(result) == [(1, 1), (6, 7), (9, 14)]

    def test_star_between_chars_match_star(self):
        star = StateSplit(None, StateChar('c', StateMatch()))
        star.out = StateChar('b', star)
        expr = StateChar('a', star)
        result = find2(expr, 'xaabbbbbcjjjabcxalcac', 0)
        assert list(result) == [(3, 9), (13, 15), (20, 21)]

    def test_simple_or(self):

# Path: luna/modules/patterns.py
# class StateMatch(State):
#     def __init__(self):
#         pass
# 
#     def clone(self, seen):
#         return StateMatch()
# 
# class StateChar(StateCharRange):
#     def __init__(self, c, out):
#         StateCharRange.__init__(self, c, c, out)
# 
# def find2(expr, string, start):
#     assert isinstance(start, int)
#     if start < 0:
#         start = len(string) + start
#         # if negative offset is bigger than length of string
#         # start at the beginning
#         if start < 0:
#             start = 0
#         start = int(start)
# 
#     found = False
#     i = start
#     while i < len(string):
#         match = False
#         valid = True
#         j = i
#         state = expr
#         backtrack = []
#         while valid and not match and (j < len(string) or len(backtrack) > 0):
#             if j >= len(string) and len(backtrack) > 0:
#                 state, j = backtrack.pop()
#             if isinstance(state, StateCharRange):
#                 if not state.match(string[j]):
#                     if len(backtrack) == 0:
#                         valid = False
#                     else:
#                         state, j = backtrack.pop()
#                 else:
#                     state = state.out
#                     j += 1
#             elif isinstance(state, StateMatch):
#                 match = True
#             elif isinstance(state, StateSplit):
#                 backtrack.append((state.out2, j))
#                 state = state.out
#             else:
#                 valid = False
#             if j == len(string):
#                 if (isinstance(state, StateMatch) or
#                         (isinstance(state, StateSplit) and
#                             isinstance(state.out2, StateMatch))):
#                     match = True
#         if match:
#             found = True
#             yield (i+1, j)
#             if j > i:
#                 i = j
#             else:
#                 i += 1
#         else:
#             i += 1
#     if not found:
#         yield (-1, -1)
# 
# class StateSplit(State):
#     def __init__(self, out, out2):
#         self.out = out
#         self.out2 = out2
# 
# class StateDot(StateCharRange):
#     def __init__(self, out):
#         StateCharRange.__init__(self, ' ', ' ', out)
# 
#     def match(self, c):
#         return True
# 
# class StateCharRange(State):
#     def __init__(self, c1, c2, out):
#         self.start = ord(c1)
#         self.stop = ord(c2)
#         self.out = out
# 
#     def match(self, c):
#         return ord(c) >= self.start and ord(c) <= self.stop
# 
# def compile_re(pattern, plain=False):
#     tokens = tokenize(pattern)
#     return tokens_to_expression(tokens)


# Path: luna/tests/modules/test_pattern.py
import pytest
from luna.modules.patterns import (
    StateMatch, StateChar, find2, StateSplit, StateDot, StateCharRange,
    compile_re
)

    def test_star_2(self):
        expr = StateSplit(None, StateMatch())
        expr.out = StateChar('a', expr)
        result = find2(expr, 'aaaaaaaabacbca', 0)
        assert list(result) == [
            (1, 8), (9, 8), (10, 10), (11, 10), (12, 11), (13, 12), (14, 14)
        ]

    def test_star_between_chars_star_match_end(self):
        star = StateSplit(None, StateMatch())
        star.out = StateChar('b', star)
        expr = StateChar('a', star)
        result = find2(expr, 'acjjjabcabbbbb', 0)
        assert list(result) == [(1, 1), (6, 7), (9, 14)]

    def test_star_and_char_star_not_match_end(self):
        star = StateSplit(None, StateMatch())
        star.out = StateChar('b', star)
        expr = StateChar('a', star)
        result = find2(expr, 'acjjjabcabbbbbfoobr', 0)
        assert list(result) == [(1, 1), (6, 7), (9, 14)]

    def test_star_between_chars_match_star(self):
        star = StateSplit(None, StateChar('c', StateMatch()))
        star.out = StateChar('b', star)
        expr = StateChar('a', star)
        result = find2(expr, 'xaabbbbbcjjjabcxalcac', 0)
        assert list(result) == [(3, 9), (13, 15), (20, 21)]

    def test_simple_or(self):

        expr = compile_re('(aa|bb)')