Last active
December 15, 2015 10:09
-
-
Save daeken/5243257 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| from funcpy import * | |
| class Chord(object): | |
| _chord_active = None | |
| def __init__(self): | |
| self._chord_queue = [] | |
| methods = {} | |
| for method in self.chord_methods.split(' '): | |
| methods[method] = rename_func(decorate(lambda name, *args: self._chord(name, args))(method), method) | |
| setattr(self, method, methods[method]) | |
| self._chord_handler = None | |
| for name in dir(self): | |
| obj = getattr(self, name) | |
| if hasattr(obj, '_chord_handler'): | |
| self._chord_handler = obj | |
| break | |
| assert self._chord_handler != None | |
| inner = inner_func(self._chord_handler) | |
| inner.func_globals.update(methods) | |
| self._chord_unexpected = None | |
| self._chord_activate() | |
| self._chord_handler = self._chord_handler() | |
| self._chord_expect = self._chord_handler.next() | |
| self._chord_deactivate() | |
| self._chord_terminated = False | |
| def _chord(self, name, args): | |
| if self._chord_terminated: | |
| return | |
| type = getattr(self, name) | |
| self._chord_activate() | |
| while self._chord_expect == Chord.peek: | |
| try: | |
| self._chord_expect = self._chord_handler.send((type, args)) | |
| except StopIteration: | |
| self._chord_terminated = True | |
| self._chord_deactivate() | |
| return | |
| if self._chord_expect == Chord.pop: | |
| try: | |
| self._chord_expect = self._chord_handler.send((type, args)) | |
| except StopIteration: | |
| self._chord_terminated = True | |
| self._chord_deactivate() | |
| return | |
| expect = self._chord_expect.func_name | |
| if name == expect: | |
| try: | |
| self._chord_expect = self._chord_handler.send(args[0] if len(args) == 1 else (args if len(args) else None)) | |
| except StopIteration: | |
| self._chord_terminated = True | |
| elif not self._chord_unexpected or not self._chord_unexpected(type, args): | |
| self._chord_terminated = True | |
| self._chord_deactivate() | |
| def _chord_activate(self): | |
| self._chord_oldactive = Chord._chord_active | |
| Chord._chord_active = self | |
| def _chord_deactivate(self): | |
| Chord._chord_active = self._chord_oldactive | |
| @staticmethod | |
| def handler(func): | |
| func._chord_handler = True | |
| return func | |
| @staticmethod | |
| def unexpected(func): | |
| Chord._chord_active._chord_unexpected = func | |
| return func | |
| @staticmethod | |
| def ignore_unexpected(): | |
| Chord._chord_active._chord_unexpected = clambda(True) | |
| @staticmethod | |
| def peek(): | |
| pass | |
| @staticmethod | |
| def pop(): | |
| pass | |
| @decorate | |
| def chorded_class(methods, func, base=None, bases=None): | |
| if base: | |
| bases = [base] | |
| if not bases: | |
| bases = [] | |
| return type(func.func_name, tuple([Chord] + bases), dict(chord_methods=methods, __chord_method=Chord.handler(impartial(func, 1)))) | |
| chorded_object = wrap_inner(chorded_class, lambda x, f: x(f)()) | |
| if __name__=='__main__': | |
| from xml import sax | |
| @chorded_object('startElement endElement characters', base=sax.handler.ContentHandler) | |
| def handler(): | |
| yield startElement | |
| while True: | |
| if (yield Chord.peek)[0] == endElement: | |
| break | |
| name, attrs = yield startElement | |
| print 'start', name | |
| print `(yield characters)` | |
| print 'end', (yield endElement) | |
| sax.parseString('<?xml version="1.0"?><test><hi>HI!</hi><bye>bye</bye></test>', handler) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment