Browse Source

move all to `pkpy` namespace

blueloveTH 3 năm trước cách đây
mục cha
commit
aab4ff7647
19 tập tin đã thay đổi với 631 bổ sung513 xóa
  1. 24 20
      src/ceval.h
  2. 26 22
      src/cffi.h
  3. 8 3
      src/codeobject.h
  4. 7 5
      src/common.h
  5. 13 9
      src/compiler.h
  6. 4 2
      src/error.h
  7. 11 7
      src/frame.h
  8. 7 3
      src/iter.h
  9. 3 1
      src/main.cpp
  10. 78 76
      src/memory.h
  11. 162 161
      src/namedict.h
  12. 34 14
      src/obj.h
  13. 7 3
      src/parser.h
  14. 125 125
      src/pocketpy.h
  15. 8 3
      src/ref.h
  16. 5 1
      src/repl.h
  17. 5 1
      src/str.h
  18. 3 3
      src/tuplelist.h
  19. 101 54
      src/vm.h

+ 24 - 20
src/ceval.h

@@ -2,6 +2,8 @@
 
 #include "vm.h"
 
+namespace pkpy{
+
 PyVar VM::run_frame(Frame* frame){
     while(frame->has_next_bytecode()){
         const Bytecode& byte = frame->next_bytecode();
@@ -15,12 +17,12 @@ PyVar VM::run_frame(Frame* frame){
         case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
         case OP_LOAD_FUNCTION: {
             const PyVar obj = frame->co->consts[byte.arg];
-            pkpy::Function f = PyFunction_AS_C(obj);  // copy
+            Function f = PyFunction_AS_C(obj);  // copy
             f._module = frame->_module;
             frame->push(PyFunction(f));
         } continue;
         case OP_SETUP_CLOSURE: {
-            pkpy::Function& f = PyFunction_AS_C(frame->top());    // reference
+            Function& f = PyFunction_AS_C(frame->top());    // reference
             f._closure = frame->_locals;
         } continue;
         case OP_LOAD_NAME_REF: {
@@ -66,15 +68,15 @@ PyVar VM::run_frame(Frame* frame){
             frame->_pop();
             continue;
         case OP_BUILD_TUPLE: {
-            pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg);
+            Args items = frame->pop_n_values_reversed(this, byte.arg);
             frame->push(PyTuple(std::move(items)));
         } continue;
         case OP_BUILD_TUPLE_REF: {
-            pkpy::Args items = frame->pop_n_reversed(byte.arg);
+            Args items = frame->pop_n_reversed(byte.arg);
             frame->push(PyRef(TupleRef(std::move(items))));
         } continue;
         case OP_BUILD_STRING: {
-            pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg);
+            Args items = frame->pop_n_values_reversed(this, byte.arg);
             StrStream ss;
             for(int i=0; i<items.size(); i++) ss << PyStr_AS_C(asStr(items[i]));
             frame->push(PyStr(ss.str()));
@@ -82,7 +84,7 @@ PyVar VM::run_frame(Frame* frame){
         case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue;
         case OP_LIST_APPEND: {
             PyVar obj = frame->pop_value(this);
-            pkpy::List& list = PyList_AS_C(frame->top_1());
+            List& list = PyList_AS_C(frame->top_1());
             list.push_back(std::move(obj));
         } continue;
         case OP_BEGIN_CLASS: {
@@ -110,19 +112,19 @@ PyVar VM::run_frame(Frame* frame){
         } continue;
         case OP_POP_TOP: frame->_pop(); continue;
         case OP_BINARY_OP: {
-            pkpy::Args args(2);
+            Args args(2);
             args[1] = frame->pop_value(this);
             args[0] = frame->top_value(this);
             frame->top() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
         } continue;
         case OP_BITWISE_OP: {
-            pkpy::Args args(2);
+            Args args(2);
             args[1] = frame->pop_value(this);
             args[0] = frame->top_value(this);
             frame->top() = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
         } continue;
         case OP_INPLACE_BINARY_OP: {
-            pkpy::Args args(2);
+            Args args(2);
             args[1] = frame->pop();
             args[0] = frame->top_value(this);
             PyVar ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
@@ -130,7 +132,7 @@ PyVar VM::run_frame(Frame* frame){
             frame->_pop();
         } continue;
         case OP_INPLACE_BITWISE_OP: {
-            pkpy::Args args(2);
+            Args args(2);
             args[1] = frame->pop_value(this);
             args[0] = frame->top_value(this);
             PyVar ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
@@ -138,7 +140,7 @@ PyVar VM::run_frame(Frame* frame){
             frame->_pop();
         } continue;
         case OP_COMPARE_OP: {
-            pkpy::Args args(2);
+            Args args(2);
             args[1] = frame->pop_value(this);
             args[0] = frame->top_value(this);
             frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args));
@@ -151,7 +153,7 @@ PyVar VM::run_frame(Frame* frame){
         } continue;
         case OP_CONTAINS_OP: {
             PyVar rhs = frame->pop_value(this);
-            bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::one_arg(frame->pop_value(this))));
+            bool ret_c = PyBool_AS_C(call(rhs, __contains__, one_arg(frame->pop_value(this))));
             if(byte.arg == 1) ret_c = !ret_c;
             frame->push(PyBool(ret_c));
         } continue;
@@ -192,10 +194,10 @@ PyVar VM::run_frame(Frame* frame){
             frame->push(PyList(frame->pop_n_values_reversed(this, byte.arg).move_to_list()));
             continue;
         case OP_BUILD_MAP: {
-            pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg*2);
+            Args items = frame->pop_n_values_reversed(this, byte.arg*2);
             PyVar obj = call(builtins->attr("dict"));
             for(int i=0; i<items.size(); i+=2){
-                call(obj, __setitem__, pkpy::two_args(items[i], items[i+1]));
+                call(obj, __setitem__, two_args(items[i], items[i+1]));
             }
             frame->push(obj);
         } continue;
@@ -203,7 +205,7 @@ PyVar VM::run_frame(Frame* frame){
             PyVar list = PyList(
                 frame->pop_n_values_reversed(this, byte.arg).move_to_list()
             );
-            PyVar obj = call(builtins->attr("set"), pkpy::one_arg(list));
+            PyVar obj = call(builtins->attr("set"), one_arg(list));
             frame->push(obj);
         } continue;
         case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
@@ -218,8 +220,8 @@ PyVar VM::run_frame(Frame* frame){
         case OP_CALL_KWARGS_UNPACK: case OP_CALL_KWARGS: {
             int ARGC = byte.arg & 0xFFFF;
             int KWARGC = (byte.arg >> 16) & 0xFFFF;
-            pkpy::Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
-            pkpy::Args args = frame->pop_n_values_reversed(this, ARGC);
+            Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
+            Args args = frame->pop_n_values_reversed(this, ARGC);
             if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
             PyVar callable = frame->pop_value(this);
             PyVar ret = call(callable, std::move(args), kwargs, true);
@@ -227,10 +229,10 @@ PyVar VM::run_frame(Frame* frame){
             frame->push(std::move(ret));
         } continue;
         case OP_CALL_UNPACK: case OP_CALL: {
-            pkpy::Args args = frame->pop_n_values_reversed(this, byte.arg);
+            Args args = frame->pop_n_values_reversed(this, byte.arg);
             if(byte.op == OP_CALL_UNPACK) unpack_args(args);
             PyVar callable = frame->pop_value(this);
-            PyVar ret = call(callable, std::move(args), pkpy::no_arg(), true);
+            PyVar ret = call(callable, std::move(args), no_arg(), true);
             if(ret == _py_op_call) return ret;
             frame->push(std::move(ret));
         } continue;
@@ -280,7 +282,7 @@ PyVar VM::run_frame(Frame* frame){
         case OP_BUILD_SLICE: {
             PyVar stop = frame->pop_value(this);
             PyVar start = frame->pop_value(this);
-            pkpy::Slice s;
+            Slice s;
             if(start != None) { s.start = (int)PyInt_AS_C(start);}
             if(stop != None) { s.stop = (int)PyInt_AS_C(stop);}
             frame->push(PySlice(s));
@@ -332,3 +334,5 @@ PyVar VM::run_frame(Frame* frame){
 #endif
     return None;
 }
+
+} // namespace pkpy

+ 26 - 22
src/cffi.h

@@ -2,6 +2,8 @@
 
 #include "vm.h"
 
+namespace pkpy {
+
 struct CType{
     PY_CLASS(c, type_)
 
@@ -13,7 +15,7 @@ struct CType{
     static void _register(VM* vm, PyVar mod, PyVar type){
         vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
 
-        vm->bind_method<0>(type, "__repr__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
             CType& self = vm->py_cast<CType>(args[0]);
             StrStream ss;
             ss << "<c._type '" << self.name << "' (" << self.size*8 << " bits)>";
@@ -67,61 +69,61 @@ struct Pointer{
     static void _register(VM* vm, PyVar mod, PyVar type){
         vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
 
-        vm->bind_method<0>(type, "__repr__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             StrStream ss;
             ss << "<" << self.ctype.name << "* at " << (i64)self.ptr << ">";
             return vm->PyStr(ss.str());
         });
 
-        vm->bind_method<1>(type, "__add__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<1>(type, "__add__", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             return vm->new_object<Pointer>(self + vm->PyInt_AS_C(args[1]));
         });
 
-        vm->bind_method<1>(type, "__sub__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<1>(type, "__sub__", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             return vm->new_object<Pointer>(self - vm->PyInt_AS_C(args[1]));
         });
 
-        vm->bind_method<1>(type, "__eq__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<1>(type, "__eq__", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             Pointer& other = vm->py_cast<Pointer>(args[1]);
             return vm->PyBool(self.ptr == other.ptr);
         });
 
-        vm->bind_method<1>(type, "__ne__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<1>(type, "__ne__", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             Pointer& other = vm->py_cast<Pointer>(args[1]);
             return vm->PyBool(self.ptr != other.ptr);
         });
 
         // https://docs.python.org/zh-cn/3/library/ctypes.html
-        vm->bind_method<1>(type, "__getitem__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<1>(type, "__getitem__", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             i64 index = vm->PyInt_AS_C(args[1]);
             return (self+index).get(vm);
         });
 
-        vm->bind_method<2>(type, "__setitem__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<2>(type, "__setitem__", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             i64 index = vm->PyInt_AS_C(args[1]);
             (self+index).set(vm, args[2]);
             return vm->None;
         });
 
-        vm->bind_method<1>(type, "cast", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<1>(type, "cast", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             CType& ctype = vm->py_cast<CType>(args[1]);
             return vm->new_object<Pointer>(self.ptr, ctype);
         });
 
-        vm->bind_method<0>(type, "get", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<0>(type, "get", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             return self.get(vm);
         });
 
-        vm->bind_method<1>(type, "set", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<1>(type, "set", [](VM* vm, Args& args) {
             Pointer& self = vm->py_cast<Pointer>(args[0]);
             self.set(vm, args[1]);
             return vm->None;
@@ -235,11 +237,11 @@ struct Struct {
     }
 
     static void _register(VM* vm, PyVar mod, PyVar type){
-        vm->bind_static_method<-1>(type, "__new__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_static_method<-1>(type, "__new__", [](VM* vm, Args& args) {
             return vm->new_object<Struct>();
         });
 
-        vm->bind_method<0>(type, "__repr__", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
             Struct& self = vm->py_cast<Struct>(args[0]);
             StrStream ss;
             ss << self.info->name << "(" << ")";
@@ -259,23 +261,23 @@ void add_module_c(VM* vm){
     }
     vm->setattr(mod, "nullptr", vm->new_object<Pointer>(nullptr, C_TYPE_T("void_")));
 
-    vm->bind_func<1>(mod, "malloc", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "malloc", [](VM* vm, Args& args) {
         i64 size = vm->PyInt_AS_C(args[0]);
         return vm->new_object<Pointer>(malloc(size), C_TYPE_T("void_"));
     });
 
-    vm->bind_func<1>(mod, "free", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "free", [](VM* vm, Args& args) {
         Pointer& self = vm->py_cast<Pointer>(args[0]);
         free(self.ptr);
         return vm->None;
     });
 
-    vm->bind_func<1>(mod, "sizeof", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "sizeof", [](VM* vm, Args& args) {
         CType& ctype = vm->py_cast<CType>(args[0]);
         return vm->PyInt(ctype.size);
     });
 
-    vm->bind_func<3>(mod, "memcpy", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<3>(mod, "memcpy", [](VM* vm, Args& args) {
         Pointer& dst = vm->py_cast<Pointer>(args[0]);
         Pointer& src = vm->py_cast<Pointer>(args[1]);
         i64 size = vm->PyInt_AS_C(args[2]);
@@ -283,7 +285,7 @@ void add_module_c(VM* vm){
         return vm->None;
     });
 
-    vm->bind_func<3>(mod, "memset", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<3>(mod, "memset", [](VM* vm, Args& args) {
         Pointer& dst = vm->py_cast<Pointer>(args[0]);
         i64 val = vm->PyInt_AS_C(args[1]);
         i64 size = vm->PyInt_AS_C(args[2]);
@@ -291,7 +293,7 @@ void add_module_c(VM* vm){
         return vm->None;
     });
 
-    vm->bind_func<1>(mod, "strdup", [ptr_t](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "strdup", [ptr_t](VM* vm, Args& args) {
         if(is_type(args[0], vm->tp_str)){
             const Str& s = vm->PyStr_AS_C(args[0]);
             return vm->new_object<Pointer>(strdup(s.c_str()), C_TYPE_T("char_"));
@@ -304,14 +306,16 @@ void add_module_c(VM* vm){
         }
     });
 
-    vm->bind_func<2>(mod, "strcmp", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<2>(mod, "strcmp", [](VM* vm, Args& args) {
         Pointer& p1 = vm->py_cast<Pointer>(args[0]);
         Pointer& p2 = vm->py_cast<Pointer>(args[1]);
         return vm->PyInt(strcmp(p1.cast<char*>(), p2.cast<char*>()));
     });
 
-    vm->bind_func<1>(mod, "strlen", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "strlen", [](VM* vm, Args& args) {
         Pointer& p = vm->py_cast<Pointer>(args[0]);
         return vm->PyInt(strlen(p.cast<char*>()));
     });
-}
+}
+
+}   // namespace pkpy

+ 8 - 3
src/codeobject.h

@@ -4,6 +4,8 @@
 #include "ref.h"
 #include "error.h"
 
+namespace pkpy{
+
 enum Opcode {
     #define OPCODE(name) OP_##name,
     #include "opcodes.h"
@@ -49,17 +51,17 @@ struct CodeBlock {
 };
 
 struct CodeObject {
-    pkpy::shared_ptr<SourceData> src;
+    shared_ptr<SourceData> src;
     Str name;
     bool is_generator = false;
 
-    CodeObject(pkpy::shared_ptr<SourceData> src, Str name) {
+    CodeObject(shared_ptr<SourceData> src, Str name) {
         this->src = src;
         this->name = name;
     }
 
     std::vector<Bytecode> codes;
-    pkpy::List consts;
+    List consts;
     std::vector<std::pair<StrName, NameScope>> names;
     std::map<StrName, int> global_names;
     std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, -1} };
@@ -111,3 +113,6 @@ struct CodeObject {
     }
     /************************************************/
 };
+
+
+} // namespace pkpy

+ 7 - 5
src/common.h

@@ -26,8 +26,6 @@
 #include <map>
 #include <set>
 #include <algorithm>
-// #include <filesystem>
-// namespace fs = std::filesystem;
 
 #define PK_VERSION "0.9.1"
 
@@ -43,6 +41,8 @@ typedef double f64;
 #define S_TO_FLOAT std::stod
 #endif
 
+namespace pkpy{
+
 struct Dummy {  };
 struct DummyInstance {  };
 struct DummyModule { };
@@ -62,8 +62,8 @@ struct Type {
 
 //#define THREAD_LOCAL thread_local
 #define THREAD_LOCAL
-#define CPP_LAMBDA(x) ([](VM* vm, pkpy::Args& args) { return x; })
-#define CPP_NOT_IMPLEMENTED() ([](VM* vm, pkpy::Args& args) { vm->NotImplementedError(); return vm->None; })
+#define CPP_LAMBDA(x) ([](VM* vm, Args& args) { return x; })
+#define CPP_NOT_IMPLEMENTED() ([](VM* vm, Args& args) { vm->NotImplementedError(); return vm->None; })
 
 #ifdef POCKETPY_H
 #define UNREACHABLE() throw std::runtime_error( "L" + std::to_string(__LINE__) + " UNREACHABLE()!");
@@ -78,4 +78,6 @@ const float kInstAttrLoadFactor = 0.67;
 const float kTypeAttrLoadFactor = 0.5;
 
 // do extra check for debug
-#define PK_EXTRA_CHECK
+#define PK_EXTRA_CHECK
+
+} // namespace pkpy

+ 13 - 9
src/compiler.h

@@ -4,6 +4,8 @@
 #include "error.h"
 #include "ceval.h"
 
+namespace pkpy{
+
 class Compiler;
 typedef void (Compiler::*GrammarFn)();
 typedef void (Compiler::*CompilerAction)();
@@ -32,7 +34,7 @@ public:
     Compiler(VM* vm, const char* source, Str filename, CompileMode mode){
         this->vm = vm;
         this->parser = std::make_unique<Parser>(
-            pkpy::make_shared<SourceData>(source, filename, mode)
+            make_sp<SourceData>(source, filename, mode)
         );
 
 // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
@@ -385,13 +387,13 @@ private:
     }
 
     void exprLambda() {
-        pkpy::Function func;
+        Function func;
         func.name = "<lambda>";
         if(!match(TK(":"))){
             _compile_f_args(func, false);
             consume(TK(":"));
         }
-        func.code = pkpy::make_shared<CodeObject>(parser->src, func.name.str());
+        func.code = make_sp<CodeObject>(parser->src, func.name.str());
         this->codes.push(func.code);
         co()->_rvalue += 1; EXPR_TUPLE(); co()->_rvalue -= 1;
         emit(OP_RETURN_VALUE);
@@ -1009,7 +1011,7 @@ __LISTCOMP:
         emit(OP_END_CLASS);
     }
 
-    void _compile_f_args(pkpy::Function& func, bool enable_type_hints){
+    void _compile_f_args(Function& func, bool enable_type_hints){
         int state = 0;      // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
         do {
             if(state == 3) SyntaxError("**kwargs should be the last argument");
@@ -1051,7 +1053,7 @@ __LISTCOMP:
 
     void compile_function(){
         bool has_decorator = !co()->codes.empty() && co()->codes.back().op == OP_SETUP_DECORATOR;
-        pkpy::Function func;
+        Function func;
         StrName obj_name;
         consume(TK("@id"));
         func.name = parser->prev.str();
@@ -1066,7 +1068,7 @@ __LISTCOMP:
             consume(TK(")"));
         }
         if(match(TK("->"))) consume(TK("@id")); // eat type hints
-        func.code = pkpy::make_shared<CodeObject>(parser->src, func.name.str());
+        func.code = make_sp<CodeObject>(parser->src, func.name.str());
         this->codes.push(func.code);
         compile_block_body();
         func.code->optimize(vm);
@@ -1116,7 +1118,7 @@ __LISTCOMP:
             cursor = parser->curr_char;
         }
         if(parser->peekchar() == '\n') lineno--;
-        auto e = pkpy::Exception("SyntaxError", msg);
+        auto e = Exception("SyntaxError", msg);
         e.st_push(parser->src->snapshot(lineno, cursor));
         throw e;
     }
@@ -1130,7 +1132,7 @@ public:
         if(used) UNREACHABLE();
         used = true;
 
-        CodeObject_ code = pkpy::make_shared<CodeObject>(parser->src, Str("<module>"));
+        CodeObject_ code = make_sp<CodeObject>(parser->src, Str("<module>"));
         codes.push(code);
 
         lex_token(); lex_token();
@@ -1162,4 +1164,6 @@ public:
         code->optimize(vm);
         return code;
     }
-};
+};
+
+} // namespace pkpy

+ 4 - 2
src/error.h

@@ -3,6 +3,8 @@
 #include "namedict.h"
 #include "tuplelist.h"
 
+namespace pkpy{
+
 struct NeedMoreLines {
     NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
     bool is_compiling_class;
@@ -67,7 +69,6 @@ struct SourceData {
     ~SourceData() { free((void*)source); }
 };
 
-namespace pkpy{
 class Exception {
     StrName type;
     Str msg;
@@ -92,4 +93,5 @@ public:
         return ss.str();
     }
 };
-}
+
+}   // namespace pkpy

+ 11 - 7
src/frame.h

@@ -2,6 +2,8 @@
 
 #include "codeobject.h"
 
+namespace pkpy{
+
 static THREAD_LOCAL uint64_t kFrameGlobalId = 0;
 
 struct Frame {
@@ -16,8 +18,8 @@ struct Frame {
     const uint64_t id;
     std::vector<std::pair<int, std::vector<PyVar>>> s_try_block;
 
-    inline pkpy::NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
-    inline pkpy::NameDict& f_globals() noexcept { return _module->attr(); }
+    inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
+    inline NameDict& f_globals() noexcept { return _module->attr(); }
 
     inline PyVar* f_closure_try_get(StrName name) noexcept {
         if(_closure == nullptr) return nullptr;
@@ -143,8 +145,8 @@ struct Frame {
         }
     }
 
-    pkpy::Args pop_n_values_reversed(VM* vm, int n){
-        pkpy::Args v(n);
+    Args pop_n_values_reversed(VM* vm, int n){
+        Args v(n);
         for(int i=n-1; i>=0; i--){
             v[i] = pop();
             try_deref(vm, v[i]);
@@ -152,9 +154,11 @@ struct Frame {
         return v;
     }
 
-    pkpy::Args pop_n_reversed(int n){
-        pkpy::Args v(n);
+    Args pop_n_reversed(int n){
+        Args v(n);
         for(int i=n-1; i>=0; i--) v[i] = pop();
         return v;
     }
-};
+};
+
+}; // namespace pkpy

+ 7 - 3
src/iter.h

@@ -2,12 +2,14 @@
 
 #include "ceval.h"
 
+namespace pkpy{
+
 class RangeIter : public BaseIter {
     i64 current;
-    pkpy::Range r;
+    Range r;
 public:
     RangeIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) {
-        this->r = OBJ_GET(pkpy::Range, _ref);
+        this->r = OBJ_GET(Range, _ref);
         this->current = r.start;
     }
 
@@ -61,4 +63,6 @@ PyVar Generator::next(){
         state = 2;
         return nullptr;
     }
-}
+}
+
+} // namespace pkpy

+ 3 - 1
src/main.cpp

@@ -1,11 +1,13 @@
 #include <fstream>
 #include "pocketpy.h"
 
+using namespace pkpy;
+
 #ifndef __EMSCRIPTEN__
 
 int main(int argc, char** argv){
     VM* vm = pkpy_new_vm(true);
-    vm->bind_builtin_func<0>("input", [](VM* vm, pkpy::Args& args){
+    vm->bind_builtin_func<0>("input", [](VM* vm, Args& args){
         static std::string line;
         std::getline(std::cin, line);
         return vm->PyStr(line);

+ 78 - 76
src/memory.h

@@ -2,97 +2,98 @@
 
 #include "common.h"
 
+namespace pkpy{
+
 struct PyObject;
 
-namespace pkpy{
-    template<typename T>
-    struct SpAllocator {
-        template<typename U>
-        inline static int* alloc(){
-            return (int*)malloc(sizeof(int) + sizeof(U));
-        }
+template<typename T>
+struct SpAllocator {
+    template<typename U>
+    inline static int* alloc(){
+        return (int*)malloc(sizeof(int) + sizeof(U));
+    }
 
-        inline static void dealloc(int* counter){
-            ((T*)(counter + 1))->~T();
-            free(counter);
-        }
-    };
+    inline static void dealloc(int* counter){
+        ((T*)(counter + 1))->~T();
+        free(counter);
+    }
+};
 
-    template <typename T>
-    struct shared_ptr {
-        union {
-            int* counter;
-            i64 bits;
-        };
+template <typename T>
+struct shared_ptr {
+    union {
+        int* counter;
+        i64 bits;
+    };
 
 #define _t() (T*)(counter + 1)
 #define _inc_counter() if(!is_tagged() && counter) ++(*counter)
 #define _dec_counter() if(!is_tagged() && counter && --(*counter) == 0) SpAllocator<T>::dealloc(counter)
 
-    public:
-        shared_ptr() : counter(nullptr) {}
-        shared_ptr(int* counter) : counter(counter) {}
-        shared_ptr(const shared_ptr& other) : counter(other.counter) {
-            _inc_counter();
-        }
-        shared_ptr(shared_ptr&& other) noexcept : counter(other.counter) {
-            other.counter = nullptr;
-        }
-        ~shared_ptr() { _dec_counter(); }
-
-        bool operator==(const shared_ptr& other) const { return counter == other.counter; }
-        bool operator!=(const shared_ptr& other) const { return counter != other.counter; }
-        bool operator<(const shared_ptr& other) const { return counter < other.counter; }
-        bool operator>(const shared_ptr& other) const { return counter > other.counter; }
-        bool operator<=(const shared_ptr& other) const { return counter <= other.counter; }
-        bool operator>=(const shared_ptr& other) const { return counter >= other.counter; }
-        bool operator==(std::nullptr_t) const { return counter == nullptr; }
-        bool operator!=(std::nullptr_t) const { return counter != nullptr; }
-
-        shared_ptr& operator=(const shared_ptr& other) {
-            _dec_counter();
-            counter = other.counter;
-            _inc_counter();
-            return *this;
-        }
+public:
+    shared_ptr() : counter(nullptr) {}
+    shared_ptr(int* counter) : counter(counter) {}
+    shared_ptr(const shared_ptr& other) : counter(other.counter) {
+        _inc_counter();
+    }
+    shared_ptr(shared_ptr&& other) noexcept : counter(other.counter) {
+        other.counter = nullptr;
+    }
+    ~shared_ptr() { _dec_counter(); }
+
+    bool operator==(const shared_ptr& other) const { return counter == other.counter; }
+    bool operator!=(const shared_ptr& other) const { return counter != other.counter; }
+    bool operator<(const shared_ptr& other) const { return counter < other.counter; }
+    bool operator>(const shared_ptr& other) const { return counter > other.counter; }
+    bool operator<=(const shared_ptr& other) const { return counter <= other.counter; }
+    bool operator>=(const shared_ptr& other) const { return counter >= other.counter; }
+    bool operator==(std::nullptr_t) const { return counter == nullptr; }
+    bool operator!=(std::nullptr_t) const { return counter != nullptr; }
+
+    shared_ptr& operator=(const shared_ptr& other) {
+        _dec_counter();
+        counter = other.counter;
+        _inc_counter();
+        return *this;
+    }
 
-        shared_ptr& operator=(shared_ptr&& other) noexcept {
-            _dec_counter();
-            counter = other.counter;
-            other.counter = nullptr;
-            return *this;
-        }
+    shared_ptr& operator=(shared_ptr&& other) noexcept {
+        _dec_counter();
+        counter = other.counter;
+        other.counter = nullptr;
+        return *this;
+    }
 
-        T& operator*() const { return *_t(); }
-        T* operator->() const { return _t(); }
-        T* get() const { return _t(); }
+    T& operator*() const { return *_t(); }
+    T* operator->() const { return _t(); }
+    T* get() const { return _t(); }
 
-        int use_count() const { 
-            if(is_tagged()) return 1;
-            return counter ? *counter : 0;
-        }
+    int use_count() const { 
+        if(is_tagged()) return 1;
+        return counter ? *counter : 0;
+    }
 
-        void reset(){
-            _dec_counter();
-            counter = nullptr;
-        }
+    void reset(){
+        _dec_counter();
+        counter = nullptr;
+    }
 
-        inline constexpr bool is_tagged() const {
-            if constexpr(!std::is_same_v<T, PyObject>) return false;
-            return (bits & 0b11) != 0b00;
-        }
-        inline bool is_tag_00() const { return (bits & 0b11) == 0b00; }
-        inline bool is_tag_01() const { return (bits & 0b11) == 0b01; }
-        inline bool is_tag_10() const { return (bits & 0b11) == 0b10; }
-        inline bool is_tag_11() const { return (bits & 0b11) == 0b11; }
-    };
+    inline constexpr bool is_tagged() const {
+        if constexpr(!std::is_same_v<T, PyObject>) return false;
+        return (bits & 0b11) != 0b00;
+    }
+    inline bool is_tag_00() const { return (bits & 0b11) == 0b00; }
+    inline bool is_tag_01() const { return (bits & 0b11) == 0b01; }
+    inline bool is_tag_10() const { return (bits & 0b11) == 0b10; }
+    inline bool is_tag_11() const { return (bits & 0b11) == 0b11; }
+};
 
 #undef _t
 #undef _inc_counter
 #undef _dec_counter
 
     template <typename T, typename U, typename... Args>
-    shared_ptr<T> make_shared(Args&&... args) {
+    shared_ptr<T> make_sp(Args&&... args) {
         static_assert(std::is_base_of_v<T, U>, "U must be derived from T");
         static_assert(std::has_virtual_destructor_v<T>, "T must have virtual destructor");
         static_assert(!std::is_same_v<T, PyObject> || (!std::is_same_v<U, i64> && !std::is_same_v<U, f64>));
@@ -102,16 +103,15 @@ namespace pkpy{
     }
 
     template <typename T, typename... Args>
-    shared_ptr<T> make_shared(Args&&... args) {
+    shared_ptr<T> make_sp(Args&&... args) {
         int* p = SpAllocator<T>::template alloc<T>(); *p = 1;
         new(p+1) T(std::forward<Args>(args)...);
         return shared_ptr<T>(p);
     }
-};
 
 static_assert(sizeof(i64) == sizeof(int*));
 static_assert(sizeof(f64) == sizeof(int*));
-static_assert(sizeof(pkpy::shared_ptr<PyObject>) == sizeof(int*));
+static_assert(sizeof(shared_ptr<PyObject>) == sizeof(int*));
 static_assert(std::numeric_limits<float>::is_iec559);
 static_assert(std::numeric_limits<double>::is_iec559);
 
@@ -147,6 +147,8 @@ struct SmallArrayPool {
 };
 
 
-typedef pkpy::shared_ptr<PyObject> PyVar;
+typedef shared_ptr<PyObject> PyVar;
 typedef PyVar PyVarOrNull;
-typedef PyVar PyVarRef;
+typedef PyVar PyVarRef;
+
+};  // namespace pkpy

+ 162 - 161
src/namedict.h

@@ -4,6 +4,8 @@
 #include "memory.h"
 #include "str.h"
 
+namespace pkpy{
+
 const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyVar);
 
 template<int __Bucket, int __BucketSize=32>
@@ -38,199 +40,198 @@ struct DictArrayPool {
     }
 };
 
-namespace pkpy{
-    const std::vector<uint16_t> kHashSeeds = {9629, 43049, 13267, 59509, 39251, 1249, 35803, 54469, 27689, 9719, 34897, 18973, 30661, 19913, 27919, 32143, 3467, 28019, 1051, 39419, 1361, 28547, 48197, 2609, 24317, 22861, 41467, 17623, 52837, 59053, 33589, 32117};
-    static DictArrayPool<32> _dict_pool;
+const std::vector<uint16_t> kHashSeeds = {9629, 43049, 13267, 59509, 39251, 1249, 35803, 54469, 27689, 9719, 34897, 18973, 30661, 19913, 27919, 32143, 3467, 28019, 1051, 39419, 1361, 28547, 48197, 2609, 24317, 22861, 41467, 17623, 52837, 59053, 33589, 32117};
+static DictArrayPool<32> _dict_pool;
 
-    uint16_t find_next_capacity(uint16_t n){
-        uint16_t x = 2;
-        while(x < n) x <<= 1;
-        return x;
-    }
+uint16_t find_next_capacity(uint16_t n){
+    uint16_t x = 2;
+    while(x < n) x <<= 1;
+    return x;
+}
 
 #define _hash(key, mask, hash_seed) ( ( (key).index * (hash_seed) >> 8 ) & (mask) )
 
-    uint16_t find_perfect_hash_seed(uint16_t capacity, const std::vector<StrName>& keys){
-        if(keys.empty()) return kHashSeeds[0];
-        std::set<uint16_t> indices;
-        std::pair<uint16_t, float> best_score = {kHashSeeds[0], 0.0f};
-        for(int i=0; i<kHashSeeds.size(); i++){
-            indices.clear();
-            for(auto key: keys){
-                uint16_t index = _hash(key, capacity-1, kHashSeeds[i]);
-                indices.insert(index);
-            }
-            float score = indices.size() / (float)keys.size();
-            if(score > best_score.second) best_score = {kHashSeeds[i], score};
-        }
-        return best_score.first;
+uint16_t find_perfect_hash_seed(uint16_t capacity, const std::vector<StrName>& keys){
+    if(keys.empty()) return kHashSeeds[0];
+    std::set<uint16_t> indices;
+    std::pair<uint16_t, float> best_score = {kHashSeeds[0], 0.0f};
+    for(int i=0; i<kHashSeeds.size(); i++){
+        indices.clear();
+        for(auto key: keys){
+            uint16_t index = _hash(key, capacity-1, kHashSeeds[i]);
+            indices.insert(index);
+        }
+        float score = indices.size() / (float)keys.size();
+        if(score > best_score.second) best_score = {kHashSeeds[i], score};
+    }
+    return best_score.first;
+}
+
+struct NameDict {
+    uint16_t _capacity;
+    uint16_t _size;
+    float _load_factor;
+    uint16_t _hash_seed;
+    uint16_t _mask;
+    StrName* _keys;
+
+    inline PyVar& value(uint16_t i){
+        return reinterpret_cast<PyVar*>(_keys + _capacity)[i];
     }
 
-    struct NameDict {
-        uint16_t _capacity;
-        uint16_t _size;
-        float _load_factor;
-        uint16_t _hash_seed;
-        uint16_t _mask;
-        StrName* _keys;
-
-        inline PyVar& value(uint16_t i){
-            return reinterpret_cast<PyVar*>(_keys + _capacity)[i];
-        }
+    inline const PyVar& value(uint16_t i) const {
+        return reinterpret_cast<const PyVar*>(_keys + _capacity)[i];
+    }
 
-        inline const PyVar& value(uint16_t i) const {
-            return reinterpret_cast<const PyVar*>(_keys + _capacity)[i];
+    NameDict(uint16_t capacity=2, float load_factor=0.67, uint16_t hash_seed=kHashSeeds[0]):
+        _capacity(capacity), _size(0), _load_factor(load_factor),
+        _hash_seed(hash_seed), _mask(capacity-1) {
+            _keys = _dict_pool.alloc(capacity);
         }
 
-        NameDict(uint16_t capacity=2, float load_factor=0.67, uint16_t hash_seed=kHashSeeds[0]):
-            _capacity(capacity), _size(0), _load_factor(load_factor),
-            _hash_seed(hash_seed), _mask(capacity-1) {
-                _keys = _dict_pool.alloc(capacity);
-            }
-
-        NameDict(const NameDict& other) {
-            memcpy(this, &other, sizeof(NameDict));
-            _keys = _dict_pool.alloc(_capacity);
-            for(int i=0; i<_capacity; i++){
-                _keys[i] = other._keys[i];
-                value(i) = other.value(i);
-            }
+    NameDict(const NameDict& other) {
+        memcpy(this, &other, sizeof(NameDict));
+        _keys = _dict_pool.alloc(_capacity);
+        for(int i=0; i<_capacity; i++){
+            _keys[i] = other._keys[i];
+            value(i) = other.value(i);
         }
+    }
 
-        NameDict& operator=(const NameDict& other) {
-            _dict_pool.dealloc(_keys, _capacity);
-            memcpy(this, &other, sizeof(NameDict));
-            _keys = _dict_pool.alloc(_capacity);
-            for(int i=0; i<_capacity; i++){
-                _keys[i] = other._keys[i];
-                value(i) = other.value(i);
-            }
-            return *this;
+    NameDict& operator=(const NameDict& other) {
+        _dict_pool.dealloc(_keys, _capacity);
+        memcpy(this, &other, sizeof(NameDict));
+        _keys = _dict_pool.alloc(_capacity);
+        for(int i=0; i<_capacity; i++){
+            _keys[i] = other._keys[i];
+            value(i) = other.value(i);
         }
-        
-        ~NameDict(){ _dict_pool.dealloc(_keys, _capacity); }
+        return *this;
+    }
+    
+    ~NameDict(){ _dict_pool.dealloc(_keys, _capacity); }
 
-        NameDict(NameDict&&) = delete;
-        NameDict& operator=(NameDict&&) = delete;
-        uint16_t size() const { return _size; }
+    NameDict(NameDict&&) = delete;
+    NameDict& operator=(NameDict&&) = delete;
+    uint16_t size() const { return _size; }
 
 #define HASH_PROBE(key, ok, i) \
-    ok = false; \
-    i = _hash(key, _mask, _hash_seed); \
-    while(!_keys[i].empty()) { \
-        if(_keys[i] == (key)) { ok = true; break; } \
-        i = (i + 1) & _mask; \
-    }
-
-        const PyVar& operator[](StrName key) const {
-            bool ok; uint16_t i;
-            HASH_PROBE(key, ok, i);
-            if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
-            return value(i);
-        }
+ok = false; \
+i = _hash(key, _mask, _hash_seed); \
+while(!_keys[i].empty()) { \
+    if(_keys[i] == (key)) { ok = true; break; } \
+    i = (i + 1) & _mask; \
+}
+
+    const PyVar& operator[](StrName key) const {
+        bool ok; uint16_t i;
+        HASH_PROBE(key, ok, i);
+        if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
+        return value(i);
+    }
 
-        PyVar& get(StrName key){
-            bool ok; uint16_t i;
-            HASH_PROBE(key, ok, i);
-            if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
-            return value(i);
-        }
+    PyVar& get(StrName key){
+        bool ok; uint16_t i;
+        HASH_PROBE(key, ok, i);
+        if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
+        return value(i);
+    }
 
-        template<typename T>
-        void set(StrName key, T&& val){
-            bool ok; uint16_t i;
-            HASH_PROBE(key, ok, i);
-            if(!ok) {
-                _size++;
-                if(_size > _capacity*_load_factor){
-                    _rehash(true);
-                    HASH_PROBE(key, ok, i);
-                }
-                _keys[i] = key;
+    template<typename T>
+    void set(StrName key, T&& val){
+        bool ok; uint16_t i;
+        HASH_PROBE(key, ok, i);
+        if(!ok) {
+            _size++;
+            if(_size > _capacity*_load_factor){
+                _rehash(true);
+                HASH_PROBE(key, ok, i);
             }
-            value(i) = std::forward<T>(val);
+            _keys[i] = key;
         }
+        value(i) = std::forward<T>(val);
+    }
 
-        void _rehash(bool resize){
-            StrName* old_keys = _keys;
-            PyVar* old_values = &value(0);
-            uint16_t old_capacity = _capacity;
-            if(resize){
-                _capacity = find_next_capacity(_capacity * 2);
-                _mask = _capacity - 1;
-            }
-            _keys = _dict_pool.alloc(_capacity);
-            for(uint16_t i=0; i<old_capacity; i++){
-                if(old_keys[i].empty()) continue;
-                bool ok; uint16_t j;
-                HASH_PROBE(old_keys[i], ok, j);
-                if(ok) UNREACHABLE();
-                _keys[j] = old_keys[i];
-                value(j) = old_values[i]; // std::move makes a segfault
-            }
-            _dict_pool.dealloc(old_keys, old_capacity);
-        }
+    void _rehash(bool resize){
+        StrName* old_keys = _keys;
+        PyVar* old_values = &value(0);
+        uint16_t old_capacity = _capacity;
+        if(resize){
+            _capacity = find_next_capacity(_capacity * 2);
+            _mask = _capacity - 1;
+        }
+        _keys = _dict_pool.alloc(_capacity);
+        for(uint16_t i=0; i<old_capacity; i++){
+            if(old_keys[i].empty()) continue;
+            bool ok; uint16_t j;
+            HASH_PROBE(old_keys[i], ok, j);
+            if(ok) UNREACHABLE();
+            _keys[j] = old_keys[i];
+            value(j) = old_values[i]; // std::move makes a segfault
+        }
+        _dict_pool.dealloc(old_keys, old_capacity);
+    }
 
-        void _try_perfect_rehash(){
-            _hash_seed = find_perfect_hash_seed(_capacity, keys());
-            _rehash(false); // do not resize
-        }
+    void _try_perfect_rehash(){
+        _hash_seed = find_perfect_hash_seed(_capacity, keys());
+        _rehash(false); // do not resize
+    }
 
-        inline PyVar* try_get(StrName key){
-            bool ok; uint16_t i;
-            HASH_PROBE(key, ok, i);
-            if(!ok) return nullptr;
-            return &value(i);
-        }
+    inline PyVar* try_get(StrName key){
+        bool ok; uint16_t i;
+        HASH_PROBE(key, ok, i);
+        if(!ok) return nullptr;
+        return &value(i);
+    }
 
-        inline bool try_set(StrName key, PyVar&& val){
-            bool ok; uint16_t i;
-            HASH_PROBE(key, ok, i);
-            if(!ok) return false;
-            value(i) = std::move(val);
-            return true;
-        }
+    inline bool try_set(StrName key, PyVar&& val){
+        bool ok; uint16_t i;
+        HASH_PROBE(key, ok, i);
+        if(!ok) return false;
+        value(i) = std::move(val);
+        return true;
+    }
 
-        inline bool contains(StrName key) const {
-            bool ok; uint16_t i;
-            HASH_PROBE(key, ok, i);
-            return ok;
-        }
+    inline bool contains(StrName key) const {
+        bool ok; uint16_t i;
+        HASH_PROBE(key, ok, i);
+        return ok;
+    }
 
-        void update(const NameDict& other){
-            for(uint16_t i=0; i<other._capacity; i++){
-                if(other._keys[i].empty()) continue;
-                set(other._keys[i], other.value(i));
-            }
+    void update(const NameDict& other){
+        for(uint16_t i=0; i<other._capacity; i++){
+            if(other._keys[i].empty()) continue;
+            set(other._keys[i], other.value(i));
         }
+    }
 
-        void erase(StrName key){
-            bool ok; uint16_t i;
-            HASH_PROBE(key, ok, i);
-            if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
-            _keys[i] = StrName(); value(i).reset();
-            _size--;
-        }
+    void erase(StrName key){
+        bool ok; uint16_t i;
+        HASH_PROBE(key, ok, i);
+        if(!ok) throw std::out_of_range("NameDict key not found: " + key.str());
+        _keys[i] = StrName(); value(i).reset();
+        _size--;
+    }
 
-        std::vector<std::pair<StrName, PyVar>> items() const {
-            std::vector<std::pair<StrName, PyVar>> v;
-            for(uint16_t i=0; i<_capacity; i++){
-                if(_keys[i].empty()) continue;
-                v.push_back(std::make_pair(_keys[i], value(i)));
-            }
-            return v;
+    std::vector<std::pair<StrName, PyVar>> items() const {
+        std::vector<std::pair<StrName, PyVar>> v;
+        for(uint16_t i=0; i<_capacity; i++){
+            if(_keys[i].empty()) continue;
+            v.push_back(std::make_pair(_keys[i], value(i)));
         }
+        return v;
+    }
 
-        std::vector<StrName> keys() const {
-            std::vector<StrName> v;
-            for(uint16_t i=0; i<_capacity; i++){
-                if(_keys[i].empty()) continue;
-                v.push_back(_keys[i]);
-            }
-            return v;
+    std::vector<StrName> keys() const {
+        std::vector<StrName> v;
+        for(uint16_t i=0; i<_capacity; i++){
+            if(_keys[i].empty()) continue;
+            v.push_back(_keys[i]);
         }
+        return v;
+    }
 #undef HASH_PROBE
 #undef _hash
-    };
+};
 
 } // namespace pkpy

+ 34 - 14
src/obj.h

@@ -3,23 +3,24 @@
 #include "namedict.h"
 #include "tuplelist.h"
 
+namespace pkpy {
+    
 struct CodeObject;
 struct Frame;
 struct BaseRef;
 class VM;
 
-typedef std::function<PyVar(VM*, pkpy::Args&)> NativeFuncRaw;
-typedef pkpy::shared_ptr<CodeObject> CodeObject_;
-typedef pkpy::shared_ptr<pkpy::NameDict> NameDict_;
+typedef std::function<PyVar(VM*, Args&)> NativeFuncRaw;
+typedef shared_ptr<CodeObject> CodeObject_;
+typedef shared_ptr<NameDict> NameDict_;
 
-namespace pkpy{
 struct NativeFunc {
     NativeFuncRaw f;
     int argc;       // DONOT include self
     bool method;
     
     NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {}
-    inline PyVar operator()(VM* vm, pkpy::Args& args) const;
+    inline PyVar operator()(VM* vm, Args& args) const;
 };
 
 struct Function {
@@ -27,7 +28,7 @@ struct Function {
     CodeObject_ code;
     std::vector<StrName> args;
     StrName starred_arg;                // empty if no *arg
-    pkpy::NameDict kwargs;              // empty if no k=v
+    NameDict kwargs;              // empty if no k=v
     std::vector<StrName> kwargs_order;
 
     // runtime settings
@@ -71,7 +72,6 @@ struct Slice {
         if(stop < start) stop = start;
     }
 };
-}
 
 class BaseIter {
 protected:
@@ -86,10 +86,10 @@ public:
 
 struct PyObject {
     Type type;
-    pkpy::NameDict* _attr;
+    NameDict* _attr;
 
     inline bool is_attr_valid() const noexcept { return _attr != nullptr; }
-    inline pkpy::NameDict& attr() noexcept { return *_attr; }
+    inline NameDict& attr() noexcept { return *_attr; }
     inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); }
     virtual void* value() = 0;
 
@@ -106,11 +106,11 @@ struct Py_ : PyObject {
 
     inline void _init() noexcept {
         if constexpr (std::is_same_v<T, Type> || std::is_same_v<T, DummyModule>) {
-            _attr = new pkpy::NameDict(16, kTypeAttrLoadFactor);
+            _attr = new NameDict(16, kTypeAttrLoadFactor);
         }else if constexpr(std::is_same_v<T, DummyInstance>){
-            _attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
-        }else if constexpr(std::is_same_v<T, pkpy::Function> || std::is_same_v<T, pkpy::NativeFunc>){
-            _attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
+            _attr = new NameDict(4, kInstAttrLoadFactor);
+        }else if constexpr(std::is_same_v<T, Function> || std::is_same_v<T, NativeFunc>){
+            _attr = new NameDict(4, kInstAttrLoadFactor);
         }else{
             _attr = nullptr;
         }
@@ -162,4 +162,24 @@ union __8B {
     f64 _float;
     __8B(i64 val) : _int(val) {}
     __8B(f64 val) : _float(val) {}
-};
+};
+
+// Create a new object with the native type `T` and return a PyVar
+template<typename T>
+PyVar object(VM* vm, T&) { UNREACHABLE(); }
+template<typename T>
+PyVar object(VM* vm, T&&) { UNREACHABLE(); }
+template<typename T>
+PyVar object(VM* vm, T) { UNREACHABLE(); }
+
+// Cast a PyVar to a native type `T` by reference
+template<typename T>
+T& cast(VM* vm, const PyVar& var) { UNREACHABLE(); }
+template<typename T>
+T cast(VM* vm, const PyVar& var) { UNREACHABLE(); }
+template<typename T>
+T& _cast(VM* vm, const PyVar& var) { UNREACHABLE(); }
+template<typename T>
+T _cast(VM* vm, const PyVar& var) { UNREACHABLE(); }
+
+}   // namespace pkpy

+ 7 - 3
src/parser.h

@@ -2,6 +2,8 @@
 
 #include "obj.h"
 
+namespace pkpy{
+
 typedef uint8_t TokenIndex;
 
 constexpr const char* kTokens[] = {
@@ -90,7 +92,7 @@ enum Precedence {
 
 // The context of the parsing phase for the compiler.
 struct Parser {
-    pkpy::shared_ptr<SourceData> src;
+    shared_ptr<SourceData> src;
 
     const char* token_start;
     const char* curr_char;
@@ -285,11 +287,13 @@ struct Parser {
         else set_next_token(one);
     }
 
-    Parser(pkpy::shared_ptr<SourceData> src) {
+    Parser(shared_ptr<SourceData> src) {
         this->src = src;
         this->token_start = src->source;
         this->curr_char = src->source;
         this->nexts.push(Token{TK("@sof"), token_start, 0, current_line});
         this->indents.push(0);
     }
-};
+};
+
+} // namespace pkpy

+ 125 - 125
src/pocketpy.h

@@ -4,12 +4,15 @@
 #include "compiler.h"
 #include "repl.h"
 #include "iter.h"
+#include "cffi.h"
+
+namespace pkpy {
 
 CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
     Compiler compiler(this, source.c_str(), filename, mode);
     try{
         return compiler.compile();
-    }catch(pkpy::Exception& e){
+    }catch(Exception& e){
         // std::cout << e.summary() << std::endl;
         _error(e);
         return nullptr;
@@ -17,7 +20,7 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
 }
 
 #define BIND_NUM_ARITH_OPT(name, op)                                                                    \
-    _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){                         \
+    _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, Args& args){                         \
         if(is_both_int(args[0], args[1])){                                                              \
             return vm->PyInt(vm->_PyInt_AS_C(args[0]) op vm->_PyInt_AS_C(args[1]));                     \
         }else{                                                                                          \
@@ -26,7 +29,7 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
     });
 
 #define BIND_NUM_LOGICAL_OPT(name, op, is_eq)                                                           \
-    _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){                         \
+    _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, Args& args){                         \
         if(!is_both_int_or_float(args[0], args[1])){                                                    \
             if constexpr(is_eq) return vm->PyBool(args[0] op args[1]);                                  \
             vm->TypeError("unsupported operand type(s) for " #op );                                     \
@@ -52,40 +55,40 @@ void init_builtins(VM* _vm) {
 #undef BIND_NUM_ARITH_OPT
 #undef BIND_NUM_LOGICAL_OPT
 
-    _vm->bind_builtin_func<1>("__sys_stdout_write", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<1>("__sys_stdout_write", [](VM* vm, Args& args) {
         (*vm->_stdout) << vm->PyStr_AS_C(args[0]);
         return vm->None;
     });
 
-    // _vm->bind_builtin_func<1>("test", [](VM* vm, pkpy::Args& args) {
+    // _vm->bind_builtin_func<1>("test", [](VM* vm, Args& args) {
     //     args[0]->attr().print_stats();
     //     return vm->None;
     // });
 
-    _vm->bind_builtin_func<0>("super", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<0>("super", [](VM* vm, Args& args) {
         const PyVar* self = vm->top_frame()->f_locals().try_get(m_self);
         if(self == nullptr) vm->TypeError("super() can only be called in a class");
         return vm->new_object(vm->tp_super, *self);
     });
 
-    _vm->bind_builtin_func<1>("id", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<1>("id", [](VM* vm, Args& args) {
         const PyVar& obj = args[0];
         if(obj.is_tagged()) return vm->PyInt((i64)0);
         return vm->PyInt(obj.bits);
     });
 
-    _vm->bind_builtin_func<1>("eval", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) {
         CodeObject_ code = vm->compile(vm->PyStr_AS_C(args[0]), "<eval>", EVAL_MODE);
         return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
     });
 
-    _vm->bind_builtin_func<1>("exec", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<1>("exec", [](VM* vm, Args& args) {
         CodeObject_ code = vm->compile(vm->PyStr_AS_C(args[0]), "<exec>", EXEC_MODE);
         vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
         return vm->None;
     });
 
-    _vm->bind_builtin_func<-1>("exit", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<-1>("exit", [](VM* vm, Args& args) {
         if(args.size() == 0) std::exit(0);
         else if(args.size() == 1) std::exit((int)vm->PyInt_AS_C(args[0]));
         else vm->TypeError("exit() takes at most 1 argument");
@@ -93,61 +96,61 @@ void init_builtins(VM* _vm) {
     });
 
     _vm->bind_builtin_func<1>("repr", CPP_LAMBDA(vm->asRepr(args[0])));
-    _vm->bind_builtin_func<1>("len", CPP_LAMBDA(vm->call(args[0], __len__, pkpy::no_arg())));
+    _vm->bind_builtin_func<1>("len", CPP_LAMBDA(vm->call(args[0], __len__, no_arg())));
 
-    _vm->bind_builtin_func<1>("hash", [](VM* vm, pkpy::Args& args){
+    _vm->bind_builtin_func<1>("hash", [](VM* vm, Args& args){
         i64 value = vm->hash(args[0]);
         if(((value << 2) >> 2) != value) value >>= 2;
         return vm->PyInt(value);
     });
 
-    _vm->bind_builtin_func<1>("chr", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<1>("chr", [](VM* vm, Args& args) {
         i64 i = vm->PyInt_AS_C(args[0]);
         if (i < 0 || i > 128) vm->ValueError("chr() arg not in range(128)");
         return vm->PyStr(std::string(1, (char)i));
     });
 
-    _vm->bind_builtin_func<1>("ord", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<1>("ord", [](VM* vm, Args& args) {
         Str s = vm->PyStr_AS_C(args[0]);
         if (s.size() != 1) vm->TypeError("ord() expected an ASCII character");
         return vm->PyInt((i64)(s.c_str()[0]));
     });
 
-    _vm->bind_builtin_func<2>("hasattr", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<2>("hasattr", [](VM* vm, Args& args) {
         return vm->PyBool(vm->getattr(args[0], vm->PyStr_AS_C(args[1]), false) != nullptr);
     });
 
-    _vm->bind_builtin_func<3>("setattr", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<3>("setattr", [](VM* vm, Args& args) {
         vm->setattr(args[0], vm->PyStr_AS_C(args[1]), args[2]);
         return vm->None;
     });
 
-    _vm->bind_builtin_func<2>("getattr", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<2>("getattr", [](VM* vm, Args& args) {
         Str name = vm->PyStr_AS_C(args[1]);
         return vm->getattr(args[0], name);
     });
 
-    _vm->bind_builtin_func<1>("hex", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<1>("hex", [](VM* vm, Args& args) {
         std::stringstream ss;
         ss << std::hex << vm->PyInt_AS_C(args[0]);
         return vm->PyStr("0x" + ss.str());
     });
 
-    _vm->bind_builtin_func<1>("dir", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_builtin_func<1>("dir", [](VM* vm, Args& args) {
         std::set<StrName> names;
         if(args[0]->is_attr_valid()){
             std::vector<StrName> keys = args[0]->attr().keys();
             names.insert(keys.begin(), keys.end());
         }
-        const pkpy::NameDict& t_attr = vm->_t(args[0])->attr();
+        const NameDict& t_attr = vm->_t(args[0])->attr();
         std::vector<StrName> keys = t_attr.keys();
         names.insert(keys.begin(), keys.end());
-        pkpy::List ret;
+        List ret;
         for (StrName name : names) ret.push_back(vm->PyStr(name.str()));
         return vm->PyList(std::move(ret));
     });
 
-    _vm->bind_method<0>("object", "__repr__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) {
         PyVar self = args[0];
         std::uintptr_t addr = self.is_tagged() ? 0 : (uintptr_t)self.get();
         StrStream ss;
@@ -161,8 +164,8 @@ void init_builtins(VM* _vm) {
 
     _vm->bind_static_method<1>("type", "__new__", CPP_LAMBDA(vm->_t(args[0])));
 
-    _vm->bind_static_method<-1>("range", "__new__", [](VM* vm, pkpy::Args& args) {
-        pkpy::Range r;
+    _vm->bind_static_method<-1>("range", "__new__", [](VM* vm, Args& args) {
+        Range r;
         switch (args.size()) {
             case 1: r.stop = vm->PyInt_AS_C(args[0]); break;
             case 2: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); break;
@@ -179,13 +182,13 @@ void init_builtins(VM* _vm) {
     _vm->bind_method<0>("NoneType", "__repr__", CPP_LAMBDA(vm->PyStr("None")));
     _vm->bind_method<0>("NoneType", "__json__", CPP_LAMBDA(vm->PyStr("null")));
 
-    _vm->_bind_methods<1>({"int", "float"}, "__truediv__", [](VM* vm, pkpy::Args& args) {
+    _vm->_bind_methods<1>({"int", "float"}, "__truediv__", [](VM* vm, Args& args) {
         f64 rhs = vm->num_to_float(args[1]);
         if (rhs == 0) vm->ZeroDivisionError();
         return vm->PyFloat(vm->num_to_float(args[0]) / rhs);
     });
 
-    _vm->_bind_methods<1>({"int", "float"}, "__pow__", [](VM* vm, pkpy::Args& args) {
+    _vm->_bind_methods<1>({"int", "float"}, "__pow__", [](VM* vm, Args& args) {
         if(is_both_int(args[0], args[1])){
             i64 lhs = vm->_PyInt_AS_C(args[0]);
             i64 rhs = vm->_PyInt_AS_C(args[1]);
@@ -205,7 +208,7 @@ void init_builtins(VM* _vm) {
     });
 
     /************ PyInt ************/
-    _vm->bind_static_method<1>("int", "__new__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_static_method<1>("int", "__new__", [](VM* vm, Args& args) {
         if (is_type(args[0], vm->tp_int)) return args[0];
         if (is_type(args[0], vm->tp_float)) return vm->PyInt((i64)vm->PyFloat_AS_C(args[0]));
         if (is_type(args[0], vm->tp_bool)) return vm->PyInt(vm->_PyBool_AS_C(args[0]) ? 1 : 0);
@@ -224,13 +227,13 @@ void init_builtins(VM* _vm) {
         return vm->None;
     });
 
-    _vm->bind_method<1>("int", "__floordiv__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("int", "__floordiv__", [](VM* vm, Args& args) {
         i64 rhs = vm->PyInt_AS_C(args[1]);
         if(rhs == 0) vm->ZeroDivisionError();
         return vm->PyInt(vm->PyInt_AS_C(args[0]) / rhs);
     });
 
-    _vm->bind_method<1>("int", "__mod__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("int", "__mod__", [](VM* vm, Args& args) {
         i64 rhs = vm->PyInt_AS_C(args[1]);
         if(rhs == 0) vm->ZeroDivisionError();
         return vm->PyInt(vm->PyInt_AS_C(args[0]) % rhs);
@@ -251,10 +254,10 @@ void init_builtins(VM* _vm) {
 #undef INT_BITWISE_OP
 
     /************ PyFloat ************/
-    _vm->bind_static_method<1>("float", "__new__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_static_method<1>("float", "__new__", [](VM* vm, Args& args) {
         if (is_type(args[0], vm->tp_int)) return vm->PyFloat((f64)vm->PyInt_AS_C(args[0]));
         if (is_type(args[0], vm->tp_float)) return args[0];
-        if (is_type(args[0], vm->tp_bool)) return vm->PyFloat(vm->PyBool_AS_C(args[0]) ? 1.0 : 0.0);
+        if (is_type(args[0], vm->tp_bool)) return vm->PyFloat(vm->_PyBool_AS_C(args[0]) ? 1.0 : 0.0);
         if (is_type(args[0], vm->tp_str)) {
             const Str& s = vm->PyStr_AS_C(args[0]);
             if(s == "inf") return vm->PyFloat(INFINITY);
@@ -270,7 +273,7 @@ void init_builtins(VM* _vm) {
         return vm->None;
     });
 
-    _vm->bind_method<0>("float", "__repr__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("float", "__repr__", [](VM* vm, Args& args) {
         f64 val = vm->PyFloat_AS_C(args[0]);
         if(std::isinf(val) || std::isnan(val)) return vm->PyStr(std::to_string(val));
         StrStream ss;
@@ -280,7 +283,7 @@ void init_builtins(VM* _vm) {
         return vm->PyStr(s);
     });
 
-    _vm->bind_method<0>("float", "__json__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("float", "__json__", [](VM* vm, Args& args) {
         f64 val = vm->PyFloat_AS_C(args[0]);
         if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'");
         return vm->PyStr(std::to_string(val));
@@ -289,18 +292,18 @@ void init_builtins(VM* _vm) {
     /************ PyString ************/
     _vm->bind_static_method<1>("str", "__new__", CPP_LAMBDA(vm->asStr(args[0])));
 
-    _vm->bind_method<1>("str", "__add__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "__add__", [](VM* vm, Args& args) {
         const Str& lhs = vm->PyStr_AS_C(args[0]);
         const Str& rhs = vm->PyStr_AS_C(args[1]);
         return vm->PyStr(lhs + rhs);
     });
 
-    _vm->bind_method<0>("str", "__len__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("str", "__len__", [](VM* vm, Args& args) {
         const Str& self = vm->PyStr_AS_C(args[0]);
         return vm->PyInt(self.u8_length());
     });
 
-    _vm->bind_method<1>("str", "__contains__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "__contains__", [](VM* vm, Args& args) {
         const Str& self = vm->PyStr_AS_C(args[0]);
         const Str& other = vm->PyStr_AS_C(args[1]);
         return vm->PyBool(self.find(other) != Str::npos);
@@ -309,33 +312,33 @@ void init_builtins(VM* _vm) {
     _vm->bind_method<0>("str", "__str__", CPP_LAMBDA(args[0]));
     _vm->bind_method<0>("str", "__iter__", CPP_LAMBDA(vm->PyIter(StringIter(vm, args[0]))));
 
-    _vm->bind_method<0>("str", "__repr__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("str", "__repr__", [](VM* vm, Args& args) {
         const Str& _self = vm->PyStr_AS_C(args[0]);
         return vm->PyStr(_self.escape(true));
     });
 
-    _vm->bind_method<0>("str", "__json__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("str", "__json__", [](VM* vm, Args& args) {
         const Str& _self = vm->PyStr_AS_C(args[0]);
         return vm->PyStr(_self.escape(false));
     });
 
-    _vm->bind_method<1>("str", "__eq__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "__eq__", [](VM* vm, Args& args) {
         if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str))
             return vm->PyBool(vm->PyStr_AS_C(args[0]) == vm->PyStr_AS_C(args[1]));
         return vm->PyBool(args[0] == args[1]);
     });
 
-    _vm->bind_method<1>("str", "__ne__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "__ne__", [](VM* vm, Args& args) {
         if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str))
             return vm->PyBool(vm->PyStr_AS_C(args[0]) != vm->PyStr_AS_C(args[1]));
         return vm->PyBool(args[0] != args[1]);
     });
 
-    _vm->bind_method<1>("str", "__getitem__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "__getitem__", [](VM* vm, Args& args) {
         const Str& self (vm->PyStr_AS_C(args[0]));
 
         if(is_type(args[1], vm->tp_slice)){
-            pkpy::Slice s = vm->PySlice_AS_C(args[1]);
+            Slice s = vm->PySlice_AS_C(args[1]);
             s.normalize(self.u8_length());
             return vm->PyStr(self.u8_substr(s.start, s.stop));
         }
@@ -345,19 +348,19 @@ void init_builtins(VM* _vm) {
         return vm->PyStr(self.u8_getitem(index));
     });
 
-    _vm->bind_method<1>("str", "__gt__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "__gt__", [](VM* vm, Args& args) {
         const Str& self (vm->PyStr_AS_C(args[0]));
         const Str& obj (vm->PyStr_AS_C(args[1]));
         return vm->PyBool(self > obj);
     });
 
-    _vm->bind_method<1>("str", "__lt__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "__lt__", [](VM* vm, Args& args) {
         const Str& self (vm->PyStr_AS_C(args[0]));
         const Str& obj (vm->PyStr_AS_C(args[1]));
         return vm->PyBool(self < obj);
     });
 
-    _vm->bind_method<2>("str", "replace", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<2>("str", "replace", [](VM* vm, Args& args) {
         const Str& _self = vm->PyStr_AS_C(args[0]);
         const Str& _old = vm->PyStr_AS_C(args[1]);
         const Str& _new = vm->PyStr_AS_C(args[2]);
@@ -371,23 +374,23 @@ void init_builtins(VM* _vm) {
         return vm->PyStr(_copy);
     });
 
-    _vm->bind_method<1>("str", "startswith", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "startswith", [](VM* vm, Args& args) {
         const Str& _self = vm->PyStr_AS_C(args[0]);
         const Str& _prefix = vm->PyStr_AS_C(args[1]);
         return vm->PyBool(_self.find(_prefix) == 0);
     });
 
-    _vm->bind_method<1>("str", "endswith", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "endswith", [](VM* vm, Args& args) {
         const Str& _self = vm->PyStr_AS_C(args[0]);
         const Str& _suffix = vm->PyStr_AS_C(args[1]);
         return vm->PyBool(_self.rfind(_suffix) == _self.length() - _suffix.length());
     });
 
-    _vm->bind_method<1>("str", "join", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("str", "join", [](VM* vm, Args& args) {
         const Str& self = vm->PyStr_AS_C(args[0]);
         StrStream ss;
         PyVar obj = vm->asList(args[1]);
-        const pkpy::List& list = vm->PyList_AS_C(obj);
+        const List& list = vm->PyList_AS_C(obj);
         for (int i = 0; i < list.size(); ++i) {
             if (i > 0) ss << self;
             ss << vm->PyStr_AS_C(list[i]);
@@ -396,29 +399,29 @@ void init_builtins(VM* _vm) {
     });
 
     /************ PyList ************/
-    _vm->bind_method<1>("list", "append", [](VM* vm, pkpy::Args& args) {
-        pkpy::List& self = vm->PyList_AS_C(args[0]);
+    _vm->bind_method<1>("list", "append", [](VM* vm, Args& args) {
+        List& self = vm->PyList_AS_C(args[0]);
         self.push_back(args[1]);
         return vm->None;
     });
 
-    _vm->bind_method<0>("list", "reverse", [](VM* vm, pkpy::Args& args) {
-        pkpy::List& self = vm->PyList_AS_C(args[0]);
+    _vm->bind_method<0>("list", "reverse", [](VM* vm, Args& args) {
+        List& self = vm->PyList_AS_C(args[0]);
         std::reverse(self.begin(), self.end());
         return vm->None;
     });
 
-    _vm->bind_method<1>("list", "__mul__", [](VM* vm, pkpy::Args& args) {
-        const pkpy::List& self = vm->PyList_AS_C(args[0]);
+    _vm->bind_method<1>("list", "__mul__", [](VM* vm, Args& args) {
+        const List& self = vm->PyList_AS_C(args[0]);
         int n = (int)vm->PyInt_AS_C(args[1]);
-        pkpy::List result;
+        List result;
         result.reserve(self.size() * n);
         for(int i = 0; i < n; i++) result.insert(result.end(), self.begin(), self.end());
         return vm->PyList(std::move(result));
     });
 
-    _vm->bind_method<2>("list", "insert", [](VM* vm, pkpy::Args& args) {
-        pkpy::List& _self = vm->PyList_AS_C(args[0]);
+    _vm->bind_method<2>("list", "insert", [](VM* vm, Args& args) {
+        List& _self = vm->PyList_AS_C(args[0]);
         int index = (int)vm->PyInt_AS_C(args[1]);
         if(index < 0) index += _self.size();
         if(index < 0) index = 0;
@@ -427,37 +430,37 @@ void init_builtins(VM* _vm) {
         return vm->None;
     });
 
-    _vm->bind_method<0>("list", "clear", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("list", "clear", [](VM* vm, Args& args) {
         vm->PyList_AS_C(args[0]).clear();
         return vm->None;
     });
 
     _vm->bind_method<0>("list", "copy", CPP_LAMBDA(vm->PyList(vm->PyList_AS_C(args[0]))));
 
-    _vm->bind_method<1>("list", "__add__", [](VM* vm, pkpy::Args& args) {
-        const pkpy::List& self = vm->PyList_AS_C(args[0]);
-        const pkpy::List& obj = vm->PyList_AS_C(args[1]);
-        pkpy::List new_list = self;
+    _vm->bind_method<1>("list", "__add__", [](VM* vm, Args& args) {
+        const List& self = vm->PyList_AS_C(args[0]);
+        const List& obj = vm->PyList_AS_C(args[1]);
+        List new_list = self;
         new_list.insert(new_list.end(), obj.begin(), obj.end());
         return vm->PyList(new_list);
     });
 
-    _vm->bind_method<0>("list", "__len__", [](VM* vm, pkpy::Args& args) {
-        const pkpy::List& self = vm->PyList_AS_C(args[0]);
+    _vm->bind_method<0>("list", "__len__", [](VM* vm, Args& args) {
+        const List& self = vm->PyList_AS_C(args[0]);
         return vm->PyInt(self.size());
     });
 
-    _vm->bind_method<0>("list", "__iter__", [](VM* vm, pkpy::Args& args) {
-        return vm->PyIter(ArrayIter<pkpy::List>(vm, args[0]));
+    _vm->bind_method<0>("list", "__iter__", [](VM* vm, Args& args) {
+        return vm->PyIter(ArrayIter<List>(vm, args[0]));
     });
 
-    _vm->bind_method<1>("list", "__getitem__", [](VM* vm, pkpy::Args& args) {
-        const pkpy::List& self = vm->PyList_AS_C(args[0]);
+    _vm->bind_method<1>("list", "__getitem__", [](VM* vm, Args& args) {
+        const List& self = vm->PyList_AS_C(args[0]);
 
         if(is_type(args[1], vm->tp_slice)){
-            pkpy::Slice s = vm->PySlice_AS_C(args[1]);
+            Slice s = vm->PySlice_AS_C(args[1]);
             s.normalize(self.size());
-            pkpy::List new_list;
+            List new_list;
             for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]);
             return vm->PyList(std::move(new_list));
         }
@@ -467,16 +470,16 @@ void init_builtins(VM* _vm) {
         return self[index];
     });
 
-    _vm->bind_method<2>("list", "__setitem__", [](VM* vm, pkpy::Args& args) {
-        pkpy::List& self = vm->PyList_AS_C(args[0]);
+    _vm->bind_method<2>("list", "__setitem__", [](VM* vm, Args& args) {
+        List& self = vm->PyList_AS_C(args[0]);
         int index = (int)vm->PyInt_AS_C(args[1]);
         index = vm->normalized_index(index, self.size());
         self[index] = args[2];
         return vm->None;
     });
 
-    _vm->bind_method<1>("list", "__delitem__", [](VM* vm, pkpy::Args& args) {
-        pkpy::List& self = vm->PyList_AS_C(args[0]);
+    _vm->bind_method<1>("list", "__delitem__", [](VM* vm, Args& args) {
+        List& self = vm->PyList_AS_C(args[0]);
         int index = (int)vm->PyInt_AS_C(args[1]);
         index = vm->normalized_index(index, self.size());
         self.erase(self.begin() + index);
@@ -484,22 +487,22 @@ void init_builtins(VM* _vm) {
     });
 
     /************ PyTuple ************/
-    _vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, pkpy::Args& args) {
-        pkpy::List list = vm->PyList_AS_C(vm->asList(args[0]));
+    _vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, Args& args) {
+        List list = vm->PyList_AS_C(vm->asList(args[0]));
         return vm->PyTuple(std::move(list));
     });
 
-    _vm->bind_method<0>("tuple", "__iter__", [](VM* vm, pkpy::Args& args) {
-        return vm->PyIter(ArrayIter<pkpy::Args>(vm, args[0]));
+    _vm->bind_method<0>("tuple", "__iter__", [](VM* vm, Args& args) {
+        return vm->PyIter(ArrayIter<Args>(vm, args[0]));
     });
 
-    _vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, pkpy::Args& args) {
-        const pkpy::Tuple& self = vm->PyTuple_AS_C(args[0]);
+    _vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, Args& args) {
+        const Tuple& self = vm->PyTuple_AS_C(args[0]);
 
         if(is_type(args[1], vm->tp_slice)){
-            pkpy::Slice s = vm->PySlice_AS_C(args[1]);
+            Slice s = vm->PySlice_AS_C(args[1]);
             s.normalize(self.size());
-            pkpy::List new_list;
+            List new_list;
             for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]);
             return vm->PyTuple(std::move(new_list));
         }
@@ -509,25 +512,25 @@ void init_builtins(VM* _vm) {
         return self[index];
     });
 
-    _vm->bind_method<0>("tuple", "__len__", [](VM* vm, pkpy::Args& args) {
-        const pkpy::Tuple& self = vm->PyTuple_AS_C(args[0]);
+    _vm->bind_method<0>("tuple", "__len__", [](VM* vm, Args& args) {
+        const Tuple& self = vm->PyTuple_AS_C(args[0]);
         return vm->PyInt(self.size());
     });
 
     /************ PyBool ************/
     _vm->bind_static_method<1>("bool", "__new__", CPP_LAMBDA(vm->asBool(args[0])));
 
-    _vm->bind_method<0>("bool", "__repr__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("bool", "__repr__", [](VM* vm, Args& args) {
         bool val = vm->PyBool_AS_C(args[0]);
         return vm->PyStr(val ? "True" : "False");
     });
 
-    _vm->bind_method<0>("bool", "__json__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<0>("bool", "__json__", [](VM* vm, Args& args) {
         bool val = vm->PyBool_AS_C(args[0]);
         return vm->PyStr(val ? "true" : "false");
     });
 
-    _vm->bind_method<1>("bool", "__xor__", [](VM* vm, pkpy::Args& args) {
+    _vm->bind_method<1>("bool", "__xor__", [](VM* vm, Args& args) {
         bool self = vm->PyBool_AS_C(args[0]);
         bool other = vm->PyBool_AS_C(args[1]);
         return vm->PyBool(self ^ other);
@@ -552,7 +555,7 @@ void init_builtins(VM* _vm) {
 
 void add_module_time(VM* vm){
     PyVar mod = vm->new_module("time");
-    vm->bind_func<0>(mod, "time", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) {
         auto now = std::chrono::high_resolution_clock::now();
         return vm->PyFloat(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0);
     });
@@ -565,7 +568,7 @@ void add_module_sys(VM* vm){
     vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(vm->PyInt(args[0].use_count())));
     vm->bind_func<0>(mod, "getrecursionlimit", CPP_LAMBDA(vm->PyInt(vm->recursionlimit)));
 
-    vm->bind_func<1>(mod, "setrecursionlimit", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "setrecursionlimit", [](VM* vm, Args& args) {
         vm->recursionlimit = (int)vm->PyInt_AS_C(args[0]);
         return vm->None;
     });
@@ -573,7 +576,7 @@ void add_module_sys(VM* vm){
 
 void add_module_json(VM* vm){
     PyVar mod = vm->new_module("json");
-    vm->bind_func<1>(mod, "loads", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) {
         const Str& expr = vm->PyStr_AS_C(args[0]);
         CodeObject_ code = vm->compile(expr, "<json>", JSON_MODE);
         return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
@@ -603,7 +606,7 @@ void add_module_math(VM* vm){
 
 void add_module_dis(VM* vm){
     PyVar mod = vm->new_module("dis");
-    vm->bind_func<1>(mod, "dis", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) {
         PyVar f = args[0];
         if(is_type(f, vm->tp_bound_method)) f = vm->PyBoundMethod_AS_C(args[0]).method;
         CodeObject_ code = vm->PyFunction_AS_C(f).code;
@@ -632,32 +635,32 @@ struct FileIO {
     }
 
     static void _register(VM* vm, PyVar mod, PyVar type){
-        vm->bind_static_method<2>(type, "__new__", [](VM* vm, pkpy::Args& args){
+        vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
             return vm->new_object<FileIO>(
                 vm, vm->PyStr_AS_C(args[0]), vm->PyStr_AS_C(args[1])
             );
         });
 
-        vm->bind_method<0>(type, "read", [](VM* vm, pkpy::Args& args){
+        vm->bind_method<0>(type, "read", [](VM* vm, Args& args){
             FileIO& io = vm->py_cast<FileIO>(args[0]);
             std::string buffer;
             io._fs >> buffer;
             return vm->PyStr(buffer);
         });
 
-        vm->bind_method<1>(type, "write", [](VM* vm, pkpy::Args& args){
+        vm->bind_method<1>(type, "write", [](VM* vm, Args& args){
             FileIO& io = vm->py_cast<FileIO>(args[0]);
             io._fs << vm->PyStr_AS_C(args[1]);
             return vm->None;
         });
 
-        vm->bind_method<0>(type, "close", [](VM* vm, pkpy::Args& args){
+        vm->bind_method<0>(type, "close", [](VM* vm, Args& args){
             FileIO& io = vm->py_cast<FileIO>(args[0]);
             io._fs.close();
             return vm->None;
         });
 
-        vm->bind_method<0>(type, "__exit__", [](VM* vm, pkpy::Args& args){
+        vm->bind_method<0>(type, "__exit__", [](VM* vm, Args& args){
             FileIO& io = vm->py_cast<FileIO>(args[0]);
             io._fs.close();
             return vm->None;
@@ -669,7 +672,7 @@ struct FileIO {
 void add_module_io(VM* vm){
     PyVar mod = vm->new_module("io");
     PyVar type = vm->register_class<FileIO>(mod);
-    vm->bind_builtin_func<2>("open", [type](VM* vm, const pkpy::Args& args){
+    vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
         return vm->call(type, args);
     });
 }
@@ -689,12 +692,12 @@ struct ReMatch {
         vm->bind_method<0>(type, "start", CPP_LAMBDA(vm->PyInt(vm->py_cast<ReMatch>(args[0]).start)));
         vm->bind_method<0>(type, "end", CPP_LAMBDA(vm->PyInt(vm->py_cast<ReMatch>(args[0]).end)));
 
-        vm->bind_method<0>(type, "span", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<0>(type, "span", [](VM* vm, Args& args) {
             auto& self = vm->py_cast<ReMatch>(args[0]);
             return vm->PyTuple({ vm->PyInt(self.start), vm->PyInt(self.end) });
         });
 
-        vm->bind_method<1>(type, "group", [](VM* vm, pkpy::Args& args) {
+        vm->bind_method<1>(type, "group", [](VM* vm, Args& args) {
             auto& self = vm->py_cast<ReMatch>(args[0]);
             int index = (int)vm->PyInt_AS_C(args[1]);
             index = vm->normalized_index(index, self.m.size());
@@ -719,19 +722,19 @@ void add_module_re(VM* vm){
     PyVar mod = vm->new_module("re");
     vm->register_class<ReMatch>(mod);
 
-    vm->bind_func<2>(mod, "match", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) {
         const Str& pattern = vm->PyStr_AS_C(args[0]);
         const Str& string = vm->PyStr_AS_C(args[1]);
         return _regex_search(pattern, string, true, vm);
     });
 
-    vm->bind_func<2>(mod, "search", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<2>(mod, "search", [](VM* vm, Args& args) {
         const Str& pattern = vm->PyStr_AS_C(args[0]);
         const Str& string = vm->PyStr_AS_C(args[1]);
         return _regex_search(pattern, string, false, vm);
     });
 
-    vm->bind_func<3>(mod, "sub", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<3>(mod, "sub", [](VM* vm, Args& args) {
         const Str& pattern = vm->PyStr_AS_C(args[0]);
         const Str& repl = vm->PyStr_AS_C(args[1]);
         const Str& string = vm->PyStr_AS_C(args[2]);
@@ -739,13 +742,13 @@ void add_module_re(VM* vm){
         return vm->PyStr(std::regex_replace(string, re, repl));
     });
 
-    vm->bind_func<2>(mod, "split", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<2>(mod, "split", [](VM* vm, Args& args) {
         const Str& pattern = vm->PyStr_AS_C(args[0]);
         const Str& string = vm->PyStr_AS_C(args[1]);
         std::regex re(pattern);
         std::sregex_token_iterator it(string.begin(), string.end(), re, -1);
         std::sregex_token_iterator end;
-        pkpy::List vec;
+        List vec;
         for(; it != end; ++it){
             vec.push_back(vm->PyStr(it->str()));
         }
@@ -756,20 +759,20 @@ void add_module_re(VM* vm){
 void add_module_random(VM* vm){
     PyVar mod = vm->new_module("random");
     std::srand(std::time(0));
-    vm->bind_func<1>(mod, "seed", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<1>(mod, "seed", [](VM* vm, Args& args) {
         std::srand((unsigned int)vm->PyInt_AS_C(args[0]));
         return vm->None;
     });
 
     vm->bind_func<0>(mod, "random", CPP_LAMBDA(vm->PyFloat(std::rand() / (f64)RAND_MAX)));
-    vm->bind_func<2>(mod, "randint", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<2>(mod, "randint", [](VM* vm, Args& args) {
         i64 a = vm->PyInt_AS_C(args[0]);
         i64 b = vm->PyInt_AS_C(args[1]);
         if(a > b) std::swap(a, b);
         return vm->PyInt(a + std::rand() % (b - a + 1));
     });
 
-    vm->bind_func<2>(mod, "uniform", [](VM* vm, pkpy::Args& args) {
+    vm->bind_func<2>(mod, "uniform", [](VM* vm, Args& args) {
         f64 a = vm->PyFloat_AS_C(args[0]);
         f64 b = vm->PyFloat_AS_C(args[1]);
         if(a > b) std::swap(a, b);
@@ -786,8 +789,6 @@ void add_module_functools(VM* vm){
     vm->_exec(code, mod);
 }
 
-#include "cffi.h"
-
 void VM::post_init(){
     init_builtins(this);
     add_module_sys(this);
@@ -806,17 +807,15 @@ void VM::post_init(){
     this->_exec(code, this->builtins);
 }
 
-
-class _PkExported{
+class PkExportedBase{
 public:
-    virtual ~_PkExported() = default;
+    virtual ~PkExportedBase() = default;
     virtual void* get() = 0;
 };
 
-static std::vector<_PkExported*> _pk_lookup_table;
-
+static std::vector<PkExportedBase*> _pk_lookup_table;
 template<typename T>
-class PkExported : public _PkExported{
+class PkExported : public PkExportedBase{
     T* _ptr;
 public:
     template<typename... Args>
@@ -832,7 +831,6 @@ public:
 
 #define PKPY_ALLOCATE(T, ...) *(new PkExported<T>(__VA_ARGS__))
 
-
 extern "C" {
     __EXPORT
     /// Delete a pointer allocated by `pkpy_xxx_xxx`.
@@ -947,12 +945,12 @@ extern "C" {
 
     __EXPORT
     /// Setup the callback functions.
-    void pkpy_setup_callbacks(f_int_t f_int, f_float_t f_float, f_bool_t f_bool, f_str_t f_str, f_None_t f_None){
-        ::f_int = f_int;
-        ::f_float = f_float;
-        ::f_bool = f_bool;
-        ::f_str = f_str;
-        ::f_None = f_None;
+    void pkpy_setup_callbacks(f_int_t _f_int, f_float_t _f_float, f_bool_t _f_bool, f_str_t _f_str, f_None_t _f_None){
+        f_int = _f_int;
+        f_float = _f_float;
+        f_bool = _f_bool;
+        f_str = _f_str;
+        f_None = _f_None;
     }
 
     __EXPORT
@@ -964,7 +962,7 @@ extern "C" {
         for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr;
         std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++);
         PyVar obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod);
-        vm->bind_func<-1>(obj, name, [ret_code, f_header](VM* vm, const pkpy::Args& args){
+        vm->bind_func<-1>(obj, name, [ret_code, f_header](VM* vm, const Args& args){
             StrStream ss;
             ss << f_header;
             for(int i=0; i<args.size(); i++){
@@ -990,4 +988,6 @@ extern "C" {
         });
         return strdup(f_header.c_str());
     }
-}
+}
+
+}   // namespace pkpy

+ 8 - 3
src/ref.h

@@ -2,6 +2,8 @@
 
 #include "obj.h"
 
+namespace pkpy {
+
 struct BaseRef {
     virtual PyVar get(VM*, Frame*) const = 0;
     virtual void set(VM*, Frame*, PyVar) const = 0;
@@ -48,10 +50,13 @@ struct IndexRef : BaseRef {
 };
 
 struct TupleRef : BaseRef {
-    pkpy::Tuple objs;
-    TupleRef(pkpy::Tuple&& objs) : objs(std::move(objs)) {}
+    Tuple objs;
+    TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
 
     PyVar get(VM* vm, Frame* frame) const;
     void set(VM* vm, Frame* frame, PyVar val) const;
     void del(VM* vm, Frame* frame) const;
-};
+};
+
+
+}   // namespace pkpy

+ 5 - 1
src/repl.h

@@ -3,6 +3,8 @@
 #include "compiler.h"
 #include "ceval.h"
 
+namespace pkpy{
+
 class REPL {
 protected:
     int need_more_lines = 0;
@@ -45,4 +47,6 @@ public:
         }
         return false;
     }
-};
+};
+
+} // namespace pkpy

+ 5 - 1
src/str.h

@@ -2,6 +2,8 @@
 
 #include "common.h"
 
+namespace pkpy {
+
 typedef std::stringstream StrStream;
 
 class Str : public std::string {
@@ -212,4 +214,6 @@ const StrName BINARY_SPECIAL_METHODS[] = {
 const StrName BITWISE_SPECIAL_METHODS[] = {
     StrName::get("__lshift__"), StrName::get("__rshift__"),
     StrName::get("__and__"), StrName::get("__or__"), StrName::get("__xor__")
-};
+};
+
+} // namespace pkpy

+ 3 - 3
src/tuplelist.h

@@ -39,7 +39,7 @@ namespace pkpy {
             other._size = 0;
         }
 
-        Args(pkpy::List&& other) noexcept {
+        Args(List&& other) noexcept {
             _alloc(other.size());
             memcpy((void*)_args, (void*)other.data(), sizeof(PyVar)*_size);
             memset((void*)other.data(), 0, sizeof(PyVar)*_size);
@@ -60,8 +60,8 @@ namespace pkpy {
 
         inline int size() const { return _size; }
 
-        pkpy::List move_to_list() noexcept {
-            pkpy::List ret(_size);
+        List move_to_list() noexcept {
+            List ret(_size);
             memcpy((void*)ret.data(), (void*)_args, sizeof(PyVar)*_size);
             memset((void*)_args, 0, sizeof(PyVar)*_size);
             return ret;

+ 101 - 54
src/vm.h

@@ -3,6 +3,8 @@
 #include "frame.h"
 #include "error.h"
 
+namespace pkpy{
+    
 #define DEF_NATIVE(type, ctype, ptype)                          \
     inline ctype& Py##type##_AS_C(const PyVar& obj) {           \
         check_type(obj, ptype);                                 \
@@ -31,8 +33,8 @@ public:
 
     PyVar run_frame(Frame* frame);
 
-    pkpy::NameDict _types;
-    pkpy::NameDict _modules;                            // loaded modules
+    NameDict _types;
+    NameDict _modules;                            // loaded modules
     std::map<StrName, Str> _lazy_modules;       // lazy loaded modules
     PyVar None, True, False, Ellipsis;
 
@@ -100,10 +102,10 @@ public:
 
     PyVar asList(const PyVar& iterable){
         if(is_type(iterable, tp_list)) return iterable;
-        return call(_t(tp_list), pkpy::one_arg(iterable));
+        return call(_t(tp_list), one_arg(iterable));
     }
 
-    PyVar fast_call(StrName name, pkpy::Args&& args){
+    PyVar fast_call(StrName name, Args&& args){
         PyObject* cls = _t(args[0]).get();
         while(cls != None.get()) {
             PyVar* val = cls->attr().try_get(name);
@@ -115,26 +117,26 @@ public:
     }
 
     inline PyVar call(const PyVar& _callable){
-        return call(_callable, pkpy::no_arg(), pkpy::no_arg(), false);
+        return call(_callable, no_arg(), no_arg(), false);
     }
 
     template<typename ArgT>
-    inline std::enable_if_t<std::is_same_v<RAW(ArgT), pkpy::Args>, PyVar>
+    inline std::enable_if_t<std::is_same_v<RAW(ArgT), Args>, PyVar>
     call(const PyVar& _callable, ArgT&& args){
-        return call(_callable, std::forward<ArgT>(args), pkpy::no_arg(), false);
+        return call(_callable, std::forward<ArgT>(args), no_arg(), false);
     }
 
     template<typename ArgT>
-    inline std::enable_if_t<std::is_same_v<RAW(ArgT), pkpy::Args>, PyVar>
+    inline std::enable_if_t<std::is_same_v<RAW(ArgT), Args>, PyVar>
     call(const PyVar& obj, const StrName name, ArgT&& args){
-        return call(getattr(obj, name), std::forward<ArgT>(args), pkpy::no_arg(), false);
+        return call(getattr(obj, name), std::forward<ArgT>(args), no_arg(), false);
     }
 
     inline PyVar call(const PyVar& obj, StrName name){
-        return call(getattr(obj, name), pkpy::no_arg(), pkpy::no_arg(), false);
+        return call(getattr(obj, name), no_arg(), no_arg(), false);
     }
 
-    PyVar call(const PyVar& _callable, pkpy::Args args, const pkpy::Args& kwargs, bool opCall){
+    PyVar call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall){
         if(is_type(_callable, tp_type)){
             PyVar* new_f = _callable->attr().try_get(__new__);
             PyVar obj;
@@ -156,12 +158,12 @@ public:
         }
         
         if(is_type(*callable, tp_native_function)){
-            const auto& f = OBJ_GET(pkpy::NativeFunc, *callable);
+            const auto& f = OBJ_GET(NativeFunc, *callable);
             if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments");
             return f(this, args);
         } else if(is_type(*callable, tp_function)){
-            const pkpy::Function& fn = PyFunction_AS_C(*callable);
-            NameDict_ locals = pkpy::make_shared<pkpy::NameDict>(
+            const Function& fn = PyFunction_AS_C(*callable);
+            NameDict_ locals = make_sp<NameDict>(
                 fn.code->perfect_locals_capacity,
                 kLocalsLoadFactor,
                 fn.code->perfect_hash_seed
@@ -179,7 +181,7 @@ public:
             locals->update(fn.kwargs);
 
             if(!fn.starred_arg.empty()){
-                pkpy::List vargs;        // handle *args
+                List vargs;        // handle *args
                 while(i < args.size()) vargs.push_back(std::move(args[i++]));
                 locals->set(fn.starred_arg, PyTuple(std::move(vargs)));
             }else{
@@ -217,7 +219,7 @@ public:
         try {
             CodeObject_ code = compile(source, filename, mode);
             return _exec(code, _module);
-        }catch (const pkpy::Exception& e){
+        }catch (const Exception& e){
             *_stderr << e.summary() << '\n';
         }catch (const std::exception& e) {
             *_stderr << "An std::exception occurred! It could be a bug.\n";
@@ -269,7 +271,7 @@ public:
                 continue;
             }catch(UnhandledException& e){
                 PyVar obj = frame->pop();
-                pkpy::Exception& _e = PyException_AS_C(obj);
+                Exception& _e = PyException_AS_C(obj);
                 _e.st_push(frame->snapshot());
                 callstack.pop();
                 if(callstack.empty()) throw _e;
@@ -285,7 +287,7 @@ public:
 
     PyVar new_type_object(PyVar mod, StrName name, PyVar base){
         if(!is_type(base, tp_type)) UNREACHABLE();
-        PyVar obj = pkpy::make_shared<PyObject, Py_<Type>>(tp_type, _all_types.size());
+        PyVar obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
         setattr(obj, __base__, base);
         Str fullName = name.str();
         if(mod != builtins) fullName = OBJ_NAME(mod) + "." + name.str();
@@ -296,7 +298,7 @@ public:
     }
 
     Type _new_type_object(StrName name, Type base=0) {
-        PyVar obj = pkpy::make_shared<PyObject, Py_<Type>>(tp_type, _all_types.size());
+        PyVar obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
         setattr(obj, __base__, _t(base));
         _types.set(name, obj);
         _all_types.push_back(obj);
@@ -306,21 +308,21 @@ public:
     template<typename T>
     inline PyVar new_object(const PyVar& type, const T& _value) {
         if(!is_type(type, tp_type)) UNREACHABLE();
-        return pkpy::make_shared<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), _value);
+        return make_sp<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), _value);
     }
     template<typename T>
     inline PyVar new_object(const PyVar& type, T&& _value) {
         if(!is_type(type, tp_type)) UNREACHABLE();
-        return pkpy::make_shared<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), std::move(_value));
+        return make_sp<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), std::move(_value));
     }
 
     template<typename T>
     inline PyVar new_object(Type type, const T& _value) {
-        return pkpy::make_shared<PyObject, Py_<RAW(T)>>(type, _value);
+        return make_sp<PyObject, Py_<RAW(T)>>(type, _value);
     }
     template<typename T>
     inline PyVar new_object(Type type, T&& _value) {
-        return pkpy::make_shared<PyObject, Py_<RAW(T)>>(type, std::move(_value));
+        return make_sp<PyObject, Py_<RAW(T)>>(type, std::move(_value));
     }
 
     template<typename T, typename... Args>
@@ -365,7 +367,7 @@ public:
             if(val != nullptr){
                 PyVarOrNull descriptor = getattr(*val, __get__, false);
                 if(descriptor != nullptr){
-                    return call(descriptor, pkpy::one_arg(obj));
+                    return call(descriptor, one_arg(obj));
                 }
                 if(is_type(*val, tp_function) || is_type(*val, tp_native_function)){
                     return PyBoundMethod({obj, *val});
@@ -391,12 +393,12 @@ public:
     template<int ARGC>
     void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn) {
         check_type(obj, tp_type);
-        setattr(obj, funcName, PyNativeFunc(pkpy::NativeFunc(fn, ARGC, true)));
+        setattr(obj, funcName, PyNativeFunc(NativeFunc(fn, ARGC, true)));
     }
 
     template<int ARGC>
     void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn) {
-        setattr(obj, funcName, PyNativeFunc(pkpy::NativeFunc(fn, ARGC, false)));
+        setattr(obj, funcName, PyNativeFunc(NativeFunc(fn, ARGC, false)));
     }
 
     template<int ARGC>
@@ -504,7 +506,7 @@ public:
 
         StrStream names;
         names << "co_names: ";
-        pkpy::List list;
+        List list;
         for(int i=0; i<co->names.size(); i++){
             list.push_back(PyStr(co->names[i].first.str()));
         }
@@ -602,15 +604,15 @@ public:
         return __8B(bits)._float;
     }
 
-    DEF_NATIVE(List, pkpy::List, tp_list)
-    DEF_NATIVE(Tuple, pkpy::Tuple, tp_tuple)
-    DEF_NATIVE(Function, pkpy::Function, tp_function)
-    DEF_NATIVE(NativeFunc, pkpy::NativeFunc, tp_native_function)
-    DEF_NATIVE(BoundMethod, pkpy::BoundMethod, tp_bound_method)
-    DEF_NATIVE(Range, pkpy::Range, tp_range)
-    DEF_NATIVE(Slice, pkpy::Slice, tp_slice)
-    DEF_NATIVE(Exception, pkpy::Exception, tp_exception)
-    DEF_NATIVE(StarWrapper, pkpy::StarWrapper, tp_star_wrapper)
+    DEF_NATIVE(List, List, tp_list)
+    DEF_NATIVE(Tuple, Tuple, tp_tuple)
+    DEF_NATIVE(Function, Function, tp_function)
+    DEF_NATIVE(NativeFunc, NativeFunc, tp_native_function)
+    DEF_NATIVE(BoundMethod, BoundMethod, tp_bound_method)
+    DEF_NATIVE(Range, Range, tp_range)
+    DEF_NATIVE(Slice, Slice, tp_slice)
+    DEF_NATIVE(Exception, Exception, tp_exception)
+    DEF_NATIVE(StarWrapper, StarWrapper, tp_star_wrapper)
     
     // there is only one True/False, so no need to copy them!
     inline bool PyBool_AS_C(const PyVar& obj){
@@ -621,8 +623,8 @@ public:
     inline const PyVar& PyBool(bool value){return value ? True : False;}
 
     void init_builtin_types(){
-        PyVar _tp_object = pkpy::make_shared<PyObject, Py_<Type>>(1, 0);
-        PyVar _tp_type = pkpy::make_shared<PyObject, Py_<Type>>(1, 1);
+        PyVar _tp_object = make_sp<PyObject, Py_<Type>>(1, 0);
+        PyVar _tp_type = make_sp<PyObject, Py_<Type>>(1, 1);
         _all_types.push_back(_tp_object);
         _all_types.push_back(_tp_type);
         tp_object = 0; tp_type = 1;
@@ -684,7 +686,7 @@ public:
         if (is_int(obj)) return PyInt_AS_C(obj);
         if (is_type(obj, tp_tuple)) {
             i64 x = 1000003;
-            const pkpy::Tuple& items = PyTuple_AS_C(obj);
+            const Tuple& items = PyTuple_AS_C(obj);
             for (int i=0; i<items.size(); i++) {
                 i64 y = hash(items[i]);
                 x = x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2)); // recommended by Github Copilot
@@ -702,12 +704,11 @@ public:
     }
 
     /***** Error Reporter *****/
-private:
     void _error(StrName name, const Str& msg){
-        _error(pkpy::Exception(name, msg));
+        _error(Exception(name, msg));
     }
 
-    void _error(pkpy::Exception e){
+    void _error(Exception e){
         if(callstack.empty()){
             e.is_re = false;
             throw e;
@@ -767,14 +768,14 @@ public:
         return OBJ_GET(T, obj);
     }
 
-    void unpack_args(pkpy::Args& args){
-        pkpy::List unpacked;
+    void unpack_args(Args& args){
+        List unpacked;
         for(int i=0; i<args.size(); i++){
             if(is_type(args[i], tp_star_wrapper)){
                 auto& star = PyStarWrapper_AS_C(args[i]);
                 if(!star.rvalue) UNREACHABLE();
                 PyVar list = asList(star.obj);
-                pkpy::List& list_c = PyList_AS_C(list);
+                List& list_c = PyList_AS_C(list);
                 unpacked.insert(unpacked.end(), list_c.begin(), list_c.end());
             }else{
                 unpacked.push_back(args[i]);
@@ -859,21 +860,21 @@ void AttrRef::del(VM* vm, Frame* frame) const{
 }
 
 PyVar IndexRef::get(VM* vm, Frame* frame) const{
-    return vm->fast_call(__getitem__, pkpy::two_args(obj, index));
+    return vm->fast_call(__getitem__, two_args(obj, index));
 }
 
 void IndexRef::set(VM* vm, Frame* frame, PyVar val) const{
-    pkpy::Args args(3);
+    Args args(3);
     args[0] = obj; args[1] = index; args[2] = std::move(val);
     vm->fast_call(__setitem__, std::move(args));
 }
 
 void IndexRef::del(VM* vm, Frame* frame) const{
-    vm->fast_call(__delitem__, pkpy::two_args(obj, index));
+    vm->fast_call(__delitem__, two_args(obj, index));
 }
 
 PyVar TupleRef::get(VM* vm, Frame* frame) const{
-    pkpy::Tuple args(objs.size());
+    Tuple args(objs.size());
     for (int i = 0; i < objs.size(); i++) {
         args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
     }
@@ -890,7 +891,7 @@ void TupleRef::set(VM* vm, Frame* frame, PyVar val) const{
             if(star.rvalue) vm->ValueError("can't use starred expression here");
             if(i != objs.size()-1) vm->ValueError("* can only be used at the end");
             auto ref = vm->PyRef_AS_C(star.obj);
-            pkpy::List list;
+            List list;
             while((x = iter->next()) != nullptr) list.push_back(x);
             ref->set(vm, frame, vm->PyList(std::move(list)));
             return;
@@ -913,7 +914,7 @@ inline void Frame::try_deref(VM* vm, PyVar& v){
     if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this);
 }
 
-PyVar pkpy::NativeFunc::operator()(VM* vm, pkpy::Args& args) const{
+PyVar NativeFunc::operator()(VM* vm, Args& args) const{
     int args_size = args.size() - (int)method;  // remove self
     if(argc != -1 && args_size != argc) {
         vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
@@ -925,8 +926,8 @@ void CodeObject::optimize(VM* vm){
     std::vector<StrName> keys;
     for(auto& p: names) if(p.second == NAME_LOCAL) keys.push_back(p.first);
     uint32_t base_n = (uint32_t)(keys.size() / kLocalsLoadFactor + 0.5);
-    perfect_locals_capacity = pkpy::find_next_capacity(base_n);
-    perfect_hash_seed = pkpy::find_perfect_hash_seed(perfect_locals_capacity, keys);
+    perfect_locals_capacity = find_next_capacity(base_n);
+    perfect_hash_seed = find_perfect_hash_seed(perfect_locals_capacity, keys);
 
     for(int i=1; i<codes.size(); i++){
         if(codes[i].op == OP_UNARY_NEGATIVE && codes[i-1].op == OP_LOAD_CONST){
@@ -952,4 +953,50 @@ void CodeObject::optimize(VM* vm){
             codes[i-2].op = OP_NO_OP;
         }
     }
-}
+}
+
+    template<> PyVar object<i64>(VM* vm, i64 val){
+        if(((val << 2) >> 2) != val){
+            vm->_error("OverflowError", std::to_string(val) + " is out of range");
+        }
+        val = (val << 2) | 0b01;
+        return PyVar(reinterpret_cast<int*>(val));
+    }
+    template<> i64 cast<i64>(VM* vm, const PyVar& obj){
+        vm->check_type(obj, vm->tp_int);
+        return obj.bits >> 2;
+    }
+    template<> i64 _cast<i64>(VM* vm, const PyVar& obj){
+        return obj.bits >> 2;
+    }
+    
+    template<> PyVar object<f64>(VM* vm, f64 val){
+        i64 bits = __8B(val)._int;
+        bits = (bits >> 2) << 2;
+        bits |= 0b10;
+        return PyVar(reinterpret_cast<int*>(bits));
+    }
+    template<> f64 cast<f64>(VM* vm, const PyVar& obj){
+        vm->check_type(obj, vm->tp_float);
+        i64 bits = obj.bits;
+        bits = (bits >> 2) << 2;
+        return __8B(bits)._float;
+    }
+    template<> f64 _cast<f64>(VM* vm, const PyVar& obj){
+        i64 bits = obj.bits;
+        bits = (bits >> 2) << 2;
+        return __8B(bits)._float;
+    }
+
+    template<> PyVar object<bool>(VM* vm, bool val){
+        return val ? vm->True : vm->False;
+    }
+    template<> bool cast<bool>(VM* vm, const PyVar& obj){
+        vm->check_type(obj, vm->tp_bool);
+        return obj == vm->True;
+    }
+    template<> bool _cast<bool>(VM* vm, const PyVar& obj){
+        return obj == vm->True;
+    }
+
+}   // namespace pkpy