blueloveTH 1 год назад
Родитель
Сommit
aea3b4758f

+ 3 - 0
include/pocketpy/common/utils.h

@@ -1,5 +1,8 @@
 #pragma once
 
+#include "stdio.h"
+#include "stdlib.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 52 - 0
include/pocketpy/compiler/expr.h

@@ -0,0 +1,52 @@
+// #pragma once
+
+// #include <stdbool.h>
+// #include "pocketpy/common/memorypool.h"
+// #include "pocketpy/compiler/lexer.h"
+
+// #ifdef __cplusplus
+// extern "C" {
+// #endif
+
+// struct pk_Expr;
+// struct pk_CodeEmitContext;
+
+// struct pk_ExprVt{
+//     void (*dtor)(pk_Expr*);
+//     /* reflections */
+//     bool (*is_literal)(const pk_Expr*);
+//     bool (*is_json_object)(const pk_Expr*);
+//     bool (*is_attrib)(const pk_Expr*);
+//     bool (*is_subscr)(const pk_Expr*);
+//     bool (*is_compare)(const pk_Expr*);
+//     int (*star_level)(const pk_Expr*);
+//     bool (*is_tuple)(const pk_Expr*);
+//     bool (*is_name)(const pk_Expr*);
+//     /* emit */
+//     void (*emit_)(pk_Expr*, pk_CodeEmitContext*);
+//     bool (*emit_del)(pk_Expr*, pk_CodeEmitContext*);
+//     bool (*emit_store)(pk_Expr*, pk_CodeEmitContext*);
+//     void (*emit_inplace)(pk_Expr*, pk_CodeEmitContext*);
+//     bool (*emit_store_inplace)(pk_Expr*, pk_CodeEmitContext*);
+// };
+
+// typedef struct pk_Expr{
+//     pk_ExprVt* vt;
+//     int line;
+// } pk_Expr;
+
+// void pk_ExprVt__ctor(pk_ExprVt* vt);
+// void pk_Expr__emit_(pk_Expr* self, pk_CodeEmitContext* ctx);
+// bool pk_Expr__emit_del(pk_Expr* self, pk_CodeEmitContext* ctx);
+// bool pk_Expr__emit_store(pk_Expr* self, pk_CodeEmitContext* ctx);
+// void pk_Expr__emit_inplace(pk_Expr* self, pk_CodeEmitContext* ctx);
+// bool pk_Expr__emit_store_inplace(pk_Expr* self, pk_CodeEmitContext* ctx);
+// void pk_Expr__delete(pk_Expr* self);
+
+// typedef struct pk_CodeEmitContext{
+
+// } pk_CodeEmitContext;
+
+// #ifdef __cplusplus
+// }
+// #endif

+ 0 - 71
include/pocketpy/compiler/expr.hpp

@@ -10,48 +10,7 @@ struct Expr;
 
 typedef small_vector<Expr*, 4> Expr_vector;
 
-static bool default_false(const Expr*) { return false; }
-static int default_zero(const Expr*) { return 0; }
-static void default_dtor(Expr*) {}
-
-struct ExprVt{
-    void (*dtor)(Expr*);
-    /* reflections */
-    bool (*is_literal)(const Expr*);
-    bool (*is_json_object)(const Expr*);
-    bool (*is_attrib)(const Expr*);
-    bool (*is_subscr)(const Expr*);
-    bool (*is_compare)(const Expr*);
-    int (*star_level)(const Expr*);
-    bool (*is_tuple)(const Expr*);
-    bool (*is_name)(const Expr*);
-    /* emit */
-    void (*emit_)(Expr*, CodeEmitContext*);
-    bool (*emit_del)(Expr*, CodeEmitContext*);
-    bool (*emit_store)(Expr*, CodeEmitContext*);
-    void (*emit_inplace)(Expr*, CodeEmitContext*);
-    bool (*emit_store_inplace)(Expr*, CodeEmitContext*);
-};
-
-void ExprVt__ctor(ExprVt* vt){
-    vt->dtor = default_dtor;
-    vt->is_literal = default_false;
-    vt->is_json_object = default_false;
-    vt->is_attrib = default_false;
-    vt->is_subscr = default_false;
-    vt->is_compare = default_false;
-    vt->star_level = default_zero;
-    vt->is_tuple = default_false;
-    vt->is_name = default_false;
-    vt->emit_ = NULL;   // must be set
-    vt->emit_del = NULL;
-    vt->emit_store = NULL;
-    vt->emit_inplace = NULL;
-    vt->emit_store_inplace = NULL;
-}
-
 struct Expr {
-    ExprVt* vt;
     int line = 0;
     virtual ~Expr() = default;
     virtual void emit_(CodeEmitContext* ctx) = 0;
@@ -80,36 +39,6 @@ struct Expr {
     [[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
 };
 
-void pk_Expr__emit_(Expr* self, CodeEmitContext* ctx){
-    assert(self->vt->emit_);
-    self->vt->emit_(self, ctx);
-}
-
-bool pk_Expr__emit_del(Expr* self, CodeEmitContext* ctx){
-    if(!self->vt->emit_del) return false;
-    return self->vt->emit_del(self, ctx);
-}
-
-bool pk_Expr__emit_store(Expr* self, CodeEmitContext* ctx){
-    if(!self->vt->emit_store) return false;
-    return self->vt->emit_store(self, ctx);
-}
-
-void pk_Expr__emit_inplace(Expr* self, CodeEmitContext* ctx){
-    if(!self->vt->emit_inplace){
-        pk_Expr__emit_(self, ctx);
-        return;
-    }
-    self->vt->emit_inplace(self, ctx);
-}
-
-bool pk_Expr__emit_store_inplace(Expr* self, CodeEmitContext* ctx){
-    if(!self->vt->emit_store_inplace){
-        return pk_Expr__emit_store(self, ctx);
-    }
-    return self->vt->emit_store_inplace(self, ctx);
-}
-
 inline void delete_expr(Expr* p) noexcept{
     if(!p) return;
     p->~Expr();

+ 1 - 1
include/pocketpy/interpreter/bindings.hpp

@@ -175,7 +175,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
             return obj;                                                                                                \
         },                                                                                                             \
         {},                                                                                                            \
-        BindType::STATICMETHOD);                                                                                       \
+        BindType_STATICMETHOD);                                                                                       \
     vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) {                                                     \
         wT& self = _CAST(wT&, args[0]);                                                                                \
         return vm->new_user_object<Struct>(&self, sizeof(wT));                                                         \

+ 8 - 8
include/pocketpy/interpreter/vm.hpp

@@ -362,25 +362,25 @@ public:
 #endif
 
 #if PK_REGION("General Bindings")
-    PyObject* bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT);
-    PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT){
+    PyObject* bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType_FUNCTION);
+    PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType_FUNCTION){
         return bind_func(_t(type), name, argc, fn, std::move(userdata), bt);
     }
     PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr);
     template<typename T, typename F, bool ReadOnly=false>
     PyObject* bind_field(PyObject*, const char*, F T::*);
 
-    PyObject* bind(PyObject*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT);
+    PyObject* bind(PyObject*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType_FUNCTION);
     template<typename Ret, typename... Params>
-    PyObject* bind(PyObject*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT);
+    PyObject* bind(PyObject*, const char*, Ret(*)(Params...), BindType bt=BindType_FUNCTION);
     template<typename Ret, typename T, typename... Params>
-    PyObject* bind(PyObject*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT);
+    PyObject* bind(PyObject*, const char*, Ret(T::*)(Params...), BindType bt=BindType_FUNCTION);
 
-    PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT);
+    PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType_FUNCTION);
     template<typename Ret, typename... Params>
-    PyObject* bind(PyObject*, const char*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT);
+    PyObject* bind(PyObject*, const char*, const char*, Ret(*)(Params...), BindType bt=BindType_FUNCTION);
     template<typename Ret, typename T, typename... Params>
-    PyObject* bind(PyObject*, const char*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT);
+    PyObject* bind(PyObject*, const char*, const char*, Ret(T::*)(Params...), BindType bt=BindType_FUNCTION);
 #endif
 
 #if PK_REGION("Error Reporting Methods")

+ 57 - 0
include/pocketpy/objects/codeobject.h

@@ -0,0 +1,57 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BC_NOARG        0
+#define BC_KEEPLINE     -1
+
+typedef enum BindType {
+    BindType_FUNCTION,
+    BindType_STATICMETHOD,
+    BindType_CLASSMETHOD,
+} BindType;
+
+typedef enum FuncType {
+    FuncType_UNSET,
+    FuncType_NORMAL,
+    FuncType_SIMPLE,
+    FuncType_EMPTY,
+    FuncType_GENERATOR,
+} FuncType;
+
+typedef enum NameScope {
+    NAME_LOCAL,
+    NAME_GLOBAL,
+    NAME_GLOBAL_UNKNOWN
+} NameScope;
+
+typedef enum CodeBlockType {
+    NO_BLOCK,
+    FOR_LOOP,
+    WHILE_LOOP,
+    CONTEXT_MANAGER,
+    TRY_EXCEPT,
+} CodeBlockType;
+
+typedef enum Opcode {
+    #define OPCODE(name) OP_##name,
+    #include "pocketpy/xmacros/opcodes.h"
+    #undef OPCODE
+} Opcode;
+
+typedef struct Bytecode {
+    uint8_t op;
+    uint16_t arg;
+} Bytecode;
+
+void Bytecode__set_signed_arg(Bytecode* self, int arg);
+bool Bytecode__is_forward_jump(const Bytecode* self);
+
+#ifdef __cplusplus
+}
+#endif

+ 2 - 47
include/pocketpy/objects/codeobject.hpp

@@ -6,49 +6,12 @@
 #include "pocketpy/objects/namedict.hpp"
 #include "pocketpy/objects/sourcedata.h"
 #include "pocketpy/common/smallmap.h"
+#include "pocketpy/objects/codeobject.h"
 
 namespace pkpy {
 
 typedef PyVar (*NativeFuncC)(VM*, ArgsView);
 
-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 "pocketpy/xmacros/opcodes.h"
-#undef OPCODE
-};
-
-struct Bytecode {
-    uint8_t op;
-    uint16_t arg;
-
-    void set_signed_arg(int arg) {
-        assert(arg >= INT16_MIN && arg <= INT16_MAX);
-        this->arg = (int16_t)arg;
-    }
-
-    bool is_forward_jump() const { return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK; }
-};
-
-enum class CodeBlockType {
-    NO_BLOCK,
-    FOR_LOOP,
-    WHILE_LOOP,
-    CONTEXT_MANAGER,
-    TRY_EXCEPT,
-};
-
-const inline uint8_t BC_NOARG = 0;
-const inline int BC_KEEPLINE = -1;
-
 struct CodeBlock {
     CodeBlockType type;
     int parent;  // parent index in blocks
@@ -116,14 +79,6 @@ struct CodeObject {
     }
 };
 
-enum class FuncType {
-    UNSET,
-    NORMAL,
-    SIMPLE,
-    EMPTY,
-    GENERATOR,
-};
-
 struct FuncDecl {
     struct KwArg {
         int index;    // index in co->varnames
@@ -142,7 +97,7 @@ struct FuncDecl {
 
     const char* docstring;  // docstring of this function (weak ref)
 
-    FuncType type = FuncType::UNSET;
+    FuncType type = FuncType_UNSET;
     c11_smallmap_n2i kw_to_index;
 
     void add_kwarg(int index, StrName key, PyVar value) {

+ 10 - 10
src/compiler/compiler.cpp

@@ -60,9 +60,9 @@ Error* Compiler::pop_context() noexcept{
     for(int i = 0; i < codes.size(); i++) {
         Bytecode& bc = codes[i];
         if(bc.op == OP_LOOP_CONTINUE) {
-            bc.set_signed_arg(ctx()->co->blocks[bc.arg].start - i);
+            Bytecode__set_signed_arg(&bc, ctx()->co->blocks[bc.arg].start - i);
         } else if(bc.op == OP_LOOP_BREAK) {
-            bc.set_signed_arg(ctx()->co->blocks[bc.arg].get_break_end() - i);
+            Bytecode__set_signed_arg(&bc, ctx()->co->blocks[bc.arg].get_break_end() - i);
         }
     }
     // pre-compute func->is_simple
@@ -71,7 +71,7 @@ Error* Compiler::pop_context() noexcept{
         // check generator
         for(Bytecode bc: func->code->codes) {
             if(bc.op == OP_YIELD_VALUE || bc.op == OP_FOR_ITER_YIELD_VALUE) {
-                func->type = FuncType::GENERATOR;
+                func->type = FuncType_GENERATOR;
                 for(Bytecode bc: func->code->codes) {
                     if(bc.op == OP_RETURN_VALUE && bc.arg == BC_NOARG) {
                         return SyntaxError("'return' with argument inside generator function");
@@ -80,26 +80,26 @@ Error* Compiler::pop_context() noexcept{
                 break;
             }
         }
-        if(func->type == FuncType::UNSET) {
+        if(func->type == FuncType_UNSET) {
             bool is_simple = true;
             if(func->kwargs.size() > 0) is_simple = false;
             if(func->starred_arg >= 0) is_simple = false;
             if(func->starred_kwarg >= 0) is_simple = false;
 
             if(is_simple) {
-                func->type = FuncType::SIMPLE;
+                func->type = FuncType_SIMPLE;
 
                 bool is_empty = false;
                 if(func->code->codes.size() == 1) {
                     Bytecode bc = func->code->codes[0];
                     if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; }
                 }
-                if(is_empty) func->type = FuncType::EMPTY;
+                if(is_empty) func->type = FuncType_EMPTY;
             } else
-                func->type = FuncType::NORMAL;
+                func->type = FuncType_NORMAL;
         }
 
-        assert(func->type != FuncType::UNSET);
+        assert(func->type != FuncType_UNSET);
     }
     contexts.back().s_clean();
     contexts.pop_back();
@@ -822,7 +822,7 @@ Error* Compiler::compile_try_except() noexcept{
         i64 target = ctx()->co->codes.size() + 2;
         ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
         int i = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
-        ctx()->co->codes[i].set_signed_arg(finally_entry - i);
+        Bytecode__set_signed_arg(&ctx()->co->codes[i], finally_entry - i);
     }
     ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
 
@@ -833,7 +833,7 @@ Error* Compiler::compile_try_except() noexcept{
         i64 target = ctx()->co->codes.size() + 2;
         ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
         int i = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
-        ctx()->co->codes[i].set_signed_arg(finally_entry - i);
+        Bytecode__set_signed_arg(&ctx()->co->codes[i], finally_entry - i);
     }
     return NULL;
 }

+ 59 - 0
src/compiler/expr.c

@@ -0,0 +1,59 @@
+// #include "pocketpy/compiler/expr.h"
+// #include "pocketpy/common/memorypool.h"
+
+// static bool default_false(const pk_Expr*) { return false; }
+// static int default_zero(const pk_Expr*) { return 0; }
+// static void default_dtor(pk_Expr*) {}
+
+// void pk_ExprVt__ctor(pk_ExprVt* vt){
+//     vt->dtor = default_dtor;
+//     vt->is_literal = default_false;
+//     vt->is_json_object = default_false;
+//     vt->is_attrib = default_false;
+//     vt->is_subscr = default_false;
+//     vt->is_compare = default_false;
+//     vt->star_level = default_zero;
+//     vt->is_tuple = default_false;
+//     vt->is_name = default_false;
+//     vt->emit_ = NULL;   // must be set
+//     vt->emit_del = NULL;
+//     vt->emit_store = NULL;
+//     vt->emit_inplace = NULL;
+//     vt->emit_store_inplace = NULL;
+// }
+
+// void pk_Expr__emit_(pk_Expr* self, pk_CodeEmitContext* ctx){
+//     assert(self->vt->emit_);
+//     self->vt->emit_(self, ctx);
+// }
+
+// bool pk_Expr__emit_del(pk_Expr* self, pk_CodeEmitContext* ctx){
+//     if(!self->vt->emit_del) return false;
+//     return self->vt->emit_del(self, ctx);
+// }
+
+// bool pk_Expr__emit_store(pk_Expr* self, pk_CodeEmitContext* ctx){
+//     if(!self->vt->emit_store) return false;
+//     return self->vt->emit_store(self, ctx);
+// }
+
+// void pk_Expr__emit_inplace(pk_Expr* self, pk_CodeEmitContext* ctx){
+//     if(!self->vt->emit_inplace){
+//         pk_Expr__emit_(self, ctx);
+//         return;
+//     }
+//     self->vt->emit_inplace(self, ctx);
+// }
+
+// bool pk_Expr__emit_store_inplace(pk_Expr* self, pk_CodeEmitContext* ctx){
+//     if(!self->vt->emit_store_inplace){
+//         return pk_Expr__emit_store(self, ctx);
+//     }
+//     return self->vt->emit_store_inplace(self, ctx);
+// }
+
+// void pk_Expr__delete(pk_Expr* self){
+//     if(!self) return;
+//     self->vt->dtor(self);
+//     PoolExpr_dealloc(self);
+// }

+ 1 - 1
src/compiler/expr.cpp

@@ -101,7 +101,7 @@ int CodeEmitContext::emit_int(i64 value, int line) noexcept{
 
 void CodeEmitContext::patch_jump(int index) noexcept{
     int target = co->codes.size();
-    co->codes[index].set_signed_arg(target - index);
+    Bytecode__set_signed_arg(&co->codes[index], target - index);
 }
 
 bool CodeEmitContext::add_label(StrName name) noexcept{

+ 1 - 1
src/interpreter/cffi.cpp

@@ -84,7 +84,7 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
             return vm->new_user_object<Struct>(std::move(buffer));
         },
         {},
-        BindType::STATICMETHOD);
+        BindType_STATICMETHOD);
 
     vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) {
         Struct& self = _CAST(Struct&, obj);

+ 14 - 12
src/interpreter/vm.cpp

@@ -738,7 +738,7 @@ PyObject* VM::new_module(Str name, Str package) {
 
 static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject* co) {
     SStream ss;
-    if(byte.is_forward_jump()) {
+    if(Bytecode__is_forward_jump(&byte)){
         std::string argStr = std::to_string((int16_t)byte.arg);
         ss << (i64)(int16_t)byte.arg;
         ss << " (to " << (i64)((int16_t)byte.arg + i) << ")";
@@ -784,7 +784,9 @@ Str VM::disassemble(CodeObject_ co) {
     vector<int> jumpTargets;
     for(int i = 0; i < co->codes.size(); i++) {
         Bytecode byte = co->codes[i];
-        if(byte.is_forward_jump()) { jumpTargets.push_back((int16_t)byte.arg + i); }
+        if(Bytecode__is_forward_jump(&byte)) {
+            jumpTargets.push_back((int16_t)byte.arg + i);
+        }
     }
     SStream ss;
     int prev_line = -1;
@@ -1070,14 +1072,14 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
         const CodeObject* co = fn.decl->code.get();
 
         switch(fn.decl->type) {
-            case FuncType::NORMAL:
+            case FuncType_NORMAL:
                 __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
                 // copy buffer back to stack
                 s_data.reset(_base + co->nlocals);
                 for(int j = 0; j < co->nlocals; j++)
                     _base[j] = __vectorcall_buffer[j];
                 break;
-            case FuncType::SIMPLE:
+            case FuncType_SIMPLE:
                 if(args.size() != fn.decl->args.size())
                     TypeError(_S(co->name,
                                  "() takes ",
@@ -1092,7 +1094,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
                 // initialize local variables to PY_NULL
                 std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
                 break;
-            case FuncType::EMPTY:
+            case FuncType_EMPTY:
                 if(args.size() != fn.decl->args.size())
                     TypeError(_S(co->name,
                                  "() takes ",
@@ -1103,7 +1105,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
                 if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
                 s_data.reset(p0);
                 return None;
-            case FuncType::GENERATOR:
+            case FuncType_GENERATOR:
                 __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
                 s_data.reset(p0);
                 callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
@@ -1360,9 +1362,9 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
 PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata, BindType bt) {
     PyObject* nf = new_object<NativeFunc>(tp_native_func, fn, argc, std::move(userdata)).get();
     switch(bt) {
-        case BindType::DEFAULT: break;
-        case BindType::STATICMETHOD: nf = new_object<StaticMethod>(tp_staticmethod, nf).get(); break;
-        case BindType::CLASSMETHOD: nf = new_object<ClassMethod>(tp_classmethod, nf).get(); break;
+        case BindType_FUNCTION: break;
+        case BindType_STATICMETHOD: nf = new_object<StaticMethod>(tp_staticmethod, nf).get(); break;
+        case BindType_CLASSMETHOD: nf = new_object<ClassMethod>(tp_classmethod, nf).get(); break;
     }
     if(obj != nullptr) obj->attr().set(name, nf);
     return nf;
@@ -1385,9 +1387,9 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
     PyObject* f_obj = new_object<NativeFunc>(tp_native_func, fn, decl, std::move(userdata)).get();
 
     switch(bt) {
-        case BindType::STATICMETHOD: f_obj = new_object<StaticMethod>(tp_staticmethod, f_obj).get(); break;
-        case BindType::CLASSMETHOD: f_obj = new_object<ClassMethod>(tp_classmethod, f_obj).get(); break;
-        case BindType::DEFAULT: break;
+        case BindType_STATICMETHOD: f_obj = new_object<StaticMethod>(tp_staticmethod, f_obj).get(); break;
+        case BindType_CLASSMETHOD: f_obj = new_object<ClassMethod>(tp_classmethod, f_obj).get(); break;
+        case BindType_FUNCTION: break;
     }
     if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
     return f_obj;

+ 6 - 6
src/modules/linalg.cpp

@@ -152,7 +152,7 @@ void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
             return VAR(Tuple(VAR(ret), VAR(current_velocity_)));
         },
         {},
-        BindType::STATICMETHOD);
+        BindType_STATICMETHOD);
 
     // @staticmethod
     vm->bind(
@@ -168,7 +168,7 @@ void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
             return VAR(val);
         },
         {},
-        BindType::STATICMETHOD);
+        BindType_STATICMETHOD);
 
     vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
         Vec2 self = _CAST(Vec2, obj);
@@ -452,7 +452,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
             return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
         },
         {},
-        BindType::STATICMETHOD);
+        BindType_STATICMETHOD);
 
     // @staticmethod
     vm->bind_func(
@@ -463,7 +463,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
             return vm->new_user_object<Mat3x3>(Mat3x3::ones());
         },
         {},
-        BindType::STATICMETHOD);
+        BindType_STATICMETHOD);
 
     // @staticmethod
     vm->bind_func(
@@ -474,7 +474,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
             return vm->new_user_object<Mat3x3>(Mat3x3::identity());
         },
         {},
-        BindType::STATICMETHOD);
+        BindType_STATICMETHOD);
 
     /*************** affine transformations ***************/
     // @staticmethod
@@ -488,7 +488,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
             return vm->new_user_object<Mat3x3>(Mat3x3::trs(t, r, s));
         },
         {},
-        BindType::STATICMETHOD);
+        BindType_STATICMETHOD);
 
     vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args) {
         Mat3x3& self = _CAST(Mat3x3&, args[0]);

+ 13 - 0
src/objects/codeobject.c

@@ -0,0 +1,13 @@
+#include "pocketpy/objects/codeobject.h"
+#include "pocketpy/common/utils.h"
+
+void Bytecode__set_signed_arg(Bytecode* self, int arg) {
+    if(arg < INT16_MIN || arg > INT16_MAX) {
+        PK_FATAL_ERROR("set_signed_arg: %d is out of range", arg);
+    }
+    self->arg = (int16_t)arg;
+}
+
+bool Bytecode__is_forward_jump(const Bytecode* self) {
+    return self->op >= OP_JUMP_FORWARD && self->op <= OP_LOOP_BREAK;
+}