Skip to content
This repository was archived by the owner on Mar 2, 2022. It is now read-only.

Commit ea2deb8

Browse files
committed
Python 3.7 future import support
Summary: Adds support for Python 3.7's from __future__ import annotations, and removes support of from __future__ import generator_stop. annotations is pretty simple from a code generation perspective, we just need to output the annotation as a LOAD_CONST instead of as normal Python objects. But that requires a bunch of of code to convert expressions back into strings (which is how CPython accomplishes this as well). Test Plan: ./python -m test.test_compiler
1 parent 9f8cc2e commit ea2deb8

File tree

10 files changed

+608
-16
lines changed

10 files changed

+608
-16
lines changed

compiler/consts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@
2626
CO_FUTURE_PRINT_FUNCTION = 0x10000
2727
CO_FUTURE_BARRY_AS_BDFL = 0x40000
2828
CO_FUTURE_GENERATOR_STOP = 0x80000
29+
CO_FUTURE_ANNOTATIONS = 0x100000

compiler/future.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ class FutureParser:
1919

2020
features = ("nested_scopes", "generators", "division",
2121
"absolute_import", "with_statement", "print_function",
22-
"unicode_literals", "generator_stop", "barry_as_FLUFL")
22+
"unicode_literals", "generator_stop", "barry_as_FLUFL",
23+
"annotations")
2324

2425
def __init__(self):
2526
self.found = {} # set

compiler/pycodegen.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
1515
CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION,
1616
CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_PRINT_FUNCTION,
17-
CO_COROUTINE, CO_ASYNC_GENERATOR, CO_FUTURE_BARRY_AS_BDFL, CO_FUTURE_GENERATOR_STOP)
17+
CO_COROUTINE, CO_ASYNC_GENERATOR, CO_FUTURE_BARRY_AS_BDFL, CO_FUTURE_GENERATOR_STOP,
18+
CO_FUTURE_ANNOTATIONS)
19+
from compiler.unparse import to_expr
1820
from .visitor import ASTVisitor
1921

2022
from . import config
@@ -265,16 +267,18 @@ def visitInteractive(self, node):
265267
self.emit('LOAD_CONST', None)
266268
self.emit('RETURN_VALUE')
267269

268-
def visitModule(self, node):
270+
def findFutures(self, node):
269271
future_flags = 0
270272
for feature in future.find_futures(node):
271273
if feature == "generator_stop":
272274
future_flags |= CO_FUTURE_GENERATOR_STOP
273275
elif feature == "barry_as_FLUFL":
274276
future_flags |= CO_FUTURE_BARRY_AS_BDFL
277+
return future_flags
275278

276-
self.future_flags = future_flags
277-
self.graph.setFlag(future_flags)
279+
def visitModule(self, node):
280+
self.future_flags = self.findFutures(node)
281+
self.graph.setFlag(self.future_flags)
278282

279283
if node.body:
280284
self.set_lineno(node.body[0])
@@ -349,6 +353,9 @@ def processBody(self, body, gen):
349353
else:
350354
gen.visit(body)
351355

356+
def _visitAnnotation(self, node):
357+
return self.visit(node)
358+
352359
def _visitFuncOrLambda(self, node, isLambda=0):
353360
if not isLambda and node.decorator_list:
354361
for decorator in node.decorator_list:
@@ -387,23 +394,23 @@ def _visitFuncOrLambda(self, node, isLambda=0):
387394
ann_num = 0
388395
for arg in node.args.args:
389396
if arg.annotation:
390-
self.visit(arg.annotation)
397+
self._visitAnnotation(arg.annotation)
391398
ann_args.append(self.mangle(arg.arg))
392399
if node.args.vararg:
393400
if node.args.vararg.annotation:
394-
self.visit(node.args.vararg.annotation)
401+
self._visitAnnotation(node.args.vararg.annotation)
395402
ann_args.append(self.mangle(node.args.vararg.arg))
396403
for arg in node.args.kwonlyargs:
397404
if arg.annotation:
398-
self.visit(arg.annotation)
405+
self._visitAnnotation(arg.annotation)
399406
ann_args.append(self.mangle(arg.arg))
400407
if node.args.kwarg:
401408
if node.args.kwarg.annotation:
402-
self.visit(node.args.kwarg.annotation)
409+
self._visitAnnotation(node.args.kwarg.annotation)
403410
ann_args.append(self.mangle(node.args.kwarg.arg))
404411
# Cannot annotate return type for lambda
405412
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.returns:
406-
self.visit(node.returns)
413+
self._visitAnnotation(node.returns)
407414
ann_args.append("return")
408415
if ann_args:
409416
flags |= 0x04
@@ -1299,7 +1306,7 @@ def visitAssign(self, node):
12991306
self.visit(elt)
13001307

13011308
def checkAnnExpr(self, node):
1302-
self.visit(node)
1309+
self._visitAnnotation(node)
13031310
self.emit('POP_TOP')
13041311

13051312
def checkAnnSlice(self, node):
@@ -1349,7 +1356,7 @@ def visitAnnAssign(self, node):
13491356
# If we have a simple name in a module or class, store the annotation
13501357
if node.simple and isinstance(self.tree, (ast.Module, ast.ClassDef)):
13511358
assert self.did_setup_annotations
1352-
self.visit(node.annotation)
1359+
self._visitAnnotation(node.annotation)
13531360
mangled = self.mangle(node.target.id)
13541361
self.emit('STORE_ANNOTATION', mangled)
13551362
elif isinstance(node.target, ast.Attribute):
@@ -1953,6 +1960,22 @@ def visitCall(self, node):
19531960
self.visit(arg)
19541961
self.emit('CALL_METHOD', len(node.args))
19551962

1963+
def findFutures(self, node):
1964+
future_flags = 0
1965+
for feature in future.find_futures(node):
1966+
if feature == "barry_as_FLUFL":
1967+
future_flags |= CO_FUTURE_BARRY_AS_BDFL
1968+
elif feature == "annotations":
1969+
future_flags |= CO_FUTURE_ANNOTATIONS
1970+
return future_flags
1971+
1972+
def _visitAnnotation(self, node):
1973+
if self.module.future_flags & CO_FUTURE_ANNOTATIONS:
1974+
self.emit('LOAD_CONST', to_expr(node))
1975+
else:
1976+
self.visit(node)
1977+
1978+
19561979

19571980
def get_docstring(node):
19581981
if node.body and isinstance(node.body[0], ast.Expr) \

0 commit comments

Comments
 (0)