mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-22 12:30:19 +00:00
update gc
This commit is contained in:
parent
6714a3f784
commit
0be3e7ab6c
@ -266,7 +266,7 @@ struct Pointer{
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T& ref() noexcept { return *reinterpret_cast<T*>(ptr); }
|
T& ref() noexcept { return *reinterpret_cast<T*>(ptr); }
|
||||||
|
|
||||||
PyObject* get(VM* vm){
|
PyObject* get(VM* vm){
|
||||||
if(level > 1) return VAR_T(Pointer, ctype, level-1, ref<char*>());
|
if(level > 1) return VAR_T(Pointer, ctype, level-1, ref<char*>());
|
||||||
|
@ -62,10 +62,10 @@ struct Type {
|
|||||||
int index;
|
int index;
|
||||||
Type(): index(-1) {}
|
Type(): index(-1) {}
|
||||||
Type(int index): index(index) {}
|
Type(int index): index(index) {}
|
||||||
inline bool operator==(Type other) const noexcept {
|
bool operator==(Type other) const noexcept {
|
||||||
return this->index == other.index;
|
return this->index == other.index;
|
||||||
}
|
}
|
||||||
inline bool operator!=(Type other) const noexcept {
|
bool operator!=(Type other) const noexcept {
|
||||||
return this->index != other.index;
|
return this->index != other.index;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -305,7 +305,7 @@ private:
|
|||||||
parser->set_next_token(TK("@eof"));
|
parser->set_next_token(TK("@eof"));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline TokenIndex peek() {
|
TokenIndex peek() {
|
||||||
return parser->curr.type;
|
return parser->curr.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
src/frame.h
32
src/frame.h
@ -18,10 +18,10 @@ struct Frame {
|
|||||||
const uint64_t id;
|
const uint64_t id;
|
||||||
std::vector<std::pair<int, std::vector<PyObject*>>> s_try_block;
|
std::vector<std::pair<int, std::vector<PyObject*>>> s_try_block;
|
||||||
|
|
||||||
inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
|
NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
|
||||||
inline NameDict& f_globals() noexcept { return _module->attr(); }
|
NameDict& f_globals() noexcept { return _module->attr(); }
|
||||||
|
|
||||||
inline PyObject** f_closure_try_get(StrName name) noexcept {
|
PyObject** f_closure_try_get(StrName name) noexcept {
|
||||||
if(_closure == nullptr) return nullptr;
|
if(_closure == nullptr) return nullptr;
|
||||||
return _closure->try_get(name);
|
return _closure->try_get(name);
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ struct Frame {
|
|||||||
const NameDict_& _closure=nullptr)
|
const NameDict_& _closure=nullptr)
|
||||||
: co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) { }
|
: co(co.get()), _module(_module), _locals(_locals), _closure(_closure), id(kFrameGlobalId++) { }
|
||||||
|
|
||||||
inline const Bytecode& next_bytecode() {
|
const Bytecode& next_bytecode() {
|
||||||
_ip = _next_ip++;
|
_ip = _next_ip++;
|
||||||
return co->codes[_ip];
|
return co->codes[_ip];
|
||||||
}
|
}
|
||||||
@ -53,11 +53,11 @@ struct Frame {
|
|||||||
// return ss.str();
|
// return ss.str();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
inline bool has_next_bytecode() const {
|
bool has_next_bytecode() const {
|
||||||
return _next_ip < co->codes.size();
|
return _next_ip < co->codes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* pop(){
|
PyObject* pop(){
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
#endif
|
#endif
|
||||||
@ -66,7 +66,7 @@ struct Frame {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void _pop(){
|
void _pop(){
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
#endif
|
#endif
|
||||||
@ -75,26 +75,26 @@ struct Frame {
|
|||||||
|
|
||||||
void try_deref(VM*, PyObject*&);
|
void try_deref(VM*, PyObject*&);
|
||||||
|
|
||||||
inline PyObject* pop_value(VM* vm){
|
PyObject* pop_value(VM* vm){
|
||||||
PyObject* value = pop();
|
PyObject* value = pop();
|
||||||
try_deref(vm, value);
|
try_deref(vm, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* top_value(VM* vm){
|
PyObject* top_value(VM* vm){
|
||||||
PyObject* value = top();
|
PyObject* value = top();
|
||||||
try_deref(vm, value);
|
try_deref(vm, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject*& top(){
|
PyObject*& top(){
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
if(_data.empty()) throw std::runtime_error("_data.empty() is true");
|
||||||
#endif
|
#endif
|
||||||
return _data.back();
|
return _data.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject*& top_1(){
|
PyObject*& top_1(){
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
|
if(_data.size() < 2) throw std::runtime_error("_data.size() < 2");
|
||||||
#endif
|
#endif
|
||||||
@ -102,16 +102,16 @@ struct Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void push(T&& obj){ _data.push_back(std::forward<T>(obj)); }
|
void push(T&& obj){ _data.push_back(std::forward<T>(obj)); }
|
||||||
|
|
||||||
inline void jump_abs(int i){ _next_ip = i; }
|
void jump_abs(int i){ _next_ip = i; }
|
||||||
inline void jump_rel(int i){ _next_ip += i; }
|
void jump_rel(int i){ _next_ip += i; }
|
||||||
|
|
||||||
inline void on_try_block_enter(){
|
void on_try_block_enter(){
|
||||||
s_try_block.emplace_back(co->codes[_ip].block, _data);
|
s_try_block.emplace_back(co->codes[_ip].block, _data);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void on_try_block_exit(){
|
void on_try_block_exit(){
|
||||||
s_try_block.pop_back();
|
s_try_block.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ public:
|
|||||||
this->current = r.start;
|
this->current = r.start;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool _has_next(){
|
bool _has_next(){
|
||||||
return r.step > 0 ? current < r.stop : current > r.stop;
|
return r.step > 0 ? current < r.stop : current > r.stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ struct DictArrayPool {
|
|||||||
const std::vector<uint16_t> kHashSeeds = {9629, 43049, 13267, 59509, 39251, 1249, 35803, 54469, 27689, 9719, 34897, 18973, 30661, 19913, 27919, 32143, 3467, 28019, 1051, 39419, 1361, 28547, 48197, 2609, 24317, 22861, 41467, 17623, 52837, 59053, 33589, 32117};
|
const std::vector<uint16_t> kHashSeeds = {9629, 43049, 13267, 59509, 39251, 1249, 35803, 54469, 27689, 9719, 34897, 18973, 30661, 19913, 27919, 32143, 3467, 28019, 1051, 39419, 1361, 28547, 48197, 2609, 24317, 22861, 41467, 17623, 52837, 59053, 33589, 32117};
|
||||||
static DictArrayPool<32> _dict_pool;
|
static DictArrayPool<32> _dict_pool;
|
||||||
|
|
||||||
inline uint16_t find_next_capacity(uint16_t n){
|
inline static uint16_t find_next_capacity(uint16_t n){
|
||||||
uint16_t x = 2;
|
uint16_t x = 2;
|
||||||
while(x < n) x <<= 1;
|
while(x < n) x <<= 1;
|
||||||
return x;
|
return x;
|
||||||
@ -49,7 +49,7 @@ inline uint16_t find_next_capacity(uint16_t n){
|
|||||||
|
|
||||||
#define _hash(key, mask, hash_seed) ( ( (key).index * (hash_seed) >> 8 ) & (mask) )
|
#define _hash(key, mask, hash_seed) ( ( (key).index * (hash_seed) >> 8 ) & (mask) )
|
||||||
|
|
||||||
inline uint16_t find_perfect_hash_seed(uint16_t capacity, const std::vector<StrName>& keys){
|
inline static uint16_t find_perfect_hash_seed(uint16_t capacity, const std::vector<StrName>& keys){
|
||||||
if(keys.empty()) return kHashSeeds[0];
|
if(keys.empty()) return kHashSeeds[0];
|
||||||
std::set<uint16_t> indices;
|
std::set<uint16_t> indices;
|
||||||
std::pair<uint16_t, float> best_score = {kHashSeeds[0], 0.0f};
|
std::pair<uint16_t, float> best_score = {kHashSeeds[0], 0.0f};
|
||||||
@ -73,11 +73,11 @@ struct NameDict {
|
|||||||
uint16_t _mask;
|
uint16_t _mask;
|
||||||
StrName* _keys;
|
StrName* _keys;
|
||||||
|
|
||||||
inline PyObject*& value(uint16_t i){
|
PyObject*& value(uint16_t i){
|
||||||
return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
|
return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* value(uint16_t i) const {
|
PyObject* value(uint16_t i) const {
|
||||||
return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
|
return reinterpret_cast<PyObject**>(_keys + _capacity)[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,14 +175,14 @@ while(!_keys[i].empty()) { \
|
|||||||
_rehash(false); // do not resize
|
_rehash(false); // do not resize
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject** try_get(StrName key){
|
PyObject** try_get(StrName key){
|
||||||
bool ok; uint16_t i;
|
bool ok; uint16_t i;
|
||||||
HASH_PROBE(key, ok, i);
|
HASH_PROBE(key, ok, i);
|
||||||
if(!ok) return nullptr;
|
if(!ok) return nullptr;
|
||||||
return &value(i);
|
return &value(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool try_set(StrName key, PyObject* val){
|
bool try_set(StrName key, PyObject* val){
|
||||||
bool ok; uint16_t i;
|
bool ok; uint16_t i;
|
||||||
HASH_PROBE(key, ok, i);
|
HASH_PROBE(key, ok, i);
|
||||||
if(!ok) return false;
|
if(!ok) return false;
|
||||||
@ -190,7 +190,7 @@ while(!_keys[i].empty()) { \
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool contains(StrName key) const {
|
bool contains(StrName key) const {
|
||||||
bool ok; uint16_t i;
|
bool ok; uint16_t i;
|
||||||
HASH_PROBE(key, ok, i);
|
HASH_PROBE(key, ok, i);
|
||||||
return ok;
|
return ok;
|
||||||
|
10
src/obj.h
10
src/obj.h
@ -22,7 +22,7 @@ struct NativeFunc {
|
|||||||
bool method;
|
bool method;
|
||||||
|
|
||||||
NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {}
|
NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {}
|
||||||
inline PyObject* operator()(VM* vm, Args& args) const;
|
PyObject* operator()(VM* vm, Args& args) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Function {
|
struct Function {
|
||||||
@ -98,9 +98,9 @@ struct PyObject {
|
|||||||
Type type;
|
Type type;
|
||||||
NameDict* _attr;
|
NameDict* _attr;
|
||||||
|
|
||||||
inline bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
||||||
inline NameDict& attr() noexcept { return *_attr; }
|
NameDict& attr() noexcept { return *_attr; }
|
||||||
inline PyObject* attr(StrName name) const noexcept { return (*_attr)[name]; }
|
PyObject* attr(StrName name) const noexcept { return (*_attr)[name]; }
|
||||||
virtual void* value() = 0;
|
virtual void* value() = 0;
|
||||||
|
|
||||||
virtual void mark() {
|
virtual void mark() {
|
||||||
@ -120,7 +120,7 @@ struct Py_ : PyObject {
|
|||||||
Py_(Type type, const T& val): PyObject(type), _value(val) { _init(); }
|
Py_(Type type, const T& val): PyObject(type), _value(val) { _init(); }
|
||||||
Py_(Type type, T&& val): PyObject(type), _value(std::move(val)) { _init(); }
|
Py_(Type type, T&& val): PyObject(type), _value(std::move(val)) { _init(); }
|
||||||
|
|
||||||
inline void _init() noexcept {
|
void _init() noexcept {
|
||||||
if constexpr (std::is_same_v<T, Type> || std::is_same_v<T, DummyModule>) {
|
if constexpr (std::is_same_v<T, Type> || std::is_same_v<T, DummyModule>) {
|
||||||
_attr = new NameDict(8, kTypeAttrLoadFactor);
|
_attr = new NameDict(8, kTypeAttrLoadFactor);
|
||||||
}else if constexpr(std::is_same_v<T, DummyInstance>){
|
}else if constexpr(std::is_same_v<T, DummyInstance>){
|
||||||
|
@ -120,7 +120,7 @@ struct Parser {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char peekchar() const{ return *curr_char; }
|
char peekchar() const{ return *curr_char; }
|
||||||
|
|
||||||
bool match_n_chars(int n, char c0){
|
bool match_n_chars(int n, char c0){
|
||||||
const char* c = curr_char;
|
const char* c = curr_char;
|
||||||
|
@ -14,8 +14,8 @@ struct BaseRef {
|
|||||||
|
|
||||||
struct NameRef : BaseRef {
|
struct NameRef : BaseRef {
|
||||||
const std::pair<StrName, NameScope> pair;
|
const std::pair<StrName, NameScope> pair;
|
||||||
inline StrName name() const { return pair.first; }
|
StrName name() const { return pair.first; }
|
||||||
inline NameScope scope() const { return pair.second; }
|
NameScope scope() const { return pair.second; }
|
||||||
NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {}
|
NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {}
|
||||||
|
|
||||||
PyObject* get(VM* vm, Frame* frame) const{
|
PyObject* get(VM* vm, Frame* frame) const{
|
||||||
|
@ -14,7 +14,7 @@ namespace pkpy {
|
|||||||
PyObject** _args;
|
PyObject** _args;
|
||||||
int _size;
|
int _size;
|
||||||
|
|
||||||
inline void _alloc(int n){
|
void _alloc(int n){
|
||||||
this->_args = _pool.alloc(n);
|
this->_args = _pool.alloc(n);
|
||||||
this->_size = n;
|
this->_size = n;
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ namespace pkpy {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int size() const { return _size; }
|
int size() const { return _size; }
|
||||||
|
|
||||||
List move_to_list() noexcept {
|
List move_to_list() noexcept {
|
||||||
List ret(_size);
|
List ret(_size);
|
||||||
|
26
src/vm.h
26
src/vm.h
@ -89,7 +89,7 @@ public:
|
|||||||
return asRepr(obj);
|
return asRepr(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Frame* top_frame() const {
|
Frame* top_frame() const {
|
||||||
#if PK_EXTRA_CHECK
|
#if PK_EXTRA_CHECK
|
||||||
if(callstack.empty()) UNREACHABLE();
|
if(callstack.empty()) UNREACHABLE();
|
||||||
#endif
|
#endif
|
||||||
@ -147,23 +147,23 @@ public:
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* call(PyObject* callable){
|
PyObject* call(PyObject* callable){
|
||||||
return call(callable, no_arg(), no_arg(), false);
|
return call(callable, no_arg(), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ArgT>
|
template<typename ArgT>
|
||||||
inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
|
std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
|
||||||
call(PyObject* _callable, ArgT&& args){
|
call(PyObject* _callable, ArgT&& args){
|
||||||
return call(_callable, std::forward<ArgT>(args), no_arg(), false);
|
return call(_callable, std::forward<ArgT>(args), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ArgT>
|
template<typename ArgT>
|
||||||
inline std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
|
std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
|
||||||
call(PyObject* obj, const StrName name, ArgT&& args){
|
call(PyObject* obj, const StrName name, ArgT&& args){
|
||||||
return call(getattr(obj, name, true, true), std::forward<ArgT>(args), no_arg(), false);
|
return call(getattr(obj, name, true, true), std::forward<ArgT>(args), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* call(PyObject* obj, StrName name){
|
PyObject* call(PyObject* obj, StrName name){
|
||||||
return call(getattr(obj, name, true, true), no_arg(), no_arg(), false);
|
return call(getattr(obj, name, true, true), no_arg(), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
inline std::unique_ptr<Frame> _new_frame(Args&&... args){
|
std::unique_ptr<Frame> _new_frame(Args&&... args){
|
||||||
if(callstack.size() > recursionlimit){
|
if(callstack.size() > recursionlimit){
|
||||||
_error("RecursionError", "maximum recursion depth exceeded");
|
_error("RecursionError", "maximum recursion depth exceeded");
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
inline PyObject* _exec(Args&&... args){
|
PyObject* _exec(Args&&... args){
|
||||||
callstack.push(_new_frame(std::forward<Args>(args)...));
|
callstack.push(_new_frame(std::forward<Args>(args)...));
|
||||||
return _exec();
|
return _exec();
|
||||||
}
|
}
|
||||||
@ -272,12 +272,12 @@ public:
|
|||||||
Type tp_super, tp_exception, tp_star_wrapper;
|
Type tp_super, tp_exception, tp_star_wrapper;
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
inline PyObject* PyIter(P&& value) {
|
PyObject* PyIter(P&& value) {
|
||||||
static_assert(std::is_base_of_v<BaseIter, std::decay_t<P>>);
|
static_assert(std::is_base_of_v<BaseIter, std::decay_t<P>>);
|
||||||
return gcnew<P>(tp_iterator, std::forward<P>(value));
|
return gcnew<P>(tp_iterator, std::forward<P>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BaseIter* PyIter_AS_C(PyObject* obj)
|
BaseIter* PyIter_AS_C(PyObject* obj)
|
||||||
{
|
{
|
||||||
check_type(obj, tp_iterator);
|
check_type(obj, tp_iterator);
|
||||||
return static_cast<BaseIter*>(obj->value());
|
return static_cast<BaseIter*>(obj->value());
|
||||||
@ -309,16 +309,16 @@ public:
|
|||||||
|
|
||||||
void AttributeError(Str msg){ _error("AttributeError", msg); }
|
void AttributeError(Str msg){ _error("AttributeError", msg); }
|
||||||
|
|
||||||
inline void check_type(PyObject* obj, Type type){
|
void check_type(PyObject* obj, Type type){
|
||||||
if(is_type(obj, type)) return;
|
if(is_type(obj, type)) return;
|
||||||
TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true));
|
TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* _t(Type t){
|
PyObject* _t(Type t){
|
||||||
return _all_types[t.index].obj;
|
return _all_types[t.index].obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* _t(PyObject* obj){
|
PyObject* _t(PyObject* obj){
|
||||||
if(is_int(obj)) return _t(tp_int);
|
if(is_int(obj)) return _t(tp_int);
|
||||||
if(is_float(obj)) return _t(tp_float);
|
if(is_float(obj)) return _t(tp_float);
|
||||||
return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj;
|
return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj;
|
||||||
@ -358,7 +358,7 @@ public:
|
|||||||
const BaseRef* PyRef_AS_C(PyObject* obj);
|
const BaseRef* PyRef_AS_C(PyObject* obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
PyObject* NativeFunc::operator()(VM* vm, Args& args) const{
|
inline PyObject* NativeFunc::operator()(VM* vm, Args& args) const{
|
||||||
int args_size = args.size() - (int)method; // remove self
|
int args_size = args.size() - (int)method; // remove self
|
||||||
if(argc != -1 && args_size != argc) {
|
if(argc != -1 && args_size != argc) {
|
||||||
vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
|
vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user