Commit d1729101 authored by Kevin Modzelewski's avatar Kevin Modzelewski Committed by Kevin Modzelewski

Better support for "interactive" statements

ie what you create either on the repl (where we were close) or
with `exec compile(foo, bar, "single")` (where we were not so close).

With these changes, doctest seems to mostly be working.
parent cd0c4bc3
......@@ -381,6 +381,7 @@ private:
case AST_LangPrimitive::NONE:
case AST_LangPrimitive::SET_EXC_INFO:
case AST_LangPrimitive::UNCACHE_EXC_INFO:
case AST_LangPrimitive::PRINT_EXPR:
return NONE;
case AST_LangPrimitive::HASNEXT:
case AST_LangPrimitive::NONZERO:
......
......@@ -875,6 +875,11 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
assert(node->args.size() == 1);
Value obj = visit_expr(node->args[0]);
v = Value(boxBool(hasnext(obj.o)), jit ? jit->emitHasnext(obj) : NULL);
} else if (node->opcode == AST_LangPrimitive::PRINT_EXPR) {
abortJITing();
Value obj = visit_expr(node->args[0]);
printExprHelper(obj.o);
v = getNone();
} else
RELEASE_ASSERT(0, "unknown opcode %d", node->opcode);
return v;
......@@ -1870,6 +1875,13 @@ Box* astInterpretDeopt(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclo
return v ? v : None;
}
extern "C" void printExprHelper(Box* obj) {
Box* displayhook = PySys_GetObject("displayhook");
if (!displayhook)
raiseExcHelper(RuntimeError, "lost sys.displayhook");
runtimeCall(displayhook, ArgPassSpec(1), obj, 0, 0, 0, 0);
}
static ASTInterpreter* getInterpreterFromFramePtr(void* frame_ptr) {
// This offsets have to match the layout inside executeInnerAndSetupFrame
ASTInterpreter** ptr = (ASTInterpreter**)(((uint8_t*)frame_ptr) - 8);
......
......@@ -83,6 +83,9 @@ FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr);
BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr);
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible);
// Executes the equivalent of CPython's PRINT_EXPR opcode (call sys.displayhook)
extern "C" void printExprHelper(Box* b);
}
#endif
......@@ -366,13 +366,9 @@ static AST_Suite* parseExec(llvm::StringRef source, bool interactive = false) {
continue;
AST_Expr* expr = (AST_Expr*)s;
AST_Print* print = new AST_Print;
print->lineno = expr->lineno;
print->col_offset = expr->col_offset;
print->dest = NULL;
print->nl = true;
print->values.push_back(expr->value);
parsedModule->body[i] = print;
AST_LangPrimitive* print_expr = new AST_LangPrimitive(AST_LangPrimitive::PRINT_EXPR);
print_expr->args.push_back(expr->value);
expr->value = print_expr;
}
}
......
......@@ -879,6 +879,16 @@ private:
return getNone();
}
case AST_LangPrimitive::PRINT_EXPR: {
assert(node->args.size() == 1);
CompilerVariable* obj = evalExpr(node->args[0], unw_info);
ConcreteCompilerVariable* converted = obj->makeConverted(emitter, obj->getBoxType());
emitter.createCall(unw_info, g.funcs.printExprHelper, converted->getValue());
return getNone();
}
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
......
......@@ -29,6 +29,7 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/Transforms/Scalar.h"
#include "codegen/ast_interpreter.h"
#include "codegen/codegen.h"
#include "codegen/irgen.h"
#include "codegen/irgen/hooks.h"
......@@ -233,6 +234,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(assertNameDefined);
GET(assertFailDerefNameDefined);
GET(assertFail);
GET(printExprHelper);
GET(printFloat);
GET(listAppendInternal);
......
......@@ -41,7 +41,7 @@ struct GlobalFuncs {
llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi,
*raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *raiseIndexErrorStrCapi,
*assertNameDefined, *assertFail, *assertFailDerefNameDefined;
*assertNameDefined, *assertFail, *assertFailDerefNameDefined, *printExprHelper;
llvm::Value* printFloat, *listAppendInternal, *getSysStdout;
llvm::Value* runtimeCall0, *runtimeCall1, *runtimeCall2, *runtimeCall3, *runtimeCall, *runtimeCallN;
llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr, *callattrN;
......
......@@ -1075,6 +1075,7 @@ public:
SET_EXC_INFO,
UNCACHE_EXC_INFO,
HASNEXT,
PRINT_EXPR,
} opcode;
std::vector<AST_expr*> args;
......
......@@ -484,20 +484,9 @@ static int main(int argc, char** argv) {
if (m->body.size() > 0 && m->body[0]->type == AST_TYPE::Expr) {
AST_Expr* e = ast_cast<AST_Expr>(m->body[0]);
AST_Call* c = new AST_Call();
AST_Name* r = new AST_Name(m->interned_strings->get("repr"), AST_TYPE::Load, 0);
c->func = r;
c->starargs = NULL;
c->kwargs = NULL;
c->args.push_back(e->value);
c->lineno = 0;
AST_Print* p = new AST_Print();
p->dest = NULL;
p->nl = true;
p->values.push_back(c);
p->lineno = 0;
m->body[0] = p;
AST_LangPrimitive* print_expr = new AST_LangPrimitive(AST_LangPrimitive::PRINT_EXPR);
print_expr->args.push_back(e->value);
e->value = print_expr;
}
compileAndRunModule(m, main_module);
......
......@@ -397,12 +397,60 @@ static PyObject* sys_excepthook(PyObject* self, PyObject* args) noexcept {
return Py_None;
}
static PyObject* sys_displayhook(PyObject* self, PyObject* o) noexcept {
PyObject* outf;
// Pyston change: we currently hardcode the builtins module
/*
PyInterpreterState* interp = PyThreadState_GET()->interp;
PyObject* modules = interp->modules;
PyObject* builtins = PyDict_GetItemString(modules, "__builtin__");
if (builtins == NULL) {
PyErr_SetString(PyExc_RuntimeError, "lost __builtin__");
return NULL;
}
*/
PyObject* builtins = builtins_module;
/* Print value except if None */
/* After printing, also assign to '_' */
/* Before, set '_' to None to avoid recursion */
if (o == Py_None) {
Py_INCREF(Py_None);
return Py_None;
}
if (PyObject_SetAttrString(builtins, "_", Py_None) != 0)
return NULL;
if (Py_FlushLine() != 0)
return NULL;
outf = PySys_GetObject("stdout");
if (outf == NULL) {
PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
return NULL;
}
if (PyFile_WriteObject(o, outf, 0) != 0)
return NULL;
PyFile_SoftSpace(outf, 1);
if (Py_FlushLine() != 0)
return NULL;
if (PyObject_SetAttrString(builtins, "_", o) != 0)
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(excepthook_doc, "excepthook(exctype, value, traceback) -> None\n"
"\n"
"Handle an exception by displaying it with a traceback on sys.stderr.\n");
PyDoc_STRVAR(displayhook_doc, "displayhook(object) -> None\n"
"\n"
"Print an object to sys.stdout and also save it in __builtin__._\n");
static PyMethodDef sys_methods[] = {
{ "excepthook", sys_excepthook, METH_VARARGS, excepthook_doc },
{ "displayhook", sys_displayhook, METH_O, displayhook_doc },
};
void setupSys() {
......@@ -507,6 +555,7 @@ void setupSys() {
sys_module->giveAttr(md.ml_name, new BoxedCApiFunction(&md, sys_module));
}
sys_module->giveAttr("__displayhook__", sys_module->getattr(internStringMortal("displayhook")));
sys_module->giveAttr("flags", new BoxedSysFlags());
}
......
......@@ -15,6 +15,7 @@
// This file is for forcing the inclusion of function declarations into the stdlib.
// This is so that the types of the functions are available to the compiler.
#include "codegen/ast_interpreter.h"
#include "codegen/irgen/hooks.h"
#include "core/ast.h"
#include "core/threading.h"
......@@ -111,6 +112,7 @@ void force() {
FORCE(assertNameDefined);
FORCE(assertFailDerefNameDefined);
FORCE(assertFail);
FORCE(printExprHelper);
FORCE(strOrUnicode);
FORCE(printFloat);
......
......@@ -30,3 +30,12 @@ print a, sorted(g.keys())
print
c = compile("a = 1; b = 2; a - b; b - a; c = a - b; c; print c", "test.py", "single")
exec c
exec compile("'hello world'", "test.py", "single")
import sys
def new_displayhook(arg):
print "my custom displayhook!"
print arg
sys.displayhook = new_displayhook
exec compile("'hello world'", "test.py", "single")
# expected: fail
# requires:
# - code.co_firstlineno
# - sys.dysplayhook
......
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