Source code for curry.tools.icy.repl

from . import commands
from . import options
import importlib, sys
curry = importlib.import_module(__package__[:__package__.find('.')])

__all__ = ['REPL']

def trap(fatal=False):
  def decorator(f):
    def decorated(*args, **kwds):
      try:
        f(*args, **kwds)
      except SystemExit:
        raise
      except KeyboardInterrupt:
        if fatal:
          sys.exit(1)
      except BaseException as e:
        sys.stderr.write('**** ERROR ****\n%s\n' % str(e))
        sys.stderr.flush()
        if fatal:
          sys.exit(1)
    return decorated
  return decorator

[docs] class REPL(object): '''A Curry read-eval-print loop.''' def __new__(cls, args, **kwds): self = object.__new__(cls) self.command = None self.args = None self.module = None # The argument of the last :load, for switch_backend. self.loaded = None self.action = kwds.pop('action', cls.defaultaction) self.options = options.Options(self) return self @trap(fatal=True) def __init__(self, args, **kwds): ''' Initialize the REPL. Command-line arguments are processed, and an exception is raised if any of them fail. ''' args = args[::-1] illegal = [] cmds = [] while args: command = args.pop() if not command.startswith(':'): illegal.append(command) else: subargs = [] while args: if args[-1].startswith(':'): break else: subargs.append(args.pop()) cmds += [(command, subargs)] if illegal: raise ValueError("Illegal arguments: %s" % (' '.join(illegal),)) for self.command, self.args in cmds: self.eval() if self.module is None: self.command = ':load' self.args = ['Prelude'] self.eval()
[docs] def read(self): '''Read user input.''' try: line = input('%s> ' % self.module.__name__) except EOFError: sys.exit(0) if not line: self.command = None self.args = None elif line.startswith(':'): args = line.split() self.command = args[0] self.args = args[1:] else: self.command = ':eval' self.args = line.split()
[docs] def eval(self): '''Evaluate a command.''' if not self.command: return else: commands.eval(self.command, self)
[docs] def switch_backend(self, backend): ''' Reloads the interpreter with ``backend`` (the setter of the option backend), records the backend in the options, and loads the module of the session again, so that the prompt and the expressions see the new interpreter. A reload replaces the Curry path; the load puts the directory of the module back. When that load fails, the session stays on the new backend with the Prelude at the prompt, keeps the argument of the last :load for a switch back, and reports the error. ''' curry.reload({'backend': backend}) self.options.values['backend'] = backend loaded = self.loaded if loaded is None: return try: commands.load(self, loaded) except BaseException: # The module object of the session belongs to the old interpreter. commands.load(self, 'Prelude') self.loaded = loaded raise
[docs] def defaultaction(self, value): '''The default handler for values.''' print(value)
[docs] def enter(self): '''Enter the loop.''' @trap(fatal=False) def body(): self.read() self.eval() while True: body()