mirror of
https://github.com/pocketpy/pocketpy
synced 2026-02-21 06:50:20 +00:00
Compare commits
15 Commits
3c379402c8
...
8bc7bf3bd7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bc7bf3bd7 | ||
|
|
3c051df06a | ||
|
|
5f8d9fefc3 | ||
|
|
f10cc37c63 | ||
|
|
a1bfebd30c | ||
|
|
f3bf7c6321 | ||
|
|
3e182d5c6b | ||
|
|
d3d83bd126 | ||
|
|
b37d3cae86 | ||
|
|
82bd2838ce | ||
|
|
45f18f8431 | ||
|
|
0bdbf17d46 | ||
|
|
07a65a8f21 | ||
|
|
b4ba0d91d5 | ||
|
|
b775d239a5 |
13
README.md
13
README.md
@ -49,17 +49,13 @@ These platforms are officially tested.
|
|||||||
+ iOS 64-bit
|
+ iOS 64-bit
|
||||||
+ Emscripten 32-bit
|
+ Emscripten 32-bit
|
||||||
+ Raspberry Pi OS 64-bit
|
+ Raspberry Pi OS 64-bit
|
||||||
|
+ [Luckfox Pico SDK](https://github.com/LuckfoxTECH/luckfox-pico) 32-bit
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
You have two options to integrate pkpy into your project.
|
You have two options to integrate pkpy into your project.
|
||||||
|
|
||||||
#### Use the single header file
|
#### Use CMake (Recommended)
|
||||||
|
|
||||||
Download the `pocketpy.h` and `pocketpy.c` on our [GitHub Release](https://github.com/pocketpy/pocketpy/releases) page.
|
|
||||||
And `#include` it in your project.
|
|
||||||
|
|
||||||
#### Use CMake
|
|
||||||
|
|
||||||
Clone the whole repository as a submodule into your project,
|
Clone the whole repository as a submodule into your project,
|
||||||
In your CMakelists.txt, add the following lines:
|
In your CMakelists.txt, add the following lines:
|
||||||
@ -73,6 +69,11 @@ See [CMakeLists.txt](https://github.com/pocketpy/pocketpy/blob/main/CMakeLists.t
|
|||||||
|
|
||||||
It is safe to use `main` branch in production if CI badge is green.
|
It is safe to use `main` branch in production if CI badge is green.
|
||||||
|
|
||||||
|
#### Use the single header file
|
||||||
|
|
||||||
|
Download the `pocketpy.h` and `pocketpy.c` on our [GitHub Release](https://github.com/pocketpy/pocketpy/releases) page.
|
||||||
|
And `#include` it in your project.
|
||||||
|
|
||||||
### Compile Flags
|
### Compile Flags
|
||||||
|
|
||||||
To compile it with your project, these flags must be set:
|
To compile it with your project, these flags must be set:
|
||||||
|
|||||||
@ -12,8 +12,9 @@ output_dir = sys.argv[3]
|
|||||||
def do_compile(src_path, dst_path):
|
def do_compile(src_path, dst_path):
|
||||||
assert os.path.isfile(src_path)
|
assert os.path.isfile(src_path)
|
||||||
cmd = f'{pkpy_exe} --compile "{src_path}" "{dst_path}"'
|
cmd = f'{pkpy_exe} --compile "{src_path}" "{dst_path}"'
|
||||||
print(src_path)
|
if os.system(cmd) != 0:
|
||||||
assert os.system(cmd) == 0
|
print(src_path)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
if os.path.isfile(source_dir):
|
if os.path.isfile(source_dir):
|
||||||
if output_dir.endswith('.py'):
|
if output_dir.endswith('.py'):
|
||||||
|
|||||||
@ -7,6 +7,7 @@ order: 17
|
|||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
pkpy provides a [pybind11](https://pybind11.readthedocs.io/en/stable/) compatible layer which allows users to do convenient bindings.
|
pkpy provides a [pybind11](https://pybind11.readthedocs.io/en/stable/) compatible layer which allows users to do convenient bindings.
|
||||||
|
Header files are located in the `include/pybind11` directory. Make sure you have added `-Iinclude` to your compiler flags.
|
||||||
|
|
||||||
To begin with, use `py::scoped_interpreter guard{}` to start the interpreter before using any Python objects.
|
To begin with, use `py::scoped_interpreter guard{}` to start the interpreter before using any Python objects.
|
||||||
Or explicitly call `py::interpreter::initialize()` and `py::interpreter::finalize()`.
|
Or explicitly call `py::interpreter::initialize()` and `py::interpreter::finalize()`.
|
||||||
|
|||||||
32
docs/features/deploy.md
Normal file
32
docs/features/deploy.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
icon: dot
|
||||||
|
title: Deploy Bytecodes
|
||||||
|
order: 81
|
||||||
|
---
|
||||||
|
|
||||||
|
!!!
|
||||||
|
The feature requires pocketpy version >= `2.1.7`
|
||||||
|
!!!
|
||||||
|
|
||||||
|
You can deploy your pocketpy program as bytecode files, which slightly improves the loading speed of your program.
|
||||||
|
|
||||||
|
It also makes your users unable to get your source code directly, unless they do expensive reverse engineering.
|
||||||
|
|
||||||
|
To compile a `.py` file into a `.pyc` bytecode file, you need the command-line executable `main`,
|
||||||
|
which can be simply built by running `python cmake_build.py` in the repository root.
|
||||||
|
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Once you have `main` executable, you can run the following command to compile `input_file.py`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./main --compile input_file.py output_file.pyc
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can invoke the `compileall.py` script in the repository root.
|
||||||
|
It compiles all `.py` files in the specified directory into `.pyc` files.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python compileall.py ./main input_path output_path
|
||||||
|
```
|
||||||
@ -22,7 +22,7 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
|
|||||||
|
|
||||||
1. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
|
1. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
|
||||||
2. `__slots__` in class definition.
|
2. `__slots__` in class definition.
|
||||||
3. `else` clause in try..except.
|
3. `else` and `finally` clause in try..except.
|
||||||
4. Inplace methods like `__iadd__` and `__imul__`.
|
4. Inplace methods like `__iadd__` and `__imul__`.
|
||||||
5. `__del__` in class definition.
|
5. `__del__` in class definition.
|
||||||
6. Multiple inheritance.
|
6. Multiple inheritance.
|
||||||
|
|||||||
@ -44,6 +44,7 @@ These platforms are officially tested.
|
|||||||
+ iOS 64-bit
|
+ iOS 64-bit
|
||||||
+ Emscripten 32-bit
|
+ Emscripten 32-bit
|
||||||
+ Raspberry Pi OS 64-bit
|
+ Raspberry Pi OS 64-bit
|
||||||
|
+ [Luckfox Pico SDK](https://github.com/LuckfoxTECH/luckfox-pico) 32-bit
|
||||||
|
|
||||||
## Star the repo
|
## Star the repo
|
||||||
|
|
||||||
|
|||||||
12
docs/modules/periphery.md
Normal file
12
docs/modules/periphery.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
icon: package
|
||||||
|
label: periphery
|
||||||
|
---
|
||||||
|
|
||||||
|
!!!
|
||||||
|
This module is optional. Set option `PK_BUILD_MODULE_PERIPHERY` to `ON` in your `CMakeLists.txt` to enable it.
|
||||||
|
!!!
|
||||||
|
|
||||||
|
#### Source code
|
||||||
|
|
||||||
|
:::code source="../../include/typings/periphery.pyi" :::
|
||||||
@ -6,12 +6,7 @@ label: Quick Start
|
|||||||
|
|
||||||
You have two options to integrate pkpy into your project.
|
You have two options to integrate pkpy into your project.
|
||||||
|
|
||||||
#### Use the single header file
|
#### Use CMake (Recommended)
|
||||||
|
|
||||||
Download the `pocketpy.h` and `pocketpy.c` on our [GitHub Release](https://github.com/pocketpy/pocketpy/releases) page.
|
|
||||||
And `#include` it in your project.
|
|
||||||
|
|
||||||
#### Use CMake
|
|
||||||
|
|
||||||
Clone the whole repository as a submodule into your project,
|
Clone the whole repository as a submodule into your project,
|
||||||
In your CMakelists.txt, add the following lines:
|
In your CMakelists.txt, add the following lines:
|
||||||
@ -25,6 +20,11 @@ See [CMakeLists.txt](https://github.com/pocketpy/pocketpy/blob/main/CMakeLists.t
|
|||||||
|
|
||||||
It is safe to use `main` branch in production if CI badge is green.
|
It is safe to use `main` branch in production if CI badge is green.
|
||||||
|
|
||||||
|
#### Use the single header file
|
||||||
|
|
||||||
|
Download the `pocketpy.h` and `pocketpy.c` on our [GitHub Release](https://github.com/pocketpy/pocketpy/releases) page.
|
||||||
|
And `#include` it in your project.
|
||||||
|
|
||||||
### Compile flags
|
### Compile flags
|
||||||
|
|
||||||
To compile it with your project, these flags must be set:
|
To compile it with your project, these flags must be set:
|
||||||
|
|||||||
@ -12,6 +12,7 @@ typedef struct c11_serializer {
|
|||||||
|
|
||||||
void c11_serializer__ctor(c11_serializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver);
|
void c11_serializer__ctor(c11_serializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver);
|
||||||
void c11_serializer__dtor(c11_serializer* self);
|
void c11_serializer__dtor(c11_serializer* self);
|
||||||
|
void c11_serializer__write_mark(c11_serializer* self, char mark);
|
||||||
void c11_serializer__write_cstr(c11_serializer* self, const char*);
|
void c11_serializer__write_cstr(c11_serializer* self, const char*);
|
||||||
void c11_serializer__write_bytes(c11_serializer* self, const void* data, int size);
|
void c11_serializer__write_bytes(c11_serializer* self, const void* data, int size);
|
||||||
void* c11_serializer__submit(c11_serializer* self, int* size);
|
void* c11_serializer__submit(c11_serializer* self, int* size);
|
||||||
@ -27,6 +28,7 @@ typedef struct c11_deserializer {
|
|||||||
|
|
||||||
void c11_deserializer__ctor(c11_deserializer* self, const void* data, int size);
|
void c11_deserializer__ctor(c11_deserializer* self, const void* data, int size);
|
||||||
void c11_deserializer__dtor(c11_deserializer* self);
|
void c11_deserializer__dtor(c11_deserializer* self);
|
||||||
|
void c11_deserializer__consume_mark(c11_deserializer* self, char expected);
|
||||||
bool c11_deserializer__check_header(c11_deserializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver_min);
|
bool c11_deserializer__check_header(c11_deserializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver_min);
|
||||||
const char* c11_deserializer__read_cstr(c11_deserializer* self);
|
const char* c11_deserializer__read_cstr(c11_deserializer* self);
|
||||||
void* c11_deserializer__read_bytes(c11_deserializer* self, int size);
|
void* c11_deserializer__read_bytes(c11_deserializer* self, int size);
|
||||||
|
|||||||
@ -56,6 +56,7 @@ c11_sv c11_sv__slice2(c11_sv sv, int start, int stop);
|
|||||||
c11_sv c11_sv__strip(c11_sv sv, c11_sv chars, bool left, bool right);
|
c11_sv c11_sv__strip(c11_sv sv, c11_sv chars, bool left, bool right);
|
||||||
int c11_sv__index(c11_sv self, char c);
|
int c11_sv__index(c11_sv self, char c);
|
||||||
int c11_sv__rindex(c11_sv self, char c);
|
int c11_sv__rindex(c11_sv self, char c);
|
||||||
|
c11_sv c11_sv__filename(c11_sv self);
|
||||||
int c11_sv__index2(c11_sv self, c11_sv sub, int start);
|
int c11_sv__index2(c11_sv self, c11_sv sub, int start);
|
||||||
int c11_sv__count(c11_sv self, c11_sv sub);
|
int c11_sv__count(c11_sv self, c11_sv sub);
|
||||||
bool c11_sv__startswith(c11_sv self, c11_sv prefix);
|
bool c11_sv__startswith(c11_sv self, c11_sv prefix);
|
||||||
|
|||||||
@ -58,8 +58,8 @@ typedef struct VM {
|
|||||||
int recursion_depth;
|
int recursion_depth;
|
||||||
int max_recursion_depth;
|
int max_recursion_depth;
|
||||||
|
|
||||||
py_TValue reg[8]; // users' registers
|
py_TValue reg[14]; // users' registers
|
||||||
void* ctx; // user-defined context
|
void* ctx; // user-defined context
|
||||||
|
|
||||||
CachedNames cached_names;
|
CachedNames cached_names;
|
||||||
|
|
||||||
|
|||||||
@ -107,8 +107,8 @@ typedef struct FuncDecl {
|
|||||||
RefCounted rc;
|
RefCounted rc;
|
||||||
CodeObject code; // strong ref
|
CodeObject code; // strong ref
|
||||||
|
|
||||||
c11_vector /*T=int*/ args; // indices in co->varnames
|
c11_vector /*T=int32_t*/ args; // indices in co->varnames
|
||||||
c11_vector /*T=KwArg*/ kwargs; // indices in co->varnames
|
c11_vector /*T=FuncDeclKwArg*/ kwargs; // indices in co->varnames
|
||||||
|
|
||||||
int starred_arg; // index in co->varnames, -1 if no *arg
|
int starred_arg; // index in co->varnames, -1 if no *arg
|
||||||
int starred_kwarg; // index in co->varnames, -1 if no **kwarg
|
int starred_kwarg; // index in co->varnames, -1 if no **kwarg
|
||||||
|
|||||||
@ -185,6 +185,8 @@ PK_API bool py_compile(const char* source,
|
|||||||
/// Compile a `.py` file into a `.pyc` file.
|
/// Compile a `.py` file into a `.pyc` file.
|
||||||
PK_API bool py_compilefile(const char* src_path,
|
PK_API bool py_compilefile(const char* src_path,
|
||||||
const char* dst_path) PY_RAISE;
|
const char* dst_path) PY_RAISE;
|
||||||
|
/// Run a compiled code object.
|
||||||
|
PK_API bool py_execo(const void* data, int size, const char* filename, py_Ref module) PY_RAISE PY_RETURN;
|
||||||
/// Run a source string.
|
/// Run a source string.
|
||||||
/// @param source source string.
|
/// @param source source string.
|
||||||
/// @param filename filename (for error messages).
|
/// @param filename filename (for error messages).
|
||||||
@ -439,6 +441,13 @@ PK_API py_GlobalRef py_retval();
|
|||||||
#define py_r6() py_getreg(6)
|
#define py_r6() py_getreg(6)
|
||||||
#define py_r7() py_getreg(7)
|
#define py_r7() py_getreg(7)
|
||||||
|
|
||||||
|
#define py_tmpr0() py_getreg(8)
|
||||||
|
#define py_tmpr1() py_getreg(9)
|
||||||
|
#define py_tmpr2() py_getreg(10)
|
||||||
|
#define py_tmpr3() py_getreg(11)
|
||||||
|
#define py_sysr0() py_getreg(12) // for debugger
|
||||||
|
#define py_sysr1() py_getreg(13) // for pybind11
|
||||||
|
|
||||||
/// Get an item from the object's `__dict__`.
|
/// Get an item from the object's `__dict__`.
|
||||||
/// Return `NULL` if not found.
|
/// Return `NULL` if not found.
|
||||||
PK_API py_ItemRef py_getdict(py_Ref self, py_Name name);
|
PK_API py_ItemRef py_getdict(py_Ref self, py_Name name);
|
||||||
|
|||||||
@ -16,6 +16,7 @@ OPCODE(LOAD_TRUE)
|
|||||||
OPCODE(LOAD_FALSE)
|
OPCODE(LOAD_FALSE)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(LOAD_SMALL_INT)
|
OPCODE(LOAD_SMALL_INT)
|
||||||
|
OPCODE(LOAD_NAME_AS_INT)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(LOAD_ELLIPSIS)
|
OPCODE(LOAD_ELLIPSIS)
|
||||||
OPCODE(LOAD_FUNCTION)
|
OPCODE(LOAD_FUNCTION)
|
||||||
|
|||||||
@ -44,8 +44,7 @@ struct object_pool {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void initialize(int size) noexcept {
|
static void initialize(int size) noexcept {
|
||||||
// use 8th register.
|
pool = py_sysr1();
|
||||||
pool = py_getreg(7);
|
|
||||||
py_newtuple(pool, size);
|
py_newtuple(pool, size);
|
||||||
indices_ = new std::vector<int>(size, 0);
|
indices_ = new std::vector<int>(size, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,12 @@ import sys
|
|||||||
import time
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
pkpy_exe = 'main.exe' if sys.platform == 'win32' else './main'
|
||||||
|
|
||||||
def test_file(filepath, cpython=False):
|
def test_file(filepath, cpython=False):
|
||||||
if cpython:
|
if cpython:
|
||||||
return os.system("python " + filepath) == 0
|
return os.system("python " + filepath) == 0
|
||||||
if sys.platform == 'win32':
|
code = os.system(pkpy_exe + ' ' + filepath)
|
||||||
code = os.system("main.exe " + filepath)
|
|
||||||
else:
|
|
||||||
code = os.system("./main " + filepath)
|
|
||||||
if code != 0:
|
if code != 0:
|
||||||
print('Return code:', code)
|
print('Return code:', code)
|
||||||
return code == 0
|
return code == 0
|
||||||
@ -18,7 +16,7 @@ def test_file(filepath, cpython=False):
|
|||||||
def test_dir(path):
|
def test_dir(path):
|
||||||
print("Testing directory:", path)
|
print("Testing directory:", path)
|
||||||
for filename in sorted(os.listdir(path)):
|
for filename in sorted(os.listdir(path)):
|
||||||
if not filename.endswith('.py'):
|
if not filename.endswith('.py') and not filename.endswith('.pyc'):
|
||||||
continue
|
continue
|
||||||
filepath = os.path.join(path, filename)
|
filepath = os.path.join(path, filename)
|
||||||
print("> " + filepath, flush=True)
|
print("> " + filepath, flush=True)
|
||||||
@ -76,6 +74,8 @@ exit()
|
|||||||
print(res.stdout)
|
print(res.stdout)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
code = os.system(f'python compileall.py {pkpy_exe} tests tmp/tests')
|
||||||
|
assert code == 0
|
||||||
|
|
||||||
if len(sys.argv) == 2:
|
if len(sys.argv) == 2:
|
||||||
assert 'benchmark' in sys.argv[1]
|
assert 'benchmark' in sys.argv[1]
|
||||||
@ -84,5 +84,11 @@ else:
|
|||||||
test_dir('tests/')
|
test_dir('tests/')
|
||||||
test_repl()
|
test_repl()
|
||||||
|
|
||||||
|
if os.path.exists('tmp/tests'):
|
||||||
|
print('-' * 50)
|
||||||
|
time.sleep(3)
|
||||||
|
test_dir('tmp/tests/')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print("ALL TESTS PASSED")
|
print("ALL TESTS PASSED")
|
||||||
|
|||||||
@ -25,6 +25,10 @@ void c11_serializer__dtor(c11_serializer* self){
|
|||||||
c11_vector__dtor(&self->data);
|
c11_vector__dtor(&self->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void c11_serializer__write_mark(c11_serializer *self, char mark) {
|
||||||
|
c11_serializer__write_i8(self, (int8_t)mark);
|
||||||
|
}
|
||||||
|
|
||||||
void c11_serializer__write_cstr(c11_serializer *self, const char* cstr) {
|
void c11_serializer__write_cstr(c11_serializer *self, const char* cstr) {
|
||||||
int len = (int)strlen(cstr);
|
int len = (int)strlen(cstr);
|
||||||
c11_serializer__write_bytes(self, cstr, len + 1);
|
c11_serializer__write_bytes(self, cstr, len + 1);
|
||||||
@ -56,6 +60,13 @@ bool c11_deserializer__error(c11_deserializer* self, const char* msg){
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void c11_deserializer__consume_mark(c11_deserializer* self, char expected) {
|
||||||
|
int8_t mark = c11_deserializer__read_i8(self);
|
||||||
|
if (mark != (int8_t)expected) {
|
||||||
|
c11__abort("internal error: deserialize mark mismatch: expected %c but got %c", expected, (char)mark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool c11_deserializer__check_header(c11_deserializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver_min){
|
bool c11_deserializer__check_header(c11_deserializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver_min){
|
||||||
if(self->size < 8){
|
if(self->size < 8){
|
||||||
return c11_deserializer__error(self, "bad header: size < 8");
|
return c11_deserializer__error(self, "bad header: size < 8");
|
||||||
|
|||||||
@ -89,9 +89,9 @@ void SourceData__snapshot(const struct SourceData* self,
|
|||||||
c11_sbuf__write_cstr(ss, name);
|
c11_sbuf__write_cstr(ss, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
c11_sbuf__write_char(ss, '\n');
|
|
||||||
const char *st = NULL, *ed;
|
const char *st = NULL, *ed;
|
||||||
if(SourceData__get_line(self, lineno, &st, &ed)) {
|
if(SourceData__get_line(self, lineno, &st, &ed)) {
|
||||||
|
c11_sbuf__write_char(ss, '\n');
|
||||||
while(st < ed && isblank(*st))
|
while(st < ed && isblank(*st))
|
||||||
++st;
|
++st;
|
||||||
if(st < ed) {
|
if(st < ed) {
|
||||||
@ -108,5 +108,5 @@ void SourceData__snapshot(const struct SourceData* self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!st) { c11_sbuf__write_cstr(ss, " <?>"); }
|
// if(!st) { c11_sbuf__write_cstr(ss, " <?>"); }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -147,6 +147,14 @@ int c11_sv__rindex(c11_sv self, char c) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c11_sv c11_sv__filename(c11_sv self) {
|
||||||
|
int sep_index_1 = c11_sv__rindex(self, '/');
|
||||||
|
int sep_index_2 = c11_sv__rindex(self, '\\');
|
||||||
|
int sep_index = c11__max(sep_index_1, sep_index_2);
|
||||||
|
if(sep_index == -1) return self;
|
||||||
|
return c11_sv__slice(self, sep_index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
int c11_sv__index2(c11_sv self, c11_sv sub, int start) {
|
int c11_sv__index2(c11_sv self, c11_sv sub, int start) {
|
||||||
if(sub.size == 0) return start;
|
if(sub.size == 0) return start;
|
||||||
int max_end = self.size - sub.size;
|
int max_end = self.size - sub.size;
|
||||||
|
|||||||
@ -78,6 +78,7 @@ int c11_vector__nextcap(c11_vector* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void c11_vector__extend(c11_vector* self, const void* p, int size) {
|
void c11_vector__extend(c11_vector* self, const void* p, int size) {
|
||||||
|
if (size <= 0) return;
|
||||||
int min_capacity = self->length + size;
|
int min_capacity = self->length + size;
|
||||||
if(self->capacity < min_capacity) {
|
if(self->capacity < min_capacity) {
|
||||||
int nextcap = c11_vector__nextcap(self);
|
int nextcap = c11_vector__nextcap(self);
|
||||||
|
|||||||
@ -77,6 +77,7 @@ static int Ctx__enter_block(Ctx* self, CodeBlockType type);
|
|||||||
static void Ctx__exit_block(Ctx* self);
|
static void Ctx__exit_block(Ctx* self);
|
||||||
static int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line);
|
static int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line);
|
||||||
static int Ctx__emit_int(Ctx* self, int64_t value, int line);
|
static int Ctx__emit_int(Ctx* self, int64_t value, int line);
|
||||||
|
static int Ctx__emit_name(Ctx* self, py_Name name, int line);
|
||||||
static void Ctx__patch_jump(Ctx* self, int index);
|
static void Ctx__patch_jump(Ctx* self, int index);
|
||||||
static void Ctx__emit_jump(Ctx* self, int target, int line);
|
static void Ctx__emit_jump(Ctx* self, int target, int line);
|
||||||
static int Ctx__add_varname(Ctx* self, py_Name name);
|
static int Ctx__add_varname(Ctx* self, py_Name name);
|
||||||
@ -1070,7 +1071,12 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
|
|
||||||
c11__foreach(Expr*, &self->args, e) { vtemit_(*e, ctx); }
|
c11__foreach(Expr*, &self->args, e) { vtemit_(*e, ctx); }
|
||||||
c11__foreach(CallExprKwArg, &self->kwargs, e) {
|
c11__foreach(CallExprKwArg, &self->kwargs, e) {
|
||||||
Ctx__emit_int(ctx, (uintptr_t)e->key, self->line);
|
if(e->key == 0) {
|
||||||
|
// special key for **kwargs
|
||||||
|
Ctx__emit_int(ctx, 0, self->line);
|
||||||
|
} else {
|
||||||
|
Ctx__emit_name(ctx, e->key, self->line);
|
||||||
|
}
|
||||||
vtemit_(e->val, ctx);
|
vtemit_(e->val, ctx);
|
||||||
}
|
}
|
||||||
int KWARGC = self->kwargs.length;
|
int KWARGC = self->kwargs.length;
|
||||||
@ -1196,6 +1202,12 @@ static int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int Ctx__emit_name(Ctx* self, py_Name name, int line) {
|
||||||
|
int index = Ctx__add_name(self, name);
|
||||||
|
assert(index <= UINT16_MAX);
|
||||||
|
return Ctx__emit_(self, OP_LOAD_NAME_AS_INT, (uint16_t)index, line);
|
||||||
|
}
|
||||||
|
|
||||||
static void Ctx__patch_jump(Ctx* self, int index) {
|
static void Ctx__patch_jump(Ctx* self, int index) {
|
||||||
Bytecode* co_codes = (Bytecode*)self->co->codes.data;
|
Bytecode* co_codes = (Bytecode*)self->co->codes.data;
|
||||||
int target = self->co->codes.length;
|
int target = self->co->codes.length;
|
||||||
@ -1214,7 +1226,10 @@ static int Ctx__add_varname(Ctx* self, py_Name name) {
|
|||||||
return CodeObject__add_varname(self->co, name);
|
return CodeObject__add_varname(self->co, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Ctx__add_name(Ctx* self, py_Name name) { return CodeObject__add_name(self->co, name); }
|
static int Ctx__add_name(Ctx* self, py_Name name) {
|
||||||
|
assert(name != 0);
|
||||||
|
return CodeObject__add_name(self->co, name);
|
||||||
|
}
|
||||||
|
|
||||||
static int Ctx__add_const_string(Ctx* self, c11_sv key) {
|
static int Ctx__add_const_string(Ctx* self, c11_sv key) {
|
||||||
if(key.size > 100) {
|
if(key.size > 100) {
|
||||||
|
|||||||
@ -46,7 +46,7 @@ static struct c11_debugger {
|
|||||||
c11_vector py_frames;
|
c11_vector py_frames;
|
||||||
c11_smallmap_d2index scopes_query_cache;
|
c11_smallmap_d2index scopes_query_cache;
|
||||||
|
|
||||||
#define python_vars py_r7()
|
#define python_vars py_sysr0()
|
||||||
|
|
||||||
} debugger;
|
} debugger;
|
||||||
|
|
||||||
|
|||||||
@ -189,6 +189,11 @@ __NEXT_STEP:
|
|||||||
py_newint(SP()++, (int16_t)byte.arg);
|
py_newint(SP()++, (int16_t)byte.arg);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
case OP_LOAD_NAME_AS_INT: {
|
||||||
|
py_Name name = co_names[byte.arg];
|
||||||
|
py_newint(SP()++, (uintptr_t)name);
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_LOAD_ELLIPSIS: {
|
case OP_LOAD_ELLIPSIS: {
|
||||||
py_newellipsis(SP()++);
|
py_newellipsis(SP()++);
|
||||||
|
|||||||
@ -99,6 +99,8 @@ void VM__ctor(VM* self) {
|
|||||||
self->recursion_depth = 0;
|
self->recursion_depth = 0;
|
||||||
self->max_recursion_depth = 1000;
|
self->max_recursion_depth = 1000;
|
||||||
|
|
||||||
|
memset(self->reg, 0, sizeof(self->reg));
|
||||||
|
|
||||||
self->ctx = NULL;
|
self->ctx = NULL;
|
||||||
self->curr_class = NULL;
|
self->curr_class = NULL;
|
||||||
self->curr_decl_based_function = NULL;
|
self->curr_decl_based_function = NULL;
|
||||||
|
|||||||
@ -114,10 +114,8 @@ py_Ref py_name2ref(py_Name name) {
|
|||||||
py_Ref res = CachedNames__try_get(d, name);
|
py_Ref res = CachedNames__try_get(d, name);
|
||||||
if(res != NULL) return res;
|
if(res != NULL) return res;
|
||||||
// not found, create a new one
|
// not found, create a new one
|
||||||
py_StackRef tmp = py_pushtmp();
|
py_newstrv(py_tmpr0(), py_name2sv(name));
|
||||||
py_newstrv(tmp, py_name2sv(name));
|
CachedNames__set(d, name, py_tmpr0());
|
||||||
CachedNames__set(d, name, tmp);
|
|
||||||
py_pop();
|
|
||||||
return CachedNames__try_get(d, name);
|
return CachedNames__try_get(d, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -72,7 +72,7 @@ static bool disassemble(CodeObject* co) {
|
|||||||
pk_sprintf(&ss, " (%q)", py_tosv(path));
|
pk_sprintf(&ss, " (%q)", py_tosv(path));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_LOAD_NAME:
|
case OP_LOAD_NAME: case OP_LOAD_NAME_AS_INT:
|
||||||
case OP_LOAD_GLOBAL:
|
case OP_LOAD_GLOBAL:
|
||||||
case OP_LOAD_NONLOCAL:
|
case OP_LOAD_NONLOCAL:
|
||||||
case OP_STORE_GLOBAL:
|
case OP_STORE_GLOBAL:
|
||||||
|
|||||||
@ -19,7 +19,6 @@ static void CodeObject__serialize(c11_serializer* s,
|
|||||||
static CodeObject CodeObject__deserialize(c11_deserializer* d, const char* filename, SourceData_ embedded_src);
|
static CodeObject CodeObject__deserialize(c11_deserializer* d, const char* filename, SourceData_ embedded_src);
|
||||||
|
|
||||||
// Serialize a py_TValue constant
|
// Serialize a py_TValue constant
|
||||||
// Supported types: None, int, float, bool, str, bytes, tuple, Ellipsis
|
|
||||||
static void TValue__serialize(c11_serializer* s, py_Ref val) {
|
static void TValue__serialize(c11_serializer* s, py_Ref val) {
|
||||||
c11_serializer__write_type(s, val->type);
|
c11_serializer__write_type(s, val->type);
|
||||||
// 1. co_consts: int | float | str
|
// 1. co_consts: int | float | str
|
||||||
@ -116,33 +115,43 @@ static void CodeObject__serialize(c11_serializer* s,
|
|||||||
// codes
|
// codes
|
||||||
_Static_assert(sizeof(Bytecode) == sizeof(uint16_t) * 2, "");
|
_Static_assert(sizeof(Bytecode) == sizeof(uint16_t) * 2, "");
|
||||||
c11_serializer__write_i32(s, co->codes.length);
|
c11_serializer__write_i32(s, co->codes.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
c11_serializer__write_bytes(s, co->codes.data, co->codes.length * sizeof(Bytecode));
|
c11_serializer__write_bytes(s, co->codes.data, co->codes.length * sizeof(Bytecode));
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// codes_ex
|
// codes_ex
|
||||||
_Static_assert(sizeof(BytecodeEx) == sizeof(int32_t) * 2, "");
|
_Static_assert(sizeof(BytecodeEx) == sizeof(int32_t) * 2, "");
|
||||||
c11_serializer__write_i32(s, co->codes_ex.length);
|
c11_serializer__write_i32(s, co->codes_ex.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
c11_serializer__write_bytes(s, co->codes_ex.data, co->codes_ex.length * sizeof(BytecodeEx));
|
c11_serializer__write_bytes(s, co->codes_ex.data, co->codes_ex.length * sizeof(BytecodeEx));
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// consts
|
// consts
|
||||||
c11_serializer__write_i32(s, co->consts.length);
|
c11_serializer__write_i32(s, co->consts.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
for(int i = 0; i < co->consts.length; i++) {
|
for(int i = 0; i < co->consts.length; i++) {
|
||||||
py_Ref val = c11__at(py_TValue, &co->consts, i);
|
py_Ref val = c11__at(py_TValue, &co->consts, i);
|
||||||
TValue__serialize(s, val);
|
TValue__serialize(s, val);
|
||||||
}
|
}
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// varnames (as cstr via py_name2str)
|
// varnames (as cstr via py_name2str)
|
||||||
c11_serializer__write_i32(s, co->varnames.length);
|
c11_serializer__write_i32(s, co->varnames.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
for(int i = 0; i < co->varnames.length; i++) {
|
for(int i = 0; i < co->varnames.length; i++) {
|
||||||
py_Name name = c11__getitem(py_Name, &co->varnames, i);
|
py_Name name = c11__getitem(py_Name, &co->varnames, i);
|
||||||
c11_serializer__write_cstr(s, py_name2str(name));
|
c11_serializer__write_cstr(s, py_name2str(name));
|
||||||
}
|
}
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// names (as cstr via py_name2str)
|
// names (as cstr via py_name2str)
|
||||||
c11_serializer__write_i32(s, co->names.length);
|
c11_serializer__write_i32(s, co->names.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
for(int i = 0; i < co->names.length; i++) {
|
for(int i = 0; i < co->names.length; i++) {
|
||||||
py_Name name = c11__getitem(py_Name, &co->names, i);
|
py_Name name = c11__getitem(py_Name, &co->names, i);
|
||||||
c11_serializer__write_cstr(s, py_name2str(name));
|
c11_serializer__write_cstr(s, py_name2str(name));
|
||||||
}
|
}
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// nlocals
|
// nlocals
|
||||||
c11_serializer__write_i32(s, co->nlocals);
|
c11_serializer__write_i32(s, co->nlocals);
|
||||||
@ -150,14 +159,19 @@ static void CodeObject__serialize(c11_serializer* s,
|
|||||||
// blocks
|
// blocks
|
||||||
_Static_assert(sizeof(CodeBlock) == sizeof(int32_t) * 5, "");
|
_Static_assert(sizeof(CodeBlock) == sizeof(int32_t) * 5, "");
|
||||||
c11_serializer__write_i32(s, co->blocks.length);
|
c11_serializer__write_i32(s, co->blocks.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
c11_serializer__write_bytes(s, co->blocks.data, co->blocks.length * sizeof(CodeBlock));
|
c11_serializer__write_bytes(s, co->blocks.data, co->blocks.length * sizeof(CodeBlock));
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// func_decls
|
// func_decls
|
||||||
c11_serializer__write_i32(s, co->func_decls.length);
|
c11_serializer__write_i32(s, co->func_decls.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
for(int i = 0; i < co->func_decls.length; i++) {
|
for(int i = 0; i < co->func_decls.length; i++) {
|
||||||
const FuncDecl* decl = c11__getitem(FuncDecl_, &co->func_decls, i);
|
const FuncDecl* decl = c11__getitem(FuncDecl_, &co->func_decls, i);
|
||||||
FuncDecl__serialize(s, decl, co->src);
|
FuncDecl__serialize(s, decl, co->src);
|
||||||
|
c11_serializer__write_mark(s, '|');
|
||||||
}
|
}
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// start_line, end_line
|
// start_line, end_line
|
||||||
c11_serializer__write_i32(s, co->start_line);
|
c11_serializer__write_i32(s, co->start_line);
|
||||||
@ -191,54 +205,70 @@ static CodeObject CodeObject__deserialize(c11_deserializer* d, const char* filen
|
|||||||
|
|
||||||
// codes
|
// codes
|
||||||
int codes_len = c11_deserializer__read_i32(d);
|
int codes_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
c11_vector__extend(&co.codes,
|
c11_vector__extend(&co.codes,
|
||||||
c11_deserializer__read_bytes(d, codes_len * sizeof(Bytecode)),
|
c11_deserializer__read_bytes(d, codes_len * sizeof(Bytecode)),
|
||||||
codes_len);
|
codes_len);
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
// codes_ex
|
// codes_ex
|
||||||
int codes_ex_len = c11_deserializer__read_i32(d);
|
int codes_ex_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
c11_vector__extend(&co.codes_ex,
|
c11_vector__extend(&co.codes_ex,
|
||||||
c11_deserializer__read_bytes(d, codes_ex_len * sizeof(BytecodeEx)),
|
c11_deserializer__read_bytes(d, codes_ex_len * sizeof(BytecodeEx)),
|
||||||
codes_ex_len);
|
codes_ex_len);
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
|
|
||||||
// consts
|
// consts
|
||||||
int consts_len = c11_deserializer__read_i32(d);
|
int consts_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
for(int i = 0; i < consts_len; i++) {
|
for(int i = 0; i < consts_len; i++) {
|
||||||
py_Ref p_val = c11_vector__emplace(&co.consts);
|
py_Ref p_val = c11_vector__emplace(&co.consts);
|
||||||
TValue__deserialize(d, p_val);
|
TValue__deserialize(d, p_val);
|
||||||
}
|
}
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
|
|
||||||
// varnames
|
// varnames
|
||||||
int varnames_len = c11_deserializer__read_i32(d);
|
int varnames_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
for(int i = 0; i < varnames_len; i++) {
|
for(int i = 0; i < varnames_len; i++) {
|
||||||
const char* s = c11_deserializer__read_cstr(d);
|
const char* s = c11_deserializer__read_cstr(d);
|
||||||
py_Name n = py_name(s);
|
py_Name n = py_name(s);
|
||||||
c11_vector__push(py_Name, &co.varnames, n);
|
c11_vector__push(py_Name, &co.varnames, n);
|
||||||
c11_smallmap_n2d__set(&co.varnames_inv, n, i);
|
c11_smallmap_n2d__set(&co.varnames_inv, n, i);
|
||||||
}
|
}
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
|
|
||||||
// names
|
// names
|
||||||
int names_len = c11_deserializer__read_i32(d);
|
int names_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
for(int i = 0; i < names_len; i++) {
|
for(int i = 0; i < names_len; i++) {
|
||||||
const char* s = c11_deserializer__read_cstr(d);
|
const char* s = c11_deserializer__read_cstr(d);
|
||||||
py_Name n = py_name(s);
|
py_Name n = py_name(s);
|
||||||
c11_vector__push(py_Name, &co.names, n);
|
c11_vector__push(py_Name, &co.names, n);
|
||||||
c11_smallmap_n2d__set(&co.names_inv, n, i);
|
c11_smallmap_n2d__set(&co.names_inv, n, i);
|
||||||
}
|
}
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
|
|
||||||
// nlocals
|
// nlocals
|
||||||
co.nlocals = c11_deserializer__read_i32(d);
|
co.nlocals = c11_deserializer__read_i32(d);
|
||||||
|
|
||||||
// blocks
|
// blocks
|
||||||
int blocks_len = c11_deserializer__read_i32(d);
|
int blocks_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
c11_vector__extend(&co.blocks,
|
c11_vector__extend(&co.blocks,
|
||||||
c11_deserializer__read_bytes(d, blocks_len * sizeof(CodeBlock)),
|
c11_deserializer__read_bytes(d, blocks_len * sizeof(CodeBlock)),
|
||||||
blocks_len);
|
blocks_len);
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
|
|
||||||
// func_decls
|
// func_decls
|
||||||
int func_decls_len = c11_deserializer__read_i32(d);
|
int func_decls_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
for(int i = 0; i < func_decls_len; i++) {
|
for(int i = 0; i < func_decls_len; i++) {
|
||||||
FuncDecl_ decl = FuncDecl__deserialize(d, src);
|
FuncDecl_ decl = FuncDecl__deserialize(d, src);
|
||||||
c11_vector__push(FuncDecl_, &co.func_decls, decl);
|
c11_vector__push(FuncDecl_, &co.func_decls, decl);
|
||||||
|
c11_deserializer__consume_mark(d, '|');
|
||||||
}
|
}
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
|
|
||||||
// start_line, end_line
|
// start_line, end_line
|
||||||
co.start_line = c11_deserializer__read_i32(d);
|
co.start_line = c11_deserializer__read_i32(d);
|
||||||
@ -252,20 +282,26 @@ static void FuncDecl__serialize(c11_serializer* s,
|
|||||||
const FuncDecl* decl,
|
const FuncDecl* decl,
|
||||||
const struct SourceData* parent_src) {
|
const struct SourceData* parent_src) {
|
||||||
// CodeObject (embedded)
|
// CodeObject (embedded)
|
||||||
|
c11_serializer__write_mark(s, '{');
|
||||||
CodeObject__serialize(s, &decl->code, parent_src);
|
CodeObject__serialize(s, &decl->code, parent_src);
|
||||||
|
c11_serializer__write_mark(s, '}');
|
||||||
|
|
||||||
// args
|
// args
|
||||||
c11_serializer__write_i32(s, decl->args.length);
|
c11_serializer__write_i32(s, decl->args.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
c11_serializer__write_bytes(s, decl->args.data, decl->args.length * sizeof(int32_t));
|
c11_serializer__write_bytes(s, decl->args.data, decl->args.length * sizeof(int32_t));
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// kwargs
|
// kwargs
|
||||||
c11_serializer__write_i32(s, decl->kwargs.length);
|
c11_serializer__write_i32(s, decl->kwargs.length);
|
||||||
|
c11_serializer__write_mark(s, '[');
|
||||||
for(int i = 0; i < decl->kwargs.length; i++) {
|
for(int i = 0; i < decl->kwargs.length; i++) {
|
||||||
FuncDeclKwArg* kw = c11__at(FuncDeclKwArg, &decl->kwargs, i);
|
FuncDeclKwArg* kw = c11__at(FuncDeclKwArg, &decl->kwargs, i);
|
||||||
c11_serializer__write_i32(s, kw->index);
|
c11_serializer__write_i32(s, kw->index);
|
||||||
c11_serializer__write_cstr(s, py_name2str(kw->key));
|
c11_serializer__write_cstr(s, py_name2str(kw->key));
|
||||||
TValue__serialize(s, &kw->value);
|
TValue__serialize(s, &kw->value);
|
||||||
}
|
}
|
||||||
|
c11_serializer__write_mark(s, ']');
|
||||||
|
|
||||||
// starred_arg, starred_kwarg
|
// starred_arg, starred_kwarg
|
||||||
c11_serializer__write_i32(s, decl->starred_arg);
|
c11_serializer__write_i32(s, decl->starred_arg);
|
||||||
@ -285,7 +321,7 @@ static void FuncDecl__serialize(c11_serializer* s,
|
|||||||
|
|
||||||
// Deserialize FuncDecl
|
// Deserialize FuncDecl
|
||||||
static FuncDecl_ FuncDecl__deserialize(c11_deserializer* d, SourceData_ embedded_src) {
|
static FuncDecl_ FuncDecl__deserialize(c11_deserializer* d, SourceData_ embedded_src) {
|
||||||
FuncDecl* self = PK_MALLOC(sizeof(FuncDecl));
|
FuncDecl_ self = PK_MALLOC(sizeof(FuncDecl));
|
||||||
self->rc.count = 1;
|
self->rc.count = 1;
|
||||||
self->rc.dtor = (void (*)(void*))FuncDecl__dtor;
|
self->rc.dtor = (void (*)(void*))FuncDecl__dtor;
|
||||||
|
|
||||||
@ -294,16 +330,21 @@ static FuncDecl_ FuncDecl__deserialize(c11_deserializer* d, SourceData_ embedded
|
|||||||
c11_smallmap_n2d__ctor(&self->kw_to_index);
|
c11_smallmap_n2d__ctor(&self->kw_to_index);
|
||||||
|
|
||||||
// CodeObject (embedded)
|
// CodeObject (embedded)
|
||||||
|
c11_deserializer__consume_mark(d, '{');
|
||||||
self->code = CodeObject__deserialize(d, NULL, embedded_src);
|
self->code = CodeObject__deserialize(d, NULL, embedded_src);
|
||||||
|
c11_deserializer__consume_mark(d, '}');
|
||||||
|
|
||||||
// args
|
// args
|
||||||
int args_len = c11_deserializer__read_i32(d);
|
int args_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
c11_vector__extend(&self->args,
|
c11_vector__extend(&self->args,
|
||||||
c11_deserializer__read_bytes(d, args_len * sizeof(int32_t)),
|
c11_deserializer__read_bytes(d, args_len * sizeof(int32_t)),
|
||||||
args_len);
|
args_len);
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
|
|
||||||
// kwargs
|
// kwargs
|
||||||
int kwargs_len = c11_deserializer__read_i32(d);
|
int kwargs_len = c11_deserializer__read_i32(d);
|
||||||
|
c11_deserializer__consume_mark(d, '[');
|
||||||
for(int i = 0; i < kwargs_len; i++) {
|
for(int i = 0; i < kwargs_len; i++) {
|
||||||
FuncDeclKwArg* kw = c11_vector__emplace(&self->kwargs);
|
FuncDeclKwArg* kw = c11_vector__emplace(&self->kwargs);
|
||||||
kw->index = c11_deserializer__read_i32(d);
|
kw->index = c11_deserializer__read_i32(d);
|
||||||
@ -312,6 +353,8 @@ static FuncDecl_ FuncDecl__deserialize(c11_deserializer* d, SourceData_ embedded
|
|||||||
TValue__deserialize(d, &kw->value);
|
TValue__deserialize(d, &kw->value);
|
||||||
c11_smallmap_n2d__set(&self->kw_to_index, kw->key, kw->index);
|
c11_smallmap_n2d__set(&self->kw_to_index, kw->key, kw->index);
|
||||||
}
|
}
|
||||||
|
c11_deserializer__consume_mark(d, ']');
|
||||||
|
|
||||||
// starred_arg
|
// starred_arg
|
||||||
self->starred_arg = c11_deserializer__read_i32(d);
|
self->starred_arg = c11_deserializer__read_i32(d);
|
||||||
// starred_kwarg
|
// starred_kwarg
|
||||||
|
|||||||
@ -149,6 +149,20 @@ bool py_exec(const char* source, const char* filename, enum py_CompileMode mode,
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool py_execo(const void* data, int size, const char* filename, py_Ref module) {
|
||||||
|
CodeObject co;
|
||||||
|
char* err = CodeObject__loads(data, size, filename, &co);
|
||||||
|
if(err == NULL) {
|
||||||
|
c11__rtassert(co.src->mode == EXEC_MODE);
|
||||||
|
c11__rtassert(co.src->is_dynamic == false);
|
||||||
|
bool ok = pk_exec(&co, module);
|
||||||
|
CodeObject__dtor(&co);
|
||||||
|
return ok;
|
||||||
|
} else {
|
||||||
|
return RuntimeError("bad code object %s: %s", filename, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool py_eval(const char* source, py_Ref module) {
|
bool py_eval(const char* source, py_Ref module) {
|
||||||
return py_exec(source, "<string>", EVAL_MODE, module);
|
return py_exec(source, "<string>", EVAL_MODE, module);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#include "pocketpy/interpreter/vm.h"
|
#include "pocketpy/interpreter/vm.h"
|
||||||
|
|
||||||
py_Ref py_getreg(int i) { return pk_current_vm->reg + i; }
|
PK_INLINE py_Ref py_getreg(int i) { return pk_current_vm->reg + i; }
|
||||||
|
|
||||||
void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; }
|
PK_INLINE void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; }
|
||||||
|
|
||||||
PK_INLINE py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
PK_INLINE py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||||
|
|
||||||
|
|||||||
@ -78,8 +78,10 @@ int py_import(const char* path_cstr) {
|
|||||||
while(dot_count < path.size && path.data[dot_count] == '.')
|
while(dot_count < path.size && path.data[dot_count] == '.')
|
||||||
dot_count++;
|
dot_count++;
|
||||||
|
|
||||||
c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename);
|
// */__init__.py[c]
|
||||||
int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
|
c11_sv top_filepath = c11_string__sv(vm->top_frame->co->src->filename);
|
||||||
|
c11_sv top_filename = c11_sv__filename(top_filepath);
|
||||||
|
int is_init = c11__sveq2(top_filename, "__init__.py") || c11__sveq2(top_filename, "__init__.pyc");
|
||||||
|
|
||||||
py_ModuleInfo* mi = py_touserdata(vm->top_frame->module);
|
py_ModuleInfo* mi = py_touserdata(vm->top_frame->module);
|
||||||
c11_sv package_sv = c11_string__sv(mi->path);
|
c11_sv package_sv = c11_string__sv(mi->path);
|
||||||
@ -186,20 +188,10 @@ __SUCCESS:
|
|||||||
|
|
||||||
bool ok;
|
bool ok;
|
||||||
if(is_pyc) {
|
if(is_pyc) {
|
||||||
CodeObject co;
|
ok = py_execo(data, data_size, filename->data, mod);
|
||||||
char* err = CodeObject__loads(data, data_size, filename->data, &co);
|
|
||||||
if(err == NULL) {
|
|
||||||
c11__rtassert(co.src->mode == EXEC_MODE);
|
|
||||||
c11__rtassert(co.src->is_dynamic == false);
|
|
||||||
ok = pk_exec(&co, mod);
|
|
||||||
} else {
|
|
||||||
RuntimeError("failed to load %s: %s", filename->data, err);
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ok = py_exec(data, filename->data, EXEC_MODE, mod);
|
ok = py_exec(data, filename->data, EXEC_MODE, mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
py_assign(py_retval(), mod);
|
py_assign(py_retval(), mod);
|
||||||
|
|
||||||
c11_string__delete(filename);
|
c11_string__delete(filename);
|
||||||
|
|||||||
51
src2/main.c
51
src2/main.c
@ -9,18 +9,17 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static char* read_file(const char* path) {
|
static char* readfile(const char* path, int* data_size) {
|
||||||
FILE* file = fopen(path, "rb");
|
FILE* f = fopen(path, "rb");
|
||||||
if(file == NULL) {
|
if(f == NULL) return NULL;
|
||||||
printf("Error: file not found\n");
|
fseek(f, 0, SEEK_END);
|
||||||
return NULL;
|
long size = ftell(f);
|
||||||
}
|
fseek(f, 0, SEEK_SET);
|
||||||
fseek(file, 0, SEEK_END);
|
|
||||||
long size = ftell(file);
|
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
char* buffer = PK_MALLOC(size + 1);
|
char* buffer = PK_MALLOC(size + 1);
|
||||||
size = fread(buffer, 1, size, file);
|
size = fread(buffer, 1, size, f);
|
||||||
buffer[size] = 0;
|
buffer[size] = 0;
|
||||||
|
fclose(f);
|
||||||
|
if(data_size) *data_size = (int)size;
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,9 +114,28 @@ int main(int argc, char** argv) {
|
|||||||
if(profile) py_profiler_begin();
|
if(profile) py_profiler_begin();
|
||||||
if(debug) py_debugger_waitforattach("127.0.0.1", 6110);
|
if(debug) py_debugger_waitforattach("127.0.0.1", 6110);
|
||||||
|
|
||||||
char* source = read_file(filename);
|
int data_size;
|
||||||
if(source) {
|
char* data = readfile(filename, &data_size);
|
||||||
if(!py_exec(source, filename, EXEC_MODE, NULL)) py_printexc();
|
// check filename endswith .pyc
|
||||||
|
bool is_pyc = false;
|
||||||
|
int filename_len = (int)strlen(filename);
|
||||||
|
if(filename_len >= 4) {
|
||||||
|
if(filename[filename_len - 4] == '.' &&
|
||||||
|
filename[filename_len - 3] == 'p' &&
|
||||||
|
filename[filename_len - 2] == 'y' &&
|
||||||
|
filename[filename_len - 1] == 'c') {
|
||||||
|
is_pyc = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data) {
|
||||||
|
bool ok;
|
||||||
|
if(is_pyc) {
|
||||||
|
ok = py_execo(data, data_size, filename, NULL);
|
||||||
|
} else {
|
||||||
|
ok = py_exec(data, filename, EXEC_MODE, NULL);
|
||||||
|
}
|
||||||
|
if(!ok) py_printexc();
|
||||||
|
|
||||||
if(profile) {
|
if(profile) {
|
||||||
char* json_report = py_profiler_report();
|
char* json_report = py_profiler_report();
|
||||||
@ -128,8 +146,11 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
PK_FREE(json_report);
|
PK_FREE(json_report);
|
||||||
}
|
}
|
||||||
|
PK_FREE(data);
|
||||||
PK_FREE(source);
|
} else {
|
||||||
|
printf("Error: cannot open file '%s'\n", filename);
|
||||||
|
py_finalize();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,14 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
os.chdir('tests')
|
import sys
|
||||||
|
is_pyc = sys.argv[0].endswith('.pyc')
|
||||||
|
|
||||||
|
if is_pyc:
|
||||||
|
os.chdir('tmp/tests')
|
||||||
|
else:
|
||||||
|
os.chdir('tests')
|
||||||
|
|
||||||
assert os.getcwd().endswith('tests')
|
assert os.getcwd().endswith('tests')
|
||||||
|
|
||||||
import test1
|
import test1
|
||||||
@ -49,8 +56,11 @@ from math import (
|
|||||||
cos
|
cos
|
||||||
)
|
)
|
||||||
|
|
||||||
# test reload (dummy)
|
|
||||||
import importlib
|
|
||||||
importlib.reload(test2.a)
|
|
||||||
|
|
||||||
assert __import__('math').pi > 3
|
assert __import__('math').pi > 3
|
||||||
|
|
||||||
|
# test reload (dummy)
|
||||||
|
if not is_pyc:
|
||||||
|
import importlib
|
||||||
|
importlib.reload(test2.a)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
filename = 'tests/801_sys.py'
|
assert (sys.argv in [
|
||||||
assert (sys.argv == [filename]), sys.argv
|
['tests/801_sys.py'],
|
||||||
|
['tmp/tests/801_sys.pyc'],
|
||||||
|
]), sys.argv
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
import traceback
|
import traceback
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.argv[0].endswith('.pyc'):
|
||||||
|
exit()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
a = {'123': 4}
|
a = {'123': 4}
|
||||||
@ -7,7 +11,7 @@ except KeyError:
|
|||||||
actual = traceback.format_exc()
|
actual = traceback.format_exc()
|
||||||
|
|
||||||
expected = '''Traceback (most recent call last):
|
expected = '''Traceback (most recent call last):
|
||||||
File "tests/802_traceback.py", line 5
|
File "tests/802_traceback.py", line 9
|
||||||
b = a[6]
|
b = a[6]
|
||||||
KeyError: 6'''
|
KeyError: 6'''
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user