1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
from tubes.itube import IFrame, ISegment
from tubes.tube import tube, receiver
from tubes.listening import Listener
from twisted.internet.endpoints import serverFromString
from twisted.internet.defer import Deferred, inlineCallbacks
from tubes.protocol import flowFountFromEndpoint
class Calculator(object):
def __init__(self):
self.stack = []
def push(self, number):
self.stack.append(number)
def do(self, operator):
if len(self.stack) < 2:
return "UNDERFLOW"
left = self.stack.pop()
right = self.stack.pop()
result = operator(left, right)
self.push(result)
return result
err = object()
@receiver(inputType=IFrame)
def linesToNumbersOrOperators(line):
from operator import add, mul
try:
yield int(line)
except ValueError:
if line == b'+':
yield add
elif line == b'*':
yield mul
else:
yield err
@tube
class CalculatingTube(object):
def __init__(self, calculator):
self.calculator = calculator
def received(self, value):
if isinstance(value, int):
self.calculator.push(value)
elif value is err:
yield "SYNTAX"
else:
yield self.calculator.do(value)
@receiver()
def numbersToLines(value):
yield str(value).encode("ascii")
@tube
class Prompter(object):
outputType = ISegment
def started(self):
yield b"> "
def received(self, item):
yield b"> "
def stopped(self, failure):
yield b"BYE"
def promptingCalculatorSeries():
from tubes.fan import Thru
from tubes.tube import series
from tubes.framing import bytesToLines, linesToBytes
full = series(bytesToLines(),
Thru([series(linesToNumbersOrOperators,
CalculatingTube(Calculator()),
numbersToLines,
linesToBytes()),
series(Prompter())]))
return full
def calculatorSeries():
from tubes.tube import series
from tubes.framing import bytesToLines, linesToBytes
return series(
bytesToLines(),
linesToNumbersOrOperators,
CalculatingTube(Calculator()),
numbersToLines,
linesToBytes()
)
def mathFlow(flow):
processor = promptingCalculatorSeries()
nextDrain = flow.fount.flowTo(processor)
nextDrain.flowTo(flow.drain)
@inlineCallbacks
def main(reactor, port="stdio:"):
endpoint = serverFromString(reactor, port)
flowFount = yield flowFountFromEndpoint(endpoint)
flowFount.flowTo(Listener(mathFlow))
yield Deferred()
if __name__ == '__main__':
from twisted.internet.task import react
from sys import argv
react(main, argv[1:])
|