#include "ASTree.h" #include "FastStack.h" #include "bytecode.h" /* Use this to determine if an error occurred (and therefore, if we should * avoid cleaning the output tree) */ static bool cleanBuild; /* Keep track of whether we're in a print statement, so we can make * chained prints (print x, y, z) prettier */ static bool inPrint; PycRef BuildFromCode(PycRef code, PycModule* mod) { PycBuffer source(code->code()->value(), code->code()->length()); FastStack stack((mod->majorVer() == 1) ? 20 : code->stackSize()); stackhist_t stack_hist; std::stack > blocks; PycRef defblock = new ASTBlock(ASTBlock::BLK_MAIN); PycRef& curblock = defblock; blocks.push(defblock); int opcode, operand; int pos = 0; bool else_pop = false; while (!source.atEof()) { bc_next(source, mod, opcode, operand, pos); if (else_pop && opcode != Pyc::JUMP_FORWARD_A) { else_pop = false; PycRef prev = curblock; blocks.pop(); curblock = blocks.top(); curblock->append(prev.cast()); } switch (opcode) { case Pyc::BINARY_ADD: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_ADD)); } break; case Pyc::BINARY_AND: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_AND)); } break; case Pyc::BINARY_DIVIDE: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_DIVIDE)); } break; case Pyc::BINARY_FLOOR_DIVIDE: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_FLOOR)); } break; case Pyc::BINARY_LSHIFT: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_LSHIFT)); } break; case Pyc::BINARY_MODULO: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_MODULO)); } break; case Pyc::BINARY_MULTIPLY: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_MULTIPLY)); } break; case Pyc::BINARY_OR: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_OR)); } break; case Pyc::BINARY_POWER: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_POWER)); } break; case Pyc::BINARY_RSHIFT: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_RSHIFT)); } break; case Pyc::BINARY_SUBSCR: { PycRef subscr = stack.top(); stack.pop(); PycRef src = stack.top(); stack.pop(); stack.push(new ASTSubscr(src, subscr)); } break; case Pyc::BINARY_SUBTRACT: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_SUBTRACT)); } break; case Pyc::BINARY_TRUE_DIVIDE: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_DIVIDE)); } break; case Pyc::BINARY_XOR: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTBinary(left, right, ASTBinary::BIN_XOR)); } break; case Pyc::BUILD_CLASS: { PycRef code = stack.top(); stack.pop(); PycRef bases = stack.top(); stack.pop(); PycRef name = stack.top(); stack.pop(); stack.push(new ASTClass(code, bases, name)); } break; case Pyc::BUILD_FUNCTION: { PycRef code = stack.top(); stack.pop(); stack.push(new ASTFunction(code, ASTFunction::defarg_t())); } break; case Pyc::BUILD_LIST_A: { ASTList::value_t values; for (int i=0; i> 8; int pparams = (operand & 0xFF); ASTCall::kwparam_t kwparamList; ASTCall::pparam_t pparamList; for (int i=0; i val = stack.top(); stack.pop(); PycRef key = stack.top(); stack.pop(); kwparamList.push_front(std::make_pair(key, val)); } for (int i=0; i func = stack.top(); stack.pop(); stack.push(new ASTCall(func, pparamList, kwparamList)); } break; case Pyc::COMPARE_OP_A: { PycRef right = stack.top(); stack.pop(); PycRef left = stack.top(); stack.pop(); stack.push(new ASTCompare(left, right, operand)); } break; case Pyc::DUP_TOP: stack.push(stack.top()); break; case Pyc::END_FINALLY: { if (curblock->blktype() == ASTBlock::BLK_FINALLY) { blocks.pop(); blocks.top()->append(curblock.cast()); curblock = blocks.top(); } } break; case Pyc::IMPORT_NAME_A: if (mod->majorVer() == 1) { stack.push(new ASTImport(new ASTName(code->getName(operand)), Node_NULL)); } else { PycRef fromlist = stack.top(); stack.pop(); if (mod->majorVer() > 2 || mod->minorVer() >= 5) stack.pop(); // Level -- we don't care stack.push(new ASTImport(new ASTName(code->getName(operand)), fromlist)); } break; case Pyc::IMPORT_FROM_A: break; case Pyc::IMPORT_STAR: { PycRef import = stack.top(); stack.pop(); curblock->append(new ASTStore(import, Node_NULL)); } break; case Pyc::INPLACE_ADD: { PycRef right = stack.top(); stack.pop(); PycRef src = stack.top(); stack.pop(); /* This is a problem, so fake it with a = a + b syntax */ stack.push(new ASTBinary(src, right, ASTBinary::BIN_ADD)); } break; case Pyc::INPLACE_SUBTRACT: { PycRef right = stack.top(); stack.pop(); PycRef src = stack.top(); stack.pop(); /* This is a problem, so fake it with a = a - b syntax */ stack.push(new ASTBinary(src, right, ASTBinary::BIN_SUBTRACT)); } break; case Pyc::JUMP_IF_FALSE_A: { stack_hist.push(stack); PycRef cond = stack.top(); // Do not pop the condition off the stack! PycRef ifblk; if (curblock->blktype() == ASTBlock::BLK_ELSE && curblock->size() == 0) { blocks.pop(); ifblk = new ASTCondBlock(ASTBlock::BLK_ELIF, pos+operand, cond, false); } else if ((curblock->blktype() == ASTBlock::BLK_WHILE || curblock->blktype() == ASTBlock::BLK_FOR) && curblock->size() == 0) { PycRef top = blocks.top(); blocks.pop(); ifblk = new ASTCondBlock(top->blktype(), pos+operand, cond, false); } else { ifblk = new ASTCondBlock(ASTBlock::BLK_IF, pos+operand, cond, false); } blocks.push(ifblk.cast()); curblock = blocks.top(); } break; case Pyc::JUMP_IF_TRUE_A: { stack_hist.push(stack); PycRef cond = stack.top(); // Do not pop the condition off the stack! PycRef ifblk; if (curblock->blktype() == ASTBlock::BLK_ELSE && curblock->size() == 0) { blocks.pop(); ifblk = new ASTCondBlock(ASTBlock::BLK_ELIF, pos+operand, cond, true); } else if ((curblock->blktype() == ASTBlock::BLK_WHILE || curblock->blktype() == ASTBlock::BLK_FOR) && curblock->size() == 0) { PycRef top = blocks.top(); blocks.pop(); ifblk = new ASTCondBlock(top->blktype(), pos+operand, cond, true); } else { ifblk = new ASTCondBlock(ASTBlock::BLK_IF, pos+operand, cond, true); } blocks.push(ifblk.cast()); curblock = blocks.top(); } break; case Pyc::JUMP_ABSOLUTE_A: { stack = stack_hist.top(); stack_hist.pop(); if (curblock->blktype() == ASTBlock::BLK_WHILE || curblock->blktype() == ASTBlock::BLK_FOR) { break; } PycRef prev = curblock; blocks.pop(); blocks.top()->append(prev.cast()); if (prev->blktype() == ASTBlock::BLK_IF || prev->blktype() == ASTBlock::BLK_ELIF) { PycRef next = new ASTBlock(ASTBlock::BLK_ELSE, blocks.top()->end()); blocks.push(next.cast()); } curblock = blocks.top(); } break; case Pyc::JUMP_FORWARD_A: { stack = stack_hist.top(); stack_hist.pop(); PycRef prev = curblock; PycRef nil; do { blocks.pop(); blocks.top()->append(prev.cast()); if (operand > 1 && (prev->blktype() == ASTBlock::BLK_IF || prev->blktype() == ASTBlock::BLK_ELIF)) { PycRef next = new ASTBlock(ASTBlock::BLK_ELSE, pos+operand); blocks.push(next.cast()); prev = nil; } else if (operand > 1 && prev->blktype() == ASTBlock::BLK_ELSE) { /* Special case */ prev = blocks.top(); } else { prev = nil; } } while (prev != nil); curblock = blocks.top(); } break; case Pyc::LOAD_ATTR_A: { PycRef name = stack.top(); stack.pop(); stack.push(new ASTBinary(name, new ASTName(code->getName(operand)), ASTBinary::BIN_ATTR)); } break; case Pyc::LOAD_CONST_A: { PycRef t_ob = new ASTObject(code->getConst(operand)); if (t_ob->object()->type() == PycObject::TYPE_TUPLE && !t_ob->object().cast()->values().size()) { ASTTuple::value_t values; stack.push(new ASTTuple(values)); } else { stack.push(t_ob.cast()); } } break; case Pyc::LOAD_FAST_A: if (mod->majorVer() == 1 && mod->minorVer() < 3) stack.push(new ASTName(code->getName(operand))); else stack.push(new ASTName(code->getVarName(operand))); break; case Pyc::LOAD_GLOBAL_A: stack.push(new ASTName(code->getName(operand))); break; case Pyc::LOAD_LOCALS: stack.push(new ASTNode(ASTNode::NODE_LOCALS)); break; case Pyc::LOAD_NAME_A: stack.push(new ASTName(code->getName(operand))); break; case Pyc::MAKE_FUNCTION_A: { PycRef code = stack.top(); stack.pop(); ASTFunction::defarg_t defArgs; for (int i=0; i tmp = curblock; blocks.pop(); curblock = blocks.top(); curblock->append(tmp.cast()); /*if (tmp->type() == ASTBlock::BLK_TRY) { PycRef tryblk = tmp.cast(); if (tryblk->except()) { //todo } } else if (tmp->type() == ASTBlock::BLK_EXCEPT) { //todo }*/ } break; case Pyc::POP_TOP: { PycRef value = stack.top(); stack.pop(); if (value->type() == ASTNode::NODE_CALL) { curblock->append(value); } } break; case Pyc::PRINT_ITEM: curblock->append(new ASTPrint(stack.top())); stack.pop(); break; case Pyc::PRINT_NEWLINE: curblock->append(new ASTPrint(Node_NULL)); break; case Pyc::RETURN_VALUE: { PycRef value = stack.top(); stack.pop(); curblock->append(new ASTReturn(value)); } break; case Pyc::ROT_THREE: { PycRef one = stack.top(); stack.pop(); PycRef two = stack.top(); stack.pop(); PycRef three = stack.top(); stack.pop(); stack.push(one); stack.push(three); stack.push(two); } break; case Pyc::SET_LINENO_A: // Ignore break; /*case Pyc::SETUP_EXCEPT_A: { if (curblock->type() == ASTBlock::BLK_TRY) { PycRef tryblk = curblock.cast(); if (tryblk->finally() && tryblk->except() == 0) { tryblk->set_except(pos+operand); } else { tryblk = new ASTTryBlock(pos, pos+operand, pos+operand, 0); blocks.push(tryblk.cast()); curblock = blocks.top(); } } else { PycRef tryblk = new ASTTryBlock(pos, pos+operand, pos+operand, 0); blocks.push(tryblk.cast()); curblock = blocks.top(); } } break;*/ /*case Pyc::SETUP_FINALLY_A: { PycRef tryblk = new ASTTryBlock(pos, pos+operand, 0, pos+operand); blocks.push(tryblk.cast()); curblock = blocks.top(); } break;*/ case Pyc::SETUP_LOOP_A: { PycRef next = new ASTCondBlock(ASTBlock::BLK_WHILE, pos+operand, Node_NULL, false); blocks.push(next.cast()); curblock = blocks.top(); } break; case Pyc::STORE_ATTR_A: { PycRef name = stack.top(); stack.pop(); PycRef value = stack.top(); stack.pop(); PycRef attr = new ASTBinary(name, new ASTName(code->getName(operand)), ASTBinary::BIN_ATTR); curblock->append(new ASTStore(value, attr)); } break; case Pyc::STORE_FAST_A: { PycRef value = stack.top(); stack.pop(); PycRef name; if (mod->majorVer() == 1 && mod->minorVer() < 3) name = new ASTName(code->getName(operand)); else name = new ASTName(code->getVarName(operand)); curblock->append(new ASTStore(value, name)); } break; case Pyc::STORE_GLOBAL_A: { PycRef value = stack.top(); stack.pop(); PycRef name = new ASTName(code->getName(operand)); curblock->append(new ASTStore(value, name)); } break; case Pyc::STORE_NAME_A: { PycRef value = stack.top(); stack.pop(); PycRef name = new ASTName(code->getName(operand)); curblock->append(new ASTStore(value, name)); } break; case Pyc::STORE_SUBSCR: { PycRef subscr = stack.top(); stack.pop(); PycRef dest = stack.top(); stack.pop(); PycRef src = stack.top(); stack.pop(); if (dest->type() == ASTNode::NODE_MAP) { dest.cast()->add(subscr, src); } else { curblock->append(new ASTStore(src, new ASTSubscr(dest, subscr))); } } break; case Pyc::UNARY_CALL: { PycRef func = stack.top(); stack.pop(); stack.push(new ASTCall(func, ASTCall::pparam_t(), ASTCall::kwparam_t())); } break; case Pyc::UNARY_INVERT: { PycRef arg = stack.top(); stack.pop(); stack.push(new ASTUnary(arg, ASTUnary::UN_INVERT)); } break; case Pyc::UNARY_NEGATIVE: { PycRef arg = stack.top(); stack.pop(); stack.push(new ASTUnary(arg, ASTUnary::UN_NEGATIVE)); } break; case Pyc::UNARY_NOT: { PycRef arg = stack.top(); stack.pop(); stack.push(new ASTUnary(arg, ASTUnary::UN_NOT)); } break; case Pyc::UNARY_POSITIVE: { PycRef arg = stack.top(); stack.pop(); stack.push(new ASTUnary(arg, ASTUnary::UN_POSITIVE)); } break; default: fprintf(stderr, "Unsupported opcode: %s\n", Pyc::OpcodeName(opcode & 0xFF)); cleanBuild = false; return new ASTNodeList(defblock->nodes()); } else_pop = curblock->blktype() == ASTBlock::BLK_ELSE && curblock->end() == pos; } if (stack_hist.size()) { fprintf(stderr, "Warning: Stack history is not empty!\n"); while (stack_hist.size()) { stack_hist.pop(); } } if (blocks.size() > 1) { fprintf(stderr, "Warning: block stack is not empty!\n"); while (blocks.size() > 1) { PycRef tmp = blocks.top(); blocks.pop(); blocks.top()->append(tmp.cast()); } } cleanBuild = true; return new ASTNodeList(defblock->nodes()); } static int cmp_prec(PycRef parent, PycRef child) { /* Determine whether the parent has higher precedence than therefore child, so we don't flood the source code with extraneous parens. Else we'd have expressions like (((a + b) + c) + d) when therefore equivalent, a + b + c + d would suffice. */ if (parent->type() == ASTNode::NODE_UNARY && parent.cast()->op() == ASTUnary::UN_NOT) return 1; // Always parenthesize not(x) if (child->type() == ASTNode::NODE_BINARY) { PycRef binChild = child.cast(); if (parent->type() == ASTNode::NODE_BINARY) return binChild->op() - parent.cast()->op(); else if (parent->type() == ASTNode::NODE_COMPARE) return (binChild->op() == ASTBinary::BIN_LOG_AND || binChild->op() == ASTBinary::BIN_LOG_OR) ? 1 : -1; else if (parent->type() == ASTNode::NODE_UNARY) return (binChild->op() == ASTBinary::BIN_POWER) ? -1 : 1; } else if (child->type() == ASTNode::NODE_UNARY) { PycRef unChild = child.cast(); if (parent->type() == ASTNode::NODE_BINARY) { PycRef binParent = parent.cast(); if (binParent->op() == ASTBinary::BIN_LOG_AND || binParent->op() == ASTBinary::BIN_LOG_OR) return -1; else if (unChild->op() == ASTUnary::UN_NOT) return 1; else if (binParent->op() == ASTBinary::BIN_POWER) return 1; else return -1; } else if (parent->type() == ASTNode::NODE_COMPARE) { return (unChild->op() == ASTUnary::UN_NOT) ? 1 : -1; } else if (parent->type() == ASTNode::NODE_UNARY) { return unChild->op() - parent.cast()->op(); } } else if (child->type() == ASTNode::NODE_COMPARE) { PycRef cmpChild = child.cast(); if (parent->type() == ASTNode::NODE_BINARY) return (parent.cast()->op() == ASTBinary::BIN_LOG_AND || parent.cast()->op() == ASTBinary::BIN_LOG_OR) ? -1 : 1; else if (parent->type() == ASTNode::NODE_COMPARE) return cmpChild->op() - parent.cast()->op(); else if (parent->type() == ASTNode::NODE_UNARY) return (parent.cast()->op() == ASTUnary::UN_NOT) ? -1 : 1; } /* For normal nodes, don't parenthesize anything */ return -1; } static void print_ordered(PycRef parent, PycRef child, PycModule* mod) { if (child->type() == ASTNode::NODE_BINARY || child->type() == ASTNode::NODE_COMPARE) { if (cmp_prec(parent, child) > 0) { printf("("); print_src(child, mod); printf(")"); } else { print_src(child, mod); } } else if (child->type() == ASTNode::NODE_UNARY) { if (cmp_prec(parent, child) > 0) { printf("("); print_src(child, mod); printf(")"); } else { print_src(child, mod); } } else { print_src(child, mod); } } static void start_line(int indent) { if (inPrint) return; for (int i=0; i node, PycModule* mod) { switch (node->type()) { case ASTNode::NODE_BINARY: case ASTNode::NODE_COMPARE: { PycRef bin = node.cast(); print_ordered(node, bin->left(), mod); printf("%s", bin->op_str()); print_ordered(node, bin->right(), mod); } break; case ASTNode::NODE_UNARY: { PycRef un = node.cast(); printf("%s", un->op_str()); print_ordered(node, un->operand(), mod); } break; case ASTNode::NODE_CALL: { PycRef call = node.cast(); print_src(call->func(), mod); printf("("); bool first = true; for (ASTCall::pparam_t::const_iterator p = call->pparams().begin(); p != call->pparams().end(); ++p) { if (!first) printf(", "); print_src(*p, mod); first = false; } for (ASTCall::kwparam_t::const_iterator p = call->kwparams().begin(); p != call->kwparams().end(); ++p) { if (!first) printf(", "); printf("%s = ", p->first.cast()->name()->value()); print_src(p->second, mod); first = false; } printf(")"); } break; case ASTNode::NODE_LIST: { ASTList::value_t values = node.cast()->values(); printf("["); bool first = true; cur_indent++; for (ASTList::value_t::const_iterator b = values.begin(); b != values.end(); ++b) { if (first) printf("\n"); else printf(",\n"); start_line(cur_indent); print_src(*b, mod); first = false; } cur_indent--; printf("]"); } break; case ASTNode::NODE_MAP: { ASTMap::map_t values = node.cast()->values(); printf("{"); bool first = true; cur_indent++; for (ASTMap::map_t::const_iterator b = values.begin(); b != values.end(); ++b) { if (first) printf("\n"); else printf(",\n"); start_line(cur_indent); print_src(b->first, mod); printf(": "); print_src(b->second, mod); first = false; } cur_indent--; printf(" }"); } break; case ASTNode::NODE_NAME: printf("%s", node.cast()->name()->value()); break; case ASTNode::NODE_NODELIST: { cur_indent++; ASTNodeList::list_t lines = node.cast()->nodes(); for (ASTNodeList::list_t::const_iterator ln = lines.begin(); ln != lines.end(); ++ln) { if ((*ln).cast()->type() != ASTNode::NODE_NODELIST) { start_line(cur_indent); } print_src(*ln, mod); end_line(); } cur_indent--; } break; case ASTNode::NODE_BLOCK: { printf("%s", node.cast()->type_str()); PycRef blk = node.cast(); if (blk->blktype() == ASTBlock::BLK_IF || blk->blktype() == ASTBlock::BLK_ELIF || blk->blktype() == ASTBlock::BLK_WHILE || blk->blktype() == ASTBlock::BLK_FOR) { if (blk.cast()->negative()) printf(" not "); else printf(" "); print_src(blk.cast()->cond(), mod); } printf(":\n"); cur_indent++; ASTBlock::list_t lines = blk->nodes(); for (ASTBlock::list_t::const_iterator ln = lines.begin(); ln != lines.end();) { if ((*ln).cast()->type() != ASTNode::NODE_NODELIST) { start_line(cur_indent); } print_src(*ln, mod); if (++ln != lines.end()) { end_line(); } } cur_indent--; } break; case ASTNode::NODE_OBJECT: { PycRef obj = node.cast()->object(); if (obj->type() == PycObject::TYPE_CODE) decompyle(obj.cast(), mod); else print_const(obj, mod); } break; case ASTNode::NODE_PASS: printf("pass"); break; case ASTNode::NODE_PRINT: if (node.cast()->value() == Node_NULL) { inPrint = false; } else if (!inPrint) { printf("print "); print_src(node.cast()->value(), mod); inPrint = true; } else { printf(", "); print_src(node.cast()->value(), mod); } break; case ASTNode::NODE_RETURN: printf("return "); print_src(node.cast()->value(), mod); break; case ASTNode::NODE_STORE: { PycRef src = node.cast()->src(); PycRef dest = node.cast()->dest(); if (src->type() == ASTNode::NODE_FUNCTION) { printf("\n"); start_line(cur_indent); printf("def "); print_src(dest, mod); printf("("); PycRef code = src.cast()->code(); PycRef code_src = code.cast()->object().cast(); ASTFunction::defarg_t defargs = src.cast()->defargs(); ASTFunction::defarg_t::iterator da = defargs.begin(); for (int i=0; iargCount(); i++) { if (i > 0) printf(", "); printf("%s", code_src->getVarName(i)->value()); if ((code_src->argCount() - i) <= (int)defargs.size()) { printf(" = "); print_src(*da++, mod); } } printf("):\n"); print_src(code, mod); } else if (src->type() == ASTNode::NODE_CLASS) { printf("\n"); start_line(cur_indent); printf("class "); print_src(dest, mod); PycRef bases = src.cast()->bases().cast(); if (bases->values().size() > 0) { printf("("); bool first = true; for (ASTTuple::value_t::const_iterator b = bases->values().begin(); b != bases->values().end(); ++b) { if (!first) printf(", "); print_src(*b, mod); first = false; } printf("):\n"); } else { // Don't put parens if there are no base classes printf(":\n"); } PycRef code = src.cast()->code().cast() ->func().cast()->code(); print_src(code, mod); } else if (src->type() == ASTNode::NODE_IMPORT) { PycRef import = src.cast(); if (import->fromlist() != Node_NULL) { PycRef fromlist = import->fromlist().cast()->object(); if (fromlist != Pyc_None) { printf("from "); if (import->name()->type() == ASTNode::NODE_IMPORT) print_src(import->name().cast()->name(), mod); else print_src(import->name(), mod); printf(" import "); if (fromlist->type() == PycObject::TYPE_TUPLE) { bool first = true; PycTuple::value_t::const_iterator ii = fromlist.cast()->values().begin(); for (; ii != fromlist.cast()->values().end(); ++ii) { if (!first) printf(", "); printf("%s", ii->cast()->value()); first = false; } } else { printf("%s", fromlist.cast()->value()); } } else { printf("import "); print_src(import->name(), mod); } } else { printf("import "); print_src(import->name(), mod); } } else { if (dest->type() == ASTNode::NODE_NAME && dest.cast()->name()->isEqual("__doc__")) { if (src->type() == ASTNode::NODE_OBJECT) { PycRef obj = src.cast()->object(); if (obj->type() == PycObject::TYPE_STRING || obj->type() == PycObject::TYPE_INTERNED || obj->type() == PycObject::TYPE_STRINGREF) OutputString(obj.cast(), (mod->majorVer() == 3) ? 'b' : 0, true); else if (obj->type() == PycObject::TYPE_UNICODE) OutputString(obj.cast(), (mod->majorVer() == 3) ? 0 : 'u', true); } else { print_src(dest, mod); printf(" = "); print_src(src, mod); } } else { print_src(dest, mod); printf(" = "); print_src(src, mod); } } } break; case ASTNode::NODE_SUBSCR: { print_src(node.cast()->name(), mod); printf("["); print_src(node.cast()->key(), mod); printf("]"); } break; case ASTNode::NODE_TUPLE: { ASTTuple::value_t values = node.cast()->values(); printf("("); bool first = true; for (ASTTuple::value_t::const_iterator b = values.begin(); b != values.end(); ++b) { if (!first) printf(", "); print_src(*b, mod); first = false; } if (values.size() == 1) printf(",)"); else printf(")"); } break; default: printf("", node->type()); fprintf(stderr, "Unsupported Node type: %d\n", node->type()); cleanBuild = false; return; } cleanBuild = true; } void decompyle(PycRef code, PycModule* mod) { PycRef source = BuildFromCode(code, mod); PycRef clean = source.cast(); if (cleanBuild) { // The Python compiler adds some stuff that we don't really care // about, and would add extra code for re-compilation anyway. // We strip these lines out here, and then add a "pass" statement // if the cleaned up code is empty if (clean->nodes().front()->type() == ASTNode::NODE_STORE) { PycRef store = clean->nodes().front().cast(); if (store->src()->type() == ASTNode::NODE_NAME && store->dest()->type() == ASTNode::NODE_NAME) { PycRef src = store->src().cast(); PycRef dest = store->dest().cast(); if (src->name()->isEqual("__name__") && dest->name()->isEqual("__module__")) { // __module__ = __name__ clean->removeFirst(); } } } clean->removeLast(); // Always an extraneous return statement } // This is outside the clean check so a source block will always // be compilable, even if decompylation failed. if (clean->nodes().size() == 0) clean->append(new ASTNode(ASTNode::NODE_PASS)); inPrint = false; bool part1clean = cleanBuild; print_src(source, mod); if (!cleanBuild || !part1clean) { start_line(cur_indent); printf("# WARNING: Decompyle incomplete\n"); } }