def Add(matcher): ''' Join tokens in the result using the "+" operator (**+**). This joins strings and merges lists. Unlike `Reduce` this will have no effect of there are no matches. ''' return Apply(matcher, TransformationWrapper(add))
def single(alphabet, node, regexp, regexp_type, wrapper=None): ''' Create a matcher for the given regular expression. ''' # avoid dependency loops from lepl.matchers.transform import TransformationWrapper matcher = regexp_type(regexp, alphabet) matcher = matcher.compose(TransformationWrapper(empty_adapter)) if wrapper is None: wrapper = node.wrapper elif wrapper and not isinstance(wrapper, TransformationWrapper): wrapper = TransformationWrapper(wrapper) if wrapper: wrapper.functions = \ list(filter(lambda x: x != empty_adapter, wrapper.functions)) matcher = matcher.compose(wrapper) return matcher
def single(alphabet, node, regexp, regexp_type, wrapper=None): ''' Create a matcher for the given regular expression. ''' # avoid dependency loops from lepl.matchers.transform import TransformationWrapper matcher = regexp_type(regexp, alphabet) matcher = matcher.compose(TransformationWrapper(empty_adapter)) if wrapper is None and hasattr(node, 'wrapper'): wrapper = node.wrapper elif wrapper and not isinstance(wrapper, TransformationWrapper): wrapper = TransformationWrapper(wrapper) if wrapper: wrapper.functions = \ list(filter(lambda x: x != empty_adapter, wrapper.functions)) matcher = matcher.compose(wrapper) return matcher
def Reduce(matcher, zero, join=__add__): ''' Combine the results from the matcher using `reduce(join, results, zero)`. Unlike `Add` this will return a value (`zero`) when there are no matches. ''' def reduce_(_stream, matcher): (results, stream_out) = matcher() return ([reduce(join, results, zero)], stream_out) return Apply(matcher, TransformationWrapper(reduce_))
def clone_and(use, original, *matchers): ''' We can convert an And only if all the sub-matchers have possible regular expressions, and even then we must tag the result unless an add transform is present. ''' assert isinstance(original, Transformable) try: # since we're going to require add anyway, we're happy to take # other inputs, whether add is required or not. (use, regexps) = \ RegexpContainer.to_regexps(use, matchers, add_reqd=None) # if we have regexp sub-expressions, join them regexp = Sequence(regexps, alphabet) log.debug(format('And: cloning {0}', regexp)) if use and len(original.wrapper.functions) > 1 \ and original.wrapper.functions[0] is add: # we have additional functions, so cannot take regexp higher, # but use is True, so return a new matcher. # hack to copy across other functions original.wrapper = \ TransformationWrapper(original.wrapper.functions[1:]) log.debug('And: OK (final)') # NEED TEST FOR THIS return single(alphabet, original, regexp, matcher_type) elif len(original.wrapper.functions) == 1 \ and original.wrapper.functions[0] is add: # OR JUST ONE? # lucky! we just combine and continue log.debug('And: OK') return RegexpContainer.build(original, regexp, alphabet, matcher_type, use, transform=False) elif not original.wrapper: # regexp can't return multiple values, so hope that we have # an add log.debug('And: add required') return RegexpContainer.build(original, regexp, alphabet, matcher_type, use, add_reqd=True) else: log.debug( format('And: wrong transformation: {0!r}', original.wrapper)) return original except Unsuitable: log.debug(format('And: not rewritten: {0}', original)) return original
def single(alphabet, node, regexp, matcher_type, transform=True): ''' Create a matcher for the given regular expression. ''' # avoid dependency loops from lepl.matchers.transform import TransformationWrapper matcher = matcher_type(regexp, alphabet) copy_standard_attributes(node, matcher, describe=False, transform=transform) return matcher.precompose(TransformationWrapper(empty_adapter))
def clone_transform(use, original, matcher, wrapper, _raw=False, _args=False): ''' We can assume that wrapper is a transformation. add joins into a sequence. ''' assert isinstance(wrapper, TransformationWrapper) try: # this is the only place add is required (use, [regexp]) = RegexpContainer.to_regexps(use, [matcher], add_reqd=True) log.debug(format('Transform: cloning {0}', regexp)) if use and len(wrapper.functions) > 1 \ and wrapper.functions[0] is add: # we have additional functions, so cannot take regexp higher, # but use is True, so return a new matcher. # hack to copy across other functions original.wrapper = \ TransformationWrapper().extend(wrapper.functions[1:]) log.debug('Transform: OK (final)') # NEED TEST FOR THIS return single(alphabet, original, regexp, matcher_type) elif len(wrapper.functions) == 1 and wrapper.functions[0] is add: # exactly what we wanted! combine and continue log.debug('Transform: OK') return RegexpContainer.build(original, regexp, alphabet, matcher_type, use, transform=False) elif not wrapper: # we're just forwarding the add_reqd from before here log.debug('Transform: empty, add required') return RegexpContainer(original, regexp, use, add_reqd=True) else: log.debug( format('Transform: wrong transformation: {0!r}', original.wrapper)) return original except Unsuitable: log.debug(format('Transform: not rewritten: {0}', original)) return original
def __init__(self, function=None): from lepl.matchers.transform import TransformationWrapper super(Transformable, self).__init__() if not isinstance(function, TransformationWrapper): function = TransformationWrapper(function) self.wrapper = function
def Add(matcher): ''' Join tokens in the result using the "+" operator (**+**). This joins strings and merges lists. ''' return Apply(matcher, TransformationWrapper(add))