Example #1
0
 def namer(stream_in, matcher):
     try:
         (result, stream_out) = matcher()
     except StopIteration:
         if show_failures:
             stream = \
                 _adjust(fmt('stream = {rest}', **s_kargs(stream_in)), 
                         right) 
             str_name = _adjust(name, left // 4, True, True)
             match = _adjust(fmt(' {0} failed', str_name), left, True)
             # Python bug #4618
             print(match + ' ' + stream, file=out, end=str('\n'))
         raise StopIteration
     else:
         try:
             try:
                 rest = fmt('{rest}', **s_kargs(stream_out))
             except StopIteration:
                 rest = '<EOS>'
             stream = _adjust(fmt('stream = {0}', rest), right) 
             str_name = _adjust(name, left // 4, True, True)
             match = _adjust(fmt(' {0} = {1}', str_name, result), left, True)
             # Python bug #4618
             print(match + ' ' + stream, file=out, end=str('\n'))
             return (result, stream_out)
         except Exception as e:
             print('Error in trace', file=out, end=str('\n'))
             print(repr(e), file=out, end=str('\n'))
             return (result, stream_out)
Example #2
0
 def namer(stream_in, matcher):
     try:
         (result, stream_out) = matcher()
     except StopIteration:
         if show_failures:
             stream = \
                 _adjust(fmt('stream = {rest}', **s_kargs(stream_in)),
                         right)
             str_name = _adjust(name, left // 4, True, True)
             match = _adjust(fmt(' {0} failed', str_name), left, True)
             # Python bug #4618
             print(match + ' ' + stream, file=out, end=str('\n'))
         raise StopIteration
     else:
         try:
             try:
                 rest = fmt('{rest}', **s_kargs(stream_out))
             except StopIteration:
                 rest = '<EOS>'
             stream = _adjust(fmt('stream = {0}', rest), right)
             str_name = _adjust(name, left // 4, True, True)
             match = _adjust(fmt(' {0} = {1}', str_name, result), left,
                             True)
             # Python bug #4618
             print(match + ' ' + stream, file=out, end=str('\n'))
             return (result, stream_out)
         except Exception as e:
             print('Error in trace', file=out, end=str('\n'))
             print(repr(e), file=out, end=str('\n'))
             return (result, stream_out)
Example #3
0
    def test_random(self):
        '''
        Compares lepl + python expressions.  This runs 'til it fails, and it
        always does fail, because lepl's expressions are guaranteed greedy
        while python's aren't.  This is "normal" (Perl is the same as Python)
        but I cannot fathom why it should be - it seems *harder* to make them
        work that way... 
        '''
        #basicConfig(level=DEBUG)
        log = getLogger('lepl.regexp._test.random')
        match_alphabet = '012'
        string_alphabet = '013'
        for _ in range(100):
            expression = random_expression(3, match_alphabet) 
            string = random_string(3, string_alphabet)
            matcher = DfaRegexp(expression)
#            matcher = NfaRegexp(expression)
            matcher.config.no_full_first_match()
            lepl_result = matcher.parse(string)
            if lepl_result:
                lepl_result = lepl_result[0]
            log.debug(fmt('{0} {1} {2}', expression, string, lepl_result))
            try:
                python_result = compile_(expression).match(string) 
                if python_result:
                    python_result = python_result.group()
                assert lepl_result == python_result, \
                    fmt('{0} != {1}\n{2} {3}', 
                           lepl_result, python_result, expression, string)
            except:
                (e, v, _t) = exc_info()
                if repr(v) == "error('nothing to repeat',)":
                    pass
                else:
                    raise e
Example #4
0
 def __str__(self):
     '''
     Example:
     0: 3, 4; 1: 2; 2(Tk1); 3: [{u'\x00'}-`b-{u'\U0010ffff'}]->3, 1; 
     4: {$}->5, 7; 5: 6; 6($); 7: {^}->10; 8: 9; 9(^); 10: 11; 
     11: [      ]->11, 8
     
     Node 0 leads to 3 and 4 (both empty)
     Node 1 leads to 2 (empty)
     Node 2 is terminal, labelled with "Tk1"
     Node 3 loops back to 3 for a character in the given range, or to 1
     etc.
     '''
     lines = []
     for node in self:
         edges = []
         for (dest, edge) in self.transitions(node):
             edges.append(fmt('{0}->{1}', edge, dest))
         for dest in self.empty_transitions(node):
             edges.append(str(dest))
         label = '' if self.terminal(node) is None \
                    else fmt('({0})', self.terminal(node))
         if edges:
             lines.append(
                 fmt('{0}{1}: {2}', node, label, ', '.join(edges)))
         else:
             lines.append(fmt('{0}{1}', node, label))
     return '; '.join(lines)
Example #5
0
 def __add_limited(self, reference):
     '''
     Add the new reference, discarding an old entry if possible.
     '''
     while reference:
         candidate = heappushpop(self.__queue, reference)
         self._debug(fmt('Exchanged {0} for {1}', reference, candidate))
         if candidate.order_epoch == self.epoch:
             # even the oldest generator is current
             break
         elif candidate.deletable(self.epoch):
             self._debug(fmt('Closing {0}', candidate))
             generator = candidate.generator
             if generator:
                 del self.__known[generator]
             candidate.close()
             return
         else:
             # try again (candidate has been updated)
             reference = candidate
     # if we are here, queue is too small
     heappush(self.__queue, candidate)
     # this is currently 1 too small, and zero means unlimited, so
     # doubling should always be sufficient.
     self.queue_len = self.queue_len * 2
     self._warn(fmt('Queue is too small - extending to {0}',
                    self.queue_len))
Example #6
0
 def __str__(self):
     generator = self.generator
     if generator:
         return fmt('{0} ({1:d}/{2:d})', self.__describe, self.order_epoch,
                    self.__last_known_epoch)
     else:
         return fmt('Empty ref to {0}', self.__describe)
Example #7
0
 def fmt_intervals(self, intervals):
     '''
     Hide unicode chars because of some strange error that occurs with
     Python2.6 on the command line.
     
     This is in StrAlphabet, but for ASCII makes no difference.  Having it
     here helps LineAwareAlphabet work (the whole idea of subclassing
     alphabets etc is not so great).
     '''
     def pretty(c):
         x = self._escape_char(c)
         if len(x) > 1 or 32 <= ord(x) <= 127:
             return str(x)
         elif ord(c) < 0x100:
             return fmt('\\x{0:02x}', ord(c)) 
         elif ord(c) < 0x10000:
             return fmt('\\u{0:04x}', ord(c)) 
         else:
             return fmt('\\U{0:08x}', ord(c)) 
     ranges = []
     if len(intervals) == 1:
         if intervals[0][0] == intervals[0][1]:
             return self._escape_char(intervals[0][0])
         elif intervals[0][0] == self.min and intervals[0][1] == self.max:
             return '.'
     # pylint: disable-msg=C0103
     # (sorry. but i use this (a, b) convention throughout the regexp lib) 
     for (a, b) in intervals:
         if a == b:
             ranges.append(pretty(a))
         else:
             ranges.append(fmt('{0!s}-{1!s}', pretty(a), pretty(b)))
     return fmt('[{0}]', self.join(ranges))
Example #8
0
 def _match(self, stream_in):
     '''
     Check that we match the current level
     '''
     try:
         generator = super(LineStart, self)._match(stream_in)
         while True:
             (indent, stream) = yield generator
             self._debug(fmt('SOL {0!r}', indent))
             if indent and indent[0] and indent[0][-1] == '\n': 
                 indent[0] = indent[0][:-1]
             # if we're not doing indents, this is empty
             if not self.indent:
                 yield ([], stream)
             # if we are doing indents, we need a match or NO_BLOCKS
             elif self._current_indent == NO_BLOCKS or \
                     len(indent[0]) == self._current_indent:
                 yield (indent, stream)
             else:
                 self._debug(
                     fmt('Incorrect indent ({0:d} != len({1!r}), {2:d})',
                            self._current_indent, indent[0], 
                            len(indent[0])))
     except StopIteration:
         pass
Example #9
0
    def fmt_intervals(self, intervals):
        '''
        Hide unicode chars because of some strange error that occurs with
        Python2.6 on the command line.
        
        This is in StrAlphabet, but for ASCII makes no difference.  Having it
        here helps LineAwareAlphabet work (the whole idea of subclassing
        alphabets etc is not so great).
        '''
        def pretty(c):
            x = self._escape_char(c)
            if len(x) > 1 or 32 <= ord(x) <= 127:
                return str(x)
            elif ord(c) < 0x100:
                return fmt('\\x{0:02x}', ord(c))
            elif ord(c) < 0x10000:
                return fmt('\\u{0:04x}', ord(c))
            else:
                return fmt('\\U{0:08x}', ord(c))

        ranges = []
        if len(intervals) == 1:
            if intervals[0][0] == intervals[0][1]:
                return self._escape_char(intervals[0][0])
            elif intervals[0][0] == self.min and intervals[0][1] == self.max:
                return '.'
        # pylint: disable-msg=C0103
        # (sorry. but i use this (a, b) convention throughout the regexp lib)
        for (a, b) in intervals:
            if a == b:
                ranges.append(pretty(a))
            else:
                ranges.append(fmt('{0!s}-{1!s}', pretty(a), pretty(b)))
        return fmt('[{0}]', self.join(ranges))
Example #10
0
 def test_random(self):
     '''
     Compares lepl + python expressions.  This runs 'til it fails, and it
     always does fail, because lepl's expressions are guaranteed greedy
     while python's aren't.  This is "normal" (Perl is the same as Python)
     but I cannot fathom why it should be - it seems *harder* to make them
     work that way... 
     '''
     #basicConfig(level=DEBUG)
     log = getLogger('lepl.regexp._test.random')
     match_alphabet = '012'
     string_alphabet = '013'
     for _ in range(100):
         expression = random_expression(3, match_alphabet)
         string = random_string(3, string_alphabet)
         matcher = DfaRegexp(expression)
         #            matcher = NfaRegexp(expression)
         matcher.config.no_full_first_match()
         lepl_result = matcher.parse(string)
         if lepl_result:
             lepl_result = lepl_result[0]
         log.debug(fmt('{0} {1} {2}', expression, string, lepl_result))
         try:
             python_result = compile_(expression).match(string)
             if python_result:
                 python_result = python_result.group()
             assert lepl_result == python_result, \
                 fmt('{0} != {1}\n{2} {3}',
                        lepl_result, python_result, expression, string)
         except:
             (e, v, _t) = exc_info()
             if repr(v) == "error('nothing to repeat',)":
                 pass
             else:
                 raise e
Example #11
0
 def to_regexps(cls, use, possibles, have_add=False):
     '''
     Convert to regular expressions.
     
     `have_add` indicaes whether the caller can supply an "add".
     None - caller doesn't care what lower code needed.
     True - caller has add, and caller should need that.
     False - caller doesn't have add, and caller should not need it.
     '''
     regexps = []
     for possible in possibles:
         if isinstance(possible, RegexpContainer):
             cls.log.debug(fmt('unpacking: {0!s}', possible))
             if have_add is None or possible.add_reqd == have_add:
                 regexps.append(possible.regexp)
                 # this flag indicates that it's "worth" using the regexp
                 # so we "inherit"
                 use = use or possible.use
             else:
                 raise Unsuitable('Add inconsistent.')
         else:
             cls.log.debug(fmt('cannot unpack: {0!s}', 
                                  possible.__class__))
             raise Unsuitable('Not a container.')
     return use, regexps
Example #12
0
 def next(self, state, count=1):
     
     def add_self(response):
         '''
         Replace the previous helper with this one, which will then 
         delegate to the previous when needed.
         '''
         ((tokens, token), (state, _)) = response
         self._debug(fmt('Return {0}', tokens))
         return ((tokens, token), (state, self))
     
     if count != 1:
         raise TypeError('Filtered tokens must be read singly')
     discard = list(reversed(self._ids))
     start = state
     while discard:
         ((tokens, _), (state, _)) = \
                     super(FilteredTokenHelper, self).next(state)
         if discard[-1] in tokens:
             self._debug(fmt('Discarding token {0}', discard[-1]))
             discard.pop()
         else:
             self._debug(fmt('Failed to discard token {0}: {1}', 
                                discard[-1], tokens))
             return add_self(super(FilteredTokenHelper, self).next(start))
     return add_self(super(FilteredTokenHelper, self).next(state))
Example #13
0
 def _tokens(self, stream, max):
     '''
     Generate tokens, on demand.
     '''
     try:
         id_ = s_id(stream)
         while not s_empty(stream):
             # avoid conflicts between tokens
             id_ += 1
             try:
                 (terminals, match, next_stream) = \
                                     self.t_regexp.match(stream)
                 self._debug(fmt('Token: {0!r} {1!r} {2!s}',
                                 terminals, match, s_debug(stream)))
                 yield (terminals, s_stream(stream, match, max=max, id_=id_))
             except TypeError:
                 (terminals, _size, next_stream) = \
                                     self.s_regexp.size_match(stream)
                 self._debug(fmt('Space: {0!r} {1!s}',
                                 terminals, s_debug(stream)))
             stream = next_stream
     except TypeError:
         raise RuntimeLexerError(
             s_fmt(stream, 
                   'No token for {rest} at {location} of {text}.'))
Example #14
0
 def __add_limited(self, reference):
     '''
     Add the new reference, discarding an old entry if possible.
     '''
     while reference:
         candidate = heappushpop(self.__queue, reference)
         self._debug(fmt('Exchanged {0} for {1}', reference, candidate))
         if candidate.order_epoch == self.epoch:
             # even the oldest generator is current
             break
         elif candidate.deletable(self.epoch):
             self._debug(fmt('Closing {0}', candidate))
             generator = candidate.generator
             if generator:
                 del self.__known[generator]
             candidate.close()
             return
         else:
             # try again (candidate has been updated)
             reference = candidate
     # if we are here, queue is too small
     heappush(self.__queue, candidate)
     # this is currently 1 too small, and zero means unlimited, so
     # doubling should always be sufficient.
     self.queue_len *= 2
     self._warn(fmt('Queue is too small - extending to {0}', self.queue_len))
Example #15
0
    def next(self, state, count=1):
        def add_self(response):
            '''
            Replace the previous helper with this one, which will then 
            delegate to the previous when needed.
            '''
            ((tokens, token), (state, _)) = response
            self._debug(fmt('Return {0}', tokens))
            return ((tokens, token), (state, self))

        if count != 1:
            raise TypeError('Filtered tokens must be read singly')
        discard = list(reversed(self._ids))
        start = state
        while discard:
            ((tokens, _), (state, _)) = \
                        super(FilteredTokenHelper, self).next(state)
            if discard[-1] in tokens:
                self._debug(fmt('Discarding token {0}', discard[-1]))
                discard.pop()
            else:
                self._debug(
                    fmt('Failed to discard token {0}: {1}', discard[-1],
                        tokens))
                return add_self(super(FilteredTokenHelper, self).next(start))
        return add_self(super(FilteredTokenHelper, self).next(state))
Example #16
0
 def _tokens(self, stream, max):
     '''
     Generate tokens, on demand.
     '''
     try:
         id_ = s_id(stream)
         while not s_empty(stream):
             # avoid conflicts between tokens
             id_ += 1
             try:
                 (terminals, match, next_stream) = \
                                     self.t_regexp.match(stream)
                 self._debug(
                     fmt('Token: {0!r} {1!r} {2!s}', terminals, match,
                         s_debug(stream)))
                 yield (terminals, s_stream(stream, match, max=max,
                                            id_=id_))
             except TypeError:
                 (terminals, _size, next_stream) = \
                                     self.s_regexp.size_match(stream)
                 self._debug(
                     fmt('Space: {0!r} {1!s}', terminals, s_debug(stream)))
             stream = next_stream
     except TypeError:
         raise RuntimeLexerError(
             s_fmt(stream, 'No token for {rest} at {location} of {text}.'))
Example #17
0
 def clone_wrapper(use, original, *args, **kargs):
     factory = original.factory
     if factory in map_:
         log.debug(fmt('Found {0}', factory))
         return map_[factory](use, original, *args, **kargs)
     else:
         log.debug(fmt('No clone for {0}, {1}', factory, map_.keys()))
         return original
Example #18
0
 def clone_wrapper(use, original, *args, **kargs):
     factory = original.factory
     if factory in map_:
         log.debug(fmt('Found {0}', factory))
         return map_[factory](use, original, *args, **kargs)
     else:
         log.debug(fmt('No clone for {0}, {1}', factory, map_.keys()))
         return original
Example #19
0
 def _typename(self, instance):
     if isinstance(instance, list) and instance:
         return fmt('<list{0}>', self._typename(instance[0]))
     else:
         try:
             return fmt('<{0}>', instance.__class__.__name__)
         except:
             return '<unknown>'
Example #20
0
 def record_success(count, stream_in, result):
     (value, stream_out) = result
     count_desc = fmt(' ({0})', count) if count > 1 else ''
     # Python bug #4618
     print(fmt('{0}{1} = {2}\n    {3} -> {4}', 
                  name, count_desc, value, 
                  fmt_stream(stream_in), fmt_stream(stream_out)), 
           file=out, end=str('\n'))
Example #21
0
 def _typename(self, instance):
     if isinstance(instance, list) and instance:
         return fmt('<list{0}>', self._typename(instance[0]))
     else:
         try:
             return fmt('<{0}>', instance.__class__.__name__)
         except:
             return '<unknown>'
Example #22
0
 def record_success(count, stream_in, result):
     (value, stream_out) = result
     count_desc = fmt(' ({0})', count) if count > 1 else ''
     # Python bug #4618
     print(fmt('{0}{1} = {2}\n    {3} -> {4}', name, count_desc, value,
               fmt_stream(stream_in), fmt_stream(stream_out)),
           file=out,
           end=str('\n'))
Example #23
0
 def __str__(self):
     generator = self.generator
     if generator:
         return fmt('{0} ({1:d}/{2:d})',
                       self.__describe, self.order_epoch, 
                       self.__last_known_epoch)
     else:
         return fmt('Empty ref to {0}', self.__describe)
Example #24
0
 def raise_(self, value):
     '''
     Log when enabled.
     '''
     if self.enabled > 0:
         if type(value) is StopIteration:
             self._info(self.fmt_final_result(fmt('raise {0!r}', value)))
         else:
             self._warn(self.fmt_final_result(fmt('raise {0!r}', value)))
Example #25
0
 def __str__(self):
     counts = fmt('total:      {total:3d}\n'
                  'leaves:     {leaves:3d}\n'
                  'duplicates: {duplicates:3d}\n', **self.__dict__)
     keys = list(self.types.keys())
     keys.sort(key=repr)
     types = '\n'.join([fmt('{0:40s}: {1:3d}', key, self.types[key])
                        for key in keys])
     return counts + types
Example #26
0
 def nfa(self):
     '''
     Generate a NFA-based matcher.
     '''
     self._debug(fmt('compiling to nfa: {0}', self))
     graph = NfaGraph(self.alphabet)
     self.expression.build(graph, graph.new_node(), graph.new_node())
     self._debug(fmt('nfa graph: {0}', graph))
     return NfaPattern(graph, self.alphabet)
Example #27
0
 def __str__(self):
     counts = fmt('total:      {total:3d}\n'
                  'leaves:     {leaves:3d}\n'
                  'duplicates: {duplicates:3d}\n', **self.__dict__)
     keys = list(self.types.keys())
     keys.sort(key=repr)
     types = '\n'.join([fmt('{0:40s}: {1:3d}', key, self.types[key])
                        for key in keys])
     return counts + types
Example #28
0
 def raise_(self, value):
     '''
     Log when enabled.
     '''
     if self.enabled > 0:
         if type(value) is StopIteration:
             self._info(self.fmt_final_result(fmt('raise {0!r}', value)))
         else:
             self._warn(self.fmt_final_result(fmt('raise {0!r}', value)))
Example #29
0
 def before_throw(self, generator, value):
     '''
     Log when enabled.
     '''
     if self.enabled > 0:
         self.generator = generator
         if type(value) is StopIteration:
             self.action = fmt('stop  ->  {0}', generator)
         else:
             self.action = fmt('{1!r}  ->  {0}', generator, value)
Example #30
0
 def pretty(c):
     x = self._escape_char(c)
     if len(x) > 1 or 32 <= ord(x) <= 127:
         return str(x)
     elif ord(c) < 0x100:
         return fmt('\\x{0:02x}', ord(c))
     elif ord(c) < 0x10000:
         return fmt('\\u{0:04x}', ord(c))
     else:
         return fmt('\\U{0:08x}', ord(c))
Example #31
0
 def pretty(c):
     x = self._escape_char(c)
     if len(x) > 1 or 32 <= ord(x) <= 127:
         return str(x)
     elif ord(c) < 0x100:
         return fmt('\\x{0:02x}', ord(c)) 
     elif ord(c) < 0x10000:
         return fmt('\\u{0:04x}', ord(c)) 
     else:
         return fmt('\\U{0:08x}', ord(c)) 
Example #32
0
 def before_throw(self, generator, value):
     '''
     Log when enabled.
     '''
     if self.enabled > 0:
         self.generator = generator
         if type(value) is StopIteration:
             self.action = fmt('stop  ->  {0}', generator)
         else:
             self.action = fmt('{1!r}  ->  {0}', generator, value)
Example #33
0
    def __args_as_attributes(self):
        '''
        Validate the arguments passed to the constructor against the spec for 
        the factory (necessary because we use *args and so the user doesn't
        get the feedback they will expect if they make a mistake).  As a side
        effect we also associated arguments with names and expand defaults
        so that attributes are more predictable.
        '''
        try:
            # function wrapper, so we have two levels, and we must construct
            # a new, empty function (ie this is a fake function that helps
            # us use the code below, even though there's no arguments because
            # factory is a dummy generated in make_factory below)
            def empty():
                return

            document(empty, self.factory.factory)
            spec = getargspec(empty)
        except:
            spec = getargspec(self.factory)
        names = list(spec.args)
        defaults = dict(
            zip(names[::-1], spec.defaults[::-1] if spec.defaults else []))
        for name in names:
            if name in self.__kargs:
                self._karg(**{name: self.__kargs[name]})
                del self.__kargs[name]
            elif self.__args:
                self._arg(**{name: self.__args[0]})
                self.__args = self.__args[1:]
            elif name in defaults:
                self._karg(**{name: defaults[name]})
            else:
                raise TypeError(
                    fmt("No value for argument '{0}' in "
                        "{1}(...)", name, self._small_str))
        if self.__args:
            if spec.varargs:
                self._args(**{spec.varargs: self.__args})
            else:
                raise TypeError(
                    fmt(
                        "No parameter matches the argument "
                        "{0!r} in {1}(...)", self.__args[0], self._small_str))
        if self.__kargs:
            if spec.keywords:
                self.__kargs(**{spec.keywords: self.__kargs})
            else:
                name = list(self.__kargs.keys())[0]
                value = self.__kargs[name]
                raise TypeError(
                    fmt(
                        "No parameter matches the argument "
                        "{0}={1!r} in {2}(...)", name, value, self._small_str))
Example #34
0
 def dfa(self):
     '''
     Generate a DFA-based matcher (faster than NFA, but returns only a
     single, greedy match).
     '''
     self._debug(fmt('compiling to dfa: {0}', self))
     ngraph = NfaGraph(self.alphabet)
     self.expression.build(ngraph, ngraph.new_node(), ngraph.new_node())
     self._debug(fmt('nfa graph: {0}', ngraph))
     dgraph = NfaToDfa(ngraph, self.alphabet).dfa
     self._debug(fmt('dfa graph: {0}', dgraph))
     return DfaPattern(dgraph, self.alphabet)
Example #35
0
 def __str__(self):
     lines = []
     for node in self:
         edges = []
         for (dest, edge) in self.transitions(node):
             edges.append(fmt('{0}->{1}', edge, dest))
         nodes = [n for n in self.nfa_nodes(node)]
         edges = ' ' + ','.join(edges) if edges else ''
         labels = list(self.terminals(node))
         labels = fmt('({0})', ','.join(str(label) for label in labels)) \
                  if labels else ''
         lines.append(fmt('{0}{1}: {2}{3}', node, labels, nodes, edges))
     return '; '.join(lines)
Example #36
0
 def __args_as_attributes(self):
     '''
     Validate the arguments passed to the constructor against the spec for 
     the factory (necessary because we use *args and so the user doesn't
     get the feedback they will expect if they make a mistake).  As a side
     effect we also associated arguments with names and expand defaults
     so that attributes are more predictable.
     '''
     try:
         # function wrapper, so we have two levels, and we must construct
         # a new, empty function (ie this is a fake function that helps
         # us use the code below, even though there's no arguments because
         # factory is a dummy generated in make_factory below)
         def empty(): return
         document(empty, self.factory.factory)
         spec = getargspec(empty)
     except:
         spec = getargspec(self.factory)
     names = list(spec.args)
     defaults = dict(zip(names[::-1], spec.defaults[::-1] if spec.defaults else []))
     for name in names:
         if name in self.__kargs:
             self._karg(**{name: self.__kargs[name]})
             del self.__kargs[name]
         elif self.__args:
             self._arg(**{name: self.__args[0]})
             self.__args = self.__args[1:]
         elif name in defaults:
             self._karg(**{name: defaults[name]})
         else:
             raise TypeError(fmt("No value for argument '{0}' in "
                                    "{1}(...)", 
                                    name, self._small_str))
     if self.__args:
         if spec.varargs:
             self._args(**{spec.varargs: self.__args})
         else:
             raise TypeError(fmt("No parameter matches the argument "
                                    "{0!r} in {1}(...)", 
                                    self.__args[0], self._small_str))
     if self.__kargs:
         if spec.keywords:
             self.__kargs(**{spec.keywords: self.__kargs})
         else:
             name = list(self.__kargs.keys())[0]
             value = self.__kargs[name]
             raise TypeError(fmt("No parameter matches the argument "
                                    "{0}={1!r} in {2}(...)", 
                                    name, value, self._small_str))
Example #37
0
 def _fmt(self,
          sequence,
          offset,
          max_len=60,
          left='',
          right='',
          index=True):
     '''fmt a possibly long subsection of data.'''
     if not sequence:
         if index:
             return fmt('{0!r}[{1:d}]', sequence, offset)
         else:
             return fmt('{0!r}', sequence)
     if 0 <= offset < len(sequence):
         centre = offset
     elif offset > 0:
         centre = len(sequence) - 1
     else:
         centre = 0
     begin, end = centre, centre + 1
     longest = None
     while True:
         if begin > 0:
             if end < len(sequence):
                 template = '{0!s}...{1!s}...{2!s}'
             else:
                 template = '{0!s}...{1!s}{2!s}'
         else:
             if end < len(sequence):
                 template = '{0!s}{1!s}...{2!s}'
             else:
                 template = '{0!s}{1!s}{2!s}'
         body = repr(sequence[begin:end])[len(left):]
         if len(right):
             body = body[:-len(right)]
         text = fmt(template, left, body, right, offset)
         if index:
             text = fmt('{0!s}[{1:d}:]', text, offset)
         if longest is None or len(text) <= max_len:
             longest = text
         if len(text) > max_len:
             return longest
         begin -= 1
         end += 1
         if begin < 0 and end > len(sequence):
             return longest
         begin = max(begin, 0)
         end = min(end, len(sequence))
Example #38
0
 def _format_repr(self, indent, key, contents):
     return fmt('{0}{1}{2}({3}{4})', 
                   ' ' * indent,
                   key + '=' if key else '',
                   self._small_str,
                   '' if self._fmt_compact else '\n',
                   ',\n'.join(contents))
Example #39
0
 def __init__(self, matcher, tokens, alphabet, discard, 
               t_regexp=None, s_regexp=None):
     '''
     matcher is the head of the original matcher graph, which will be called
     with a tokenised stream. 
     
     tokens is the set of `Token` instances that define the lexer.
     
     alphabet is the alphabet for which the regexps are defined.
     
     discard is the regular expression for spaces (which are silently
     dropped if not token can be matcher).
     
     t_regexp and s_regexp are internally compiled state, used in cloning,
     and should not be provided by non-cloning callers.
     '''
     super(Lexer, self).__init__(TOKENS, TokenNamespace)
     if t_regexp is None:
         unique = {}
         for token in tokens:
             token.compile(alphabet)
             self._debug(fmt('Token: {0}', token))
             # this just reduces the work for the regexp compiler
             unique[token.id_] = token
         t_regexp = Compiler.multiple(alphabet, 
                         [(t.id_, t.regexp) 
                          for t in unique.values() if t.regexp is not None]).dfa()
     if s_regexp is None and discard is not None:
         s_regexp = Compiler.single(alphabet, discard).dfa()
     self._arg(matcher=matcher)
     self._arg(tokens=tokens)
     self._arg(alphabet=alphabet)
     self._arg(discard=discard)
     self._karg(t_regexp=t_regexp)
     self._karg(s_regexp=s_regexp)
Example #40
0
 def build(cls,
           node,
           regexp,
           alphabet,
           regexp_type,
           use,
           add_reqd=False,
           wrapper=None):
     '''
     Construct a container or matcher.
     '''
     if use and not add_reqd:
         matcher = single(alphabet, node, regexp, regexp_type, wrapper)
         # if matcher is a Transformable with a Transformation other than
         # the standard empty_adapter then we must stop
         if len(matcher.wrapper.functions) > 1:
             cls.log.debug(fmt('Force matcher: {0}', matcher.wrapper))
             return matcher
     else:
         # not good enough to have a regexp as default, so either force
         # the original matcher if it has transforms, or keep going in the
         # hope we can get more complex later
         matcher = node
         if hasattr(matcher, 'wrapper') and matcher.wrapper:
             return matcher
     return RegexpContainer(matcher, regexp, use, add_reqd)
Example #41
0
def RepeatWrapper(matcher, start, stop, step, separator, add, reduce):
    '''Parse `step` if it is a string.'''
    # Handle circular dependencies
    from lepl.matchers.derived import Repeat
    try:
        int(step) # if this works, we may have a var, so keep the instance
        limit = step
        algorithm = DEPTH_FIRST
    except ValueError:
        if (isinstance(step, basestring)):
            limit = None
            algorithm = None
            while step:
                match = DIGITS.match(step)
                if match:
                    if limit is None:
                        limit = int(match.group(1))
                        step = match.group(2)
                    else:
                        raise TypeError(fmt('Cannot parse limit/algorithm for []: {}',
                                            step))
                else:
                    if algorithm is None:
                        algorithm = step[0]
                        step = step[1:]
        else:
            raise TypeError('The step of [...] must be an integer limit, or a '
                            'string to select the algorithm, or both as a string '
                            'like "d1" for a single value, depth first')
    return Repeat(matcher, start=start, stop=stop, limit=limit, 
                  algorithm=algorithm, separator=separator, add_=add,
                  reduce=reduce)
Example #42
0
 def before_next(self, generator):
     '''
     Log when enabled.
     '''
     if self.enabled > 0:
         self.generator = generator
         self.action = fmt('next({0})', generator)
Example #43
0
def find_tokens(matcher):
    '''
    Returns a set of Tokens.  Also asserts that children of tokens are
    not themselves Tokens. 
    
    Should we also check that a Token occurs somewhere on every path to a
    leaf node?
    '''
    (tokens, visited, non_tokens) = (set(), set(), set())
    stack = deque([matcher])
    while stack:
        matcher = stack.popleft()
        if matcher not in visited:
            if is_child(matcher, NonToken):
                non_tokens.add(matcher)
            if isinstance(matcher, BaseToken):
                tokens.add(matcher)
                if matcher.content:
                    assert_not_token(matcher.content, visited)
            else:
                for child in matcher:
                    if isinstance(child, Matcher):
                        stack.append(child)
            visited.add(matcher)
    if tokens and non_tokens:
        raise LexerError(
            fmt('The grammar contains a mix of Tokens and non-Token '
                   'matchers at the top level.  If Tokens are used then '
                   'non-token matchers that consume input must only '
                   'appear "inside" Tokens.  The non-Token matchers '
                   'include: {0}.',
                   '; '.join(str(n) for n in non_tokens)))
    return tokens
Example #44
0
 def clone_transform(use, original, matcher, wrapper):
     '''
     We can assume that wrapper is a transformation.  Add joins into
     a sequence.
     '''
     if original.wrapper:
         if original.wrapper.functions[0] is add:
             have_add = True
             wrapper = original.wrapper.functions[1:]
         else:
             have_add = False
             wrapper = original.wrapper.functions
     else:
         # punt to next level
         return matcher
     (use, [regexp]) = \
         RegexpContainer.to_regexps(use, [matcher], have_add=have_add)
     log.debug(fmt('Transform: cloning {0}', regexp))
     return RegexpContainer.build(original,
                                  regexp,
                                  alphabet_,
                                  regexp_type,
                                  use,
                                  add_reqd=False,
                                  wrapper=wrapper)
Example #45
0
 def __init__(self, conservative=None, left=None, right=None, d=0):
     super(AutoMemoize, self).__init__(Rewriter.MEMOIZE,
         fmt('AutoMemoize({0}, {1}, {2})', conservative, left, right))
     self.conservative = conservative
     self.left = left
     self.right = right
     self.d = d
Example #46
0
    def __init__(self, matcher, tokens, alphabet, discard,
                 t_regexp=None, s_regexp=None):
        '''
        matcher is the head of the original matcher graph, which will be called
        with a tokenised stream.

        tokens is the set of `Token` instances that define the lexer.

        alphabet is the alphabet for which the regexps are defined.

        discard is the regular expression for spaces (which are silently
        dropped if not token can be matcher).

        t_regexp and s_regexp are internally compiled state, used in cloning,
        and should not be provided by non-cloning callers.
        '''
        super(Lexer, self).__init__(TOKENS, TokenNamespace)
        if t_regexp is None:
            unique = {}
            for token in tokens:
                token.compile(alphabet)
                self._debug(fmt('Token: {0}', token))
                # this just reduces the work for the regexp compiler
                unique[token.id_] = token
            t_regexp = Compiler.multiple(alphabet,
                [(t.id_, t.regexp)
                for t in unique.values() if t.regexp is not None]).dfa()
        if s_regexp is None and discard is not None:
            s_regexp = Compiler.single(alphabet, discard).dfa()
        self._arg(matcher=matcher)
        self._arg(tokens=tokens)
        self._arg(alphabet=alphabet)
        self._arg(discard=discard)
        self._karg(t_regexp=t_regexp)
        self._karg(s_regexp=s_regexp)
Example #47
0
 def new_clone(i, j, node, args, kargs):
     type_, ok = None, False
     for parent in self.spec:
         if is_child(node, parent):
             type_ = self.spec[parent]
     if type_:
         ok = True
         for arg in args:
             if isinstance(arg, Matcher) and not \
                     isinstance(arg, NoTrampoline):
                 ok = False
         for name in kargs:
             arg = kargs[name]
             if isinstance(arg, Matcher) and not \
                     isinstance(arg, NoTrampoline):
                 ok = False
     if not ok:
         type_ = type(node)
     try:
         copy = type_(*args, **kargs)
         copy_standard_attributes(node, copy)
         return copy
     except TypeError as err:
         raise TypeError(
             fmt('Error cloning {0} with ({1}, {2}): {3}', type_, args,
                 kargs, err))
Example #48
0
 def __init__(self, type_, **extra_kargs):
     super(SetArguments,
           self).__init__(Rewriter.SET_ARGUMENTS,
                          fmt('SetArguments({0}, {1})', type_, extra_kargs),
                          False)
     self.type = type_
     self.extra_kargs = extra_kargs
Example #49
0
 def before_next(self, generator):
     '''
     Log when enabled.
     '''
     if self.enabled > 0:
         self.generator = generator
         self.action = fmt('next({0})', generator)
Example #50
0
 def push_level(self, level):
     '''
     Add a new indent level.
     '''
     self.__stack.append(level)
     self.__state[BlockMonitor] = level
     self._debug(fmt('Indent -> {0:d}', level))
Example #51
0
 def before_send(self, generator, value):
     '''
     Log when enabled.
     '''
     if self.enabled > 0:
         self.generator = generator
         self.action = fmt('{1!r}  ->  {0}', generator, value)
Example #52
0
 def push_level(self, level):
     '''
     Add a new indent level.
     '''
     self.__stack.append(level)
     self.__state[BlockMonitor] = level
     self._debug(fmt('Indent -> {0:d}', level))
Example #53
0
 def __init__(self, conservative=None, left=None, right=None, d=0):
     super(AutoMemoize, self).__init__(Rewriter.MEMOIZE,
         fmt('AutoMemoize({0}, {1}, {2})', conservative, left, right))
     self.conservative = conservative
     self.left = left
     self.right = right
     self.d = d
Example #54
0
def TraceVariables(on=True, show_failures=True, width=80, out=stderr):
    '''
    Add this as a context (`with TraceVariables():`) and you will see 
    debug logging indicating how variables are bound during matching.
    '''
    if on:
        before = _getframe(2).f_locals.copy()
    yield None
    if on:
        after = _getframe(2).f_locals
        for key in after:
            value = after[key]
            if key not in before or value != before[key]:
                try:
                    try:
                        value.wrapper.append(
                            name(key, show_failures, width, out))
                    except AttributeError:
                        value.trace_variables = name(key, show_failures, width,
                                                     out)
                except:  # what exception?
                    print(
                        'Unfortunately the following matchers cannot '
                        'be tracked:',
                        end=str('\n'))
                    print(fmt('  {0} = {1}', key, value), end=str('\n'))
Example #55
0
 def new_clone(i, j, node, args, kargs):
     type_, ok = None, False
     for parent in self.spec:
         if is_child(node, parent):
             type_ = self.spec[parent]
     if type_:
         ok = True
         for arg in args:
             if isinstance(arg, Matcher) and not \
                     isinstance(arg, NoTrampoline):
                 ok = False
         for name in kargs:
             arg = kargs[name]
             if isinstance(arg, Matcher) and not \
                     isinstance(arg, NoTrampoline):
                 ok = False
     if not ok:
         type_ = type(node)
     try:
         copy = type_(*args, **kargs)
         copy_standard_attributes(node, copy)
         return copy
     except TypeError as err:
         raise TypeError(fmt('Error cloning {0} with ({1}, {2}): {3}',
                                type_, args, kargs, err))
Example #56
0
 def before_send(self, generator, value):
     '''
     Log when enabled.
     '''
     if self.enabled > 0:
         self.generator = generator
         self.action = fmt('{1!r}  ->  {0}', generator, value)
Example #57
0
def apply_modifiers(func, args, kargs, modifiers, margs, mkargs):
    '''
    Modify values in args and kargs.
    '''
    spec = getargspec(func)
    names = list(spec.args)
    defaults = dict(
        zip(names[::-1], spec.defaults[::-1] if spec.defaults else []))
    newargs = []
    newkargs = {}
    for name in names:
        if name in kargs:
            value = kargs[name]
            if name in modifiers:
                value = modifiers[name](value)
            newkargs[name] = value
            del kargs[name]
        elif args:
            (value, args) = (args[0], args[1:])
            if name in modifiers:
                value = modifiers[name](value)
            newargs.append(value)
        elif name in defaults:
            value = defaults[name]
            if name in modifiers:
                value = modifiers[name](value)
            newkargs[name] = value
        else:
            raise TypeError(
                fmt("No value for argument '{0}' in "
                    "{1}(...)", name, func.__name__))
    # copy across varags
    if spec.varargs:
        newargs.extend(map(margs, args))
    elif args:
        raise TypeError(
            fmt("Unexpected argument {0!r} for {1}(...)", args[0],
                func.__name__))
    if spec.keywords:
        for name in kargs:
            newkargs[name] = mkargs(kargs[name])
    elif kargs:
        for name in kargs:
            raise TypeError(
                fmt("Unexpected argument {0}={1!r} for {2}(...)", name,
                    kargs[name], func.__name__))
    return (newargs, newkargs)