From 57574bd8be6686d050e27a9d5ae617d606a333c6 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 14 Apr 2024 01:49:50 +0800 Subject: [PATCH] some fix --- docs/features/precompile.md | 114 ++++++++++++++++++++++++++++++++++++ tests/94_compile.py | 14 +++++ 2 files changed, 128 insertions(+) create mode 100644 docs/features/precompile.md diff --git a/docs/features/precompile.md b/docs/features/precompile.md new file mode 100644 index 00000000..f0c60f0e --- /dev/null +++ b/docs/features/precompile.md @@ -0,0 +1,114 @@ +--- +icon: dot +title: Precompiling +--- + +pkpy allows you to precompile your python code into a special form, which can be executed later. + +### In-memory precompilation + +You can use `vm->compile` to compile your source code into a `CodeObject_` object. +This object can be executed later by `vm->_exec`. + +```cpp +CodeObject_ code = vm->compile("print('Hello, world!')", "", EXEC_MODE); +vm->_exec(code); // Hello, world! +``` + +This `CodeObject_` object is a very non-generic form of the compiled code. +It is an in-memory form. You are not able to save it to a file or load it from a file. + + +### String precompilation + +In order to save the compiled code to a file, you need to use `vm->precompile`. +It does some basic preprocessing and outputs the result as a human-readable string. + +```cpp +// precompile the source code into a string +Str source = vm->precompile("print('Hello, world!')", "", EXEC_MODE); + +CodeObject code = vm->compile(source, "", EXEC_MODE); +vm->_exec(code); // Hello, world! +``` + +You can also use python's `compile` function to achieve the same effect. + +```python +code = compile("print('Hello, world!')", "", "exec") +exec(code) # Hello, world! +``` + +Let's take a look at the precompiled string. +```python +print(code) +``` + +```txt +pkpy:1.4.4 +0 +|print| +=6 +5,1,0, +6,1,5,1,0, +42,1,1, +8,1,1,S48656c6c6f2c20776f726c6421 +43,1,0, +3,1,0, + +``` + +Comparing with **In-memory precompilation**, +**String precompilation** drops most of the original source code. +It has an encryption effect, which can protect your source code from being stolen. +It also means there is no source line information when an error occurs. + +```python +src = """ +def f(a, b): + return g(a, b) + +def g(a, b): + c = f(a, b) + d = g(a, b) + return c + d +""" + +code = compile(src, "", "exec") +exec(code) +f(1, 2) +``` + +You will get this (without source line information): +```txt +Traceback (most recent call last): + File "", line 3, in f + File "", line 6, in g + File "", line 3, in f + File "", line 6, in g + File "", line 3, in f + File "", line 6, in g + File "", line 3, in f +StackOverflowError +``` + +instead of this (with source line information): + +```txt +Traceback (most recent call last): + File "", line 2, in f + return g(a, b) + File "", line 2, in g + c = f(a, b) + File "", line 2, in f + return g(a, b) + File "", line 2, in g + c = f(a, b) + File "", line 2, in f + return g(a, b) + File "", line 2, in g + c = f(a, b) + File "", line 2, in f + return g(a, b) +StackOverflowError +``` diff --git a/tests/94_compile.py b/tests/94_compile.py index fd90e88a..bb9ae4e0 100644 --- a/tests/94_compile.py +++ b/tests/94_compile.py @@ -1,2 +1,16 @@ code = compile("1+2", "", "eval") assert eval(code) == 3 + +src = """ +def f(a, b): + return g(a, b) + +def g(a, b): + c = f(a, b) + d = g(a, b) + return c + d +""" + +code = compile(src, "<12>", "exec") +exec(code) +f(1, 2)