From fc70cd4b08352b7d798ecd006b8fc12c2b349414 Mon Sep 17 00:00:00 2001 From: BLUELOVETH Date: Tue, 18 Jul 2023 18:17:33 +0800 Subject: [PATCH 1/7] ... --- .gitignore | 1 + include/pocketpy/expr.h | 43 ++--------------------------------------- src/expr.cpp | 14 -------------- src/io.cpp | 2 +- 4 files changed, 4 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index 6714e503..ee394036 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ pocketpy.dSYM main pypi/ +libpocketpy.dylib diff --git a/include/pocketpy/expr.h b/include/pocketpy/expr.h index 1ec109dc..41baf2b5 100644 --- a/include/pocketpy/expr.h +++ b/include/pocketpy/expr.h @@ -16,8 +16,6 @@ struct Expr{ int line = 0; virtual ~Expr() = default; virtual void emit(CodeEmitContext* ctx) = 0; - virtual std::string str() const = 0; - virtual bool is_literal() const { return false; } virtual bool is_json_object() const { return false; } virtual bool is_attrib() const { return false; } @@ -26,6 +24,8 @@ struct Expr{ virtual bool is_tuple() const { return false; } bool is_starred() const { return star_level() > 0; } + std::string str() const { PK_ASSERT(false); } + // for OP_DELETE_XXX [[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { PK_UNUSED(ctx); @@ -70,9 +70,6 @@ struct NameExpr: Expr{ StrName name; NameScope scope; NameExpr(StrName name, NameScope scope): name(name), scope(scope) {} - - std::string str() const override { return fmt("Name(", name.escape(), ")"); } - void emit(CodeEmitContext* ctx) override; bool emit_del(CodeEmitContext* ctx) override; bool emit_store(CodeEmitContext* ctx) override; @@ -81,7 +78,6 @@ struct NameExpr: Expr{ struct InvertExpr: Expr{ Expr_ child; InvertExpr(Expr_&& child): child(std::move(child)) {} - std::string str() const override { return "Invert()"; } void emit(CodeEmitContext* ctx) override; }; @@ -89,7 +85,6 @@ struct StarredExpr: Expr{ int level; Expr_ child; StarredExpr(int level, Expr_&& child): level(level), child(std::move(child)) {} - std::string str() const override { return fmt("Starred(level=", level, ")"); } int star_level() const override { return level; } void emit(CodeEmitContext* ctx) override; bool emit_store(CodeEmitContext* ctx) override; @@ -98,22 +93,18 @@ struct StarredExpr: Expr{ struct NotExpr: Expr{ Expr_ child; NotExpr(Expr_&& child): child(std::move(child)) {} - std::string str() const override { return "Not()"; } - void emit(CodeEmitContext* ctx) override; }; struct AndExpr: Expr{ Expr_ lhs; Expr_ rhs; - std::string str() const override { return "And()"; } void emit(CodeEmitContext* ctx) override; }; struct OrExpr: Expr{ Expr_ lhs; Expr_ rhs; - std::string str() const override { return "Or()"; } void emit(CodeEmitContext* ctx) override; }; @@ -121,7 +112,6 @@ struct OrExpr: Expr{ struct Literal0Expr: Expr{ TokenIndex token; Literal0Expr(TokenIndex token): token(token) {} - std::string str() const override { return TK_STR(token); } bool is_json_object() const override { return true; } void emit(CodeEmitContext* ctx) override; @@ -130,14 +120,12 @@ struct Literal0Expr: Expr{ struct LongExpr: Expr{ Str s; LongExpr(const Str& s): s(s) {} - std::string str() const override { return s.str(); } void emit(CodeEmitContext* ctx) override; }; struct BytesExpr: Expr{ Str s; BytesExpr(const Str& s): s(s) {} - std::string str() const override { return s.str(); } void emit(CodeEmitContext* ctx) override; }; @@ -145,7 +133,6 @@ struct BytesExpr: Expr{ struct LiteralExpr: Expr{ TokenValue value; LiteralExpr(TokenValue value): value(value) {} - std::string str() const override; void emit(CodeEmitContext* ctx) override; bool is_literal() const override { return true; } bool is_json_object() const override { return true; } @@ -154,8 +141,6 @@ struct LiteralExpr: Expr{ struct NegatedExpr: Expr{ Expr_ child; NegatedExpr(Expr_&& child): child(std::move(child)) {} - std::string str() const override { return "Negated()"; } - void emit(CodeEmitContext* ctx) override; bool is_json_object() const override { return child->is_literal(); } }; @@ -164,14 +149,12 @@ struct SliceExpr: Expr{ Expr_ start; Expr_ stop; Expr_ step; - std::string str() const override { return "Slice()"; } void emit(CodeEmitContext* ctx) override; }; struct DictItemExpr: Expr{ Expr_ key; // maybe nullptr if it is **kwargs Expr_ value; - std::string str() const override { return "DictItem()"; } int star_level() const override { return value->star_level(); } void emit(CodeEmitContext* ctx) override; }; @@ -189,8 +172,6 @@ struct SequenceExpr: Expr{ struct ListExpr: SequenceExpr{ using SequenceExpr::SequenceExpr; - std::string str() const override { return "List()"; } - Opcode opcode() const override { for(auto& e: items) if(e->is_starred()) return OP_BUILD_LIST_UNPACK; return OP_BUILD_LIST; @@ -201,7 +182,6 @@ struct ListExpr: SequenceExpr{ struct DictExpr: SequenceExpr{ using SequenceExpr::SequenceExpr; - std::string str() const override { return "Dict()"; } Opcode opcode() const override { for(auto& e: items) if(e->is_starred()) return OP_BUILD_DICT_UNPACK; return OP_BUILD_DICT; @@ -212,7 +192,6 @@ struct DictExpr: SequenceExpr{ struct SetExpr: SequenceExpr{ using SequenceExpr::SequenceExpr; - std::string str() const override { return "Set()"; } Opcode opcode() const override { for(auto& e: items) if(e->is_starred()) return OP_BUILD_SET_UNPACK; return OP_BUILD_SET; @@ -221,7 +200,6 @@ struct SetExpr: SequenceExpr{ struct TupleExpr: SequenceExpr{ using SequenceExpr::SequenceExpr; - std::string str() const override { return "Tuple()"; } bool is_tuple() const override { return true; } Opcode opcode() const override { for(auto& e: items) if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK; @@ -247,24 +225,20 @@ struct CompExpr: Expr{ struct ListCompExpr: CompExpr{ Opcode op0() override { return OP_BUILD_LIST; } Opcode op1() override { return OP_LIST_APPEND; } - std::string str() const override { return "ListComp()"; } }; struct DictCompExpr: CompExpr{ Opcode op0() override { return OP_BUILD_DICT; } Opcode op1() override { return OP_DICT_ADD; } - std::string str() const override { return "DictComp()"; } }; struct SetCompExpr: CompExpr{ Opcode op0() override { return OP_BUILD_SET; } Opcode op1() override { return OP_SET_ADD; } - std::string str() const override { return "SetComp()"; } }; struct LambdaExpr: Expr{ FuncDecl_ decl; - std::string str() const override { return "Lambda()"; } LambdaExpr(FuncDecl_ decl): decl(decl) {} @@ -277,10 +251,6 @@ struct LambdaExpr: Expr{ struct FStringExpr: Expr{ Str src; FStringExpr(const Str& src): src(src) {} - std::string str() const override { - return fmt("f", src.escape()); - } - void _load_simple_expr(CodeEmitContext* ctx, Str expr); void emit(CodeEmitContext* ctx) override; }; @@ -288,8 +258,6 @@ struct FStringExpr: Expr{ struct SubscrExpr: Expr{ Expr_ a; Expr_ b; - std::string str() const override { return "Subscr()"; } - void emit(CodeEmitContext* ctx) override; bool emit_del(CodeEmitContext* ctx) override; bool emit_store(CodeEmitContext* ctx) override; @@ -300,7 +268,6 @@ struct AttribExpr: Expr{ Str b; AttribExpr(Expr_ a, const Str& b): a(std::move(a)), b(b) {} AttribExpr(Expr_ a, Str&& b): a(std::move(a)), b(std::move(b)) {} - std::string str() const override { return "Attrib()"; } void emit(CodeEmitContext* ctx) override; bool emit_del(CodeEmitContext* ctx) override; @@ -314,14 +281,11 @@ struct CallExpr: Expr{ std::vector args; // **a will be interpreted as a special keyword argument: {"**": a} std::vector> kwargs; - std::string str() const override { return "Call()"; } void emit(CodeEmitContext* ctx) override; }; struct GroupedExpr: Expr{ Expr_ a; - std::string str() const override { return "Grouped()"; } - GroupedExpr(Expr_&& a): a(std::move(a)) {} void emit(CodeEmitContext* ctx) override{ @@ -341,8 +305,6 @@ struct BinaryExpr: Expr{ TokenIndex op; Expr_ lhs; Expr_ rhs; - std::string str() const override { return TK_STR(op); } - bool is_compare() const override; void _emit_compare(CodeEmitContext* ctx, std::vector& jmps); void emit(CodeEmitContext* ctx) override; @@ -353,7 +315,6 @@ struct TernaryExpr: Expr{ Expr_ cond; Expr_ true_expr; Expr_ false_expr; - std::string str() const override { return "Ternary()"; } void emit(CodeEmitContext* ctx) override; }; diff --git a/src/expr.cpp b/src/expr.cpp index 665c066b..029089fe 100644 --- a/src/expr.cpp +++ b/src/expr.cpp @@ -196,20 +196,6 @@ namespace pkpy{ ctx->emit(OP_BUILD_BYTES, BC_NOARG, line); } - std::string LiteralExpr::str() const{ - if(std::holds_alternative(value)){ - return std::to_string(std::get(value)); - } - if(std::holds_alternative(value)){ - return std::to_string(std::get(value)); - } - if(std::holds_alternative(value)){ - Str s = std::get(value).escape(); - return s.str(); - } - FATAL_ERROR(); - } - void LiteralExpr::emit(CodeEmitContext* ctx) { VM* vm = ctx->vm; PyObject* obj = nullptr; diff --git a/src/io.cpp b/src/io.cpp index 6f250613..c6a080d4 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -40,7 +40,7 @@ Bytes _default_import_handler(const Str& name){ size_t sz = fread(buffer.data(), 1, buffer.size(), io.fp); PK_UNUSED(sz); Bytes b(std::move(buffer)); - if(io.is_text()) return VAR(Str(b.str())); + if(io.is_text()) return VAR(b.str()); return VAR(std::move(b)); }); From 4223004b8d584b754d4d50743cb1a594ad510bf0 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 18 Jul 2023 22:02:05 +0800 Subject: [PATCH 2/7] ... --- src/pocketpy_c.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index ed4ed4c1..ea2be28a 100644 --- a/src/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -127,7 +127,7 @@ int pkpy_stack_size(pkpy_vm* vm_handle){ if(vm->callstack.empty()){ return vm->s_data.size(); } - PK_ASSERT(!vm->_c.s_view.empty()); + if(vm->_c.s_view.empty()) exit(127); return vm->s_data._sp - vm->_c.s_view.top().begin(); } @@ -499,7 +499,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) { if(vm->callstack.empty()){ vm->s_data.clear(); }else{ - PK_ASSERT(!vm->_c.s_view.empty()); + if(vm->_c.s_view.empty()) exit(127); vm->s_data.reset(vm->_c.s_view.top().end()); } return true; From 692f3c52665ecf0d6e816976b1b8e7d53d8d7a99 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 18 Jul 2023 22:44:25 +0800 Subject: [PATCH 3/7] ... --- scripts/genstub.py | 34 ++++++++++++++++++++++++++++++++++ src2/pocketpy_c.cpp | 14 +++++++++++--- 2 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 scripts/genstub.py diff --git a/scripts/genstub.py b/scripts/genstub.py new file mode 100644 index 00000000..a071a2b2 --- /dev/null +++ b/scripts/genstub.py @@ -0,0 +1,34 @@ +import os + +with open('include/pocketpy/pocketpy_c.h') as f: + lines = f.readlines() + +a = [] +for line in lines: + if line.startswith("PK_EXPORT"): + _, ret, *body = line.split() + else: + continue + body = ' '.join(body) + assert body.endswith(";") + body = body[:-1] + + if ret == 'void': + mock_string = '' + else: + mock_string = ' '*4 + ret + ' returnValue;\n return returnValue;' + + a.append( + ret + ' ' + body + ' {\n' + mock_string + '\n}\n' + ) + +with open('src2/pocketpy_c.cpp', 'w') as f: + f.write(''' +#include "pocketpy_c.h" + +#ifdef _WIN32 +#pragma warning(disable: 4700) +#endif + +''') + f.write('\n'.join(a)) \ No newline at end of file diff --git a/src2/pocketpy_c.cpp b/src2/pocketpy_c.cpp index ed9a4a04..b3e13c63 100644 --- a/src2/pocketpy_c.cpp +++ b/src2/pocketpy_c.cpp @@ -1,17 +1,17 @@ -/* autogenerated code. Do not edit */ #include "pocketpy_c.h" #ifdef _WIN32 #pragma warning(disable: 4700) #endif - + pkpy_vm* pkpy_new_vm(bool enable_os) { pkpy_vm* returnValue; return returnValue; } void pkpy_delete_vm(pkpy_vm*) { + } bool pkpy_exec(pkpy_vm*, const char* source) { @@ -24,6 +24,11 @@ bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, c return returnValue; } +bool pkpy_dup(pkpy_vm*, int) { + bool returnValue; + return returnValue; +} + bool pkpy_pop(pkpy_vm*, int) { bool returnValue; return returnValue; @@ -184,7 +189,7 @@ bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName) { return returnValue; } -bool pkpy_py_repr(pkpy_vm*, int i) { +bool pkpy_py_repr(pkpy_vm*) { bool returnValue; return returnValue; } @@ -210,6 +215,7 @@ bool pkpy_vectorcall(pkpy_vm*, int argc) { } void pkpy_free(void* p) { + } pkpy_CString pkpy_string(const char*) { @@ -228,6 +234,7 @@ pkpy_CString pkpy_name_to_string(pkpy_CName) { } void pkpy_compile_to_string(pkpy_vm*, const char* source, const char* filename, int mode, bool* ok, char** out) { + } void* pkpy_new_repl(pkpy_vm* vm) { @@ -241,4 +248,5 @@ bool pkpy_repl_input(void* r, const char* line) { } void pkpy_delete_repl(void* repl) { + } From 9a7fabeb75ba7a6230874fac4477dcd9ecea650d Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 18 Jul 2023 23:02:22 +0800 Subject: [PATCH 4/7] ... --- dylib/src/test.c | 2 +- src/pocketpy.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dylib/src/test.c b/dylib/src/test.c index ea277392..39614781 100644 --- a/dylib/src/test.c +++ b/dylib/src/test.c @@ -15,7 +15,7 @@ const char* pkpy_module__init__(pkpy_vm* vm, const char* version){ pkpy_setattr(vm, pkpy_name("hello")); if(pkpy_check_error(vm)){ pkpy_clear_error(vm, NULL); - exit(1); + return NULL; } return "test"; } \ No newline at end of file diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 4a180cf3..fb4f066a 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -174,6 +174,9 @@ void init_builtins(VM* _vm) { vm->_error("ImportError", "cannot load dynamic library: " + name.escape()); } const char* name = entry(vm, PK_VERSION); + if(name == nullptr){ + vm->_error("ImportError", "module initialization failed: " + Str(name).escape()); + } return vm->_modules[name]; } } From 74f45757783634677b52880a496f33591513546e Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 18 Jul 2023 23:04:47 +0800 Subject: [PATCH 5/7] ... --- dylib/src/test.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dylib/src/test.c b/dylib/src/test.c index 39614781..d02ed610 100644 --- a/dylib/src/test.c +++ b/dylib/src/test.c @@ -13,9 +13,7 @@ const char* pkpy_module__init__(pkpy_vm* vm, const char* version){ pkpy_push_function(vm, "hello()", hello); pkpy_push_module(vm, "test"); pkpy_setattr(vm, pkpy_name("hello")); - if(pkpy_check_error(vm)){ - pkpy_clear_error(vm, NULL); - return NULL; - } + // check if initialization failed + if(pkpy_clear_error(vm, NULL)) return NULL; return "test"; } \ No newline at end of file From 7f289c4201d5d8c3bc8af05aac8c22a636c3016f Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 18 Jul 2023 23:13:34 +0800 Subject: [PATCH 6/7] ... --- docs/quick-start/dylib.md | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 docs/quick-start/dylib.md diff --git a/docs/quick-start/dylib.md b/docs/quick-start/dylib.md new file mode 100644 index 00000000..25a8a76c --- /dev/null +++ b/docs/quick-start/dylib.md @@ -0,0 +1,58 @@ +--- +icon: dot +label: 'Using dynamic library' +order: 45 +--- + +You can import a native module from a dynamic library at runtime. +This feature is supported on Windows, Linux, macOS, and Android. + +## Create a module as a dynamic library + +Implement a `pkpy_module__init__` function and export it as a symbol. +This is the entry point of the module. When users call `__import__` function, +the VM will call this function to initialize the module. + +You can create one or more modules inside `pkpy_module__init__` function, +and return the name of the module you want users to import directly. + +You should use C-APIs to interact with the VM in the dynamic library. +This is to make sure the dynamic library is compatible with different compilers. + +```c +#include "pocketpy_c.h" +#include +#include + +static int hello(pkpy_vm* vm){ + printf("Hello from dylib!\n"); + return 0; +} + +PK_EXPORT +const char* pkpy_module__init__(pkpy_vm* vm, const char* version){ + printf("version: %s\n", version); + pkpy_push_function(vm, "hello()", hello); + pkpy_push_module(vm, "test"); + pkpy_setattr(vm, pkpy_name("hello")); + // check if initialization failed + if(pkpy_clear_error(vm, NULL)) return NULL; + return "test"; +} +``` + +## Load a dynamic library + +You can load a dynamic library with `__import__` function with a path to the library. + +```python +test = __import__("test.dll") # Windows + +test = __import__("libtest.so") # Linux + +test = __import__("libtest.dylib") # macOS + +test = __import__("libtest.so") # Android + +test.hello() # Hello from dylib! +``` \ No newline at end of file From 1490e9db73c11724b33a82eaf2fc6f13126c6790 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 18 Jul 2023 23:21:23 +0800 Subject: [PATCH 7/7] ... --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 710b4071..55924c2e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,6 +43,7 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} directory: .coverage + if: github.ref == 'refs/heads/main' - name: Compile run: | export CXX=clang++