소스 검색

add `os` module

blueloveTH 3 년 전
부모
커밋
765fb83007
10개의 변경된 파일151개의 추가작업 그리고 82개의 파일을 삭제
  1. 0 1
      .gitignore
  2. 1 1
      amalgamate.py
  3. 1 1
      preprocess.py
  4. 1 1
      src/ceval.h
  5. 3 7
      src/common.h
  6. 4 4
      src/frame.h
  7. 129 0
      src/io.h
  8. 1 64
      src/pocketpy.h
  9. 3 3
      src/vm.h
  10. 8 0
      tests/70_file.py

+ 0 - 1
.gitignore

@@ -19,7 +19,6 @@ plugins/flutter/example/web/lib/pocketpy.wasm
 plugins/flutter/src/pocketpy.h
 plugins/flutter/src/pocketpy.h
 plugins/macos/pocketpy/pocketpy.h
 plugins/macos/pocketpy/pocketpy.h
 plugins/godot/godot-cpp/
 plugins/godot/godot-cpp/
-123.txt
 src/_generated.h
 src/_generated.h
 profile.sh
 profile.sh
 test
 test

+ 1 - 1
amalgamate.py

@@ -9,7 +9,7 @@ pipeline = [
 	["common.h", "memory.h", "str.h", "tuplelist.h", "namedict.h", "error.h"],
 	["common.h", "memory.h", "str.h", "tuplelist.h", "namedict.h", "error.h"],
 	["obj.h", "parser.h", "codeobject.h", "frame.h"],
 	["obj.h", "parser.h", "codeobject.h", "frame.h"],
 	["vm.h", "ref.h", "ceval.h", "compiler.h", "repl.h"],
 	["vm.h", "ref.h", "ceval.h", "compiler.h", "repl.h"],
-	["iter.h", "cffi.h", "_generated.h", "pocketpy.h"]
+	["iter.h", "cffi.h", "io.h", "_generated.h", "pocketpy.h"]
 ]
 ]
 
 
 copied = set()
 copied = set()

+ 1 - 1
preprocess.py

@@ -20,7 +20,7 @@ def generate_python_sources():
 #include <string>
 #include <string>
 
 
 namespace pkpy{
 namespace pkpy{
-    std::map<std::string, std::string> kPythonLibs = {
+    std::map<std::string, const char*> kPythonLibs = {
 '''
 '''
     for key, value in sources.items():
     for key, value in sources.items():
         header += ' '*8 + '{"' + key + '", "' + value + '"},'
         header += ' '*8 + '{"' + key + '", "' + value + '"},'

+ 1 - 1
src/ceval.h

@@ -330,7 +330,7 @@ PyVar VM::run_frame(Frame* frame){
         if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE");
         if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE");
         return frame->pop_value(this);
         return frame->pop_value(this);
     }
     }
-#ifdef PK_EXTRA_CHECK
+#if PK_EXTRA_CHECK
     if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE");
     if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE");
 #endif
 #endif
     return None;
     return None;

+ 3 - 7
src/common.h

@@ -26,16 +26,16 @@
 #include <map>
 #include <map>
 #include <set>
 #include <set>
 #include <algorithm>
 #include <algorithm>
-#include <fstream>
 
 
-#define PK_VERSION "0.9.2"
+#define PK_VERSION				"0.9.3"
+#define PK_EXTRA_CHECK 			0
+#define PK_ENABLE_FILEIO 		1
 
 
 #if defined(__EMSCRIPTEN__) || defined(__arm__) || defined(__i386__)
 #if defined(__EMSCRIPTEN__) || defined(__arm__) || defined(__i386__)
 typedef int32_t i64;
 typedef int32_t i64;
 typedef float f64;
 typedef float f64;
 #define S_TO_INT std::stoi
 #define S_TO_INT std::stoi
 #define S_TO_FLOAT std::stof
 #define S_TO_FLOAT std::stof
-#define PKPY_USE_32_BITS
 #else
 #else
 typedef int64_t i64;
 typedef int64_t i64;
 typedef double f64;
 typedef double f64;
@@ -78,8 +78,4 @@ struct Type {
 const float kLocalsLoadFactor = 0.67f;
 const float kLocalsLoadFactor = 0.67f;
 const float kInstAttrLoadFactor = 0.67f;
 const float kInstAttrLoadFactor = 0.67f;
 const float kTypeAttrLoadFactor = 0.5f;
 const float kTypeAttrLoadFactor = 0.5f;
-
-// do extra check for debug
-// #define PK_EXTRA_CHECK
-
 } // namespace pkpy
 } // namespace pkpy

+ 4 - 4
src/frame.h

@@ -58,7 +58,7 @@ struct Frame {
     }
     }
 
 
     inline PyVar pop(){
     inline PyVar pop(){
-#ifdef PK_EXTRA_CHECK
+#if PK_EXTRA_CHECK
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");
 #endif
 #endif
         PyVar v = std::move(_data.back());
         PyVar v = std::move(_data.back());
@@ -67,7 +67,7 @@ struct Frame {
     }
     }
 
 
     inline void _pop(){
     inline void _pop(){
-#ifdef PK_EXTRA_CHECK
+#if PK_EXTRA_CHECK
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");
 #endif
 #endif
         _data.pop_back();
         _data.pop_back();
@@ -88,14 +88,14 @@ struct Frame {
     }
     }
 
 
     inline PyVar& top(){
     inline PyVar& top(){
-#ifdef PK_EXTRA_CHECK
+#if PK_EXTRA_CHECK
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");
 #endif
 #endif
         return _data.back();
         return _data.back();
     }
     }
 
 
     inline PyVar& top_1(){
     inline PyVar& top_1(){
-#ifdef PK_EXTRA_CHECK
+#if PK_EXTRA_CHECK
         if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
         if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
 #endif
 #endif
         return _data[_data.size()-2];
         return _data[_data.size()-2];

+ 129 - 0
src/io.h

@@ -0,0 +1,129 @@
+#pragma once
+
+#include "ceval.h"
+#include "cffi.h"
+
+#if PK_ENABLE_FILEIO
+
+#include <fstream>
+#include <filesystem>
+
+namespace pkpy{
+
+struct FileIO {
+    PY_CLASS(FileIO, io, FileIO)
+
+    Str file;
+    Str mode;
+    std::fstream _fs;
+
+    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(!_fs.is_open()) vm->IOError(strerror(errno));
+    }
+
+    static void _register(VM* vm, PyVar mod, PyVar type){
+        vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
+            return VAR_T(FileIO, 
+                vm, CAST(Str, args[0]), CAST(Str, args[1])
+            );
+        });
+
+        vm->bind_method<0>(type, "read", [](VM* vm, Args& args){
+            FileIO& io = CAST(FileIO&, args[0]);
+            std::string buffer;
+            io._fs >> buffer;
+            return VAR(buffer);
+        });
+
+        vm->bind_method<1>(type, "write", [](VM* vm, Args& args){
+            FileIO& io = CAST(FileIO&, args[0]);
+            io._fs << CAST(Str&, args[1]);
+            return vm->None;
+        });
+
+        vm->bind_method<0>(type, "close", [](VM* vm, Args& args){
+            FileIO& io = CAST(FileIO&, args[0]);
+            io._fs.close();
+            return vm->None;
+        });
+
+        vm->bind_method<0>(type, "__exit__", [](VM* vm, Args& args){
+            FileIO& io = CAST(FileIO&, args[0]);
+            io._fs.close();
+            return vm->None;
+        });
+
+        vm->bind_method<0>(type, "__enter__", CPP_LAMBDA(vm->None));
+    }
+};
+
+void add_module_io(VM* vm){
+    PyVar mod = vm->new_module("io");
+    PyVar type = FileIO::register_class(vm, mod);
+    vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
+        return vm->call(type, args);
+    });
+}
+
+void add_module_os(VM* vm){
+    PyVar mod = vm->new_module("os");
+    vm->bind_func<0>(mod, "getcwd", [](VM* vm, const Args& args){
+        return VAR(std::filesystem::current_path().string());
+    });
+
+    vm->bind_func<1>(mod, "listdir", [](VM* vm, const Args& args){
+        std::filesystem::path path(CAST(Str&, args[0]).c_str());
+        std::filesystem::directory_iterator di;
+        try{
+            di = std::filesystem::directory_iterator(path);
+        }catch(std::filesystem::filesystem_error& e){
+            Str msg = e.what();
+            auto pos = msg.find_last_of(":");
+            if(pos != Str::npos) msg = msg.substr(pos + 1);
+            vm->IOError(msg.lstrip());
+        }
+        List ret;
+        for(auto& p: di) ret.push_back(VAR(p.path().filename().string()));
+        return VAR(ret);
+    });
+
+    vm->bind_func<1>(mod, "remove", [](VM* vm, const Args& args){
+        std::filesystem::path path(CAST(Str&, args[0]).c_str());
+        bool ok = std::filesystem::remove(path);
+        if(!ok) vm->IOError("operation failed");
+        return vm->None;
+    });
+
+    vm->bind_func<1>(mod, "mkdir", [](VM* vm, const Args& args){
+        std::filesystem::path path(CAST(Str&, args[0]).c_str());
+        bool ok = std::filesystem::create_directory(path);
+        if(!ok) vm->IOError("operation failed");
+        return vm->None;
+    });
+
+    vm->bind_func<1>(mod, "rmdir", [](VM* vm, const Args& args){
+        std::filesystem::path path(CAST(Str&, args[0]).c_str());
+        bool ok = std::filesystem::remove(path);
+        if(!ok) vm->IOError("operation failed");
+        return vm->None;
+    });
+}
+
+} // namespace pkpy
+
+
+#else
+
+namespace pkpy{
+void add_module_io(VM* vm){}
+void add_module_os(VM* vm){}
+} // namespace pkpy
+
+#endif

+ 1 - 64
src/pocketpy.h

@@ -5,6 +5,7 @@
 #include "repl.h"
 #include "repl.h"
 #include "iter.h"
 #include "iter.h"
 #include "cffi.h"
 #include "cffi.h"
+#include "io.h"
 #include "_generated.h"
 #include "_generated.h"
 
 
 namespace pkpy {
 namespace pkpy {
@@ -546,7 +547,6 @@ void init_builtins(VM* _vm) {
 #define __EXPORT
 #define __EXPORT
 #endif
 #endif
 
 
-
 void add_module_time(VM* vm){
 void add_module_time(VM* vm){
     PyVar mod = vm->new_module("time");
     PyVar mod = vm->new_module("time");
     vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) {
     vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) {
@@ -609,69 +609,6 @@ void add_module_dis(VM* vm){
     });
     });
 }
 }
 
 
-struct FileIO {
-    PY_CLASS(FileIO, io, FileIO)
-
-    Str file;
-    Str mode;
-    std::fstream _fs;
-
-    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(!_fs.is_open()) vm->IOError(strerror(errno));
-    }
-
-    static void _register(VM* vm, PyVar mod, PyVar type){
-        vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
-            return VAR_T(FileIO, 
-                vm, CAST(Str, args[0]), CAST(Str, args[1])
-            );
-        });
-
-        vm->bind_method<0>(type, "read", [](VM* vm, Args& args){
-            FileIO& io = CAST(FileIO&, args[0]);
-            std::string buffer;
-            io._fs >> buffer;
-            return VAR(buffer);
-        });
-
-        vm->bind_method<1>(type, "write", [](VM* vm, Args& args){
-            FileIO& io = CAST(FileIO&, args[0]);
-            io._fs << CAST(Str&, args[1]);
-            return vm->None;
-        });
-
-        vm->bind_method<0>(type, "close", [](VM* vm, Args& args){
-            FileIO& io = CAST(FileIO&, args[0]);
-            io._fs.close();
-            return vm->None;
-        });
-
-        vm->bind_method<0>(type, "__exit__", [](VM* vm, Args& args){
-            FileIO& io = CAST(FileIO&, args[0]);
-            io._fs.close();
-            return vm->None;
-        });
-
-        vm->bind_method<0>(type, "__enter__", CPP_LAMBDA(vm->None));
-    }
-};
-void add_module_io(VM* vm){
-    PyVar mod = vm->new_module("io");
-    PyVar type = FileIO::register_class(vm, mod);
-    vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
-        return vm->call(type, args);
-    });
-}
-
-void add_module_os(VM* vm){}
-
 struct ReMatch {
 struct ReMatch {
     PY_CLASS(ReMatch, re, Match)
     PY_CLASS(ReMatch, re, Match)
 
 

+ 3 - 3
src/vm.h

@@ -79,7 +79,7 @@ public:
     }
     }
 
 
     inline Frame* top_frame() const {
     inline Frame* top_frame() const {
-#ifdef PK_EXTRA_CHECK
+#if PK_EXTRA_CHECK
         if(callstack.empty()) UNREACHABLE();
         if(callstack.empty()) UNREACHABLE();
 #endif
 #endif
         return callstack.top().get();
         return callstack.top().get();
@@ -170,14 +170,14 @@ public:
 
 
     template<typename T>
     template<typename T>
     inline PyVar new_object(const PyVar& type, const T& _value) {
     inline PyVar new_object(const PyVar& type, const T& _value) {
-#ifdef PK_EXTRA_CHECK
+#if PK_EXTRA_CHECK
         if(!is_type(type, tp_type)) UNREACHABLE();
         if(!is_type(type, tp_type)) UNREACHABLE();
 #endif
 #endif
         return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value);
         return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), _value);
     }
     }
     template<typename T>
     template<typename T>
     inline PyVar new_object(const PyVar& type, T&& _value) {
     inline PyVar new_object(const PyVar& type, T&& _value) {
-#ifdef PK_EXTRA_CHECK
+#if PK_EXTRA_CHECK
         if(!is_type(type, tp_type)) UNREACHABLE();
         if(!is_type(type, tp_type)) UNREACHABLE();
 #endif
 #endif
         return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), std::move(_value));
         return make_sp<PyObject, Py_<std::decay_t<T>>>(OBJ_GET(Type, type), std::move(_value));

+ 8 - 0
tests/70_file.py

@@ -1,3 +1,9 @@
+try:
+    import os
+    import io
+except ImportError:
+    exit(0)
+
 a = open('123.txt', 'wt')
 a = open('123.txt', 'wt')
 a.write('123')
 a.write('123')
 a.write('456')
 a.write('456')
@@ -11,3 +17,5 @@ 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' + '测试'
+
+os.remove('123.txt')