Merge remote-tracking branch 'gurnec/docstrings'
This commit is contained in:
117
ASTree.cpp
117
ASTree.cpp
@@ -15,9 +15,12 @@ static bool inPrint;
|
||||
/* Use this to prevent printing return keywords and newlines in lambdas. */
|
||||
static bool inLambda = false;
|
||||
|
||||
/* Use this to keep track of whether we need to print out the list of global
|
||||
* variables that we are using (such as inside a function). */
|
||||
static bool printGlobals = false;
|
||||
/* Use this to keep track of whether we need to print out any docstring and
|
||||
* the list of global variables that we are using (such as inside a function). */
|
||||
static bool printDocstringAndGlobals = false;
|
||||
|
||||
/* Use this to keep track of whether we need to print a class or module docstring */
|
||||
static bool printClassDocstring = true;
|
||||
|
||||
PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
{
|
||||
@@ -2585,7 +2588,7 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
|
||||
fprintf(pyc_output, ": ");
|
||||
} else {
|
||||
fprintf(pyc_output, "):\n");
|
||||
printGlobals = true;
|
||||
printDocstringAndGlobals = true;
|
||||
}
|
||||
|
||||
bool preLambda = inLambda;
|
||||
@@ -2614,6 +2617,7 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
|
||||
// Don't put parens if there are no base classes
|
||||
fprintf(pyc_output, ":\n");
|
||||
}
|
||||
printClassDocstring = true;
|
||||
PycRef<ASTNode> code = src.cast<ASTClass>()->code().cast<ASTCall>()
|
||||
->func().cast<ASTFunction>()->code();
|
||||
print_src(code, mod);
|
||||
@@ -2654,38 +2658,13 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
|
||||
print_src(dest, mod);
|
||||
}
|
||||
}
|
||||
} else if (src->type() == ASTNode::NODE_BINARY &&
|
||||
src.cast<ASTBinary>()->is_inplace() == true) {
|
||||
print_src(src, mod);
|
||||
} else {
|
||||
if (src->type() == ASTNode::NODE_BINARY &&
|
||||
src.cast<ASTBinary>()->is_inplace() == true) {
|
||||
print_src(src, mod);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dest->type() == ASTNode::NODE_NAME &&
|
||||
dest.cast<ASTName>()->name()->isEqual("__doc__")) {
|
||||
if (src->type() == ASTNode::NODE_OBJECT) {
|
||||
PycRef<PycObject> obj = src.cast<ASTObject>()->object();
|
||||
if (obj->type() == PycObject::TYPE_STRING)
|
||||
OutputString(obj.cast<PycString>(), (mod->majorVer() == 3) ? 'b' : 0, true);
|
||||
else if (obj->type() == PycObject::TYPE_UNICODE)
|
||||
OutputString(obj.cast<PycString>(), (mod->majorVer() == 3) ? 0 : 'u', true);
|
||||
else if (obj->type() == PycObject::TYPE_INTERNED ||
|
||||
obj->type() == PycObject::TYPE_STRINGREF ||
|
||||
obj->type() == PycObject::TYPE_ASCII ||
|
||||
obj->type() == PycObject::TYPE_ASCII_INTERNED ||
|
||||
obj->type() == PycObject::TYPE_SHORT_ASCII ||
|
||||
obj->type() == PycObject::TYPE_SHORT_ASCII_INTERNED)
|
||||
OutputString(obj.cast<PycString>(), 0, true);
|
||||
} else {
|
||||
print_src(dest, mod);
|
||||
fprintf(pyc_output, " = ");
|
||||
print_src(src, mod);
|
||||
}
|
||||
} else {
|
||||
print_src(dest, mod);
|
||||
fprintf(pyc_output, " = ");
|
||||
print_src(src, mod);
|
||||
}
|
||||
print_src(dest, mod);
|
||||
fprintf(pyc_output, " = ");
|
||||
print_src(src, mod);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2731,6 +2710,30 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
|
||||
cleanBuild = true;
|
||||
}
|
||||
|
||||
bool print_docstring(PycRef<PycObject> obj, int indent, PycModule* mod)
|
||||
{
|
||||
// docstrings are translated from the bytecode __doc__ = 'string' to simply '''string'''
|
||||
char prefix = -1;
|
||||
if (obj->type() == PycObject::TYPE_STRING)
|
||||
prefix = mod->majorVer() == 3 ? 'b' : 0;
|
||||
else if (obj->type() == PycObject::TYPE_UNICODE)
|
||||
prefix = mod->majorVer() == 3 ? 0 : 'u';
|
||||
else if (obj->type() == PycObject::TYPE_INTERNED ||
|
||||
obj->type() == PycObject::TYPE_STRINGREF ||
|
||||
obj->type() == PycObject::TYPE_ASCII ||
|
||||
obj->type() == PycObject::TYPE_ASCII_INTERNED ||
|
||||
obj->type() == PycObject::TYPE_SHORT_ASCII ||
|
||||
obj->type() == PycObject::TYPE_SHORT_ASCII_INTERNED)
|
||||
prefix = 0;
|
||||
if (prefix != -1) {
|
||||
start_line(indent);
|
||||
OutputString(obj.cast<PycString>(), prefix, true);
|
||||
fprintf(pyc_output, "\n");
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
void decompyle(PycRef<PycCode> code, PycModule* mod)
|
||||
{
|
||||
PycRef<ASTNode> source = BuildFromCode(code, mod);
|
||||
@@ -2754,6 +2757,17 @@ void decompyle(PycRef<PycCode> code, PycModule* mod)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Class and module docstrings may only appear at the beginning of their source
|
||||
if (printClassDocstring && clean->nodes().front()->type() == ASTNode::NODE_STORE) {
|
||||
PycRef<ASTStore> store = clean->nodes().front().cast<ASTStore>();
|
||||
if (store->dest()->type() == ASTNode::NODE_NAME &&
|
||||
store->dest().cast<ASTName>()->name()->isEqual("__doc__") &&
|
||||
store->src()->type() == ASTNode::NODE_OBJECT) {
|
||||
if (print_docstring(store->src().cast<ASTObject>()->object(),
|
||||
cur_indent + (code->name()->isEqual("<module>") ? 0 : 1), mod))
|
||||
clean->removeFirst();
|
||||
}
|
||||
}
|
||||
if (clean->nodes().back()->type() == ASTNode::NODE_RETURN) {
|
||||
PycRef<ASTReturn> ret = clean->nodes().back().cast<ASTReturn>();
|
||||
|
||||
@@ -2762,6 +2776,8 @@ void decompyle(PycRef<PycCode> code, PycModule* mod)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (printClassDocstring)
|
||||
printClassDocstring = false;
|
||||
// This is outside the clean check so a source block will always
|
||||
// be compilable, even if decompylation failed.
|
||||
if (clean->nodes().size() == 0)
|
||||
@@ -2770,20 +2786,25 @@ void decompyle(PycRef<PycCode> code, PycModule* mod)
|
||||
inPrint = false;
|
||||
bool part1clean = cleanBuild;
|
||||
|
||||
PycCode::globals_t globs = code->getGlobals();
|
||||
if (printGlobals && globs.size()) {
|
||||
start_line(cur_indent+1);
|
||||
fprintf(pyc_output, "global ");
|
||||
bool first = true;
|
||||
PycCode::globals_t::iterator it;
|
||||
for (it = globs.begin(); it != globs.end(); ++it) {
|
||||
if (!first)
|
||||
fprintf(pyc_output, ", ");
|
||||
fprintf(pyc_output, "%s", (*it)->value());
|
||||
first = false;
|
||||
if (printDocstringAndGlobals) {
|
||||
if (code->consts()->size())
|
||||
print_docstring(code->getConst(0), cur_indent + 1, mod);
|
||||
|
||||
PycCode::globals_t globs = code->getGlobals();
|
||||
if (globs.size()) {
|
||||
start_line(cur_indent + 1);
|
||||
fprintf(pyc_output, "global ");
|
||||
bool first = true;
|
||||
PycCode::globals_t::iterator it;
|
||||
for (it = globs.begin(); it != globs.end(); ++it) {
|
||||
if (!first)
|
||||
fprintf(pyc_output, ", ");
|
||||
fprintf(pyc_output, "%s", (*it)->value());
|
||||
first = false;
|
||||
}
|
||||
fprintf(pyc_output, "\n");
|
||||
}
|
||||
fprintf(pyc_output, "\n");
|
||||
printGlobals = false;
|
||||
printDocstringAndGlobals = false;
|
||||
}
|
||||
|
||||
print_src(source, mod);
|
||||
|
Reference in New Issue
Block a user