<commit_before>from .core import Sort, Attribute
from .exceptions import ArgumentError


class _Strategy(Sort):

    def __init__(self, fn, **kwargs):
        super().__init__(**kwargs)
        self.fn = fn

    def __call__(self, terms):
        if not isinstance(terms, (set, frozenset)):
            terms = frozenset([terms])

        attributes = {name: getattr(self, name) for name in self.__attributes__}
        rv = set()
        for term in terms:
            term = self.fn(term=term, **attributes)
            if isinstance(term, (set, frozenset)):
                rv |= term
            else:
                rv.add(term)
        return rv


def strategy(*args, **kwargs):
    if args and callable(args[0]):
        return _Strategy(args[0])

    def strategy_factory(fn):
        def __init__(self, **kwargs):
            _Strategy.__init__(self, fn, **kwargs)

        cls_dict = dict(kwargs)
        cls_dict['__init__'] = __init__
        return type(fn.__name__, (_Strategy,), cls_dict)

    return strategy_factory


@strategy
def identity(term):
    return term


class union(_Strategy):

    left = Attribute(domain=Sort)
    right = Attribute(domain=Sort)

    def __init__(self, *operands):
        def fn(left, right, term):
            return left(term) | right(term)

        if len(operands) < 2:
            raise ArgumentError('%s requires at least 2 operands.' % self.__class__.__name__)
        elif len(operands) == 2:
            super().__init__(fn, left=operands[0], right=operands[1])
        else:
            super().__init__(fn, left=operands[0], right=union(*operands[1:]))


class fixpoint(_Strategy):

    def __call__(self, terms):
        if not isinstance(terms, (set, frozenset)):
            terms = frozenset([terms])

        rv = self.fn(terms)
        while rv != terms:
            terms = rv
            rv = self.fn(terms)
        return rv<commit_msg>makes all strategies functions of the form [args...] -> (sort -> sort)<commit_after>from .core import Sort, Attribute
from .exceptions import ArgumentError


class _Strategy(Sort):

    def __init__(self, fn, **kwargs):
        super().__init__(**kwargs)
        self.fn = fn

    def __call__(self, terms):
        if not isinstance(terms, (set, frozenset)):
            terms = set([terms])

        attributes = {name: getattr(self, name) for name in self.__attributes__}
        rv = set()
        for term in terms:
            term = self.fn(**attributes)(term)
            if isinstance(term, (set, frozenset)):
                rv |= term
            else:
                rv.add(term)
        return rv


def strategy(*args, **kwargs):
    if args and callable(args[0]):
        return _Strategy(args[0])

    def strategy_factory(fn):
        def __init__(self, **kwargs):
            _Strategy.__init__(self, fn, **kwargs)

        cls_dict = dict(kwargs)
        cls_dict['__init__'] = __init__
        return type(fn.__name__, (_Strategy,), cls_dict)

    return strategy_factory


@strategy
def identity():
    return lambda term: term


class union(_Strategy):

    left = Attribute(domain=_Strategy)
    right = Attribute(domain=_Strategy)

    def __init__(self, *operands):
        # "cast" operands as strategies if there aren't.
        for i in range(len(operands)):
            if not isinstance(operands[i], _Strategy):
                operands[i] = strategy(operands[i])

        def fn(left, right):
            return lambda term: left(term) | right(term)

        if len(operands) < 2:
            raise ArgumentError('%s requires at least 2 operands.' % self.__class__.__name__)
        elif len(operands) == 2:
            super().__init__(fn, left=operands[0], right=operands[1])
        else:
            super().__init__(fn, left=operands[0], right=union(*operands[1:]))


class fixpoint(_Strategy):

    def __call__(self, terms):
        if not isinstance(terms, (set, frozenset)):
            terms = set([terms])

        rv = self.fn(terms)
        while rv != terms:
            terms = rv
            rv = self.fn(terms)
        return rv
{'fraction_non_alphanumeric': 0.12224399804017638, 'fraction_numerical': 0.004409603135717786, 'mean_word_length': 2.292741935483871, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5480144', 'n_tokens_mistral': 1225, 'n_tokens_neox': 1165, 'n_words': 321}