1
0
blueloveTH 1 жил өмнө
parent
commit
2dfb6ed07a
86 өөрчлөгдсөн 667 нэмэгдсэн , 642 устгасан
  1. 1 1
      3rd/cjson/include/cJSONw.hpp
  2. 2 2
      3rd/lua_bridge/src/lua_bridge.cpp
  3. 1 1
      CMakeLists.txt
  4. 2 0
      build_g.sh
  5. 1 1
      include/pocketpy.h
  6. 3 0
      include/pocketpy.hpp
  7. 0 4
      include/pocketpy/ceval.h
  8. 0 240
      include/pocketpy/common.h
  9. 0 0
      include/pocketpy/common/_generated.hpp
  10. 6 3
      include/pocketpy/common/any.hpp
  11. 17 0
      include/pocketpy/common/gil.hpp
  12. 3 1
      include/pocketpy/common/memorypool.hpp
  13. 7 14
      include/pocketpy/common/namedict.hpp
  14. 6 3
      include/pocketpy/common/str.hpp
  15. 36 0
      include/pocketpy/common/traits.hpp
  16. 28 0
      include/pocketpy/common/types.hpp
  17. 28 0
      include/pocketpy/common/utils.hpp
  18. 11 14
      include/pocketpy/common/vector.hpp
  19. 6 0
      include/pocketpy/common/version.hpp
  20. 1 4
      include/pocketpy/compiler/compiler.hpp
  21. 2 5
      include/pocketpy/compiler/expr.hpp
  22. 4 4
      include/pocketpy/compiler/lexer.hpp
  23. 8 5
      include/pocketpy/interpreter/bindings.hpp
  24. 4 0
      include/pocketpy/interpreter/ceval.hpp
  25. 1 2
      include/pocketpy/interpreter/cffi.hpp
  26. 5 29
      include/pocketpy/interpreter/frame.hpp
  27. 4 3
      include/pocketpy/interpreter/gc.hpp
  28. 1 3
      include/pocketpy/interpreter/iter.hpp
  29. 1 1
      include/pocketpy/interpreter/profiler.hpp
  30. 11 13
      include/pocketpy/interpreter/vm.hpp
  31. 1 1
      include/pocketpy/modules/array2d.hpp
  32. 1 1
      include/pocketpy/modules/base64.hpp
  33. 1 1
      include/pocketpy/modules/csv.hpp
  34. 1 1
      include/pocketpy/modules/dataclasses.hpp
  35. 1 1
      include/pocketpy/modules/easing.hpp
  36. 1 1
      include/pocketpy/modules/io.hpp
  37. 4 1
      include/pocketpy/modules/linalg.hpp
  38. 1 1
      include/pocketpy/modules/modules.hpp
  39. 1 1
      include/pocketpy/modules/random.hpp
  40. 100 0
      include/pocketpy/objects/base.hpp
  41. 6 83
      include/pocketpy/objects/builtins.hpp
  42. 19 6
      include/pocketpy/objects/codeobject.hpp
  43. 2 4
      include/pocketpy/objects/dict.hpp
  44. 3 31
      include/pocketpy/objects/error.hpp
  45. 63 0
      include/pocketpy/objects/object.hpp
  46. 35 0
      include/pocketpy/objects/sourcedata.hpp
  47. 17 0
      include/pocketpy/objects/stackmemory.hpp
  48. 2 4
      include/pocketpy/objects/tuplelist.hpp
  49. 0 18
      include/pocketpy/pocketpy.h
  50. 8 0
      include/pocketpy/pocketpy.hpp
  51. 1 1
      include/pocketpy/tools/repl.hpp
  52. 3 3
      prebuild.py
  53. 1 1
      src/common/_generated.cpp
  54. 7 3
      src/common/any.cpp
  55. 5 14
      src/common/memorypool.cpp
  56. 9 3
      src/common/str.cpp
  57. 13 11
      src/compiler/compiler.cpp
  58. 10 10
      src/compiler/expr.cpp
  59. 1 2
      src/compiler/lexer.cpp
  60. 7 7
      src/interpreter/ceval.cpp
  61. 1 1
      src/interpreter/cffi.cpp
  62. 27 3
      src/interpreter/frame.cpp
  63. 2 2
      src/interpreter/gc.cpp
  64. 1 1
      src/interpreter/iter.cpp
  65. 3 3
      src/interpreter/profiler.cpp
  66. 15 16
      src/interpreter/vm.cpp
  67. 6 5
      src/modules/array2d.cpp
  68. 2 1
      src/modules/base64.cpp
  69. 2 1
      src/modules/csv.cpp
  70. 2 1
      src/modules/dataclasses.cpp
  71. 4 1
      src/modules/easing.cpp
  72. 3 2
      src/modules/io.cpp
  73. 3 2
      src/modules/linalg.cpp
  74. 9 1
      src/modules/modules.cpp
  75. 4 1
      src/modules/random.cpp
  76. 0 4
      src/namedict.cpp
  77. 6 0
      src/objects/builtins.cpp
  78. 1 4
      src/objects/codeobject.cpp
  79. 3 3
      src/objects/dict.cpp
  80. 20 0
      src/objects/error.cpp
  81. 1 1
      src/objects/object.cpp
  82. 1 19
      src/objects/sourcedata.cpp
  83. 1 1
      src/objects/tuplelist.cpp
  84. 17 2
      src/pocketpy.cpp
  85. 5 3
      src/pocketpy_c.cpp
  86. 4 1
      src/tools/repl.cpp

+ 1 - 1
3rd/cjson/include/cJSONw.hpp

@@ -1,5 +1,5 @@
 #include "cJSON.h"
-#include "pocketpy/pocketpy.h"
+#include "pocketpy/pocketpy.hpp"
 
 namespace pkpy {
 

+ 2 - 2
3rd/lua_bridge/src/lua_bridge.cpp

@@ -8,7 +8,7 @@ static PyVar lua_popx_to_python(VM*);
 
 template<typename T>
 static void table_apply(VM* vm, T f){
-    PK_ASSERT(lua_istable(_L, -1));
+    assert(lua_istable(_L, -1));
     lua_pushnil(_L);                 // [key]
     while(lua_next(_L, -2) != 0){    // [key, val]
         lua_pushvalue(_L, -2);       // [key, val, key]
@@ -191,7 +191,7 @@ static PyVar lua_popx_multi_to_python(VM* vm, int count){
         }
         return VAR(std::move(ret));
     }
-    PK_FATAL_ERROR()
+    assert(false);
 }
 
 struct PyLuaFunction: PyLuaObject{

+ 1 - 1
CMakeLists.txt

@@ -17,7 +17,7 @@ else()
 endif()
 
 include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
-aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src POCKETPY_SRC)
+file(GLOB_RECURSE POCKETPY_SRC ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp)
 
 option(PK_USE_CJSON "" OFF)
 if(PK_USE_CJSON)

+ 2 - 0
build_g.sh

@@ -1,3 +1,5 @@
+python prebuild.py
+
 SRC=$(find src/ -name "*.cpp")
 
 FLAGS="-std=c++17 -Og -stdlib=libc++ -Iinclude -frtti -Wfatal-errors -g"

+ 1 - 1
include/pocketpy.h

@@ -1,3 +1,3 @@
 #pragma once
 
-#include "pocketpy/pocketpy.h"
+#include "pocketpy/pocketpy.hpp"

+ 3 - 0
include/pocketpy.hpp

@@ -0,0 +1,3 @@
+#pragma once
+
+#include "pocketpy/pocketpy.hpp"

+ 0 - 4
include/pocketpy/ceval.h

@@ -1,4 +0,0 @@
-#pragma once
-
-#include "vm.h"
-// dummy header for ceval.cpp

+ 0 - 240
include/pocketpy/common.h

@@ -1,240 +0,0 @@
-#pragma once
-
-#include <cmath>
-#include <cstring>
-#include <ctime>
-
-#include <stdexcept>
-#include <string>
-#include <chrono>
-#include <string_view>
-#include <memory>
-#include <iostream>
-#include <map>
-#include <algorithm>
-#include <variant>
-#include <type_traits>
-#include <typeindex>
-
-#define PK_VERSION				"2.0.0"
-#define PK_VERSION_MAJOR            2
-#define PK_VERSION_MINOR            0
-#define PK_VERSION_PATCH            0
-
-#include "config.h"
-#include "export.h"
-
-#include "_generated.h"
-
-#ifdef min
-#undef min
-#endif
-
-#ifdef max
-#undef max
-#endif
-
-/*******************************************************************************/
-
-#if PK_ENABLE_THREAD
-#define PK_THREAD_LOCAL thread_local
-#include <mutex>
-
-struct GIL {
-	inline static std::mutex _mutex;
-    explicit GIL() { _mutex.lock(); }
-    ~GIL() { _mutex.unlock(); }
-};
-#define PK_GLOBAL_SCOPE_LOCK() GIL _lock;
-
-#else
-#define PK_THREAD_LOCAL
-#define PK_GLOBAL_SCOPE_LOCK()
-#endif
-
-/*******************************************************************************/
-namespace pkpy{
-
-namespace std = ::std;
-
-using i64 = int64_t;		// always 64-bit
-using f64 = double;			// always 64-bit
-
-static_assert(sizeof(i64) == 8);
-static_assert(sizeof(f64) == 8);
-
-struct DummyInstance { };
-struct DummyModule { };
-struct NoReturn { };
-struct Discarded { };
-
-struct Type {
-	int16_t index;
-	constexpr Type(): index(0) {}
-	explicit constexpr Type(int index): index(index) {}
-	bool operator==(Type other) const { return this->index == other.index; }
-	bool operator!=(Type other) const { return this->index != other.index; }
-    constexpr operator int() const { return index; }
-};
-
-#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return x; })
-#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); })
-#define PK_ACTION(x) ([](VM* vm, ArgsView args) -> PyVar { x; return vm->None; })
-
-#define PK_REGION(name)	1
-
-#ifdef POCKETPY_H
-#define PK_FATAL_ERROR() throw std::runtime_error( "L" + std::to_string(__LINE__) + " FATAL_ERROR()!");
-#else
-#define PK_FATAL_ERROR() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " FATAL_ERROR()!");
-#endif
-
-#define PK_ASSERT(x) if(!(x)) PK_FATAL_ERROR();
-
-#if PK_DEBUG_EXTRA_CHECK
-#define PK_DEBUG_ASSERT(x) if(!(x)) PK_FATAL_ERROR();
-#else
-#define PK_DEBUG_ASSERT(x)
-#endif
-
-// is_pod_v<> for c++17 and c++20
-template<typename T>
-inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
-
-#define PK_ALWAYS_PASS_BY_POINTER(T) \
-	T(const T&) = delete; \
-	T& operator=(const T&) = delete; \
-	T(T&&) = delete; \
-	T& operator=(T&&) = delete;
-
-inline const char* kPlatformStrings[] = {
-    "win32",        // 0
-    "emscripten",   // 1
-    "ios",          // 2
-    "darwin",       // 3
-    "android",      // 4
-    "linux",        // 5
-    "unknown"       // 6
-};
-
-#define PK_SLICE_LOOP(i, start, stop, step) for(int i=start; step>0?i<stop:i>stop; i+=step)
-
-template<typename T>
-inline constexpr bool is_integral_v = std::is_same_v<T, char>
-        || std::is_same_v<T, short>
-        || std::is_same_v<T, int>
-        || std::is_same_v<T, long>
-        || std::is_same_v<T, long long>
-        || std::is_same_v<T, unsigned char>
-        || std::is_same_v<T, unsigned short>
-        || std::is_same_v<T, unsigned int>
-        || std::is_same_v<T, unsigned long>
-        || std::is_same_v<T, unsigned long long>
-		|| std::is_same_v<T, signed char>;		// for imgui
-
-template<typename T>
-inline constexpr bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>;
-
-inline const char* PK_HEX_TABLE = "0123456789abcdef";
-
-struct PyObject;
-struct Frame;
-class VM;
-
-// by default, only `int` and `float` enable SSO
-// users can specialize this template to enable SSO for other types
-// SSO types cannot have instance dict
-template<typename T>
-inline constexpr bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
-
-// make a obj_get_t<T> for a given type T, if is_sso_v<T> is true, return T, else return T&
-template<typename T>
-using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>;
-
-struct const_sso_var {};
-
-struct PyVar final{
-    Type type;
-    bool is_ptr;
-    uint8_t flags;
-    // 12 bytes SSO
-    int _0; i64 _1;
-
-    // uninitialized
-    PyVar() = default;
-
-    // implict conversion
-    PyVar(PyObject* p);
-
-    /* We must initialize all members to allow == operator to work correctly */
-    // constexpr initialized
-    constexpr PyVar(const const_sso_var&, Type type, int value): type(type), is_ptr(false), flags(0), _0(value), _1(0) {}
-    // zero initialized
-    constexpr PyVar(std::nullptr_t): type(0), is_ptr(false), flags(0), _0(0), _1(0) {}
-    // PyObject* initialized (is_sso = false)
-    PyVar(Type type, PyObject* p): type(type), is_ptr(true), flags(0), _0(0), _1(reinterpret_cast<i64>(p)) {}
-    // SSO initialized (is_sso = true)
-    template<typename T>
-    PyVar(Type type, T value): type(type), is_ptr(false), flags(0), _0(0), _1(0) {
-        static_assert(sizeof(T) <= 12, "SSO size exceeded");
-        as<T>() = value;
-    }
-
-    template<typename T>
-    T& as(){
-        static_assert(!std::is_reference_v<T>);
-        if constexpr(sizeof(T) <= 8){
-            return reinterpret_cast<T&>(_1);
-        }else{
-            return reinterpret_cast<T&>(_0);
-        }
-    }
-
-    explicit operator bool() const { return (bool)type; }
-
-    void set_null() { _qword(0) = 0; _qword(1) = 0; }
-
-    i64 _qword(int i) const { return ((const i64*)this)[i]; }
-    i64& _qword(int i) { return ((i64*)this)[i]; }
-
-    bool operator==(const PyVar& other) const {
-        return _qword(0) == other._qword(0) && _qword(1) == other._qword(1);
-    }
-
-    bool operator!=(const PyVar& other) const {
-        return _qword(0) != other._qword(0) || _qword(1) != other._qword(1);
-    }
-
-    bool operator==(std::nullptr_t) const { return !(bool)type; }
-    bool operator!=(std::nullptr_t) const { return (bool)type; }
-
-    PyObject* get() const {
-        PK_DEBUG_ASSERT(is_ptr)
-        return reinterpret_cast<PyObject*>(_1);
-    }
-
-    PyObject* operator->() const {
-        PK_DEBUG_ASSERT(is_ptr)
-        return reinterpret_cast<PyObject*>(_1);
-    }
-
-    i64 hash() const { return _0 + _1; }
-
-    template<typename T>
-    obj_get_t<T> obj_get();
-};
-
-static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);
-
-} // namespace pkpy
-
-
-// specialize std::less for PyVar
-namespace std {
-    template<>
-    struct less<pkpy::PyVar> {
-        bool operator()(const pkpy::PyVar& lhs, const pkpy::PyVar& rhs) const {
-            return memcmp(&lhs, &rhs, sizeof(pkpy::PyVar)) < 0;
-        }
-    };
-}

+ 0 - 0
include/pocketpy/_generated.h → include/pocketpy/common/_generated.hpp


+ 6 - 3
include/pocketpy/any.h → include/pocketpy/common/any.hpp

@@ -1,7 +1,10 @@
 #pragma once
 
-#include "common.h"
-#include "str.h"
+#include "pocketpy/common/traits.hpp"
+
+#include <typeindex>
+#include <cassert>
+#include <utility>
 
 namespace pkpy {
 
@@ -98,7 +101,7 @@ struct function<Ret(Params...)>{
     }
 
     Ret operator()(Params... params) const{
-        if(!_wrapper) throw std::runtime_error("empty function");
+        assert(_wrapper);
         return _wrapper(_impl, std::forward<Params>(params)...);
     }
 };

+ 17 - 0
include/pocketpy/common/gil.hpp

@@ -0,0 +1,17 @@
+#pragma once
+
+#if PK_ENABLE_THREAD
+#define PK_THREAD_LOCAL thread_local
+#include <mutex>
+
+struct GIL {
+	inline static std::mutex _mutex;
+    explicit GIL() { _mutex.lock(); }
+    ~GIL() { _mutex.unlock(); }
+};
+#define PK_GLOBAL_SCOPE_LOCK() GIL _lock;
+
+#else
+#define PK_THREAD_LOCAL
+#define PK_GLOBAL_SCOPE_LOCK()
+#endif

+ 3 - 1
include/pocketpy/memory.h → include/pocketpy/common/memorypool.hpp

@@ -1,11 +1,13 @@
 #pragma once
 
-#include "common.h"
+#include <cstddef>
+#include <string>
 
 namespace pkpy{
 
 void* pool128_alloc(size_t) noexcept;
 void pool128_dealloc(void*) noexcept;
+
 template<typename T>
 void* pool128_alloc() noexcept{
     return pool128_alloc(sizeof(T));

+ 7 - 14
include/pocketpy/namedict.h → include/pocketpy/common/namedict.hpp

@@ -1,16 +1,16 @@
 #pragma once
 
-#include "common.h"
-#include "memory.h"
-#include "str.h"
+#include "pocketpy/common/utils.hpp"
+#include "pocketpy/common/str.hpp"
+
+#include "pocketpy/config.h"
 
 namespace pkpy{
 
 template<typename T>
 constexpr T default_invalid_value(){
-    if constexpr(std::is_same_v<PyVar, T>) return nullptr;
-    else if constexpr(std::is_same_v<int, T>) return -1;
-    else return Discarded();
+    if constexpr(std::is_same_v<int, T>) return -1;
+    else return nullptr;
 }
 
 template<typename T>
@@ -80,7 +80,7 @@ while(!_items[i].first.empty()) {           \
             if(old_items[i].first.empty()) continue;
             bool ok; uint16_t j;
             HASH_PROBE_1(old_items[i].first, ok, j);
-            if(ok) PK_FATAL_ERROR();
+            assert(!ok);
             _items[j] = old_items[i];
         }
         free(old_items);
@@ -190,11 +190,4 @@ while(!_items[i].first.empty()) {           \
 #undef HASH_PROBE_1
 };
 
-
-using NameDict = NameDictImpl<PyVar>;
-using NameDict_ = std::shared_ptr<NameDict>;
-using NameDictInt = NameDictImpl<int>;
-
-static_assert(sizeof(NameDict) <= 128);
-
 } // namespace pkpy

+ 6 - 3
include/pocketpy/str.h → include/pocketpy/common/str.hpp

@@ -1,8 +1,11 @@
 #pragma once
 
-#include "common.h"
-#include "memory.h"
-#include "vector.h"
+#include "pocketpy/common/utils.hpp"
+#include "pocketpy/common/memorypool.hpp"
+#include "pocketpy/common/vector.hpp"
+
+#include <string_view>
+#include <map>
 
 namespace pkpy {
 

+ 36 - 0
include/pocketpy/common/traits.hpp

@@ -0,0 +1,36 @@
+#pragma once
+
+#include <type_traits>
+
+namespace pkpy{
+
+// is_pod_v<> for c++17 and c++20
+template<typename T>
+inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
+
+// https://en.cppreference.com/w/cpp/types/is_integral
+template<typename T>
+inline constexpr bool is_integral_v = !std::is_same_v<T, bool> && std::is_integral_v<T>;
+
+template<typename T>
+inline constexpr bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>;
+
+// by default, only `int` and `float` enable SSO
+// users can specialize this template to enable SSO for other types
+// SSO types cannot have instance dict
+template<typename T>
+inline constexpr bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
+
+// if is_sso_v<T> is true, return T, else return T&
+template<typename T>
+using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>;
+
+template<typename T>
+constexpr inline bool is_trivially_relocatable_v = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
+
+template <typename, typename=void> struct has_gc_marker : std::false_type {};
+template <typename T> struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
+
+template<typename T>
+inline constexpr int py_sizeof = 16 + sizeof(T);
+}   // namespace pkpy

+ 28 - 0
include/pocketpy/common/types.hpp

@@ -0,0 +1,28 @@
+#pragma once
+
+#include <cstdint>
+
+namespace pkpy{
+
+using i64 = int64_t;		// always 64-bit
+using f64 = double;			// always 64-bit
+
+static_assert(sizeof(i64) == 8);
+static_assert(sizeof(f64) == 8);
+
+// Explicitly allow copying if copy constructor is deleted
+struct explicit_copy_t {
+    explicit explicit_copy_t() = default;
+};
+
+// Dummy types
+struct DummyInstance { };
+struct DummyModule { };
+struct NoReturn { };
+
+// Forward declarations
+struct PyObject;
+struct Frame;
+class VM;
+
+};  // namespace pkpy

+ 28 - 0
include/pocketpy/common/utils.hpp

@@ -0,0 +1,28 @@
+#pragma once
+
+#define PK_REGION(name)	1
+
+#define PK_ALWAYS_PASS_BY_POINTER(T) \
+	T(const T&) = delete; \
+	T& operator=(const T&) = delete; \
+	T(T&&) = delete; \
+	T& operator=(T&&) = delete;
+
+#define PK_SLICE_LOOP(i, start, stop, step) for(int i=start; step>0?i<stop:i>stop; i+=step)
+
+namespace pkpy{
+    
+// global constants
+inline const char* PK_HEX_TABLE = "0123456789abcdef";
+
+inline const char* kPlatformStrings[] = {
+    "win32",        // 0
+    "emscripten",   // 1
+    "ios",          // 2
+    "darwin",       // 3
+    "android",      // 4
+    "linux",        // 5
+    "unknown"       // 6
+};
+
+} // namespace pkpy

+ 11 - 14
include/pocketpy/vector.h → include/pocketpy/common/vector.hpp

@@ -1,16 +1,13 @@
 #pragma once
 
-#include "common.h"
-#include "memory.h"
+#include "pocketpy/common/traits.hpp"
+#include "pocketpy/common/types.hpp"
 
-namespace pkpy{
-
-struct explicit_copy_t {
-    explicit explicit_copy_t() = default;
-};
+#include <cstring>
+#include <memory>
+#include <cassert>
 
-template<typename T>
-constexpr inline bool is_trivially_relocatable_v = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
+namespace pkpy{
 
 template<typename T>
 struct array{
@@ -48,12 +45,12 @@ struct array{
     array& operator=(const array& other) = delete;
 
     T& operator[](int i) {
-        PK_DEBUG_ASSERT(i>=0 && i<_size);
+        assert(i >= 0 && i < _size);
         return _data[i];
     }
 
     const T& operator[](int i) const {
-        PK_DEBUG_ASSERT(i>=0 && i<_size);
+        assert(i >= 0 && i < _size);
         return _data[i];
     }
 
@@ -192,7 +189,7 @@ struct vector{
     }
 
     void pop_back(){
-        PK_DEBUG_ASSERT(_size > 0);
+        assert(_size > 0);
         _size--;
         if constexpr(!std::is_trivially_destructible_v<T>){
             _data[_size].~T();
@@ -315,7 +312,7 @@ namespace pkpy {
         {
             if constexpr (std::is_trivially_copyable_v<T>)
             {
-                std::memcpy(dest, src, sizeof(T) * n);
+                memcpy(dest, src, sizeof(T) * n);
             }
             else
             {
@@ -330,7 +327,7 @@ namespace pkpy {
         {
             if constexpr (is_trivially_relocatable_v<T>)
             {
-                std::memcpy(dest, src, sizeof(T) * n);
+                memcpy(dest, src, sizeof(T) * n);
             }
             else
             {

+ 6 - 0
include/pocketpy/common/version.hpp

@@ -0,0 +1,6 @@
+#pragma once
+
+#define PK_VERSION				"2.0.0"
+#define PK_VERSION_MAJOR            2
+#define PK_VERSION_MINOR            0
+#define PK_VERSION_PATCH            0

+ 1 - 4
include/pocketpy/compiler.h → include/pocketpy/compiler/compiler.hpp

@@ -1,9 +1,6 @@
 #pragma once
 
-#include "codeobject.h"
-#include "common.h"
-#include "expr.h"
-#include "obj.h"
+#include "pocketpy/compiler/expr.hpp"
 
 namespace pkpy{
 

+ 2 - 5
include/pocketpy/expr.h → include/pocketpy/compiler/expr.hpp

@@ -1,10 +1,7 @@
 #pragma once
 
-#include "codeobject.h"
-#include "common.h"
-#include "lexer.h"
-#include "error.h"
-#include "vm.h"
+#include "pocketpy/objects/codeobject.hpp"
+#include "pocketpy/compiler/lexer.hpp"
 
 namespace pkpy{
 

+ 4 - 4
include/pocketpy/lexer.h → include/pocketpy/compiler/lexer.hpp

@@ -1,9 +1,9 @@
 #pragma once
 
-#include "common.h"
-#include "error.h"
-#include "str.h"
-#include "obj.h"
+#include "pocketpy/objects/sourcedata.hpp"
+#include "pocketpy/objects/error.hpp"
+
+#include <variant>
 
 namespace pkpy{
 

+ 8 - 5
include/pocketpy/bindings.h → include/pocketpy/interpreter/bindings.hpp

@@ -1,7 +1,6 @@
 #pragma once
 
-#include "cffi.h"
-#include "vm.h"
+#include "pocketpy/interpreter/cffi.hpp"
 
 namespace pkpy{
 struct NativeProxyFuncCBase {
@@ -16,7 +15,7 @@ struct NativeProxyFuncC final: NativeProxyFuncCBase {
     NativeProxyFuncC(_Fp func) : func(func) {}
 
     PyVar operator()(VM* vm, ArgsView args) override {
-        PK_DEBUG_ASSERT(args.size() == N);
+        assert(args.size() == N);
         return call<Ret>(vm, args, std::make_index_sequence<N>());
     }
 
@@ -40,7 +39,7 @@ struct NativeProxyMethodC final: NativeProxyFuncCBase {
     NativeProxyMethodC(_Fp func) : func(func) {}
 
     PyVar operator()(VM* vm, ArgsView args) override {
-        PK_DEBUG_ASSERT(args.size() == N+1);
+        assert(args.size() == N+1);
         return call<Ret>(vm, args, std::make_index_sequence<N>());
     }
 
@@ -89,7 +88,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(T:
 template<typename T, typename F, bool ReadOnly>
 PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
     static_assert(!std::is_reference_v<F>);
-    PK_ASSERT(is_type(obj, tp_type));
+    assert(is_type(obj, tp_type));
     std::string_view name_sv(name); int pos = name_sv.find(':');
     if(pos > 0) name_sv = name_sv.substr(0, pos);
     auto fget = [](VM* vm, ArgsView args) -> PyVar{
@@ -201,4 +200,8 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
             tgt[i] = CAST(T, _2);                                                               \
         });                                                                                     \
 
+#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return x; })
+#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); })
+#define PK_ACTION(x) ([](VM* vm, ArgsView args) -> PyVar { x; return vm->None; })
+
 }   // namespace pkpy

+ 4 - 0
include/pocketpy/interpreter/ceval.hpp

@@ -0,0 +1,4 @@
+#pragma once
+
+#include "pocketpy/interpreter/vm.hpp"
+// dummy header for ceval.cpp

+ 1 - 2
include/pocketpy/cffi.h → include/pocketpy/interpreter/cffi.hpp

@@ -1,7 +1,6 @@
 #pragma once
 
-#include "common.h"
-#include "vm.h"
+#include "pocketpy/interpreter/vm.hpp"
 
 namespace pkpy {
 

+ 5 - 29
include/pocketpy/frame.h → include/pocketpy/interpreter/frame.hpp

@@ -1,10 +1,6 @@
 #pragma once
 
-#include "codeobject.h"
-#include "common.h"
-#include "memory.h"
-#include "obj.h"
-#include "vector.h"
+#include "pocketpy/objects/codeobject.hpp"
 
 namespace pkpy{
 
@@ -155,32 +151,12 @@ struct CallStack{
         ++_size;
     }
 
-    void pop(){
-        PK_DEBUG_ASSERT(!empty())
-        LinkedFrame* p = _tail;
-        _tail = p->f_back;
-        p->~LinkedFrame();
-        pool128_dealloc(p);
-        --_size;
-    }
-
-    LinkedFrame* popx(){
-        PK_DEBUG_ASSERT(!empty())
-        LinkedFrame* p = _tail;
-        _tail = p->f_back;
-        --_size;
-        p->f_back = nullptr;        // unlink
-        return p;
-    }
-
-    void pushx(LinkedFrame* p){
-        p->f_back = _tail;
-        _tail = p;
-        ++_size;
-    }
+    void pop();
+    LinkedFrame* popx();
+    void pushx(LinkedFrame* p);
 
     Frame& top() const {
-        PK_DEBUG_ASSERT(!empty())
+        assert(!empty());
         return _tail->frame;
     }
 

+ 4 - 3
include/pocketpy/gc.h → include/pocketpy/interpreter/gc.hpp

@@ -1,8 +1,9 @@
 #pragma once
 
-#include "common.h"
-#include "memory.h"
-#include "obj.h"
+#include "pocketpy/config.h"
+#include "pocketpy/common/vector.hpp"
+#include "pocketpy/common/utils.hpp"
+#include "pocketpy/objects/object.hpp"
 
 namespace pkpy {
 struct ManagedHeap{

+ 1 - 3
include/pocketpy/iter.h → include/pocketpy/interpreter/iter.hpp

@@ -1,8 +1,6 @@
 #pragma once
 
-#include "cffi.h"
-#include "common.h"
-#include "frame.h"
+#include "pocketpy/interpreter/bindings.hpp"
 
 namespace pkpy{
 

+ 1 - 1
include/pocketpy/profiler.h → include/pocketpy/interpreter/profiler.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "frame.h"
+#include "pocketpy/interpreter/frame.hpp"
 
 namespace pkpy {
 

+ 11 - 13
include/pocketpy/vm.h → include/pocketpy/interpreter/vm.hpp

@@ -1,17 +1,12 @@
 #pragma once
 
-#include "codeobject.h"
-#include "common.h"
-#include "frame.h"
-#include "error.h"
-#include "gc.h"
-#include "memory.h"
-#include "obj.h"
-#include "str.h"
-#include "tuplelist.h"
-#include "dict.h"
-#include "profiler.h"
-
+#include "pocketpy/objects/object.hpp"
+#include "pocketpy/objects/dict.hpp"
+#include "pocketpy/objects/error.hpp"
+#include "pocketpy/objects/stackmemory.hpp"
+#include "pocketpy/objects/builtins.hpp"
+#include "pocketpy/interpreter/gc.hpp"
+#include "pocketpy/interpreter/frame.hpp"
 
 namespace pkpy{
 
@@ -654,7 +649,10 @@ PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _reg
                 return vm->new_object<T>(cls_t);
             });
         }else{
-            bind_func(type, __new__, -1, PK_ACTION(vm->NotImplementedError()));
+            bind_func(type, __new__, -1, [](VM* vm, ArgsView args){
+                vm->NotImplementedError();
+                return vm->None;
+            });
         }
     }
     return type;

+ 1 - 1
include/pocketpy/array2d.h → include/pocketpy/modules/array2d.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
 
 namespace pkpy {
 

+ 1 - 1
include/pocketpy/base64.h → include/pocketpy/modules/base64.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
 
 namespace pkpy {
 

+ 1 - 1
include/pocketpy/csv.h → include/pocketpy/modules/csv.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
 
 namespace pkpy {
 

+ 1 - 1
include/pocketpy/dataclasses.h → include/pocketpy/modules/dataclasses.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
 
 namespace pkpy{
 

+ 1 - 1
include/pocketpy/easing.h → include/pocketpy/modules/easing.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
 
 namespace pkpy{
 

+ 1 - 1
include/pocketpy/io.h → include/pocketpy/modules/io.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
 
 namespace pkpy{
     unsigned char* _default_import_handler(const char*, int*);

+ 4 - 1
include/pocketpy/linalg.h → include/pocketpy/modules/linalg.hpp

@@ -1,6 +1,9 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
+#include "pocketpy/common/traits.hpp"
+
+#include <cmath>
 
 namespace pkpy{
 

+ 1 - 1
include/pocketpy/modules.h → include/pocketpy/modules/modules.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
 
 namespace pkpy{
 

+ 1 - 1
include/pocketpy/random.h → include/pocketpy/modules/random.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "bindings.h"
+#include "pocketpy/common/types.hpp"
 
 namespace pkpy{
 

+ 100 - 0
include/pocketpy/objects/base.hpp

@@ -0,0 +1,100 @@
+#pragma once
+
+#include "pocketpy/common/types.hpp"
+#include "pocketpy/common/traits.hpp"
+
+#include <cstdint>
+#include <cassert>
+#include <cstring>
+
+namespace pkpy{
+
+struct Type {
+	int16_t index;
+	constexpr Type(): index(0) {}
+	explicit constexpr Type(int index): index(index) {}
+	bool operator==(Type other) const { return this->index == other.index; }
+	bool operator!=(Type other) const { return this->index != other.index; }
+    constexpr operator int() const { return index; }
+};
+
+struct const_sso_var {};
+
+struct PyVar final{
+    Type type;
+    bool is_ptr;
+    uint8_t flags;
+    // 12 bytes SSO
+    int _0; i64 _1;
+
+    // uninitialized
+    PyVar() = default;
+
+    // implict conversion
+    PyVar(PyObject* p);
+
+    /* We must initialize all members to allow == operator to work correctly */
+    // constexpr initialized
+    constexpr PyVar(const const_sso_var&, Type type, int value): type(type), is_ptr(false), flags(0), _0(value), _1(0) {}
+    // zero initialized
+    constexpr PyVar(std::nullptr_t): type(0), is_ptr(false), flags(0), _0(0), _1(0) {}
+    // PyObject* initialized (is_sso = false)
+    PyVar(Type type, PyObject* p): type(type), is_ptr(true), flags(0), _0(0), _1(reinterpret_cast<i64>(p)) {}
+    // SSO initialized (is_sso = true)
+    template<typename T>
+    PyVar(Type type, T value): type(type), is_ptr(false), flags(0), _0(0), _1(0) {
+        static_assert(sizeof(T) <= 12, "SSO size exceeded");
+        as<T>() = value;
+    }
+
+    template<typename T>
+    T& as(){
+        static_assert(!std::is_reference_v<T>);
+        if constexpr(sizeof(T) <= 8){
+            return reinterpret_cast<T&>(_1);
+        }else{
+            return reinterpret_cast<T&>(_0);
+        }
+    }
+
+    explicit operator bool() const { return (bool)type; }
+
+    void set_null() { _qword(0) = 0; _qword(1) = 0; }
+
+    i64 _qword(int i) const { return ((const i64*)this)[i]; }
+    i64& _qword(int i) { return ((i64*)this)[i]; }
+
+    bool operator==(const PyVar& other) const {
+        return _qword(0) == other._qword(0) && _qword(1) == other._qword(1);
+    }
+
+    bool operator!=(const PyVar& other) const {
+        return _qword(0) != other._qword(0) || _qword(1) != other._qword(1);
+    }
+
+    bool operator==(std::nullptr_t) const { return !(bool)type; }
+    bool operator!=(std::nullptr_t) const { return (bool)type; }
+
+    PyObject* get() const {
+        assert(is_ptr);
+        return reinterpret_cast<PyObject*>(_1);
+    }
+
+    PyObject* operator->() const {
+        assert(is_ptr);
+        return reinterpret_cast<PyObject*>(_1);
+    }
+
+    i64 hash() const { return _0 + _1; }
+
+    template<typename T>
+    obj_get_t<T> obj_get();
+
+    // for std::map<>
+    bool operator<(const PyVar& other) const {
+        return memcmp(this, &other, sizeof(PyVar)) < 0;
+    }
+};
+
+static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);
+}   // namespace pkpy

+ 6 - 83
include/pocketpy/obj.h → include/pocketpy/objects/builtins.hpp

@@ -1,22 +1,9 @@
 #pragma once
 
-#include "common.h"
-#include "namedict.h"
-#include "tuplelist.h"
-
-namespace pkpy {
-    
-#if PK_ENABLE_STD_FUNCTION
-using NativeFuncC = function<PyVar(VM*, ArgsView)>;
-#else
-typedef PyVar (*NativeFuncC)(VM*, ArgsView);
-#endif
-
-enum class BindType{
-    DEFAULT,
-    STATICMETHOD,
-    CLASSMETHOD,
-};
+#include "pocketpy/common/vector.hpp"
+#include "pocketpy/objects/object.hpp"
+
+namespace pkpy{
 
 struct BoundMethod {
     PyVar self;
@@ -50,13 +37,6 @@ struct Range {
     i64 step = 1;
 };
 
-struct StackMemory{
-    int count;
-    StackMemory(int count) : count(count) {}
-};
-
-template<>
-inline bool constexpr is_sso_v<StackMemory> = true;
 
 struct StarWrapper{
     int level;      // either 1 or 2
@@ -82,76 +62,19 @@ struct Slice {
     void _gc_mark(VM*) const;
 };
 
-struct PyObject final{
-    static constexpr int FIXED_SIZE = 16;
-    
-    bool gc_marked;     // whether this object is marked
-    Type type;          // we have a duplicated type here for convenience
-    NameDict* _attr;    // gc will delete this on destruction
-
-    bool is_attr_valid() const noexcept { return _attr != nullptr; }
-    void* _value_ptr() noexcept { return (char*)this + FIXED_SIZE; }
-
-    template<typename T> T& as() noexcept {
-        static_assert(std::is_same_v<T, std::decay_t<T>>);
-        return *reinterpret_cast<T*>(_value_ptr());
-    }
-
-    NameDict& attr() {
-        PK_DEBUG_ASSERT(is_attr_valid())
-        return *_attr;
-    }
-
-    PyVar attr(StrName name) const {
-        PK_DEBUG_ASSERT(is_attr_valid())
-        return (*_attr)[name];
-    }
-
-    PyObject(Type type) : gc_marked(false), type(type), _attr(nullptr) {}
-
-    template<typename T, typename ...Args>
-    void placement_new(Args&&... args){
-        static_assert(std::is_same_v<T, std::decay_t<T>>);
-        new(_value_ptr()) T(std::forward<Args>(args)...);
-
-        // backdoor for important builtin types
-        if constexpr(std::is_same_v<T, DummyInstance>){
-            _enable_instance_dict();
-        }else if constexpr(std::is_same_v<T, Type>){
-            _enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
-        }else if constexpr(std::is_same_v<T, DummyModule>){
-            _enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
-        }
-    }
-
-    void _enable_instance_dict() {
-        _attr = new(pool128_alloc<NameDict>()) NameDict();
-    }
-    void _enable_instance_dict(float lf){
-        _attr = new(pool128_alloc<NameDict>()) NameDict(lf);
-    }
-};
-
-static_assert(sizeof(PyObject) <= PyObject::FIXED_SIZE);
-template<typename T>
-inline constexpr int py_sizeof = PyObject::FIXED_SIZE + sizeof(T);
 
 inline const int kTpIntIndex = 3;
 inline const int kTpFloatIndex = 4;
-inline const int kTpStackMemoryIndex = 27;
 
 inline bool is_tagged(PyVar p) noexcept { return !p.is_ptr; }
 inline bool is_float(PyVar p) noexcept { return p.type.index == kTpFloatIndex; }
 inline bool is_int(PyVar p) noexcept { return p.type.index == kTpIntIndex; }
 
 inline bool is_type(PyVar obj, Type type) {
-    PK_DEBUG_ASSERT(obj != nullptr)
+    assert(obj != nullptr);
     return obj.type == type;
 }
 
-template <typename, typename=void> struct has_gc_marker : std::false_type {};
-template <typename T> struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
-
 struct MappingProxy{
     PyObject* obj;
     MappingProxy(PyObject* obj) : obj(obj) {}
@@ -169,7 +92,7 @@ obj_get_t<T> PyVar::obj_get(){
     if constexpr(is_sso_v<T>){
         return as<T>();
     }else{
-        PK_DEBUG_ASSERT(is_ptr)
+        assert(is_ptr);
         void* v = ((PyObject*)_1)->_value_ptr();
         return *reinterpret_cast<T*>(v);
     }

+ 19 - 6
include/pocketpy/codeobject.h → include/pocketpy/objects/codeobject.hpp

@@ -1,16 +1,29 @@
 #pragma once
 
-#include "obj.h"
-#include "error.h"
-#include "any.h"
+#include "pocketpy/common/any.hpp"
+#include "pocketpy/objects/tuplelist.hpp"
+#include "pocketpy/objects/object.hpp"
+#include "pocketpy/objects/sourcedata.hpp"
 
 namespace pkpy{
 
+#if PK_ENABLE_STD_FUNCTION
+using NativeFuncC = function<PyVar(VM*, ArgsView)>;
+#else
+typedef PyVar (*NativeFuncC)(VM*, ArgsView);
+#endif
+
+enum class BindType{
+    DEFAULT,
+    STATICMETHOD,
+    CLASSMETHOD,
+};
+
 enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
 
 enum Opcode: uint8_t {
     #define OPCODE(name) OP_##name,
-    #include "opcodes.h"
+    #include "pocketpy/opcodes.h"
     #undef OPCODE
 };
 
@@ -158,8 +171,8 @@ struct Function{
 template<typename T>
 T& lambda_get_userdata(PyVar* p){
     static_assert(std::is_same_v<T, std::decay_t<T>>);
-    int offset = p[-1] != PY_NULL ? -1 : -2;
-    return PK_OBJ_GET(NativeFunc, p[offset])._userdata.cast<T>();
+    int offset = p[-1] != nullptr ? -1 : -2;
+    return p[offset].obj_get<NativeFunc>()._userdata.cast<T>();
 }
 
 } // namespace pkpy

+ 2 - 4
include/pocketpy/dict.h → include/pocketpy/objects/dict.hpp

@@ -1,9 +1,7 @@
 #pragma once
 
-#include "obj.h"
-#include "common.h"
-#include "memory.h"
-#include "str.h"
+#include "pocketpy/objects/base.hpp"
+#include "pocketpy/objects/tuplelist.hpp"
 
 namespace pkpy{
 

+ 3 - 31
include/pocketpy/error.h → include/pocketpy/objects/error.hpp

@@ -1,8 +1,7 @@
 #pragma once
 
-#include "namedict.h"
-#include "str.h"
-#include "tuplelist.h"
+#include "pocketpy/common/str.hpp"
+#include "pocketpy/objects/sourcedata.hpp"
 
 namespace pkpy{
 
@@ -22,33 +21,6 @@ struct InternalException final{
     InternalException(InternalExceptionType type, int arg=-1): type(type), arg(arg) {}
 };
 
-enum CompileMode {
-    EXEC_MODE,
-    EVAL_MODE,
-    REPL_MODE,
-    JSON_MODE,
-    CELL_MODE
-};
-
-struct SourceData {
-    PK_ALWAYS_PASS_BY_POINTER(SourceData)
-
-    Str filename;
-    CompileMode mode;
-
-    Str source;
-    vector<const char*> line_starts;
-
-    bool is_precompiled;
-    vector<Str> _precompiled_tokens;
-    
-    SourceData(std::string_view source, const Str& filename, CompileMode mode);
-    SourceData(const Str& filename, CompileMode mode);
-    std::pair<const char*,const char*> _get_line(int lineno) const;
-    std::string_view get_line(int lineno) const;
-    Str snapshot(int lineno, const char* cursor, std::string_view name) const;
-};
-
 struct Exception {
     StrName type;
     Str msg;
@@ -75,7 +47,7 @@ struct Exception {
     Exception(StrName type): type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
 
     PyObject* self() const{
-        PK_ASSERT(_self != nullptr);
+        assert(_self != nullptr);
         return _self;
     }
 

+ 63 - 0
include/pocketpy/objects/object.hpp

@@ -0,0 +1,63 @@
+#pragma once
+
+#include "pocketpy/common/namedict.hpp"
+#include "pocketpy/objects/base.hpp"
+
+namespace pkpy{
+using NameDict = NameDictImpl<PyVar>;
+using NameDict_ = std::shared_ptr<NameDict>;
+using NameDictInt = NameDictImpl<int>;
+
+static_assert(sizeof(NameDict) <= 128);
+
+struct PyObject final{
+    bool gc_marked;     // whether this object is marked
+    Type type;          // we have a duplicated type here for convenience
+    NameDict* _attr;    // gc will delete this on destruction
+
+    bool is_attr_valid() const noexcept { return _attr != nullptr; }
+    void* _value_ptr() noexcept { return (char*)this + 16; }
+
+    template<typename T> T& as() noexcept {
+        static_assert(std::is_same_v<T, std::decay_t<T>>);
+        return *reinterpret_cast<T*>(_value_ptr());
+    }
+
+    NameDict& attr() {
+        assert(is_attr_valid());
+        return *_attr;
+    }
+
+    PyVar attr(StrName name) const {
+        assert(is_attr_valid());
+        return (*_attr)[name];
+    }
+
+    PyObject(Type type) : gc_marked(false), type(type), _attr(nullptr) {}
+
+    template<typename T, typename ...Args>
+    void placement_new(Args&&... args){
+        static_assert(std::is_same_v<T, std::decay_t<T>>);
+        new(_value_ptr()) T(std::forward<Args>(args)...);
+
+        // backdoor for important builtin types
+        if constexpr(std::is_same_v<T, DummyInstance>){
+            _enable_instance_dict();
+        }else if constexpr(std::is_same_v<T, Type>){
+            _enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
+        }else if constexpr(std::is_same_v<T, DummyModule>){
+            _enable_instance_dict(PK_TYPE_ATTR_LOAD_FACTOR);
+        }
+    }
+
+    void _enable_instance_dict() {
+        _attr = new(pool128_alloc<NameDict>()) NameDict();
+    }
+    void _enable_instance_dict(float lf){
+        _attr = new(pool128_alloc<NameDict>()) NameDict(lf);
+    }
+};
+
+static_assert(sizeof(PyObject) <= 16);
+
+}   // namespace pkpy

+ 35 - 0
include/pocketpy/objects/sourcedata.hpp

@@ -0,0 +1,35 @@
+#pragma once
+
+#include "pocketpy/common/utils.hpp"
+#include "pocketpy/common/str.hpp"
+
+namespace pkpy{
+
+enum CompileMode {
+    EXEC_MODE,
+    EVAL_MODE,
+    REPL_MODE,
+    JSON_MODE,
+    CELL_MODE
+};
+
+struct SourceData {
+    PK_ALWAYS_PASS_BY_POINTER(SourceData)
+
+    Str filename;
+    CompileMode mode;
+
+    Str source;
+    vector<const char*> line_starts;
+
+    bool is_precompiled;
+    vector<Str> _precompiled_tokens;
+    
+    SourceData(std::string_view source, const Str& filename, CompileMode mode);
+    SourceData(const Str& filename, CompileMode mode);
+    std::pair<const char*,const char*> _get_line(int lineno) const;
+    std::string_view get_line(int lineno) const;
+    Str snapshot(int lineno, const char* cursor, std::string_view name) const;
+};
+
+}   // namespace pkpy

+ 17 - 0
include/pocketpy/objects/stackmemory.hpp

@@ -0,0 +1,17 @@
+#pragma once
+
+#include "pocketpy/common/traits.hpp"
+
+namespace pkpy{
+
+struct StackMemory{
+    int count;
+    StackMemory(int count) : count(count) {}
+};
+
+template<>
+inline bool constexpr is_sso_v<StackMemory> = true;
+
+inline const int kTpStackMemoryIndex = 27;
+
+}   // namespace pkpy

+ 2 - 4
include/pocketpy/tuplelist.h → include/pocketpy/objects/tuplelist.hpp

@@ -1,9 +1,7 @@
 #pragma once
 
-#include "common.h"
-#include "memory.h"
-#include "str.h"
-#include "vector.h"
+#include "pocketpy/common/vector.hpp"
+#include "pocketpy/objects/base.hpp"
 
 namespace pkpy {
 

+ 0 - 18
include/pocketpy/pocketpy.h

@@ -1,18 +0,0 @@
-#pragma once
-
-#include "compiler.h"
-#include "obj.h"
-#include "repl.h"
-#include "iter.h"
-#include "base64.h"
-#include "cffi.h"
-#include "linalg.h"
-#include "easing.h"
-#include "io.h"
-#include "vm.h"
-#include "random.h"
-#include "bindings.h"
-#include "csv.h"
-#include "dataclasses.h"
-#include "array2d.h"
-#include "modules.h"

+ 8 - 0
include/pocketpy/pocketpy.hpp

@@ -0,0 +1,8 @@
+#pragma once
+
+#include "pocketpy/objects/builtins.hpp"
+#include "pocketpy/interpreter/vm.hpp"
+#include "pocketpy/interpreter/iter.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
+#include "pocketpy/compiler/compiler.hpp"
+#include "pocketpy/tools/repl.hpp"

+ 1 - 1
include/pocketpy/repl.h → include/pocketpy/tools/repl.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "vm.h"
+#include "pocketpy/interpreter/vm.hpp"
 
 namespace pkpy{
     

+ 3 - 3
prebuild.py

@@ -23,7 +23,7 @@ def get_sources():
 sources = get_sources()
 
 # use LF line endings instead of CRLF
-with open("include/pocketpy/_generated.h", "wt", encoding='utf-8', newline='\n') as f:
+with open("include/pocketpy/common/_generated.hpp", "wt", encoding='utf-8', newline='\n') as f:
     data = '''#pragma once
 // generated by prebuild.py
 
@@ -35,9 +35,9 @@ namespace pkpy{
     data += '}    // namespace pkpy\n'
     f.write(data)
 
-with open("src/_generated.cpp", "wt", encoding='utf-8', newline='\n') as f:
+with open("src/common/_generated.cpp", "wt", encoding='utf-8', newline='\n') as f:
     data = '''// generated by prebuild.py
-#include "pocketpy/_generated.h"
+#include "pocketpy/common/_generated.hpp"
 
 namespace pkpy{
 '''

+ 1 - 1
src/_generated.cpp → src/common/_generated.cpp

@@ -1,5 +1,5 @@
 // generated by prebuild.py
-#include "pocketpy/_generated.h"
+#include "pocketpy/common/_generated.hpp"
 
 namespace pkpy{
     const char kPythonLibs__enum[] = "class Enum:\n    def __init__(self, name, value):\n        self.name = name\n        self.value = value\n\n    def __str__(self):\n        return f'{type(self).__name__}.{self.name}'\n    \n    def __repr__(self):\n        return f'<{str(self)}: {self.value!r}>'\n    \n";

+ 7 - 3
src/any.cpp → src/common/any.cpp

@@ -1,10 +1,14 @@
-#include "pocketpy/any.h"
+#include "pocketpy/common/any.hpp"
+
+#include <stdexcept>
+#include <cstdio>
 
 namespace pkpy{
 
 void any::__bad_any_cast(const std::type_index expected, const std::type_index actual){
-    Str error = _S("bad_any_cast: expected ", expected.name(), ", got ", actual.name());
-    throw std::runtime_error(error.c_str());
+    char error[256];
+    snprintf(error, sizeof(error), "bad_any_cast: expected %s, got %s", expected.name(), actual.name());
+    throw std::runtime_error(error);
 }
 
 any::any(any&& other) noexcept: data(other.data), _vt(other._vt){

+ 5 - 14
src/memory.cpp → src/common/memorypool.cpp

@@ -1,4 +1,8 @@
-#include "pocketpy/memory.h"
+#include "pocketpy/common/memorypool.hpp"
+#include "pocketpy/common/gil.hpp"
+#include "pocketpy/config.h"
+
+#include <cstring>
 
 namespace pkpy{
 
@@ -84,18 +88,6 @@ struct DoubleLinkedList{
         _size--;
     }
 
-    // void move_all_back(DoubleLinkedList<T>& other){
-    //     if(other.empty()) return;
-    //     other.tail.prev->next = &tail;
-    //     tail.prev->next = other.head.next;
-    //     other.head.next->prev = tail.prev;
-    //     tail.prev = other.tail.prev;
-    //     _size += other._size;
-    //     other.head.next = &other.tail;
-    //     other.tail.prev = &other.head;
-    //     other._size = 0;
-    // }
-
     bool empty() const {
 #if PK_DEBUG_MEMORY_POOL
         if(size() == 0){
@@ -269,7 +261,6 @@ struct MemoryPool{
 
 static MemoryPool<128> pool128;
 
-
 void* pool128_alloc(size_t size) noexcept { return pool128.alloc(size); }
 void pool128_dealloc(void* p) noexcept { pool128.dealloc(p); }
 

+ 9 - 3
src/str.cpp → src/common/str.cpp

@@ -1,4 +1,10 @@
-#include "pocketpy/str.h"
+#include "pocketpy/common/str.hpp"
+
+#include <stdexcept>
+#include <cassert>
+#include <ostream>
+#include <algorithm>
+#include <cmath>
 
 namespace pkpy {
 
@@ -60,7 +66,7 @@ int utf8len(unsigned char c, bool suppress){
         for(int i=0; i<size; i++){
             if(!isascii(data[i])){ is_ascii = false; break; }
         }
-        PK_ASSERT(data[size] == '\0');
+        assert(data[size] == '\0');
     }
 
     Str::Str(const Str& other): size(other.size), is_ascii(other.is_ascii) {
@@ -396,7 +402,7 @@ int utf8len(unsigned char c, bool suppress){
         uint16_t index = ((_pesudo_random_index*5) + 1) & 65535;
         if(index == 0) throw std::runtime_error("StrName index overflow");
         auto res = _r_interned().emplace(index, s);
-        PK_ASSERT(res.second);
+        assert(res.second);
         s = std::string_view(res.first->second);
         _interned()[s] = index;
         _pesudo_random_index = index;

+ 13 - 11
src/compiler.cpp → src/compiler/compiler.cpp

@@ -1,4 +1,6 @@
-#include "pocketpy/compiler.h"
+#include "pocketpy/compiler/compiler.hpp"
+#include "pocketpy/common/version.hpp"
+#include "pocketpy/interpreter/vm.hpp"
 
 namespace pkpy{
     PrattRule Compiler::rules[kTokenCount];
@@ -92,7 +94,7 @@ namespace pkpy{
                 else func->type = FuncType::NORMAL;
             }
 
-            PK_ASSERT(func->type != FuncType::UNSET);
+            assert(func->type != FuncType::UNSET);
         }
         contexts.pop();
     }
@@ -322,7 +324,7 @@ namespace pkpy{
             case TK("**"):
                 ctx()->s_expr.push(make_expr<StarredExpr>(2, ctx()->s_expr.popx()));
                 break;
-            default: PK_FATAL_ERROR();
+            default: assert(false);
         }
     }
 
@@ -640,7 +642,7 @@ __EAT_DOTS_END:
             TokenIndex op = curr().type;
             advance();
             PrattCallback infix = rules[op].infix;
-            PK_ASSERT(infix != nullptr);
+            assert(infix != nullptr);
             (this->*infix)();
         }
     }
@@ -1015,7 +1017,7 @@ __EAT_DOTS_END:
                             ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
                         }
                     }else{
-                        PK_ASSERT(ctx()->s_expr.size() == 1)
+                        assert(ctx()->s_expr.size() == 1);
                         ctx()->s_expr.pop();
                     }
                 }
@@ -1185,7 +1187,7 @@ __EAT_DOTS_END:
         if(std::holds_alternative<Str>(value)){
             obj = VAR(std::get<Str>(value));
         }
-        PK_ASSERT(obj != nullptr)
+        assert(obj != nullptr);
         return obj;
     }
 
@@ -1239,7 +1241,7 @@ __EAT_DOTS_END:
                 if(it == token_indices.end()){
                     token_indices[token.sv()] = 0;
                     // assert no '\n' in token.sv()
-                    for(char c: token.sv()) if(c=='\n') PK_FATAL_ERROR();
+                    for(char c: token.sv()) assert(c!='\n');
                 }
             }
         }
@@ -1336,7 +1338,7 @@ __EAT_DOTS_END:
     }
 
     CodeObject_ Compiler::compile(){
-        PK_ASSERT(i == 0)       // make sure it is the first time to compile
+        assert(i == 0);       // make sure it is the first time to compile
 
         if(lexer.src->is_precompiled){
             from_precompiled(lexer.src->source.c_str());
@@ -1397,11 +1399,11 @@ __EAT_DOTS_END:
             char c = 0;
             if(s[i]>='0' && s[i]<='9') c += s[i]-'0';
             else if(s[i]>='a' && s[i]<='f') c += s[i]-'a'+10;
-            else PK_FATAL_ERROR();
+            else assert(false);
             c <<= 4;
             if(s[i+1]>='0' && s[i+1]<='9') c += s[i+1]-'0';
             else if(s[i+1]>='a' && s[i+1]<='f') c += s[i+1]-'a'+10;
-            else PK_FATAL_ERROR();
+            else assert(false);
             buffer[i/2] = c;
         }
         buffer[s.size()/2] = 0;
@@ -1409,7 +1411,7 @@ __EAT_DOTS_END:
     }
 
     int TokenDeserializer::read_count(){
-        PK_ASSERT(*curr == '=')
+        assert(*curr == '=');
         curr++;
         return read_uint('\n');
     }

+ 10 - 10
src/expr.cpp → src/compiler/expr.cpp

@@ -1,4 +1,5 @@
-#include "pocketpy/expr.h"
+#include "pocketpy/compiler/expr.hpp"
+#include "pocketpy/interpreter/vm.hpp"
 
 namespace pkpy{
 
@@ -33,8 +34,7 @@ namespace pkpy{
         auto curr_type = co->blocks[curr_iblock].type;
         co->blocks[curr_iblock].end = co->codes.size();
         curr_iblock = co->blocks[curr_iblock].parent;
-        if(curr_iblock < 0) PK_FATAL_ERROR();
-
+        assert(curr_iblock >= 0);
         if(curr_type == CodeBlockType::FOR_LOOP){
             // add a no op here to make block check work
             emit_(OP_NO_OP, BC_NOARG, BC_KEEPLINE, true);
@@ -127,7 +127,7 @@ namespace pkpy{
     }
 
     int CodeEmitContext::add_const(PyVar v){
-        PK_ASSERT(!is_type(v, VM::tp_str))
+        assert(!is_type(v, VM::tp_str));
         // non-string deduplication
         auto it = _co_consts_nonstring_dedup_map.find(v);
         if(it != _co_consts_nonstring_dedup_map.end()){
@@ -156,7 +156,7 @@ namespace pkpy{
             case NAME_GLOBAL_UNKNOWN:
                 emit_(OP_STORE_NAME, StrName(name).index, line);
                 break;
-            default: PK_FATAL_ERROR(); break;
+            default: assert(false); break;
         }
     }
 
@@ -191,7 +191,7 @@ namespace pkpy{
             case NAME_GLOBAL_UNKNOWN:
                 ctx->emit_(OP_DELETE_NAME, StrName(name).index, line);
                 break;
-            default: PK_FATAL_ERROR(); break;
+            default: assert(false); break;
         }
         return true;
     }
@@ -246,7 +246,7 @@ namespace pkpy{
             case TK("True"):    ctx->emit_(OP_LOAD_TRUE, BC_NOARG, line); break;
             case TK("False"):   ctx->emit_(OP_LOAD_FALSE, BC_NOARG, line); break;
             case TK("..."):     ctx->emit_(OP_LOAD_ELLIPSIS, BC_NOARG, line); break;
-            default: PK_FATAL_ERROR();
+            default: assert(false);
         }
     }
 
@@ -330,7 +330,7 @@ namespace pkpy{
 
     void DictItemExpr::emit_(CodeEmitContext* ctx) {
         if(is_starred()){
-            PK_ASSERT(key == nullptr);
+            assert(key == nullptr);
             value->emit_(ctx);
         }else{
             value->emit_(ctx);
@@ -647,7 +647,7 @@ namespace pkpy{
             if(!kwargs.empty()){
                 for(auto& item: kwargs){
                     if(item.second->is_starred()){
-                        PK_ASSERT(item.second->star_level() == 2)
+                        assert(item.second->star_level() == 2);
                         item.second->emit_(ctx);
                     }else{
                         // k=v
@@ -752,7 +752,7 @@ namespace pkpy{
             case TK("^"):   ctx->emit_(OP_BITWISE_XOR, BC_NOARG, line);  break;
 
             case TK("@"):   ctx->emit_(OP_BINARY_MATMUL, BC_NOARG, line);  break;
-            default: PK_FATAL_ERROR();
+            default: assert(false);
         }
 
         for(int i: jmps) ctx->patch_jump(i);

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 1 - 2
src/compiler/lexer.cpp


+ 7 - 7
src/ceval.cpp → src/interpreter/ceval.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/ceval.h"
+#include "pocketpy/interpreter/ceval.hpp"
 
 namespace pkpy{
 
@@ -224,7 +224,7 @@ __NEXT_STEP:
         TOP() = getattr(TOP(), StrName(byte.arg));
     } DISPATCH()
     case OP_LOAD_CLASS_GLOBAL:{
-        PK_ASSERT(__curr_class != nullptr);
+        assert(__curr_class != nullptr);
         StrName _name(byte.arg);
         PyVar _0 = getattr(__curr_class, _name, false);
         if(_0 != nullptr) { PUSH(_0); DISPATCH() }
@@ -284,7 +284,7 @@ __NEXT_STEP:
             }else{
                 Function& func = frame->_callable->as<Function>();
                 if(func.decl == __dynamic_func_decl){
-                    PK_DEBUG_ASSERT(func._closure != nullptr);
+                    assert(func._closure != nullptr);
                     func._closure->set(_name, _0);
                 }else{
                     vm->NameError(_name);
@@ -340,7 +340,7 @@ __NEXT_STEP:
             }else{
                 Function& func = frame->_callable->as<Function>();
                 if(func.decl == __dynamic_func_decl){
-                    PK_DEBUG_ASSERT(func._closure != nullptr);
+                    assert(func._closure != nullptr);
                     bool ok = func._closure->del(_name);
                     if(!ok) vm->NameError(_name);
                 }else{
@@ -941,7 +941,7 @@ __NEXT_STEP:
         __curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true);
     } DISPATCH()
     case OP_END_CLASS: {
-        PK_ASSERT(__curr_class != nullptr);
+        assert(__curr_class != nullptr);
         StrName _name(byte.arg);
         frame->_module->attr().set(_name, __curr_class);
         // call on_end_subclass
@@ -953,7 +953,7 @@ __NEXT_STEP:
         __curr_class = nullptr;
     } DISPATCH()
     case OP_STORE_CLASS_ATTR:{
-        PK_ASSERT(__curr_class != nullptr);
+        assert(__curr_class != nullptr);
         StrName _name(byte.arg);
         PyVar _0 = POPX();
         if(is_type(_0, tp_function)){
@@ -968,7 +968,7 @@ __NEXT_STEP:
         __curr_class = POPX().get();
     } DISPATCH()
     case OP_ADD_CLASS_ANNOTATION: {
-        PK_ASSERT(__curr_class != nullptr);
+        assert(__curr_class != nullptr);
         StrName _name(byte.arg);
         Type type = __curr_class->as<Type>();
         _all_types[type].annotated_fields.push_back(_name);

+ 1 - 1
src/cffi.cpp → src/interpreter/cffi.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/cffi.h"
+#include "pocketpy/interpreter/cffi.hpp"
 
 namespace pkpy{
 

+ 27 - 3
src/frame.cpp → src/interpreter/frame.cpp

@@ -1,4 +1,5 @@
-#include "pocketpy/frame.h"
+#include "pocketpy/objects/stackmemory.hpp"
+#include "pocketpy/interpreter/frame.hpp"
 
 namespace pkpy{
     PyVar* FastLocals::try_get_name(StrName name){
@@ -11,7 +12,7 @@ namespace pkpy{
         NameDict_ dict = std::make_shared<NameDict>();
         co->varnames_inv.apply([&](StrName name, int index){
             PyVar value = a[index];
-            if(value != PY_NULL) dict->set(name, value);
+            if(value) dict->set(name, value);
         });
         return dict;
     }
@@ -45,7 +46,7 @@ namespace pkpy{
             // pop possible stack memory slots
             if(_s->top().type == kTpStackMemoryIndex){
                 int count = _s->top().as<StackMemory>().count;
-                PK_DEBUG_ASSERT(count < 0);
+                assert(count < 0);
                 _s->_sp += count;
                 _s->_sp -= 2;   // pop header and tail
             }
@@ -99,4 +100,27 @@ namespace pkpy{
         }
     }
 
+    void CallStack::pop(){
+        assert(!empty());
+        LinkedFrame* p = _tail;
+        _tail = p->f_back;
+        p->~LinkedFrame();
+        pool128_dealloc(p);
+        --_size;
+    }
+
+    LinkedFrame* CallStack::popx(){
+        assert(!empty());
+        LinkedFrame* p = _tail;
+        _tail = p->f_back;
+        --_size;
+        p->f_back = nullptr;        // unlink
+        return p;
+    }
+
+    void CallStack::pushx(LinkedFrame* p){
+        p->f_back = _tail;
+        _tail = p;
+        ++_size;
+    }
 }   // namespace pkpy

+ 2 - 2
src/gc.cpp → src/interpreter/gc.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/gc.h"
+#include "pocketpy/interpreter/gc.hpp"
 
 namespace pkpy{
 
@@ -48,7 +48,7 @@ namespace pkpy{
     }
 
     int ManagedHeap::collect(){
-        PK_ASSERT(_gc_lock_counter == 0)
+        assert(_gc_lock_counter == 0);
         mark();
         int freed = sweep();
         return freed;

+ 1 - 1
src/iter.cpp → src/interpreter/iter.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/iter.h"
+#include "pocketpy/interpreter/iter.hpp"
 
 namespace pkpy{
 

+ 3 - 3
src/profiler.cpp → src/interpreter/profiler.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/profiler.h"
+#include "pocketpy/interpreter/profiler.hpp"
 
 namespace pkpy{
 
@@ -49,7 +49,7 @@ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line){
     _LineRecord* prev_record = top_frame_record.prev_record;
 
     int id_delta = callstack_size - top_frame_record.callstack_size;
-    PK_ASSERT(abs(id_delta) <= 1)
+    assert(abs(id_delta) <= 1);
 
     // current line is about to change
     if(prev_record->line != line){
@@ -77,7 +77,7 @@ void LineProfiler::end(){
     prev_record->time += delta;
 
     frames.pop();
-    PK_ASSERT(frames.empty());
+    assert(frames.empty());
 }
 
 Str LineProfiler::stats(){

+ 15 - 16
src/vm.cpp → src/interpreter/vm.cpp

@@ -1,4 +1,7 @@
-#include "pocketpy/vm.h"
+#include "pocketpy/interpreter/vm.hpp"
+
+#include <iostream>
+#include <cmath>
 
 static const char* OP_NAMES[] = {
     #define OPCODE(name) #name,
@@ -358,7 +361,7 @@ namespace pkpy{
             path = f_join(cpnts);
         }
 
-        PK_ASSERT(path.begin()[0] != '.' && path.end()[-1] != '.');
+        assert(path.begin()[0] != '.' && path.end()[-1] != '.');
 
         // check existing module
         StrName name(path);
@@ -388,7 +391,7 @@ namespace pkpy{
                 if(throw_err) ImportError(_S("module ", path.escape(), " not found"));
                 else return nullptr;
             }
-            PK_ASSERT(out_size >= 0)
+            assert(out_size >= 0);
             source = Str(std::string_view((char*)out, out_size));
             free(out);
         }else{
@@ -787,7 +790,7 @@ Str VM::disassemble(CodeObject_ co){
         }
 
         std::string pointer;
-        if(std::find(jumpTargets.begin(), jumpTargets.end(), i) != jumpTargets.end()){
+        if(jumpTargets.contains(i)){
             pointer = "-> ";
         }else{
             pointer = "   ";
@@ -817,7 +820,7 @@ void VM::__log_s_data(const char* title) {
     if(title) ss << title << " | ";
     std::map<PyVar*, int> sp_bases;
     callstack.apply([&](Frame& f){
-        if(f._sp_base == nullptr) PK_FATAL_ERROR();
+        assert(f._sp_base != nullptr);
         sp_bases[f._sp_base] += 1;
     });
     Frame* frame = &callstack.top();
@@ -1046,7 +1049,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
 
     // handle boundmethod, do a patch
     if(callable_t == tp_bound_method){
-        PK_DEBUG_ASSERT(p0[1] == PY_NULL)
+        assert(p0[1] == PY_NULL);
         BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable);
         callable = bm.func;      // get unbound method
         callable_t = _tp(callable);
@@ -1097,11 +1100,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
                     callstack.popx(),
                     ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals)
                 );
-#if PK_DEBUG_EXTRA_CHECK
-            default: PK_FATAL_ERROR(); break;
-#else
-            default: PK_UNREACHABLE()
-#endif
+            default: PK_UNREACHABLE();
         };
 
         // simple or normal
@@ -1138,7 +1137,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
         // [type, NULL, args..., kwargs...]
         PyVar new_f = *find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
         PyVar obj;
-        PK_DEBUG_ASSERT(new_f != nullptr && p0[1]==PY_NULL);
+        assert(new_f != nullptr && p0[1]==PY_NULL);
         if(new_f == __cached_object_new) {
             // fast path for object.__new__
             obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
@@ -1407,7 +1406,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
 }
 
 PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, NativeFuncC fset){
-    PK_ASSERT(is_type(obj, tp_type));
+    assert(is_type(obj, tp_type));
     std::string_view name_sv(name); int pos = name_sv.find(':');
     if(pos > 0) name_sv = name_sv.substr(0, pos);
     PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
@@ -1437,7 +1436,7 @@ void VM::AttributeError(PyVar obj, StrName name){
 }
 
 void VM::_error(PyVar e_obj){
-    PK_ASSERT(isinstance(e_obj, tp_exception))
+    assert(isinstance(e_obj, tp_exception));
     Exception& e = PK_OBJ_GET(Exception, e_obj);
     if(callstack.empty()){
         e.is_re = false;
@@ -1752,8 +1751,8 @@ void VM::__breakpoint(){
 
             if(is_list){
                 int max_line = frame_0->co->src->line_starts.size() + 1;
-                start = std::max(1, lineno-5);
-                end = std::min(max_line, lineno+5);
+                start = (std::max)(1, lineno-5);
+                end = (std::min)(max_line, lineno+5);
             }else{
                 start = frame_0->co->start_line;
                 end = frame_0->co->end_line;

+ 6 - 5
src/array2d.cpp → src/modules/array2d.cpp

@@ -1,4 +1,5 @@
-#include "pocketpy/array2d.h"
+#include "pocketpy/modules/array2d.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
 
 namespace pkpy{
 
@@ -340,10 +341,10 @@ struct Array2d{
             for(int j = 0; j < self.n_rows; j++){
                 for(int i = 0; i < self.n_cols; i++){
                     if(vm->py_eq(self._get(i, j), value)){
-                        left = std::min(left, i);
-                        top = std::min(top, j);
-                        right = std::max(right, i);
-                        bottom = std::max(bottom, j);
+                        left = (std::min)(left, i);
+                        top = (std::min)(top, j);
+                        right = (std::max)(right, i);
+                        bottom = (std::max)(bottom, j);
                     }
                 }
             }

+ 2 - 1
src/base64.cpp → src/modules/base64.cpp

@@ -1,4 +1,5 @@
-#include "pocketpy/base64.h"
+#include "pocketpy/modules/base64.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
 
 namespace pkpy{
 

+ 2 - 1
src/csv.cpp → src/modules/csv.cpp

@@ -1,4 +1,5 @@
-#include "pocketpy/csv.h"
+#include "pocketpy/modules/csv.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
 
 namespace pkpy{
 

+ 2 - 1
src/dataclasses.cpp → src/modules/dataclasses.cpp

@@ -1,4 +1,5 @@
-#include "pocketpy/dataclasses.h"
+#include "pocketpy/modules/dataclasses.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
 
 namespace pkpy{
 

+ 4 - 1
src/easing.cpp → src/modules/easing.cpp

@@ -1,4 +1,7 @@
-#include "pocketpy/easing.h"
+#include "pocketpy/modules/easing.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
+
+#include <cmath>
 
 namespace pkpy{
 // https://easings.net/

+ 3 - 2
src/io.cpp → src/modules/io.cpp

@@ -1,4 +1,5 @@
-#include "pocketpy/io.h"
+#include "pocketpy/modules/io.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
 
 #if PK_ENABLE_OS
 #include <filesystem>
@@ -75,7 +76,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
         }
         unsigned char* buffer = (unsigned char*)malloc(buffer_size);
         i64 actual_size = io_fread(buffer, 1, buffer_size, io.fp);
-        PK_ASSERT(actual_size <= buffer_size);
+        assert(actual_size <= buffer_size);
         // in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
         Bytes b(buffer, actual_size);
         if(io.is_text){

+ 3 - 2
src/linalg.cpp → src/modules/linalg.cpp

@@ -1,4 +1,5 @@
-#include "pocketpy/linalg.h"
+#include "pocketpy/modules/linalg.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
 
 namespace pkpy{
 
@@ -76,7 +77,7 @@ namespace pkpy{
 static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
 {
     // Based on Game Programming Gems 4 Chapter 1.10
-    smoothTime = std::max(0.0001F, smoothTime);
+    smoothTime = (std::max)(0.0001F, smoothTime);
     float omega = 2.0F / smoothTime;
 
     float x = omega * deltaTime;

+ 9 - 1
src/modules.cpp → src/modules/modules.cpp

@@ -1,4 +1,12 @@
-#include "pocketpy/modules.h"
+#include "pocketpy/modules/modules.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
+#include "pocketpy/common/version.hpp"
+#include "pocketpy/export.h"
+
+#include "pocketpy/common/_generated.hpp"
+
+#include <chrono>
+#include <cmath>
 
 namespace pkpy{
 

+ 4 - 1
src/random.cpp → src/modules/random.cpp

@@ -1,4 +1,7 @@
-#include "pocketpy/random.h"
+#include "pocketpy/modules/random.hpp"
+#include "pocketpy/interpreter/bindings.hpp"
+
+#include <chrono>
 
 /* https://github.com/clibs/mt19937ar
 

+ 0 - 4
src/namedict.cpp

@@ -1,4 +0,0 @@
-#include "pocketpy/namedict.h"
-
-namespace pkpy{
-}   // namespace pkpy

+ 6 - 0
src/objects/builtins.cpp

@@ -0,0 +1,6 @@
+#include "pocketpy/objects/builtins.hpp"
+
+namespace pkpy{
+    PyVar const PY_OP_CALL(Type(), new PyObject(Type()));
+    PyVar const PY_OP_YIELD(Type(), new PyObject(Type()));
+}   // namespace pkpy

+ 1 - 4
src/codeobject.cpp → src/objects/codeobject.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/codeobject.h"
+#include "pocketpy/objects/codeobject.hpp"
 
 namespace pkpy{
 
@@ -6,7 +6,4 @@ namespace pkpy{
         src(src), name(name), nlocals(0), start_line(-1), end_line(-1) {
             blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0));
         }
-
-    PyVar const PY_OP_CALL(Type(), new PyObject(Type()));
-    PyVar const PY_OP_YIELD(Type(), new PyObject(Type()));
 }   // namespace pkpy

+ 3 - 3
src/dict.cpp → src/objects/dict.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/dict.h"
+#include "pocketpy/objects/dict.hpp"
 
 namespace pkpy{
 
@@ -140,7 +140,7 @@ namespace pkpy{
             t[j++] = _items[i].first;
             i = _items[i].next;
         }
-        PK_ASSERT(j == _size);
+        assert(j == _size);
         return t;
     }
 
@@ -152,7 +152,7 @@ namespace pkpy{
             t[j++] = _items[i].second;
             i = _items[i].next;
         }
-        PK_ASSERT(j == _size);
+        assert(j == _size);
         return t;
     }
 

+ 20 - 0
src/objects/error.cpp

@@ -0,0 +1,20 @@
+#include "pocketpy/objects/error.hpp"
+
+namespace pkpy{
+    Str Exception::summary() const {
+        SStream ss;
+        if(is_re) ss << "Traceback (most recent call last):\n";
+        // while(!st.empty()) {
+        //     ss << st.top().snapshot() << '\n';
+        //     st.pop();
+        // }
+        const auto& container = stacktrace.container();
+        for(int i=container.size()-1; i>=0; i--){
+            ss << container[i].snapshot() << '\n';
+        }
+        if (!msg.empty()) ss << type.sv() << ": " << msg;
+        else ss << type.sv();
+        return ss.str();
+    }
+
+}   // namespace pkpy

+ 1 - 1
src/obj.cpp → src/objects/object.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/obj.h"
+#include "pocketpy/objects/object.hpp"
 
 namespace pkpy{
     PyVar::PyVar(PyObject* p): PyVar(p->type, p) {}

+ 1 - 19
src/error.cpp → src/objects/sourcedata.cpp

@@ -1,7 +1,6 @@
-#include "pocketpy/error.h"
+#include "pocketpy/objects/sourcedata.hpp"
 
 namespace pkpy{
-
     SourceData::SourceData(std::string_view source, const Str& filename, CompileMode mode): filename(filename), mode(mode) {
         int index = 0;
         // Skip utf8 BOM if there is any.
@@ -64,21 +63,4 @@ namespace pkpy{
         }
         return ss.str();
     }
-
-    Str Exception::summary() const {
-        SStream ss;
-        if(is_re) ss << "Traceback (most recent call last):\n";
-        // while(!st.empty()) {
-        //     ss << st.top().snapshot() << '\n';
-        //     st.pop();
-        // }
-        const auto& container = stacktrace.container();
-        for(int i=container.size()-1; i>=0; i--){
-            ss << container[i].snapshot() << '\n';
-        }
-        if (!msg.empty()) ss << type.sv() << ": " << msg;
-        else ss << type.sv();
-        return ss.str();
-    }
-
 }   // namespace pkpy

+ 1 - 1
src/tuplelist.cpp → src/objects/tuplelist.cpp

@@ -1,4 +1,4 @@
-#include "pocketpy/tuplelist.h"
+#include "pocketpy/objects/tuplelist.hpp"
 
 namespace pkpy {
 

+ 17 - 2
src/pocketpy.cpp

@@ -1,4 +1,19 @@
-#include "pocketpy/pocketpy.h"
+#include "pocketpy/pocketpy.hpp"
+
+#include "pocketpy/common/_generated.hpp"
+
+#include "pocketpy/modules/array2d.hpp"
+#include "pocketpy/modules/base64.hpp"
+#include "pocketpy/modules/csv.hpp"
+#include "pocketpy/modules/dataclasses.hpp"
+#include "pocketpy/modules/easing.hpp"
+#include "pocketpy/modules/io.hpp"
+#include "pocketpy/modules/linalg.hpp"
+#include "pocketpy/modules/random.hpp"
+#include "pocketpy/modules/modules.hpp"
+
+#include <iostream>
+#include <algorithm>
 
 namespace pkpy{
 
@@ -332,7 +347,7 @@ void __init_builtins(VM* _vm) {
 
     // tp_object
     _vm->bind__repr__(VM::tp_object, [](VM* vm, PyVar obj) -> Str{
-        if(is_tagged(obj)) PK_FATAL_ERROR();
+        assert(!is_tagged(obj));
         SStream ss;
         ss << "<" << _type_name(vm, vm->_tp(obj)) << " object at ";
         ss.write_hex(obj.get());

+ 5 - 3
src/pocketpy_c.cpp

@@ -3,6 +3,8 @@
 #include "pocketpy.h"
 #include "pocketpy_c.h"
 
+#include <iostream>
+
 using namespace pkpy;
 
 #define PK_ASSERT_N_EXTRA_ELEMENTS(n) \
@@ -21,7 +23,7 @@ static int count_extra_elements(VM* vm, int n){
     if(vm->callstack.empty()){
         return vm->s_data.size();
     }
-    PK_ASSERT(!vm->__c.s_view.empty());
+    assert(!vm->__c.s_view.empty());
     return vm->s_data._sp - vm->__c.s_view.top().end();
 }
 
@@ -31,7 +33,7 @@ static PyVar stack_item(VM* vm, int index){
     if(vm->callstack.empty()){
         begin = vm->s_data.begin();
     }else{
-        PK_ASSERT(!vm->__c.s_view.empty());
+        assert(!vm->__c.s_view.empty());
         begin = vm->__c.s_view.top().begin();
     }
     int size = end - begin;
@@ -347,7 +349,7 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
         vm->_error(e_obj);
         return nullptr;
     }
-    PK_ASSERT(retc == vm->s_data._sp-curr_sp);
+    assert(retc == vm->s_data._sp-curr_sp);
     if(retc == 0) return vm->None;
     if (retc == 1) return vm->s_data.popx();
     ArgsView ret_view(curr_sp, vm->s_data._sp);

+ 4 - 1
src/repl.cpp → src/tools/repl.cpp

@@ -1,4 +1,7 @@
-#include "pocketpy/repl.h"
+#include "pocketpy/tools/repl.hpp"
+
+#include "pocketpy/common/version.hpp"
+#include "pocketpy/export.h"
 
 namespace pkpy {
     REPL::REPL(VM* vm) : vm(vm){

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно