Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
#include "executable/bytecode/BytecodeProgram.hpp"
#include "utilities.hpp"

#include <cstdio>
#include <filesystem>
#include <unistd.h>

namespace fs = std::filesystem;
using namespace py;
Expand Down Expand Up @@ -186,10 +188,23 @@ void Interpreter::internal_setup(const std::string &name,
std::get<PyObject *>(io_module->symbol_table()->map().at(String{ "FileIO" }));
auto *buffered_writer =
std::get<PyObject *>(io_module->symbol_table()->map().at(String{ "BufferedWriter" }));
auto *buffered_reader =
std::get<PyObject *>(io_module->symbol_table()->map().at(String{ "BufferedReader" }));
auto *text_io_wrapper =
std::get<PyObject *>(io_module->symbol_table()->map().at(String{ "TextIOWrapper" }));
auto py_stdin =
file_io->call(PyTuple::create(Number{ STDIN_FILENO }, String{ "rb" }).unwrap(), nullptr)
.and_then([buffered_reader](PyObject *stdin) {
return buffered_reader->call(PyTuple::create(stdin).unwrap(), nullptr);
})
.and_then([text_io_wrapper](PyObject *stdin_buffer_writer) {
return text_io_wrapper->call(
PyTuple::create(stdin_buffer_writer).unwrap(), nullptr);
});
ASSERT(py_stdin.is_ok());
auto py_stdout =
file_io->call(PyTuple::create(Number{ 1 }, String{ "wb" }).unwrap(), nullptr)
file_io->call(
PyTuple::create(Number{ STDOUT_FILENO }, String{ "wb" }).unwrap(), nullptr)
.and_then([buffered_writer](PyObject *stdout) {
return buffered_writer->call(PyTuple::create(stdout).unwrap(), nullptr);
})
Expand All @@ -199,7 +214,8 @@ void Interpreter::internal_setup(const std::string &name,
});
ASSERT(py_stdout.is_ok());
auto py_stderr =
file_io->call(PyTuple::create(Number{ 2 }, String{ "wb" }).unwrap(), nullptr)
file_io->call(
PyTuple::create(Number{ STDERR_FILENO }, String{ "wb" }).unwrap(), nullptr)
.and_then([buffered_writer](PyObject *stderr) {
return buffered_writer->call(PyTuple::create(stderr).unwrap(), nullptr);
})
Expand All @@ -208,6 +224,7 @@ void Interpreter::internal_setup(const std::string &name,
PyTuple::create(stderr_buffer_writer).unwrap(), nullptr);
});
ASSERT(py_stderr.is_ok());
sys->add_symbol(PyString::create("stdin").unwrap(), py_stdin.unwrap());
sys->add_symbol(PyString::create("stdout").unwrap(), py_stdout.unwrap());
sys->add_symbol(PyString::create("stderr").unwrap(), py_stderr.unwrap());
}
Expand Down
7 changes: 7 additions & 0 deletions src/runtime/PyMemoryView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,13 @@ PyResult<PyObject *> PyMemoryView::create(PyObject *object)
type_error("memoryview: a bytes-like object is required, not {}", object->type()->name()));
}

PyResult<PyObject *> PyMemoryView::create(PyBuffer buffer)
{
auto obj = VirtualMachine::the().heap().allocate<PyMemoryView>(std::move(buffer));
if (!obj) { return Err(memory_error(sizeof(PyMemoryView))); }
return Ok(obj);
}

PyResult<PyObject *> PyMemoryView::__new__(const PyType *, PyTuple *args, PyDict *kwargs)
{
auto result = PyArgsParser<PyObject *>::unpack_tuple(args,
Expand Down
1 change: 1 addition & 0 deletions src/runtime/PyMemoryView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class PyMemoryView : public PyBaseObject

public:
static PyResult<PyObject *> create(PyObject *object);
static PyResult<PyObject *> create(PyBuffer buffer);

static PyResult<PyObject *> __new__(const PyType *type, PyTuple *args, PyDict *kwargs);
PyResult<PyObject *> __repr__() const;
Expand Down
16 changes: 16 additions & 0 deletions src/runtime/modules/BuiltinsModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,14 @@ PyResult<PyObject *> print(const PyTuple *args, const PyDict *kwargs, Interprete
.unwrap();
// sys.stdout may be None when FILE* stdout isn't connected
if (!file || file == py_none()) { return Ok(py_none()); }
// TODO: flush should be false, but for now we keep it as true, since there is no flush at
// interpreter shutdown
bool flush = true;
if (kwargs) {
static const Value separator_keyword = String{ "sep" };
static const Value end_keyword = String{ "end" };
static const Value file_keyword = String{ "file" };
static const Value flush_keyword = String{ "flush" };

if (auto it = kwargs->map().find(separator_keyword); it != kwargs->map().end()) {
auto maybe_str = it->second;
Expand All @@ -107,6 +111,18 @@ PyResult<PyObject *> print(const PyTuple *args, const PyDict *kwargs, Interprete
}
end = PyString::create(std::get<String>(maybe_str).s).unwrap();
}
if (auto it = kwargs->map().find(file_keyword); it != kwargs->map().end()) {
auto file_ = PyObject::from(it->second);
if (file_.is_err()) { return file_; }
file = file_.unwrap();
}
Comment on lines +114 to +118

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file == py_none() fallback check above (line 82) runs before this kwarg is parsed. If a caller passes file=None explicitly, file is reassigned to py_none() here with no subsequent none-check, so file->get_method("write") below then errors with an AttributeError instead of falling back to sys.stdout as CPython's print() does ("if it is not present or None, sys.stdout will be used"). (bug)

if (auto it = kwargs->map().find(flush_keyword); it != kwargs->map().end()) {
auto flush_ = PyObject::from(it->second);
if (flush_.is_err()) { return flush_; }
const auto truthy = flush_.unwrap()->true_();
if (truthy.is_err()) { return Err(truthy.unwrap_err()); }
flush = truthy.unwrap();
}
}
auto file_write_ = file->get_method(PyString::create("write").unwrap());
if (file_write_.is_err()) { return file_write_; }
Expand Down
Loading
Loading