mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
...
This commit is contained in:
parent
d70b7653f2
commit
f7af705367
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
65
src/io.h
65
src/io.h
@ -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);
|
||||
});
|
||||
|
@ -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>;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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')
|
Loading…
x
Reference in New Issue
Block a user