# pragma mypy relaxed import asyncio from typing import Any # Write an asynchronous parser for a very limited subset of the LISP # grammar from ‹t3/lisp.py›. Specifically, only consider compound # expressions and atoms. Represent atoms using ‹str› and compound # expressions using lists (note: it might be hard to find a # reasonable ‹mypy› type – it is quite okay to skip ‹mypy› in this # exercise). The argument to the parser is an ‹asyncio.StreamReader› # instance. Your best bet is reading the data using ‹readexactly( 1 # )›. The parser should immediately return after reading the closing # bracket of the initial expression. async def minilisp( reader ): pass async def test_main() -> None: import os loop = asyncio.get_running_loop() r_fd, w_fd = os.pipe() w_file = os.fdopen( w_fd, 'w' ) r_stream = asyncio.StreamReader() await loop.connect_read_pipe( lambda: asyncio.StreamReaderProtocol( r_stream ), os.fdopen( r_fd ) ) def send( data: str ) -> None: w_file.write( data ) w_file.flush() async def check( *expect: Any ) -> None: got = await minilisp( r_stream ) assert got == list( expect ), f"{got} == {expect}" send( '(hello)' ) await check( 'hello' ) send( '(hello world)' ) await check( 'hello', 'world' ) send( '(hello (world))' ) await check( 'hello', [ 'world' ] ) send( '((hello) (cruel (or not) world))' ) await check( [ 'hello' ], [ 'cruel', [ 'or', 'not' ], 'world' ] ) if __name__ == '__main__': asyncio.run( test_main() )