예제 #1
0
파일: coqtop.py 프로젝트: elfi/neovim-coq
    def __init__(self,
            args=['coqtop', '-ideslave',
                '-main-channel', 'stdfds',
                '-async-proofs', 'on'],
            extra_args_file=None,
            handler=lambda x: None):
        if extra_args_file is not None:
            with open(extra_args_file, 'r') as f:
                args = args + shlex.split(f.read())

        from subprocess import PIPE
        coro = asyncio.create_subprocess_exec(*args,
                stdin=PIPE,
                stdout=PIPE,
                stderr=open('fifo', 'w'))
        self._proc = await(coro)
        self._to_coq = self._proc.stdin
        self._from_coq = self._proc.stdout

        self._do_recv()

        self._parser = XMLStreamParser(self._handle_response, encoding='utf-8')
        self._response_waiters = deque([])

        self._message_handler = None
예제 #2
0
파일: coqtop.py 프로젝트: elfi/neovim-coq
class Coqtop(object):
    # __init__ must run in a greenlet context so it can wait for the subprocess
    # to start up.
    def __init__(self,
            args=['coqtop', '-ideslave',
                '-main-channel', 'stdfds',
                '-async-proofs', 'on'],
            extra_args_file=None,
            handler=lambda x: None):
        if extra_args_file is not None:
            with open(extra_args_file, 'r') as f:
                args = args + shlex.split(f.read())

        from subprocess import PIPE
        coro = asyncio.create_subprocess_exec(*args,
                stdin=PIPE,
                stdout=PIPE,
                stderr=open('fifo', 'w'))
        self._proc = await(coro)
        self._to_coq = self._proc.stdin
        self._from_coq = self._proc.stdout

        self._do_recv()

        self._parser = XMLStreamParser(self._handle_response, encoding='utf-8')
        self._response_waiters = deque([])

        self._message_handler = None

    # The low-level receiver code runs directly on the event loop greenlet,
    # inside an ordinary async callback.
    def _do_recv(self):
        coro = self._from_coq.read(4096)
        task = asyncio.async(coro)
        task.add_done_callback(self._handle_recv)

    def _handle_recv(self, task):
        msg = task.result()
        assert len(msg) > 0
        self._parser.feed(msg)
        self._do_recv()

    def _handle_response(self, xml):
        if xml.tag == 'value':
            self._handle_response_value(xml)
        elif xml.tag == 'message':
            self._handle_response_message(xml)
        else:
            print('unhandled: %r' % ET.tostring(xml))

    def _handle_response_value(self, xml):
        resp = parse_response(xml)

        gr = self._response_waiters.popleft()
        def callback():
            gr.switch(resp)
        asyncio.get_event_loop().call_soon_threadsafe(callback)

    def _handle_response_message(self, xml):
        if self._message_handler is None:
            return

        assert xml[0].tag == 'message_level'
        level = xml[0].get('val')

        msg = parse_value(xml[1])

        def task():
            self._message_handler(level, msg)
        gr = greenlet.greenlet(task)
        def callback():
            gr.switch()
        asyncio.get_event_loop().call_soon_threadsafe(callback)

    def set_message_handler(self, f):
        self._message_handler = f

    # The higher-level code runs in a greenlet, so it can block for responses.
    def _get_response(self):
        gr = greenlet.getcurrent()
        self._response_waiters.append(gr)
        return gr.parent.switch()

    def call(self, name, arg):
        xml = encode_call(name, arg)
        msg = ET.tostring(xml, encoding='utf-8')
        self._to_coq.write(msg)
        self._to_coq.drain()
        resp = self._get_response()
        return resp