mirror of
https://github.com/pocketpy/pocketpy
synced 2026-03-01 10:50:18 +00:00
Compare commits
1 Commits
657e54d2f7
...
e2286ad90f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2286ad90f |
2
.gitignore
vendored
2
.gitignore
vendored
@ -42,5 +42,3 @@ docs/C-API/functions.md
|
|||||||
cmake-build-*
|
cmake-build-*
|
||||||
tmp/
|
tmp/
|
||||||
profiler_report.json
|
profiler_report.json
|
||||||
|
|
||||||
tmp/
|
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2026 blueloveTH
|
Copyright (c) 2025 blueloveTH
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
15
README.md
15
README.md
@ -49,15 +49,17 @@ 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
|
|
||||||
|
|
||||||
On Windows platform, only MSVC compiler is officially supported.
|
|
||||||
|
|
||||||
## 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 CMake (Recommended)
|
#### 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.
|
||||||
|
|
||||||
|
#### 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:
|
||||||
@ -71,11 +73,6 @@ 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:
|
||||||
|
|||||||
@ -11,7 +11,7 @@ ROOT = 'include/pocketpy'
|
|||||||
PUBLIC_HEADERS = ['config.h', 'export.h', 'vmath.h', 'pocketpy.h']
|
PUBLIC_HEADERS = ['config.h', 'export.h', 'vmath.h', 'pocketpy.h']
|
||||||
|
|
||||||
COPYRIGHT = '''/*
|
COPYRIGHT = '''/*
|
||||||
* Copyright (c) 2026 blueloveTH
|
* Copyright (c) 2025 blueloveTH
|
||||||
* Distributed Under The MIT License
|
* Distributed Under The MIT License
|
||||||
* https://github.com/pocketpy/pocketpy
|
* https://github.com/pocketpy/pocketpy
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
if len(sys.argv) != 4:
|
|
||||||
print('Usage: python compileall.py <pocketpy_executable> <source_dir> <output_dir>')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
pkpy_exe = sys.argv[1]
|
|
||||||
source_dir = sys.argv[2]
|
|
||||||
output_dir = sys.argv[3]
|
|
||||||
|
|
||||||
def do_compile(src_path, dst_path):
|
|
||||||
assert os.path.isfile(src_path)
|
|
||||||
cmd = f'{pkpy_exe} --compile "{src_path}" "{dst_path}"'
|
|
||||||
if os.system(cmd) != 0:
|
|
||||||
print(src_path)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if os.path.isfile(source_dir):
|
|
||||||
if output_dir.endswith('.py'):
|
|
||||||
output_dir += 'c'
|
|
||||||
do_compile(source_dir, output_dir)
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
for root, _, files in os.walk(source_dir):
|
|
||||||
for file in files:
|
|
||||||
if not file.endswith('.py'):
|
|
||||||
continue
|
|
||||||
src_path = os.path.join(root, file)
|
|
||||||
dst_path = os.path.join(
|
|
||||||
output_dir,
|
|
||||||
os.path.relpath(root, source_dir),
|
|
||||||
file + 'c'
|
|
||||||
)
|
|
||||||
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
|
|
||||||
do_compile(src_path, dst_path)
|
|
||||||
@ -7,7 +7,6 @@ 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()`.
|
||||||
|
|||||||
@ -1,53 +0,0 @@
|
|||||||
---
|
|
||||||
icon: dot
|
|
||||||
title: Deploy Bytecodes
|
|
||||||
order: 81
|
|
||||||
---
|
|
||||||
|
|
||||||
!!!
|
|
||||||
The feature requires pocketpy version >= `2.1.7`
|
|
||||||
!!!
|
|
||||||
|
|
||||||
You can deploy your pocketpy program as `.pyc` files, which are compiled bytecodes with necessary metadata.
|
|
||||||
This 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running `.pyc` files
|
|
||||||
|
|
||||||
The command-line executable `main` can run `.pyc` files directly:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./main output_file.pyc
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are using C-APIs, you can use the `py_execo()` function.
|
|
||||||
|
|
||||||
```c
|
|
||||||
/// 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;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Trackback Support
|
|
||||||
|
|
||||||
Since `.pyc` files do not contain raw sources,
|
|
||||||
trackbacks will show line numbers but not the actual source code lines.
|
|
||||||
@ -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` and `finally` clause in try..except.
|
3. `else` 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.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
icon: dot
|
icon: dot
|
||||||
title: Compute Threads
|
title: Threading
|
||||||
---
|
---
|
||||||
|
|
||||||
pocketpy organizes its state by `VM` structure.
|
pocketpy organizes its state by `VM` structure.
|
||||||
|
|||||||
@ -44,9 +44,6 @@ 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
|
|
||||||
|
|
||||||
On Windows platform, only MSVC compiler is officially supported.
|
|
||||||
|
|
||||||
## Star the repo
|
## Star the repo
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ pkpy is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
|||||||
```
|
```
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2026 blueloveTH
|
Copyright (c) 2025 blueloveTH
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
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,7 +6,12 @@ label: Quick Start
|
|||||||
|
|
||||||
You have two options to integrate pkpy into your project.
|
You have two options to integrate pkpy into your project.
|
||||||
|
|
||||||
#### Use CMake (Recommended)
|
#### 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.
|
||||||
|
|
||||||
|
#### 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:
|
||||||
@ -20,11 +25,6 @@ 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:
|
||||||
|
|||||||
@ -3,7 +3,7 @@ output: .retype
|
|||||||
url: https://pocketpy.dev
|
url: https://pocketpy.dev
|
||||||
branding:
|
branding:
|
||||||
title: pocketpy
|
title: pocketpy
|
||||||
label: v2.1.7
|
label: v2.1.6
|
||||||
logo: "./static/logo.png"
|
logo: "./static/logo.png"
|
||||||
favicon: "./static/logo.png"
|
favicon: "./static/logo.png"
|
||||||
meta:
|
meta:
|
||||||
|
|||||||
@ -1,58 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "pocketpy/common/vector.h"
|
|
||||||
#include "pocketpy/common/str.h"
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct c11_serializer {
|
|
||||||
c11_vector data;
|
|
||||||
} c11_serializer;
|
|
||||||
|
|
||||||
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__write_mark(c11_serializer* self, char mark);
|
|
||||||
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__submit(c11_serializer* self, int* size);
|
|
||||||
|
|
||||||
typedef struct c11_deserializer {
|
|
||||||
char error_msg[64];
|
|
||||||
const uint8_t* data;
|
|
||||||
int size;
|
|
||||||
int index;
|
|
||||||
int8_t major_ver;
|
|
||||||
int8_t minor_ver;
|
|
||||||
} c11_deserializer;
|
|
||||||
|
|
||||||
void c11_deserializer__ctor(c11_deserializer* self, const void* data, int size);
|
|
||||||
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);
|
|
||||||
const char* c11_deserializer__read_cstr(c11_deserializer* self);
|
|
||||||
void* c11_deserializer__read_bytes(c11_deserializer* self, int size);
|
|
||||||
|
|
||||||
|
|
||||||
#define DEF_ATOMIC_INLINE_RW(name, T) \
|
|
||||||
static inline void c11_serializer__write_##name(c11_serializer* self, T value){ \
|
|
||||||
c11_serializer__write_bytes(self, &value, sizeof(T)); \
|
|
||||||
} \
|
|
||||||
static inline T c11_deserializer__read_##name(c11_deserializer* self){ \
|
|
||||||
const void* p = self->data + self->index; \
|
|
||||||
self->index += sizeof(T); \
|
|
||||||
T retval;\
|
|
||||||
memcpy(&retval, p, sizeof(T)); \
|
|
||||||
return retval; \
|
|
||||||
}
|
|
||||||
|
|
||||||
DEF_ATOMIC_INLINE_RW(i8, int8_t)
|
|
||||||
DEF_ATOMIC_INLINE_RW(i16, int16_t)
|
|
||||||
DEF_ATOMIC_INLINE_RW(i32, int32_t)
|
|
||||||
DEF_ATOMIC_INLINE_RW(i64, int64_t)
|
|
||||||
DEF_ATOMIC_INLINE_RW(f32, float)
|
|
||||||
DEF_ATOMIC_INLINE_RW(f64, double)
|
|
||||||
DEF_ATOMIC_INLINE_RW(type, py_Type)
|
|
||||||
|
|
||||||
#undef DEF_ATOMIC_INLINE_RW
|
|
||||||
|
|
||||||
@ -56,7 +56,6 @@ 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);
|
||||||
|
|||||||
@ -22,7 +22,6 @@ bool c11_vector__contains(const c11_vector* self, void* elem);
|
|||||||
void* c11_vector__submit(c11_vector* self, int* length);
|
void* c11_vector__submit(c11_vector* self, int* length);
|
||||||
void c11_vector__swap(c11_vector* self, c11_vector* other);
|
void c11_vector__swap(c11_vector* self, c11_vector* other);
|
||||||
int c11_vector__nextcap(c11_vector* self);
|
int c11_vector__nextcap(c11_vector* self);
|
||||||
void c11_vector__extend(c11_vector* self, const void* p, int size);
|
|
||||||
|
|
||||||
#define c11__getitem(T, self, index) (((T*)(self)->data)[index])
|
#define c11__getitem(T, self, index) (((T*)(self)->data)[index])
|
||||||
#define c11__setitem(T, self, index, value) ((T*)(self)->data)[index] = value;
|
#define c11__setitem(T, self, index, value) ((T*)(self)->data)[index] = value;
|
||||||
@ -41,6 +40,17 @@ void c11_vector__extend(c11_vector* self, const void* p, int size);
|
|||||||
|
|
||||||
#define c11_vector__back(T, self) (((T*)(self)->data)[(self)->length - 1])
|
#define c11_vector__back(T, self) (((T*)(self)->data)[(self)->length - 1])
|
||||||
|
|
||||||
|
#define c11_vector__extend(T, self, p, size) \
|
||||||
|
do { \
|
||||||
|
int min_capacity = (self)->length + (size); \
|
||||||
|
if((self)->capacity < min_capacity) { \
|
||||||
|
int nextcap = c11_vector__nextcap(self); \
|
||||||
|
c11_vector__reserve((self), c11__max(nextcap, min_capacity)); \
|
||||||
|
} \
|
||||||
|
memcpy((T*)(self)->data + (self)->length, (p), (size) * sizeof(T)); \
|
||||||
|
(self)->length += (size); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#define c11_vector__insert(T, self, index, elem) \
|
#define c11_vector__insert(T, self, index, elem) \
|
||||||
do { \
|
do { \
|
||||||
if((self)->length == (self)->capacity) { \
|
if((self)->length == (self)->capacity) { \
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
#define PK_VERSION "2.1.7"
|
#define PK_VERSION "2.1.6"
|
||||||
#define PK_VERSION_MAJOR 2
|
#define PK_VERSION_MAJOR 2
|
||||||
#define PK_VERSION_MINOR 1
|
#define PK_VERSION_MINOR 1
|
||||||
#define PK_VERSION_PATCH 7
|
#define PK_VERSION_PATCH 6
|
||||||
|
|
||||||
/*************** feature settings ***************/
|
/*************** feature settings ***************/
|
||||||
#ifndef PK_ENABLE_OS // can be overridden by cmake
|
#ifndef PK_ENABLE_OS // can be overridden by cmake
|
||||||
|
|||||||
@ -58,10 +58,11 @@ typedef struct VM {
|
|||||||
int recursion_depth;
|
int recursion_depth;
|
||||||
int max_recursion_depth;
|
int max_recursion_depth;
|
||||||
|
|
||||||
py_TValue reg[14]; // users' registers
|
py_TValue reg[8]; // users' registers
|
||||||
void* ctx; // user-defined context
|
void* ctx; // user-defined context
|
||||||
|
|
||||||
CachedNames cached_names;
|
CachedNames cached_names;
|
||||||
|
NameDict compile_time_funcs;
|
||||||
|
|
||||||
py_StackRef curr_class;
|
py_StackRef curr_class;
|
||||||
py_StackRef curr_decl_based_function; // this is for get current function without frame
|
py_StackRef curr_decl_based_function; // this is for get current function without frame
|
||||||
|
|||||||
@ -45,26 +45,26 @@ typedef enum Opcode {
|
|||||||
} Opcode;
|
} Opcode;
|
||||||
|
|
||||||
typedef struct Bytecode {
|
typedef struct Bytecode {
|
||||||
uint16_t op;
|
uint8_t op;
|
||||||
uint16_t arg;
|
uint16_t arg;
|
||||||
} Bytecode;
|
} Bytecode;
|
||||||
|
|
||||||
void Bytecode__set_signed_arg(Bytecode* self, int arg);
|
void Bytecode__set_signed_arg(Bytecode* self, int arg);
|
||||||
bool Bytecode__is_forward_jump(const Bytecode* self);
|
bool Bytecode__is_forward_jump(const Bytecode* self);
|
||||||
|
|
||||||
typedef struct BytecodeEx {
|
|
||||||
int32_t lineno; // line number for each bytecode
|
|
||||||
int32_t iblock; // block index
|
|
||||||
} BytecodeEx;
|
|
||||||
|
|
||||||
typedef struct CodeBlock {
|
typedef struct CodeBlock {
|
||||||
int32_t type;
|
CodeBlockType type;
|
||||||
int32_t parent; // parent index in blocks
|
int parent; // parent index in blocks
|
||||||
int32_t start; // start index of this block in codes, inclusive
|
int start; // start index of this block in codes, inclusive
|
||||||
int32_t end; // end index of this block in codes, exclusive
|
int end; // end index of this block in codes, exclusive
|
||||||
int32_t end2; // ...
|
int end2; // ...
|
||||||
} CodeBlock;
|
} CodeBlock;
|
||||||
|
|
||||||
|
typedef struct BytecodeEx {
|
||||||
|
int lineno; // line number for each bytecode
|
||||||
|
int iblock; // block index
|
||||||
|
} BytecodeEx;
|
||||||
|
|
||||||
typedef struct CodeObject {
|
typedef struct CodeObject {
|
||||||
SourceData_ src;
|
SourceData_ src;
|
||||||
c11_string* name;
|
c11_string* name;
|
||||||
@ -74,8 +74,8 @@ typedef struct CodeObject {
|
|||||||
|
|
||||||
c11_vector /*T=py_TValue*/ consts; // constants
|
c11_vector /*T=py_TValue*/ consts; // constants
|
||||||
c11_vector /*T=py_Name*/ varnames; // local variables
|
c11_vector /*T=py_Name*/ varnames; // local variables
|
||||||
c11_vector /*T=py_Name*/ names; // non-local names
|
c11_vector /*T=py_Name*/ names;
|
||||||
int nlocals; // number of local variables
|
int nlocals;
|
||||||
|
|
||||||
c11_smallmap_n2d varnames_inv;
|
c11_smallmap_n2d varnames_inv;
|
||||||
c11_smallmap_n2d names_inv;
|
c11_smallmap_n2d names_inv;
|
||||||
@ -93,10 +93,6 @@ int CodeObject__add_varname(CodeObject* self, py_Name name);
|
|||||||
int CodeObject__add_name(CodeObject* self, py_Name name);
|
int CodeObject__add_name(CodeObject* self, py_Name name);
|
||||||
void CodeObject__gc_mark(const CodeObject* self, c11_vector* p_stack);
|
void CodeObject__gc_mark(const CodeObject* self, c11_vector* p_stack);
|
||||||
|
|
||||||
// Serialization
|
|
||||||
void* CodeObject__dumps(const CodeObject* co, int* size);
|
|
||||||
char* CodeObject__loads(const void* data, int size, const char* filename, CodeObject* out);
|
|
||||||
|
|
||||||
typedef struct FuncDeclKwArg {
|
typedef struct FuncDeclKwArg {
|
||||||
int index; // index in co->varnames
|
int index; // index in co->varnames
|
||||||
py_Name key; // name of this argument
|
py_Name key; // name of this argument
|
||||||
@ -107,14 +103,14 @@ typedef struct FuncDecl {
|
|||||||
RefCounted rc;
|
RefCounted rc;
|
||||||
CodeObject code; // strong ref
|
CodeObject code; // strong ref
|
||||||
|
|
||||||
c11_vector /*T=int32_t*/ args; // indices in co->varnames
|
c11_vector /*T=int*/ args; // indices in co->varnames
|
||||||
c11_vector /*T=FuncDeclKwArg*/ kwargs; // indices in co->varnames
|
c11_vector /*T=KwArg*/ 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
|
||||||
bool nested; // whether this function is nested
|
bool nested; // whether this function is nested
|
||||||
|
|
||||||
char* docstring;
|
const char* docstring; // docstring of this function (weak ref)
|
||||||
|
|
||||||
FuncType type;
|
FuncType type;
|
||||||
c11_smallmap_n2d kw_to_index;
|
c11_smallmap_n2d kw_to_index;
|
||||||
@ -129,7 +125,6 @@ void FuncDecl__add_kwarg(FuncDecl* self, py_Name name, const py_TValue* value);
|
|||||||
void FuncDecl__add_starred_arg(FuncDecl* self, py_Name name);
|
void FuncDecl__add_starred_arg(FuncDecl* self, py_Name name);
|
||||||
void FuncDecl__add_starred_kwarg(FuncDecl* self, py_Name name);
|
void FuncDecl__add_starred_kwarg(FuncDecl* self, py_Name name);
|
||||||
void FuncDecl__gc_mark(const FuncDecl* self, c11_vector* p_stack);
|
void FuncDecl__gc_mark(const FuncDecl* self, c11_vector* p_stack);
|
||||||
void FuncDecl__dtor(FuncDecl* self);
|
|
||||||
|
|
||||||
// runtime function
|
// runtime function
|
||||||
typedef struct Function {
|
typedef struct Function {
|
||||||
|
|||||||
@ -79,8 +79,8 @@ typedef void (*py_TraceFunc)(py_Frame* frame, enum py_TraceEvent);
|
|||||||
|
|
||||||
/// A struct contains the callbacks of the VM.
|
/// A struct contains the callbacks of the VM.
|
||||||
typedef struct py_Callbacks {
|
typedef struct py_Callbacks {
|
||||||
/// Used by `__import__` to load a source or compiled module.
|
/// Used by `__import__` to load a source module.
|
||||||
char* (*importfile)(const char* path, int* data_size);
|
char* (*importfile)(const char*);
|
||||||
/// Called before `importfile` to lazy-import a C module.
|
/// Called before `importfile` to lazy-import a C module.
|
||||||
PY_MAYBENULL py_GlobalRef (*lazyimport)(const char*);
|
PY_MAYBENULL py_GlobalRef (*lazyimport)(const char*);
|
||||||
/// Used by `print` to output a string.
|
/// Used by `print` to output a string.
|
||||||
@ -182,11 +182,6 @@ PK_API bool py_compile(const char* source,
|
|||||||
const char* filename,
|
const char* filename,
|
||||||
enum py_CompileMode mode,
|
enum py_CompileMode mode,
|
||||||
bool is_dynamic) PY_RAISE PY_RETURN;
|
bool is_dynamic) PY_RAISE PY_RETURN;
|
||||||
/// Compile a `.py` file into a `.pyc` file.
|
|
||||||
PK_API bool py_compilefile(const char* src_path,
|
|
||||||
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).
|
||||||
@ -305,6 +300,10 @@ PK_API void
|
|||||||
py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter);
|
py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter);
|
||||||
/// Bind a magic method to type.
|
/// Bind a magic method to type.
|
||||||
PK_API void py_bindmagic(py_Type type, py_Name name, py_CFunction f);
|
PK_API void py_bindmagic(py_Type type, py_Name name, py_CFunction f);
|
||||||
|
/// Bind a compile-time function via "decl-based" style.
|
||||||
|
PK_API void py_macrobind(const char* sig, py_CFunction f);
|
||||||
|
/// Get a compile-time function by name.
|
||||||
|
PK_API py_ItemRef py_macroget(py_Name name);
|
||||||
|
|
||||||
/************* Value Cast *************/
|
/************* Value Cast *************/
|
||||||
|
|
||||||
@ -441,13 +440,6 @@ 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,7 +16,6 @@ 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,7 +44,8 @@ struct object_pool {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void initialize(int size) noexcept {
|
static void initialize(int size) noexcept {
|
||||||
pool = py_sysr1();
|
// use 8th register.
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,8 +94,8 @@ struct import_callback {
|
|||||||
_importfile = nullptr;
|
_importfile = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static char* importfile(const char* path, int* data_size) {
|
static char* importfile(const char* path) {
|
||||||
if(value.empty()) return _importfile(path, data_size);
|
if(value.empty()) return _importfile(path);
|
||||||
// +1 for the null terminator
|
// +1 for the null terminator
|
||||||
char* cstr = new char[value.size() + 1];
|
char* cstr = new char[value.size() + 1];
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ A new Flutter FFI plugin project.
|
|||||||
|
|
||||||
s.prepare_command = <<-CMD
|
s.prepare_command = <<-CMD
|
||||||
rm -rf pocketpy
|
rm -rf pocketpy
|
||||||
git clone --branch v2.1.7 --depth 1 https://github.com/pocketpy/pocketpy.git
|
git clone --branch v2.1.6 --depth 1 https://github.com/pocketpy/pocketpy.git
|
||||||
cd pocketpy
|
cd pocketpy
|
||||||
git submodule update --init --recursive --depth 1
|
git submodule update --init --recursive --depth 1
|
||||||
bash build_ios_libs.sh
|
bash build_ios_libs.sh
|
||||||
|
|||||||
@ -357,47 +357,6 @@ class PocketpyBindings {
|
|||||||
late final _py_compile = _py_compilePtr.asFunction<
|
late final _py_compile = _py_compilePtr.asFunction<
|
||||||
bool Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, int, bool)>();
|
bool Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, int, bool)>();
|
||||||
|
|
||||||
/// Compile a `.py` file into a `.pyc` file.
|
|
||||||
bool py_compilefile(
|
|
||||||
ffi.Pointer<ffi.Char> src_path,
|
|
||||||
ffi.Pointer<ffi.Char> dst_path,
|
|
||||||
) {
|
|
||||||
return _py_compilefile(
|
|
||||||
src_path,
|
|
||||||
dst_path,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
late final _py_compilefilePtr = _lookup<
|
|
||||||
ffi.NativeFunction<
|
|
||||||
ffi.Bool Function(
|
|
||||||
ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>)>>('py_compilefile');
|
|
||||||
late final _py_compilefile = _py_compilefilePtr.asFunction<
|
|
||||||
bool Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>)>();
|
|
||||||
|
|
||||||
/// Run a compiled code object.
|
|
||||||
bool py_execo(
|
|
||||||
ffi.Pointer<ffi.Void> data,
|
|
||||||
int size,
|
|
||||||
ffi.Pointer<ffi.Char> filename,
|
|
||||||
py_Ref module,
|
|
||||||
) {
|
|
||||||
return _py_execo(
|
|
||||||
data,
|
|
||||||
size,
|
|
||||||
filename,
|
|
||||||
module,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
late final _py_execoPtr = _lookup<
|
|
||||||
ffi.NativeFunction<
|
|
||||||
ffi.Bool Function(ffi.Pointer<ffi.Void>, ffi.Int,
|
|
||||||
ffi.Pointer<ffi.Char>, py_Ref)>>('py_execo');
|
|
||||||
late final _py_execo = _py_execoPtr.asFunction<
|
|
||||||
bool Function(
|
|
||||||
ffi.Pointer<ffi.Void>, int, ffi.Pointer<ffi.Char>, py_Ref)>();
|
|
||||||
|
|
||||||
/// 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).
|
||||||
@ -1001,6 +960,38 @@ class PocketpyBindings {
|
|||||||
late final _py_bindmagic =
|
late final _py_bindmagic =
|
||||||
_py_bindmagicPtr.asFunction<void Function(int, py_Name, py_CFunction)>();
|
_py_bindmagicPtr.asFunction<void Function(int, py_Name, py_CFunction)>();
|
||||||
|
|
||||||
|
/// Bind a compile-time function via "decl-based" style.
|
||||||
|
void py_macrobind(
|
||||||
|
ffi.Pointer<ffi.Char> sig,
|
||||||
|
py_CFunction f,
|
||||||
|
) {
|
||||||
|
return _py_macrobind(
|
||||||
|
sig,
|
||||||
|
f,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _py_macrobindPtr = _lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(
|
||||||
|
ffi.Pointer<ffi.Char>, py_CFunction)>>('py_macrobind');
|
||||||
|
late final _py_macrobind = _py_macrobindPtr
|
||||||
|
.asFunction<void Function(ffi.Pointer<ffi.Char>, py_CFunction)>();
|
||||||
|
|
||||||
|
/// Get a compile-time function by name.
|
||||||
|
py_ItemRef py_macroget(
|
||||||
|
py_Name name,
|
||||||
|
) {
|
||||||
|
return _py_macroget(
|
||||||
|
name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _py_macrogetPtr =
|
||||||
|
_lookup<ffi.NativeFunction<py_ItemRef Function(py_Name)>>('py_macroget');
|
||||||
|
late final _py_macroget =
|
||||||
|
_py_macrogetPtr.asFunction<py_ItemRef Function(py_Name)>();
|
||||||
|
|
||||||
/// Convert an `int` object in python to `int64_t`.
|
/// Convert an `int` object in python to `int64_t`.
|
||||||
int py_toint(
|
int py_toint(
|
||||||
py_Ref arg0,
|
py_Ref arg0,
|
||||||
@ -3955,12 +3946,10 @@ abstract class py_TraceEvent {
|
|||||||
|
|
||||||
/// A struct contains the callbacks of the VM.
|
/// A struct contains the callbacks of the VM.
|
||||||
final class py_Callbacks extends ffi.Struct {
|
final class py_Callbacks extends ffi.Struct {
|
||||||
/// Used by `__import__` to load a source or compiled module.
|
/// Used by `__import__` to load a source module.
|
||||||
external ffi.Pointer<
|
external ffi.Pointer<
|
||||||
ffi.NativeFunction<
|
ffi.NativeFunction<
|
||||||
ffi.Pointer<ffi.Char> Function(
|
ffi.Pointer<ffi.Char> Function(ffi.Pointer<ffi.Char>)>> importfile;
|
||||||
ffi.Pointer<ffi.Char> path, ffi.Pointer<ffi.Int> data_size)>>
|
|
||||||
importfile;
|
|
||||||
|
|
||||||
/// Called before `importfile` to lazy-import a C module.
|
/// Called before `importfile` to lazy-import a C module.
|
||||||
external ffi
|
external ffi
|
||||||
@ -4046,13 +4035,13 @@ typedef py_CFunction = ffi.Pointer<
|
|||||||
/// A pointer that represents a python identifier. For fast name resolution.
|
/// A pointer that represents a python identifier. For fast name resolution.
|
||||||
typedef py_Name = ffi.Pointer<py_OpaqueName>;
|
typedef py_Name = ffi.Pointer<py_OpaqueName>;
|
||||||
|
|
||||||
|
/// An item reference to a container object. It invalidates when the container is modified.
|
||||||
|
typedef py_ItemRef = ffi.Pointer<py_TValue>;
|
||||||
|
|
||||||
/// A generic destructor function.
|
/// A generic destructor function.
|
||||||
typedef py_Dtor
|
typedef py_Dtor
|
||||||
= ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>;
|
= ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>;
|
||||||
|
|
||||||
/// An item reference to a container object. It invalidates when the container is modified.
|
|
||||||
typedef py_ItemRef = ffi.Pointer<py_TValue>;
|
|
||||||
|
|
||||||
/// A reference which has the same lifespan as the python object.
|
/// A reference which has the same lifespan as the python object.
|
||||||
typedef py_ObjectRef = ffi.Pointer<py_TValue>;
|
typedef py_ObjectRef = ffi.Pointer<py_TValue>;
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ A new Flutter FFI plugin project.
|
|||||||
|
|
||||||
s.prepare_command = <<-CMD
|
s.prepare_command = <<-CMD
|
||||||
rm -rf pocketpy
|
rm -rf pocketpy
|
||||||
git clone --branch v2.1.7 --depth 1 https://github.com/pocketpy/pocketpy.git
|
git clone --branch v2.1.6 --depth 1 https://github.com/pocketpy/pocketpy.git
|
||||||
cd pocketpy
|
cd pocketpy
|
||||||
git submodule update --init --recursive --depth 1
|
git submodule update --init --recursive --depth 1
|
||||||
bash build_darwin_libs.sh
|
bash build_darwin_libs.sh
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
name: pocketpy
|
name: pocketpy
|
||||||
description: A lightweight Python interpreter for game engines. It supports Android/iOS/Windows/Linux/MacOS.
|
description: A lightweight Python interpreter for game engines. It supports Android/iOS/Windows/Linux/MacOS.
|
||||||
version: 2.1.7
|
version: 2.1.6
|
||||||
homepage: https://pocketpy.dev
|
homepage: https://pocketpy.dev
|
||||||
repository: https://github.com/pocketpy/pocketpy
|
repository: https://github.com/pocketpy/pocketpy
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ set(PK_BUILD_SHARED_LIB ON CACHE BOOL "" FORCE)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
pocketpy
|
pocketpy
|
||||||
GIT_REPOSITORY https://github.com/pocketpy/pocketpy.git
|
GIT_REPOSITORY https://github.com/pocketpy/pocketpy.git
|
||||||
GIT_TAG v2.1.7
|
GIT_TAG v2.1.6
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(pocketpy)
|
FetchContent_MakeAvailable(pocketpy)
|
||||||
|
|||||||
@ -3,12 +3,14 @@ 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
|
||||||
code = os.system(pkpy_exe + ' ' + filepath)
|
if sys.platform == 'win32':
|
||||||
|
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
|
||||||
@ -16,7 +18,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') and not filename.endswith('.pyc'):
|
if not filename.endswith('.py'):
|
||||||
continue
|
continue
|
||||||
filepath = os.path.join(path, filename)
|
filepath = os.path.join(path, filename)
|
||||||
print("> " + filepath, flush=True)
|
print("> " + filepath, flush=True)
|
||||||
@ -74,8 +76,6 @@ 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,11 +84,5 @@ 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")
|
||||||
|
|||||||
@ -10,7 +10,7 @@ PK_INLINE int c11__bit_length(unsigned long x) {
|
|||||||
#if(defined(__clang__) || defined(__GNUC__))
|
#if(defined(__clang__) || defined(__GNUC__))
|
||||||
return x == 0 ? 0 : (int)sizeof(unsigned long) * 8 - __builtin_clzl(x);
|
return x == 0 ? 0 : (int)sizeof(unsigned long) * 8 - __builtin_clzl(x);
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
_Static_assert(sizeof(unsigned long) <= 4, "unsigned long is greater than 4 bytes");
|
static_assert(sizeof(unsigned long) <= 4, "unsigned long is greater than 4 bytes");
|
||||||
unsigned long msb;
|
unsigned long msb;
|
||||||
if(_BitScanReverse(&msb, x)) { return (int)msb + 1; }
|
if(_BitScanReverse(&msb, x)) { return (int)msb + 1; }
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -1,113 +0,0 @@
|
|||||||
#include "pocketpy/common/serialize.h"
|
|
||||||
|
|
||||||
// >>> ord('🥕')
|
|
||||||
// 129365
|
|
||||||
// >>> ord('🍋')
|
|
||||||
// 127819
|
|
||||||
|
|
||||||
static uint32_t c11__checksum_32bit(const void* data, int size){
|
|
||||||
const uint8_t* p = (const uint8_t*)data;
|
|
||||||
uint32_t res = 0;
|
|
||||||
for(int i = 0; i < size; i++){
|
|
||||||
res = res * 31 + p[i];
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void c11_serializer__ctor(c11_serializer* self, int16_t magic, int8_t major_ver, int8_t minor_ver){
|
|
||||||
c11_vector__ctor(&self->data, 1);
|
|
||||||
c11_serializer__write_i16(self, magic);
|
|
||||||
c11_serializer__write_i8(self, major_ver);
|
|
||||||
c11_serializer__write_i8(self, minor_ver);
|
|
||||||
}
|
|
||||||
|
|
||||||
void c11_serializer__dtor(c11_serializer* self){
|
|
||||||
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) {
|
|
||||||
int len = (int)strlen(cstr);
|
|
||||||
c11_serializer__write_bytes(self, cstr, len + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void c11_serializer__write_bytes(c11_serializer* self, const void* data, int size){
|
|
||||||
c11_vector__extend(&self->data, data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* c11_serializer__submit(c11_serializer* self, int* size){
|
|
||||||
uint32_t checksum = c11__checksum_32bit(self->data.data, self->data.length);
|
|
||||||
c11_serializer__write_bytes(self, &checksum, sizeof(uint32_t));
|
|
||||||
return c11_vector__submit(&self->data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void c11_deserializer__ctor(c11_deserializer* self, const void* data, int size){
|
|
||||||
self->data = (const uint8_t*)data;
|
|
||||||
self->size = size;
|
|
||||||
self->index = 0;
|
|
||||||
self->error_msg[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void c11_deserializer__dtor(c11_deserializer* self){
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
bool c11_deserializer__error(c11_deserializer* self, const char* msg){
|
|
||||||
snprintf(self->error_msg, sizeof(self->error_msg), "%s", msg);
|
|
||||||
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){
|
|
||||||
if(self->size < 8){
|
|
||||||
return c11_deserializer__error(self, "bad header: size < 8");
|
|
||||||
}
|
|
||||||
// read 16bit magic
|
|
||||||
int16_t file_magic = c11_deserializer__read_i16(self);
|
|
||||||
if(file_magic != magic){
|
|
||||||
return c11_deserializer__error(self, "bad header: magic mismatch");
|
|
||||||
}
|
|
||||||
// read 16bit version
|
|
||||||
self->major_ver = c11_deserializer__read_i8(self);
|
|
||||||
self->minor_ver = c11_deserializer__read_i8(self);
|
|
||||||
|
|
||||||
// check checksum
|
|
||||||
uint32_t checksum;
|
|
||||||
memcpy(&checksum, self->data + self->size - 4, sizeof(uint32_t));
|
|
||||||
uint32_t actual_checksum = c11__checksum_32bit(self->data, self->size - 4);
|
|
||||||
if(checksum != actual_checksum){
|
|
||||||
return c11_deserializer__error(self, "bad header: checksum mismatch");
|
|
||||||
}
|
|
||||||
// check version
|
|
||||||
if(self->major_ver != major_ver){
|
|
||||||
return c11_deserializer__error(self, "bad header: major version mismatch");
|
|
||||||
}
|
|
||||||
if(self->minor_ver < minor_ver_min){
|
|
||||||
// file_ver: 1.1, require_ver: 1.0 => ok
|
|
||||||
// file_ver: 1.1, require_ver: 1.1 => ok
|
|
||||||
// file_ver: 1.1, require_ver: 1.2 => error
|
|
||||||
return c11_deserializer__error(self, "bad header: minor version mismatch");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* c11_deserializer__read_cstr(c11_deserializer* self){
|
|
||||||
const char* p = (const char*)(self->data + self->index);
|
|
||||||
self->index += (strlen(p) + 1);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* c11_deserializer__read_bytes(c11_deserializer* self, int size){
|
|
||||||
void* p = (void*)(self->data + self->index);
|
|
||||||
self->index += size;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
@ -8,16 +8,10 @@ static void SourceData__ctor(struct SourceData* self,
|
|||||||
const char* filename,
|
const char* filename,
|
||||||
enum py_CompileMode mode,
|
enum py_CompileMode mode,
|
||||||
bool is_dynamic) {
|
bool is_dynamic) {
|
||||||
self->mode = mode;
|
|
||||||
self->is_dynamic = is_dynamic;
|
|
||||||
self->filename = c11_string__new(filename);
|
self->filename = c11_string__new(filename);
|
||||||
|
self->mode = mode;
|
||||||
c11_vector__ctor(&self->line_starts, sizeof(const char*));
|
c11_vector__ctor(&self->line_starts, sizeof(const char*));
|
||||||
|
|
||||||
if(!source) {
|
|
||||||
self->source = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip utf8 BOM if there is any.
|
// Skip utf8 BOM if there is any.
|
||||||
if(strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3;
|
if(strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3;
|
||||||
// Drop all '\r'
|
// Drop all '\r'
|
||||||
@ -40,12 +34,13 @@ static void SourceData__ctor(struct SourceData* self,
|
|||||||
self->source->data[last_index + 1] = '\0';
|
self->source->data[last_index + 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->is_dynamic = is_dynamic;
|
||||||
c11_vector__push(const char*, &self->line_starts, self->source->data);
|
c11_vector__push(const char*, &self->line_starts, self->source->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SourceData__dtor(struct SourceData* self) {
|
static void SourceData__dtor(struct SourceData* self) {
|
||||||
c11_string__delete(self->filename);
|
c11_string__delete(self->filename);
|
||||||
if(self->source) c11_string__delete(self->source);
|
c11_string__delete(self->source);
|
||||||
c11_vector__dtor(&self->line_starts);
|
c11_vector__dtor(&self->line_starts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +59,7 @@ bool SourceData__get_line(const struct SourceData* self,
|
|||||||
int lineno,
|
int lineno,
|
||||||
const char** st,
|
const char** st,
|
||||||
const char** ed) {
|
const char** ed) {
|
||||||
if(lineno < 0 || !self->source) return false;
|
if(lineno < 0) return false;
|
||||||
lineno -= 1;
|
lineno -= 1;
|
||||||
if(lineno < 0) lineno = 0;
|
if(lineno < 0) lineno = 0;
|
||||||
const char* _start = c11__getitem(const char*, &self->line_starts, lineno);
|
const char* _start = c11__getitem(const char*, &self->line_starts, lineno);
|
||||||
@ -89,9 +84,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 +103,5 @@ void SourceData__snapshot(const struct SourceData* self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(!st) { c11_sbuf__write_cstr(ss, " <?>"); }
|
if(!st) { c11_sbuf__write_cstr(ss, " <?>"); }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,7 +79,7 @@ void c11_sbuf__write_cstr(c11_sbuf* self, const char* str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void c11_sbuf__write_cstrn(c11_sbuf* self, const char* str, int n) {
|
void c11_sbuf__write_cstrn(c11_sbuf* self, const char* str, int n) {
|
||||||
c11_vector__extend(&self->data, str, n);
|
c11_vector__extend(char, &self->data, str, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void c11_sbuf__write_quoted(c11_sbuf* self, c11_sv sv, char quote) {
|
void c11_sbuf__write_quoted(c11_sbuf* self, c11_sv sv, char quote) {
|
||||||
|
|||||||
@ -147,14 +147,6 @@ 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;
|
||||||
|
|||||||
@ -76,15 +76,3 @@ int c11_vector__nextcap(c11_vector* self) {
|
|||||||
return self->capacity + (self->capacity >> 2);
|
return self->capacity + (self->capacity >> 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void c11_vector__extend(c11_vector* self, const void* p, int size) {
|
|
||||||
if (size <= 0) return;
|
|
||||||
int min_capacity = self->length + size;
|
|
||||||
if(self->capacity < min_capacity) {
|
|
||||||
int nextcap = c11_vector__nextcap(self);
|
|
||||||
c11_vector__reserve((self), c11__max(nextcap, min_capacity));
|
|
||||||
}
|
|
||||||
void* dst = (char*)self->data + self->length * self->elem_size;
|
|
||||||
memcpy(dst, p, size * self->elem_size);
|
|
||||||
self->length += size;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -76,8 +76,8 @@ static int Ctx__prepare_loop_divert(Ctx* self, int line, bool is_break);
|
|||||||
static int Ctx__enter_block(Ctx* self, CodeBlockType type);
|
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 void Ctx__revert_last_emit_(Ctx* self);
|
||||||
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);
|
||||||
@ -1071,12 +1071,7 @@ 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) {
|
||||||
if(e->key == 0) {
|
Ctx__emit_int(ctx, (uintptr_t)e->key, self->line);
|
||||||
// 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;
|
||||||
@ -1182,7 +1177,7 @@ static void Ctx__s_emit_decorators(Ctx* self, int count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
Bytecode bc = {(uint16_t)opcode, arg};
|
Bytecode bc = {(uint8_t)opcode, arg};
|
||||||
BytecodeEx bcx = {line, self->curr_iblock};
|
BytecodeEx bcx = {line, self->curr_iblock};
|
||||||
c11_vector__push(Bytecode, &self->co->codes, bc);
|
c11_vector__push(Bytecode, &self->co->codes, bc);
|
||||||
c11_vector__push(BytecodeEx, &self->co->codes_ex, bcx);
|
c11_vector__push(BytecodeEx, &self->co->codes_ex, bcx);
|
||||||
@ -1192,6 +1187,11 @@ static int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line) {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static void Ctx__revert_last_emit_(Ctx* self) {
|
||||||
|
// c11_vector__pop(&self->co->codes);
|
||||||
|
// c11_vector__pop(&self->co->codes_ex);
|
||||||
|
// }
|
||||||
|
|
||||||
static int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
static int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
||||||
if(INT16_MIN <= value && value <= INT16_MAX) {
|
if(INT16_MIN <= value && value <= INT16_MAX) {
|
||||||
return Ctx__emit_(self, OP_LOAD_SMALL_INT, (uint16_t)value, line);
|
return Ctx__emit_(self, OP_LOAD_SMALL_INT, (uint16_t)value, line);
|
||||||
@ -1202,12 +1202,6 @@ 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;
|
||||||
@ -1226,10 +1220,7 @@ 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) {
|
static int Ctx__add_name(Ctx* self, py_Name name) { return CodeObject__add_name(self->co, 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) {
|
||||||
@ -1890,10 +1881,64 @@ static Error* exprMap(Compiler* self) {
|
|||||||
|
|
||||||
static Error* read_literal(Compiler* self, py_Ref out);
|
static Error* read_literal(Compiler* self, py_Ref out);
|
||||||
|
|
||||||
|
static Error* exprCompileTimeCall(Compiler* self, py_ItemRef func, int line) {
|
||||||
|
Error* err;
|
||||||
|
py_push(func);
|
||||||
|
py_pushnil();
|
||||||
|
|
||||||
|
uint16_t argc = 0;
|
||||||
|
uint16_t kwargc = 0;
|
||||||
|
// copied from `exprCall`
|
||||||
|
do {
|
||||||
|
if(curr()->type == TK_RPAREN) break;
|
||||||
|
if(curr()->type == TK_ID && next()->type == TK_ASSIGN) {
|
||||||
|
consume(TK_ID);
|
||||||
|
py_Name key = py_namev(Token__sv(prev()));
|
||||||
|
consume(TK_ASSIGN);
|
||||||
|
// k=v
|
||||||
|
py_pushname(key);
|
||||||
|
check(read_literal(self, py_pushtmp()));
|
||||||
|
kwargc += 1;
|
||||||
|
} else {
|
||||||
|
if(kwargc > 0) {
|
||||||
|
return SyntaxError(self, "positional argument follows keyword argument");
|
||||||
|
}
|
||||||
|
check(read_literal(self, py_pushtmp()));
|
||||||
|
argc += 1;
|
||||||
|
}
|
||||||
|
} while(match(TK_COMMA));
|
||||||
|
consume(TK_RPAREN);
|
||||||
|
|
||||||
|
py_StackRef p0 = py_peek(0);
|
||||||
|
bool ok = py_vectorcall(argc, kwargc);
|
||||||
|
if(!ok) {
|
||||||
|
char* msg = py_formatexc();
|
||||||
|
py_clearexc(p0);
|
||||||
|
err = SyntaxError(self, "compile-time call error:\n%s", msg);
|
||||||
|
PK_FREE(msg);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: optimize string dedup
|
||||||
|
int index = Ctx__add_const(ctx(), py_retval());
|
||||||
|
Ctx__s_push(ctx(), (Expr*)LoadConstExpr__new(line, index));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static Error* exprCall(Compiler* self) {
|
static Error* exprCall(Compiler* self) {
|
||||||
Error* err;
|
Error* err;
|
||||||
Expr* callable = Ctx__s_popx(ctx());
|
Expr* callable = Ctx__s_popx(ctx());
|
||||||
int line = prev()->line;
|
int line = prev()->line;
|
||||||
|
if(callable->vt->is_name) {
|
||||||
|
NameExpr* ne = (NameExpr*)callable;
|
||||||
|
py_ItemRef func = py_macroget(ne->name);
|
||||||
|
if(func != NULL) {
|
||||||
|
py_StackRef p0 = py_peek(0);
|
||||||
|
err = exprCompileTimeCall(self, func, line);
|
||||||
|
if(err != NULL) py_clearexc(p0);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CallExpr* e = CallExpr__new(line, callable);
|
CallExpr* e = CallExpr__new(line, callable);
|
||||||
Ctx__s_push(ctx(), (Expr*)e); // push onto the stack in advance
|
Ctx__s_push(ctx(), (Expr*)e); // push onto the stack in advance
|
||||||
@ -2380,7 +2425,7 @@ static Error* compile_function(Compiler* self, int decorators) {
|
|||||||
py_TValue* consts = decl->code.consts.data;
|
py_TValue* consts = decl->code.consts.data;
|
||||||
py_TValue* c = &consts[codes[0].arg];
|
py_TValue* c = &consts[codes[0].arg];
|
||||||
if(py_isstr(c)) {
|
if(py_isstr(c)) {
|
||||||
decl->docstring = c11_strdup(py_tostr(c));
|
decl->docstring = py_tostr(c);
|
||||||
codes[0].op = OP_NO_OP;
|
codes[0].op = OP_NO_OP;
|
||||||
codes[1].op = OP_NO_OP;
|
codes[1].op = OP_NO_OP;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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_sysr0()
|
#define python_vars py_r7()
|
||||||
|
|
||||||
} debugger;
|
} debugger;
|
||||||
|
|
||||||
|
|||||||
@ -189,11 +189,6 @@ __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()++);
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
#include "pocketpy/pocketpy.h"
|
|
||||||
#include "pocketpy/interpreter/vm.h"
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
bool py_compilefile(const char* src_path, const char* dst_path) {
|
|
||||||
// read
|
|
||||||
FILE* fp = fopen(src_path, "rb");
|
|
||||||
if(fp == NULL) {
|
|
||||||
const char* msg = strerror(errno);
|
|
||||||
return OSError("[Errno %d] %s: '%s'", errno, msg, src_path);
|
|
||||||
}
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
long size = ftell(fp);
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
|
||||||
char* buffer = PK_MALLOC(size + 1);
|
|
||||||
size = fread(buffer, 1, size, fp);
|
|
||||||
buffer[size] = 0;
|
|
||||||
fclose(fp);
|
|
||||||
// compile
|
|
||||||
bool ok = py_compile(buffer, src_path, EXEC_MODE, false);
|
|
||||||
PK_FREE(buffer);
|
|
||||||
if(!ok) return false;
|
|
||||||
// dump
|
|
||||||
py_assign(py_pushtmp(), py_retval());
|
|
||||||
int bc_size;
|
|
||||||
void* bc_data = CodeObject__dumps(py_touserdata(py_peek(-1)), &bc_size);
|
|
||||||
py_pop();
|
|
||||||
// write
|
|
||||||
fp = fopen(dst_path, "wb");
|
|
||||||
if(fp == NULL) {
|
|
||||||
PK_FREE(bc_data);
|
|
||||||
const char* msg = strerror(errno);
|
|
||||||
return OSError("[Errno %d] %s: '%s'", errno, msg, dst_path);
|
|
||||||
}
|
|
||||||
fwrite(bc_data, 1, bc_size, fp);
|
|
||||||
fclose(fp);
|
|
||||||
PK_FREE(bc_data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@ -12,7 +12,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
static char* pk_default_importfile(const char* path, int* data_size) {
|
static char* pk_default_importfile(const char* path) {
|
||||||
#if PK_ENABLE_OS
|
#if PK_ENABLE_OS
|
||||||
FILE* f = fopen(path, "rb");
|
FILE* f = fopen(path, "rb");
|
||||||
if(f == NULL) return NULL;
|
if(f == NULL) return NULL;
|
||||||
@ -23,7 +23,6 @@ static char* pk_default_importfile(const char* path, int* data_size) {
|
|||||||
size = fread(buffer, 1, size, f);
|
size = fread(buffer, 1, size, f);
|
||||||
buffer[size] = 0;
|
buffer[size] = 0;
|
||||||
fclose(f);
|
fclose(f);
|
||||||
if(data_size) *data_size = (int)size;
|
|
||||||
return buffer;
|
return buffer;
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -99,8 +98,6 @@ 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;
|
||||||
@ -115,6 +112,7 @@ void VM__ctor(VM* self) {
|
|||||||
self->stack.end = self->stack.begin + PK_VM_STACK_SIZE;
|
self->stack.end = self->stack.begin + PK_VM_STACK_SIZE;
|
||||||
|
|
||||||
CachedNames__ctor(&self->cached_names);
|
CachedNames__ctor(&self->cached_names);
|
||||||
|
NameDict__ctor(&self->compile_time_funcs, PK_TYPE_ATTR_LOAD_FACTOR);
|
||||||
|
|
||||||
/* Init Builtin Types */
|
/* Init Builtin Types */
|
||||||
// 0: unused
|
// 0: unused
|
||||||
@ -308,6 +306,7 @@ void VM__dtor(VM* self) {
|
|||||||
BinTree__dtor(&self->modules);
|
BinTree__dtor(&self->modules);
|
||||||
FixedMemoryPool__dtor(&self->pool_frame);
|
FixedMemoryPool__dtor(&self->pool_frame);
|
||||||
CachedNames__dtor(&self->cached_names);
|
CachedNames__dtor(&self->cached_names);
|
||||||
|
NameDict__dtor(&self->compile_time_funcs);
|
||||||
c11_vector__dtor(&self->types);
|
c11_vector__dtor(&self->types);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,6 +671,12 @@ void ManagedHeap__mark(ManagedHeap* self) {
|
|||||||
CachedNames_KV* kv = c11_chunkedvector__at(&vm->cached_names.entries, i);
|
CachedNames_KV* kv = c11_chunkedvector__at(&vm->cached_names.entries, i);
|
||||||
pk__mark_value(&kv->val);
|
pk__mark_value(&kv->val);
|
||||||
}
|
}
|
||||||
|
// mark compile time functions
|
||||||
|
for(int i = 0; i < vm->compile_time_funcs.capacity; i++) {
|
||||||
|
NameDict_KV* kv = &vm->compile_time_funcs.items[i];
|
||||||
|
if(kv->key == NULL) continue;
|
||||||
|
pk__mark_value(&kv->value);
|
||||||
|
}
|
||||||
// mark types
|
// mark types
|
||||||
int types_length = vm->types.length;
|
int types_length = vm->types.length;
|
||||||
// 0-th type is placeholder
|
// 0-th type is placeholder
|
||||||
|
|||||||
@ -114,8 +114,10 @@ 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_newstrv(py_tmpr0(), py_name2sv(name));
|
py_StackRef tmp = py_pushtmp();
|
||||||
CachedNames__set(d, name, py_tmpr0());
|
py_newstrv(tmp, py_name2sv(name));
|
||||||
|
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_AS_INT:
|
case OP_LOAD_NAME:
|
||||||
case OP_LOAD_GLOBAL:
|
case OP_LOAD_GLOBAL:
|
||||||
case OP_LOAD_NONLOCAL:
|
case OP_LOAD_NONLOCAL:
|
||||||
case OP_STORE_GLOBAL:
|
case OP_STORE_GLOBAL:
|
||||||
|
|||||||
@ -59,7 +59,7 @@ static void PickleObject__dtor(PickleObject* self) {
|
|||||||
static bool PickleObject__py_submit(PickleObject* self, py_OutRef out);
|
static bool PickleObject__py_submit(PickleObject* self, py_OutRef out);
|
||||||
|
|
||||||
static void PickleObject__write_bytes(PickleObject* buf, const void* data, int size) {
|
static void PickleObject__write_bytes(PickleObject* buf, const void* data, int size) {
|
||||||
c11_vector__extend(&buf->codes, data, size);
|
c11_vector__extend(char, &buf->codes, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void c11_sbuf__write_type_path(c11_sbuf* path_buf, py_Type type) {
|
static void c11_sbuf__write_type_path(c11_sbuf* path_buf, py_Type type) {
|
||||||
|
|||||||
@ -17,12 +17,11 @@ bool Bytecode__is_forward_jump(const Bytecode* self) {
|
|||||||
(op == OP_FOR_ITER || op == OP_FOR_ITER_YIELD_VALUE);
|
(op == OP_FOR_ITER || op == OP_FOR_ITER_YIELD_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuncDecl__dtor(FuncDecl* self) {
|
static void FuncDecl__dtor(FuncDecl* self) {
|
||||||
CodeObject__dtor(&self->code);
|
CodeObject__dtor(&self->code);
|
||||||
c11_vector__dtor(&self->args);
|
c11_vector__dtor(&self->args);
|
||||||
c11_vector__dtor(&self->kwargs);
|
c11_vector__dtor(&self->kwargs);
|
||||||
c11_smallmap_n2d__dtor(&self->kw_to_index);
|
c11_smallmap_n2d__dtor(&self->kw_to_index);
|
||||||
if(self->docstring) py_free(self->docstring);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FuncDecl_ FuncDecl__rcnew(SourceData_ src, c11_sv name) {
|
FuncDecl_ FuncDecl__rcnew(SourceData_ src, c11_sv name) {
|
||||||
@ -31,7 +30,7 @@ FuncDecl_ FuncDecl__rcnew(SourceData_ src, c11_sv name) {
|
|||||||
self->rc.dtor = (void (*)(void*))FuncDecl__dtor;
|
self->rc.dtor = (void (*)(void*))FuncDecl__dtor;
|
||||||
CodeObject__ctor(&self->code, src, name);
|
CodeObject__ctor(&self->code, src, name);
|
||||||
|
|
||||||
c11_vector__ctor(&self->args, sizeof(int32_t));
|
c11_vector__ctor(&self->args, sizeof(int));
|
||||||
c11_vector__ctor(&self->kwargs, sizeof(FuncDeclKwArg));
|
c11_vector__ctor(&self->kwargs, sizeof(FuncDeclKwArg));
|
||||||
|
|
||||||
self->starred_arg = -1;
|
self->starred_arg = -1;
|
||||||
@ -67,8 +66,8 @@ bool FuncDecl__is_duplicated_arg(const FuncDecl* decl, py_Name name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FuncDecl__add_arg(FuncDecl* self, py_Name name) {
|
void FuncDecl__add_arg(FuncDecl* self, py_Name name) {
|
||||||
int32_t index = CodeObject__add_varname(&self->code, name);
|
int index = CodeObject__add_varname(&self->code, name);
|
||||||
c11_vector__push(int32_t, &self->args, index);
|
c11_vector__push(int, &self->args, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuncDecl__add_kwarg(FuncDecl* self, py_Name name, const py_TValue* value) {
|
void FuncDecl__add_kwarg(FuncDecl* self, py_Name name, const py_TValue* value) {
|
||||||
@ -90,6 +89,32 @@ void FuncDecl__add_starred_kwarg(FuncDecl* self, py_Name name) {
|
|||||||
self->starred_kwarg = index;
|
self->starred_kwarg = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FuncDecl_ FuncDecl__build(c11_sv name,
|
||||||
|
c11_sv* args,
|
||||||
|
int argc,
|
||||||
|
c11_sv starred_arg,
|
||||||
|
c11_sv* kwargs,
|
||||||
|
int kwargc,
|
||||||
|
py_Ref kwdefaults, // a tuple contains default values
|
||||||
|
c11_sv starred_kwarg,
|
||||||
|
const char* docstring) {
|
||||||
|
SourceData_ source = SourceData__rcnew("pass", "<bind>", EXEC_MODE, false);
|
||||||
|
FuncDecl_ decl = FuncDecl__rcnew(source, name);
|
||||||
|
for(int i = 0; i < argc; i++) {
|
||||||
|
FuncDecl__add_arg(decl, py_namev(args[i]));
|
||||||
|
}
|
||||||
|
if(starred_arg.size) { FuncDecl__add_starred_arg(decl, py_namev(starred_arg)); }
|
||||||
|
assert(py_istype(kwdefaults, tp_tuple));
|
||||||
|
assert(py_tuple_len(kwdefaults) == kwargc);
|
||||||
|
for(int i = 0; i < kwargc; i++) {
|
||||||
|
FuncDecl__add_kwarg(decl, py_namev(kwargs[i]), py_tuple_getitem(kwdefaults, i));
|
||||||
|
}
|
||||||
|
if(starred_kwarg.size) FuncDecl__add_starred_kwarg(decl, py_namev(starred_kwarg));
|
||||||
|
decl->docstring = docstring;
|
||||||
|
PK_DECREF(source);
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
|
||||||
void CodeObject__ctor(CodeObject* self, SourceData_ src, c11_sv name) {
|
void CodeObject__ctor(CodeObject* self, SourceData_ src, c11_sv name) {
|
||||||
self->src = src;
|
self->src = src;
|
||||||
PK_INCREF(src);
|
PK_INCREF(src);
|
||||||
|
|||||||
@ -1,411 +0,0 @@
|
|||||||
#include "pocketpy/objects/codeobject.h"
|
|
||||||
#include "pocketpy/common/serialize.h"
|
|
||||||
#include "pocketpy/common/utils.h"
|
|
||||||
|
|
||||||
// Magic number for CodeObject serialization: "CO" = 0x434F
|
|
||||||
#define CODEOBJECT_MAGIC 0x434F
|
|
||||||
#define CODEOBJECT_VER_MAJOR 1
|
|
||||||
#define CODEOBJECT_VER_MINOR 0
|
|
||||||
#define CODEOBJECT_VER_MINOR_MIN 0
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
static void FuncDecl__serialize(c11_serializer* s,
|
|
||||||
const FuncDecl* decl,
|
|
||||||
const struct SourceData* parent_src);
|
|
||||||
static FuncDecl_ FuncDecl__deserialize(c11_deserializer* d, SourceData_ embedded_src);
|
|
||||||
static void CodeObject__serialize(c11_serializer* s,
|
|
||||||
const CodeObject* co,
|
|
||||||
const struct SourceData* parent_src);
|
|
||||||
static CodeObject CodeObject__deserialize(c11_deserializer* d, const char* filename, SourceData_ embedded_src);
|
|
||||||
|
|
||||||
// Serialize a py_TValue constant
|
|
||||||
static void TValue__serialize(c11_serializer* s, py_Ref val) {
|
|
||||||
c11_serializer__write_type(s, val->type);
|
|
||||||
// 1. co_consts: int | float | str
|
|
||||||
// 2. function defaults: see `read_literal()` in compiler.c
|
|
||||||
switch(val->type) {
|
|
||||||
case tp_int: c11_serializer__write_i64(s, val->_i64); break;
|
|
||||||
case tp_float: c11_serializer__write_f64(s, val->_f64); break;
|
|
||||||
case tp_str: {
|
|
||||||
c11_sv sv = py_tosv((py_Ref)val);
|
|
||||||
c11_serializer__write_i32(s, sv.size);
|
|
||||||
c11_serializer__write_bytes(s, sv.data, sv.size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tp_bool: {
|
|
||||||
bool value = py_tobool(val);
|
|
||||||
c11_serializer__write_i8(s, value ? 1 : 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tp_NoneType: break;
|
|
||||||
case tp_ellipsis: break;
|
|
||||||
case tp_tuple: {
|
|
||||||
int len = py_tuple_len(val);
|
|
||||||
c11_serializer__write_i32(s, len);
|
|
||||||
for(int i = 0; i < len; i++) {
|
|
||||||
py_Ref item = py_tuple_getitem(val, i);
|
|
||||||
TValue__serialize(s, item);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: c11__abort("TValue__serialize: invalid type '%s'", py_tpname(val->type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize a py_TValue constant
|
|
||||||
static void TValue__deserialize(c11_deserializer* d, py_OutRef out) {
|
|
||||||
py_Type type = c11_deserializer__read_type(d);
|
|
||||||
switch(type) {
|
|
||||||
case tp_int: {
|
|
||||||
py_i64 v = c11_deserializer__read_i64(d);
|
|
||||||
py_newint(out, v);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tp_float: {
|
|
||||||
py_f64 v = c11_deserializer__read_f64(d);
|
|
||||||
py_newfloat(out, v);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tp_str: {
|
|
||||||
int size = c11_deserializer__read_i32(d);
|
|
||||||
char* dst = py_newstrn(out, size);
|
|
||||||
char* src = c11_deserializer__read_bytes(d, size);
|
|
||||||
memcpy(dst, src, size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tp_bool: {
|
|
||||||
bool v = c11_deserializer__read_i8(d) != 0;
|
|
||||||
py_newbool(out, v);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tp_NoneType: {
|
|
||||||
py_newnone(out);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tp_ellipsis: {
|
|
||||||
py_newellipsis(out);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case tp_tuple: {
|
|
||||||
int len = c11_deserializer__read_i32(d);
|
|
||||||
py_newtuple(out, len);
|
|
||||||
for(int i = 0; i < len; i++) {
|
|
||||||
py_ItemRef item = py_tuple_getitem(out, i);
|
|
||||||
TValue__deserialize(d, item);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
c11__abort("TValue__deserialize: invalid type '%s'", py_tpname(type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize CodeObject
|
|
||||||
static void CodeObject__serialize(c11_serializer* s,
|
|
||||||
const CodeObject* co,
|
|
||||||
const struct SourceData* parent_src) {
|
|
||||||
// SourceData
|
|
||||||
if(parent_src) {
|
|
||||||
c11__rtassert(co->src == parent_src);
|
|
||||||
}
|
|
||||||
|
|
||||||
// name
|
|
||||||
c11_serializer__write_cstr(s, co->name->data);
|
|
||||||
|
|
||||||
// codes
|
|
||||||
_Static_assert(sizeof(Bytecode) == sizeof(uint16_t) * 2, "");
|
|
||||||
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_mark(s, ']');
|
|
||||||
|
|
||||||
// codes_ex
|
|
||||||
_Static_assert(sizeof(BytecodeEx) == sizeof(int32_t) * 2, "");
|
|
||||||
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_mark(s, ']');
|
|
||||||
|
|
||||||
// consts
|
|
||||||
c11_serializer__write_i32(s, co->consts.length);
|
|
||||||
c11_serializer__write_mark(s, '[');
|
|
||||||
for(int i = 0; i < co->consts.length; i++) {
|
|
||||||
py_Ref val = c11__at(py_TValue, &co->consts, i);
|
|
||||||
TValue__serialize(s, val);
|
|
||||||
}
|
|
||||||
c11_serializer__write_mark(s, ']');
|
|
||||||
|
|
||||||
// varnames (as cstr via py_name2str)
|
|
||||||
c11_serializer__write_i32(s, co->varnames.length);
|
|
||||||
c11_serializer__write_mark(s, '[');
|
|
||||||
for(int i = 0; i < co->varnames.length; i++) {
|
|
||||||
py_Name name = c11__getitem(py_Name, &co->varnames, i);
|
|
||||||
c11_serializer__write_cstr(s, py_name2str(name));
|
|
||||||
}
|
|
||||||
c11_serializer__write_mark(s, ']');
|
|
||||||
|
|
||||||
// names (as cstr via py_name2str)
|
|
||||||
c11_serializer__write_i32(s, co->names.length);
|
|
||||||
c11_serializer__write_mark(s, '[');
|
|
||||||
for(int i = 0; i < co->names.length; i++) {
|
|
||||||
py_Name name = c11__getitem(py_Name, &co->names, i);
|
|
||||||
c11_serializer__write_cstr(s, py_name2str(name));
|
|
||||||
}
|
|
||||||
c11_serializer__write_mark(s, ']');
|
|
||||||
|
|
||||||
// nlocals
|
|
||||||
c11_serializer__write_i32(s, co->nlocals);
|
|
||||||
|
|
||||||
// blocks
|
|
||||||
_Static_assert(sizeof(CodeBlock) == sizeof(int32_t) * 5, "");
|
|
||||||
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_mark(s, ']');
|
|
||||||
|
|
||||||
// func_decls
|
|
||||||
c11_serializer__write_i32(s, co->func_decls.length);
|
|
||||||
c11_serializer__write_mark(s, '[');
|
|
||||||
for(int i = 0; i < co->func_decls.length; i++) {
|
|
||||||
const FuncDecl* decl = c11__getitem(FuncDecl_, &co->func_decls, i);
|
|
||||||
FuncDecl__serialize(s, decl, co->src);
|
|
||||||
c11_serializer__write_mark(s, '|');
|
|
||||||
}
|
|
||||||
c11_serializer__write_mark(s, ']');
|
|
||||||
|
|
||||||
// start_line, end_line
|
|
||||||
c11_serializer__write_i32(s, co->start_line);
|
|
||||||
c11_serializer__write_i32(s, co->end_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize CodeObject (initialize co before calling)
|
|
||||||
static CodeObject CodeObject__deserialize(c11_deserializer* d, const char* filename, SourceData_ embedded_src) {
|
|
||||||
CodeObject co;
|
|
||||||
|
|
||||||
// SourceData
|
|
||||||
SourceData_ src;
|
|
||||||
if(embedded_src != NULL) {
|
|
||||||
c11__rtassert(filename == NULL);
|
|
||||||
src = embedded_src;
|
|
||||||
PK_INCREF(src);
|
|
||||||
} else {
|
|
||||||
c11__rtassert(filename != NULL);
|
|
||||||
src = SourceData__rcnew(NULL, filename, EXEC_MODE, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// name
|
|
||||||
const char* name = c11_deserializer__read_cstr(d);
|
|
||||||
c11_sv name_sv = {name, strlen(name)};
|
|
||||||
|
|
||||||
// Initialize the CodeObject
|
|
||||||
CodeObject__ctor(&co, src, name_sv);
|
|
||||||
PK_DECREF(src); // CodeObject__ctor increments ref count
|
|
||||||
// Clear the default root block that CodeObject__ctor adds
|
|
||||||
c11_vector__clear(&co.blocks);
|
|
||||||
|
|
||||||
// codes
|
|
||||||
int codes_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
c11_vector__extend(&co.codes,
|
|
||||||
c11_deserializer__read_bytes(d, codes_len * sizeof(Bytecode)),
|
|
||||||
codes_len);
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
// codes_ex
|
|
||||||
int codes_ex_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
c11_vector__extend(&co.codes_ex,
|
|
||||||
c11_deserializer__read_bytes(d, codes_ex_len * sizeof(BytecodeEx)),
|
|
||||||
codes_ex_len);
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
|
|
||||||
// consts
|
|
||||||
int consts_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
for(int i = 0; i < consts_len; i++) {
|
|
||||||
py_Ref p_val = c11_vector__emplace(&co.consts);
|
|
||||||
TValue__deserialize(d, p_val);
|
|
||||||
}
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
|
|
||||||
// varnames
|
|
||||||
int varnames_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
for(int i = 0; i < varnames_len; i++) {
|
|
||||||
const char* s = c11_deserializer__read_cstr(d);
|
|
||||||
py_Name n = py_name(s);
|
|
||||||
c11_vector__push(py_Name, &co.varnames, n);
|
|
||||||
c11_smallmap_n2d__set(&co.varnames_inv, n, i);
|
|
||||||
}
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
|
|
||||||
// names
|
|
||||||
int names_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
for(int i = 0; i < names_len; i++) {
|
|
||||||
const char* s = c11_deserializer__read_cstr(d);
|
|
||||||
py_Name n = py_name(s);
|
|
||||||
c11_vector__push(py_Name, &co.names, n);
|
|
||||||
c11_smallmap_n2d__set(&co.names_inv, n, i);
|
|
||||||
}
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
|
|
||||||
// nlocals
|
|
||||||
co.nlocals = c11_deserializer__read_i32(d);
|
|
||||||
|
|
||||||
// blocks
|
|
||||||
int blocks_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
c11_vector__extend(&co.blocks,
|
|
||||||
c11_deserializer__read_bytes(d, blocks_len * sizeof(CodeBlock)),
|
|
||||||
blocks_len);
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
|
|
||||||
// func_decls
|
|
||||||
int func_decls_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
for(int i = 0; i < func_decls_len; i++) {
|
|
||||||
FuncDecl_ decl = FuncDecl__deserialize(d, src);
|
|
||||||
c11_vector__push(FuncDecl_, &co.func_decls, decl);
|
|
||||||
c11_deserializer__consume_mark(d, '|');
|
|
||||||
}
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
|
|
||||||
// start_line, end_line
|
|
||||||
co.start_line = c11_deserializer__read_i32(d);
|
|
||||||
co.end_line = c11_deserializer__read_i32(d);
|
|
||||||
|
|
||||||
return co;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize FuncDecl
|
|
||||||
static void FuncDecl__serialize(c11_serializer* s,
|
|
||||||
const FuncDecl* decl,
|
|
||||||
const struct SourceData* parent_src) {
|
|
||||||
// CodeObject (embedded)
|
|
||||||
c11_serializer__write_mark(s, '{');
|
|
||||||
CodeObject__serialize(s, &decl->code, parent_src);
|
|
||||||
c11_serializer__write_mark(s, '}');
|
|
||||||
|
|
||||||
// args
|
|
||||||
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_mark(s, ']');
|
|
||||||
|
|
||||||
// kwargs
|
|
||||||
c11_serializer__write_i32(s, decl->kwargs.length);
|
|
||||||
c11_serializer__write_mark(s, '[');
|
|
||||||
for(int i = 0; i < decl->kwargs.length; i++) {
|
|
||||||
FuncDeclKwArg* kw = c11__at(FuncDeclKwArg, &decl->kwargs, i);
|
|
||||||
c11_serializer__write_i32(s, kw->index);
|
|
||||||
c11_serializer__write_cstr(s, py_name2str(kw->key));
|
|
||||||
TValue__serialize(s, &kw->value);
|
|
||||||
}
|
|
||||||
c11_serializer__write_mark(s, ']');
|
|
||||||
|
|
||||||
// starred_arg, starred_kwarg
|
|
||||||
c11_serializer__write_i32(s, decl->starred_arg);
|
|
||||||
c11_serializer__write_i32(s, decl->starred_kwarg);
|
|
||||||
|
|
||||||
// nested
|
|
||||||
c11_serializer__write_i8(s, decl->nested ? 1 : 0);
|
|
||||||
|
|
||||||
// docstring
|
|
||||||
int has_docstring = decl->docstring != NULL ? 1 : 0;
|
|
||||||
c11_serializer__write_i8(s, has_docstring);
|
|
||||||
if(has_docstring) c11_serializer__write_cstr(s, decl->docstring);
|
|
||||||
|
|
||||||
// type
|
|
||||||
c11_serializer__write_i8(s, (int8_t)decl->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize FuncDecl
|
|
||||||
static FuncDecl_ FuncDecl__deserialize(c11_deserializer* d, SourceData_ embedded_src) {
|
|
||||||
FuncDecl_ self = PK_MALLOC(sizeof(FuncDecl));
|
|
||||||
self->rc.count = 1;
|
|
||||||
self->rc.dtor = (void (*)(void*))FuncDecl__dtor;
|
|
||||||
|
|
||||||
c11_vector__ctor(&self->args, sizeof(int32_t));
|
|
||||||
c11_vector__ctor(&self->kwargs, sizeof(FuncDeclKwArg));
|
|
||||||
c11_smallmap_n2d__ctor(&self->kw_to_index);
|
|
||||||
|
|
||||||
// CodeObject (embedded)
|
|
||||||
c11_deserializer__consume_mark(d, '{');
|
|
||||||
self->code = CodeObject__deserialize(d, NULL, embedded_src);
|
|
||||||
c11_deserializer__consume_mark(d, '}');
|
|
||||||
|
|
||||||
// args
|
|
||||||
int args_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
c11_vector__extend(&self->args,
|
|
||||||
c11_deserializer__read_bytes(d, args_len * sizeof(int32_t)),
|
|
||||||
args_len);
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
|
|
||||||
// kwargs
|
|
||||||
int kwargs_len = c11_deserializer__read_i32(d);
|
|
||||||
c11_deserializer__consume_mark(d, '[');
|
|
||||||
for(int i = 0; i < kwargs_len; i++) {
|
|
||||||
FuncDeclKwArg* kw = c11_vector__emplace(&self->kwargs);
|
|
||||||
kw->index = c11_deserializer__read_i32(d);
|
|
||||||
const char* key_str = c11_deserializer__read_cstr(d);
|
|
||||||
kw->key = py_name(key_str);
|
|
||||||
TValue__deserialize(d, &kw->value);
|
|
||||||
c11_smallmap_n2d__set(&self->kw_to_index, kw->key, kw->index);
|
|
||||||
}
|
|
||||||
c11_deserializer__consume_mark(d, ']');
|
|
||||||
|
|
||||||
// starred_arg
|
|
||||||
self->starred_arg = c11_deserializer__read_i32(d);
|
|
||||||
// starred_kwarg
|
|
||||||
self->starred_kwarg = c11_deserializer__read_i32(d);
|
|
||||||
|
|
||||||
// nested
|
|
||||||
self->nested = c11_deserializer__read_i8(d) != 0;
|
|
||||||
|
|
||||||
// docstring
|
|
||||||
int has_docstring = c11_deserializer__read_i8(d);
|
|
||||||
if(has_docstring) {
|
|
||||||
const char* docstring = c11_deserializer__read_cstr(d);
|
|
||||||
self->docstring = c11_strdup(docstring);
|
|
||||||
} else {
|
|
||||||
self->docstring = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// type
|
|
||||||
self->type = (FuncType)c11_deserializer__read_i8(d);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public API: Serialize CodeObject to bytes
|
|
||||||
void* CodeObject__dumps(const CodeObject* co, int* size) {
|
|
||||||
c11_serializer s;
|
|
||||||
c11_serializer__ctor(&s, CODEOBJECT_MAGIC, CODEOBJECT_VER_MAJOR, CODEOBJECT_VER_MINOR);
|
|
||||||
CodeObject__serialize(&s, co, NULL);
|
|
||||||
return c11_serializer__submit(&s, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public API: Deserialize CodeObject from bytes
|
|
||||||
// Returns error message or NULL on success
|
|
||||||
char* CodeObject__loads(const void* data, int size, const char* filename, CodeObject* out) {
|
|
||||||
c11_deserializer d;
|
|
||||||
c11_deserializer__ctor(&d, data, size);
|
|
||||||
|
|
||||||
if(!c11_deserializer__check_header(&d,
|
|
||||||
CODEOBJECT_MAGIC,
|
|
||||||
CODEOBJECT_VER_MAJOR,
|
|
||||||
CODEOBJECT_VER_MINOR_MIN)) {
|
|
||||||
char* error_msg = c11_strdup(d.error_msg);
|
|
||||||
c11_deserializer__dtor(&d);
|
|
||||||
return error_msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = CodeObject__deserialize(&d, filename, NULL);
|
|
||||||
c11_deserializer__dtor(&d);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CODEOBJECT_MAGIC
|
|
||||||
#undef CODEOBJECT_VER_MAJOR
|
|
||||||
#undef CODEOBJECT_VER_MINOR
|
|
||||||
#undef CODEOBJECT_VER_MINOR_MIN
|
|
||||||
@ -46,3 +46,16 @@ void py_bindmagic(py_Type type, py_Name name, py_CFunction f) {
|
|||||||
py_Ref tmp = py_emplacedict(py_tpobject(type), name);
|
py_Ref tmp = py_emplacedict(py_tpobject(type), name);
|
||||||
py_newnativefunc(tmp, f);
|
py_newnativefunc(tmp, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void py_macrobind(const char* sig, py_CFunction f) {
|
||||||
|
py_Ref tmp = py_pushtmp();
|
||||||
|
py_Name name = py_newfunction(tmp, sig, f, NULL, 0);
|
||||||
|
NameDict__set(&pk_current_vm->compile_time_funcs, name, tmp);
|
||||||
|
py_pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
py_ItemRef py_macroget(py_Name name) {
|
||||||
|
NameDict* d = &pk_current_vm->compile_time_funcs;
|
||||||
|
if(d->length == 0) return NULL;
|
||||||
|
return NameDict__try_get(d, name);
|
||||||
|
}
|
||||||
|
|||||||
@ -149,20 +149,6 @@ 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"
|
||||||
|
|
||||||
PK_INLINE py_Ref py_getreg(int i) { return pk_current_vm->reg + i; }
|
py_Ref py_getreg(int i) { return pk_current_vm->reg + i; }
|
||||||
|
|
||||||
PK_INLINE void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; }
|
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; }
|
||||||
|
|
||||||
|
|||||||
@ -32,10 +32,6 @@ void py_initialize() {
|
|||||||
_Static_assert(sizeof(py_TValue) == 24, "sizeof(py_TValue) != 24");
|
_Static_assert(sizeof(py_TValue) == 24, "sizeof(py_TValue) != 24");
|
||||||
_Static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");
|
_Static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");
|
||||||
|
|
||||||
// check sizes
|
|
||||||
_Static_assert(sizeof(float) == 4, "");
|
|
||||||
_Static_assert(sizeof(double) == 8, "");
|
|
||||||
|
|
||||||
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
|
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
|
||||||
|
|
||||||
// initialize some convenient references
|
// initialize some convenient references
|
||||||
@ -121,7 +117,7 @@ void py_sys_setargv(int argc, char** argv) {
|
|||||||
py_GlobalRef sys = py_getmodule("sys");
|
py_GlobalRef sys = py_getmodule("sys");
|
||||||
py_Ref argv_list = py_getdict(sys, py_name("argv"));
|
py_Ref argv_list = py_getdict(sys, py_name("argv"));
|
||||||
py_list_clear(argv_list);
|
py_list_clear(argv_list);
|
||||||
for(int i = 1; i < argc; i++) {
|
for(int i = 0; i < argc; i++) {
|
||||||
py_newstr(py_list_emplace(argv_list), argv[i]);
|
py_newstr(py_list_emplace(argv_list), argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,10 +78,8 @@ 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++;
|
||||||
|
|
||||||
// */__init__.py[c]
|
c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename);
|
||||||
c11_sv top_filepath = c11_string__sv(vm->top_frame->co->src->filename);
|
int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
|
||||||
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);
|
||||||
@ -142,39 +140,20 @@ int py_import(const char* path_cstr) {
|
|||||||
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
||||||
|
|
||||||
bool need_free = true;
|
bool need_free = true;
|
||||||
bool is_pyc = false;
|
|
||||||
const char* data = load_kPythonLib(path_cstr);
|
const char* data = load_kPythonLib(path_cstr);
|
||||||
int data_size = -1;
|
|
||||||
|
|
||||||
if(data != NULL) {
|
if(data != NULL) {
|
||||||
need_free = false;
|
need_free = false;
|
||||||
goto __SUCCESS;
|
goto __SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = vm->callbacks.importfile(filename->data, &data_size);
|
data = vm->callbacks.importfile(filename->data);
|
||||||
if(data != NULL) goto __SUCCESS;
|
if(data != NULL) goto __SUCCESS;
|
||||||
|
|
||||||
c11_string__delete(filename);
|
|
||||||
filename = c11_string__new3("%s.pyc", slashed_path->data);
|
|
||||||
data = vm->callbacks.importfile(filename->data, &data_size);
|
|
||||||
if(data != NULL) {
|
|
||||||
is_pyc = true;
|
|
||||||
goto __SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
c11_string__delete(filename);
|
c11_string__delete(filename);
|
||||||
filename = c11_string__new3("%s%c__init__.py", slashed_path->data, PK_PLATFORM_SEP);
|
filename = c11_string__new3("%s%c__init__.py", slashed_path->data, PK_PLATFORM_SEP);
|
||||||
data = vm->callbacks.importfile(filename->data, &data_size);
|
data = vm->callbacks.importfile(filename->data);
|
||||||
if(data != NULL) goto __SUCCESS;
|
if(data != NULL) goto __SUCCESS;
|
||||||
|
|
||||||
c11_string__delete(filename);
|
|
||||||
filename = c11_string__new3("%s%c__init__.pyc", slashed_path->data, PK_PLATFORM_SEP);
|
|
||||||
data = vm->callbacks.importfile(filename->data, &data_size);
|
|
||||||
if(data != NULL) {
|
|
||||||
is_pyc = true;
|
|
||||||
goto __SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
c11_string__delete(filename);
|
c11_string__delete(filename);
|
||||||
c11_string__delete(slashed_path);
|
c11_string__delete(slashed_path);
|
||||||
// not found
|
// not found
|
||||||
@ -183,15 +162,8 @@ int py_import(const char* path_cstr) {
|
|||||||
__SUCCESS:
|
__SUCCESS:
|
||||||
do {
|
do {
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
py_GlobalRef mod = py_newmodule(path_cstr);
|
py_GlobalRef mod = py_newmodule(path_cstr);
|
||||||
|
bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod);
|
||||||
bool ok;
|
|
||||||
if(is_pyc) {
|
|
||||||
ok = py_execo(data, data_size, filename->data, mod);
|
|
||||||
} else {
|
|
||||||
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);
|
||||||
@ -208,13 +180,11 @@ bool py_importlib_reload(py_Ref module) {
|
|||||||
c11_sv path = c11_string__sv(mi->path);
|
c11_sv path = c11_string__sv(mi->path);
|
||||||
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
|
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
|
||||||
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
||||||
// Here we only consider source modules.
|
char* data = vm->callbacks.importfile(filename->data);
|
||||||
// Because compiled modules have no source file (it cannot be reloaded)
|
|
||||||
char* data = vm->callbacks.importfile(filename->data, NULL);
|
|
||||||
if(data == NULL) {
|
if(data == NULL) {
|
||||||
c11_string__delete(filename);
|
c11_string__delete(filename);
|
||||||
filename = c11_string__new3("%s%c__init__.py", slashed_path->data, PK_PLATFORM_SEP);
|
filename = c11_string__new3("%s%c__init__.py", slashed_path->data, PK_PLATFORM_SEP);
|
||||||
data = vm->callbacks.importfile(filename->data, NULL);
|
data = vm->callbacks.importfile(filename->data);
|
||||||
}
|
}
|
||||||
c11_string__delete(slashed_path);
|
c11_string__delete(slashed_path);
|
||||||
if(data == NULL) return ImportError("module '%v' not found", path);
|
if(data == NULL) return ImportError("module '%v' not found", path);
|
||||||
|
|||||||
@ -203,8 +203,8 @@ static bool list__add__(int argc, py_Ref argv) {
|
|||||||
List* list_1 = py_touserdata(_1);
|
List* list_1 = py_touserdata(_1);
|
||||||
py_newlist(py_retval());
|
py_newlist(py_retval());
|
||||||
List* list = py_touserdata(py_retval());
|
List* list = py_touserdata(py_retval());
|
||||||
c11_vector__extend(list, list_0->data, list_0->length);
|
c11_vector__extend(py_TValue, list, list_0->data, list_0->length);
|
||||||
c11_vector__extend(list, list_1->data, list_1->length);
|
c11_vector__extend(py_TValue, list, list_1->data, list_1->length);
|
||||||
} else {
|
} else {
|
||||||
py_newnotimplemented(py_retval());
|
py_newnotimplemented(py_retval());
|
||||||
}
|
}
|
||||||
@ -221,7 +221,7 @@ static bool list__mul__(int argc, py_Ref argv) {
|
|||||||
List* list = py_touserdata(py_retval());
|
List* list = py_touserdata(py_retval());
|
||||||
List* list_0 = py_touserdata(_0);
|
List* list_0 = py_touserdata(_0);
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++) {
|
||||||
c11_vector__extend(list, list_0->data, list_0->length);
|
c11_vector__extend(py_TValue, list, list_0->data, list_0->length);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
py_newnotimplemented(py_retval());
|
py_newnotimplemented(py_retval());
|
||||||
@ -264,7 +264,7 @@ static bool list_extend(int argc, py_Ref argv) {
|
|||||||
py_TValue* p;
|
py_TValue* p;
|
||||||
int length = pk_arrayview(py_arg(1), &p);
|
int length = pk_arrayview(py_arg(1), &p);
|
||||||
if(length == -1) return TypeError("extend() argument must be a list or tuple");
|
if(length == -1) return TypeError("extend() argument must be a list or tuple");
|
||||||
c11_vector__extend(self, p, length);
|
c11_vector__extend(py_TValue, self, p, length);
|
||||||
py_newnone(py_retval());
|
py_newnone(py_retval());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -293,7 +293,7 @@ static bool list_copy(int argc, py_Ref argv) {
|
|||||||
py_newlist(py_retval());
|
py_newlist(py_retval());
|
||||||
List* self = py_touserdata(py_arg(0));
|
List* self = py_touserdata(py_arg(0));
|
||||||
List* list = py_touserdata(py_retval());
|
List* list = py_touserdata(py_retval());
|
||||||
c11_vector__extend(list, self->data, self->length);
|
c11_vector__extend(py_TValue, list, self->data, self->length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -121,7 +121,7 @@ py_Name py_newfunction(py_OutRef out,
|
|||||||
c11__abort("py_newfunction(): invalid signature '%s'", sig);
|
c11__abort("py_newfunction(): invalid signature '%s'", sig);
|
||||||
}
|
}
|
||||||
FuncDecl_ decl = c11__getitem(FuncDecl_, &code.func_decls, 0);
|
FuncDecl_ decl = c11__getitem(FuncDecl_, &code.func_decls, 0);
|
||||||
if(docstring) decl->docstring = c11_strdup(docstring);
|
decl->docstring = docstring;
|
||||||
// construct the function
|
// construct the function
|
||||||
Function* ud = py_newobject(out, tp_function, slots, sizeof(Function));
|
Function* ud = py_newobject(out, tp_function, slots, sizeof(Function));
|
||||||
Function__ctor(ud, decl, NULL, NULL);
|
Function__ctor(ud, decl, NULL, NULL);
|
||||||
|
|||||||
82
src2/main.c
82
src2/main.c
@ -9,17 +9,18 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static char* readfile(const char* path, int* data_size) {
|
static char* read_file(const char* path) {
|
||||||
FILE* f = fopen(path, "rb");
|
FILE* file = fopen(path, "rb");
|
||||||
if(f == NULL) return NULL;
|
if(file == NULL) {
|
||||||
fseek(f, 0, SEEK_END);
|
printf("Error: file not found\n");
|
||||||
long size = ftell(f);
|
return NULL;
|
||||||
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, f);
|
size = fread(buffer, 1, size, file);
|
||||||
buffer[size] = 0;
|
buffer[size] = 0;
|
||||||
fclose(f);
|
|
||||||
if(data_size) *data_size = (int)size;
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,9 +34,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
bool profile = false;
|
bool profile = false;
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
bool compile = false;
|
const char* filename = NULL;
|
||||||
const char* arg1 = NULL;
|
|
||||||
const char* arg2 = NULL;
|
|
||||||
|
|
||||||
for(int i = 1; i < argc; i++) {
|
for(int i = 1; i < argc; i++) {
|
||||||
if(strcmp(argv[i], "--profile") == 0) {
|
if(strcmp(argv[i], "--profile") == 0) {
|
||||||
@ -46,19 +45,11 @@ int main(int argc, char** argv) {
|
|||||||
debug = true;
|
debug = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(strcmp(argv[i], "--compile") == 0) {
|
if(filename == NULL) {
|
||||||
compile = true;
|
filename = argv[i];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(arg1 == NULL) {
|
printf("Usage: pocketpy [--profile] [--debug] filename\n");
|
||||||
arg1 = argv[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(arg2 == NULL) {
|
|
||||||
arg2 = argv[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
printf("Usage: pocketpy [--profile] [--debug] [--compile] filename\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(debug && profile) {
|
if(debug && profile) {
|
||||||
@ -66,22 +57,9 @@ int main(int argc, char** argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(compile && (debug || profile)) {
|
|
||||||
printf("Error: --compile cannot be used with --debug or --profile.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
py_initialize();
|
py_initialize();
|
||||||
py_sys_setargv(argc, argv);
|
py_sys_setargv(argc, argv);
|
||||||
|
|
||||||
if(compile) {
|
|
||||||
bool ok = py_compilefile(arg1, arg2);
|
|
||||||
if(!ok) py_printexc();
|
|
||||||
py_finalize();
|
|
||||||
return ok ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* filename = arg1;
|
|
||||||
if(filename == NULL) {
|
if(filename == NULL) {
|
||||||
if(profile) printf("Warning: --profile is ignored in REPL mode.\n");
|
if(profile) printf("Warning: --profile is ignored in REPL mode.\n");
|
||||||
if(debug) printf("Warning: --debug is ignored in REPL mode.\n");
|
if(debug) printf("Warning: --debug is ignored in REPL mode.\n");
|
||||||
@ -114,28 +92,9 @@ 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);
|
||||||
|
|
||||||
int data_size;
|
char* source = read_file(filename);
|
||||||
char* data = readfile(filename, &data_size);
|
if(source) {
|
||||||
// check filename endswith .pyc
|
if(!py_exec(source, filename, EXEC_MODE, NULL)) py_printexc();
|
||||||
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();
|
||||||
@ -146,11 +105,8 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
PK_FREE(json_report);
|
PK_FREE(json_report);
|
||||||
}
|
}
|
||||||
PK_FREE(data);
|
|
||||||
} else {
|
PK_FREE(source);
|
||||||
printf("Error: cannot open file '%s'\n", filename);
|
|
||||||
py_finalize();
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,14 +3,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
import sys
|
os.chdir('tests')
|
||||||
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
|
||||||
@ -56,11 +49,8 @@ from math import (
|
|||||||
cos
|
cos
|
||||||
)
|
)
|
||||||
|
|
||||||
assert __import__('math').pi > 3
|
|
||||||
|
|
||||||
# test reload (dummy)
|
# test reload (dummy)
|
||||||
if not is_pyc:
|
import importlib
|
||||||
import importlib
|
importlib.reload(test2.a)
|
||||||
importlib.reload(test2.a)
|
|
||||||
|
|
||||||
|
|
||||||
|
assert __import__('math').pi > 3
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
assert (sys.argv in [
|
assert len(sys.argv) == 2
|
||||||
['tests/801_sys.py'],
|
assert (sys.argv[1] == 'tests/801_sys.py'), sys.argv
|
||||||
['tmp/tests/801_sys.pyc'],
|
|
||||||
]), sys.argv
|
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,4 @@
|
|||||||
import traceback
|
import traceback
|
||||||
import sys
|
|
||||||
|
|
||||||
if sys.argv[0].endswith('.pyc'):
|
|
||||||
exit()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
a = {'123': 4}
|
a = {'123': 4}
|
||||||
@ -11,7 +7,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 9
|
File "tests/802_traceback.py", line 5
|
||||||
b = a[6]
|
b = a[6]
|
||||||
KeyError: 6'''
|
KeyError: 6'''
|
||||||
|
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
try:
|
|
||||||
import os
|
|
||||||
except ImportError:
|
|
||||||
print('os is not enabled, skipping test...')
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
import sys
|
|
||||||
if sys.platform == 'win32':
|
|
||||||
exe_name = 'main.exe'
|
|
||||||
else:
|
|
||||||
exe_name = './main'
|
|
||||||
assert os.system(f'{exe_name} --compile python/heapq.py heapq1.pyc') == 0
|
|
||||||
assert os.path.exists('heapq1.pyc')
|
|
||||||
|
|
||||||
import heapq1
|
|
||||||
import heapq
|
|
||||||
|
|
||||||
a = [1, 2, -3, 2, 1, 5, 11, 123] * 10
|
|
||||||
b = a.copy()
|
|
||||||
|
|
||||||
heapq.heapify(a)
|
|
||||||
heapq1.heapify(b)
|
|
||||||
|
|
||||||
assert a == b
|
|
||||||
|
|
||||||
os.remove('heapq1.pyc')
|
|
||||||
Loading…
x
Reference in New Issue
Block a user