Created
October 7, 2016 22:47
-
-
Save QuiteClose/107ead7ecb09ec9edf13747da363dcb4 to your computer and use it in GitHub Desktop.
repl.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
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