Source code for pushgp.push.interpreter

import numbers
import collections
import logging


logger = logging.getLogger(__name__)


[docs]class Push(collections.defaultdict): ''' The Push interpreter. The different stack types are available as dictionary keys and values. For example: >>> p = Push() >>> p['exec'] = [1, 2] >>> p Push: {'exec': [1, 2]} Each stack is implemented as a List, so any method that work on lists will work on the stacks. For example, to pop an item from a stack use the ``.pop()`` method. >>> p = Push() >>> p['exec'] = [1, 2] >>> p['exec'].pop() 2 >>> p Push: {'exec': [1]} As you can see, the top of stack is the last item in the list. To execute the ``exec`` stack, call :py:meth:`~.execute` on an instance. >>> p = Push() >>> p['exec'] = [1, 2] >>> p.execute() >>> p Push: {'int': [2, 1], 'exec': []} To push an item to the ``exec`` stack and then execute it, just call the initiated object on any number of items. >>> Push()(1, 2) Push: {'exec': [], 'int': [2, 1]} You can even chane these calls together. >>> Push()(1)(2) Push: {'exec': [], 'int': [1, 2]} '''
[docs] def __init__(self): self.default_factory = list self.stack_types = collections.OrderedDict([ [bool, 'bool'], [str, 'str'], [numbers.Integral, 'int'], [numbers.Real, 'float'], ])
[docs] def __str__(self): return 'Push: {}'.format(dict(self.items()))
[docs] def __repr__(self): return self.__str__() # return 'Push({}): {}'.format(self.stack_types, dict(self.items()))
[docs] def stack_for_item(self, item): ''' Returns the right stack name for any ``item``, using the ``stack_types`` map attribute. If no stack has this type, it will return None. ''' for item_type, stack_name in self.stack_types.items(): if isinstance(item, item_type): return stack_name
[docs] def execute(self): ''' Pops each item off the ``exec`` stack until it is empty, using the `.pop()` method. If the item is in instance in the ``stack_types`` attribute then it will be pushed to the corresponding stack. Else if it a callable is will be called with the Push object and should return a modified Push object. Else it will raise a ``TypeError`` ''' while self['exec']: logger.debug('Starting execution: %s', self) item = self['exec'].pop() literal_stack_name = self.stack_for_item(item) if literal_stack_name: self[literal_stack_name].append(item) elif callable(item): item(self) else: raise TypeError( '{}:{} is not recognized by Push'.format(type(item), item) ) logger.debug('Finished execution: %s', self)
[docs] def __call__(self, *items): ''' Pushes a list of ``items`` onto the ``exec`` stack and executes them. Uses the ._execute() method to run through the ``exec`` stack. ''' logger.debug('Pushing %s', items) self['exec'].extend(items) self.execute() return self