Skip to content

Instantly share code, notes, and snippets.

@QuiteClose
Created October 7, 2016 22:47
Show Gist options
  • Save QuiteClose/107ead7ecb09ec9edf13747da363dcb4 to your computer and use it in GitHub Desktop.
Save QuiteClose/107ead7ecb09ec9edf13747da363dcb4 to your computer and use it in GitHub Desktop.
repl.py
'''
Basic REPL using coroutines. Change the operator or initial state to
modify behaviour. Currently input is just accumulated and the whole
is printed out each time.
Tested on Python 3.4 and higher. Not expected to work with Python 2.
Of course, this entire thing could just be replaced with something
much less interesting:
>>> state = ''
>>> try:
... while True:
... given = input('>>> ')
... state += given
... print(state)
... except EOFError:
... pass
...
>>>
But where's the fun in that?
'''
import readline
###############################################################################
INITIAL_STATE = ''
OPERATOR = lambda a, b: a + b if a else b
PROMPT = '>>> '
###############################################################################
def coroutine(func):
'''
Decorator to initialise a coroutine (as per Beasley)
'''
def start(*args, **kwargs):
cr = func(*args, **kwargs)
next(cr)
return cr
return start
##################################################
@coroutine
def _read(prompt, target):
'''
Expects to be sent the current state. Reads a line of input and
sends that as the tuple (state, input) to the target. Yields the
result of the target.
'''
state = yield
try:
while True:
given = input(prompt)
state = yield target.send((state, given))
except EOFError:
pass
##############################
@coroutine
def _eval(operator, target):
'''
Expects to be sent the current state and the latest input in the
form (state, input). Applies the operator to the two fields and
sends the result of that to the target. Yields the result of the
target.
'''
state, given = yield
while True:
state, given = yield target.send(operator(state, given))
##############################
@coroutine
def _print():
'''
Expects to be sent the current state. Prints it if not-empty.
Yields the current state unaltered.
'''
state = yield
while True:
print(state)
state = yield state
##################################################
def _loop(repl, state):
try:
while True:
state = repl.send(state)
except StopIteration:
return state
###############################################################################
if __name__ == '__main__':
repl = _read(PROMPT, _eval(OPERATOR, _print()))
_loop(repl, INITIAL_STATE)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment