Kaydet (Commit) 9ab019be authored tarafından Jeremy Hylton's avatar Jeremy Hylton

Generate docstrings.

Fixes SF buf #217004

Add method fixDocstring() to CodeGenerator.  It converts the Discard
node containing the docstring into an assignment to __doc__.
üst 4c1f4273
...@@ -141,13 +141,16 @@ class CodeGenerator: ...@@ -141,13 +141,16 @@ class CodeGenerator:
def visitModule(self, node): def visitModule(self, node):
lnf = walk(node.node, LocalNameFinder(), 0) lnf = walk(node.node, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
self.setDocstring(node.doc) if node.doc:
self.fixDocstring(node.node)
self.visit(node.node) self.visit(node.node)
self.emit('LOAD_CONST', None) self.emit('LOAD_CONST', None)
self.emit('RETURN_VALUE') self.emit('RETURN_VALUE')
def visitFunction(self, node): def visitFunction(self, node):
self._visitFuncOrLambda(node, isLambda=0) self._visitFuncOrLambda(node, isLambda=0)
if node.doc:
self.setDocstring(node.doc)
self.storeName(node.name) self.storeName(node.name)
def visitLambda(self, node): def visitLambda(self, node):
...@@ -165,6 +168,8 @@ class CodeGenerator: ...@@ -165,6 +168,8 @@ class CodeGenerator:
def visitClass(self, node): def visitClass(self, node):
gen = ClassCodeGenerator(node, self.filename) gen = ClassCodeGenerator(node, self.filename)
if node.doc:
self.fixDocstring(node.code)
walk(node.code, gen) walk(node.code, gen)
gen.finish() gen.finish()
self.set_lineno(node) self.set_lineno(node)
...@@ -178,6 +183,19 @@ class CodeGenerator: ...@@ -178,6 +183,19 @@ class CodeGenerator:
self.emit('BUILD_CLASS') self.emit('BUILD_CLASS')
self.storeName(node.name) self.storeName(node.name)
def fixDocstring(self, node):
"""Rewrite the ast for a class with a docstring.
The AST includes a Discard(Const(docstring)) node. Replace
this with an Assign([AssName('__doc__', ...])
"""
assert isinstance(node, ast.Stmt)
stmts = node.nodes
discard = stmts[0]
assert isinstance(discard, ast.Discard)
stmts[0] = ast.Assign([ast.AssName('__doc__', 'OP_ASSIGN')],
discard.expr)
stmts[0].lineno = discard.lineno
# The rest are standard visitor methods # The rest are standard visitor methods
# The next few implement control-flow statements # The next few implement control-flow statements
...@@ -627,7 +645,7 @@ class CodeGenerator: ...@@ -627,7 +645,7 @@ class CodeGenerator:
def visitAugSlice(self, node, mode): def visitAugSlice(self, node, mode):
if mode == "load": if mode == "load":
self.visitSlice(node, 1) self.visitlSice(node, 1)
elif mode == "store": elif mode == "store":
slice = 0 slice = 0
if node.lower: if node.lower:
...@@ -900,6 +918,9 @@ class FunctionCodeGenerator(CodeGenerator): ...@@ -900,6 +918,9 @@ class FunctionCodeGenerator(CodeGenerator):
self.isLambda = isLambda self.isLambda = isLambda
self.super_init(filename) self.super_init(filename)
if not isLambda and func.doc:
self.setDocstring(func.doc)
lnf = walk(func.code, LocalNameFinder(args), 0) lnf = walk(func.code, LocalNameFinder(args), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
if func.varargs: if func.varargs:
...@@ -947,6 +968,8 @@ class ClassCodeGenerator(CodeGenerator): ...@@ -947,6 +968,8 @@ class ClassCodeGenerator(CodeGenerator):
lnf = walk(klass.code, LocalNameFinder(), 0) lnf = walk(klass.code, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
self.graph.setFlag(CO_NEWLOCALS) self.graph.setFlag(CO_NEWLOCALS)
if klass.doc:
self.setDocstring(klass.doc)
def finish(self): def finish(self):
self.graph.startExitBlock() self.graph.startExitBlock()
......
...@@ -141,13 +141,16 @@ class CodeGenerator: ...@@ -141,13 +141,16 @@ class CodeGenerator:
def visitModule(self, node): def visitModule(self, node):
lnf = walk(node.node, LocalNameFinder(), 0) lnf = walk(node.node, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
self.setDocstring(node.doc) if node.doc:
self.fixDocstring(node.node)
self.visit(node.node) self.visit(node.node)
self.emit('LOAD_CONST', None) self.emit('LOAD_CONST', None)
self.emit('RETURN_VALUE') self.emit('RETURN_VALUE')
def visitFunction(self, node): def visitFunction(self, node):
self._visitFuncOrLambda(node, isLambda=0) self._visitFuncOrLambda(node, isLambda=0)
if node.doc:
self.setDocstring(node.doc)
self.storeName(node.name) self.storeName(node.name)
def visitLambda(self, node): def visitLambda(self, node):
...@@ -165,6 +168,8 @@ class CodeGenerator: ...@@ -165,6 +168,8 @@ class CodeGenerator:
def visitClass(self, node): def visitClass(self, node):
gen = ClassCodeGenerator(node, self.filename) gen = ClassCodeGenerator(node, self.filename)
if node.doc:
self.fixDocstring(node.code)
walk(node.code, gen) walk(node.code, gen)
gen.finish() gen.finish()
self.set_lineno(node) self.set_lineno(node)
...@@ -178,6 +183,19 @@ class CodeGenerator: ...@@ -178,6 +183,19 @@ class CodeGenerator:
self.emit('BUILD_CLASS') self.emit('BUILD_CLASS')
self.storeName(node.name) self.storeName(node.name)
def fixDocstring(self, node):
"""Rewrite the ast for a class with a docstring.
The AST includes a Discard(Const(docstring)) node. Replace
this with an Assign([AssName('__doc__', ...])
"""
assert isinstance(node, ast.Stmt)
stmts = node.nodes
discard = stmts[0]
assert isinstance(discard, ast.Discard)
stmts[0] = ast.Assign([ast.AssName('__doc__', 'OP_ASSIGN')],
discard.expr)
stmts[0].lineno = discard.lineno
# The rest are standard visitor methods # The rest are standard visitor methods
# The next few implement control-flow statements # The next few implement control-flow statements
...@@ -627,7 +645,7 @@ class CodeGenerator: ...@@ -627,7 +645,7 @@ class CodeGenerator:
def visitAugSlice(self, node, mode): def visitAugSlice(self, node, mode):
if mode == "load": if mode == "load":
self.visitSlice(node, 1) self.visitlSice(node, 1)
elif mode == "store": elif mode == "store":
slice = 0 slice = 0
if node.lower: if node.lower:
...@@ -900,6 +918,9 @@ class FunctionCodeGenerator(CodeGenerator): ...@@ -900,6 +918,9 @@ class FunctionCodeGenerator(CodeGenerator):
self.isLambda = isLambda self.isLambda = isLambda
self.super_init(filename) self.super_init(filename)
if not isLambda and func.doc:
self.setDocstring(func.doc)
lnf = walk(func.code, LocalNameFinder(args), 0) lnf = walk(func.code, LocalNameFinder(args), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
if func.varargs: if func.varargs:
...@@ -947,6 +968,8 @@ class ClassCodeGenerator(CodeGenerator): ...@@ -947,6 +968,8 @@ class ClassCodeGenerator(CodeGenerator):
lnf = walk(klass.code, LocalNameFinder(), 0) lnf = walk(klass.code, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
self.graph.setFlag(CO_NEWLOCALS) self.graph.setFlag(CO_NEWLOCALS)
if klass.doc:
self.setDocstring(klass.doc)
def finish(self): def finish(self):
self.graph.startExitBlock() self.graph.startExitBlock()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment