This commit is contained in:
blueloveTH 2023-04-22 21:57:06 +08:00
parent d70b7653f2
commit f7af705367
8 changed files with 93 additions and 45 deletions

View File

@ -521,8 +521,12 @@ __NEXT_STEP:;
} DISPATCH();
/*****************************************/
// // TODO: using "goto" inside with block may cause __exit__ not called
// TARGET(WITH_ENTER) call(frame->pop_value(this), __enter__, no_arg()); DISPATCH();
// TARGET(WITH_EXIT) call(frame->pop_value(this), __exit__, no_arg()); DISPATCH();
TARGET(WITH_ENTER)
call_method(POPX(), __enter__);
DISPATCH();
TARGET(WITH_EXIT)
call_method(POPX(), __exit__);
DISPATCH();
/*****************************************/
TARGET(ASSERT) {
PyObject* obj = TOP();

View File

@ -46,7 +46,7 @@
#if (defined(__ANDROID__) && __ANDROID_API__ <= 22) || defined(__EMSCRIPTEN__)
#define PK_ENABLE_FILEIO 0
#else
#define PK_ENABLE_FILEIO 0 // TODO: refactor this
#define PK_ENABLE_FILEIO 1
#endif
// This is the maximum number of arguments in a function declaration

View File

@ -795,17 +795,16 @@ __SUBSCR_END:
consume_end_stmt();
} break;
case TK("with"): {
// TODO: reimpl this
EXPR(false);
ctx()->emit(OP_POP_TOP, BC_NOARG, prev().line);
consume(TK("as"));
consume(TK("@id"));
// emit(OP_STORE_NAME, index);
// emit(OP_LOAD_NAME_REF, index);
// emit(OP_WITH_ENTER);
StrName name(prev().str());
ctx()->emit(OP_STORE_NAME, name.index, prev().line);
ctx()->emit(OP_LOAD_NAME, name.index, prev().line);
ctx()->emit(OP_WITH_ENTER, BC_NOARG, prev().line);
compile_block_body();
// emit(OP_LOAD_NAME_REF, index);
// emit(OP_WITH_EXIT);
ctx()->emit(OP_LOAD_NAME, name.index, prev().line);
ctx()->emit(OP_WITH_EXIT, BC_NOARG, prev().line);
} break;
/*************************************************/
// TODO: refactor goto/label use special $ syntax

View File

@ -2,6 +2,7 @@
#include "ceval.h"
#include "cffi.h"
#include "common.h"
#if PK_ENABLE_FILEIO
@ -11,7 +12,7 @@
namespace pkpy{
inline Str _read_file_cwd(const Str& name, bool* ok){
std::filesystem::path path(name.c_str());
std::filesystem::path path(name.sv());
bool exists = std::filesystem::exists(path);
if(!exists){
*ok = false;
@ -31,13 +32,17 @@ struct FileIO {
Str mode;
std::fstream _fs;
bool is_text() const { return mode != "rb" && mode != "wb" && mode != "ab"; }
FileIO(VM* vm, Str file, Str mode): file(file), mode(mode) {
if(mode == "rt" || mode == "r"){
_fs.open(file, std::ios::in);
}else if(mode == "wt" || mode == "w"){
_fs.open(file, std::ios::out);
}else if(mode == "at" || mode == "a"){
_fs.open(file, std::ios::app);
if(mode == "rt" || mode == "r" || mode == "rb"){
_fs.open(file.sv(), std::ios::in);
}else if(mode == "wt" || mode == "w" || mode == "wb"){
_fs.open(file.sv(), std::ios::out);
}else if(mode == "at" || mode == "a" || mode == "ab"){
_fs.open(file.sv(), std::ios::app);
}else{
vm->ValueError("invalid mode");
}
if(!_fs.is_open()) vm->IOError(strerror(errno));
}
@ -51,14 +56,19 @@ struct FileIO {
vm->bind_method<0>(type, "read", [](VM* vm, ArgsView args){
FileIO& io = CAST(FileIO&, args[0]);
std::string buffer;
io._fs >> buffer;
Bytes buffer;
io._fs >> buffer._data;
if(io.is_text()) return VAR(Str(buffer._data));
return VAR(buffer);
});
vm->bind_method<1>(type, "write", [](VM* vm, ArgsView args){
FileIO& io = CAST(FileIO&, args[0]);
io._fs << CAST(Str&, args[1]);
if(io.is_text()) io._fs << CAST(Str&, args[1]);
else{
Bytes& buffer = CAST(Bytes&, args[1]);
io._fs << buffer._data;
}
return vm->None;
});
@ -80,35 +90,40 @@ struct FileIO {
inline void add_module_io(VM* vm){
PyObject* mod = vm->new_module("io");
PyObject* type = FileIO::register_class(vm, mod);
vm->bind_builtin_func<2>("open", [type](VM* vm, ArgsView args){
return vm->call(type, args);
FileIO::register_class(vm, mod);
vm->bind_builtin_func<2>("open", [](VM* vm, ArgsView args){
static StrName m_io("io");
static StrName m_FileIO("FileIO");
return vm->call(vm->_modules[m_io]->attr(m_FileIO), args[0], args[1]);
});
}
inline void add_module_os(VM* vm){
PyObject* mod = vm->new_module("os");
PyObject* path_obj = vm->heap.gcnew<DummyInstance>(vm->tp_object, {});
mod->attr().set("path", path_obj);
// Working directory is shared by all VMs!!
vm->bind_func<0>(mod, "getcwd", [](VM* vm, ArgsView args){
return VAR(std::filesystem::current_path().string());
});
vm->bind_func<1>(mod, "chdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).c_str());
std::filesystem::path path(CAST(Str&, args[0]).sv());
std::filesystem::current_path(path);
return vm->None;
});
vm->bind_func<1>(mod, "listdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).c_str());
std::filesystem::path path(CAST(Str&, args[0]).sv());
std::filesystem::directory_iterator di;
try{
di = std::filesystem::directory_iterator(path);
}catch(std::filesystem::filesystem_error& e){
Str msg = e.what();
std::string msg = e.what();
auto pos = msg.find_last_of(":");
if(pos != Str::npos) msg = msg.substr(pos + 1);
vm->IOError(msg.lstrip());
if(pos != std::string::npos) msg = msg.substr(pos + 1);
vm->IOError(Str(msg).lstrip());
}
List ret;
for(auto& p: di) ret.push_back(VAR(p.path().filename().string()));
@ -116,36 +131,36 @@ inline void add_module_os(VM* vm){
});
vm->bind_func<1>(mod, "remove", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).c_str());
std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::remove(path);
if(!ok) vm->IOError("operation failed");
return vm->None;
});
vm->bind_func<1>(mod, "mkdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).c_str());
std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::create_directory(path);
if(!ok) vm->IOError("operation failed");
return vm->None;
});
vm->bind_func<1>(mod, "rmdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).c_str());
std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::remove(path);
if(!ok) vm->IOError("operation failed");
return vm->None;
});
vm->bind_func<-1>(mod, "path_join", [](VM* vm, ArgsView args){
vm->bind_func<-1>(path_obj, "join", [](VM* vm, ArgsView args){
std::filesystem::path path;
for(int i=0; i<args.size(); i++){
path /= CAST(Str&, args[i]).c_str();
path /= CAST(Str&, args[i]).sv();
}
return VAR(path.string());
});
vm->bind_func<1>(mod, "path_exists", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).c_str());
vm->bind_func<1>(path_obj, "exists", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv());
bool exists = std::filesystem::exists(path);
return VAR(exists);
});

View File

@ -62,6 +62,9 @@ struct Bytes{
int size() const noexcept { return _data.size(); }
int operator[](int i) const noexcept { return (int)(uint8_t)_data[i]; }
bool operator==(const Bytes& rhs) const noexcept { return _data == rhs._data; }
bool operator!=(const Bytes& rhs) const noexcept { return _data != rhs._data; }
};
using Super = std::pair<PyObject*, Type>;

View File

@ -102,8 +102,8 @@ OPCODE(BEGIN_CLASS)
OPCODE(END_CLASS)
OPCODE(STORE_CLASS_ATTR)
/**************************/
// OPCODE(WITH_ENTER)
// OPCODE(WITH_EXIT)
OPCODE(WITH_ENTER)
OPCODE(WITH_EXIT)
/**************************/
OPCODE(ASSERT)
OPCODE(EXCEPTION_MATCH)

View File

@ -353,15 +353,15 @@ inline void init_builtins(VM* _vm) {
});
_vm->bind_method<1>("str", "__eq__", [](VM* vm, ArgsView args) {
if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str))
return VAR(CAST(Str&, args[0]) == CAST(Str&, args[1]));
return VAR(args[0] == args[1]);
const Str& self = CAST(Str&, args[0]);
if(!is_type(args[1], vm->tp_str)) return VAR(false);
return VAR(self == CAST(Str&, args[1]));
});
_vm->bind_method<1>("str", "__ne__", [](VM* vm, ArgsView args) {
if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str))
return VAR(CAST(Str&, args[0]) != CAST(Str&, args[1]));
return VAR(args[0] != args[1]);
const Str& self = CAST(Str&, args[0]);
if(!is_type(args[1], vm->tp_str)) return VAR(true);
return VAR(self != CAST(Str&, args[1]));
});
_vm->bind_method<1>("str", "__getitem__", [](VM* vm, ArgsView args) {
@ -609,6 +609,19 @@ inline void init_builtins(VM* _vm) {
return VAR(Str(self._data));
});
_vm->bind_method<1>("bytes", "__eq__", [](VM* vm, ArgsView args) {
const Bytes& self = CAST(Bytes&, args[0]);
if(!is_type(args[1], vm->tp_bytes)) return VAR(false);
const Bytes& other = CAST(Bytes&, args[1]);
return VAR(self == other);
});
_vm->bind_method<1>("bytes", "__ne__", [](VM* vm, ArgsView args) {
const Bytes& self = CAST(Bytes&, args[0]);
if(!is_type(args[1], vm->tp_bytes)) return VAR(true);
const Bytes& other = CAST(Bytes&, args[1]);
return VAR(self != other);
});
}
#ifdef _WIN32

View File

@ -18,6 +18,20 @@ with open('123.txt', 'a') as f:
with open('123.txt', 'r') as f:
assert f.read() == '123456' + '测试'
assert os.path_exists('123.txt')
assert os.path.exists('123.txt')
os.remove('123.txt')
assert not os.path_exists('123.txt')
assert not os.path.exists('123.txt')
with open('123.bin', 'wb') as f:
f.write('123'.encode())
f.write('测试'.encode())
with open('123.bin', 'rb') as f:
b = f.read()
assert isinstance(b, bytes)
assert b == '123测试'.encode()
assert os.path.exists('123.bin')
os.remove('123.bin')
assert not os.path.exists('123.bin')