diff --git a/python/builtins.py b/python/builtins.py index 07d0bc5f..805ae4de 100644 --- a/python/builtins.py +++ b/python/builtins.py @@ -270,11 +270,8 @@ type.__repr__ = lambda self: "" def help(obj): if hasattr(obj, '__func__'): obj = obj.__func__ - if hasattr(obj, '__doc__'): - print(obj.__doc__) - else: - print("No docstring found") - + print(obj.__signature__) + print(obj.__doc__) del __f diff --git a/src/c.pyi b/src/c.pyi index 392d0599..7f79f04f 100644 --- a/src/c.pyi +++ b/src/c.pyi @@ -65,12 +65,24 @@ class void_p: def set_base_offset(self, offset: str) -> None: ... class struct: + @overload + def __init__(self, size: int): ... + @overload + def __init__(self, p: 'void_p', size: int): ... + @overload + def __init__(self, s: str): ... + @overload + def __init__(self, b: bytes): ... + def addr(self) -> 'void_p': ... def copy(self) -> 'struct': ... def size(self) -> int: ... def __eq__(self, other: 'struct') -> bool: ... def __ne__(self, other: 'struct') -> bool: ... + def to_string(self) -> str: ... + def to_bytes(self) -> bytes: ... + def read_char(self, offset=0) -> int: ... def read_uchar(self, offset=0) -> int: ... def read_short(self, offset=0) -> int: ... diff --git a/src/ceval.h b/src/ceval.h index 4285235d..d5ccd140 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -11,7 +11,6 @@ inline PyObject* VM::_run_top_frame(){ DEF_SNAME(set); DEF_SNAME(__enter__); DEF_SNAME(__exit__); - DEF_SNAME(__doc__); FrameId frame = top_frame(); const int base_id = frame.index; @@ -674,9 +673,6 @@ __NEXT_STEP:; TARGET(RE_RAISE) _raise(); DISPATCH(); TARGET(POP_EXCEPTION) _last_exception = POPX(); DISPATCH(); /*****************************************/ - TARGET(SETUP_DOCSTRING) - TOP()->attr().set(__doc__, co_consts[byte.arg]); - DISPATCH(); TARGET(FORMAT_STRING) { _0 = POPX(); const Str& spec = CAST(Str&, co_consts[byte.arg]); diff --git a/src/cffi.h b/src/cffi.h index 5b1cf4de..adc157d7 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -191,7 +191,7 @@ struct C99Struct{ char* p; int size; - void _init(int new_size){ + C99Struct(int new_size){ this->size = new_size; if(size <= INLINE_SIZE){ p = _inlined; @@ -201,27 +201,46 @@ struct C99Struct{ } template - C99Struct(const T& data){ + C99Struct(const T& data): C99Struct(sizeof(T)){ static_assert(std::is_pod_v); static_assert(!std::is_pointer_v); - _init(sizeof(T)); memcpy(p, &data, this->size); } - C99Struct() { p = _inlined; } - C99Struct(void* p, int size){ - _init(size); - if(p!=nullptr) memcpy(this->p, p, size); + C99Struct(void* p, int size): C99Struct(size){ + if(p != nullptr) memcpy(this->p, p, size); } + + C99Struct(const C99Struct& other): C99Struct(other.p, other.size){} + ~C99Struct(){ if(p!=_inlined) free(p); } - C99Struct(const C99Struct& other){ - _init(other.size); - memcpy(p, other.p, size); - } - static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->bind_default_constructor(type); + vm->bind_constructor<-1>(type, [](VM* vm, ArgsView args){ + if(args.size() == 1+1){ + if(is_int(args[1])){ + int size = _CAST(int, args[1]); + return VAR_T(C99Struct, size); + } + if(is_non_tagged_type(args[1], vm->tp_str)){ + const Str& s = _CAST(Str&, args[1]); + return VAR_T(C99Struct, (void*)s.data, s.size); + } + if(is_non_tagged_type(args[1], vm->tp_bytes)){ + const Bytes& b = _CAST(Bytes&, args[1]); + return VAR_T(C99Struct, (void*)b.data(), b.size()); + } + vm->TypeError("expected int, str or bytes"); + return vm->None; + } + if(args.size() == 1+2){ + void* p = CAST(void*, args[1]); + int size = CAST(int, args[2]); + return VAR_T(C99Struct, p, size); + } + vm->TypeError("expected 1 or 2 arguments"); + return vm->None; + }); vm->bind_method<0>(type, "addr", [](VM* vm, ArgsView args){ C99Struct& self = _CAST(C99Struct&, args[0]); @@ -238,6 +257,18 @@ struct C99Struct{ return VAR_T(C99Struct, self); }); + vm->bind_method<0>(type, "to_string", [](VM* vm, ArgsView args){ + C99Struct& self = _CAST(C99Struct&, args[0]); + return VAR(Str(self.p, self.size)); + }); + + vm->bind_method<0>(type, "to_bytes", [](VM* vm, ArgsView args){ + C99Struct& self = _CAST(C99Struct&, args[0]); + std::vector buffer(self.size); + memcpy(buffer.data(), self.p, self.size); + return VAR(Bytes(std::move(buffer))); + }); + vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ C99Struct& self = _CAST(C99Struct&, lhs); if(!is_non_tagged_type(rhs, C99Struct::_type(vm))) return vm->NotImplemented; diff --git a/src/compiler.h b/src/compiler.h index 1820c2d0..67e22a72 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -972,9 +972,9 @@ __SUBSCR_END: } void compile_function(const std::vector& decorators={}){ - Str decl_name; + const char* _start = curr().start; consume(TK("@id")); - decl_name = prev().str(); + Str decl_name = prev().str(); FuncDecl_ decl = push_f_context(decl_name); consume(TK("(")); if (!match(TK(")"))) { @@ -982,6 +982,8 @@ __SUBSCR_END: consume(TK(")")); } if(match(TK("->"))) consume_type_hints(); + const char* _end = curr().start; + decl->signature = Str(_start, _end-_start); compile_block_body(); pop_context(); @@ -994,10 +996,11 @@ __SUBSCR_END: docstring = c; } } - ctx()->emit(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line); if(docstring != nullptr){ - ctx()->emit(OP_SETUP_DOCSTRING, ctx()->add_const(docstring), prev().line); + decl->docstring = PK_OBJ_GET(Str, docstring); } + ctx()->emit(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line); + // add decorators for(auto it=decorators.rbegin(); it!=decorators.rend(); ++it){ (*it)->emit(ctx()); diff --git a/src/main.cpp b/src/main.cpp index de93aac4..4ae9f23e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,11 +7,25 @@ int main(int argc, char** argv){ pkpy::VM* vm = pkpy_new_vm(); - pkpy::PyObject* input_f = vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){ + vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){ // pkpy::getline() has bugs for PIPE input on Windows return VAR(pkpy::getline()); }); - vm->_modules["sys"]->attr("stdin")->attr().set("readline", input_f); + + // vm->bind(vm->builtins, "test_sum(a: int, b: int, *args, x=5)", + // "Test function for summing up numbers.", + // [](pkpy::VM* vm, pkpy::ArgsView args){ + // PK_ASSERT(args.size() == 4); + // int sum = 0; + // sum += pkpy::CAST(int, args[0]); + // sum += pkpy::CAST(int, args[1]); + // pkpy::Tuple& t = pkpy::CAST(pkpy::Tuple&, args[2]); + // for(pkpy::PyObject* ob: t){ + // sum += pkpy::CAST(int, ob); + // } + // sum *= pkpy::CAST(int, args[3]); + // return VAR(sum); + // }); if(argc == 1){ pkpy::REPL* repl = pkpy_new_repl(vm); bool need_more_lines = false; diff --git a/src/obj.h b/src/obj.h index a548773e..bd343a07 100644 --- a/src/obj.h +++ b/src/obj.h @@ -30,6 +30,9 @@ struct FuncDecl { int starred_arg = -1; // index in co->varnames, -1 if no *arg int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg bool nested = false; // whether this function is nested + + Str signature; // signature of this function + Str docstring; // docstring of this function void _gc_mark() const; }; @@ -43,7 +46,6 @@ struct NativeFunc { // new style decl-based call FuncDecl_ decl; - const char* docstring; using UserData = char[32]; UserData _userdata; @@ -75,11 +77,10 @@ struct NativeFunc { _has_userdata = false; } - NativeFunc(NativeFuncC f, FuncDecl_ decl, const char* docstring){ + NativeFunc(NativeFuncC f, FuncDecl_ decl){ this->f = f; this->argc = -1; this->decl = decl; - this->docstring = docstring; _has_userdata = false; } diff --git a/src/opcodes.h b/src/opcodes.h index bf2f37ff..c1ce7c72 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -123,7 +123,6 @@ OPCODE(RAISE) OPCODE(RE_RAISE) OPCODE(POP_EXCEPTION) /**************************/ -OPCODE(SETUP_DOCSTRING) OPCODE(FORMAT_STRING) /**************************/ OPCODE(INC_FAST) diff --git a/src/pocketpy.h b/src/pocketpy.h index ee9e57c4..266dba49 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -559,16 +559,6 @@ inline void init_builtins(VM* _vm) { return VAR(ss.str()); }); - _vm->bind_method<0>("str", "to_c_str", [](VM* vm, ArgsView args){ - const Str& self = _CAST(Str&, args[0]); - return VAR(self.c_str_dup()); - }); - - _vm->bind_func<1>("str", "from_c_str", [](VM* vm, ArgsView args){ - char* p = CAST(char*, args[0]); - return VAR(Str(p)); - }); - _vm->bind_method<0>("str", "lower", [](VM* vm, ArgsView args) { const Str& self = _CAST(Str&, args[0]); return VAR(self.lower()); @@ -907,21 +897,6 @@ inline void init_builtins(VM* _vm) { return VAR(Str(self.str())); }); - _vm->bind_method<0>("bytes", "to_char_array", [](VM* vm, ArgsView args) { - const Bytes& self = _CAST(Bytes&, args[0]); - void* buffer = malloc(self.size()); - memcpy(buffer, self.data(), self.size()); - return VAR_T(VoidP, buffer); - }); - - _vm->bind_func<2>("bytes", "from_char_array", [](VM* vm, ArgsView args) { - const VoidP& data = _CAST(VoidP&, args[0]); - int size = CAST(int, args[1]); - std::vector buffer(size); - memcpy(buffer.data(), data.ptr, size); - return VAR(Bytes(std::move(buffer))); - }); - _vm->bind__eq__(_vm->tp_bytes, [](VM* vm, PyObject* lhs, PyObject* rhs) { if(!is_non_tagged_type(rhs, vm->tp_bytes)) return vm->NotImplemented; return VAR(_CAST(Bytes&, lhs) == _CAST(Bytes&, rhs)); @@ -1175,6 +1150,28 @@ inline void init_builtins(VM* _vm) { vm->TypeError("property() takes at most 2 arguments"); return vm->None; }); + + _vm->_t(_vm->tp_function)->attr().set("__doc__", _vm->property([](VM* vm, ArgsView args) { + Function& func = _CAST(Function&, args[0]); + return VAR(func.decl->docstring); + })); + + _vm->_t(_vm->tp_native_func)->attr().set("__doc__", _vm->property([](VM* vm, ArgsView args) { + NativeFunc& func = _CAST(NativeFunc&, args[0]); + if(func.decl != nullptr) return VAR(func.decl->docstring); + return VAR(""); + })); + + _vm->_t(_vm->tp_function)->attr().set("__signature__", _vm->property([](VM* vm, ArgsView args) { + Function& func = _CAST(Function&, args[0]); + return VAR(func.decl->signature); + })); + + _vm->_t(_vm->tp_native_func)->attr().set("__signature__", _vm->property([](VM* vm, ArgsView args) { + NativeFunc& func = _CAST(NativeFunc&, args[0]); + if(func.decl != nullptr) return VAR(func.decl->signature); + return VAR("unknown(*args, **kwargs)"); + })); RangeIter::register_class(_vm, _vm->builtins); ArrayIter::register_class(_vm, _vm->builtins); @@ -1288,10 +1285,8 @@ inline void add_module_sys(VM* vm){ PyObject* stdout_ = vm->heap.gcnew(vm->tp_object, {}); PyObject* stderr_ = vm->heap.gcnew(vm->tp_object, {}); - PyObject* stdin_ = vm->heap.gcnew(vm->tp_object, {}); vm->setattr(mod, "stdout", stdout_); vm->setattr(mod, "stderr", stderr_); - vm->setattr(mod, "stdin", stdin_); vm->bind_func<1>(stdout_, "write", [](VM* vm, ArgsView args) { vm->_stdout(vm, CAST(Str&, args[0])); diff --git a/src/str.h b/src/str.h index b8bb76ec..21267ec6 100644 --- a/src/str.h +++ b/src/str.h @@ -228,6 +228,17 @@ struct Str{ return Str(copy); } + Str strip() const { + std::string copy(data, size); + copy.erase(copy.begin(), std::find_if(copy.begin(), copy.end(), [](char c) { + return c != ' ' && c != '\t' && c != '\r' && c != '\n'; + })); + copy.erase(std::find_if(copy.rbegin(), copy.rend(), [](char c) { + return c != ' ' && c != '\t' && c != '\r' && c != '\n'; + }).base(), copy.end()); + return Str(copy); + } + Str lower() const{ std::string copy(data, size); std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c){ return std::tolower(c); }); diff --git a/src/vm.h b/src/vm.h index 329d8f86..8463e6e5 100644 --- a/src/vm.h +++ b/src/vm.h @@ -1561,7 +1561,11 @@ inline PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, throw std::runtime_error("expected 1 function declaration"); } FuncDecl_ decl = co->func_decls[0]; - PyObject* f_obj = VAR(NativeFunc(fn, decl, docstring)); + decl->signature = Str(sig); + if(docstring != nullptr){ + decl->docstring = Str(docstring).strip(); + } + PyObject* f_obj = VAR(NativeFunc(fn, decl)); obj->attr().set(decl->code->name, f_obj); return f_obj; }