Commit dcd76808 authored by Marius Wachtler's avatar Marius Wachtler

cleanup print code and enable cpython test

parent 550e52ed
# expected: fail
"""Test correct operation of the print function.
"""
......
......@@ -1633,6 +1633,8 @@ static void** slotptr(BoxedClass* type, int offset) noexcept {
ETSLOT_2ARG(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, "x." NAME "(y) <==> " DOC)
static slotdef slotdefs[] = {
TPSLOT("__str__", tp_print, NULL, NULL, ""),
TPSLOT("__repr__", tp_print, NULL, NULL, ""),
TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
......
......@@ -1265,7 +1265,7 @@ Value ASTInterpreter::visit_print(AST_Print* node) {
if (node->dest)
printHelper(dest.o, var.o, node->nl);
else
printHelper(getSysStdout(), var.o, node->nl);
printHelper(NULL, var.o, node->nl);
return Value();
}
......
......@@ -480,7 +480,7 @@ void JitFragmentWriter::emitPendingCallsCheck() {
void JitFragmentWriter::emitPrint(RewriterVar* dest, RewriterVar* var, bool nl) {
if (!dest)
dest = call(false, (void*)getSysStdout);
dest = imm(0ul);
if (!var)
var = imm(0ul);
call(false, (void*)printHelper, dest, var, imm(nl));
......
......@@ -2139,9 +2139,7 @@ private:
dest = d->makeConverted(emitter, d->getBoxType());
d->decvref(emitter);
} else {
llvm::Value* sys_stdout_val = emitter.createCall(unw_info, g.funcs.getSysStdout);
dest = new ConcreteCompilerVariable(UNKNOWN, sys_stdout_val, true);
// TODO: speculate that sys.stdout is a file?
dest = new ConcreteCompilerVariable(UNKNOWN, getNullPtr(g.llvm_value_type_ptr), true);
}
assert(dest);
......
......@@ -243,7 +243,6 @@ void initGlobalFuncs(GlobalState& g) {
GET(printHelper);
GET(listAppendInternal);
GET(getSysStdout);
GET(exec);
GET(boxedLocalsSet);
......
......@@ -42,7 +42,7 @@ struct GlobalFuncs {
llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi,
*raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *raiseIndexErrorStrCapi,
*assertNameDefined, *assertFail, *assertFailDerefNameDefined, *printExprHelper, *printHelper;
llvm::Value* listAppendInternal, *getSysStdout;
llvm::Value* listAppendInternal;
ExceptionSwitchable<llvm::Value*> runtimeCall0, runtimeCall1, runtimeCall2, runtimeCall3, runtimeCall, runtimeCallN;
ExceptionSwitchable<llvm::Value*> callattr0, callattr1, callattr2, callattr3, callattr, callattrN;
llvm::Value* reoptCompiledFunc, *compilePartialFunc;
......
......@@ -20,6 +20,7 @@
#include "llvm/Support/FileSystem.h"
#include "capi/typeobject.h"
#include "capi/types.h"
#include "codegen/ast_interpreter.h"
#include "codegen/irgen/hooks.h"
#include "codegen/parser.h"
......@@ -1261,54 +1262,111 @@ Box* powFunc(Box* x, Box* y, Box* z) {
return rtn;
}
Box* print(BoxedTuple* args, BoxedDict* kwargs) {
assert(args->cls == tuple_cls);
assert(!kwargs || kwargs->cls == dict_cls);
Box* dest, *end;
static BoxedString* file_str = internStringImmortal("file");
static BoxedString* end_str = internStringImmortal("end");
static BoxedString* space_str = internStringImmortal(" ");
static PyObject* builtin_print(PyObject* self, PyObject* args, PyObject* kwds) noexcept {
static const char* kwlist[] = { "sep", "end", "file", 0 };
static PyObject* dummy_args = NULL;
static PyObject* unicode_newline = NULL, * unicode_space = NULL;
static PyObject* str_newline = NULL, * str_space = NULL;
PyObject* newline, *space;
PyObject* sep = NULL, * end = NULL, * file = NULL;
int i, err, use_unicode = 0;
BoxedDict::DictMap::iterator it;
if (kwargs && ((it = kwargs->d.find(file_str)) != kwargs->d.end())) {
dest = it->second;
kwargs->d.erase(it);
} else {
dest = getSysStdout();
if (dummy_args == NULL) {
if (!(dummy_args = PyTuple_New(0)))
return NULL;
}
if (str_newline == NULL) {
str_newline = PyString_FromString("\n");
if (str_newline == NULL)
return NULL;
str_space = PyString_FromString(" ");
if (str_space == NULL) {
Py_CLEAR(str_newline);
return NULL;
}
#ifdef Py_USING_UNICODE
unicode_newline = PyUnicode_FromString("\n");
if (unicode_newline == NULL) {
Py_CLEAR(str_newline);
Py_CLEAR(str_space);
return NULL;
}
unicode_space = PyUnicode_FromString(" ");
if (unicode_space == NULL) {
Py_CLEAR(str_newline);
Py_CLEAR(str_space);
Py_CLEAR(unicode_space);
return NULL;
}
#endif
}
if (!PyArg_ParseTupleAndKeywords(dummy_args, kwds, "|OOO:print", const_cast<char**>(kwlist), &sep, &end, &file))
return NULL;
if (file == NULL || file == Py_None) {
file = PySys_GetObject("stdout");
/* sys.stdout may be None when FILE* stdout isn't connected */
if (file == Py_None)
Py_RETURN_NONE;
}
if (sep == Py_None) {
sep = NULL;
} else if (sep) {
if (PyUnicode_Check(sep)) {
use_unicode = 1;
} else if (!PyString_Check(sep)) {
PyErr_Format(PyExc_TypeError, "sep must be None, str or unicode, not %.200s", sep->cls->tp_name);
return NULL;
}
}
if (end == Py_None)
end = NULL;
else if (end) {
if (PyUnicode_Check(end)) {
use_unicode = 1;
} else if (!PyString_Check(end)) {
PyErr_Format(PyExc_TypeError, "end must be None, str or unicode, not %.200s", end->cls->tp_name);
return NULL;
}
}
if (kwargs && ((it = kwargs->d.find(end_str)) != kwargs->d.end())) {
end = it->second;
kwargs->d.erase(it);
if (!use_unicode) {
for (i = 0; i < PyTuple_Size(args); i++) {
if (PyUnicode_Check(PyTuple_GET_ITEM(args, i))) {
use_unicode = 1;
break;
}
}
}
if (use_unicode) {
newline = unicode_newline;
space = unicode_space;
} else {
end = boxString("\n");
newline = str_newline;
space = str_space;
}
RELEASE_ASSERT(!kwargs || kwargs->d.size() == 0, "print() got unexpected keyword arguments");
static BoxedString* write_str = internStringImmortal("write");
CallattrFlags callattr_flags{.cls_only = false, .null_on_nonexistent = false, .argspec = ArgPassSpec(1) };
// TODO softspace handling?
// TODO: duplicates code with ASTInterpreter::visit_print()
bool first = true;
for (auto e : *args) {
BoxedString* s = str(e);
if (!first) {
Box* r = callattr(dest, write_str, callattr_flags, space_str, NULL, NULL, NULL, NULL);
RELEASE_ASSERT(r, "");
for (i = 0; i < PyTuple_Size(args); i++) {
if (i > 0) {
if (sep == NULL)
err = PyFile_WriteObject(space, file, Py_PRINT_RAW);
else
err = PyFile_WriteObject(sep, file, Py_PRINT_RAW);
if (err)
return NULL;
}
first = false;
Box* r = callattr(dest, write_str, callattr_flags, s, NULL, NULL, NULL, NULL);
RELEASE_ASSERT(r, "");
err = PyFile_WriteObject(PyTuple_GetItem(args, i), file, Py_PRINT_RAW);
if (err)
return NULL;
}
Box* r = callattr(dest, write_str, callattr_flags, end, NULL, NULL, NULL, NULL);
RELEASE_ASSERT(r, "");
return None;
if (end == NULL)
err = PyFile_WriteObject(newline, file, Py_PRINT_RAW);
else
err = PyFile_WriteObject(end, file, Py_PRINT_RAW);
if (err)
return NULL;
Py_RETURN_NONE;
}
Box* getreversed(Box* o) {
......@@ -1860,10 +1918,6 @@ void setupBuiltins() {
builtins_module->giveAttr("__debug__", False);
builtins_module->giveAttr(
"print", new BoxedBuiltinFunctionOrMethod(FunctionMetadata::create((void*)print, NONE, 0, true, true), "print",
print_doc));
notimplemented_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "NotImplementedType");
notimplemented_cls->giveAttr("__repr__",
new BoxedFunction(FunctionMetadata::create((void*)notimplementedRepr, STR, 1)));
......@@ -2117,5 +2171,13 @@ void setupBuiltins() {
builtins_module->giveAttr(
"format", new BoxedBuiltinFunctionOrMethod(FunctionMetadata::create((void*)builtinFormat, UNKNOWN, 2), "format",
format_doc));
static PyMethodDef builtin_methods[] = {
{ "print", (PyCFunction)builtin_print, METH_VARARGS | METH_KEYWORDS, print_doc },
};
for (auto& md : builtin_methods) {
builtins_module->giveAttr(md.ml_name, new BoxedCApiFunction(&md, builtins_module));
}
}
}
......@@ -98,13 +98,6 @@ BoxedList* getSysPath() {
return static_cast<BoxedList*>(_sys_path);
}
Box* getSysStdout() {
Box* sys_stdout = sys_module->getattr(internStringMortal("stdout"));
if (!sys_stdout)
raiseExcHelper(RuntimeError, "lost sys.stdout");
return sys_stdout;
}
Box* sysGetFrame(Box* val) {
int depth = 0;
if (val) {
......
......@@ -748,6 +748,49 @@ static Box* dict_repr(PyObject* self) noexcept {
}
}
static int dict_print(PyObject* mp, FILE* fp, int flags) noexcept {
Py_ssize_t any;
int status;
status = Py_ReprEnter((PyObject*)mp);
if (status != 0) {
if (status < 0)
return status;
Py_BEGIN_ALLOW_THREADS fprintf(fp, "{...}");
Py_END_ALLOW_THREADS return 0;
}
Py_BEGIN_ALLOW_THREADS fprintf(fp, "{");
Py_END_ALLOW_THREADS any = 0;
for (auto&& entry : *(BoxedDict*)mp) {
PyObject* pvalue = entry.second;
if (pvalue != NULL) {
/* Prevent PyObject_Repr from deleting value during
key format */
Py_INCREF(pvalue);
if (any++ > 0) {
Py_BEGIN_ALLOW_THREADS fprintf(fp, ", ");
Py_END_ALLOW_THREADS
}
if (PyObject_Print((PyObject*)entry.first, fp, 0) != 0) {
Py_DECREF(pvalue);
Py_ReprLeave((PyObject*)mp);
return -1;
}
Py_BEGIN_ALLOW_THREADS fprintf(fp, ": ");
Py_END_ALLOW_THREADS if (PyObject_Print(pvalue, fp, 0) != 0) {
Py_DECREF(pvalue);
Py_ReprLeave((PyObject*)mp);
return -1;
}
Py_DECREF(pvalue);
}
}
Py_BEGIN_ALLOW_THREADS fprintf(fp, "}");
Py_END_ALLOW_THREADS Py_ReprLeave((PyObject*)mp);
return 0;
}
void BoxedDict::dealloc(Box* b) noexcept {
assert(PyDict_Check(b));
static_cast<BoxedDict*>(b)->d.freeAllMemory();
......@@ -886,6 +929,7 @@ void setupDict() {
// subclass Python classes.
dict_cls->tp_init = dict_init;
dict_cls->tp_repr = dict_repr;
dict_cls->tp_print = dict_print;
dict_cls->tp_iter = dict_iter;
dict_cls->tp_as_mapping->mp_length = (lenfunc)dict_length;
......
......@@ -119,7 +119,6 @@ void force() {
FORCE(printHelper);
FORCE(listAppendInternal);
FORCE(getSysStdout);
FORCE(runtimeCall);
FORCE(runtimeCallCapi);
......
......@@ -141,12 +141,15 @@ extern "C" Box* deopt(AST_expr* expr, Box* value) {
}
extern "C" void printHelper(Box* w, Box* v, bool nl) {
if (w == None)
w = getSysStdout();
// copied from cpythons PRINT_ITEM and PRINT_NEWLINE op handling code
if (w == NULL || w == None) {
w = PySys_GetObject("stdout");
if (w == NULL)
raiseExcHelper(RuntimeError, "lost sys.stdout");
}
int err = 0;
// copied from cpythons PRINT_ITEM and PRINT_NEWLINE op handling code
if (v) {
/* PyFile_SoftSpace() can exececute arbitrary code
if sys.stdout is an instance with a __getattr__.
......
......@@ -2818,7 +2818,6 @@ void setupStr() {
str_iterator_cls->tp_iter = PyObject_SelfIter;
str_cls->tp_as_buffer = &string_as_buffer;
str_cls->tp_print = string_print;
str_cls->giveAttr("__getnewargs__", new BoxedFunction(FunctionMetadata::create((void*)string_getnewargs, UNKNOWN, 1,
ParamNames::empty(), CAPI)));
......@@ -2910,6 +2909,7 @@ void setupStr() {
str_cls->tp_repr = str_repr;
str_cls->tp_str = str_str;
str_cls->tp_print = string_print;
str_cls->tp_iter = (decltype(str_cls->tp_iter))strIter;
str_cls->tp_hash = (hashfunc)str_hash;
str_cls->tp_as_sequence->sq_length = str_length;
......
......@@ -82,7 +82,6 @@ void setupSysEnd();
BoxedDict* getSysModulesDict();
BoxedList* getSysPath();
extern "C" Box* getSysStdout();
extern "C" BoxedTuple* EmptyTuple;
extern "C" BoxedString* EmptyString;
......
......@@ -166,7 +166,6 @@ test_pickle unknown
test_pkg unknown bug
test_poplib [unknown]
test_pprint [unknown]
test_print [unknown]
test_profile [unknown]
test_py3kwarn [unknown]
test_pyclbr This test passes but takes a very long time in debug mode (60s vs 5s for release mode).
......
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