Show More
@@ -80,6 +80,40 b' def _asyncify(code: str) -> str:' | |||||
80 | return res |
|
80 | return res | |
81 |
|
81 | |||
82 |
|
82 | |||
|
83 | class _AsyncSyntaxErrorVisitor(ast.NodeVisitor): | |||
|
84 | """ | |||
|
85 | Find syntax errors that would be an error in an async repl, but because | |||
|
86 | the implementation involves wrapping the repl in an async function, it | |||
|
87 | is erroneously allowed (e.g. yield or return at the top level) | |||
|
88 | """ | |||
|
89 | def generic_visit(self, node): | |||
|
90 | func_types = (ast.FunctionDef, ast.AsyncFunctionDef) | |||
|
91 | invalid_types = (ast.Return, ast.Yield, ast.YieldFrom) | |||
|
92 | ||||
|
93 | if isinstance(node, func_types): | |||
|
94 | return # Don't recurse into functions | |||
|
95 | elif isinstance(node, invalid_types): | |||
|
96 | raise SyntaxError() | |||
|
97 | else: | |||
|
98 | super().generic_visit(node) | |||
|
99 | ||||
|
100 | ||||
|
101 | def _async_parse_cell(cell: str) -> ast.AST: | |||
|
102 | """ | |||
|
103 | This is a compatibility shim for pre-3.7 when async outside of a function | |||
|
104 | is a syntax error at the parse stage. | |||
|
105 | ||||
|
106 | It will return an abstract syntax tree parsed as if async and await outside | |||
|
107 | of a function were not a syntax error. | |||
|
108 | """ | |||
|
109 | if sys.version_info < (3, 7): | |||
|
110 | # Prior to 3.7 you need to asyncify before parse | |||
|
111 | wrapped_parse_tree = ast.parse(_asyncify(cell)) | |||
|
112 | return wrapped_parse_tree.body[0].body[0] | |||
|
113 | else: | |||
|
114 | return ast.parse(cell) | |||
|
115 | ||||
|
116 | ||||
83 | def _should_be_async(cell: str) -> bool: |
|
117 | def _should_be_async(cell: str) -> bool: | |
84 | """Detect if a block of code need to be wrapped in an `async def` |
|
118 | """Detect if a block of code need to be wrapped in an `async def` | |
85 |
|
119 | |||
@@ -99,8 +133,12 b' def _should_be_async(cell: str) -> bool:' | |||||
99 | return False |
|
133 | return False | |
100 | except SyntaxError: |
|
134 | except SyntaxError: | |
101 | try: |
|
135 | try: | |
102 |
|
|
136 | parse_tree = _async_parse_cell(cell) | |
103 | # TODO verify ast has not "top level" return or yield. |
|
137 | ||
|
138 | # Raise a SyntaxError if there are top-level return or yields | |||
|
139 | v = _AsyncSyntaxErrorVisitor() | |||
|
140 | v.visit(parse_tree) | |||
|
141 | ||||
104 | except SyntaxError: |
|
142 | except SyntaxError: | |
105 | return False |
|
143 | return False | |
106 | return True |
|
144 | return True |
General Comments 0
You need to be logged in to leave comments.
Login now