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(); } DISPATCH();
/*****************************************/ /*****************************************/
// // TODO: using "goto" inside with block may cause __exit__ not called // // 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_ENTER)
// TARGET(WITH_EXIT) call(frame->pop_value(this), __exit__, no_arg()); DISPATCH(); call_method(POPX(), __enter__);
DISPATCH();
TARGET(WITH_EXIT)
call_method(POPX(), __exit__);
DISPATCH();
/*****************************************/ /*****************************************/
TARGET(ASSERT) { TARGET(ASSERT) {
PyObject* obj = TOP(); PyObject* obj = TOP();

View File

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

View File

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

View File

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

View File

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

View File

@ -102,8 +102,8 @@ OPCODE(BEGIN_CLASS)
OPCODE(END_CLASS) OPCODE(END_CLASS)
OPCODE(STORE_CLASS_ATTR) OPCODE(STORE_CLASS_ATTR)
/**************************/ /**************************/
// OPCODE(WITH_ENTER) OPCODE(WITH_ENTER)
// OPCODE(WITH_EXIT) OPCODE(WITH_EXIT)
/**************************/ /**************************/
OPCODE(ASSERT) OPCODE(ASSERT)
OPCODE(EXCEPTION_MATCH) 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) { _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)) const Str& self = CAST(Str&, args[0]);
return VAR(CAST(Str&, args[0]) == CAST(Str&, args[1])); if(!is_type(args[1], vm->tp_str)) return VAR(false);
return VAR(args[0] == args[1]); return VAR(self == CAST(Str&, args[1]));
}); });
_vm->bind_method<1>("str", "__ne__", [](VM* vm, ArgsView args) { _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)) const Str& self = CAST(Str&, args[0]);
return VAR(CAST(Str&, args[0]) != CAST(Str&, args[1])); if(!is_type(args[1], vm->tp_str)) return VAR(true);
return VAR(args[0] != args[1]); return VAR(self != CAST(Str&, args[1]));
}); });
_vm->bind_method<1>("str", "__getitem__", [](VM* vm, ArgsView args) { _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)); 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 #ifdef _WIN32

View File

@ -18,6 +18,20 @@ with open('123.txt', 'a') as f:
with open('123.txt', 'r') as f: with open('123.txt', 'r') as f:
assert f.read() == '123456' + '测试' assert f.read() == '123456' + '测试'
assert os.path_exists('123.txt') assert os.path.exists('123.txt')
os.remove('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')