mirror of
https://github.com/pocketpy/pocketpy
synced 2025-12-06 18:20:17 +00:00
remove *.cpp
This commit is contained in:
parent
23d7b56c86
commit
19ed0fdaf5
BIN
.github/workflows.zip
vendored
Normal file
BIN
.github/workflows.zip
vendored
Normal file
Binary file not shown.
204
.github/workflows/main.yml
vendored
204
.github/workflows/main.yml
vendored
@ -1,204 +0,0 @@
|
||||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'web/**'
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'web/**'
|
||||
- '**.md'
|
||||
jobs:
|
||||
# build_win32_amalgamated:
|
||||
# runs-on: windows-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - uses: ilammy/msvc-dev-cmd@v1
|
||||
# - name: Compile
|
||||
# shell: powershell
|
||||
# run: |
|
||||
# python amalgamate.py
|
||||
# cd amalgamated
|
||||
# cl.exe /std:c++17 /EHsc /utf-8 /Ox /I. /DPK_ENABLE_OS=1 main.cpp /link /out:pkpy.exe
|
||||
build_win32:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Compile
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p output/x86_64
|
||||
python cmake_build.py
|
||||
cp main.exe output/x86_64
|
||||
cp pocketpy.dll output/x86_64
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows
|
||||
path: output
|
||||
- name: Unit Test
|
||||
run: python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
build_linux:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Clang
|
||||
uses: egor-tensin/setup-clang@v1
|
||||
with:
|
||||
version: 15
|
||||
platform: x64
|
||||
- name: Install libc++
|
||||
run: sudo apt-get install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev
|
||||
# - name: Unit Test with Coverage
|
||||
# run: bash run_tests.sh
|
||||
# - name: Upload coverage reports to Codecov
|
||||
# uses: codecov/codecov-action@v4
|
||||
# with:
|
||||
# token: ${{ secrets.CODECOV_TOKEN }}
|
||||
# directory: .coverage
|
||||
# if: github.ref == 'refs/heads/main'
|
||||
- name: Compile and Test
|
||||
run: |
|
||||
mkdir -p output/x86_64
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
cp main output/x86_64
|
||||
cp libpocketpy.so output/x86_64
|
||||
env:
|
||||
CXX: clang++
|
||||
CC: clang
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux
|
||||
path: output
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
- name: C Binding Test
|
||||
run: bash run_c_binding_test.sh
|
||||
build_linux_x86:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Alpine Linux for aarch64
|
||||
uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: x86
|
||||
packages: gcc g++ make cmake libc-dev linux-headers python3
|
||||
- name: Build and Test
|
||||
run: |
|
||||
uname -m
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
python scripts/run_tests.py benchmark
|
||||
shell: alpine.sh --root {0}
|
||||
build_darwin:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile and Test
|
||||
run: |
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
# - run: |
|
||||
# python amalgamate.py
|
||||
# cd plugins/macos/pocketpy
|
||||
# mkdir output
|
||||
# xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
|
||||
# cp -r build/Release/pocketpy.bundle output
|
||||
# - uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: macos
|
||||
# path: plugins/macos/pocketpy/output
|
||||
build_android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r23
|
||||
local-cache: false
|
||||
add-to-path: false
|
||||
- name: Compile Shared Library
|
||||
run: |
|
||||
bash build_android.sh arm64-v8a
|
||||
bash build_android.sh armeabi-v7a
|
||||
bash build_android.sh x86_64
|
||||
|
||||
mkdir -p output/arm64-v8a
|
||||
mkdir -p output/armeabi-v7a
|
||||
mkdir -p output/x86_64
|
||||
|
||||
cp build/android/arm64-v8a/libpocketpy.so output/arm64-v8a
|
||||
cp build/android/armeabi-v7a/libpocketpy.so output/armeabi-v7a
|
||||
cp build/android/x86_64/libpocketpy.so output/x86_64
|
||||
env:
|
||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: android
|
||||
path: output
|
||||
build_ios:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile Frameworks
|
||||
run: |
|
||||
git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake
|
||||
bash build_ios.sh
|
||||
mkdir -p output
|
||||
cp -r build/pocketpy.xcframework output/pocketpy.xcframework
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ios
|
||||
path: output
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ build_win32, build_linux, build_darwin, build_android, build_ios ]
|
||||
steps:
|
||||
- name: "Create output directory"
|
||||
run: "mkdir $GITHUB_WORKSPACE/output"
|
||||
|
||||
- name: "Merge win32"
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
name: windows
|
||||
path: $GITHUB_WORKSPACE/output/windows
|
||||
|
||||
- name: "Merge linux"
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
name: linux
|
||||
path: $GITHUB_WORKSPACE/output/linux
|
||||
|
||||
# - name: "Merge darwin"
|
||||
# uses: actions/download-artifact@v4.1.7
|
||||
# with:
|
||||
# name: macos
|
||||
# path: $GITHUB_WORKSPACE/output/macos
|
||||
|
||||
- name: "Merge android"
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
name: android
|
||||
path: $GITHUB_WORKSPACE/output/android
|
||||
|
||||
- name: "Merge ios"
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
name: ios
|
||||
path: $GITHUB_WORKSPACE/output/ios
|
||||
|
||||
- name: "Upload merged artifact"
|
||||
uses: actions/upload-artifact@v4.3.3
|
||||
with:
|
||||
name: all-in-one
|
||||
path: $GITHUB_WORKSPACE/output
|
||||
42
.github/workflows/website.yml
vendored
42
.github/workflows/website.yml
vendored
@ -1,42 +0,0 @@
|
||||
name: website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
###################################################
|
||||
- uses: actions/setup-node@v3.1.1
|
||||
- name: Retype build
|
||||
run: |
|
||||
python scripts/build_references.py
|
||||
cd docs
|
||||
npm install retypeapp --global
|
||||
retype build
|
||||
###################################################
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
with:
|
||||
version: 3.1.25
|
||||
actions-cache-folder: 'emsdk-cache'
|
||||
- name: Compile
|
||||
run: |
|
||||
bash build_web.sh
|
||||
mv web docs/.retype/static
|
||||
###################################################
|
||||
- uses: crazy-max/ghaction-github-pages@v3
|
||||
with:
|
||||
target_branch: gh-pages
|
||||
build_dir: docs/.retype
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: github.ref == 'refs/heads/main'
|
||||
@ -1,9 +1,9 @@
|
||||
-Wall
|
||||
-W*
|
||||
-xc++
|
||||
-xc
|
||||
|
||||
-std=c++17
|
||||
-std=c11
|
||||
|
||||
-Iinclude/
|
||||
-I3rd/cjson/include/
|
||||
-I3rd/lua_bridge/include/
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/pocketpy.hpp"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/pocketpy.hpp"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
|
||||
|
||||
@ -1,404 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/common/vector.hpp"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct Str: pkpy_Str {
|
||||
bool is_inlined() const { return is_sso; }
|
||||
|
||||
Str(){
|
||||
pkpy_Str__ctor2(this, "", 0);
|
||||
}
|
||||
|
||||
Str(pkpy_Str&& s){
|
||||
std::memcpy(this, &s, sizeof(pkpy_Str));
|
||||
}
|
||||
|
||||
Str(const std::string& s){
|
||||
pkpy_Str__ctor2(this, s.data(), s.size());
|
||||
}
|
||||
|
||||
Str(std::string_view s){
|
||||
pkpy_Str__ctor2(this, s.data(), s.size());
|
||||
}
|
||||
|
||||
Str(const char* s){
|
||||
pkpy_Str__ctor2(this, s, strlen(s));
|
||||
}
|
||||
|
||||
Str(const char* s, int len){
|
||||
pkpy_Str__ctor2(this, s, len);
|
||||
}
|
||||
|
||||
Str(pair<char*, int> detached) {
|
||||
this->size = detached.second;
|
||||
this->is_ascii = c11__isascii(detached.first, detached.second);
|
||||
this->is_sso = false;
|
||||
this->_ptr = detached.first;
|
||||
assert(_ptr[size] == '\0');
|
||||
}
|
||||
|
||||
Str(const Str& other){
|
||||
pkpy_Str__ctor2(this, pkpy_Str__data(&other), other.size);
|
||||
}
|
||||
|
||||
Str(Str&& other){
|
||||
std::memcpy(this, &other, sizeof(pkpy_Str));
|
||||
other.size = 0;
|
||||
other.is_sso = true;
|
||||
}
|
||||
|
||||
operator std::string_view () const { return sv(); }
|
||||
const char* begin() const { return pkpy_Str__data(this); }
|
||||
const char* end() const { return pkpy_Str__data(this) + size; }
|
||||
int length() const { return size; }
|
||||
char operator[] (int idx) const { return pkpy_Str__data(this)[idx]; }
|
||||
bool empty() const { return size == 0; }
|
||||
size_t hash() const { return std::hash<std::string_view>()(sv()); }
|
||||
|
||||
Str& operator= (const Str& other){
|
||||
pkpy_Str__dtor(this);
|
||||
pkpy_Str__ctor2(this, pkpy_Str__data(&other), other.size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Str operator+ (const Str& other) const{
|
||||
return pkpy_Str__concat(this, &other);
|
||||
}
|
||||
|
||||
Str operator+ (const char* other) const{
|
||||
return pkpy_Str__concat2(this, other, strlen(other));
|
||||
}
|
||||
|
||||
friend Str operator+ (const char* self, const Str& other){
|
||||
pkpy_Str tmp;
|
||||
pkpy_Str__ctor2(&tmp, self, strlen(self));
|
||||
pkpy_Str retval = pkpy_Str__concat(&tmp, &other);
|
||||
pkpy_Str__dtor(&tmp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool operator== (const std::string_view other) const{
|
||||
int res = pkpy_Str__cmp2(this, other.data(), other.size());
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
bool operator!= (const std::string_view other) const{
|
||||
int res = pkpy_Str__cmp2(this, other.data(), other.size());
|
||||
return res != 0;
|
||||
}
|
||||
|
||||
bool operator< (const std::string_view other) const{
|
||||
int res = pkpy_Str__cmp2(this, other.data(), other.size());
|
||||
return res < 0;
|
||||
}
|
||||
|
||||
friend bool operator< (const std::string_view other, const Str& str){
|
||||
int res = pkpy_Str__cmp2(&str, other.data(), other.size());
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
bool operator== (const char* p) const{
|
||||
int res = pkpy_Str__cmp2(this, p, strlen(p));
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
bool operator!= (const char* p) const{
|
||||
int res = pkpy_Str__cmp2(this, p, strlen(p));
|
||||
return res != 0;
|
||||
}
|
||||
|
||||
bool operator== (const Str& other) const{
|
||||
return pkpy_Str__cmp(this, &other) == 0;
|
||||
}
|
||||
bool operator!= (const Str& other) const{
|
||||
return pkpy_Str__cmp(this, &other) != 0;
|
||||
}
|
||||
bool operator< (const Str& other) const{
|
||||
return pkpy_Str__cmp(this, &other) < 0;
|
||||
}
|
||||
bool operator> (const Str& other) const{
|
||||
return pkpy_Str__cmp(this, &other) > 0;
|
||||
}
|
||||
bool operator<= (const Str& other) const{
|
||||
return pkpy_Str__cmp(this, &other) <= 0;
|
||||
}
|
||||
bool operator>= (const Str& other) const{
|
||||
return pkpy_Str__cmp(this, &other) >= 0;
|
||||
}
|
||||
|
||||
~Str(){
|
||||
pkpy_Str__dtor(this);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<< (std::ostream& os, const Str& self){
|
||||
os.write(pkpy_Str__data(&self), self.size);
|
||||
return os;
|
||||
}
|
||||
|
||||
const char* c_str() const { return pkpy_Str__data(this); }
|
||||
|
||||
std::string_view sv() const {
|
||||
return std::string_view(pkpy_Str__data(this), size);
|
||||
}
|
||||
|
||||
std::string str() const {
|
||||
return std::string(pkpy_Str__data(this), size);
|
||||
}
|
||||
|
||||
Str slice(int start, int stop) const{
|
||||
return pkpy_Str__slice2(this, start, stop);
|
||||
}
|
||||
|
||||
Str slice(int start) const{
|
||||
return pkpy_Str__slice(this, start);
|
||||
}
|
||||
|
||||
Str substr(int start) const{
|
||||
return pkpy_Str__slice(this, start);
|
||||
}
|
||||
|
||||
Str strip(bool left, bool right, const Str& chars) const{
|
||||
return pkpy_Str__strip2(this, left, right, &chars);
|
||||
}
|
||||
|
||||
Str strip(bool left = true, bool right = true) const{
|
||||
return pkpy_Str__strip(this, left, right);
|
||||
}
|
||||
|
||||
Str lstrip() const { return strip(true, false); }
|
||||
|
||||
Str rstrip() const { return strip(false, true); }
|
||||
|
||||
Str lower() const{
|
||||
return pkpy_Str__lower(this);
|
||||
}
|
||||
Str upper() const{
|
||||
return pkpy_Str__upper(this);
|
||||
}
|
||||
Str replace(char old, char new_) const{
|
||||
return pkpy_Str__replace(this, old, new_);
|
||||
}
|
||||
Str replace(const Str& old, const Str& new_) const{
|
||||
return pkpy_Str__replace2(this, &old, &new_);
|
||||
}
|
||||
|
||||
Str escape(char quote='\'') const{
|
||||
return pkpy_Str__escape(this, quote);
|
||||
}
|
||||
|
||||
vector<std::string_view> split(const Str& sep) const{
|
||||
c11_vector/* T=c11_string */ res = pkpy_Str__split2(this, &sep);
|
||||
vector<std::string_view> retval(res.count);
|
||||
for(int i = 0; i < res.count; i++){
|
||||
c11_string tmp = c11__getitem(c11_string, &res, i);
|
||||
retval[i] = std::string_view(tmp.data, tmp.size);
|
||||
}
|
||||
c11_vector__dtor(&res);
|
||||
return retval;
|
||||
}
|
||||
|
||||
vector<std::string_view> split(char sep) const{
|
||||
c11_vector/* T=c11_string */ res = pkpy_Str__split(this, sep);
|
||||
vector<std::string_view> retval(res.count);
|
||||
for(int i = 0; i < res.count; i++){
|
||||
c11_string tmp = c11__getitem(c11_string, &res, i);
|
||||
retval[i] = std::string_view(tmp.data, tmp.size);
|
||||
}
|
||||
c11_vector__dtor(&res);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int index(const Str& sub, int start = 0) const{
|
||||
return pkpy_Str__index(this, &sub, start);
|
||||
}
|
||||
|
||||
int count(const Str& sub) const{
|
||||
return pkpy_Str__count(this, &sub);
|
||||
}
|
||||
|
||||
/*************unicode*************/
|
||||
int _unicode_index_to_byte(int i) const{
|
||||
return pkpy_Str__unicode_index_to_byte(this, i);
|
||||
}
|
||||
|
||||
int _byte_index_to_unicode(int n) const{
|
||||
return pkpy_Str__byte_index_to_unicode(this, n);
|
||||
}
|
||||
|
||||
Str u8_getitem(int i) const{
|
||||
return pkpy_Str__u8_getitem(this, i);
|
||||
}
|
||||
|
||||
Str u8_slice(int start, int stop, int step) const{
|
||||
return pkpy_Str__u8_slice(this, start, stop, step);
|
||||
}
|
||||
|
||||
int u8_length() const{
|
||||
return pkpy_Str__u8_length(this);
|
||||
}
|
||||
};
|
||||
|
||||
struct StrName {
|
||||
uint16_t index;
|
||||
|
||||
StrName() : index(0) {}
|
||||
|
||||
StrName(uint16_t index) : index(index) {}
|
||||
|
||||
StrName(const char* s) : index(get(s).index) {}
|
||||
|
||||
StrName(const Str& s) : index(get(s.sv()).index) {}
|
||||
|
||||
bool empty() const { return index == 0; }
|
||||
|
||||
Str escape() const { return Str(sv()).escape(); }
|
||||
|
||||
bool operator== (const StrName& other) const noexcept { return this->index == other.index; }
|
||||
|
||||
bool operator!= (const StrName& other) const noexcept { return this->index != other.index; }
|
||||
|
||||
bool operator< (const StrName& other) const noexcept { return sv() < other.sv(); }
|
||||
|
||||
bool operator> (const StrName& other) const noexcept { return sv() > other.sv(); }
|
||||
|
||||
inline static StrName get(std::string_view s){
|
||||
uint16_t index = pkpy_StrName__map2({s.data(), (int)s.size()});
|
||||
return StrName(index);
|
||||
}
|
||||
|
||||
std::string_view sv() const{
|
||||
return pkpy_StrName__rmap(index);
|
||||
}
|
||||
|
||||
const char* c_str() const{
|
||||
return pkpy_StrName__rmap(index);
|
||||
}
|
||||
};
|
||||
|
||||
struct SStream: pk_SStream {
|
||||
PK_ALWAYS_PASS_BY_POINTER(SStream)
|
||||
|
||||
int _precision = -1;
|
||||
bool _submited = false;
|
||||
bool empty() const { return data.count == 0; }
|
||||
|
||||
void setprecision(int precision) { _precision = precision; }
|
||||
|
||||
SStream() {
|
||||
pk_SStream__ctor(this);
|
||||
}
|
||||
|
||||
SStream(int guess_size) { c11_vector__reserve(&data, guess_size); }
|
||||
|
||||
~SStream() {
|
||||
// in case of error
|
||||
if(!_submited) pk_SStream__dtor(this);
|
||||
}
|
||||
|
||||
Str str(){
|
||||
assert(!_submited);
|
||||
_submited = true;
|
||||
return pk_SStream__submit(this);
|
||||
}
|
||||
|
||||
SStream& operator<< (const Str& val){
|
||||
pk_SStream__write_Str(this, &val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (const char* val){
|
||||
pk_SStream__write_cstr(this, val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (int val){
|
||||
pk_SStream__write_int(this, val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (size_t val){
|
||||
// size_t could overflow int64, but nevermind...
|
||||
pk_SStream__write_i64(this, val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (i64 val){
|
||||
pk_SStream__write_i64(this, val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (f64 val){
|
||||
pk_SStream__write_double(this, val, _precision);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (const std::string& val){
|
||||
pk_SStream__write_cstrn(this, val.data(), val.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (std::string_view val){
|
||||
pk_SStream__write_cstrn(this, val.data(), val.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (c11_string val){
|
||||
pk_SStream__write_cstrn(this, val.data, val.size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (char val){
|
||||
pk_SStream__write_char(this, val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& operator<< (StrName name){
|
||||
std::string_view sv = name.sv();
|
||||
pk_SStream__write_cstrn(this, sv.data(), sv.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void write_hex(unsigned char val, bool non_zero = false){
|
||||
pk_SStream__write_hex(this, val, non_zero);
|
||||
}
|
||||
|
||||
void write_ptr(void* p){
|
||||
pk_SStream__write_ptr(this, p);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _S
|
||||
#undef _S
|
||||
#endif
|
||||
|
||||
template <typename... Args>
|
||||
Str _S(Args&&... args) {
|
||||
SStream ss;
|
||||
(ss << ... << args);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
struct CString {
|
||||
const char* ptr;
|
||||
|
||||
CString(const char* ptr) : ptr(ptr) {}
|
||||
|
||||
operator const char* () const { return ptr; }
|
||||
};
|
||||
|
||||
#define DEF_SNAME(name) const static StrName name(#name)
|
||||
|
||||
} // namespace pkpy
|
||||
@ -7,14 +7,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint16_t pkpy_StrName;
|
||||
typedef uint16_t StrName;
|
||||
|
||||
uint16_t pkpy_StrName__map(const char*);
|
||||
uint16_t pkpy_StrName__map2(c11_string);
|
||||
const char* pkpy_StrName__rmap(uint16_t index);
|
||||
uint16_t pk_StrName__map(const char*);
|
||||
uint16_t pk_StrName__map2(c11_string);
|
||||
const char* pk_StrName__rmap(uint16_t index);
|
||||
|
||||
void pkpy_StrName__initialize();
|
||||
void pkpy_StrName__finalize();
|
||||
void pk_StrName__initialize();
|
||||
void pk_StrName__finalize();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
// is_pod_v<> for c++17 and c++20
|
||||
template <typename T>
|
||||
constexpr inline bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/is_integral
|
||||
template <typename T>
|
||||
constexpr inline bool is_integral_v = !std::is_same_v<T, bool> && std::is_integral_v<T>;
|
||||
|
||||
template <typename T>
|
||||
constexpr inline bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>;
|
||||
|
||||
// by default, only `int` and `float` enable SSO
|
||||
// users can specialize this template to enable SSO for other types
|
||||
// SSO types cannot have instance dict
|
||||
template <typename T>
|
||||
constexpr inline bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
|
||||
|
||||
template <typename T>
|
||||
using obj_get_t = T&;
|
||||
|
||||
template <typename T>
|
||||
constexpr inline bool is_trivially_relocatable_v =
|
||||
std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
|
||||
|
||||
template <typename, typename = void>
|
||||
struct has_gc_marker : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr inline int py_sizeof = 16 + sizeof(T);
|
||||
|
||||
#define PK_ALWAYS_PASS_BY_POINTER(T) \
|
||||
T(const T&) = delete; \
|
||||
T& operator= (const T&) = delete; \
|
||||
T(T&&) = delete; \
|
||||
T& operator= (T&&) = delete;
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
using i64 = int64_t; // always 64-bit
|
||||
using f64 = double; // always 64-bit
|
||||
|
||||
static_assert(sizeof(i64) == 8);
|
||||
static_assert(sizeof(f64) == 8);
|
||||
|
||||
// Explicitly allow copying if copy constructor is deleted
|
||||
struct explicit_copy_t {
|
||||
explicit explicit_copy_t() = default;
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct pair {
|
||||
K first;
|
||||
V second;
|
||||
pair(K first, V second) : first(first), second(second) {}
|
||||
};
|
||||
|
||||
// Dummy types
|
||||
struct DummyInstance {};
|
||||
|
||||
struct DummyModule {};
|
||||
|
||||
struct NoReturn {};
|
||||
|
||||
// Forward declarations
|
||||
struct PyObject;
|
||||
struct Frame;
|
||||
class VM;
|
||||
|
||||
}; // namespace pkpy
|
||||
@ -33,6 +33,8 @@ extern const char* kPlatformStrings[];
|
||||
#define PK_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define PK_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define PK_ARRAY_COUNT(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
// NARGS
|
||||
#define PK_NARGS_SEQ(_1, _2, _3, _4, N, ...) N
|
||||
#define PK_NARGS(...) PK_NARGS_SEQ(__VA_ARGS__, 4, 3, 2, 1, 0)
|
||||
|
||||
@ -1,459 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include "pocketpy/common/traits.hpp"
|
||||
#include "pocketpy/common/types.hpp"
|
||||
#include "pocketpy/common/algorithm.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
template <typename T>
|
||||
struct array {
|
||||
static_assert(is_pod_v<T>);
|
||||
|
||||
T* _data;
|
||||
int _size;
|
||||
|
||||
using size_type = int;
|
||||
|
||||
array() : _data(nullptr), _size(0) {}
|
||||
|
||||
array(int size) : _data((T*)std::malloc(sizeof(T) * size)), _size(size) {}
|
||||
|
||||
array(array&& other) noexcept : _data(other._data), _size(other._size) {
|
||||
other._data = nullptr;
|
||||
other._size = 0;
|
||||
}
|
||||
|
||||
array(const array& other) = delete;
|
||||
|
||||
array(explicit_copy_t, const array& other) {
|
||||
_data = (T*)std::malloc(sizeof(T) * other._size);
|
||||
_size = other._size;
|
||||
for(int i = 0; i < _size; i++)
|
||||
_data[i] = other._data[i];
|
||||
}
|
||||
|
||||
array(T* data, int size) : _data(data), _size(size) {}
|
||||
|
||||
array& operator= (array&& other) noexcept {
|
||||
if(_data) std::free(_data);
|
||||
_data = other._data;
|
||||
_size = other._size;
|
||||
other._data = nullptr;
|
||||
other._size = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
array& operator= (const array& other) = delete;
|
||||
|
||||
T& operator[] (int i) {
|
||||
assert(i >= 0 && i < _size);
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
const T& operator[] (int i) const {
|
||||
assert(i >= 0 && i < _size);
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
int size() const { return _size; }
|
||||
|
||||
T* begin() const { return _data; }
|
||||
|
||||
T* end() const { return _data + _size; }
|
||||
|
||||
T* data() const { return _data; }
|
||||
|
||||
pair<T*, int> detach() noexcept {
|
||||
pair<T*, int> retval(_data, _size);
|
||||
_data = nullptr;
|
||||
_size = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
~array() {
|
||||
if(_data) std::free(_data);
|
||||
}
|
||||
};
|
||||
|
||||
template <bool may_alias = false, typename T>
|
||||
void uninitialized_copy_n(const T* src, int n, T* dest) {
|
||||
if(n == 0) return;
|
||||
if constexpr(std::is_trivially_copyable_v<T>) {
|
||||
if constexpr(may_alias) {
|
||||
std::memmove(dest, src, sizeof(T) * n);
|
||||
} else {
|
||||
std::memcpy(dest, src, sizeof(T) * n);
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < n; i++) {
|
||||
new (dest + i) T(*(src + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool may_alias = false, bool backward = false, typename T>
|
||||
void uninitialized_relocate_n(T* src, int n, T* dest) {
|
||||
if(n == 0) return;
|
||||
if constexpr(is_trivially_relocatable_v<T>) {
|
||||
if constexpr(may_alias) {
|
||||
std::memmove(dest, src, sizeof(T) * n);
|
||||
} else {
|
||||
std::memcpy(dest, src, sizeof(T) * n);
|
||||
}
|
||||
} else {
|
||||
if constexpr(backward) {
|
||||
for(int i = n - 1; i >= 0; i--) {
|
||||
new (dest + i) T(std::move(*(src + i)));
|
||||
(src + i)->~T();
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < n; i++) {
|
||||
new (dest + i) T(std::move(*(src + i)));
|
||||
(src + i)->~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct vector {
|
||||
T* _data;
|
||||
int _capacity;
|
||||
int _size;
|
||||
|
||||
using size_type = int;
|
||||
|
||||
vector() : _data(nullptr), _capacity(0), _size(0) {}
|
||||
|
||||
vector(int size) : _data((T*)std::malloc(sizeof(T) * size)), _capacity(size), _size(size) {}
|
||||
|
||||
vector(vector&& other) noexcept : _data(other._data), _capacity(other._capacity), _size(other._size) {
|
||||
other._data = nullptr;
|
||||
other._capacity = 0;
|
||||
other._size = 0;
|
||||
}
|
||||
|
||||
vector(const vector& other) = delete;
|
||||
|
||||
vector(explicit_copy_t, const vector& other) : _capacity(other._size), _size(other._size) {
|
||||
_data = (T*)std::malloc(sizeof(T) * _capacity);
|
||||
uninitialized_copy_n(other._data, _size, _data);
|
||||
}
|
||||
|
||||
// allow move
|
||||
vector& operator= (vector&& other) noexcept {
|
||||
if(_data) {
|
||||
std::destroy(begin(), end());
|
||||
std::free(_data);
|
||||
}
|
||||
new (this) vector(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// disallow copy
|
||||
vector& operator= (const vector& other) = delete;
|
||||
|
||||
bool empty() const { return _size == 0; }
|
||||
|
||||
int size() const { return _size; }
|
||||
|
||||
int capacity() const { return _capacity; }
|
||||
|
||||
T& back() {
|
||||
assert(_size > 0);
|
||||
return _data[_size - 1];
|
||||
}
|
||||
|
||||
T* begin() const { return _data; }
|
||||
|
||||
T* end() const { return _data + _size; }
|
||||
|
||||
T* data() const { return _data; }
|
||||
|
||||
T& operator[] (int i) {
|
||||
assert(i >= 0 && i < _size);
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
const T& operator[] (int i) const {
|
||||
assert(i >= 0 && i < _size);
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
void clear() {
|
||||
std::destroy(begin(), end());
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
void reserve(int cap) {
|
||||
if(cap < 4) cap = 4; // minimum capacity
|
||||
if(cap <= capacity()) return;
|
||||
T* new_data = (T*)std::malloc(sizeof(T) * cap);
|
||||
uninitialized_relocate_n(_data, _size, new_data);
|
||||
if(_data) std::free(_data);
|
||||
_data = new_data;
|
||||
_capacity = cap;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace_back(Args&&... args) {
|
||||
if(_size == _capacity) reserve(_capacity * 2);
|
||||
new (_data + _size) T(std::forward<Args>(args)...);
|
||||
_size++;
|
||||
}
|
||||
|
||||
void push_back(const T& t) { emplace_back(t); }
|
||||
|
||||
void push_back(T&& t) { emplace_back(std::move(t)); }
|
||||
|
||||
bool contains(const T& t) const {
|
||||
for(int i = 0; i < _size; i++) {
|
||||
if(_data[i] == t) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void extend(const T* begin, const T* end) {
|
||||
int n = end - begin;
|
||||
reserve(_size + n);
|
||||
uninitialized_copy_n(begin, n, _data + _size);
|
||||
_size += n;
|
||||
}
|
||||
|
||||
void insert(const T* it, const T& t) {
|
||||
assert(it >= begin() && it <= end());
|
||||
int pos = it - begin();
|
||||
if(_size == _capacity) {
|
||||
int new_capacity = (_capacity == 0) ? 4 : _capacity * 2;
|
||||
T* new_data = (T*)std::malloc(sizeof(T) * new_capacity);
|
||||
uninitialized_relocate_n(_data, pos, new_data);
|
||||
new (new_data + pos) T(t);
|
||||
uninitialized_relocate_n(_data + pos, _size - pos, new_data + pos + 1);
|
||||
if(_data) std::free(_data);
|
||||
_data = new_data;
|
||||
_capacity = new_capacity;
|
||||
} else {
|
||||
uninitialized_relocate_n<true, true>(_data + pos, _size - pos, _data + pos + 1);
|
||||
new (_data + pos) T(t);
|
||||
}
|
||||
_size++;
|
||||
}
|
||||
|
||||
void erase(T* it) {
|
||||
assert(it >= begin() && it < end());
|
||||
int pos = it - begin();
|
||||
_data[pos].~T();
|
||||
uninitialized_relocate_n<true>(_data + pos + 1, _size - pos, _data + pos);
|
||||
_size--;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
assert(_size > 0);
|
||||
_size--;
|
||||
_data[_size].~T();
|
||||
}
|
||||
|
||||
[[nodiscard]] T popx_back() {
|
||||
T retval = std::move(back());
|
||||
pop_back();
|
||||
return retval;
|
||||
}
|
||||
|
||||
pair<T*, int> detach() noexcept {
|
||||
pair<T*, int> retval(_data, _size);
|
||||
_data = nullptr;
|
||||
_capacity = 0;
|
||||
_size = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void swap(vector& other) {
|
||||
std::swap(_data, other._data);
|
||||
std::swap(_capacity, other._capacity);
|
||||
std::swap(_size, other._size);
|
||||
}
|
||||
|
||||
~vector() {
|
||||
if(_data) {
|
||||
std::destroy(begin(), end());
|
||||
std::free(_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct small_vector {
|
||||
static_assert(is_pod_v<T>);
|
||||
|
||||
alignas(T) char _buffer[sizeof(T) * N];
|
||||
T* _begin;
|
||||
T* _end;
|
||||
T* _capacity;
|
||||
|
||||
[[nodiscard]] bool is_small() const { return _begin == reinterpret_cast<const T*>(_buffer); }
|
||||
|
||||
[[nodiscard]] int size() const { return _end - _begin; }
|
||||
|
||||
[[nodiscard]] int capacity() const { return _capacity - _begin; }
|
||||
|
||||
[[nodiscard]] bool empty() const { return _begin == _end; }
|
||||
|
||||
[[nodiscard]] T* data() const { return _begin; }
|
||||
|
||||
[[nodiscard]] T* begin() const { return _begin; }
|
||||
|
||||
[[nodiscard]] T* end() const { return _end; }
|
||||
|
||||
[[nodiscard]] T& back() const { return *(end() - 1); }
|
||||
|
||||
[[nodiscard]] T& operator[] (int index) { return _begin[index]; }
|
||||
|
||||
[[nodiscard]] const T& operator[] (int index) const { return _begin[index]; }
|
||||
|
||||
small_vector() : _begin(reinterpret_cast<T*>(_buffer)), _end(_begin), _capacity(_begin + N) {}
|
||||
|
||||
small_vector(const small_vector& other) noexcept {
|
||||
const auto size = other.size();
|
||||
const auto capacity = other.capacity();
|
||||
_begin = reinterpret_cast<T*>(other.is_small() ? _buffer : std::malloc(sizeof(T) * capacity));
|
||||
uninitialized_copy_n(other._begin, size, this->_begin);
|
||||
_end = _begin + size;
|
||||
_capacity = _begin + capacity;
|
||||
}
|
||||
|
||||
small_vector(small_vector&& other) noexcept {
|
||||
if(other.is_small()) {
|
||||
_begin = reinterpret_cast<T*>(_buffer);
|
||||
uninitialized_relocate_n((T*)other._buffer, other.size(), (T*)_buffer);
|
||||
_end = _begin + other.size();
|
||||
_capacity = _begin + N;
|
||||
} else {
|
||||
_begin = other._begin;
|
||||
_end = other._end;
|
||||
_capacity = other._capacity;
|
||||
}
|
||||
other._begin = reinterpret_cast<T*>(other._buffer);
|
||||
other._end = other._begin;
|
||||
other._capacity = other._begin + N;
|
||||
}
|
||||
|
||||
small_vector& operator= (const small_vector& other) = delete;
|
||||
|
||||
small_vector& operator= (small_vector&& other) noexcept {
|
||||
if(this != &other) {
|
||||
~small_vector();
|
||||
::new (this) small_vector(std::move(other));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~small_vector() {
|
||||
std::destroy(_begin, _end);
|
||||
if(!is_small()) std::free(_begin);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace_back(Args&&... args) noexcept {
|
||||
if(_end == _capacity) {
|
||||
const auto new_capacity = capacity() * 2;
|
||||
const auto size = this->size();
|
||||
auto new_data = (T*)std::malloc(sizeof(T) * new_capacity);
|
||||
uninitialized_relocate_n(_begin, size, new_data);
|
||||
if(!is_small()) std::free(_begin);
|
||||
_begin = new_data;
|
||||
_end = _begin + size;
|
||||
_capacity = _begin + new_capacity;
|
||||
}
|
||||
::new (_end) T(std::forward<Args>(args)...);
|
||||
_end++;
|
||||
}
|
||||
|
||||
void push_back(const T& value) { emplace_back(value); }
|
||||
|
||||
void push_back(T&& value) { emplace_back(std::move(value)); }
|
||||
|
||||
void pop_back() {
|
||||
_end--;
|
||||
_end->~T();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
std::destroy(_begin, _end);
|
||||
_end = _begin;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
class small_vector_2 : public small_vector<T, N> {
|
||||
public:
|
||||
small_vector_2() = default;
|
||||
small_vector_2(const small_vector_2& other) = delete;
|
||||
small_vector_2& operator= (const small_vector_2& other) = delete;
|
||||
small_vector_2(small_vector_2&& other) = delete;
|
||||
small_vector_2& operator= (small_vector_2&& other) = delete;
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
struct small_map {
|
||||
struct Item {
|
||||
K first;
|
||||
V second;
|
||||
|
||||
bool operator< (const K& other) const { return first < other; }
|
||||
|
||||
bool operator< (const Item& other) const { return first < other.first; }
|
||||
};
|
||||
|
||||
vector<Item> _data;
|
||||
|
||||
small_map() = default;
|
||||
|
||||
using size_type = int;
|
||||
|
||||
int size() const { return _data.size(); }
|
||||
|
||||
bool empty() const { return _data.empty(); }
|
||||
|
||||
Item* begin() const { return _data.begin(); }
|
||||
|
||||
Item* end() const { return _data.end(); }
|
||||
|
||||
Item* data() const { return _data.data(); }
|
||||
|
||||
void insert(const K& key, const V& value) {
|
||||
Item* it = std::lower_bound(_data.begin(), _data.end(), key);
|
||||
assert(it == _data.end() || it->first != key);
|
||||
_data.insert(it, {key, value});
|
||||
}
|
||||
|
||||
V* try_get(const K& key) const {
|
||||
auto it = std::lower_bound(_data.begin(), _data.end(), key);
|
||||
if(it == _data.end() || it->first != key) return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
V get(const K& key, V default_value) const {
|
||||
static_assert(is_pod_v<V>);
|
||||
auto it = try_get(key);
|
||||
return it ? *it : default_value;
|
||||
}
|
||||
|
||||
bool contains(const K& key) const { return try_get(key) != nullptr; }
|
||||
|
||||
void clear() { _data.clear(); }
|
||||
|
||||
const V& operator[] (const K& key) const {
|
||||
auto it = try_get(key);
|
||||
assert(it != nullptr);
|
||||
return *it;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,229 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/interpreter/cffi.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
struct NativeProxyFuncCBase {
|
||||
virtual PyVar operator() (VM* vm, ArgsView args) = 0;
|
||||
};
|
||||
|
||||
template <typename Ret, typename... Params>
|
||||
struct NativeProxyFuncC final : NativeProxyFuncCBase {
|
||||
constexpr static int N = sizeof...(Params);
|
||||
using _Fp = Ret (*)(Params...);
|
||||
_Fp func;
|
||||
|
||||
NativeProxyFuncC(_Fp func) : func(func) {}
|
||||
|
||||
PyVar operator() (VM* vm, ArgsView args) override {
|
||||
assert(args.size() == N);
|
||||
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template <typename __Ret, size_t... Is>
|
||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
|
||||
if constexpr(std::is_void_v<__Ret>) {
|
||||
func(py_cast<Params>(vm, args[Is])...);
|
||||
return vm->None;
|
||||
} else {
|
||||
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
|
||||
return VAR(std::move(ret));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Ret, typename T, typename... Params>
|
||||
struct NativeProxyMethodC final : NativeProxyFuncCBase {
|
||||
constexpr static int N = sizeof...(Params);
|
||||
using _Fp = Ret (T::*)(Params...);
|
||||
_Fp func;
|
||||
|
||||
NativeProxyMethodC(_Fp func) : func(func) {}
|
||||
|
||||
PyVar operator() (VM* vm, ArgsView args) override {
|
||||
assert(args.size() == N + 1);
|
||||
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template <typename __Ret, size_t... Is>
|
||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes
|
||||
if constexpr(std::is_void_v<__Ret>) {
|
||||
(self.*func)(py_cast<Params>(vm, args[Is + 1])...);
|
||||
return vm->None;
|
||||
} else {
|
||||
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is + 1])...);
|
||||
return VAR(std::move(ret));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*****************************************************************/
|
||||
inline PyVar __proxy_wrapper(VM* vm, ArgsView args) {
|
||||
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
|
||||
return (*pf)(vm, args);
|
||||
}
|
||||
|
||||
template <typename Ret, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, Ret (*func)(Params...), BindType bt) {
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
||||
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template <typename Ret, typename T, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, Ret (T::*func)(Params...), BindType bt) {
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
||||
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template <typename Ret, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (*func)(Params...), BindType bt) {
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
||||
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template <typename Ret, typename T, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (T::*func)(Params...), BindType bt) {
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
||||
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template <typename T, typename F, bool ReadOnly>
|
||||
PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
||||
static_assert(!std::is_reference_v<F>);
|
||||
assert(is_type(obj, tp_type));
|
||||
std::string_view name_sv(name);
|
||||
int pos = name_sv.find(':');
|
||||
if(pos > 0) name_sv = name_sv.substr(0, pos);
|
||||
auto fget = [](VM* vm, ArgsView args) -> PyVar {
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||
return VAR(self.*field);
|
||||
};
|
||||
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field);
|
||||
PyVar _1 = vm->None;
|
||||
if constexpr(!ReadOnly) {
|
||||
auto fset = [](VM* vm, ArgsView args) {
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||
self.*field = py_cast<F>(vm, args[1]);
|
||||
return vm->None;
|
||||
};
|
||||
_1 = new_object<NativeFunc>(tp_native_func, fset, 2, field);
|
||||
}
|
||||
PyObject* prop = new_object<Property>(tp_property, _0, _1).get();
|
||||
obj->attr().set(StrName(name_sv), prop);
|
||||
return prop;
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
|
||||
#define PY_FIELD(T, NAME, EXPR) \
|
||||
vm->bind_property( \
|
||||
type, \
|
||||
NAME, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.EXPR); \
|
||||
}, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
self.EXPR = CAST(decltype(self.EXPR), args[1]); \
|
||||
return vm->None; \
|
||||
});
|
||||
|
||||
#define PY_READONLY_FIELD(T, NAME, EXPR) \
|
||||
vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.EXPR); \
|
||||
});
|
||||
|
||||
#define PY_PROPERTY(T, NAME, FGET, FSET) \
|
||||
vm->bind_property( \
|
||||
type, \
|
||||
NAME, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.FGET()); \
|
||||
}, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
using __NT = decltype(self.FGET()); \
|
||||
self.FSET(CAST(__NT, args[1])); \
|
||||
return vm->None; \
|
||||
});
|
||||
|
||||
#define PY_READONLY_PROPERTY(T, NAME, FGET) \
|
||||
vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.FGET()); \
|
||||
});
|
||||
/*****************************************************************/
|
||||
#define PY_STRUCT_LIKE(wT) \
|
||||
static_assert(std::is_trivially_copyable<wT>::value); \
|
||||
static_assert(!is_sso_v<wT>); \
|
||||
type->attr().set("__struct__", vm->True); \
|
||||
vm->bind_func( \
|
||||
type, \
|
||||
"fromstruct", \
|
||||
1, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
Struct& s = CAST(Struct&, args[0]); \
|
||||
if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
|
||||
PyVar obj = vm->new_user_object<wT>(); \
|
||||
std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
|
||||
return obj; \
|
||||
}, \
|
||||
{}, \
|
||||
BindType_STATICMETHOD); \
|
||||
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) { \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<Struct>(&self, sizeof(wT)); \
|
||||
}); \
|
||||
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args) { \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<VoidP>(&self); \
|
||||
}); \
|
||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) { \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<wT>(self); \
|
||||
}); \
|
||||
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { \
|
||||
return VAR(sizeof(wT)); \
|
||||
}); \
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
wT& self = _CAST(wT&, _0); \
|
||||
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
|
||||
wT& other = _CAST(wT&, _1); \
|
||||
return VAR(self == other); \
|
||||
});
|
||||
|
||||
#define PY_POINTER_SETGETITEM(T) \
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
|
||||
i64 i = CAST(i64, _1); \
|
||||
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
||||
return VAR(tgt[i]); \
|
||||
}); \
|
||||
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2) { \
|
||||
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
|
||||
i64 i = CAST(i64, _1); \
|
||||
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
||||
tgt[i] = CAST(T, _2); \
|
||||
});
|
||||
|
||||
#define PK_LAMBDA(x) \
|
||||
([](VM* vm, ArgsView args) -> PyVar { \
|
||||
return x; \
|
||||
})
|
||||
#define PK_VAR_LAMBDA(x) \
|
||||
([](VM* vm, ArgsView args) -> PyVar { \
|
||||
return VAR(x); \
|
||||
})
|
||||
#define PK_ACTION(x) \
|
||||
([](VM* vm, ArgsView args) -> PyVar { \
|
||||
x; \
|
||||
return vm->None; \
|
||||
})
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,105 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/interpreter/vm.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
#define PY_CLASS(T, mod, name) \
|
||||
[[deprecated]] static Type _type(VM* vm) { return vm->_cxx_typeid_map[typeid(T)]; } \
|
||||
[[deprecated]] static PyVar register_class(VM* vm, PyVar mod, Type base = VM::tp_object) { \
|
||||
return vm->register_user_class<T>(mod, #name, base); \
|
||||
}
|
||||
|
||||
struct VoidP {
|
||||
void* ptr;
|
||||
|
||||
VoidP(const void* ptr) : ptr(const_cast<void*>(ptr)) {}
|
||||
|
||||
bool operator== (const VoidP& other) const { return ptr == other.ptr; }
|
||||
|
||||
bool operator!= (const VoidP& other) const { return ptr != other.ptr; }
|
||||
|
||||
bool operator< (const VoidP& other) const { return ptr < other.ptr; }
|
||||
|
||||
bool operator<= (const VoidP& other) const { return ptr <= other.ptr; }
|
||||
|
||||
bool operator> (const VoidP& other) const { return ptr > other.ptr; }
|
||||
|
||||
bool operator>= (const VoidP& other) const { return ptr >= other.ptr; }
|
||||
|
||||
Str hex() const {
|
||||
SStream ss;
|
||||
ss.write_ptr(ptr);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
#define POINTER_VAR(Tp, NAME) \
|
||||
inline PyVar py_var(VM* vm, Tp val) { \
|
||||
const static pair<StrName, StrName> P("c", NAME); \
|
||||
PyVar type = vm->_modules[P.first]->attr()[P.second]; \
|
||||
return vm->new_object<VoidP>(type->as<Type>(), val); \
|
||||
}
|
||||
|
||||
POINTER_VAR(char*, "char_p")
|
||||
// const char* is special, need to rethink about it
|
||||
POINTER_VAR(const unsigned char*, "uchar_p")
|
||||
POINTER_VAR(const short*, "short_p")
|
||||
POINTER_VAR(const unsigned short*, "ushort_p")
|
||||
POINTER_VAR(const int*, "int_p")
|
||||
POINTER_VAR(const unsigned int*, "uint_p")
|
||||
POINTER_VAR(const long*, "long_p")
|
||||
POINTER_VAR(const unsigned long*, "ulong_p")
|
||||
POINTER_VAR(const long long*, "longlong_p")
|
||||
POINTER_VAR(const unsigned long long*, "ulonglong_p")
|
||||
POINTER_VAR(const float*, "float_p")
|
||||
POINTER_VAR(const double*, "double_p")
|
||||
POINTER_VAR(const bool*, "bool_p")
|
||||
|
||||
#undef POINTER_VAR
|
||||
|
||||
struct Struct {
|
||||
constexpr static int INLINE_SIZE = 24;
|
||||
|
||||
char _inlined[INLINE_SIZE];
|
||||
char* p;
|
||||
int size;
|
||||
|
||||
Struct(int new_size, bool zero_init = true) {
|
||||
this->size = new_size;
|
||||
if(size <= INLINE_SIZE) {
|
||||
p = _inlined;
|
||||
} else {
|
||||
p = (char*)std::malloc(size);
|
||||
}
|
||||
if(zero_init) std::memset(p, 0, size);
|
||||
}
|
||||
|
||||
Struct(void* p, int size) : Struct(size, false) {
|
||||
if(p != nullptr) std::memcpy(this->p, p, size);
|
||||
}
|
||||
|
||||
Struct(const Struct& other) : Struct(other.p, other.size) {}
|
||||
|
||||
~Struct() {
|
||||
if(p != _inlined) std::free(p);
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
/***********************************************/
|
||||
template <typename Tp>
|
||||
Tp to_void_p(VM* vm, PyVar var) {
|
||||
static_assert(std::is_pointer_v<Tp>);
|
||||
if(is_none(var)) return nullptr; // None can be casted to any pointer implicitly
|
||||
VoidP& p = CAST(VoidP&, var);
|
||||
return reinterpret_cast<Tp>(p.ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
void add_module_c(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
102
include/pocketpy/interpreter/frame.h
Normal file
102
include/pocketpy/interpreter/frame.h
Normal file
@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/namedict.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, StrName name);
|
||||
pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co);
|
||||
|
||||
typedef struct ValueStack {
|
||||
// We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
|
||||
PyVar* sp;
|
||||
PyVar* end;
|
||||
PyVar begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128];
|
||||
} ValueStack;
|
||||
|
||||
void ValueStack__ctor(ValueStack* self);
|
||||
void ValueStack__clear(ValueStack* self);
|
||||
|
||||
typedef struct UnwindTarget {
|
||||
struct UnwindTarget* next;
|
||||
int iblock;
|
||||
int offset;
|
||||
} UnwindTarget;
|
||||
|
||||
UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset);
|
||||
void UnwindTarget__delete(UnwindTarget* self);
|
||||
|
||||
typedef struct Frame {
|
||||
struct Frame* f_back; // TODO: set this
|
||||
const Bytecode* ip;
|
||||
const CodeObject* co;
|
||||
PyObject* module_;
|
||||
PyObject* function; // a function object or NULL (global scope)
|
||||
PyVar* p0; // unwinding base
|
||||
PyVar* locals; // locals base
|
||||
const CodeObject* locals_co;
|
||||
UnwindTarget* uw_list;
|
||||
} Frame;
|
||||
|
||||
|
||||
Frame* Frame__new(Frame* f_back, const CodeObject* co, PyObject* module_, PyObject* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co);
|
||||
void Frame__delete(Frame* self);
|
||||
|
||||
PK_INLINE int Frame__ip(const Frame* self){
|
||||
return self->ip - (Bytecode*)self->co->codes.data;
|
||||
}
|
||||
|
||||
PK_INLINE int Frame__lineno(const Frame* self){
|
||||
int ip = Frame__ip(self);
|
||||
return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).lineno;
|
||||
}
|
||||
|
||||
PK_INLINE int Frame__iblock(const Frame* self){
|
||||
int ip = Frame__ip(self);
|
||||
return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).iblock;
|
||||
}
|
||||
|
||||
PK_INLINE pk_NameDict* Frame__f_globals(Frame* self){
|
||||
return self->module_->dict;
|
||||
}
|
||||
|
||||
PK_INLINE PyVar* Frame__f_globals_try_get(Frame* self, StrName name){
|
||||
return pk_NameDict__try_get(self->module_->dict, name);
|
||||
}
|
||||
|
||||
PyVar* Frame__f_closure_try_get(Frame* self, StrName name);
|
||||
|
||||
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*);
|
||||
void Frame__prepare_jump_break(Frame* self, ValueStack*, int);
|
||||
int Frame__prepare_loop_break(Frame* self, ValueStack*);
|
||||
int Frame__exit_block(Frame* self, ValueStack*, int);
|
||||
|
||||
void Frame__gc_mark(Frame* self);
|
||||
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock);
|
||||
void Frame__set_unwind_target(Frame* self, PyVar* sp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// some patch here
|
||||
#ifdef __cplusplus
|
||||
#include "pocketpy/objects/codeobject.hpp"
|
||||
|
||||
extern "C"{
|
||||
inline PyVar* Frame__f_closure_try_get(Frame* self, StrName name){
|
||||
if(self->function == NULL) return NULL;
|
||||
pkpy::Function* fn = PyObject__as(pkpy::Function, self->function);
|
||||
if(fn->_closure == nullptr) return nullptr;
|
||||
return pk_NameDict__try_get(fn->_closure, name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1,214 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/codeobject.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
// weak reference fast locals
|
||||
struct FastLocals {
|
||||
// this is a weak reference
|
||||
const CodeObject* co;
|
||||
PyVar* a;
|
||||
|
||||
int size() const { return co->nlocals; }
|
||||
|
||||
PyVar& operator[] (int i) { return a[i]; }
|
||||
|
||||
PyVar operator[] (int i) const { return a[i]; }
|
||||
|
||||
FastLocals(const CodeObject* co, PyVar* a) : co(co), a(a) {}
|
||||
|
||||
PyVar* try_get_name(StrName name);
|
||||
NameDict* to_namedict();
|
||||
|
||||
PyVar* begin() const { return a; }
|
||||
|
||||
PyVar* end() const { return a + size(); }
|
||||
};
|
||||
|
||||
struct ValueStack {
|
||||
PK_ALWAYS_PASS_BY_POINTER(ValueStack)
|
||||
|
||||
// We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
|
||||
PyVar _begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128];
|
||||
PyVar* _sp;
|
||||
PyVar* _max_end;
|
||||
|
||||
constexpr static size_t max_size() { return PK_VM_STACK_SIZE; }
|
||||
|
||||
ValueStack() : _sp(_begin), _max_end(_begin + PK_VM_STACK_SIZE) {}
|
||||
|
||||
PyVar& top() { return _sp[-1]; }
|
||||
|
||||
PyVar top() const { return _sp[-1]; }
|
||||
|
||||
PyVar& second() { return _sp[-2]; }
|
||||
|
||||
PyVar second() const { return _sp[-2]; }
|
||||
|
||||
PyVar& third() { return _sp[-3]; }
|
||||
|
||||
PyVar third() const { return _sp[-3]; }
|
||||
|
||||
PyVar& peek(int n) { return _sp[-n]; }
|
||||
|
||||
PyVar peek(int n) const { return _sp[-n]; }
|
||||
|
||||
void push(PyVar v) { *_sp++ = v; }
|
||||
|
||||
void push(std::nullptr_t) { std::memset(_sp++, 0, sizeof(PyVar)); }
|
||||
|
||||
void pop() { --_sp; }
|
||||
|
||||
PyVar popx() {
|
||||
--_sp;
|
||||
return *_sp;
|
||||
}
|
||||
|
||||
ArgsView view(int n) { return ArgsView(_sp - n, _sp); }
|
||||
|
||||
void shrink(int n) { _sp -= n; }
|
||||
|
||||
int size() const { return _sp - _begin; }
|
||||
|
||||
bool empty() const { return _sp == _begin; }
|
||||
|
||||
PyVar* begin() { return _begin; }
|
||||
|
||||
PyVar* end() { return _sp; }
|
||||
|
||||
void reset(PyVar* sp) { _sp = sp; }
|
||||
|
||||
void clear() { _sp = _begin; }
|
||||
|
||||
bool is_overflow() const { return _sp >= _max_end; }
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
new (_sp) PyVar(std::forward<Args>(args)...);
|
||||
++_sp;
|
||||
}
|
||||
};
|
||||
|
||||
struct UnwindTarget {
|
||||
UnwindTarget* next;
|
||||
int iblock;
|
||||
int offset;
|
||||
|
||||
UnwindTarget(int iblock, int offset) : next(nullptr), iblock(iblock), offset(offset) {}
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Frame)
|
||||
|
||||
const Bytecode* _ip;
|
||||
// This is for unwinding only, use `actual_sp_base()` for value stack access
|
||||
PyVar* _sp_base;
|
||||
|
||||
const CodeObject* co;
|
||||
PyObject* _module;
|
||||
PyObject* _callable; // a function object or nullptr (global scope)
|
||||
FastLocals _locals;
|
||||
|
||||
// This list will be freed in __pop_frame
|
||||
UnwindTarget* _uw_list;
|
||||
|
||||
NameDict& f_globals() { return _module->attr(); }
|
||||
|
||||
PyVar* f_closure_try_get(StrName name);
|
||||
|
||||
int ip() const { return _ip - (Bytecode*)co->codes.data; }
|
||||
|
||||
// function scope
|
||||
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) :
|
||||
_ip((Bytecode*)co->codes.data - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable),
|
||||
_locals(co, _locals_base), _uw_list(nullptr) {}
|
||||
|
||||
// exec/eval
|
||||
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) :
|
||||
_ip((Bytecode*)co->codes.data - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals),
|
||||
_uw_list(nullptr) {}
|
||||
|
||||
// global scope
|
||||
Frame(PyVar* p0, const CodeObject* co, PyObject* _module) :
|
||||
_ip((Bytecode*)co->codes.data - 1), _sp_base(p0), co(co), _module(_module), _callable(nullptr),
|
||||
_locals(co, p0), _uw_list(nullptr) {}
|
||||
|
||||
PyVar* actual_sp_base() const { return _locals.a; }
|
||||
|
||||
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
|
||||
|
||||
[[nodiscard]] int prepare_jump_exception_handler(ValueStack*);
|
||||
void prepare_jump_break(ValueStack*, int);
|
||||
int _exit_block(ValueStack*, int);
|
||||
|
||||
[[nodiscard]] int prepare_loop_break(ValueStack* s_data) {
|
||||
int iblock = c11__getitem(BytecodeEx, &co->codes_ex, ip()).iblock;
|
||||
int target = c11__getitem(CodeBlock, &co->blocks, iblock).end;
|
||||
prepare_jump_break(s_data, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
int curr_lineno() const {
|
||||
return c11__getitem(BytecodeEx, &co->codes_ex, ip()).lineno;
|
||||
}
|
||||
|
||||
void set_unwind_target(PyVar* _sp);
|
||||
UnwindTarget* find_unwind_target(int iblock);
|
||||
|
||||
void _gc_mark(VM* vm) const;
|
||||
~Frame();
|
||||
};
|
||||
|
||||
struct LinkedFrame {
|
||||
LinkedFrame* f_back;
|
||||
Frame frame;
|
||||
|
||||
template <typename... Args>
|
||||
LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward<Args>(args)...) {}
|
||||
};
|
||||
|
||||
struct CallStack {
|
||||
static_assert(sizeof(LinkedFrame) <= 128);
|
||||
|
||||
LinkedFrame* _tail;
|
||||
int _size;
|
||||
|
||||
CallStack() : _tail(nullptr), _size(0) {}
|
||||
|
||||
int size() const { return _size; }
|
||||
|
||||
bool empty() const { return _size == 0; }
|
||||
|
||||
void clear() {
|
||||
while(!empty())
|
||||
pop();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
static_assert(sizeof(LinkedFrame) <= kPoolFrameBlockSize);
|
||||
_tail = new (PoolFrame_alloc()) LinkedFrame(_tail, std::forward<Args>(args)...);
|
||||
++_size;
|
||||
}
|
||||
|
||||
void pop();
|
||||
LinkedFrame* popx();
|
||||
void pushx(LinkedFrame* p);
|
||||
|
||||
Frame& top() const {
|
||||
assert(!empty());
|
||||
return _tail->frame;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void apply(Func&& f) {
|
||||
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back)
|
||||
f(p->frame);
|
||||
}
|
||||
|
||||
~CallStack() { clear(); }
|
||||
};
|
||||
|
||||
}; // namespace pkpy
|
||||
@ -13,13 +13,13 @@ typedef struct pk_ManagedHeap{
|
||||
int gc_threshold;
|
||||
int gc_counter;
|
||||
int gc_lock_counter;
|
||||
pkpy_VM* vm;
|
||||
pk_VM* vm;
|
||||
|
||||
void (*_gc_on_delete)(pkpy_VM*, PyObject*);
|
||||
void (*_gc_marker_ex)(pkpy_VM*);
|
||||
void (*_gc_on_delete)(pk_VM*, PyObject*);
|
||||
void (*_gc_marker_ex)(pk_VM*);
|
||||
} pk_ManagedHeap;
|
||||
|
||||
void pk_ManagedHeap__ctor(pk_ManagedHeap* self, pkpy_VM* vm);
|
||||
void pk_ManagedHeap__ctor(pk_ManagedHeap* self, pk_VM* vm);
|
||||
void pk_ManagedHeap__dtor(pk_ManagedHeap* self);
|
||||
|
||||
void pk_ManagedHeap__push_lock(pk_ManagedHeap* self);
|
||||
@ -29,7 +29,8 @@ void pk_ManagedHeap__collect_if_needed(pk_ManagedHeap* self);
|
||||
int pk_ManagedHeap__collect(pk_ManagedHeap* self);
|
||||
int pk_ManagedHeap__sweep(pk_ManagedHeap* self);
|
||||
|
||||
PyObject* pk_ManagedHeap__new(pk_ManagedHeap* self, pkpy_Type type, int size, bool gc);
|
||||
PyObject* pk_ManagedHeap__new(pk_ManagedHeap* self, Type type, int size);
|
||||
PyObject* pk_ManagedHeap__gcnew(pk_ManagedHeap* self, Type type, int size);
|
||||
|
||||
// external implementation
|
||||
void pk_ManagedHeap__mark(pk_ManagedHeap* self);
|
||||
|
||||
@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct RangeIter { // step > 0
|
||||
Range r;
|
||||
i64 current;
|
||||
|
||||
RangeIter(Range r) : r(r), current(r.start) {}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
struct RangeIterR { // step < 0
|
||||
Range r;
|
||||
i64 current;
|
||||
|
||||
RangeIterR(Range r) : r(r), current(r.start) {}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
struct ArrayIter {
|
||||
PyObject* ref;
|
||||
PyVar* end;
|
||||
PyVar* current;
|
||||
|
||||
ArrayIter(PyObject* ref, PyVar* begin, PyVar* end) : ref(ref), end(end), current(begin) {}
|
||||
|
||||
void _gc_mark(VM* vm) const { vm->__obj_gc_mark(ref); }
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
struct StringIter {
|
||||
PyVar ref;
|
||||
int i; // byte index
|
||||
|
||||
StringIter(PyVar ref) : ref(ref), i(0) {}
|
||||
|
||||
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
struct Generator {
|
||||
LinkedFrame* lf;
|
||||
int state; // 0,1,2
|
||||
List s_backup;
|
||||
|
||||
Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) {
|
||||
for(PyVar obj: buffer)
|
||||
s_backup.push_back(obj);
|
||||
}
|
||||
|
||||
void _gc_mark(VM* vm) {
|
||||
if(lf == nullptr) return;
|
||||
lf->frame._gc_mark(vm);
|
||||
vm->__stack_gc_mark(s_backup.begin(), s_backup.end());
|
||||
}
|
||||
|
||||
PyVar next(VM* vm);
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
|
||||
~Generator() {
|
||||
if(lf) {
|
||||
lf->~LinkedFrame();
|
||||
PoolFrame_dealloc(lf);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DictItemsIter {
|
||||
PyVar ref;
|
||||
pkpy_DictIter it;
|
||||
|
||||
DictItemsIter(PyVar ref) : ref(ref) { it = PK_OBJ_GET(Dict, ref).iter(); }
|
||||
|
||||
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/interpreter/frame.hpp"
|
||||
|
||||
#if PK_ENABLE_PROFILER
|
||||
#include <ctime>
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct _LineRecord {
|
||||
int line;
|
||||
i64 hits;
|
||||
clock_t time;
|
||||
|
||||
_LineRecord() : line(-1), hits(0), time(0) {}
|
||||
|
||||
bool is_valid() const { return line != -1; }
|
||||
};
|
||||
|
||||
struct _FrameRecord {
|
||||
int callstack_size;
|
||||
Frame* frame;
|
||||
clock_t prev_time;
|
||||
_LineRecord* prev_record;
|
||||
};
|
||||
|
||||
struct LineProfiler {
|
||||
// filename -> records
|
||||
small_map<std::string_view, _LineRecord*> records;
|
||||
vector<_FrameRecord> frames;
|
||||
vector<FuncDecl*> functions;
|
||||
|
||||
void begin();
|
||||
void _step(int, Frame*);
|
||||
void _step_end(int, Frame*, int);
|
||||
void end();
|
||||
Str stats();
|
||||
~LineProfiler();
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
|
||||
#endif
|
||||
@ -1,12 +1,82 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#pragma once
|
||||
|
||||
typedef struct pkpy_VM{
|
||||
PyVar True;
|
||||
PyVar False;
|
||||
PyVar None;
|
||||
PyVar NotImplemented;
|
||||
PyVar Ellipsis;
|
||||
} pkpy_VM;
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/gc.h"
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
|
||||
void pkpy_VM__ctor(pkpy_VM* self);
|
||||
void pkpy_VM__dtor(pkpy_VM* self);
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct pk_TypeInfo{
|
||||
StrName name;
|
||||
Type base;
|
||||
|
||||
PyObject* obj; // the type object itself
|
||||
PyObject* module; // the module where the type is defined
|
||||
bool subclass_enabled;
|
||||
|
||||
void (*dtor)(void*);
|
||||
void (*gc_mark)(void*);
|
||||
|
||||
c11_vector/*T=StrName*/ annotated_fields;
|
||||
|
||||
/* Magic Caches */
|
||||
// unary operators
|
||||
py_CFunction m__repr__, m__str__, m__hash__, m__len__;
|
||||
py_CFunction m__iter__, m__next__, m__neg__, m__invert__;
|
||||
// binary operators
|
||||
py_CFunction m__eq__, m__lt__, m__le__, m__gt__, m__ge__, m__contains__;
|
||||
py_CFunction m__add__, m__sub__, m__mul__, m__truediv__, m__floordiv__;
|
||||
py_CFunction m__mod__, m__pow__, m__matmul__;
|
||||
py_CFunction m__lshift__, m__rshift__, m__and__, m__xor__, m__or__;
|
||||
// indexer
|
||||
py_CFunction m__getitem__, m__setitem__, m__delitem__;
|
||||
// attribute access (internal use only)
|
||||
py_CFunction m__getattr__, m__setattr__, m__delattr__;
|
||||
// backdoors
|
||||
py_CFunction on_end_subclass; // for enum module
|
||||
} pk_TypeInfo;
|
||||
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo *self, StrName name, Type base, PyObject* obj, PyObject* module, bool subclass_enabled);
|
||||
void pk_TypeInfo__dtor(pk_TypeInfo* self);
|
||||
|
||||
typedef struct pk_VM {
|
||||
Frame* top_frame;
|
||||
|
||||
pk_NameDict modules;
|
||||
c11_vector/*T=pk_TypeInfo*/ types;
|
||||
|
||||
PyObject* StopIteration; // a special Exception class
|
||||
PyObject* builtins; // builtins module
|
||||
PyObject* main; // __main__ module
|
||||
|
||||
void (*_ceval_on_step)(struct pk_VM*, Frame*, Bytecode);
|
||||
unsigned char* (*_import_file)(struct pk_VM*, const char*);
|
||||
void (*_stdout)(struct pk_VM*, const char*);
|
||||
void (*_stderr)(struct pk_VM*, const char*);
|
||||
|
||||
// singleton objects
|
||||
PyVar True, False, None, NotImplemented, Ellipsis;
|
||||
|
||||
PyObject* __last_exception;
|
||||
PyObject* __curr_class;
|
||||
PyObject* __cached_object_new;
|
||||
FuncDecl_ __dynamic_func_decl;
|
||||
PyVar __vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
void* userdata; // for user-defined data (unused by pkpy itself)
|
||||
|
||||
pk_ManagedHeap heap;
|
||||
ValueStack stack; // put `stack` at the end for better cache locality
|
||||
} pk_VM;
|
||||
|
||||
void pk_VM__ctor(pk_VM* self);
|
||||
void pk_VM__dtor(pk_VM* self);
|
||||
|
||||
Type pk_VM__new_type(pk_VM* self, const char* name, Type base, PyObject* module, bool subclass_enabled);
|
||||
PyObject* pk_VM__new_module(pk_VM* self, const char* name, const char* package);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/object.hpp"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/objects/dict.hpp"
|
||||
#include "pocketpy/objects/error.hpp"
|
||||
#include "pocketpy/objects/builtins.hpp"
|
||||
#include "pocketpy/interpreter/gc.h"
|
||||
#include "pocketpy/interpreter/frame.hpp"
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/interpreter/profiler.hpp"
|
||||
|
||||
#include <typeindex>
|
||||
@ -14,14 +15,15 @@ namespace pkpy {
|
||||
|
||||
/* Stack manipulation macros */
|
||||
// https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123
|
||||
#define TOP() (s_data.top())
|
||||
#define SECOND() (s_data.second())
|
||||
#define THIRD() (s_data.third())
|
||||
#define STACK_SHRINK(n) (s_data.shrink(n))
|
||||
#define PUSH(v) (s_data.push(v))
|
||||
#define POP() (s_data.pop())
|
||||
#define POPX() (s_data.popx())
|
||||
#define STACK_VIEW(n) (s_data.view(n))
|
||||
#define TOP() (s_data.sp[-1])
|
||||
#define SECOND() (s_data.sp[-2])
|
||||
#define THIRD() (s_data.sp[-3])
|
||||
#define STACK_SHRINK(n) (s_data.sp -= (n))
|
||||
#define PUSH(v) (*s_data.sp++ = (v))
|
||||
#define PUSH_NULL() memset(s_data.sp++, 0, sizeof(PyVar))
|
||||
#define POP() (--s_data.sp)
|
||||
#define POPX() (*--s_data.sp)
|
||||
#define STACK_VIEW(n) (ArgsView(s_data.sp - (n), s_data.sp))
|
||||
|
||||
typedef PyVar (*BinaryFuncC)(VM*, PyVar, PyVar);
|
||||
typedef void (*RegisterFunc)(VM*, PyObject*, PyObject*);
|
||||
@ -163,11 +165,10 @@ class VM {
|
||||
|
||||
public:
|
||||
pk_ManagedHeap heap;
|
||||
ValueStack s_data;
|
||||
CallStack callstack;
|
||||
Frame* top_frame;
|
||||
vector<PyTypeInfo> _all_types;
|
||||
|
||||
NameDict _modules; // loaded modules
|
||||
pk_NameDict _modules; // loaded modules
|
||||
small_map<StrName, Str> _lazy_modules; // lazy loaded modules
|
||||
|
||||
struct {
|
||||
@ -200,13 +201,10 @@ public:
|
||||
void (*_stdout)(const char*, int);
|
||||
void (*_stderr)(const char*, int);
|
||||
unsigned char* (*_import_handler)(const char*, int*);
|
||||
// function<void(const char*, int)> _stdout;
|
||||
// function<void(const char*, int)> _stderr;
|
||||
// function<unsigned char*(const char*, int*)> _import_handler;
|
||||
|
||||
// for quick access
|
||||
constexpr static Type tp_object = Type(1), tp_type = Type(2);
|
||||
constexpr static Type tp_int = Type(kTpIntIndex), tp_float = Type(kTpFloatIndex), tp_bool = Type(5),
|
||||
constexpr static Type tp_int = Type(3), tp_float = Type(4), tp_bool = Type(5),
|
||||
tp_str = Type(6);
|
||||
constexpr static Type tp_list = Type(7), tp_tuple = Type(8);
|
||||
constexpr static Type tp_slice = Type(9), tp_range = Type(10), tp_module = Type(11);
|
||||
@ -214,7 +212,7 @@ public:
|
||||
constexpr static Type tp_super = Type(15), tp_exception = Type(16), tp_bytes = Type(17), tp_mappingproxy = Type(18);
|
||||
constexpr static Type tp_dict = Type(19), tp_property = Type(20), tp_star_wrapper = Type(21);
|
||||
constexpr static Type tp_staticmethod = Type(22), tp_classmethod = Type(23);
|
||||
constexpr static Type tp_none_type = Type(kTpNoneTypeIndex), tp_not_implemented_type = Type(kTpNotImplementedTypeIndex);
|
||||
constexpr static Type tp_none_type = Type(24), tp_not_implemented_type = Type(25);
|
||||
constexpr static Type tp_ellipsis = Type(26);
|
||||
|
||||
PyVar True;
|
||||
@ -224,6 +222,10 @@ public:
|
||||
PyVar Ellipsis;
|
||||
|
||||
const bool enable_os;
|
||||
|
||||
// put s_data at the end of VM struct to improve cache locality
|
||||
ValueStack s_data;
|
||||
|
||||
VM(bool enable_os = true);
|
||||
|
||||
// clang-format off
|
||||
@ -255,10 +257,10 @@ public:
|
||||
return !py_eq(lhs, rhs);
|
||||
}
|
||||
|
||||
PyVar py_op(std::string_view name); // (name) -> operator.name
|
||||
PyVar py_op(const char* name); // (name) -> operator.name
|
||||
|
||||
void py_exec(std::string_view, PyVar, PyVar); // exec(source, globals, locals)
|
||||
PyVar py_eval(std::string_view, PyVar, PyVar); // eval(source, globals, locals)
|
||||
void py_exec(const char*, PyVar, PyVar); // exec(source, globals, locals)
|
||||
PyVar py_eval(const char*, PyVar, PyVar); // eval(source, globals, locals)
|
||||
#endif
|
||||
|
||||
#if PK_REGION("Utility Methods")
|
||||
@ -267,7 +269,7 @@ public:
|
||||
i64 normalized_index(i64 index, int size);
|
||||
Str disassemble(CodeObject* co);
|
||||
void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
|
||||
void obj_gc_mark(PyVar obj) { if(obj.is_ptr) __obj_gc_mark(obj.get()); }
|
||||
void obj_gc_mark(PyVar obj) { if(obj.is_ptr) __obj_gc_mark(obj._obj); }
|
||||
void obj_gc_mark(PyObject* p) { if(p) __obj_gc_mark(p); }
|
||||
#endif
|
||||
|
||||
@ -288,7 +290,7 @@ public:
|
||||
|
||||
template<typename ...Args>
|
||||
PyVar _exec(Args&&... args){
|
||||
callstack.emplace(s_data._sp, std::forward<Args>(args)...);
|
||||
callstack.emplace(s_data.sp, std::forward<Args>(args)...);
|
||||
return __run_top_frame();
|
||||
}
|
||||
#endif
|
||||
@ -298,7 +300,7 @@ public:
|
||||
|
||||
template<typename... Args>
|
||||
PyVar call(PyVar callable, Args&&... args){
|
||||
PUSH(callable); PUSH(PY_NULL);
|
||||
PUSH(callable); PUSH_NULL();
|
||||
__push_varargs(args...);
|
||||
return vectorcall(sizeof...(args));
|
||||
}
|
||||
@ -433,44 +435,44 @@ public:
|
||||
template<typename T>
|
||||
bool is_user_type(PyVar obj){ return _tp(obj) == _tp_user<T>(); }
|
||||
|
||||
template<typename T>
|
||||
PyObject* register_user_class(PyObject*, StrName, RegisterFunc, Type base=tp_object, bool subclass_enabled=false);
|
||||
template<typename T>
|
||||
PyObject* register_user_class(PyObject*, StrName, Type base=tp_object, bool subclass_enabled=false);
|
||||
// template<typename T>
|
||||
// PyObject* register_user_class(PyObject*, StrName, RegisterFunc, Type base=tp_object, bool subclass_enabled=false);
|
||||
// template<typename T>
|
||||
// PyObject* register_user_class(PyObject*, StrName, Type base=tp_object, bool subclass_enabled=false);
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
PyVar new_user_object(Args&&... args){
|
||||
return new_object<T>(_tp_user<T>(), std::forward<Args>(args)...);
|
||||
}
|
||||
// template<typename T, typename ...Args>
|
||||
// PyVar new_user_object(Args&&... args){
|
||||
// return new_object<T>(_tp_user<T>(), std::forward<Args>(args)...);
|
||||
// }
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
PyVar new_object(Type type, Args&&... args){
|
||||
static_assert(!is_sso_v<T>);
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
PyObject* p = (PyObject*)pk_ManagedHeap__new(&heap, type, py_sizeof<T>, true);
|
||||
new (p->_value_ptr()) T(std::forward<Args>(args)...);
|
||||
PyObject* p = pk_ManagedHeap__new(&heap, type, py_sizeof<T>, true);
|
||||
new (PyObject__value_ptr(p)) T(std::forward<Args>(args)...);
|
||||
// backdoor for important builtin types
|
||||
if constexpr(std::is_same_v<T, DummyInstance>
|
||||
|| std::is_same_v<T, Type>
|
||||
|| std::is_same_v<T, DummyModule>) {
|
||||
p->_attr = new NameDict();
|
||||
p->_attr = pk_NameDict__new();
|
||||
}
|
||||
return p;
|
||||
return PyVar__fromobj(p);
|
||||
}
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
PyVar new_object_no_gc(Type type, Args&&... args){
|
||||
static_assert(!is_sso_v<T>);
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
PyObject* p = (PyObject*)pk_ManagedHeap__new(&heap, type, py_sizeof<T>, false);
|
||||
new (p->_value_ptr()) T(std::forward<Args>(args)...);
|
||||
PyObject* p = pk_ManagedHeap__new(&heap, type, py_sizeof<T>, true);
|
||||
new (PyObject__value_ptr(p)) T(std::forward<Args>(args)...);
|
||||
// backdoor for important builtin types
|
||||
if constexpr(std::is_same_v<T, DummyInstance>
|
||||
|| std::is_same_v<T, Type>
|
||||
|| std::is_same_v<T, DummyModule>) {
|
||||
p->_attr = new NameDict();
|
||||
p->_attr = pk_NameDict__new();
|
||||
}
|
||||
return p;
|
||||
return PyVar__fromobj(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -499,7 +501,7 @@ public:
|
||||
PyVar __format_object(PyVar, Str);
|
||||
PyVar __run_top_frame();
|
||||
void __pop_frame();
|
||||
PyVar __py_generator(LinkedFrame* frame, ArgsView buffer);
|
||||
PyVar __py_generator(Frame* frame, ArgsView buffer);
|
||||
void __op_unpack_sequence(uint16_t arg);
|
||||
void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl*);
|
||||
void __unpack_as_list(ArgsView args, List& list);
|
||||
@ -686,32 +688,32 @@ __T _py_cast(VM* vm, PyVar obj) {
|
||||
return _py_cast__internal<__T, false>(vm, obj);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PyObject*
|
||||
VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled) {
|
||||
PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get<T>());
|
||||
mod->attr().set(name, type);
|
||||
_cxx_typeid_map.insert(typeid(T), type->as<Type>());
|
||||
_register(this, mod, type);
|
||||
if(!type->attr().contains(__new__)) {
|
||||
if constexpr(std::is_default_constructible_v<T>) {
|
||||
bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
Type cls_t = args[0]->as<Type>();
|
||||
return vm->new_object<T>(cls_t);
|
||||
});
|
||||
} else {
|
||||
bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
vm->NotImplementedError();
|
||||
return vm->None;
|
||||
});
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
// template <typename T>
|
||||
// PyObject*
|
||||
// VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled) {
|
||||
// PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get<T>());
|
||||
// mod->attr().set(name, type);
|
||||
// _cxx_typeid_map.insert(typeid(T), type->as<Type>());
|
||||
// _register(this, mod, type);
|
||||
// if(!type->attr().contains(__new__)) {
|
||||
// if constexpr(std::is_default_constructible_v<T>) {
|
||||
// bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
// Type cls_t = args[0]->as<Type>();
|
||||
// return vm->new_object<T>(cls_t);
|
||||
// });
|
||||
// } else {
|
||||
// bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
// vm->NotImplementedError();
|
||||
// return vm->None;
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// return type;
|
||||
// }
|
||||
|
||||
template <typename T>
|
||||
PyObject* VM::register_user_class(PyObject* mod, StrName name, Type base, bool subclass_enabled) {
|
||||
return register_user_class<T>(mod, name, &T::_register, base, subclass_enabled);
|
||||
}
|
||||
// template <typename T>
|
||||
// PyObject* VM::register_user_class(PyObject* mod, StrName name, Type base, bool subclass_enabled) {
|
||||
// return register_user_class<T>(mod, name, &T::_register, base, subclass_enabled);
|
||||
// }
|
||||
|
||||
} // namespace pkpy
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_array2d(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_base64(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_csv(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_dataclasses(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_easing(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
unsigned char* _default_import_handler(const char*, int*);
|
||||
void add_module_os(VM* vm);
|
||||
void add_module_io(VM* vm);
|
||||
} // namespace pkpy
|
||||
@ -1,215 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
#include "pocketpy/common/traits.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
inline bool isclose(float a, float b) { return std::fabs(a - b) < 1e-4; }
|
||||
|
||||
struct Vec2 {
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
|
||||
float x, y;
|
||||
|
||||
Vec2() : x(0.0f), y(0.0f) {}
|
||||
|
||||
Vec2(float x, float y) : x(x), y(y) {}
|
||||
|
||||
Vec2 operator+ (const Vec2& v) const { return Vec2(x + v.x, y + v.y); }
|
||||
|
||||
Vec2 operator- (const Vec2& v) const { return Vec2(x - v.x, y - v.y); }
|
||||
|
||||
Vec2 operator* (float s) const { return Vec2(x * s, y * s); }
|
||||
|
||||
Vec2 operator* (const Vec2& v) const { return Vec2(x * v.x, y * v.y); }
|
||||
|
||||
Vec2 operator/ (float s) const { return Vec2(x / s, y / s); }
|
||||
|
||||
Vec2 operator- () const { return Vec2(-x, -y); }
|
||||
|
||||
bool operator== (const Vec2& v) const { return isclose(x, v.x) && isclose(y, v.y); }
|
||||
|
||||
bool operator!= (const Vec2& v) const { return !isclose(x, v.x) || !isclose(y, v.y); }
|
||||
|
||||
float operator[] (int i) const { return (&x)[i]; }
|
||||
|
||||
float dot(const Vec2& v) const { return x * v.x + y * v.y; }
|
||||
|
||||
float cross(const Vec2& v) const { return x * v.y - y * v.x; }
|
||||
|
||||
float length() const { return sqrtf(x * x + y * y); }
|
||||
|
||||
float length_squared() const { return x * x + y * y; }
|
||||
|
||||
Vec2 normalize() const {
|
||||
float l = length();
|
||||
return Vec2(x / l, y / l);
|
||||
}
|
||||
|
||||
Vec2 rotate(float radian) const {
|
||||
float cr = cosf(radian), sr = sinf(radian);
|
||||
return Vec2(x * cr - y * sr, x * sr + y * cr);
|
||||
}
|
||||
};
|
||||
|
||||
struct Vec3 {
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
|
||||
float x, y, z;
|
||||
|
||||
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
|
||||
|
||||
Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
|
||||
|
||||
Vec3 operator+ (const Vec3& v) const { return Vec3(x + v.x, y + v.y, z + v.z); }
|
||||
|
||||
Vec3 operator- (const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); }
|
||||
|
||||
Vec3 operator* (float s) const { return Vec3(x * s, y * s, z * s); }
|
||||
|
||||
Vec3 operator* (const Vec3& v) const { return Vec3(x * v.x, y * v.y, z * v.z); }
|
||||
|
||||
Vec3 operator/ (float s) const { return Vec3(x / s, y / s, z / s); }
|
||||
|
||||
Vec3 operator- () const { return Vec3(-x, -y, -z); }
|
||||
|
||||
bool operator== (const Vec3& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z); }
|
||||
|
||||
bool operator!= (const Vec3& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z); }
|
||||
|
||||
float operator[] (int i) const { return (&x)[i]; }
|
||||
|
||||
float dot(const Vec3& v) const { return x * v.x + y * v.y + z * v.z; }
|
||||
|
||||
Vec3 cross(const Vec3& v) const { return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
|
||||
|
||||
float length() const { return sqrtf(x * x + y * y + z * z); }
|
||||
|
||||
float length_squared() const { return x * x + y * y + z * z; }
|
||||
|
||||
Vec3 normalize() const {
|
||||
float l = length();
|
||||
return Vec3(x / l, y / l, z / l);
|
||||
}
|
||||
};
|
||||
|
||||
struct Vec4 {
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
|
||||
float x, y, z, w;
|
||||
|
||||
Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
|
||||
|
||||
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
||||
|
||||
Vec4 operator+ (const Vec4& v) const { return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); }
|
||||
|
||||
Vec4 operator- (const Vec4& v) const { return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); }
|
||||
|
||||
Vec4 operator* (float s) const { return Vec4(x * s, y * s, z * s, w * s); }
|
||||
|
||||
Vec4 operator* (const Vec4& v) const { return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); }
|
||||
|
||||
Vec4 operator/ (float s) const { return Vec4(x / s, y / s, z / s, w / s); }
|
||||
|
||||
Vec4 operator- () const { return Vec4(-x, -y, -z, -w); }
|
||||
|
||||
bool operator== (const Vec4& v) const {
|
||||
return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w);
|
||||
}
|
||||
|
||||
bool operator!= (const Vec4& v) const {
|
||||
return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w);
|
||||
}
|
||||
|
||||
float operator[] (int i) const { return (&x)[i]; }
|
||||
|
||||
float dot(const Vec4& v) const { return x * v.x + y * v.y + z * v.z + w * v.w; }
|
||||
|
||||
float length() const { return sqrtf(x * x + y * y + z * z + w * w); }
|
||||
|
||||
float length_squared() const { return x * x + y * y + z * z + w * w; }
|
||||
|
||||
Vec4 normalize() const {
|
||||
float l = length();
|
||||
return Vec4(x / l, y / l, z / l, w / l);
|
||||
}
|
||||
|
||||
NoReturn normalize_() {
|
||||
float l = length();
|
||||
x /= l;
|
||||
y /= l;
|
||||
z /= l;
|
||||
w /= l;
|
||||
return {};
|
||||
}
|
||||
|
||||
NoReturn copy_(const Vec4& v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
w = v.w;
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
struct Mat3x3 {
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
|
||||
union {
|
||||
struct {
|
||||
float _11, _12, _13;
|
||||
float _21, _22, _23;
|
||||
float _31, _32, _33;
|
||||
};
|
||||
|
||||
float m[3][3];
|
||||
float v[9];
|
||||
};
|
||||
|
||||
Mat3x3();
|
||||
Mat3x3(float, float, float, float, float, float, float, float, float);
|
||||
|
||||
static Mat3x3 zeros();
|
||||
static Mat3x3 ones();
|
||||
static Mat3x3 identity();
|
||||
|
||||
Mat3x3 operator+ (const Mat3x3& other) const;
|
||||
Mat3x3 operator- (const Mat3x3& other) const;
|
||||
Mat3x3 operator* (float scalar) const;
|
||||
Mat3x3 operator/ (float scalar) const;
|
||||
|
||||
bool operator== (const Mat3x3& other) const;
|
||||
bool operator!= (const Mat3x3& other) const;
|
||||
|
||||
Mat3x3 matmul(const Mat3x3& other) const;
|
||||
Vec3 matmul(const Vec3& other) const;
|
||||
|
||||
float determinant() const;
|
||||
Mat3x3 transpose() const;
|
||||
bool inverse(Mat3x3& out) const;
|
||||
|
||||
/*************** affine transformations ***************/
|
||||
static Mat3x3 trs(Vec2 t, float radian, Vec2 s);
|
||||
bool is_affine() const;
|
||||
Vec2 _t() const;
|
||||
float _r() const;
|
||||
Vec2 _s() const;
|
||||
};
|
||||
|
||||
void add_module_linalg(VM* vm);
|
||||
|
||||
static_assert(is_pod_v<Vec2>);
|
||||
static_assert(is_pod_v<Vec3>);
|
||||
static_assert(is_pod_v<Vec4>);
|
||||
static_assert(is_pod_v<Mat3x3>);
|
||||
|
||||
// template <>
|
||||
// constexpr inline bool is_sso_v<Vec2> = true;
|
||||
// template <>
|
||||
// constexpr inline bool is_sso_v<Vec3> = true;
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_time(VM* vm);
|
||||
void add_module_sys(VM* vm);
|
||||
void add_module_json(VM* vm);
|
||||
void add_module_math(VM* vm);
|
||||
void add_module_traceback(VM* vm);
|
||||
void add_module_dis(VM* vm);
|
||||
void add_module_gc(VM* vm);
|
||||
void add_module_line_profiler(VM* vm);
|
||||
void add_module_enum(VM* vm);
|
||||
void add_module___builtins(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_random(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -7,14 +7,16 @@
|
||||
#include "string.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/public.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int16_t Type;
|
||||
|
||||
typedef struct PyVar{
|
||||
pkpy_Type type;
|
||||
Type type;
|
||||
bool is_ptr;
|
||||
int extra;
|
||||
union {
|
||||
@ -37,22 +39,23 @@ typedef struct PyVar{
|
||||
static_assert(sizeof(PyVar) == 16, "sizeof(PyVar) != 16");
|
||||
|
||||
/* predefined vars */
|
||||
static const pkpy_Type tp_object = 1, tp_type = 2;
|
||||
static const pkpy_Type tp_int = 3, tp_float = 4, tp_bool = 5, tp_str = 6;
|
||||
static const pkpy_Type tp_list = 7, tp_tuple = 8;
|
||||
static const pkpy_Type tp_slice = 9, tp_range = 10, tp_module = 11;
|
||||
static const pkpy_Type tp_function = 12, tp_native_func = 13, tp_bound_method = 14;
|
||||
static const pkpy_Type tp_super = 15, tp_exception = 16, tp_bytes = 17, tp_mappingproxy = 18;
|
||||
static const pkpy_Type tp_dict = 19, tp_property = 20, tp_star_wrapper = 21;
|
||||
static const pkpy_Type tp_staticmethod = 22, tp_classmethod = 23;
|
||||
static const pkpy_Type tp_none_type = 24, tp_not_implemented_type = 25;
|
||||
static const pkpy_Type tp_ellipsis = 26;
|
||||
static const pkpy_Type tp_op_call = 27, tp_op_yield = 28;
|
||||
static const Type tp_object = {1}, tp_type = {2};
|
||||
static const Type tp_int = {3}, tp_float = {4}, tp_bool = {5}, tp_str = {6};
|
||||
static const Type tp_list = {7}, tp_tuple = {8};
|
||||
static const Type tp_slice = {9}, tp_range = {10}, tp_module = {11};
|
||||
static const Type tp_function = {12}, tp_native_func = {13}, tp_bound_method = {14};
|
||||
static const Type tp_super = {15}, tp_exception = {16}, tp_bytes = {17}, tp_mappingproxy = {18};
|
||||
static const Type tp_dict = {19}, tp_property = {20}, tp_star_wrapper = {21};
|
||||
static const Type tp_staticmethod = {22}, tp_classmethod = {23};
|
||||
static const Type tp_none_type = {24}, tp_not_implemented_type = {25};
|
||||
static const Type tp_ellipsis = {26};
|
||||
static const Type tp_op_call = {27}, tp_op_yield = {28};
|
||||
static const Type tp_syntax_error = {29}, tp_stop_iteration = {30};
|
||||
|
||||
PK_INLINE bool PyVar__is_null(const PyVar* self) { return self->type == 0; }
|
||||
PK_INLINE int64_t PyVar__hash(const PyVar* self) { return self->extra + self->_i64; }
|
||||
|
||||
PK_INLINE void PyVar__ctor(PyVar* self, pkpy_Type type, PyObject* obj){
|
||||
PK_INLINE void PyVar__ctor(PyVar* self, Type type, PyObject* obj){
|
||||
self->type = type;
|
||||
self->is_ptr = true;
|
||||
self->_obj = obj;
|
||||
@ -67,7 +70,7 @@ PK_INLINE bool PyVar__IS_OP(const PyVar* a, const PyVar* b){
|
||||
#define pkpy_Var__is_null(self) ((self)->type == 0)
|
||||
#define pkpy_Var__set_null(self) do { (self)->type = 0; } while(0)
|
||||
|
||||
extern PyVar pkpy_NULL, pkpy_OP_CALL, pkpy_OP_YIELD;
|
||||
extern PyVar PY_NULL, PY_OP_CALL, PY_OP_YIELD;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
#include "pocketpy/common/traits.hpp"
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct Type {
|
||||
pkpy_Type index;
|
||||
constexpr Type() : index(0) {}
|
||||
constexpr Type(pkpy_Type index) : index(index) {}
|
||||
bool operator== (Type other) const { return this->index == other.index; }
|
||||
bool operator!= (Type other) const { return this->index != other.index; }
|
||||
constexpr operator pkpy_Type () const { return index; }
|
||||
};
|
||||
|
||||
struct PyVar final: ::PyVar {
|
||||
// uninitialized
|
||||
PyVar() = default;
|
||||
|
||||
// implict conversion
|
||||
PyVar(PyObject* existing){
|
||||
PyVar__ctor3(this, (::PyObject*)existing);
|
||||
}
|
||||
|
||||
/* We must initialize all members to allow == operator to work correctly */
|
||||
// zero initialized
|
||||
PyVar(std::nullptr_t){
|
||||
set_null();
|
||||
}
|
||||
|
||||
// PyObject* initialized (is_sso = false)
|
||||
PyVar(Type type, PyObject* p){
|
||||
PyVar__ctor(this, type, (::PyObject*)p);
|
||||
}
|
||||
|
||||
PyVar(Type type, i64 value){
|
||||
this->type = type;
|
||||
this->is_ptr = false;
|
||||
this->_i64 = value;
|
||||
}
|
||||
|
||||
explicit operator bool () const { return (bool)type; }
|
||||
|
||||
void set_null() {
|
||||
memset(this, 0, sizeof(PyVar));
|
||||
}
|
||||
|
||||
bool operator==(PyObject* other){
|
||||
return is_ptr && (PyObject*)_obj == other;
|
||||
}
|
||||
bool operator!=(PyObject* other){
|
||||
return !is_ptr || (PyObject*)_obj != other;
|
||||
}
|
||||
bool operator==(std::nullptr_t){
|
||||
return type == 0;
|
||||
}
|
||||
bool operator!=(std::nullptr_t){
|
||||
return type != 0;
|
||||
}
|
||||
|
||||
PyObject* get() const {
|
||||
assert(is_ptr);
|
||||
return (PyObject*)_obj;
|
||||
}
|
||||
|
||||
PyObject* operator->() const {
|
||||
assert(is_ptr);
|
||||
return (PyObject*)_obj;
|
||||
}
|
||||
|
||||
i64 hash() const { return PyVar__hash(this); }
|
||||
|
||||
template <typename T>
|
||||
obj_get_t<T> obj_get();
|
||||
|
||||
// implicit convert from ::PyVar
|
||||
PyVar(const ::PyVar& var) {
|
||||
memcpy(this, &var, sizeof(var));
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);
|
||||
} // namespace pkpy
|
||||
@ -1,141 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.hpp"
|
||||
#include "pocketpy/objects/object.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct BoundMethod {
|
||||
PyVar self;
|
||||
PyVar func;
|
||||
|
||||
BoundMethod(PyVar self, PyVar func) : self(self), func(func) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct StaticMethod {
|
||||
PyVar func;
|
||||
|
||||
StaticMethod(PyVar func) : func(func) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct ClassMethod {
|
||||
PyVar func;
|
||||
|
||||
ClassMethod(PyVar func) : func(func) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct Property {
|
||||
PyVar getter;
|
||||
PyVar setter;
|
||||
|
||||
Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct Range {
|
||||
i64 start = 0;
|
||||
i64 stop = -1;
|
||||
i64 step = 1;
|
||||
};
|
||||
|
||||
struct StarWrapper {
|
||||
int level; // either 1 or 2
|
||||
PyVar obj;
|
||||
|
||||
StarWrapper(int level, PyVar obj) : level(level), obj(obj) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
using Bytes = array<unsigned char>;
|
||||
|
||||
struct Super {
|
||||
PyVar first;
|
||||
Type second;
|
||||
|
||||
Super(PyVar first, Type second) : first(first), second(second) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct Slice {
|
||||
PyVar start;
|
||||
PyVar stop;
|
||||
PyVar step;
|
||||
|
||||
Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
const inline int16_t kTpIntIndex = 3;
|
||||
const inline int16_t kTpFloatIndex = 4;
|
||||
const inline int16_t kTpNoneTypeIndex = 24;
|
||||
const inline int16_t kTpNotImplementedTypeIndex = 25;
|
||||
|
||||
inline bool is_tagged(PyVar p) noexcept { return !p.is_ptr; }
|
||||
|
||||
inline bool is_float(PyVar p) noexcept { return p.type == kTpFloatIndex; }
|
||||
|
||||
inline bool is_int(PyVar p) noexcept { return p.type == kTpIntIndex; }
|
||||
|
||||
inline bool is_none(PyVar p) noexcept { return p.type == kTpNoneTypeIndex; }
|
||||
|
||||
inline bool is_not_implemented(PyVar p) noexcept { return p.type == kTpNotImplementedTypeIndex; }
|
||||
|
||||
inline bool is_type(PyVar obj, Type type) {
|
||||
assert(obj != nullptr);
|
||||
return obj.type == type;
|
||||
}
|
||||
|
||||
inline bool is_type(PyObject* p, Type type) {
|
||||
assert(p != nullptr);
|
||||
return p->type == type;
|
||||
}
|
||||
|
||||
struct MappingProxy {
|
||||
PyObject* obj;
|
||||
|
||||
MappingProxy(PyObject* obj) : obj(obj) {}
|
||||
|
||||
NameDict& attr() { return obj->attr(); }
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
StrName _type_name(VM* vm, Type type);
|
||||
template <typename T>
|
||||
T to_void_p(VM*, PyVar);
|
||||
PyVar from_void_p(VM*, void*);
|
||||
|
||||
template <typename T>
|
||||
T& PyVar::obj_get() {
|
||||
static_assert(!is_sso_v<T>, "unsupported");
|
||||
assert(is_ptr);
|
||||
void* v = PyObject__value_ptr(_obj);
|
||||
return *reinterpret_cast<T*>(v);
|
||||
}
|
||||
|
||||
#define PK_OBJ_GET(T, obj) ((obj).obj_get<T>())
|
||||
|
||||
// deprecated
|
||||
#define PK_OBJ_MARK(obj) vm->obj_gc_mark(obj)
|
||||
|
||||
#define VAR(x) py_var(vm, x)
|
||||
#define CAST(T, x) py_cast<T>(vm, x)
|
||||
#define _CAST(T, x) _py_cast<T>(vm, x)
|
||||
|
||||
#define CAST_F(x) py_cast<f64>(vm, x)
|
||||
#define CAST_DEFAULT(T, x, default_value) (x != vm->None) ? py_cast<T>(vm, x) : (default_value)
|
||||
|
||||
/*****************************************************************/
|
||||
#define PY_NULL nullptr
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/any.h"
|
||||
#include "pocketpy/common/traits.hpp"
|
||||
#include "pocketpy/objects/tuplelist.hpp"
|
||||
#include "pocketpy/objects/namedict.hpp"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/common/smallmap.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
typedef PyVar (*NativeFuncC)(VM*, ArgsView);
|
||||
|
||||
struct NativeFunc {
|
||||
NativeFuncC f;
|
||||
int argc; // old style argc-based call
|
||||
FuncDecl_ decl; // new style decl-based call
|
||||
any _userdata;
|
||||
|
||||
NativeFunc(NativeFuncC f, int argc, any userdata = {}) :
|
||||
f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
|
||||
|
||||
NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata = {}) :
|
||||
f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
|
||||
|
||||
PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
|
||||
~NativeFunc() {
|
||||
if(decl) PK_DECREF(decl);
|
||||
}
|
||||
};
|
||||
|
||||
struct Function {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Function)
|
||||
|
||||
FuncDecl_ decl;
|
||||
PyObject* _module; // weak ref
|
||||
PyObject* _class; // weak ref
|
||||
NameDict* _closure; // strong ref
|
||||
|
||||
Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict* _closure) :
|
||||
decl(decl), _module(_module), _class(_class), _closure(_closure) {
|
||||
PK_INCREF(decl);
|
||||
}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
|
||||
~Function() {
|
||||
PK_DECREF(decl);
|
||||
delete _closure;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T lambda_get_userdata(PyVar* p) {
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
static_assert(is_pod_v<T>);
|
||||
int offset = p[-1] != nullptr ? -1 : -2;
|
||||
NativeFunc& nf = p[offset].obj_get<NativeFunc>();
|
||||
return nf._userdata.as<T>();
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,98 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/base.hpp"
|
||||
#include "pocketpy/objects/tuplelist.hpp"
|
||||
#include "pocketpy/objects/dict.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct Dict : private pkpy_Dict {
|
||||
Dict() {
|
||||
pkpy_Dict__ctor(this);
|
||||
}
|
||||
|
||||
Dict(Dict&& other) {
|
||||
std::memcpy(this, &other, sizeof(Dict));
|
||||
pkpy_Dict__ctor(&other);
|
||||
}
|
||||
|
||||
Dict(const Dict& other) {
|
||||
// OPTIMIZEME: reduce copy
|
||||
auto clone = pkpy_Dict__copy(&other);
|
||||
std::memcpy(this, &clone, sizeof(Dict));
|
||||
}
|
||||
|
||||
Dict& operator= (const Dict&) = delete;
|
||||
Dict& operator= (Dict&&) = delete;
|
||||
|
||||
int size() const { return count; }
|
||||
|
||||
void set(VM* vm, PyVar key, PyVar val) {
|
||||
pkpy_Dict__set(this, *(::PyVar*)(&key), *(::PyVar*)(&val));
|
||||
}
|
||||
|
||||
PyVar try_get(VM* vm, PyVar key) const {
|
||||
auto res = pkpy_Dict__try_get(this, *(::PyVar*)(&key));
|
||||
if (!res) return nullptr;
|
||||
return *(const PyVar*)(res);
|
||||
}
|
||||
|
||||
bool contains(VM* vm, PyVar key) const {
|
||||
return pkpy_Dict__contains(this, *(::PyVar*)(&key));
|
||||
}
|
||||
|
||||
bool del(VM* vm, PyVar key) {
|
||||
return pkpy_Dict__del(this, *(::PyVar*)(&key));
|
||||
}
|
||||
|
||||
void update(VM* vm, const Dict& other) {
|
||||
pkpy_Dict__update(this, &other);
|
||||
}
|
||||
|
||||
template <typename __Func>
|
||||
void apply(__Func f) const {
|
||||
pkpy_DictIter it = iter();
|
||||
PyVar key, val;
|
||||
while(pkpy_DictIter__next(&it, (::PyVar*)(&key), (::PyVar*)(&val))) {
|
||||
f(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
Tuple keys() const {
|
||||
Tuple res(count);
|
||||
pkpy_DictIter it = iter();
|
||||
PyVar key, val;
|
||||
int i = 0;
|
||||
while(pkpy_DictIter__next(&it, (::PyVar*)(&key), (::PyVar*)(&val))) {
|
||||
res[i++] = key;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Tuple values() const {
|
||||
Tuple res(count);
|
||||
pkpy_DictIter it = iter();
|
||||
PyVar key, val;
|
||||
int i = 0;
|
||||
while(pkpy_DictIter__next(&it, (::PyVar*)(&key), (::PyVar*)(&val))) {
|
||||
res[i++] = val;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
pkpy_DictIter iter() const {
|
||||
return pkpy_Dict__iter(this);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
pkpy_Dict__clear(this);
|
||||
}
|
||||
|
||||
~Dict() {
|
||||
pkpy_Dict__dtor(this);
|
||||
}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -17,7 +17,7 @@ typedef struct pkpy_ExceptionFrame {
|
||||
} pkpy_ExceptionFrame;
|
||||
|
||||
typedef struct pkpy_Exception {
|
||||
pkpy_StrName type;
|
||||
pk_StrName type;
|
||||
pkpy_Str msg;
|
||||
bool is_re;
|
||||
|
||||
@ -29,7 +29,7 @@ typedef struct pkpy_Exception {
|
||||
c11_vector/*T=pkpy_ExceptionFrame*/ stacktrace;
|
||||
} pkpy_Exception;
|
||||
|
||||
void pkpy_Exception__ctor(pkpy_Exception* self, pkpy_StrName type);
|
||||
void pkpy_Exception__ctor(pkpy_Exception* self, pk_StrName type);
|
||||
void pkpy_Exception__dtor(pkpy_Exception* self);
|
||||
void pkpy_Exception__stpush(pkpy_Exception* self, pkpy_SourceData_ src, int lineno, const char* cursor, const char* name);
|
||||
pkpy_Str pkpy_Exception__summary(pkpy_Exception* self);
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/str.hpp"
|
||||
#include "pocketpy/common/traits.hpp"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/error.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct NeedMoreLines {
|
||||
NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
|
||||
|
||||
bool is_compiling_class;
|
||||
};
|
||||
|
||||
enum class InternalExceptionType : int { Null, Handled, Unhandled, ToBeRaised };
|
||||
|
||||
struct InternalException final {
|
||||
InternalExceptionType type;
|
||||
int arg;
|
||||
|
||||
InternalException() : type(InternalExceptionType::Null), arg(-1) {}
|
||||
|
||||
InternalException(InternalExceptionType type, int arg = -1) : type(type), arg(arg) {}
|
||||
};
|
||||
|
||||
struct Exception: pkpy_Exception{
|
||||
PK_ALWAYS_PASS_BY_POINTER(Exception)
|
||||
|
||||
Exception(uint16_t type){
|
||||
pkpy_Exception__ctor(this, type);
|
||||
}
|
||||
|
||||
~Exception(){
|
||||
pkpy_Exception__dtor(this);
|
||||
}
|
||||
|
||||
void stpush(pkpy_SourceData_ src, int lineno, const char* cursor, const char* name){
|
||||
pkpy_Exception__stpush(this, src, lineno, cursor, name);
|
||||
}
|
||||
|
||||
Str summary(){
|
||||
return pkpy_Exception__summary(this);
|
||||
}
|
||||
};
|
||||
|
||||
struct TopLevelException : std::exception {
|
||||
VM* vm;
|
||||
Exception* ptr;
|
||||
|
||||
TopLevelException(VM* vm, Exception* ptr) : vm(vm), ptr(ptr) {}
|
||||
|
||||
Str summary() const { return ptr->summary(); }
|
||||
|
||||
const char* what() const noexcept override {
|
||||
static Str cached_summary;
|
||||
cached_summary = summary();
|
||||
return cached_summary.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace pkpy
|
||||
@ -12,7 +12,7 @@ extern "C" {
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K uint16_t
|
||||
#define V PyVar
|
||||
#define NAME pkpy_NameDict
|
||||
#define NAME pk_NameDict
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__HEADER
|
||||
|
||||
|
||||
@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/common/str.hpp"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.hpp"
|
||||
#include "pocketpy/objects/namedict.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct NameDict: pkpy_NameDict {
|
||||
PK_ALWAYS_PASS_BY_POINTER(NameDict)
|
||||
|
||||
using Item = pair<StrName, PyVar>;
|
||||
|
||||
NameDict() {
|
||||
pkpy_NameDict__ctor(this);
|
||||
}
|
||||
|
||||
~NameDict() {
|
||||
pkpy_NameDict__dtor(this);
|
||||
}
|
||||
|
||||
uint16_t size() const {
|
||||
return count;
|
||||
}
|
||||
|
||||
void set(StrName key, PyVar val){
|
||||
PyVar* p = (PyVar*)&val;
|
||||
pkpy_NameDict__set(this, key.index, *p);
|
||||
}
|
||||
|
||||
PyVar try_get(StrName key) const{
|
||||
PyVar* p = try_get_2(key);
|
||||
if(p) return *p;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyVar* try_get_2(StrName key) const{
|
||||
PyVar* p = (PyVar*)pkpy_NameDict__try_get(this, key.index);
|
||||
return p;
|
||||
}
|
||||
|
||||
PyVar try_get_likely_found(StrName key) const{
|
||||
return try_get(key);
|
||||
}
|
||||
|
||||
PyVar* try_get_2_likely_found(StrName key) const{
|
||||
return try_get_2(key);
|
||||
}
|
||||
|
||||
bool del(StrName key){
|
||||
return pkpy_NameDict__del(this, key.index);
|
||||
}
|
||||
|
||||
bool contains(StrName key) const{
|
||||
return pkpy_NameDict__contains(this, key.index);
|
||||
}
|
||||
|
||||
PyVar operator[] (StrName key) const{
|
||||
PyVar* val = try_get_2_likely_found(key);
|
||||
if(val == nullptr){
|
||||
PK_FATAL_ERROR("NameDict key not found: %d (%s)\n", (int)key.index, key.escape().c_str())
|
||||
}
|
||||
return *val;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
pkpy_NameDict__clear(this);
|
||||
}
|
||||
|
||||
array<StrName> keys() const{
|
||||
array<StrName> retval((int)size());
|
||||
for(int i=0; i<size(); i++){
|
||||
auto it = c11__at(pkpy_NameDict_KV, this, i);
|
||||
retval[i] = StrName(it->key);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
array<Item> items() const{
|
||||
array<Item> retval((int)size());
|
||||
for(int i=0; i<size(); i++){
|
||||
auto it = c11__at(pkpy_NameDict_KV, this, i);
|
||||
PyVar* p = (PyVar*)&it->value;
|
||||
retval[i] = Item(StrName(it->key), *p);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void apply(void (*f)(StrName, PyVar, void*), void* data){
|
||||
for(int i=0; i<size(); i++){
|
||||
auto it = c11__at(pkpy_NameDict_KV, this, i);
|
||||
PyVar* p = (PyVar*)&it->value;
|
||||
f(StrName(it->key), *p, data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(NameDict) <= 128);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -8,22 +8,33 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct PyObject{
|
||||
pkpy_Type type; // we have a duplicated type here for convenience
|
||||
Type type; // we have a duplicated type here for convenience
|
||||
bool gc_is_large;
|
||||
bool gc_marked;
|
||||
pkpy_NameDict* _attr; // gc will delete this on destruction
|
||||
pk_NameDict* dict; // gc will delete this on destruction
|
||||
} PyObject;
|
||||
|
||||
static_assert(sizeof(PyObject) <= 16, "!(sizeof(PyObject) <= 16)");
|
||||
|
||||
#define PyObject__value_ptr(self) ((char*)self + 16)
|
||||
#define PyObject__as(T, self) (T*)(PyObject__value_ptr(self))
|
||||
#define PK_OBJ_GET(T, val) (*(T*)(PyObject__value_ptr((val)._obj)))
|
||||
#define PK_OBJ_SIZEOF(T) (sizeof(T) + 16)
|
||||
|
||||
PK_INLINE void PyObject__ctor(PyObject* self, pkpy_Type type, bool gc_is_large){
|
||||
PK_INLINE void PyObject__ctor(PyObject* self, Type type, bool gc_is_large){
|
||||
self->type = type;
|
||||
self->gc_is_large = gc_is_large;
|
||||
self->gc_marked = false;
|
||||
self->_attr = NULL;
|
||||
self->dict = NULL;
|
||||
}
|
||||
|
||||
PK_INLINE PyVar PyVar__fromobj(PyObject* obj){
|
||||
PyVar retval = {
|
||||
.type = obj->type,
|
||||
.is_ptr = true,
|
||||
._obj = obj;
|
||||
};
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/str.hpp"
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/objects/base.hpp"
|
||||
#include "pocketpy/objects/object.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct NameDict;
|
||||
|
||||
struct PyObject final: ::PyObject {
|
||||
bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
||||
|
||||
void* _value_ptr() noexcept { return PyObject__value_ptr(this); }
|
||||
|
||||
NameDict& attr() const{
|
||||
assert(is_attr_valid());
|
||||
return *(NameDict*)_attr;
|
||||
}
|
||||
|
||||
PyVar attr(StrName name) const;
|
||||
|
||||
template <typename T>
|
||||
T& as() noexcept {
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
return *reinterpret_cast<T*>(_value_ptr());
|
||||
}
|
||||
|
||||
PyObject(Type type, bool gc_is_large){
|
||||
PyObject__ctor(this, type, gc_is_large);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(PyObject) <= 16);
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,77 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.hpp"
|
||||
#include "pocketpy/objects/base.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct Tuple {
|
||||
const static int INLINED_SIZE = 3;
|
||||
|
||||
PyVar* _args;
|
||||
PyVar _inlined[INLINED_SIZE];
|
||||
int _size;
|
||||
|
||||
Tuple(int n);
|
||||
Tuple(Tuple&& other) noexcept;
|
||||
Tuple(const Tuple& other) = delete;
|
||||
Tuple& operator= (const Tuple& other) = delete;
|
||||
Tuple& operator= (Tuple&& other) = delete;
|
||||
~Tuple();
|
||||
|
||||
Tuple(PyVar, PyVar);
|
||||
Tuple(PyVar, PyVar, PyVar);
|
||||
|
||||
bool is_inlined() const { return _args == _inlined; }
|
||||
|
||||
PyVar& operator[] (int i) { return _args[i]; }
|
||||
|
||||
PyVar operator[] (int i) const { return _args[i]; }
|
||||
|
||||
int size() const { return _size; }
|
||||
|
||||
PyVar* begin() const { return _args; }
|
||||
|
||||
PyVar* end() const { return _args + _size; }
|
||||
|
||||
PyVar* data() const { return _args; }
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct List : public vector<PyVar> {
|
||||
using vector<PyVar>::vector;
|
||||
void _gc_mark(VM*) const;
|
||||
|
||||
Tuple to_tuple() const {
|
||||
Tuple ret(size());
|
||||
for(int i = 0; i < size(); i++)
|
||||
ret[i] = (*this)[i];
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// a lightweight view for function args, it does not own the memory
|
||||
struct ArgsView {
|
||||
PyVar* _begin;
|
||||
PyVar* _end;
|
||||
|
||||
ArgsView(PyVar* begin, PyVar* end) : _begin(begin), _end(end) {}
|
||||
|
||||
ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {}
|
||||
|
||||
PyVar* begin() const { return _begin; }
|
||||
|
||||
PyVar* end() const { return _end; }
|
||||
|
||||
int size() const { return _end - _begin; }
|
||||
|
||||
bool empty() const { return _begin == _end; }
|
||||
|
||||
PyVar operator[] (int i) const { return _begin[i]; }
|
||||
|
||||
List to_list() const;
|
||||
Tuple to_tuple() const;
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,5 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
@ -7,19 +5,27 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int16_t pkpy_Type;
|
||||
typedef struct PyObject PyObject;
|
||||
typedef struct PyVar PyVar;
|
||||
typedef struct pkpy_VM pkpy_VM;
|
||||
typedef struct pk_VM pk_VM;
|
||||
typedef struct py_Error py_Error;
|
||||
|
||||
struct pkpy_G {
|
||||
pkpy_VM* vm;
|
||||
} extern pkpy_g;
|
||||
typedef unsigned (*py_CFunction)(const PyVar*, int);
|
||||
|
||||
extern pk_VM* pk_vm;
|
||||
|
||||
void py_initialize();
|
||||
void py_switch_vm(const char* name);
|
||||
// void py_switch_vm(const char* name);
|
||||
void py_finalize();
|
||||
|
||||
py_Error* py_exec_simple(const char*);
|
||||
py_Error* py_eval_simple(const char*, PyVar*);
|
||||
|
||||
/* py_error */
|
||||
void py_Error__print(const py_Error*);
|
||||
void py_Error__delete(py_Error*);
|
||||
|
||||
|
||||
bool py_eq(const PyVar*, const PyVar*);
|
||||
bool py_le(const PyVar*, const PyVar*);
|
||||
int64_t py_hash(const PyVar*);
|
||||
@ -34,6 +40,8 @@ void py_newstr2(PyVar*, const char*, int);
|
||||
void py_newbytes(PyVar*, const uint8_t*, int);
|
||||
void py_newnone(PyVar*);
|
||||
|
||||
#define py_isnull(self) ((self)->type == 0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/traits.hpp"
|
||||
#include "pocketpy/objects/builtins.hpp"
|
||||
#include "pocketpy/interpreter/vm.hpp"
|
||||
#include "pocketpy/interpreter/iter.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
#include "pocketpy/compiler/compiler.hpp"
|
||||
#include "pocketpy/modules/linalg.hpp"
|
||||
#include "pocketpy/tools/repl.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
static_assert(py_sizeof<Str> <= 64);
|
||||
static_assert(py_sizeof<Mat3x3> <= 64);
|
||||
static_assert(py_sizeof<Struct> <= 64);
|
||||
static_assert(py_sizeof<Tuple> <= 80);
|
||||
static_assert(py_sizeof<List> <= 64);
|
||||
static_assert(py_sizeof<Dict> <= 64);
|
||||
static_assert(py_sizeof<RangeIter> <= 64);
|
||||
static_assert(py_sizeof<RangeIterR> <= 64);
|
||||
static_assert(py_sizeof<ArrayIter> <= 64);
|
||||
static_assert(py_sizeof<StringIter> <= 64);
|
||||
static_assert(py_sizeof<Generator> <= 64);
|
||||
static_assert(py_sizeof<DictItemsIter> <= 64);
|
||||
} // namespace pkpy
|
||||
@ -1,107 +0,0 @@
|
||||
#ifndef POCKETPY_C_H
|
||||
#define POCKETPY_C_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pocketpy/common/export.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
namespace pkpy{
|
||||
#endif
|
||||
typedef struct pkpy_vm_handle pkpy_vm;
|
||||
typedef int (*pkpy_CFunction)(pkpy_vm*);
|
||||
typedef void (*pkpy_COutputHandler)(const char*, int);
|
||||
typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*);
|
||||
typedef int pkpy_CName;
|
||||
typedef int pkpy_CType;
|
||||
typedef const char* pkpy_CString;
|
||||
|
||||
/* Basic Functions */
|
||||
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
|
||||
PK_EXPORT void pkpy_delete_vm(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_exec(pkpy_vm*, const char* source);
|
||||
PK_EXPORT bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module);
|
||||
PK_EXPORT void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv);
|
||||
|
||||
/* Stack Manipulation */
|
||||
PK_EXPORT bool pkpy_dup(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
|
||||
PK_EXPORT bool pkpy_pop_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
|
||||
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
||||
|
||||
// int
|
||||
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val);
|
||||
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out);
|
||||
|
||||
// float
|
||||
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val);
|
||||
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out);
|
||||
|
||||
// bool
|
||||
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val);
|
||||
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out);
|
||||
|
||||
// string
|
||||
PK_EXPORT bool pkpy_push_string(pkpy_vm*, pkpy_CString val);
|
||||
PK_EXPORT bool pkpy_is_string(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_string(pkpy_vm*, int i, pkpy_CString* out);
|
||||
|
||||
// void_p
|
||||
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val);
|
||||
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out);
|
||||
|
||||
// none
|
||||
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
||||
|
||||
// special push
|
||||
PK_EXPORT bool pkpy_push_null(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_push_function(pkpy_vm*, const char* sig, pkpy_CFunction val);
|
||||
PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name);
|
||||
|
||||
// some opt
|
||||
PK_EXPORT bool pkpy_getattr(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_setattr(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_getglobal(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_setglobal(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
||||
PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size);
|
||||
PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_py_repr(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_py_str(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name);
|
||||
|
||||
/* Error Handling */
|
||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg);
|
||||
PK_EXPORT bool pkpy_check_error(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
||||
|
||||
/* Callables */
|
||||
PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc);
|
||||
|
||||
/* Special APIs */
|
||||
PK_EXPORT void pkpy_free(void* p);
|
||||
#define pkpy_string(__s) (__s)
|
||||
PK_EXPORT pkpy_CName pkpy_name(const char* s);
|
||||
PK_EXPORT pkpy_CString pkpy_name_to_string(pkpy_CName name);
|
||||
PK_EXPORT void pkpy_set_output_handler(pkpy_vm*, pkpy_COutputHandler handler);
|
||||
PK_EXPORT void pkpy_set_import_handler(pkpy_vm*, pkpy_CImportHandler handler);
|
||||
|
||||
/* REPL */
|
||||
PK_EXPORT void* pkpy_new_repl(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_repl_input(void* r, const char* line);
|
||||
PK_EXPORT void pkpy_delete_repl(void* repl);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -37,6 +37,8 @@ typedef c11_vector NAME;
|
||||
|
||||
void METHOD(ctor)(NAME* self);
|
||||
void METHOD(dtor)(NAME* self);
|
||||
NAME* METHOD(new)();
|
||||
void METHOD(delete)(NAME* self);
|
||||
void METHOD(set)(NAME* self, K key, V value);
|
||||
V* METHOD(try_get)(const NAME* self, K key);
|
||||
V METHOD(get)(const NAME* self, K key, V default_value);
|
||||
@ -58,6 +60,17 @@ void METHOD(dtor)(NAME* self) {
|
||||
c11_vector__dtor(self);
|
||||
}
|
||||
|
||||
NAME* METHOD(new)() {
|
||||
NAME* self = malloc(sizeof(NAME));
|
||||
METHOD(ctor)(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
void METHOD(delete)(NAME* self) {
|
||||
METHOD(dtor)(self);
|
||||
free(self);
|
||||
}
|
||||
|
||||
void METHOD(set)(NAME* self, K key, V value) {
|
||||
int index;
|
||||
c11__lower_bound(KV, self->data, self->count, key, partial_less, &index);
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/pocketpy_c.h"
|
||||
@ -10,7 +10,7 @@ static c11_smallmap_s2n _interned;
|
||||
static c11_vector/*T=char* */ _r_interned;
|
||||
static bool _initialized = false;
|
||||
|
||||
void pkpy_StrName__initialize(){
|
||||
void pk_StrName__initialize(){
|
||||
if(_initialized) return;
|
||||
c11_smallmap_s2n__ctor(&_interned);
|
||||
for(int i=0; i<_r_interned.count; i++){
|
||||
@ -20,77 +20,77 @@ void pkpy_StrName__initialize(){
|
||||
_initialized = true;
|
||||
|
||||
// unary operators
|
||||
__repr__ = pkpy_StrName__map("__repr__");
|
||||
__str__ = pkpy_StrName__map("__str__");
|
||||
__hash__ = pkpy_StrName__map("__hash__");
|
||||
__len__ = pkpy_StrName__map("__len__");
|
||||
__iter__ = pkpy_StrName__map("__iter__");
|
||||
__next__ = pkpy_StrName__map("__next__");
|
||||
__neg__ = pkpy_StrName__map("__neg__");
|
||||
__repr__ = pk_StrName__map("__repr__");
|
||||
__str__ = pk_StrName__map("__str__");
|
||||
__hash__ = pk_StrName__map("__hash__");
|
||||
__len__ = pk_StrName__map("__len__");
|
||||
__iter__ = pk_StrName__map("__iter__");
|
||||
__next__ = pk_StrName__map("__next__");
|
||||
__neg__ = pk_StrName__map("__neg__");
|
||||
// logical operators
|
||||
__eq__ = pkpy_StrName__map("__eq__");
|
||||
__lt__ = pkpy_StrName__map("__lt__");
|
||||
__le__ = pkpy_StrName__map("__le__");
|
||||
__gt__ = pkpy_StrName__map("__gt__");
|
||||
__ge__ = pkpy_StrName__map("__ge__");
|
||||
__contains__ = pkpy_StrName__map("__contains__");
|
||||
__eq__ = pk_StrName__map("__eq__");
|
||||
__lt__ = pk_StrName__map("__lt__");
|
||||
__le__ = pk_StrName__map("__le__");
|
||||
__gt__ = pk_StrName__map("__gt__");
|
||||
__ge__ = pk_StrName__map("__ge__");
|
||||
__contains__ = pk_StrName__map("__contains__");
|
||||
// binary operators
|
||||
__add__ = pkpy_StrName__map("__add__");
|
||||
__radd__ = pkpy_StrName__map("__radd__");
|
||||
__sub__ = pkpy_StrName__map("__sub__");
|
||||
__rsub__ = pkpy_StrName__map("__rsub__");
|
||||
__mul__ = pkpy_StrName__map("__mul__");
|
||||
__rmul__ = pkpy_StrName__map("__rmul__");
|
||||
__truediv__ = pkpy_StrName__map("__truediv__");
|
||||
__floordiv__ = pkpy_StrName__map("__floordiv__");
|
||||
__mod__ = pkpy_StrName__map("__mod__");
|
||||
__pow__ = pkpy_StrName__map("__pow__");
|
||||
__matmul__ = pkpy_StrName__map("__matmul__");
|
||||
__lshift__ = pkpy_StrName__map("__lshift__");
|
||||
__rshift__ = pkpy_StrName__map("__rshift__");
|
||||
__and__ = pkpy_StrName__map("__and__");
|
||||
__or__ = pkpy_StrName__map("__or__");
|
||||
__xor__ = pkpy_StrName__map("__xor__");
|
||||
__invert__ = pkpy_StrName__map("__invert__");
|
||||
__add__ = pk_StrName__map("__add__");
|
||||
__radd__ = pk_StrName__map("__radd__");
|
||||
__sub__ = pk_StrName__map("__sub__");
|
||||
__rsub__ = pk_StrName__map("__rsub__");
|
||||
__mul__ = pk_StrName__map("__mul__");
|
||||
__rmul__ = pk_StrName__map("__rmul__");
|
||||
__truediv__ = pk_StrName__map("__truediv__");
|
||||
__floordiv__ = pk_StrName__map("__floordiv__");
|
||||
__mod__ = pk_StrName__map("__mod__");
|
||||
__pow__ = pk_StrName__map("__pow__");
|
||||
__matmul__ = pk_StrName__map("__matmul__");
|
||||
__lshift__ = pk_StrName__map("__lshift__");
|
||||
__rshift__ = pk_StrName__map("__rshift__");
|
||||
__and__ = pk_StrName__map("__and__");
|
||||
__or__ = pk_StrName__map("__or__");
|
||||
__xor__ = pk_StrName__map("__xor__");
|
||||
__invert__ = pk_StrName__map("__invert__");
|
||||
// indexer
|
||||
__getitem__ = pkpy_StrName__map("__getitem__");
|
||||
__setitem__ = pkpy_StrName__map("__setitem__");
|
||||
__delitem__ = pkpy_StrName__map("__delitem__");
|
||||
__getitem__ = pk_StrName__map("__getitem__");
|
||||
__setitem__ = pk_StrName__map("__setitem__");
|
||||
__delitem__ = pk_StrName__map("__delitem__");
|
||||
|
||||
// specials
|
||||
__new__ = pkpy_StrName__map("__new__");
|
||||
__init__ = pkpy_StrName__map("__init__");
|
||||
__call__ = pkpy_StrName__map("__call__");
|
||||
__divmod__ = pkpy_StrName__map("__divmod__");
|
||||
__enter__ = pkpy_StrName__map("__enter__");
|
||||
__exit__ = pkpy_StrName__map("__exit__");
|
||||
__name__ = pkpy_StrName__map("__name__");
|
||||
__all__ = pkpy_StrName__map("__all__");
|
||||
__package__ = pkpy_StrName__map("__package__");
|
||||
__path__ = pkpy_StrName__map("__path__");
|
||||
__class__ = pkpy_StrName__map("__class__");
|
||||
__missing__ = pkpy_StrName__map("__missing__");
|
||||
__new__ = pk_StrName__map("__new__");
|
||||
__init__ = pk_StrName__map("__init__");
|
||||
__call__ = pk_StrName__map("__call__");
|
||||
__divmod__ = pk_StrName__map("__divmod__");
|
||||
__enter__ = pk_StrName__map("__enter__");
|
||||
__exit__ = pk_StrName__map("__exit__");
|
||||
__name__ = pk_StrName__map("__name__");
|
||||
__all__ = pk_StrName__map("__all__");
|
||||
__package__ = pk_StrName__map("__package__");
|
||||
__path__ = pk_StrName__map("__path__");
|
||||
__class__ = pk_StrName__map("__class__");
|
||||
__missing__ = pk_StrName__map("__missing__");
|
||||
|
||||
pk_id_add = pkpy_StrName__map("add");
|
||||
pk_id_set = pkpy_StrName__map("set");
|
||||
pk_id_long = pkpy_StrName__map("long");
|
||||
pk_id_complex = pkpy_StrName__map("complex");
|
||||
pk_id_add = pk_StrName__map("add");
|
||||
pk_id_set = pk_StrName__map("set");
|
||||
pk_id_long = pk_StrName__map("long");
|
||||
pk_id_complex = pk_StrName__map("complex");
|
||||
}
|
||||
|
||||
void pkpy_StrName__finalize(){
|
||||
void pk_StrName__finalize(){
|
||||
if(!_initialized) return;
|
||||
c11_smallmap_s2n__dtor(&_interned);
|
||||
c11_vector__dtor(&_r_interned);
|
||||
}
|
||||
|
||||
uint16_t pkpy_StrName__map(const char* name){
|
||||
return pkpy_StrName__map2((c11_string){name, strlen(name)});
|
||||
uint16_t pk_StrName__map(const char* name){
|
||||
return pk_StrName__map2((c11_string){name, strlen(name)});
|
||||
}
|
||||
|
||||
uint16_t pkpy_StrName__map2(c11_string name){
|
||||
uint16_t pk_StrName__map2(c11_string name){
|
||||
// TODO: PK_GLOBAL_SCOPE_LOCK()
|
||||
if(!_initialized){
|
||||
pkpy_StrName__initialize(); // lazy init
|
||||
pk_StrName__initialize(); // lazy init
|
||||
}
|
||||
uint16_t index = c11_smallmap_s2n__get(&_interned, name, 0);
|
||||
if(index != 0) return index;
|
||||
@ -110,7 +110,7 @@ uint16_t pkpy_StrName__map2(c11_string name){
|
||||
return index;
|
||||
}
|
||||
|
||||
const char* pkpy_StrName__rmap(uint16_t index){
|
||||
const char* pk_StrName__rmap(uint16_t index){
|
||||
assert(_initialized);
|
||||
assert(index > 0 && index <= _interned.count);
|
||||
return c11__getitem(char*, &_r_interned, index - 1);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#include "pocketpy/common/strname.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
|
||||
void pkpy_Exception__ctor(pkpy_Exception* self, pkpy_StrName type){
|
||||
void pkpy_Exception__ctor(pkpy_Exception* self, pk_StrName type){
|
||||
self->type = type;
|
||||
self->is_re = true;
|
||||
self->_ip_on_error = -1;
|
||||
@ -48,7 +48,7 @@ pkpy_Str pkpy_Exception__summary(pkpy_Exception* self){
|
||||
pk_SStream__write_cstr(&ss, "\n");
|
||||
}
|
||||
|
||||
const char* name = pkpy_StrName__rmap(self->type);
|
||||
const char* name = pk_StrName__rmap(self->type);
|
||||
pk_SStream__write_cstr(&ss, name);
|
||||
|
||||
if(self->msg.size > 0){
|
||||
|
||||
@ -25,7 +25,7 @@ namespace pkpy {
|
||||
} else { \
|
||||
PyVar self; \
|
||||
PyVar _2 = get_unbound_method(_0, func, &self, false); \
|
||||
if(_2) \
|
||||
if(_2.type) \
|
||||
ret = call_method(self, _2, _1); \
|
||||
else \
|
||||
ret = NotImplemented; \
|
||||
@ -33,7 +33,7 @@ namespace pkpy {
|
||||
if(is_not_implemented(ret)) { \
|
||||
PyVar self; \
|
||||
PyVar _2 = get_unbound_method(_1, rfunc, &self, false); \
|
||||
if(_2) \
|
||||
if(_2.type) \
|
||||
ret = call_method(self, _2, _0); \
|
||||
else \
|
||||
BinaryOptError(op, _0, _1); \
|
||||
@ -192,7 +192,7 @@ PyVar VM::__run_top_frame() {
|
||||
if(decl->nested) {
|
||||
NameDict* captured = frame->_locals.to_namedict();
|
||||
obj = new_object<Function>(tp_function, decl, frame->_module, nullptr, captured);
|
||||
uint16_t name = pkpy_StrName__map2(pkpy_Str__sv(&decl->code->name));
|
||||
uint16_t name = pk_StrName__map2(pkpy_Str__sv(&decl->code->name));
|
||||
captured->set(name, obj);
|
||||
} else {
|
||||
obj = new_object<Function>(tp_function, decl, frame->_module, nullptr, nullptr);
|
||||
@ -863,7 +863,7 @@ PyVar VM::__run_top_frame() {
|
||||
}
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_YIELD_VALUE: return pkpy_OP_YIELD;
|
||||
case OP_YIELD_VALUE: return PY_OP_YIELD;
|
||||
/*****************************************/
|
||||
case OP_LIST_APPEND: {
|
||||
PyVar _0 = POPX();
|
||||
@ -935,7 +935,7 @@ PyVar VM::__run_top_frame() {
|
||||
DISPATCH_JUMP_ABSOLUTE(target)
|
||||
} else {
|
||||
PUSH(_0);
|
||||
return pkpy_OP_YIELD;
|
||||
return PY_OP_YIELD;
|
||||
}
|
||||
}
|
||||
case OP_FOR_ITER_UNPACK: {
|
||||
@ -1075,7 +1075,7 @@ PyVar VM::__run_top_frame() {
|
||||
DISPATCH()
|
||||
/*****************************************/
|
||||
case OP_TRY_ENTER: {
|
||||
frame->set_unwind_target(s_data._sp);
|
||||
frame->set_unwind_target(s_data.sp);
|
||||
DISPATCH()
|
||||
}
|
||||
case OP_EXCEPTION_MATCH: {
|
||||
@ -1,289 +0,0 @@
|
||||
#include "pocketpy/interpreter/cffi.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void VoidP::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
i64 addr = CAST(i64, args[1]);
|
||||
return vm->new_object<VoidP>(cls, reinterpret_cast<void*>(addr));
|
||||
});
|
||||
|
||||
vm->bind__hash__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj);
|
||||
return reinterpret_cast<i64>(self.ptr);
|
||||
});
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj);
|
||||
return _S("<void* at ", self.hex(), ">");
|
||||
});
|
||||
|
||||
#define BIND_CMP(name, op) \
|
||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) return vm->NotImplemented; \
|
||||
void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \
|
||||
void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \
|
||||
return VAR(_0 op _1); \
|
||||
});
|
||||
|
||||
BIND_CMP(__eq__, ==)
|
||||
BIND_CMP(__lt__, <)
|
||||
BIND_CMP(__le__, <=)
|
||||
BIND_CMP(__gt__, >)
|
||||
BIND_CMP(__ge__, >=)
|
||||
|
||||
#undef BIND_CMP
|
||||
}
|
||||
|
||||
void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
int size = CAST(int, args[1]);
|
||||
return vm->new_object<Struct>(cls, size);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) {
|
||||
const Struct& self = _CAST(Struct&, args[0]);
|
||||
SStream ss;
|
||||
for(int i = 0; i < self.size; i++)
|
||||
ss.write_hex((unsigned char)self.p[i]);
|
||||
return VAR(ss.str());
|
||||
});
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func(
|
||||
type,
|
||||
"fromhex",
|
||||
1,
|
||||
[](VM* vm, ArgsView args) {
|
||||
const Str& s = CAST(Str&, args[0]);
|
||||
if(s.size < 2 || s.size % 2 != 0) vm->ValueError("invalid hex string");
|
||||
Struct buffer(s.size / 2, false);
|
||||
for(int i = 0; i < s.size; i += 2) {
|
||||
char c = 0;
|
||||
if(s[i] >= '0' && s[i] <= '9')
|
||||
c += s[i] - '0';
|
||||
else if(s[i] >= 'A' && s[i] <= 'F')
|
||||
c += s[i] - 'A' + 10;
|
||||
else if(s[i] >= 'a' && s[i] <= 'f')
|
||||
c += s[i] - 'a' + 10;
|
||||
else
|
||||
vm->ValueError(_S("invalid hex char: '", s[i], "'"));
|
||||
c <<= 4;
|
||||
if(s[i + 1] >= '0' && s[i + 1] <= '9')
|
||||
c += s[i + 1] - '0';
|
||||
else if(s[i + 1] >= 'A' && s[i + 1] <= 'F')
|
||||
c += s[i + 1] - 'A' + 10;
|
||||
else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
|
||||
c += s[i + 1] - 'a' + 10;
|
||||
else
|
||||
vm->ValueError(_S("invalid hex char: '", s[i + 1], "'"));
|
||||
buffer.p[i / 2] = c;
|
||||
}
|
||||
return vm->new_user_object<Struct>(std::move(buffer));
|
||||
},
|
||||
{},
|
||||
BindType_STATICMETHOD);
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||
Struct& self = _CAST(Struct&, obj);
|
||||
SStream ss;
|
||||
ss << "<struct object of " << self.size << " bytes>";
|
||||
return ss.str();
|
||||
});
|
||||
|
||||
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args) {
|
||||
Struct& self = _CAST(Struct&, args[0]);
|
||||
return vm->new_user_object<VoidP>(self.p);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) {
|
||||
Struct& self = _CAST(Struct&, args[0]);
|
||||
return VAR(self.size);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) {
|
||||
const Struct& self = _CAST(Struct&, args[0]);
|
||||
return vm->new_object<Struct>(vm->_tp(args[0]), self);
|
||||
});
|
||||
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
|
||||
Struct& self = _CAST(Struct&, lhs);
|
||||
if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented;
|
||||
Struct& other = _CAST(Struct&, rhs);
|
||||
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
|
||||
return VAR(ok);
|
||||
});
|
||||
|
||||
#define BIND_SETGET(T, name) \
|
||||
vm->bind(type, "read_" name "(self, offset=0)", [](VM* vm, ArgsView args) { \
|
||||
Struct& self = _CAST(Struct&, args[0]); \
|
||||
i64 offset = CAST(i64, args[1]); \
|
||||
void* ptr = self.p + offset; \
|
||||
return VAR(*(T*)ptr); \
|
||||
}); \
|
||||
vm->bind(type, "write_" name "(self, value, offset=0)", [](VM* vm, ArgsView args) { \
|
||||
Struct& self = _CAST(Struct&, args[0]); \
|
||||
i64 offset = CAST(i64, args[2]); \
|
||||
void* ptr = self.p + offset; \
|
||||
*(T*)ptr = CAST(T, args[1]); \
|
||||
return vm->None; \
|
||||
});
|
||||
BIND_SETGET(char, "char")
|
||||
BIND_SETGET(unsigned char, "uchar")
|
||||
BIND_SETGET(short, "short")
|
||||
BIND_SETGET(unsigned short, "ushort")
|
||||
BIND_SETGET(int, "int")
|
||||
BIND_SETGET(unsigned int, "uint")
|
||||
BIND_SETGET(long, "long")
|
||||
BIND_SETGET(unsigned long, "ulong")
|
||||
BIND_SETGET(long long, "longlong")
|
||||
BIND_SETGET(unsigned long long, "ulonglong")
|
||||
BIND_SETGET(float, "float")
|
||||
BIND_SETGET(double, "double")
|
||||
BIND_SETGET(bool, "bool")
|
||||
BIND_SETGET(void*, "void_p")
|
||||
#undef BIND_SETGET
|
||||
}
|
||||
|
||||
void add_module_c(VM* vm) {
|
||||
PyObject* mod = vm->new_module("c");
|
||||
|
||||
vm->bind_func(mod, "malloc", 1, [](VM* vm, ArgsView args) {
|
||||
i64 size = CAST(i64, args[0]);
|
||||
return VAR(std::malloc(size));
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "free", 1, [](VM* vm, ArgsView args) {
|
||||
void* p = CAST(void*, args[0]);
|
||||
std::free(p);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "memset", 3, [](VM* vm, ArgsView args) {
|
||||
void* p = CAST(void*, args[0]);
|
||||
std::memset(p, CAST(int, args[1]), CAST(size_t, args[2]));
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "memcpy", 3, [](VM* vm, ArgsView args) {
|
||||
void* dst = CAST(void*, args[0]);
|
||||
void* src = CAST(void*, args[1]);
|
||||
i64 size = CAST(i64, args[2]);
|
||||
std::memcpy(dst, src, size);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->register_user_class<VoidP>(mod, "void_p", VM::tp_object, true);
|
||||
vm->register_user_class<Struct>(mod, "struct", VM::tp_object, true);
|
||||
|
||||
mod->attr().set("NULL", vm->new_user_object<VoidP>(nullptr));
|
||||
|
||||
vm->bind(mod, "p_cast(ptr: 'void_p', cls: type[T]) -> T", [](VM* vm, ArgsView args) {
|
||||
VoidP& ptr = CAST(VoidP&, args[0]);
|
||||
vm->check_type(args[1], vm->tp_type);
|
||||
Type cls = PK_OBJ_GET(Type, args[1]);
|
||||
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) { vm->ValueError("expected a subclass of void_p"); }
|
||||
return vm->new_object<VoidP>(cls, ptr.ptr);
|
||||
});
|
||||
|
||||
vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args) {
|
||||
VoidP& ptr = CAST(VoidP&, args[0]);
|
||||
return VAR(reinterpret_cast<i64>(ptr.ptr));
|
||||
});
|
||||
|
||||
vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args) {
|
||||
VoidP& ptr = CAST(VoidP&, args[0]);
|
||||
void* value = *reinterpret_cast<void**>(ptr.ptr);
|
||||
return vm->new_object<VoidP>(args[0].type, value);
|
||||
});
|
||||
|
||||
PyObject* type;
|
||||
Type type_t;
|
||||
|
||||
#define BIND_PRIMITIVE(T, CNAME) \
|
||||
vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args) { \
|
||||
T val = CAST(T, args[0]); \
|
||||
return vm->new_user_object<Struct>(&val, sizeof(T)); \
|
||||
}); \
|
||||
type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user<VoidP>(), true); \
|
||||
mod->attr().set(CNAME "_p", type); \
|
||||
type_t = type->as<Type>(); \
|
||||
vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args) { \
|
||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
return VAR(*target); \
|
||||
}); \
|
||||
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args) { \
|
||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
|
||||
T val = CAST(T, args[1]); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
*target = val; \
|
||||
return vm->None; \
|
||||
}); \
|
||||
vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index) { \
|
||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
|
||||
i64 offset = CAST(i64, index); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
return VAR(target[offset]); \
|
||||
}); \
|
||||
vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value) { \
|
||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
|
||||
i64 offset = CAST(i64, index); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
target[offset] = CAST(T, value); \
|
||||
}); \
|
||||
vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
|
||||
i64 offset = CAST(i64, rhs); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
return vm->new_object<VoidP>(lhs.type, target + offset); \
|
||||
}); \
|
||||
vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
|
||||
i64 offset = CAST(i64, rhs); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
return vm->new_object<VoidP>(lhs.type, target - offset); \
|
||||
}); \
|
||||
vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str { \
|
||||
VoidP& self = _CAST(VoidP&, obj); \
|
||||
return _S("<", CNAME, "* at ", self.hex(), ">"); \
|
||||
});
|
||||
|
||||
BIND_PRIMITIVE(char, "char")
|
||||
BIND_PRIMITIVE(unsigned char, "uchar")
|
||||
BIND_PRIMITIVE(short, "short")
|
||||
BIND_PRIMITIVE(unsigned short, "ushort")
|
||||
BIND_PRIMITIVE(int, "int")
|
||||
BIND_PRIMITIVE(unsigned int, "uint")
|
||||
BIND_PRIMITIVE(long, "long")
|
||||
BIND_PRIMITIVE(unsigned long, "ulong")
|
||||
BIND_PRIMITIVE(long long, "longlong")
|
||||
BIND_PRIMITIVE(unsigned long long, "ulonglong")
|
||||
BIND_PRIMITIVE(float, "float")
|
||||
BIND_PRIMITIVE(double, "double")
|
||||
BIND_PRIMITIVE(bool, "bool")
|
||||
|
||||
#undef BIND_PRIMITIVE
|
||||
|
||||
PyObject* char_p_t = mod->attr()["char_p"].get();
|
||||
vm->bind(char_p_t, "read_string(self) -> str", [](VM* vm, ArgsView args) {
|
||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]);
|
||||
const char* target = (const char*)voidp.ptr;
|
||||
return VAR(target);
|
||||
});
|
||||
|
||||
vm->bind(char_p_t, "write_string(self, value: str)", [](VM* vm, ArgsView args) {
|
||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]);
|
||||
std::string_view sv = CAST(Str&, args[1]).sv();
|
||||
char* target = (char*)voidp.ptr;
|
||||
std::memcpy(target, sv.data(), sv.size());
|
||||
target[sv.size()] = '\0';
|
||||
return vm->None;
|
||||
});
|
||||
}
|
||||
|
||||
PyVar from_void_p(VM* vm, void* p) { return vm->new_user_object<VoidP>(p); }
|
||||
|
||||
} // namespace pkpy
|
||||
133
src/interpreter/frame.c
Normal file
133
src/interpreter/frame.c
Normal file
@ -0,0 +1,133 @@
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
|
||||
void ValueStack__ctor(ValueStack* self) {
|
||||
self->sp = self->begin;
|
||||
self->end = self->begin + PK_VM_STACK_SIZE;
|
||||
}
|
||||
|
||||
void ValueStack__clear(ValueStack* self) {
|
||||
self->sp = self->begin;
|
||||
}
|
||||
|
||||
PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, StrName name){
|
||||
int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1);
|
||||
if(index == -1) return NULL;
|
||||
return &locals[index];
|
||||
}
|
||||
|
||||
pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co) {
|
||||
pk_NameDict* dict = pk_NameDict__new();
|
||||
c11_vector__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
|
||||
PyVar value = locals[entry->value];
|
||||
if(!py_isnull(&value)){
|
||||
pk_NameDict__set(dict, entry->key, value);
|
||||
}
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset){
|
||||
UnwindTarget* self = malloc(sizeof(UnwindTarget));
|
||||
self->next = next;
|
||||
self->iblock = iblock;
|
||||
self->offset = offset;
|
||||
return self;
|
||||
}
|
||||
|
||||
void UnwindTarget__delete(UnwindTarget* self){
|
||||
free(self);
|
||||
}
|
||||
|
||||
Frame* Frame__new(Frame* f_back, const CodeObject* co, PyObject* module_, PyObject* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co){
|
||||
static_assert(sizeof(Frame) <= kPoolFrameBlockSize);
|
||||
Frame* self = PoolFrame_alloc();
|
||||
self->f_back = f_back;
|
||||
self->ip = (Bytecode*)co->codes.data - 1;
|
||||
self->co = co;
|
||||
self->module_ = module_;
|
||||
self->function = function;
|
||||
self->p0 = p0;
|
||||
self->locals = locals;
|
||||
self->locals_co = locals_co;
|
||||
self->uw_list = NULL;
|
||||
return self;
|
||||
}
|
||||
|
||||
void Frame__delete(Frame* self){
|
||||
while(self->uw_list) {
|
||||
UnwindTarget* p = self->uw_list;
|
||||
self->uw_list = p->next;
|
||||
UnwindTarget__delete(p);
|
||||
}
|
||||
PoolFrame_dealloc(self);
|
||||
}
|
||||
|
||||
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s){
|
||||
// try to find a parent try block
|
||||
int iblock = Frame__iblock(self);
|
||||
while(iblock >= 0) {
|
||||
CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, iblock);
|
||||
if(block->type == CodeBlockType_TRY_EXCEPT) break;
|
||||
iblock = block->parent;
|
||||
}
|
||||
if(iblock < 0) return -1;
|
||||
PyVar obj = *--_s->sp; // pop exception object
|
||||
UnwindTarget* uw = Frame__find_unwind_target(self, iblock);
|
||||
_s->sp = (self->locals + uw->offset); // unwind the stack
|
||||
*(_s->sp++) = obj; // push it back
|
||||
return c11__at(CodeBlock, &self->co->blocks, iblock)->end;
|
||||
}
|
||||
|
||||
void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target){
|
||||
int iblock = Frame__iblock(self);
|
||||
if(target >= self->co->codes.count) {
|
||||
while(iblock >= 0) iblock = Frame__exit_block(self, _s, iblock);
|
||||
} else {
|
||||
// BUG (solved)
|
||||
// for i in range(4):
|
||||
// _ = 0
|
||||
// # if there is no op here, the block check will fail
|
||||
// while i: --i
|
||||
int next_block = c11__at(BytecodeEx, &self->co->codes_ex, target)->iblock;
|
||||
while(iblock >= 0 && iblock != next_block)
|
||||
iblock = Frame__exit_block(self, _s, iblock);
|
||||
assert(iblock == next_block);
|
||||
}
|
||||
}
|
||||
|
||||
int Frame__prepare_loop_break(Frame* self, ValueStack* _s){
|
||||
int iblock = Frame__iblock(self);
|
||||
int target = c11__getitem(CodeBlock, &self->co->blocks, iblock).end;
|
||||
Frame__prepare_jump_break(self, _s, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
int Frame__exit_block(Frame* self, ValueStack* _s, int iblock){
|
||||
CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, iblock);
|
||||
if(block->type == CodeBlockType_FOR_LOOP) {
|
||||
_s->sp--; // pop iterator
|
||||
} else if(block->type == CodeBlockType_CONTEXT_MANAGER) {
|
||||
_s->sp--; // pop context variable
|
||||
}
|
||||
return block->parent;
|
||||
}
|
||||
|
||||
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock){
|
||||
UnwindTarget* uw;
|
||||
for(uw = self->uw_list; uw; uw = uw->next) {
|
||||
if(uw->iblock == iblock) return uw;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Frame__set_unwind_target(Frame* self, PyVar* sp) {
|
||||
int iblock = Frame__iblock(self);
|
||||
UnwindTarget* existing = Frame__find_unwind_target(self, iblock);
|
||||
if(existing) {
|
||||
existing->offset = sp - self->locals;
|
||||
} else {
|
||||
UnwindTarget* prev = self->uw_list;
|
||||
self->uw_list = UnwindTarget__new(prev, iblock, sp - self->locals);
|
||||
}
|
||||
}
|
||||
@ -1,122 +0,0 @@
|
||||
#include "pocketpy/interpreter/frame.hpp"
|
||||
#include "pocketpy/common/smallmap.h"
|
||||
|
||||
namespace pkpy {
|
||||
PyVar* FastLocals::try_get_name(StrName name) {
|
||||
int index = c11_smallmap_n2i__get(&co->varnames_inv, name.index, -1);
|
||||
if(index == -1) return nullptr;
|
||||
return &a[index];
|
||||
}
|
||||
|
||||
NameDict* FastLocals::to_namedict() {
|
||||
NameDict* dict = new NameDict();
|
||||
for(int i=0; i<co->varnames_inv.count; i++){
|
||||
auto entry = c11__getitem(c11_smallmap_n2i_KV, &co->varnames_inv, i);
|
||||
PyVar value = a[entry.value];
|
||||
if(value) dict->set(StrName(entry.key), value);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyVar* Frame::f_closure_try_get(StrName name) {
|
||||
if(_callable == nullptr) return nullptr;
|
||||
Function& fn = _callable->as<Function>();
|
||||
if(fn._closure == nullptr) return nullptr;
|
||||
return fn._closure->try_get_2(name);
|
||||
}
|
||||
|
||||
int Frame::prepare_jump_exception_handler(ValueStack* _s) {
|
||||
// try to find a parent try block
|
||||
int i = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock;
|
||||
while(i >= 0) {
|
||||
CodeBlock* block = c11__at(CodeBlock, &co->blocks, i);
|
||||
if(block->type == CodeBlockType_TRY_EXCEPT) break;
|
||||
i = block->parent;
|
||||
}
|
||||
if(i < 0) return -1;
|
||||
PyVar obj = _s->popx(); // pop exception object
|
||||
UnwindTarget* uw = find_unwind_target(i);
|
||||
_s->reset(actual_sp_base() + uw->offset); // unwind the stack
|
||||
_s->push(obj); // push it back
|
||||
return c11__at(CodeBlock, &co->blocks, i)->end;
|
||||
}
|
||||
|
||||
int Frame::_exit_block(ValueStack* _s, int i) {
|
||||
CodeBlock* block = c11__at(CodeBlock, &co->blocks, i);
|
||||
if(block->type == CodeBlockType_FOR_LOOP) {
|
||||
_s->pop(); // pop the iterator
|
||||
} else if(block->type == CodeBlockType_CONTEXT_MANAGER) {
|
||||
_s->pop();
|
||||
}
|
||||
return block->parent;
|
||||
}
|
||||
|
||||
void Frame::prepare_jump_break(ValueStack* _s, int target) {
|
||||
int i = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock;
|
||||
if(target >= co->codes.count) {
|
||||
while(i >= 0) i = _exit_block(_s, i);
|
||||
} else {
|
||||
// BUG (solved)
|
||||
// for i in range(4):
|
||||
// _ = 0
|
||||
// # if there is no op here, the block check will fail
|
||||
// while i: --i
|
||||
int next_block = c11__at(BytecodeEx, &co->codes_ex, target)->iblock;
|
||||
while(i >= 0 && i != next_block)
|
||||
i = _exit_block(_s, i);
|
||||
assert(i == next_block);
|
||||
}
|
||||
}
|
||||
|
||||
void Frame::set_unwind_target(PyVar* _sp) {
|
||||
int iblock = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock;
|
||||
UnwindTarget* existing = find_unwind_target(iblock);
|
||||
if(existing) {
|
||||
existing->offset = _sp - actual_sp_base();
|
||||
} else {
|
||||
UnwindTarget* prev = _uw_list;
|
||||
_uw_list = new UnwindTarget(iblock, _sp - actual_sp_base());
|
||||
_uw_list->next = prev;
|
||||
}
|
||||
}
|
||||
|
||||
UnwindTarget* Frame::find_unwind_target(int iblock) {
|
||||
UnwindTarget* p;
|
||||
for(p = _uw_list; p != nullptr; p = p->next) {
|
||||
if(p->iblock == iblock) return p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Frame::~Frame() {
|
||||
while(_uw_list != nullptr) {
|
||||
UnwindTarget* p = _uw_list;
|
||||
_uw_list = p->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
void CallStack::pop() {
|
||||
assert(!empty());
|
||||
LinkedFrame* p = _tail;
|
||||
_tail = p->f_back;
|
||||
p->~LinkedFrame();
|
||||
PoolFrame_dealloc(p);
|
||||
--_size;
|
||||
}
|
||||
|
||||
LinkedFrame* CallStack::popx() {
|
||||
assert(!empty());
|
||||
LinkedFrame* p = _tail;
|
||||
_tail = p->f_back;
|
||||
--_size;
|
||||
p->f_back = nullptr; // unlink
|
||||
return p;
|
||||
}
|
||||
|
||||
void CallStack::pushx(LinkedFrame* p) {
|
||||
p->f_back = _tail;
|
||||
_tail = p;
|
||||
++_size;
|
||||
}
|
||||
} // namespace pkpy
|
||||
@ -1,7 +1,7 @@
|
||||
#include "pocketpy/interpreter/gc.h"
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
|
||||
void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pkpy_VM *vm){
|
||||
void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pk_VM *vm){
|
||||
c11_vector__ctor(&self->no_gc, sizeof(PyObject*));
|
||||
c11_vector__ctor(&self->gen, sizeof(PyObject*));
|
||||
|
||||
@ -88,9 +88,8 @@ int pk_ManagedHeap__sweep(pk_ManagedHeap *self){
|
||||
return freed;
|
||||
}
|
||||
|
||||
PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, pkpy_Type type, int size, bool gc){
|
||||
PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, Type type, int size){
|
||||
PyObject* obj;
|
||||
// TODO: can we use compile time check?
|
||||
if(size <= kPoolObjectBlockSize){
|
||||
obj = PoolObject_alloc();
|
||||
PyObject__ctor(obj, type, false);
|
||||
@ -98,12 +97,21 @@ PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, pkpy_Type type, int size, bo
|
||||
obj = malloc(size);
|
||||
PyObject__ctor(obj, type, true);
|
||||
}
|
||||
// TODO: can we use compile time check?
|
||||
if(gc){
|
||||
c11_vector__push(PyObject*, &self->gen, obj);
|
||||
self->gc_counter++;
|
||||
}else{
|
||||
c11_vector__push(PyObject*, &self->no_gc, obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
PyObject* pk_ManagedHeap__gcnew(pk_ManagedHeap *self, Type type, int size){
|
||||
PyObject* obj;
|
||||
if(size <= kPoolObjectBlockSize){
|
||||
obj = PoolObject_alloc();
|
||||
PyObject__ctor(obj, type, false);
|
||||
}else{
|
||||
obj = malloc(size);
|
||||
PyObject__ctor(obj, type, true);
|
||||
}
|
||||
c11_vector__push(PyObject*, &self->gen, obj);
|
||||
self->gc_counter++;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
@ -1,135 +0,0 @@
|
||||
#include "pocketpy/interpreter/iter.hpp"
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||
return _0;
|
||||
});
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
RangeIter& self = PK_OBJ_GET(RangeIter, _0);
|
||||
if(self.current >= self.r.stop) return 0;
|
||||
vm->s_data.emplace(VM::tp_int, self.current);
|
||||
self.current += self.r.step;
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||
return _0;
|
||||
});
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
|
||||
if(self.current <= self.r.stop) return 0;
|
||||
vm->s_data.emplace(VM::tp_int, self.current);
|
||||
self.current += self.r.step;
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||
return _0;
|
||||
});
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
ArrayIter& self = _CAST(ArrayIter&, _0);
|
||||
if(self.current == self.end) return 0;
|
||||
vm->s_data.push(*self.current++);
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||
return _0;
|
||||
});
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
StringIter& self = _CAST(StringIter&, _0);
|
||||
Str& s = PK_OBJ_GET(Str, self.ref);
|
||||
if(self.i == s.size) return 0;
|
||||
int start = self.i;
|
||||
int len = c11__u8_header(s[self.i], false);
|
||||
self.i += len;
|
||||
vm->s_data.push(VAR(s.slice(start, self.i)));
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
PyVar Generator::next(VM* vm) {
|
||||
if(state == 2) return vm->StopIteration;
|
||||
// reset frame._sp_base
|
||||
lf->frame._sp_base = vm->s_data._sp;
|
||||
lf->frame._locals.a = vm->s_data._sp;
|
||||
// restore the context
|
||||
for(PyVar obj: s_backup)
|
||||
vm->s_data.push(obj);
|
||||
s_backup.clear();
|
||||
vm->callstack.pushx(lf);
|
||||
lf = nullptr;
|
||||
|
||||
PyVar ret;
|
||||
try {
|
||||
ret = vm->__run_top_frame();
|
||||
} catch(...) {
|
||||
state = 2; // end this generator immediately when an exception is thrown
|
||||
throw;
|
||||
}
|
||||
|
||||
if(ret.type == tp_op_yield) {
|
||||
// backup the context
|
||||
lf = vm->callstack.popx();
|
||||
ret = vm->s_data.popx();
|
||||
for(PyVar obj: lf->frame.stack_view(&vm->s_data))
|
||||
s_backup.push_back(obj);
|
||||
vm->s_data.reset(lf->frame._sp_base);
|
||||
// TODO: should we add this snippet here?
|
||||
// #if PK_ENABLE_PROFILER
|
||||
// if(!_next_breakpoint.empty() && callstack.size()<_next_breakpoint.callstack_size){
|
||||
// _next_breakpoint = NextBreakpoint();
|
||||
// }
|
||||
// #endif
|
||||
state = 1;
|
||||
if(ret == vm->StopIteration) state = 2;
|
||||
return ret;
|
||||
} else {
|
||||
state = 2;
|
||||
return vm->StopIteration;
|
||||
}
|
||||
}
|
||||
|
||||
void Generator::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||
return _0;
|
||||
});
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
Generator& self = _CAST(Generator&, _0);
|
||||
PyVar retval = self.next(vm);
|
||||
if(retval == vm->StopIteration) return 0;
|
||||
vm->s_data.push(retval);
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||
return _0;
|
||||
});
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
DictItemsIter& self = _CAST(DictItemsIter&, _0);
|
||||
PyVar key, val;
|
||||
if (pkpy_DictIter__next(&self.it, (PyVar*)(&key), (PyVar*)(&val))) {
|
||||
vm->s_data.push(key);
|
||||
vm->s_data.push(val);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
PyVar VM::__py_generator(LinkedFrame* frame, ArgsView buffer) {
|
||||
return vm->new_user_object<Generator>(std::move(frame), buffer);
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,131 +0,0 @@
|
||||
#include "pocketpy/interpreter/profiler.hpp"
|
||||
|
||||
#if PK_ENABLE_PROFILER
|
||||
namespace pkpy {
|
||||
|
||||
static std::string left_pad(std::string s, int width) {
|
||||
int n = width - s.size();
|
||||
if(n <= 0) return s;
|
||||
return std::string(n, ' ') + s;
|
||||
}
|
||||
|
||||
static std::string to_string_1f(f64 x) {
|
||||
char buf[32];
|
||||
snprintf(buf, 32, "%.1f", x);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void LineProfiler::begin() { frames.clear(); }
|
||||
|
||||
void LineProfiler::_step(int callstack_size, Frame* frame) {
|
||||
auto line_info = frame->co->lines[frame->ip()];
|
||||
if(line_info.is_virtual) return;
|
||||
std::string_view filename = frame->co->src.filename().sv();
|
||||
int line = line_info.lineno;
|
||||
|
||||
if(frames.empty()) {
|
||||
frames.push_back({callstack_size, frame, clock(), nullptr});
|
||||
} else {
|
||||
_step_end(callstack_size, frame, line);
|
||||
}
|
||||
|
||||
_LineRecord* file_records;
|
||||
|
||||
auto p = records.try_get(filename);
|
||||
if(p == nullptr) {
|
||||
int total_lines = frame->co->src->line_starts.size();
|
||||
file_records = new _LineRecord[total_lines + 1];
|
||||
for(int i = 1; i <= total_lines; i++) file_records[i].line = i;
|
||||
records.insert(filename, file_records);
|
||||
}else{
|
||||
file_records = *p;
|
||||
}
|
||||
|
||||
frames.back().prev_record = &file_records[line];
|
||||
}
|
||||
|
||||
void LineProfiler::_step_end(int callstack_size, Frame* frame, int line) {
|
||||
clock_t now = clock();
|
||||
_FrameRecord& top_frame_record = frames.back();
|
||||
_LineRecord* prev_record = top_frame_record.prev_record;
|
||||
|
||||
int id_delta = callstack_size - top_frame_record.callstack_size;
|
||||
assert(abs(id_delta) <= 1);
|
||||
|
||||
// current line is about to change
|
||||
if(prev_record->line != line) {
|
||||
clock_t delta = now - top_frame_record.prev_time;
|
||||
top_frame_record.prev_time = now;
|
||||
if(id_delta != 1) prev_record->hits++;
|
||||
prev_record->time += delta;
|
||||
}
|
||||
|
||||
if(id_delta == 1) {
|
||||
frames.push_back({callstack_size, frame, now, nullptr});
|
||||
} else {
|
||||
if(id_delta == -1) frames.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void LineProfiler::end() {
|
||||
clock_t now = clock();
|
||||
_FrameRecord& top_frame_record = frames.back();
|
||||
_LineRecord* prev_record = top_frame_record.prev_record;
|
||||
|
||||
clock_t delta = now - top_frame_record.prev_time;
|
||||
top_frame_record.prev_time = now;
|
||||
prev_record->hits++;
|
||||
prev_record->time += delta;
|
||||
|
||||
frames.pop_back();
|
||||
assert(frames.empty());
|
||||
}
|
||||
|
||||
Str LineProfiler::stats() {
|
||||
SStream ss;
|
||||
for(FuncDecl* decl: functions) {
|
||||
int start_line = decl->code->start_line;
|
||||
int end_line = decl->code->end_line;
|
||||
if(start_line == -1 || end_line == -1) continue;
|
||||
std::string_view filename = decl->code->src.filename().sv();
|
||||
const _LineRecord* file_records = records[filename];
|
||||
clock_t total_time = 0;
|
||||
for(int line = start_line; line <= end_line; line++) {
|
||||
total_time += file_records[line].time;
|
||||
}
|
||||
ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n";
|
||||
ss << "File: " << filename << "\n";
|
||||
ss << "Function: " << decl->code->name << " at line " << start_line << "\n";
|
||||
ss << "Line # Hits Time Per Hit % Time Line Contents\n";
|
||||
ss << "==============================================================\n";
|
||||
for(int line = start_line; line <= end_line; line++) {
|
||||
const _LineRecord& record = file_records[line];
|
||||
if(!record.is_valid()) continue;
|
||||
ss << left_pad(std::to_string(line), 6);
|
||||
if(record.hits == 0) {
|
||||
ss << std::string(10 + 13 + 9 + 9, ' ');
|
||||
} else {
|
||||
ss << left_pad(std::to_string(record.hits), 10);
|
||||
ss << left_pad(std::to_string(record.time), 13);
|
||||
ss << left_pad(std::to_string(record.time / record.hits), 9);
|
||||
if(total_time == 0) {
|
||||
ss << left_pad("0.0", 9);
|
||||
} else {
|
||||
ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9);
|
||||
}
|
||||
}
|
||||
// line_content
|
||||
ss << " " << decl->code->src->get_line(line) << "\n";
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
LineProfiler::~LineProfiler() {
|
||||
for(auto& p: records) delete p.second;
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
|
||||
#endif
|
||||
@ -1,40 +1,161 @@
|
||||
// #include "pocketpy/interpreter/vm.h"
|
||||
// #include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
// void pkpy_VM__ctor(pkpy_VM* self){
|
||||
// self->True = (PyVar){
|
||||
// .type=tp_bool,
|
||||
// .is_ptr=true,
|
||||
// .extra=1,
|
||||
// ._obj=pkpy_VM__gcnew(self, tp_bool)
|
||||
// };
|
||||
static unsigned char* pk_default_import_file(pk_VM* vm, const char* path){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// self->False = (PyVar){
|
||||
// .type=tp_bool,
|
||||
// .is_ptr=true,
|
||||
// .extra=0,
|
||||
// ._obj=pkpy_VM__gcnew(self, tp_bool)
|
||||
// };
|
||||
static void pk_default_stdout(pk_VM* vm, const char* s){
|
||||
fprintf(stdout, "%s", s);
|
||||
}
|
||||
|
||||
// self->None = (PyVar){
|
||||
// .type=tp_none_type,
|
||||
// .is_ptr=true,
|
||||
// ._obj=pkpy_VM__gcnew(self, tp_none_type)
|
||||
// };
|
||||
static void pk_default_stderr(pk_VM* vm, const char* s){
|
||||
fprintf(stderr, "%s", s);
|
||||
}
|
||||
|
||||
// self->NotImplemented = (PyVar){
|
||||
// .type=tp_not_implemented_type,
|
||||
// .is_ptr=true,
|
||||
// ._obj=pkpy_VM__gcnew(self, tp_not_implemented_type)
|
||||
// };
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo *self, StrName name, Type base, PyObject* obj, PyObject* module, bool subclass_enabled){
|
||||
memset(self, 0, sizeof(pk_TypeInfo));
|
||||
|
||||
// self->Ellipsis = (PyVar){
|
||||
// .type=tp_ellipsis,
|
||||
// .is_ptr=true,
|
||||
// ._obj=pkpy_VM__gcnew(self, tp_ellipsis)
|
||||
// };
|
||||
// }
|
||||
self->name = name;
|
||||
self->base = base;
|
||||
|
||||
// void pkpy_VM__dtor(pkpy_VM* self){
|
||||
self->obj = obj;
|
||||
self->module = module;
|
||||
self->subclass_enabled = subclass_enabled;
|
||||
|
||||
// }
|
||||
c11_vector__ctor(&self->annotated_fields, sizeof(StrName));
|
||||
}
|
||||
|
||||
void pk_TypeInfo__dtor(pk_TypeInfo *self){
|
||||
c11_vector__dtor(&self->annotated_fields);
|
||||
}
|
||||
|
||||
void pk_VM__ctor(pk_VM* self){
|
||||
self->top_frame = NULL;
|
||||
|
||||
pk_NameDict__ctor(&self->modules);
|
||||
c11_vector__ctor(&self->types, sizeof(pk_TypeInfo));
|
||||
|
||||
self->StopIteration = NULL;
|
||||
self->builtins = NULL;
|
||||
self->main = NULL;
|
||||
|
||||
self->_ceval_on_step = NULL;
|
||||
self->_import_file = pk_default_import_file;
|
||||
self->_stdout = pk_default_stdout;
|
||||
self->_stderr = pk_default_stderr;
|
||||
|
||||
self->__last_exception = NULL;
|
||||
self->__curr_class = NULL;
|
||||
self->__cached_object_new = NULL;
|
||||
self->__dynamic_func_decl = NULL;
|
||||
|
||||
pk_ManagedHeap__ctor(&self->heap, self);
|
||||
ValueStack__ctor(&self->stack);
|
||||
|
||||
self->True = (PyVar){.type=tp_bool, .is_ptr=true, .extra=1,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 1),
|
||||
};
|
||||
self->False = (PyVar){.type=tp_bool, .is_ptr=true, .extra=0,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 1),
|
||||
};
|
||||
self->None = (PyVar){.type=tp_none_type, .is_ptr=true,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_none_type, 1),
|
||||
};
|
||||
self->NotImplemented = (PyVar){.type=tp_not_implemented_type, .is_ptr=true,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_not_implemented_type, 1),
|
||||
};
|
||||
self->Ellipsis = (PyVar){.type=tp_ellipsis, .is_ptr=true,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_ellipsis, 1),
|
||||
};
|
||||
|
||||
/* Init Builtin Types */
|
||||
// 0: unused
|
||||
pk_TypeInfo__ctor(c11_vector__emplace(&self->types), 0, 0, NULL, NULL);
|
||||
#define validate(t, expr) if(t != (expr)) abort()
|
||||
|
||||
validate(tp_object, pk_VM__new_type(self, "object", 0, NULL, true));
|
||||
validate(tp_type, pk_VM__new_type(self, "type", 1, NULL, false));
|
||||
|
||||
validate(tp_int, pk_VM__new_type(self, "int", tp_object, NULL, false));
|
||||
validate(tp_float, pk_VM__new_type(self, "float", tp_object, NULL, false));
|
||||
validate(tp_bool, pk_VM__new_type(self, "bool", tp_object, NULL, false));
|
||||
validate(tp_str, pk_VM__new_type(self, "str", tp_object, NULL, false));
|
||||
|
||||
validate(tp_list, pk_VM__new_type(self, "list", tp_object, NULL, false));
|
||||
validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false));
|
||||
|
||||
validate(tp_slice, pk_VM__new_type(self, "slice", tp_object, NULL, false));
|
||||
validate(tp_range, pk_VM__new_type(self, "range", tp_object, NULL, false));
|
||||
validate(tp_module, pk_VM__new_type(self, "module", tp_object, NULL, false));
|
||||
|
||||
validate(tp_function, pk_VM__new_type(self, "function", tp_object, NULL, false));
|
||||
validate(tp_native_func, pk_VM__new_type(self, "native_func", tp_object, NULL, false));
|
||||
validate(tp_bound_method, pk_VM__new_type(self, "bound_method", tp_object, NULL, false));
|
||||
|
||||
validate(tp_super, pk_VM__new_type(self, "super", tp_object, NULL, false));
|
||||
validate(tp_exception, pk_VM__new_type(self, "Exception", tp_object, NULL, true));
|
||||
validate(tp_bytes, pk_VM__new_type(self, "bytes", tp_object, NULL, false));
|
||||
validate(tp_mappingproxy, pk_VM__new_type(self, "mappingproxy", tp_object, NULL, false));
|
||||
|
||||
validate(tp_dict, pk_VM__new_type(self, "dict", tp_object, NULL, true));
|
||||
validate(tp_property, pk_VM__new_type(self, "property", tp_object, NULL, false));
|
||||
validate(tp_star_wrapper, pk_VM__new_type(self, "star_wrapper", tp_object, NULL, false));
|
||||
|
||||
validate(tp_staticmethod, pk_VM__new_type(self, "staticmethod", tp_object, NULL, false));
|
||||
validate(tp_classmethod, pk_VM__new_type(self, "classmethod", tp_object, NULL, false));
|
||||
|
||||
validate(tp_none_type, pk_VM__new_type(self, "NoneType", tp_object, NULL, false));
|
||||
validate(tp_not_implemented_type, pk_VM__new_type(self, "NotImplementedType", tp_object, NULL, false));
|
||||
validate(tp_ellipsis, pk_VM__new_type(self, "ellipsis", tp_object, NULL, false));
|
||||
|
||||
validate(tp_op_call, pk_VM__new_type(self, "__op_call", tp_object, NULL, false));
|
||||
validate(tp_op_yield, pk_VM__new_type(self, "__op_yield", tp_object, NULL, false));
|
||||
|
||||
validate(tp_syntax_error, pk_VM__new_type(self, "SyntaxError", tp_exception, NULL, false));
|
||||
validate(tp_stop_iteration, pk_VM__new_type(self, "StopIteration", tp_exception, NULL, false));
|
||||
#undef validate
|
||||
|
||||
self->StopIteration = c11__at(pk_TypeInfo, &self->types, tp_stop_iteration)->obj;
|
||||
self->builtins = pk_VM__new_module(self, "builtins", NULL);
|
||||
|
||||
/* Setup Public Builtin Types */
|
||||
Type public_types[] = {
|
||||
tp_object, tp_type,
|
||||
tp_int, tp_float, tp_bool, tp_str,
|
||||
tp_list, tp_tuple,
|
||||
tp_slice, tp_range,
|
||||
tp_bytes, tp_dict, tp_property,
|
||||
tp_exception, tp_stop_iteration, tp_syntax_error
|
||||
};
|
||||
|
||||
for(int i=0; i<PK_ARRAY_COUNT(public_types); i++){
|
||||
Type t = public_types[i];
|
||||
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, t);
|
||||
pk_NameDict__set(self->builtins->dict, ti->name, PyVar__fromobj(ti->obj));
|
||||
}
|
||||
pk_NameDict__set(self->builtins->dict, pk_StrName__map("NotImplemented"), self->NotImplemented);
|
||||
|
||||
/* Do Buildin Bindings*/
|
||||
// TODO: ...
|
||||
self->main = pk_VM__new_module(self, "__main__", NULL);
|
||||
}
|
||||
|
||||
void pk_VM__dtor(pk_VM* self){
|
||||
PK_DECREF(self->__dynamic_func_decl);
|
||||
// destroy all objects
|
||||
pk_ManagedHeap__dtor(&self->heap);
|
||||
// clear frames
|
||||
// ...
|
||||
pk_NameDict__dtor(&self->modules);
|
||||
c11_vector__dtor(&self->types);
|
||||
ValueStack__clear(&self->stack);
|
||||
}
|
||||
|
||||
Type pk_VM__new_type(pk_VM* self, const char* name, Type base, PyObject* module, bool subclass_enabled){
|
||||
Type type = self->types.count;
|
||||
pk_TypeInfo* ti = c11_vector__emplace(&self->types);
|
||||
PyObject* typeobj = pk_ManagedHeap__gcnew(&self->heap, tp_type, PK_OBJ_SIZEOF(Type));
|
||||
*PyObject__as(Type, typeobj) = type;
|
||||
pk_TypeInfo__ctor(ti, pk_StrName__map(name), base, typeobj, module, subclass_enabled);
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "pocketpy/interpreter/vm.hpp"
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/public.h"
|
||||
@ -86,10 +87,11 @@ struct JsonSerializer {
|
||||
};
|
||||
|
||||
VM::VM(bool enable_os) : enable_os(enable_os) {
|
||||
pkpy_g.vm = (pkpy_VM*)this; // setup the current VM
|
||||
pkpy_g.vm = (pk_VM*)this; // setup the current VM
|
||||
Pools_initialize();
|
||||
pkpy_StrName__initialize();
|
||||
pk_ManagedHeap__ctor(&heap, (pkpy_VM*)this);
|
||||
pk_StrName__initialize();
|
||||
|
||||
pk_ManagedHeap__ctor(&heap, (pk_VM*)this);
|
||||
|
||||
static ::PyObject __true_obj = {tp_bool, false, false, NULL};
|
||||
static ::PyObject __false_obj = {tp_bool, false, false, NULL};
|
||||
@ -127,7 +129,7 @@ Str VM::py_str(PyVar obj) {
|
||||
if(ti->m__str__) return ti->m__str__(this, obj);
|
||||
PyVar self;
|
||||
PyVar f = get_unbound_method(obj, __str__, &self, false);
|
||||
if(self) {
|
||||
if(self.type) {
|
||||
PyVar retval = call_method(self, f);
|
||||
if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__str__ must return str"); }
|
||||
return PK_OBJ_GET(Str, retval);
|
||||
@ -153,7 +155,7 @@ PyVar VM::py_iter(PyVar obj) {
|
||||
if(ti->m__iter__) return ti->m__iter__(this, obj);
|
||||
PyVar self;
|
||||
PyVar iter_f = get_unbound_method(obj, __iter__, &self, false);
|
||||
if(self) return call_method(self, iter_f);
|
||||
if(self.type) return call_method(self, iter_f);
|
||||
TypeError(_type_name(vm, _tp(obj)).escape() + " object is not iterable");
|
||||
return nullptr;
|
||||
}
|
||||
@ -223,8 +225,8 @@ PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject
|
||||
stderr_write(msg);
|
||||
}
|
||||
CodeObject__delete(code);
|
||||
callstack.clear();
|
||||
s_data.clear();
|
||||
while(top_frame) __pop_frame(); // this changes s_data.sp, it must put before ValueStack__clear();
|
||||
ValueStack__clear(&s_data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -320,7 +322,7 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
|
||||
|
||||
if(args_tuple.size() == 0) TypeError("expected at least 1 argument, got 0");
|
||||
|
||||
ArgsView view(nullptr, nullptr);
|
||||
ArgsView view;
|
||||
if(args_tuple.size() == 1) {
|
||||
view = cast_array_view(args_tuple[0]);
|
||||
} else {
|
||||
@ -428,11 +430,11 @@ VM::~VM() {
|
||||
PK_DECREF(__dynamic_func_decl);
|
||||
// destroy all objects
|
||||
pk_ManagedHeap__dtor(&heap);
|
||||
pk_NameDict__dtor(&_modules);
|
||||
// clear everything
|
||||
callstack.clear();
|
||||
s_data.clear();
|
||||
while(top_frame) __pop_frame(); // this changes s_data.sp, it must put before ValueStack__clear();
|
||||
ValueStack__clear(&s_data);
|
||||
_all_types.clear();
|
||||
_modules.clear();
|
||||
_lazy_modules.clear();
|
||||
}
|
||||
|
||||
@ -608,7 +610,7 @@ PyVar VM::__py_exec_internal(const CodeObject* code, PyVar globals, PyVar locals
|
||||
});
|
||||
PyObject* _callable =
|
||||
new_object<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure).get();
|
||||
retval = vm->_exec(code, globals_obj, _callable, vm->s_data._sp);
|
||||
retval = vm->_exec(code, globals_obj, _callable, vm->s_data.sp);
|
||||
}
|
||||
|
||||
if(globals_dict) {
|
||||
@ -1063,7 +1065,7 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
|
||||
}
|
||||
|
||||
PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
PyVar* p1 = s_data._sp - KWARGC * 2;
|
||||
PyVar* p1 = (PyVar*)(s_data.sp - KWARGC * 2);
|
||||
PyVar* p0 = p1 - ARGC - 2;
|
||||
// [callable, <self>, args..., kwargs...]
|
||||
// ^p0 ^p1 ^_sp
|
||||
@ -1082,14 +1084,14 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
}
|
||||
|
||||
ArgsView args((!p0[1]) ? (p0 + 2) : (p0 + 1), p1);
|
||||
ArgsView kwargs(p1, s_data._sp);
|
||||
ArgsView kwargs(p1, s_data.sp);
|
||||
|
||||
PyVar* _base = args.begin();
|
||||
|
||||
if(callable_t == tp_function) {
|
||||
/*****************_py_call*****************/
|
||||
// check stack overflow
|
||||
if(s_data.is_overflow()) StackOverflowError();
|
||||
if(s_data.sp > s_data.end) StackOverflowError();
|
||||
|
||||
const Function& fn = PK_OBJ_GET(Function, callable);
|
||||
const CodeObject* co = fn.decl->code;
|
||||
@ -1098,7 +1100,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
case FuncType_NORMAL:
|
||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||
// copy buffer back to stack
|
||||
s_data.reset(_base + co->nlocals);
|
||||
s_data.sp = (_base + co->nlocals);
|
||||
for(int j = 0; j < co->nlocals; j++)
|
||||
_base[j] = __vectorcall_buffer[j];
|
||||
break;
|
||||
@ -1114,9 +1116,9 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
}
|
||||
// [callable, <self>, args..., local_vars...]
|
||||
// ^p0 ^p1 ^_sp
|
||||
s_data.reset(_base + co->nlocals);
|
||||
s_data.sp = (_base + co->nlocals);
|
||||
// initialize local variables to PY_NULL
|
||||
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
|
||||
std::memset(p1, 0, (char*)s_data.sp - (char*)p1);
|
||||
break;
|
||||
case FuncType_EMPTY:
|
||||
if(args.size() != fn.decl->args.count){
|
||||
@ -1128,11 +1130,11 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
if(!kwargs.empty()){
|
||||
TypeError(pk_format("{} takes no keyword arguments", &co->name));
|
||||
}
|
||||
s_data.reset(p0);
|
||||
s_data.sp = p0;
|
||||
return None;
|
||||
case FuncType_GENERATOR:
|
||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||
s_data.reset(p0);
|
||||
s_data.sp = p0;
|
||||
callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
|
||||
return __py_generator(callstack.popx(),
|
||||
ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals));
|
||||
@ -1141,7 +1143,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
|
||||
// simple or normal
|
||||
callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
|
||||
if(op_call) return pkpy_OP_CALL;
|
||||
if(op_call) return PY_OP_CALL;
|
||||
return __run_top_frame();
|
||||
/*****************_py_call*****************/
|
||||
}
|
||||
@ -1153,10 +1155,10 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
int co_nlocals = f.decl->code->nlocals;
|
||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl);
|
||||
// copy buffer back to stack
|
||||
s_data.reset(_base + co_nlocals);
|
||||
s_data.sp = (_base + co_nlocals);
|
||||
for(int j = 0; j < co_nlocals; j++)
|
||||
_base[j] = __vectorcall_buffer[j];
|
||||
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
|
||||
ret = f.call(vm, ArgsView(s_data.sp - co_nlocals, s_data.sp));
|
||||
} else {
|
||||
if(f.argc != -1) {
|
||||
if(KWARGC != 0)
|
||||
@ -1166,7 +1168,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
}
|
||||
ret = f.call(this, args);
|
||||
}
|
||||
s_data.reset(p0);
|
||||
s_data.sp = (p0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1180,7 +1182,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
|
||||
} else {
|
||||
PUSH(new_f);
|
||||
PUSH(PY_NULL);
|
||||
PUSH_NULL();
|
||||
PUSH(callable); // cls
|
||||
for(PyVar o: args)
|
||||
PUSH(o);
|
||||
@ -1204,7 +1206,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
// in cpython it raises a TypeError if the return value is not None
|
||||
} else {
|
||||
// manually reset the stack
|
||||
s_data.reset(p0);
|
||||
s_data.sp = (p0);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@ -1474,7 +1476,7 @@ void VM::_error(PyVar e_obj) {
|
||||
|
||||
void VM::__raise_exc(bool re_raise) {
|
||||
Frame* frame = &callstack.top();
|
||||
Exception& e = PK_OBJ_GET(Exception, s_data.top());
|
||||
Exception& e = PK_OBJ_GET(Exception, (PyVar&)s_data.sp[-1]);
|
||||
if(!re_raise) {
|
||||
e._ip_on_error = frame->ip();
|
||||
e._code_on_error = (void*)frame->co;
|
||||
@ -1537,9 +1539,10 @@ void VM::bind__delitem__(Type type, void (*f)(VM*, PyVar, PyVar)) {
|
||||
|
||||
PyVar VM::__pack_next_retval(unsigned n) {
|
||||
if(n == 0) return StopIteration;
|
||||
if(n == 1) return s_data.popx();
|
||||
PyVar retval = VAR(s_data.view(n).to_tuple());
|
||||
s_data._sp -= n;
|
||||
if(n == 1) return *--s_data.sp;
|
||||
ArgsView view(s_data.sp - n, s_data.sp);
|
||||
PyVar retval = VAR(view.to_tuple());
|
||||
s_data.sp -= n;
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1692,8 +1695,12 @@ void NextBreakpoint::_step(VM* vm) {
|
||||
#endif
|
||||
|
||||
void VM::__pop_frame() {
|
||||
s_data.reset(callstack.top()._sp_base);
|
||||
callstack.pop();
|
||||
assert(top_frame);
|
||||
s_data.sp = top_frame->p0;
|
||||
// callstack.pop()
|
||||
Frame* p = top_frame;
|
||||
top_frame = p->f_back;
|
||||
Frame__delete(p);
|
||||
|
||||
#if PK_ENABLE_PROFILER
|
||||
if(!_next_breakpoint.empty() && callstack.size() < _next_breakpoint.callstack_size) {
|
||||
@ -1937,8 +1944,8 @@ extern "C"{
|
||||
vm->obj_gc_mark(vm->__last_exception);
|
||||
vm->obj_gc_mark(vm->__curr_class);
|
||||
vm->obj_gc_mark(vm->__c.error);
|
||||
vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end());
|
||||
if(self->_gc_marker_ex) self->_gc_marker_ex((pkpy_VM*)vm);
|
||||
vm->__stack_gc_mark((PyVar*)vm->s_data.begin, (PyVar*)vm->s_data.end);
|
||||
if(self->_gc_marker_ex) self->_gc_marker_ex((pk_VM*)vm);
|
||||
}
|
||||
|
||||
void pk_ManagedHeap__delete_obj(pk_ManagedHeap* self, ::PyObject* __obj){
|
||||
|
||||
@ -1,406 +0,0 @@
|
||||
#include "pocketpy/modules/array2d.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct Array2d {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Array2d)
|
||||
|
||||
PyVar* data;
|
||||
int n_cols;
|
||||
int n_rows;
|
||||
int numel;
|
||||
|
||||
Array2d() {
|
||||
data = nullptr;
|
||||
n_cols = 0;
|
||||
n_rows = 0;
|
||||
numel = 0;
|
||||
}
|
||||
|
||||
void init(int n_cols, int n_rows) {
|
||||
this->n_cols = n_cols;
|
||||
this->n_rows = n_rows;
|
||||
this->numel = n_cols * n_rows;
|
||||
this->data = new PyVar[numel];
|
||||
}
|
||||
|
||||
bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
|
||||
|
||||
void check_valid(VM* vm, int col, int row) const {
|
||||
if(is_valid(col, row)) return;
|
||||
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
|
||||
}
|
||||
|
||||
PyVar _get(int col, int row) { return data[row * n_cols + col]; }
|
||||
|
||||
void _set(int col, int row, PyVar value) { data[row * n_cols + col] = value; }
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
return vm->new_object<Array2d>(cls);
|
||||
});
|
||||
|
||||
vm->bind(type, "__init__(self, n_cols: int, n_rows: int, default=None)", [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
int n_cols = CAST(int, args[1]);
|
||||
int n_rows = CAST(int, args[2]);
|
||||
if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); }
|
||||
self.init(n_cols, n_rows);
|
||||
if(vm->py_callable(args[3])) {
|
||||
for(int i = 0; i < self.numel; i++)
|
||||
self.data[i] = vm->call(args[3]);
|
||||
} else {
|
||||
for(int i = 0; i < self.numel; i++)
|
||||
self.data[i] = args[3];
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
PY_READONLY_FIELD(Array2d, "n_cols", n_cols);
|
||||
PY_READONLY_FIELD(Array2d, "n_rows", n_rows);
|
||||
PY_READONLY_FIELD(Array2d, "width", n_cols);
|
||||
PY_READONLY_FIELD(Array2d, "height", n_rows);
|
||||
PY_READONLY_FIELD(Array2d, "numel", numel);
|
||||
|
||||
// _get
|
||||
vm->bind_func(type, "_get", 3, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
int col = CAST(int, args[1]);
|
||||
int row = CAST(int, args[2]);
|
||||
self.check_valid(vm, col, row);
|
||||
return self._get(col, row);
|
||||
});
|
||||
|
||||
// _set
|
||||
vm->bind_func(type, "_set", 4, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
int col = CAST(int, args[1]);
|
||||
int row = CAST(int, args[2]);
|
||||
self.check_valid(vm, col, row);
|
||||
self._set(col, row, args[3]);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "is_valid", 3, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
int col = CAST(int, args[1]);
|
||||
int row = CAST(int, args[2]);
|
||||
return VAR(self.is_valid(col, row));
|
||||
});
|
||||
|
||||
vm->bind(type, "get(self, col: int, row: int, default=None)", [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
int col = CAST(int, args[1]);
|
||||
int row = CAST(int, args[2]);
|
||||
if(!self.is_valid(col, row)) return args[3];
|
||||
return self._get(col, row);
|
||||
});
|
||||
|
||||
#define HANDLE_SLICE() \
|
||||
int start_col, stop_col, step_col; \
|
||||
int start_row, stop_row, step_row; \
|
||||
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \
|
||||
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \
|
||||
if(step_col != 1 || step_row != 1) vm->ValueError("slice step must be 1"); \
|
||||
int slice_width = stop_col - start_col; \
|
||||
int slice_height = stop_row - start_row; \
|
||||
if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive");
|
||||
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||
const Tuple& xy = CAST(Tuple&, _1);
|
||||
|
||||
if(is_int(xy[0]) && is_int(xy[1])) {
|
||||
i64 col = xy[0]._i64;
|
||||
i64 row = xy[1]._i64;
|
||||
self.check_valid(vm, col, row);
|
||||
return self._get(col, row);
|
||||
}
|
||||
|
||||
if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)) {
|
||||
HANDLE_SLICE();
|
||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||
new_array.init(stop_col - start_col, stop_row - start_row);
|
||||
for(int j = start_row; j < stop_row; j++) {
|
||||
for(int i = start_col; i < stop_col; i++) {
|
||||
new_array._set(i - start_col, j - start_row, self._get(i, j));
|
||||
}
|
||||
}
|
||||
return new_array_obj;
|
||||
}
|
||||
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
|
||||
});
|
||||
|
||||
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||
const Tuple& xy = CAST(Tuple&, _1);
|
||||
if(is_int(xy[0]) && is_int(xy[1])) {
|
||||
i64 col = xy[0]._i64;
|
||||
i64 row = xy[1]._i64;
|
||||
self.check_valid(vm, col, row);
|
||||
self._set(col, row, _2);
|
||||
return;
|
||||
}
|
||||
|
||||
if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)) {
|
||||
HANDLE_SLICE();
|
||||
|
||||
bool is_basic_type = false;
|
||||
switch(vm->_tp(_2)) {
|
||||
case VM::tp_int: is_basic_type = true; break;
|
||||
case VM::tp_float: is_basic_type = true; break;
|
||||
case VM::tp_str: is_basic_type = true; break;
|
||||
case VM::tp_bool: is_basic_type = true; break;
|
||||
default: is_basic_type = is_none(_2);
|
||||
}
|
||||
|
||||
if(is_basic_type) {
|
||||
for(int j = 0; j < slice_height; j++)
|
||||
for(int i = 0; i < slice_width; i++)
|
||||
self._set(i + start_col, j + start_row, _2);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!vm->is_user_type<Array2d>(_2)) {
|
||||
vm->TypeError(_S("expected int/float/str/bool/None or an array2d instance"));
|
||||
}
|
||||
|
||||
Array2d& other = PK_OBJ_GET(Array2d, _2);
|
||||
if(slice_width != other.n_cols || slice_height != other.n_rows) {
|
||||
vm->ValueError("array2d size does not match the slice size");
|
||||
}
|
||||
for(int j = 0; j < slice_height; j++)
|
||||
for(int i = 0; i < slice_width; i++)
|
||||
self._set(i + start_col, j + start_row, other._get(i, j));
|
||||
return;
|
||||
}
|
||||
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
|
||||
});
|
||||
|
||||
#undef HANDLE_SLICE
|
||||
|
||||
vm->bind_func(type, "tolist", 1, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
List t(self.n_rows);
|
||||
for(int j = 0; j < self.n_rows; j++) {
|
||||
List row(self.n_cols);
|
||||
for(int i = 0; i < self.n_cols; i++)
|
||||
row[i] = self._get(i, j);
|
||||
t[j] = VAR(std::move(row));
|
||||
}
|
||||
return VAR(std::move(t));
|
||||
});
|
||||
|
||||
vm->bind__len__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||
return (i64)self.numel;
|
||||
});
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar _0) -> Str {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||
return _S("array2d(", self.n_cols, ", ", self.n_rows, ')');
|
||||
});
|
||||
|
||||
vm->bind_func(type, "map", 2, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
PyVar f = args[1];
|
||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||
new_array.init(self.n_cols, self.n_rows);
|
||||
for(int i = 0; i < new_array.numel; i++) {
|
||||
new_array.data[i] = vm->call(f, self.data[i]);
|
||||
}
|
||||
return new_array_obj;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||
new_array.init(self.n_cols, self.n_rows);
|
||||
for(int i = 0; i < new_array.numel; i++) {
|
||||
new_array.data[i] = self.data[i];
|
||||
}
|
||||
return new_array_obj;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "fill_", 2, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
for(int i = 0; i < self.numel; i++) {
|
||||
self.data[i] = args[1];
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "apply_", 2, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
PyVar f = args[1];
|
||||
for(int i = 0; i < self.numel; i++) {
|
||||
self.data[i] = vm->call(f, self.data[i]);
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
if(is_type(args[1], VM::tp_list)) {
|
||||
const List& list = PK_OBJ_GET(List, args[1]);
|
||||
if(list.size() != self.numel) {
|
||||
vm->ValueError("list size must be equal to the number of elements in the array2d");
|
||||
}
|
||||
for(int i = 0; i < self.numel; i++) {
|
||||
self.data[i] = list[i];
|
||||
}
|
||||
return vm->None;
|
||||
}
|
||||
Array2d& other = CAST(Array2d&, args[1]);
|
||||
// if self and other have different sizes, re-initialize self
|
||||
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) {
|
||||
delete self.data;
|
||||
self.init(other.n_cols, other.n_rows);
|
||||
}
|
||||
for(int i = 0; i < self.numel; i++) {
|
||||
self.data[i] = other.data[i];
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||
if(!vm->is_user_type<Array2d>(_1)) return vm->NotImplemented;
|
||||
Array2d& other = PK_OBJ_GET(Array2d, _1);
|
||||
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False;
|
||||
for(int i = 0; i < self.numel; i++) {
|
||||
if(vm->py_ne(self.data[i], other.data[i])) return vm->False;
|
||||
}
|
||||
return vm->True;
|
||||
});
|
||||
|
||||
vm->bind(type, "count_neighbors(self, value, neighborhood='Moore') -> array2d[int]", [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||
new_array.init(self.n_cols, self.n_rows);
|
||||
PyVar value = args[1];
|
||||
const Str& neighborhood = CAST(Str&, args[2]);
|
||||
if(neighborhood == "Moore") {
|
||||
for(int j = 0; j < new_array.n_rows; j++) {
|
||||
for(int i = 0; i < new_array.n_cols; i++) {
|
||||
int count = 0;
|
||||
count += self.is_valid(i - 1, j - 1) && vm->py_eq(self._get(i - 1, j - 1), value);
|
||||
count += self.is_valid(i, j - 1) && vm->py_eq(self._get(i, j - 1), value);
|
||||
count += self.is_valid(i + 1, j - 1) && vm->py_eq(self._get(i + 1, j - 1), value);
|
||||
count += self.is_valid(i - 1, j) && vm->py_eq(self._get(i - 1, j), value);
|
||||
count += self.is_valid(i + 1, j) && vm->py_eq(self._get(i + 1, j), value);
|
||||
count += self.is_valid(i - 1, j + 1) && vm->py_eq(self._get(i - 1, j + 1), value);
|
||||
count += self.is_valid(i, j + 1) && vm->py_eq(self._get(i, j + 1), value);
|
||||
count += self.is_valid(i + 1, j + 1) && vm->py_eq(self._get(i + 1, j + 1), value);
|
||||
new_array._set(i, j, VAR(count));
|
||||
}
|
||||
}
|
||||
} else if(neighborhood == "von Neumann") {
|
||||
for(int j = 0; j < new_array.n_rows; j++) {
|
||||
for(int i = 0; i < new_array.n_cols; i++) {
|
||||
int count = 0;
|
||||
count += self.is_valid(i, j - 1) && vm->py_eq(self._get(i, j - 1), value);
|
||||
count += self.is_valid(i - 1, j) && vm->py_eq(self._get(i - 1, j), value);
|
||||
count += self.is_valid(i + 1, j) && vm->py_eq(self._get(i + 1, j), value);
|
||||
count += self.is_valid(i, j + 1) && vm->py_eq(self._get(i, j + 1), value);
|
||||
new_array._set(i, j, VAR(count));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vm->ValueError("neighborhood must be 'Moore' or 'von Neumann'");
|
||||
}
|
||||
return new_array_obj;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "count", 2, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
PyVar value = args[1];
|
||||
int count = 0;
|
||||
for(int i = 0; i < self.numel; i++)
|
||||
count += vm->py_eq(self.data[i], value);
|
||||
return VAR(count);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "find_bounding_rect", 2, [](VM* vm, ArgsView args) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
PyVar value = args[1];
|
||||
int left = self.n_cols;
|
||||
int top = self.n_rows;
|
||||
int right = 0;
|
||||
int bottom = 0;
|
||||
for(int j = 0; j < self.n_rows; j++) {
|
||||
for(int i = 0; i < self.n_cols; i++) {
|
||||
if(vm->py_eq(self._get(i, j), value)) {
|
||||
left = (std::min)(left, i);
|
||||
top = (std::min)(top, j);
|
||||
right = (std::max)(right, i);
|
||||
bottom = (std::max)(bottom, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
int width = right - left + 1;
|
||||
int height = bottom - top + 1;
|
||||
if(width <= 0 || height <= 0) return vm->None;
|
||||
Tuple t(4);
|
||||
t[0] = VAR(left);
|
||||
t[1] = VAR(top);
|
||||
t[2] = VAR(width);
|
||||
t[3] = VAR(height);
|
||||
return VAR(std::move(t));
|
||||
});
|
||||
}
|
||||
|
||||
void _gc_mark(VM* vm) const {
|
||||
for(int i = 0; i < numel; i++)
|
||||
vm->obj_gc_mark(data[i]);
|
||||
}
|
||||
|
||||
~Array2d() { delete[] data; }
|
||||
};
|
||||
|
||||
struct Array2dIter {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Array2dIter)
|
||||
|
||||
PyVar ref;
|
||||
Array2d* a;
|
||||
int i;
|
||||
|
||||
Array2dIter(PyVar ref, Array2d* a) : ref(ref), a(a), i(0) {}
|
||||
|
||||
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||
return _0;
|
||||
});
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
|
||||
if(self.i == self.a->numel) return 0;
|
||||
std::div_t res = std::div(self.i, self.a->n_cols);
|
||||
vm->s_data.emplace(VM::tp_int, res.rem);
|
||||
vm->s_data.emplace(VM::tp_int, res.quot);
|
||||
vm->s_data.push(self.a->data[self.i++]);
|
||||
return 3;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void add_module_array2d(VM* vm) {
|
||||
PyObject* mod = vm->new_module("array2d");
|
||||
|
||||
vm->register_user_class<Array2d>(mod, "array2d", VM::tp_object, true);
|
||||
vm->register_user_class<Array2dIter>(mod, "_array2d_iter");
|
||||
|
||||
Type array2d_iter_t = vm->_tp_user<Array2d>();
|
||||
vm->bind__iter__(array2d_iter_t, [](VM* vm, PyVar _0) {
|
||||
return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>());
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,175 +0,0 @@
|
||||
#include "pocketpy/modules/base64.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
// https://github.com/zhicheng/base64/blob/master/base64.c
|
||||
|
||||
const char BASE64_PAD = '=';
|
||||
const char BASE64DE_FIRST = '+';
|
||||
const char BASE64DE_LAST = 'z';
|
||||
|
||||
// clang-format off
|
||||
/* BASE 64 encode table */
|
||||
const char base64en[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/',
|
||||
};
|
||||
|
||||
/* ASCII order for BASE 64 decode, 255 in unused character */
|
||||
const unsigned char base64de[] = {
|
||||
/* nul, soh, stx, etx, eot, enq, ack, bel, */
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
|
||||
/* bs, ht, nl, vt, np, cr, so, si, */
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
|
||||
/* dle, dc1, dc2, dc3, dc4, nak, syn, etb, */
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
|
||||
/* can, em, sub, esc, fs, gs, rs, us, */
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
|
||||
/* sp, '!', '"', '#', '$', '%', '&', ''', */
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
|
||||
/* '(', ')', '*', '+', ',', '-', '.', '/', */
|
||||
255, 255, 255, 62, 255, 255, 255, 63,
|
||||
|
||||
/* '0', '1', '2', '3', '4', '5', '6', '7', */
|
||||
52, 53, 54, 55, 56, 57, 58, 59,
|
||||
|
||||
/* '8', '9', ':', ';', '<', '=', '>', '?', */
|
||||
60, 61, 255, 255, 255, 255, 255, 255,
|
||||
|
||||
/* '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', */
|
||||
255, 0, 1, 2, 3, 4, 5, 6,
|
||||
|
||||
/* 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', */
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
|
||||
/* 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', */
|
||||
15, 16, 17, 18, 19, 20, 21, 22,
|
||||
|
||||
/* 'X', 'Y', 'Z', '[', '\', ']', '^', '_', */
|
||||
23, 24, 25, 255, 255, 255, 255, 255,
|
||||
|
||||
/* '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', */
|
||||
255, 26, 27, 28, 29, 30, 31, 32,
|
||||
|
||||
/* 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', */
|
||||
33, 34, 35, 36, 37, 38, 39, 40,
|
||||
|
||||
/* 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', */
|
||||
41, 42, 43, 44, 45, 46, 47, 48,
|
||||
|
||||
/* 'x', 'y', 'z', '{', '|', '}', '~', del, */
|
||||
49, 50, 51, 255, 255, 255, 255, 255
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static unsigned int base64_encode(const unsigned char* in, unsigned int inlen, char* out) {
|
||||
int s;
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
unsigned char c;
|
||||
unsigned char l;
|
||||
|
||||
s = 0;
|
||||
l = 0;
|
||||
for(i = j = 0; i < inlen; i++) {
|
||||
c = in[i];
|
||||
|
||||
switch(s) {
|
||||
case 0:
|
||||
s = 1;
|
||||
out[j++] = base64en[(c >> 2) & 0x3F];
|
||||
break;
|
||||
case 1:
|
||||
s = 2;
|
||||
out[j++] = base64en[((l & 0x3) << 4) | ((c >> 4) & 0xF)];
|
||||
break;
|
||||
case 2:
|
||||
s = 0;
|
||||
out[j++] = base64en[((l & 0xF) << 2) | ((c >> 6) & 0x3)];
|
||||
out[j++] = base64en[c & 0x3F];
|
||||
break;
|
||||
}
|
||||
l = c;
|
||||
}
|
||||
|
||||
switch(s) {
|
||||
case 1:
|
||||
out[j++] = base64en[(l & 0x3) << 4];
|
||||
out[j++] = BASE64_PAD;
|
||||
out[j++] = BASE64_PAD;
|
||||
break;
|
||||
case 2:
|
||||
out[j++] = base64en[(l & 0xF) << 2];
|
||||
out[j++] = BASE64_PAD;
|
||||
break;
|
||||
}
|
||||
|
||||
out[j] = 0;
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
static unsigned int base64_decode(const char* in, unsigned int inlen, unsigned char* out) {
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
unsigned char c;
|
||||
|
||||
if(inlen & 0x3) { return 0; }
|
||||
|
||||
for(i = j = 0; i < inlen; i++) {
|
||||
if(in[i] == BASE64_PAD) { break; }
|
||||
if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { return 0; }
|
||||
|
||||
c = base64de[(unsigned char)in[i]];
|
||||
if(c == 255) { return 0; }
|
||||
|
||||
switch(i & 0x3) {
|
||||
case 0: out[j] = (c << 2) & 0xFF; break;
|
||||
case 1:
|
||||
out[j++] |= (c >> 4) & 0x3;
|
||||
out[j] = (c & 0xF) << 4;
|
||||
break;
|
||||
case 2:
|
||||
out[j++] |= (c >> 2) & 0xF;
|
||||
out[j] = (c & 0x3) << 6;
|
||||
break;
|
||||
case 3: out[j++] |= c; break;
|
||||
}
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
void add_module_base64(VM* vm) {
|
||||
PyObject* mod = vm->new_module("base64");
|
||||
|
||||
// b64encode
|
||||
vm->bind_func(mod, "b64encode", 1, [](VM* vm, ArgsView args) {
|
||||
Bytes& b = CAST(Bytes&, args[0]);
|
||||
unsigned char* p = (unsigned char*)std::malloc(b.size() * 2);
|
||||
int size = base64_encode((const unsigned char*)b.data(), b.size(), (char*)p);
|
||||
return VAR(Bytes(p, size));
|
||||
});
|
||||
|
||||
// b64decode
|
||||
vm->bind_func(mod, "b64decode", 1, [](VM* vm, ArgsView args) {
|
||||
Bytes& b = CAST(Bytes&, args[0]);
|
||||
unsigned char* p = (unsigned char*)std::malloc(b.size());
|
||||
int size = base64_decode((const char*)b.data(), b.size(), p);
|
||||
return VAR(Bytes(p, size));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,87 +0,0 @@
|
||||
#include "pocketpy/modules/csv.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_csv(VM* vm) {
|
||||
PyObject* mod = vm->new_module("csv");
|
||||
|
||||
vm->bind(mod, "reader(csvfile: list[str]) -> list[list]", [](VM* vm, ArgsView args) {
|
||||
const List& csvfile = CAST(List&, args[0]);
|
||||
List ret;
|
||||
for(int i = 0; i < csvfile.size(); i++) {
|
||||
std::string_view line = CAST(Str&, csvfile[i]).sv();
|
||||
if(i == 0) {
|
||||
// Skip utf8 BOM if there is any.
|
||||
if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3);
|
||||
}
|
||||
List row;
|
||||
int j;
|
||||
bool in_quote = false;
|
||||
std::string buffer;
|
||||
__NEXT_LINE:
|
||||
j = 0;
|
||||
while(j < line.size()) {
|
||||
switch(line[j]) {
|
||||
case '"':
|
||||
if(in_quote) {
|
||||
if(j + 1 < line.size() && line[j + 1] == '"') {
|
||||
buffer += '"';
|
||||
j++;
|
||||
} else {
|
||||
in_quote = false;
|
||||
}
|
||||
} else {
|
||||
in_quote = true;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if(in_quote) {
|
||||
buffer += line[j];
|
||||
} else {
|
||||
row.push_back(VAR(buffer));
|
||||
buffer.clear();
|
||||
}
|
||||
break;
|
||||
case '\r': break; // ignore
|
||||
default: buffer += line[j]; break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if(in_quote) {
|
||||
if(i == csvfile.size() - 1) {
|
||||
vm->ValueError("unterminated quote");
|
||||
} else {
|
||||
buffer += '\n';
|
||||
i++;
|
||||
line = CAST(Str&, csvfile[i]).sv();
|
||||
goto __NEXT_LINE;
|
||||
}
|
||||
}
|
||||
row.push_back(VAR(buffer));
|
||||
ret.push_back(VAR(std::move(row)));
|
||||
}
|
||||
return VAR(std::move(ret));
|
||||
});
|
||||
|
||||
vm->bind(mod, "DictReader(csvfile: list[str]) -> list[dict]", [](VM* vm, ArgsView args) {
|
||||
PyVar csv_reader = vm->_modules["csv"]->attr()["reader"];
|
||||
PyVar ret_obj = vm->call(csv_reader, args[0]);
|
||||
const List& ret = CAST(List&, ret_obj);
|
||||
if(ret.size() == 0) { vm->ValueError("empty csvfile"); }
|
||||
const List& header = CAST(List&, ret[0]);
|
||||
List new_ret;
|
||||
for(int i = 1; i < ret.size(); i++) {
|
||||
const List& row = CAST(List&, ret[i]);
|
||||
if(row.size() != header.size()) { vm->ValueError("row.size() != header.size()"); }
|
||||
Dict row_dict;
|
||||
for(int j = 0; j < header.size(); j++) {
|
||||
row_dict.set(vm, header[j], row[j]);
|
||||
}
|
||||
new_ret.push_back(VAR(std::move(row_dict)));
|
||||
}
|
||||
return VAR(std::move(new_ret));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,120 +0,0 @@
|
||||
#include "pocketpy/modules/dataclasses.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
static void patch__init__(VM* vm, Type cls) {
|
||||
vm->bind(vm->_t(cls), "__init__(self, *args, **kwargs)", [](VM* vm, ArgsView _view) {
|
||||
PyVar self = _view[0];
|
||||
const Tuple& args = CAST(Tuple&, _view[1]);
|
||||
const Dict& kwargs_ = CAST(Dict&, _view[2]);
|
||||
NameDict kwargs;
|
||||
kwargs_.apply([&](PyVar k, PyVar v) {
|
||||
kwargs.set(CAST(Str&, k), v);
|
||||
});
|
||||
|
||||
Type cls = vm->_tp(self);
|
||||
const PyTypeInfo* cls_info = &vm->_all_types[cls];
|
||||
NameDict& cls_d = cls_info->obj->attr();
|
||||
const auto& fields = cls_info->annotated_fields;
|
||||
|
||||
int i = 0; // index into args
|
||||
for(StrName field: fields) {
|
||||
if(kwargs.contains(field)) {
|
||||
self->attr().set(field, kwargs[field]);
|
||||
kwargs.del(field);
|
||||
} else {
|
||||
if(i < args.size()) {
|
||||
self->attr().set(field, args[i]);
|
||||
++i;
|
||||
} else if(cls_d.contains(field)) { // has default value
|
||||
self->attr().set(field, cls_d[field]);
|
||||
} else {
|
||||
vm->TypeError(_S(cls_info->name, " missing required argument ", field.escape()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(args.size() > i) {
|
||||
vm->TypeError(
|
||||
_S(cls_info->name, " takes ", fields.size(), " positional arguments but ", args.size(), " were given"));
|
||||
}
|
||||
if(kwargs.size() > 0) {
|
||||
StrName unexpected_key = kwargs.items()[0].first;
|
||||
vm->TypeError(_S(cls_info->name, " got an unexpected keyword argument ", unexpected_key.escape()));
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
}
|
||||
|
||||
static void patch__repr__(VM* vm, Type cls) {
|
||||
vm->bind__repr__(cls, [](VM* vm, PyVar _0) -> Str {
|
||||
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
||||
const auto& fields = cls_info->annotated_fields;
|
||||
const NameDict& obj_d = _0->attr();
|
||||
SStream ss;
|
||||
ss << cls_info->name << "(";
|
||||
bool first = true;
|
||||
for(StrName field: fields) {
|
||||
if(first)
|
||||
first = false;
|
||||
else
|
||||
ss << ", ";
|
||||
ss << field << "=" << vm->py_repr(obj_d[field]);
|
||||
}
|
||||
ss << ")";
|
||||
return ss.str();
|
||||
});
|
||||
}
|
||||
|
||||
static void patch__eq__(VM* vm, Type cls) {
|
||||
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented;
|
||||
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
||||
const auto& fields = cls_info->annotated_fields;
|
||||
for(StrName field: fields) {
|
||||
PyVar lhs = _0->attr()[field];
|
||||
PyVar rhs = _1->attr()[field];
|
||||
if(vm->py_ne(lhs, rhs)) return vm->False;
|
||||
}
|
||||
return vm->True;
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_dataclasses(VM* vm) {
|
||||
PyObject* mod = vm->new_module("dataclasses");
|
||||
|
||||
vm->bind_func(mod, "dataclass", 1, [](VM* vm, ArgsView args) {
|
||||
vm->check_type(args[0], VM::tp_type);
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
NameDict& cls_d = args[0]->attr();
|
||||
|
||||
if(!cls_d.contains(__init__)) patch__init__(vm, cls);
|
||||
if(!cls_d.contains(__repr__)) patch__repr__(vm, cls);
|
||||
if(!cls_d.contains(__eq__)) patch__eq__(vm, cls);
|
||||
|
||||
const auto& fields = vm->_all_types[cls].annotated_fields;
|
||||
bool has_default = false;
|
||||
for(StrName field: fields) {
|
||||
if(cls_d.contains(field)) {
|
||||
has_default = true;
|
||||
} else {
|
||||
if(has_default) {
|
||||
vm->TypeError(_S("non-default argument ", field.escape(), " follows default argument"));
|
||||
}
|
||||
}
|
||||
}
|
||||
return args[0];
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "asdict", 1, [](VM* vm, ArgsView args) {
|
||||
const auto& fields = vm->_tp_info(args[0])->annotated_fields;
|
||||
const NameDict& obj_d = args[0]->attr();
|
||||
Dict d;
|
||||
for(StrName field: fields) {
|
||||
d.set(vm, VAR(field.sv()), obj_d[field]);
|
||||
}
|
||||
return VAR(std::move(d));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,218 +0,0 @@
|
||||
#include "pocketpy/modules/easing.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace pkpy {
|
||||
// https://easings.net/
|
||||
|
||||
const double kPi = 3.1415926545;
|
||||
|
||||
static double easeLinear(double x) { return x; }
|
||||
|
||||
static double easeInSine(double x) { return 1.0 - std::cos(x * kPi / 2); }
|
||||
|
||||
static double easeOutSine(double x) { return std::sin(x * kPi / 2); }
|
||||
|
||||
static double easeInOutSine(double x) { return -(std::cos(kPi * x) - 1) / 2; }
|
||||
|
||||
static double easeInQuad(double x) { return x * x; }
|
||||
|
||||
static double easeOutQuad(double x) { return 1 - std::pow(1 - x, 2); }
|
||||
|
||||
static double easeInOutQuad(double x) {
|
||||
if(x < 0.5) {
|
||||
return 2 * x * x;
|
||||
} else {
|
||||
return 1 - std::pow(-2 * x + 2, 2) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInCubic(double x) { return x * x * x; }
|
||||
|
||||
static double easeOutCubic(double x) { return 1 - std::pow(1 - x, 3); }
|
||||
|
||||
static double easeInOutCubic(double x) {
|
||||
if(x < 0.5) {
|
||||
return 4 * x * x * x;
|
||||
} else {
|
||||
return 1 - std::pow(-2 * x + 2, 3) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInQuart(double x) { return std::pow(x, 4); }
|
||||
|
||||
static double easeOutQuart(double x) { return 1 - std::pow(1 - x, 4); }
|
||||
|
||||
static double easeInOutQuart(double x) {
|
||||
if(x < 0.5) {
|
||||
return 8 * std::pow(x, 4);
|
||||
} else {
|
||||
return 1 - std::pow(-2 * x + 2, 4) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInQuint(double x) { return std::pow(x, 5); }
|
||||
|
||||
static double easeOutQuint(double x) { return 1 - std::pow(1 - x, 5); }
|
||||
|
||||
static double easeInOutQuint(double x) {
|
||||
if(x < 0.5) {
|
||||
return 16 * std::pow(x, 5);
|
||||
} else {
|
||||
return 1 - std::pow(-2 * x + 2, 5) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInExpo(double x) { return x == 0 ? 0 : std::pow(2, 10 * x - 10); }
|
||||
|
||||
static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - std::pow(2, -10 * x); }
|
||||
|
||||
static double easeInOutExpo(double x) {
|
||||
if(x == 0) {
|
||||
return 0;
|
||||
} else if(x == 1) {
|
||||
return 1;
|
||||
} else if(x < 0.5) {
|
||||
return std::pow(2, 20 * x - 10) / 2;
|
||||
} else {
|
||||
return (2 - std::pow(2, -20 * x + 10)) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInCirc(double x) { return 1 - std::sqrt(1 - std::pow(x, 2)); }
|
||||
|
||||
static double easeOutCirc(double x) { return std::sqrt(1 - std::pow(x - 1, 2)); }
|
||||
|
||||
static double easeInOutCirc(double x) {
|
||||
if(x < 0.5) {
|
||||
return (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2;
|
||||
} else {
|
||||
return (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInBack(double x) {
|
||||
const double c1 = 1.70158;
|
||||
const double c3 = c1 + 1;
|
||||
return c3 * x * x * x - c1 * x * x;
|
||||
}
|
||||
|
||||
static double easeOutBack(double x) {
|
||||
const double c1 = 1.70158;
|
||||
const double c3 = c1 + 1;
|
||||
return 1 + c3 * std::pow(x - 1, 3) + c1 * std::pow(x - 1, 2);
|
||||
}
|
||||
|
||||
static double easeInOutBack(double x) {
|
||||
const double c1 = 1.70158;
|
||||
const double c2 = c1 * 1.525;
|
||||
if(x < 0.5) {
|
||||
return (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2;
|
||||
} else {
|
||||
return (std::pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInElastic(double x) {
|
||||
const double c4 = (2 * kPi) / 3;
|
||||
if(x == 0) {
|
||||
return 0;
|
||||
} else if(x == 1) {
|
||||
return 1;
|
||||
} else {
|
||||
return -std::pow(2, 10 * x - 10) * std::sin((x * 10 - 10.75) * c4);
|
||||
}
|
||||
}
|
||||
|
||||
static double easeOutElastic(double x) {
|
||||
const double c4 = (2 * kPi) / 3;
|
||||
if(x == 0) {
|
||||
return 0;
|
||||
} else if(x == 1) {
|
||||
return 1;
|
||||
} else {
|
||||
return std::pow(2, -10 * x) * std::sin((x * 10 - 0.75) * c4) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInOutElastic(double x) {
|
||||
const double c5 = (2 * kPi) / 4.5;
|
||||
if(x == 0) {
|
||||
return 0;
|
||||
} else if(x == 1) {
|
||||
return 1;
|
||||
} else if(x < 0.5) {
|
||||
return -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2;
|
||||
} else {
|
||||
return (std::pow(2, -20 * x + 10) * std::sin((20 * x - 11.125) * c5)) / 2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeOutBounce(double x) {
|
||||
const double n1 = 7.5625;
|
||||
const double d1 = 2.75;
|
||||
if(x < 1 / d1) {
|
||||
return n1 * x * x;
|
||||
} else if(x < 2 / d1) {
|
||||
x -= 1.5 / d1;
|
||||
return n1 * x * x + 0.75;
|
||||
} else if(x < 2.5 / d1) {
|
||||
x -= 2.25 / d1;
|
||||
return n1 * x * x + 0.9375;
|
||||
} else {
|
||||
x -= 2.625 / d1;
|
||||
return n1 * x * x + 0.984375;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInBounce(double x) { return 1 - easeOutBounce(1 - x); }
|
||||
|
||||
static double easeInOutBounce(double x) {
|
||||
return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
|
||||
}
|
||||
|
||||
void add_module_easing(VM* vm) {
|
||||
PyObject* mod = vm->new_module("easing");
|
||||
|
||||
#define EASE(name) \
|
||||
vm->bind_func(mod, #name, 1, [](VM* vm, ArgsView args) { \
|
||||
f64 t = CAST(f64, args[0]); \
|
||||
return VAR(ease##name(t)); \
|
||||
});
|
||||
|
||||
EASE(Linear)
|
||||
EASE(InSine)
|
||||
EASE(OutSine)
|
||||
EASE(InOutSine)
|
||||
EASE(InQuad)
|
||||
EASE(OutQuad)
|
||||
EASE(InOutQuad)
|
||||
EASE(InCubic)
|
||||
EASE(OutCubic)
|
||||
EASE(InOutCubic)
|
||||
EASE(InQuart)
|
||||
EASE(OutQuart)
|
||||
EASE(InOutQuart)
|
||||
EASE(InQuint)
|
||||
EASE(OutQuint)
|
||||
EASE(InOutQuint)
|
||||
EASE(InExpo)
|
||||
EASE(OutExpo)
|
||||
EASE(InOutExpo)
|
||||
EASE(InCirc)
|
||||
EASE(OutCirc)
|
||||
EASE(InOutCirc)
|
||||
EASE(InBack)
|
||||
EASE(OutBack)
|
||||
EASE(InOutBack)
|
||||
EASE(InElastic)
|
||||
EASE(OutElastic)
|
||||
EASE(InOutElastic)
|
||||
EASE(InBounce)
|
||||
EASE(OutBounce)
|
||||
EASE(InOutBounce)
|
||||
|
||||
#undef EASE
|
||||
}
|
||||
} // namespace pkpy
|
||||
@ -1,247 +0,0 @@
|
||||
#include "pocketpy/modules/io.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
#if PK_ENABLE_OS
|
||||
#include <filesystem>
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
#if PK_ENABLE_OS
|
||||
|
||||
struct FileIO {
|
||||
FILE* fp;
|
||||
bool is_text;
|
||||
|
||||
FileIO(VM* vm, const Str& file, const Str& mode);
|
||||
void close();
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
static FILE* io_fopen(const char* name, const char* mode) {
|
||||
#if _MSC_VER
|
||||
FILE* fp;
|
||||
errno_t err = fopen_s(&fp, name, mode);
|
||||
if(err != 0) return nullptr;
|
||||
return fp;
|
||||
#else
|
||||
return fopen(name, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp) {
|
||||
#if _MSC_VER
|
||||
return fread_s(buffer, std::numeric_limits<size_t>::max(), size, count, fp);
|
||||
#else
|
||||
return fread(buffer, size, count, fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned char* _default_import_handler(const char* name, int* out_size) {
|
||||
bool exists = std::filesystem::exists(std::filesystem::path(name));
|
||||
if(!exists) return nullptr;
|
||||
FILE* fp = io_fopen(name, "rb");
|
||||
if(!fp) return nullptr;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int buffer_size = ftell(fp);
|
||||
unsigned char* buffer = new unsigned char[buffer_size];
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
size_t sz = io_fread(buffer, 1, buffer_size, fp);
|
||||
(void)sz; // suppress warning
|
||||
fclose(fp);
|
||||
*out_size = buffer_size;
|
||||
return buffer;
|
||||
};
|
||||
|
||||
void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
return vm->new_object<FileIO>(cls, vm, py_cast<Str&>(vm, args[1]), py_cast<Str&>(vm, args[2]));
|
||||
});
|
||||
|
||||
vm->bind(type, "read(self, size=-1)", [](VM* vm, ArgsView args) {
|
||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||
i64 size = CAST(i64, args[1]);
|
||||
i64 buffer_size;
|
||||
if(size < 0) {
|
||||
long current = ftell(io.fp);
|
||||
fseek(io.fp, 0, SEEK_END);
|
||||
buffer_size = ftell(io.fp);
|
||||
fseek(io.fp, current, SEEK_SET);
|
||||
} else {
|
||||
buffer_size = size;
|
||||
}
|
||||
unsigned char* buffer = (unsigned char*)std::malloc(buffer_size);
|
||||
i64 actual_size = io_fread(buffer, 1, buffer_size, io.fp);
|
||||
assert(actual_size <= buffer_size);
|
||||
// in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
|
||||
Bytes b(buffer, actual_size);
|
||||
if(io.is_text) { return VAR(std::string_view((char*)b.data(), b.size())); }
|
||||
return VAR(std::move(b));
|
||||
});
|
||||
|
||||
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args) {
|
||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||
if(io.is_text) {
|
||||
Str& s = CAST(Str&, args[1]);
|
||||
fwrite(s.c_str(), 1, s.length(), io.fp);
|
||||
} else {
|
||||
Bytes& buffer = CAST(Bytes&, args[1]);
|
||||
fwrite(buffer.data(), 1, buffer.size(), io.fp);
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) {
|
||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||
long pos = ftell(io.fp);
|
||||
if(pos == -1) vm->IOError(strerror(errno));
|
||||
return VAR(pos);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "seek", 3, [](VM* vm, ArgsView args) {
|
||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||
long offset = CAST(long, args[1]);
|
||||
int whence = CAST(int, args[2]);
|
||||
int ret = fseek(io.fp, offset, whence);
|
||||
if(ret != 0) vm->IOError(strerror(errno));
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "close", 1, [](VM* vm, ArgsView args) {
|
||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||
io.close();
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, __exit__, 1, [](VM* vm, ArgsView args) {
|
||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||
io.close();
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, __enter__, 1, PK_LAMBDA(args[0]));
|
||||
}
|
||||
|
||||
FileIO::FileIO(VM* vm, const Str& file, const Str& mode) {
|
||||
this->is_text = mode.sv().find("b") == std::string::npos;
|
||||
fp = io_fopen(file.c_str(), mode.c_str());
|
||||
if(!fp) vm->IOError(strerror(errno));
|
||||
}
|
||||
|
||||
void FileIO::close() {
|
||||
if(fp == nullptr) return;
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
}
|
||||
|
||||
void add_module_io(VM* vm) {
|
||||
PyObject* mod = vm->new_module("io");
|
||||
vm->register_user_class<FileIO>(mod, "FileIO");
|
||||
|
||||
mod->attr().set("SEEK_SET", VAR(SEEK_SET));
|
||||
mod->attr().set("SEEK_CUR", VAR(SEEK_CUR));
|
||||
mod->attr().set("SEEK_END", VAR(SEEK_END));
|
||||
|
||||
vm->bind(vm->builtins, "open(path, mode='r')", [](VM* vm, ArgsView args) {
|
||||
return vm->call(vm->_modules["io"]->attr("FileIO"), args[0], args[1]);
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_os(VM* vm) {
|
||||
PyObject* mod = vm->new_module("os");
|
||||
PyObject* path_obj = vm->new_object<DummyInstance>(VM::tp_object).get();
|
||||
mod->attr().set("path", path_obj);
|
||||
|
||||
// Working directory is shared by all VMs!!
|
||||
vm->bind_func(mod, "getcwd", 0, [](VM* vm, ArgsView args) {
|
||||
return VAR(std::filesystem::current_path().string());
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "chdir", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
std::filesystem::current_path(path);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "listdir", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
std::filesystem::directory_iterator di;
|
||||
try {
|
||||
di = std::filesystem::directory_iterator(path);
|
||||
} catch(std::filesystem::filesystem_error&) { vm->IOError(path.string()); }
|
||||
List ret;
|
||||
for(auto& p: di)
|
||||
ret.push_back(VAR(p.path().filename().string()));
|
||||
return VAR(std::move(ret));
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool ok = std::filesystem::remove(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool ok = std::filesystem::create_directory(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool ok = std::filesystem::remove(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(path_obj, "join", -1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path;
|
||||
for(int i = 0; i < args.size(); i++) {
|
||||
path /= CAST(Str&, args[i]).sv();
|
||||
}
|
||||
return VAR(path.string());
|
||||
});
|
||||
|
||||
vm->bind_func(path_obj, "exists", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool exists = std::filesystem::exists(path);
|
||||
return VAR(exists);
|
||||
});
|
||||
|
||||
vm->bind_func(path_obj, "basename", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
return VAR(path.filename().string());
|
||||
});
|
||||
|
||||
vm->bind_func(path_obj, "isdir", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool isdir = std::filesystem::is_directory(path);
|
||||
return VAR(isdir);
|
||||
});
|
||||
|
||||
vm->bind_func(path_obj, "isfile", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool isfile = std::filesystem::is_regular_file(path);
|
||||
return VAR(isfile);
|
||||
});
|
||||
|
||||
vm->bind_func(path_obj, "abspath", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
return VAR(std::filesystem::absolute(path).string());
|
||||
});
|
||||
}
|
||||
#else
|
||||
|
||||
void add_module_io(VM* vm) {}
|
||||
|
||||
void add_module_os(VM* vm) {}
|
||||
|
||||
unsigned char* _default_import_handler(const char* name, int* out_size) { return nullptr; }
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,717 +0,0 @@
|
||||
#include "pocketpy/modules/linalg.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
#define BIND_VEC_VEC_OP(D, name, op) \
|
||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
Vec##D other = CAST(Vec##D, _1); \
|
||||
return VAR(self op other); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_FLOAT_OP(D, name, op) \
|
||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
f64 other = CAST(f64, _1); \
|
||||
return VAR(self op other); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_FUNCTION_0(T, name) \
|
||||
vm->bind_func(type, #name, 1, [](VM* vm, ArgsView args) { \
|
||||
T self = _CAST(T, args[0]); \
|
||||
return VAR(self.name()); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_FUNCTION_1(T, name) \
|
||||
vm->bind_func(type, #name, 2, [](VM* vm, ArgsView args) { \
|
||||
T self = _CAST(T, args[0]); \
|
||||
T other = CAST(T, args[1]); \
|
||||
return VAR(self.name(other)); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_MUL_OP(D) \
|
||||
vm->bind__mul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
if(vm->is_user_type<Vec##D>(_1)) { \
|
||||
Vec##D other = _CAST(Vec##D, _1); \
|
||||
return VAR(self * other); \
|
||||
} \
|
||||
f64 other = CAST(f64, _1); \
|
||||
return VAR(self * other); \
|
||||
}); \
|
||||
vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args) { \
|
||||
Vec##D self = _CAST(Vec##D, args[0]); \
|
||||
f64 other = CAST(f64, args[1]); \
|
||||
return VAR(self * other); \
|
||||
}); \
|
||||
vm->bind__truediv__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
f64 other = CAST(f64, _1); \
|
||||
return VAR(self / other); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_GETITEM(D) \
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) { \
|
||||
Vec##D self = _CAST(Vec##D, obj); \
|
||||
i64 i = CAST(i64, index); \
|
||||
if(i < 0 || i >= D) vm->IndexError("index out of range"); \
|
||||
return VAR(self[i]); \
|
||||
});
|
||||
|
||||
#define BIND_SSO_VEC_COMMON(D) \
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
if(!vm->is_user_type<Vec##D>(_1)) return vm->NotImplemented; \
|
||||
Vec##D other = _CAST(Vec##D, _1); \
|
||||
return VAR(self == other); \
|
||||
}); \
|
||||
vm->bind_func(type, "__getnewargs__", 1, [](VM* vm, ArgsView args) { \
|
||||
Vec##D self = _CAST(Vec##D, args[0]); \
|
||||
Tuple t(D); \
|
||||
for(int i = 0; i < D; i++) \
|
||||
t[i] = VAR(self[i]); \
|
||||
return VAR(std::move(t)); \
|
||||
});
|
||||
|
||||
// https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector2.cs#L289
|
||||
static Vec2
|
||||
SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime) {
|
||||
// Based on Game Programming Gems 4 Chapter 1.10
|
||||
smoothTime = (std::max)(0.0001F, smoothTime);
|
||||
float omega = 2.0F / smoothTime;
|
||||
|
||||
float x = omega * deltaTime;
|
||||
float exp = 1.0F / (1.0F + x + 0.48F * x * x + 0.235F * x * x * x);
|
||||
|
||||
float change_x = current.x - target.x;
|
||||
float change_y = current.y - target.y;
|
||||
Vec2 originalTo = target;
|
||||
|
||||
// Clamp maximum speed
|
||||
float maxChange = maxSpeed * smoothTime;
|
||||
|
||||
float maxChangeSq = maxChange * maxChange;
|
||||
float sqDist = change_x * change_x + change_y * change_y;
|
||||
if(sqDist > maxChangeSq) {
|
||||
float mag = std::sqrt(sqDist);
|
||||
change_x = change_x / mag * maxChange;
|
||||
change_y = change_y / mag * maxChange;
|
||||
}
|
||||
|
||||
target.x = current.x - change_x;
|
||||
target.y = current.y - change_y;
|
||||
|
||||
float temp_x = (currentVelocity.x + omega * change_x) * deltaTime;
|
||||
float temp_y = (currentVelocity.y + omega * change_y) * deltaTime;
|
||||
|
||||
currentVelocity.x = (currentVelocity.x - omega * temp_x) * exp;
|
||||
currentVelocity.y = (currentVelocity.y - omega * temp_y) * exp;
|
||||
|
||||
float output_x = target.x + (change_x + temp_x) * exp;
|
||||
float output_y = target.y + (change_y + temp_y) * exp;
|
||||
|
||||
// Prevent overshooting
|
||||
float origMinusCurrent_x = originalTo.x - current.x;
|
||||
float origMinusCurrent_y = originalTo.y - current.y;
|
||||
float outMinusOrig_x = output_x - originalTo.x;
|
||||
float outMinusOrig_y = output_y - originalTo.y;
|
||||
|
||||
if(origMinusCurrent_x * outMinusOrig_x + origMinusCurrent_y * outMinusOrig_y > 0) {
|
||||
output_x = originalTo.x;
|
||||
output_y = originalTo.y;
|
||||
|
||||
currentVelocity.x = (output_x - originalTo.x) / deltaTime;
|
||||
currentVelocity.y = (output_y - originalTo.y) / deltaTime;
|
||||
}
|
||||
return Vec2(output_x, output_y);
|
||||
}
|
||||
|
||||
void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
type->attr().set("ZERO", vm->new_user_object<Vec2>(0, 0));
|
||||
type->attr().set("ONE", vm->new_user_object<Vec2>(1, 1));
|
||||
|
||||
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args) {
|
||||
float x = CAST_F(args[1]);
|
||||
float y = CAST_F(args[2]);
|
||||
return vm->new_object<Vec2>(PK_OBJ_GET(Type, args[0]), x, y);
|
||||
});
|
||||
|
||||
// @staticmethod
|
||||
vm->bind(
|
||||
type,
|
||||
"smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2",
|
||||
[](VM* vm, ArgsView args) {
|
||||
Vec2 current = CAST(Vec2, args[0]);
|
||||
Vec2 target = CAST(Vec2, args[1]);
|
||||
Vec2 current_velocity_ = CAST(Vec2, args[2]);
|
||||
float smooth_time = CAST_F(args[3]);
|
||||
float max_speed = CAST_F(args[4]);
|
||||
float delta_time = CAST_F(args[5]);
|
||||
Vec2 ret = SmoothDamp(current, target, current_velocity_, smooth_time, max_speed, delta_time);
|
||||
return VAR(Tuple(VAR(ret), VAR(current_velocity_)));
|
||||
},
|
||||
{},
|
||||
BindType_STATICMETHOD);
|
||||
|
||||
// @staticmethod
|
||||
vm->bind(
|
||||
type,
|
||||
"angle(__from: vec2, __to: vec2) -> float",
|
||||
[](VM* vm, ArgsView args) {
|
||||
Vec2 __from = CAST(Vec2, args[0]);
|
||||
Vec2 __to = CAST(Vec2, args[1]);
|
||||
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
|
||||
const float PI = 3.1415926535897932384f;
|
||||
if(val > PI) val -= 2 * PI;
|
||||
if(val < -PI) val += 2 * PI;
|
||||
return VAR(val);
|
||||
},
|
||||
{},
|
||||
BindType_STATICMETHOD);
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
Vec2 self = _CAST(Vec2, obj);
|
||||
SStream ss;
|
||||
ss.setprecision(3);
|
||||
ss << "vec2(" << self.x << ", " << self.y << ")";
|
||||
return ss.str();
|
||||
});
|
||||
|
||||
vm->bind_func(type, "rotate", 2, [](VM* vm, ArgsView args) {
|
||||
Vec2 self = _CAST(Vec2, args[0]);
|
||||
float radian = CAST(f64, args[1]);
|
||||
return vm->new_user_object<Vec2>(self.rotate(radian));
|
||||
});
|
||||
|
||||
PY_READONLY_FIELD(Vec2, "x", x)
|
||||
PY_READONLY_FIELD(Vec2, "y", y)
|
||||
|
||||
BIND_VEC_VEC_OP(2, __add__, +)
|
||||
BIND_VEC_VEC_OP(2, __sub__, -)
|
||||
BIND_VEC_MUL_OP(2)
|
||||
BIND_VEC_FLOAT_OP(2, __truediv__, /)
|
||||
BIND_VEC_FUNCTION_1(Vec2, dot)
|
||||
BIND_VEC_FUNCTION_1(Vec2, cross)
|
||||
BIND_VEC_FUNCTION_0(Vec2, length)
|
||||
BIND_VEC_FUNCTION_0(Vec2, length_squared)
|
||||
BIND_VEC_FUNCTION_0(Vec2, normalize)
|
||||
BIND_VEC_GETITEM(2)
|
||||
BIND_SSO_VEC_COMMON(2)
|
||||
}
|
||||
|
||||
void Vec3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
type->attr().set("ZERO", vm->new_user_object<Vec3>(0, 0, 0));
|
||||
type->attr().set("ONE", vm->new_user_object<Vec3>(1, 1, 1));
|
||||
|
||||
vm->bind_func(type, __new__, 4, [](VM* vm, ArgsView args) {
|
||||
float x = CAST_F(args[1]);
|
||||
float y = CAST_F(args[2]);
|
||||
float z = CAST_F(args[3]);
|
||||
return vm->new_object<Vec3>(PK_OBJ_GET(Type, args[0]), x, y, z);
|
||||
});
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
Vec3 self = _CAST(Vec3, obj);
|
||||
SStream ss;
|
||||
ss.setprecision(3);
|
||||
ss << "vec3(" << self.x << ", " << self.y << ", " << self.z << ")";
|
||||
return ss.str();
|
||||
});
|
||||
|
||||
PY_READONLY_FIELD(Vec3, "x", x)
|
||||
PY_READONLY_FIELD(Vec3, "y", y)
|
||||
PY_READONLY_FIELD(Vec3, "z", z)
|
||||
|
||||
BIND_VEC_VEC_OP(3, __add__, +)
|
||||
BIND_VEC_VEC_OP(3, __sub__, -)
|
||||
BIND_VEC_MUL_OP(3)
|
||||
BIND_VEC_FUNCTION_1(Vec3, dot)
|
||||
BIND_VEC_FUNCTION_1(Vec3, cross)
|
||||
BIND_VEC_FUNCTION_0(Vec3, length)
|
||||
BIND_VEC_FUNCTION_0(Vec3, length_squared)
|
||||
BIND_VEC_FUNCTION_0(Vec3, normalize)
|
||||
BIND_VEC_GETITEM(3)
|
||||
BIND_SSO_VEC_COMMON(3)
|
||||
}
|
||||
|
||||
void Vec4::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
PY_STRUCT_LIKE(Vec4)
|
||||
|
||||
type->attr().set("ZERO", vm->new_user_object<Vec4>(0, 0, 0, 0));
|
||||
type->attr().set("ONE", vm->new_user_object<Vec4>(1, 1, 1, 1));
|
||||
|
||||
vm->bind_func(type, __new__, 5, [](VM* vm, ArgsView args) {
|
||||
float x = CAST_F(args[1]);
|
||||
float y = CAST_F(args[2]);
|
||||
float z = CAST_F(args[3]);
|
||||
float w = CAST_F(args[4]);
|
||||
return vm->new_object<Vec4>(PK_OBJ_GET(Type, args[0]), x, y, z, w);
|
||||
});
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
Vec4 self = _CAST(Vec4&, obj);
|
||||
SStream ss;
|
||||
ss.setprecision(3);
|
||||
ss << "vec4(" << self.x << ", " << self.y << ", " << self.z << ", " << self.w << ")";
|
||||
return ss.str();
|
||||
});
|
||||
|
||||
PY_FIELD(Vec4, "x", x)
|
||||
PY_FIELD(Vec4, "y", y)
|
||||
PY_FIELD(Vec4, "z", z)
|
||||
PY_FIELD(Vec4, "w", w)
|
||||
|
||||
BIND_VEC_VEC_OP(4, __add__, +)
|
||||
BIND_VEC_VEC_OP(4, __sub__, -)
|
||||
BIND_VEC_MUL_OP(4)
|
||||
BIND_VEC_FUNCTION_1(Vec4&, dot)
|
||||
BIND_VEC_FUNCTION_1(Vec4&, copy_)
|
||||
BIND_VEC_FUNCTION_0(Vec4&, length)
|
||||
BIND_VEC_FUNCTION_0(Vec4&, length_squared)
|
||||
BIND_VEC_FUNCTION_0(Vec4&, normalize)
|
||||
BIND_VEC_FUNCTION_0(Vec4&, normalize_)
|
||||
BIND_VEC_GETITEM(4)
|
||||
}
|
||||
|
||||
#undef BIND_VEC_VEC_OP
|
||||
#undef BIND_VEC_MUL_OP
|
||||
#undef BIND_VEC_FUNCTION_0
|
||||
#undef BIND_VEC_FUNCTION_1
|
||||
#undef BIND_VEC_GETITEM
|
||||
|
||||
void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
PY_STRUCT_LIKE(Mat3x3)
|
||||
|
||||
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
if(args.size() == 1 + 0) return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
|
||||
if(args.size() == 1 + 1) {
|
||||
const List& list = CAST(List&, args[1]);
|
||||
if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
|
||||
Mat3x3 mat;
|
||||
for(int i = 0; i < 9; i++)
|
||||
mat.v[i] = CAST_F(list[i]);
|
||||
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
||||
}
|
||||
if(args.size() == 1 + 9) {
|
||||
Mat3x3 mat;
|
||||
for(int i = 0; i < 9; i++)
|
||||
mat.v[i] = CAST_F(args[1 + i]);
|
||||
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
||||
}
|
||||
vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size() - 1));
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
const Mat3x3& other = CAST(Mat3x3&, args[1]);
|
||||
self = other;
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
SStream ss;
|
||||
ss.setprecision(3);
|
||||
ss << "mat3x3([" << self._11 << ", " << self._12 << ", " << self._13 << ",\n";
|
||||
ss << " " << self._21 << ", " << self._22 << ", " << self._23 << ",\n";
|
||||
ss << " " << self._31 << ", " << self._32 << ", " << self._33 << "])";
|
||||
return ss.str();
|
||||
});
|
||||
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
Tuple& t = CAST(Tuple&, index);
|
||||
if(t.size() != 2) { vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers"); }
|
||||
i64 i = CAST(i64, t[0]);
|
||||
i64 j = CAST(i64, t[1]);
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
|
||||
return VAR(self.m[i][j]);
|
||||
});
|
||||
|
||||
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index, PyVar value) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
const Tuple& t = CAST(Tuple&, index);
|
||||
if(t.size() != 2) { vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers"); }
|
||||
i64 i = CAST(i64, t[0]);
|
||||
i64 j = CAST(i64, t[1]);
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
|
||||
self.m[i][j] = CAST_F(value);
|
||||
});
|
||||
|
||||
vm->bind_field(type, "_11", &Mat3x3::_11);
|
||||
vm->bind_field(type, "_12", &Mat3x3::_12);
|
||||
vm->bind_field(type, "_13", &Mat3x3::_13);
|
||||
vm->bind_field(type, "_21", &Mat3x3::_21);
|
||||
vm->bind_field(type, "_22", &Mat3x3::_22);
|
||||
vm->bind_field(type, "_23", &Mat3x3::_23);
|
||||
vm->bind_field(type, "_31", &Mat3x3::_31);
|
||||
vm->bind_field(type, "_32", &Mat3x3::_32);
|
||||
vm->bind_field(type, "_33", &Mat3x3::_33);
|
||||
|
||||
vm->bind__add__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
Mat3x3& other = CAST(Mat3x3&, _1);
|
||||
return vm->new_user_object<Mat3x3>(self + other);
|
||||
});
|
||||
|
||||
vm->bind__sub__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
Mat3x3& other = CAST(Mat3x3&, _1);
|
||||
return vm->new_user_object<Mat3x3>(self - other);
|
||||
});
|
||||
|
||||
vm->bind__mul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
f64 other = CAST_F(_1);
|
||||
return vm->new_user_object<Mat3x3>(self * other);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
f64 other = CAST_F(args[1]);
|
||||
return vm->new_user_object<Mat3x3>(self * other);
|
||||
});
|
||||
|
||||
vm->bind__truediv__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
f64 other = CAST_F(_1);
|
||||
return vm->new_user_object<Mat3x3>(self / other);
|
||||
});
|
||||
|
||||
vm->bind__matmul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
if(vm->is_user_type<Mat3x3>(_1)) {
|
||||
const Mat3x3& other = _CAST(Mat3x3&, _1);
|
||||
return vm->new_user_object<Mat3x3>(self.matmul(other));
|
||||
}
|
||||
if(vm->is_user_type<Vec3>(_1)) {
|
||||
const Vec3 other = _CAST(Vec3, _1);
|
||||
return vm->new_user_object<Vec3>(self.matmul(other));
|
||||
}
|
||||
return vm->NotImplemented;
|
||||
});
|
||||
|
||||
vm->bind(type, "matmul(self, other: mat3x3, out: mat3x3 = None)", [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
const Mat3x3& other = CAST(Mat3x3&, args[1]);
|
||||
if(is_none(args[2])) {
|
||||
return vm->new_user_object<Mat3x3>(self.matmul(other));
|
||||
} else {
|
||||
Mat3x3& out = CAST(Mat3x3&, args[2]);
|
||||
out = self.matmul(other);
|
||||
return vm->None;
|
||||
}
|
||||
});
|
||||
|
||||
vm->bind_func(type, "determinant", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return VAR(self.determinant());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "transpose", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return vm->new_user_object<Mat3x3>(self.transpose());
|
||||
});
|
||||
|
||||
vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
Mat3x3 ret;
|
||||
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||
return vm->new_user_object<Mat3x3>(ret);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Mat3x3 ret;
|
||||
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||
return vm->new_user_object<Mat3x3>(ret);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Mat3x3 ret;
|
||||
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||
self = ret;
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "transpose_", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
self = self.transpose();
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func(
|
||||
type,
|
||||
"zeros",
|
||||
0,
|
||||
[](VM* vm, ArgsView args) {
|
||||
return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
|
||||
},
|
||||
{},
|
||||
BindType_STATICMETHOD);
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func(
|
||||
type,
|
||||
"ones",
|
||||
0,
|
||||
[](VM* vm, ArgsView args) {
|
||||
return vm->new_user_object<Mat3x3>(Mat3x3::ones());
|
||||
},
|
||||
{},
|
||||
BindType_STATICMETHOD);
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func(
|
||||
type,
|
||||
"identity",
|
||||
0,
|
||||
[](VM* vm, ArgsView args) {
|
||||
return vm->new_user_object<Mat3x3>(Mat3x3::identity());
|
||||
},
|
||||
{},
|
||||
BindType_STATICMETHOD);
|
||||
|
||||
/*************** affine transformations ***************/
|
||||
// @staticmethod
|
||||
vm->bind(
|
||||
type,
|
||||
"trs(t: vec2, r: float, s: vec2)",
|
||||
[](VM* vm, ArgsView args) {
|
||||
Vec2 t = CAST(Vec2, args[0]);
|
||||
f64 r = CAST_F(args[1]);
|
||||
Vec2 s = CAST(Vec2, args[2]);
|
||||
return vm->new_user_object<Mat3x3>(Mat3x3::trs(t, r, s));
|
||||
},
|
||||
{},
|
||||
BindType_STATICMETHOD);
|
||||
|
||||
vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 t = CAST(Vec2, args[1]);
|
||||
f64 r = CAST_F(args[2]);
|
||||
Vec2 s = CAST(Vec2, args[3]);
|
||||
self = Mat3x3::trs(t, r, s);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(type, "copy_t_(self, t: vec2)", [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 t = CAST(Vec2, args[1]);
|
||||
self = Mat3x3::trs(t, self._r(), self._s());
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(type, "copy_r_(self, r: float)", [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
f64 r = CAST_F(args[1]);
|
||||
self = Mat3x3::trs(self._t(), r, self._s());
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(type, "copy_s_(self, s: vec2)", [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 s = CAST(Vec2, args[1]);
|
||||
self = Mat3x3::trs(self._t(), self._r(), s);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "is_affine", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return VAR(self.is_affine());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "_t", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return vm->new_user_object<Vec2>(self._t());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "_r", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return VAR(self._r());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "_s", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return vm->new_user_object<Vec2>(self._s());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "transform_point", 2, [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
Vec2 res(self._11 * v.x + self._12 * v.y + self._13, self._21 * v.x + self._22 * v.y + self._23);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse_transform_point", 2, [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
Mat3x3 inv;
|
||||
if(!self.inverse(inv)) vm->ValueError("matrix is not invertible");
|
||||
Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "transform_vector", 2, [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
Vec2 res(self._11 * v.x + self._12 * v.y, self._21 * v.x + self._22 * v.y);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse_transform_vector", 2, [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
Mat3x3 inv;
|
||||
if(!self.inverse(inv)) vm->ValueError("matrix is not invertible");
|
||||
Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_linalg(VM* vm) {
|
||||
PyObject* linalg = vm->new_module("linalg");
|
||||
|
||||
vm->register_user_class<Vec2>(linalg, "vec2", VM::tp_object);
|
||||
vm->register_user_class<Vec3>(linalg, "vec3", VM::tp_object);
|
||||
vm->register_user_class<Vec4>(linalg, "vec4", VM::tp_object, true);
|
||||
vm->register_user_class<Mat3x3>(linalg, "mat3x3", VM::tp_object, true);
|
||||
|
||||
PyVar float_p = vm->_modules["c"]->attr("float_p");
|
||||
linalg->attr().set("vec4_p", float_p);
|
||||
linalg->attr().set("mat3x3_p", float_p);
|
||||
}
|
||||
|
||||
/////////////// mat3x3 ///////////////
|
||||
Mat3x3::Mat3x3() {}
|
||||
|
||||
Mat3x3::Mat3x3(float _11, float _12, float _13, float _21, float _22, float _23, float _31, float _32, float _33) :
|
||||
_11(_11), _12(_12), _13(_13), _21(_21), _22(_22), _23(_23), _31(_31), _32(_32), _33(_33) {}
|
||||
|
||||
Mat3x3 Mat3x3::zeros() { return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0); }
|
||||
|
||||
Mat3x3 Mat3x3::ones() { return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1); }
|
||||
|
||||
Mat3x3 Mat3x3::identity() { return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); }
|
||||
|
||||
Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const {
|
||||
Mat3x3 ret;
|
||||
for(int i = 0; i < 9; ++i)
|
||||
ret.v[i] = v[i] + other.v[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::operator- (const Mat3x3& other) const {
|
||||
Mat3x3 ret;
|
||||
for(int i = 0; i < 9; ++i)
|
||||
ret.v[i] = v[i] - other.v[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::operator* (float scalar) const {
|
||||
Mat3x3 ret;
|
||||
for(int i = 0; i < 9; ++i)
|
||||
ret.v[i] = v[i] * scalar;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::operator/ (float scalar) const {
|
||||
Mat3x3 ret;
|
||||
for(int i = 0; i < 9; ++i)
|
||||
ret.v[i] = v[i] / scalar;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Mat3x3::operator== (const Mat3x3& other) const {
|
||||
for(int i = 0; i < 9; ++i) {
|
||||
if(!isclose(v[i], other.v[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mat3x3::operator!= (const Mat3x3& other) const {
|
||||
for(int i = 0; i < 9; ++i) {
|
||||
if(!isclose(v[i], other.v[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::matmul(const Mat3x3& other) const {
|
||||
Mat3x3 out;
|
||||
out._11 = _11 * other._11 + _12 * other._21 + _13 * other._31;
|
||||
out._12 = _11 * other._12 + _12 * other._22 + _13 * other._32;
|
||||
out._13 = _11 * other._13 + _12 * other._23 + _13 * other._33;
|
||||
out._21 = _21 * other._11 + _22 * other._21 + _23 * other._31;
|
||||
out._22 = _21 * other._12 + _22 * other._22 + _23 * other._32;
|
||||
out._23 = _21 * other._13 + _22 * other._23 + _23 * other._33;
|
||||
out._31 = _31 * other._11 + _32 * other._21 + _33 * other._31;
|
||||
out._32 = _31 * other._12 + _32 * other._22 + _33 * other._32;
|
||||
out._33 = _31 * other._13 + _32 * other._23 + _33 * other._33;
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec3 Mat3x3::matmul(const Vec3& other) const {
|
||||
Vec3 out;
|
||||
out.x = _11 * other.x + _12 * other.y + _13 * other.z;
|
||||
out.y = _21 * other.x + _22 * other.y + _23 * other.z;
|
||||
out.z = _31 * other.x + _32 * other.y + _33 * other.z;
|
||||
return out;
|
||||
}
|
||||
|
||||
float Mat3x3::determinant() const {
|
||||
return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32 - _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::transpose() const {
|
||||
Mat3x3 ret;
|
||||
ret._11 = _11;
|
||||
ret._12 = _21;
|
||||
ret._13 = _31;
|
||||
ret._21 = _12;
|
||||
ret._22 = _22;
|
||||
ret._23 = _32;
|
||||
ret._31 = _13;
|
||||
ret._32 = _23;
|
||||
ret._33 = _33;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Mat3x3::inverse(Mat3x3& out) const {
|
||||
float det = determinant();
|
||||
if(isclose(det, 0)) return false;
|
||||
float inv_det = 1.0f / det;
|
||||
out._11 = (_22 * _33 - _23 * _32) * inv_det;
|
||||
out._12 = (_13 * _32 - _12 * _33) * inv_det;
|
||||
out._13 = (_12 * _23 - _13 * _22) * inv_det;
|
||||
out._21 = (_23 * _31 - _21 * _33) * inv_det;
|
||||
out._22 = (_11 * _33 - _13 * _31) * inv_det;
|
||||
out._23 = (_13 * _21 - _11 * _23) * inv_det;
|
||||
out._31 = (_21 * _32 - _22 * _31) * inv_det;
|
||||
out._32 = (_12 * _31 - _11 * _32) * inv_det;
|
||||
out._33 = (_11 * _22 - _12 * _21) * inv_det;
|
||||
return true;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s) {
|
||||
float cr = cosf(radian);
|
||||
float sr = sinf(radian);
|
||||
return Mat3x3(s.x * cr, -s.y * sr, t.x, s.x * sr, s.y * cr, t.y, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
bool Mat3x3::is_affine() const {
|
||||
float det = _11 * _22 - _12 * _21;
|
||||
if(isclose(det, 0)) return false;
|
||||
return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
|
||||
}
|
||||
|
||||
Vec2 Mat3x3::_t() const { return Vec2(_13, _23); }
|
||||
|
||||
float Mat3x3::_r() const { return atan2f(_21, _11); }
|
||||
|
||||
Vec2 Mat3x3::_s() const { return Vec2(sqrtf(_11 * _11 + _21 * _21), sqrtf(_12 * _12 + _22 * _22)); }
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,355 +0,0 @@
|
||||
#include "pocketpy/modules/modules.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
#include "pocketpy/common/export.h"
|
||||
|
||||
#include "pocketpy/common/_generated.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct PyStructTime {
|
||||
int tm_year;
|
||||
int tm_mon;
|
||||
int tm_mday;
|
||||
int tm_hour;
|
||||
int tm_min;
|
||||
int tm_sec;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
|
||||
PyStructTime(std::time_t t) {
|
||||
std::tm* tm = std::localtime(&t);
|
||||
tm_year = tm->tm_year + 1900;
|
||||
tm_mon = tm->tm_mon + 1;
|
||||
tm_mday = tm->tm_mday;
|
||||
tm_hour = tm->tm_hour;
|
||||
tm_min = tm->tm_min;
|
||||
tm_sec = tm->tm_sec;
|
||||
tm_wday = (tm->tm_wday + 6) % 7;
|
||||
tm_yday = tm->tm_yday + 1;
|
||||
tm_isdst = tm->tm_isdst;
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_year", tm_year);
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_mon", tm_mon);
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_mday", tm_mday);
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_hour", tm_hour);
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_min", tm_min);
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_sec", tm_sec);
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_wday", tm_wday);
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_yday", tm_yday);
|
||||
PY_READONLY_FIELD(PyStructTime, "tm_isdst", tm_isdst);
|
||||
}
|
||||
};
|
||||
|
||||
void add_module_time(VM* vm) {
|
||||
PyObject* mod = vm->new_module("time");
|
||||
vm->register_user_class<PyStructTime>(mod, "struct_time");
|
||||
|
||||
vm->bind_func(mod, "time", 0, [](VM* vm, ArgsView args) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
return VAR(std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() / 1000.0);
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "sleep", 1, [](VM* vm, ArgsView args) {
|
||||
f64 seconds = CAST_F(args[0]);
|
||||
auto begin = std::chrono::system_clock::now();
|
||||
while(true) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
|
||||
if(elapsed >= seconds) break;
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "localtime", 0, [](VM* vm, ArgsView args) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
std::time_t t = std::chrono::system_clock::to_time_t(now);
|
||||
return vm->new_user_object<PyStructTime>(t);
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_sys(VM* vm) {
|
||||
PyObject* mod = vm->new_module("sys");
|
||||
vm->setattr(mod, "version", VAR(PK_VERSION));
|
||||
vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM]));
|
||||
|
||||
PyObject* stdout_ = vm->new_object<DummyInstance>(vm->tp_object).get();
|
||||
PyObject* stderr_ = vm->new_object<DummyInstance>(vm->tp_object).get();
|
||||
vm->setattr(mod, "stdout", stdout_);
|
||||
vm->setattr(mod, "stderr", stderr_);
|
||||
|
||||
vm->bind_func(stdout_, "write", 1, [](VM* vm, ArgsView args) {
|
||||
Str& s = CAST(Str&, args[0]);
|
||||
vm->stdout_write(s);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(stderr_, "write", 1, [](VM* vm, ArgsView args) {
|
||||
Str& s = CAST(Str&, args[0]);
|
||||
vm->stderr_write(s);
|
||||
return vm->None;
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_json(VM* vm) {
|
||||
PyObject* mod = vm->new_module("json");
|
||||
vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args) {
|
||||
std::string_view sv;
|
||||
if(is_type(args[0], vm->tp_bytes)) {
|
||||
const Bytes& b = PK_OBJ_GET(Bytes, args[0]);
|
||||
sv = std::string_view((char*)b.data(), b.size());
|
||||
} else {
|
||||
sv = CAST(Str&, args[0]).sv();
|
||||
}
|
||||
CodeObject* code = vm->compile(sv, "<json>", JSON_MODE);
|
||||
PyVar retval = vm->_exec(code, vm->callstack.top()._module);
|
||||
CodeObject__delete(code);
|
||||
return retval;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) {
|
||||
return VAR(vm->py_json(args[0]));
|
||||
});
|
||||
}
|
||||
|
||||
// https://docs.python.org/3.5/library/math.html
|
||||
void add_module_math(VM* vm) {
|
||||
PyObject* mod = vm->new_module("math");
|
||||
mod->attr().set("pi", VAR(3.1415926535897932384));
|
||||
mod->attr().set("e", VAR(2.7182818284590452354));
|
||||
mod->attr().set("inf", VAR(std::numeric_limits<double>::infinity()));
|
||||
mod->attr().set("nan", VAR(std::numeric_limits<double>::quiet_NaN()));
|
||||
|
||||
vm->bind_func(mod, "ceil", 1, PK_LAMBDA(VAR((i64)std::ceil(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "fabs", 1, PK_LAMBDA(VAR(std::fabs(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "floor", 1, PK_LAMBDA(VAR((i64)std::floor(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "fsum", 1, [](VM* vm, ArgsView args) {
|
||||
List& list = CAST(List&, args[0]);
|
||||
double sum = 0;
|
||||
double c = 0;
|
||||
for(PyVar arg: list) {
|
||||
double x = CAST_F(arg);
|
||||
double y = x - c;
|
||||
double t = sum + y;
|
||||
c = (t - sum) - y;
|
||||
sum = t;
|
||||
}
|
||||
return VAR(sum);
|
||||
});
|
||||
vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) {
|
||||
i64 a = CAST(i64, args[0]);
|
||||
i64 b = CAST(i64, args[1]);
|
||||
if(a < 0) a = -a;
|
||||
if(b < 0) b = -b;
|
||||
while(b != 0) {
|
||||
i64 t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return VAR(a);
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "isfinite", 1, PK_LAMBDA(VAR(std::isfinite(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "isinf", 1, PK_LAMBDA(VAR(std::isinf(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "isnan", 1, PK_LAMBDA(VAR(std::isnan(CAST_F(args[0])))));
|
||||
|
||||
vm->bind_func(mod, "isclose", 2, [](VM* vm, ArgsView args) {
|
||||
f64 a = CAST_F(args[0]);
|
||||
f64 b = CAST_F(args[1]);
|
||||
return VAR(std::fabs(a - b) < 1e-9);
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "exp", 1, PK_LAMBDA(VAR(std::exp(CAST_F(args[0])))));
|
||||
|
||||
vm->bind(mod, "log(x, base=2.718281828459045)", [](VM* vm, ArgsView args) {
|
||||
f64 x = CAST_F(args[0]);
|
||||
f64 base = CAST_F(args[1]);
|
||||
return VAR(std::log(x) / std::log(base));
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "log2", 1, PK_LAMBDA(VAR(std::log2(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "log10", 1, PK_LAMBDA(VAR(std::log10(CAST_F(args[0])))));
|
||||
|
||||
vm->bind_func(mod, "pow", 2, PK_LAMBDA(VAR(std::pow(CAST_F(args[0]), CAST_F(args[1])))));
|
||||
vm->bind_func(mod, "sqrt", 1, PK_LAMBDA(VAR(std::sqrt(CAST_F(args[0])))));
|
||||
|
||||
vm->bind_func(mod, "acos", 1, PK_LAMBDA(VAR(std::acos(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "asin", 1, PK_LAMBDA(VAR(std::asin(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "atan", 1, PK_LAMBDA(VAR(std::atan(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "atan2", 2, PK_LAMBDA(VAR(std::atan2(CAST_F(args[0]), CAST_F(args[1])))));
|
||||
|
||||
vm->bind_func(mod, "cos", 1, PK_LAMBDA(VAR(std::cos(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "sin", 1, PK_LAMBDA(VAR(std::sin(CAST_F(args[0])))));
|
||||
vm->bind_func(mod, "tan", 1, PK_LAMBDA(VAR(std::tan(CAST_F(args[0])))));
|
||||
|
||||
vm->bind_func(mod, "degrees", 1, PK_LAMBDA(VAR(CAST_F(args[0]) * 180 / 3.1415926535897932384)));
|
||||
vm->bind_func(mod, "radians", 1, PK_LAMBDA(VAR(CAST_F(args[0]) * 3.1415926535897932384 / 180)));
|
||||
|
||||
vm->bind_func(mod, "modf", 1, [](VM* vm, ArgsView args) {
|
||||
f64 i;
|
||||
f64 f = std::modf(CAST_F(args[0]), &i);
|
||||
return VAR(Tuple(VAR(f), VAR(i)));
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) {
|
||||
i64 n = CAST(i64, args[0]);
|
||||
if(n < 0) vm->ValueError("factorial() not defined for negative values");
|
||||
i64 r = 1;
|
||||
for(i64 i = 2; i <= n; i++)
|
||||
r *= i;
|
||||
return VAR(r);
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_traceback(VM* vm) {
|
||||
PyObject* mod = vm->new_module("traceback");
|
||||
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
|
||||
if(vm->__last_exception == nullptr) vm->ValueError("no exception");
|
||||
Exception& e = vm->__last_exception->as<Exception>();
|
||||
vm->stdout_write(e.summary());
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) {
|
||||
if(vm->__last_exception == nullptr) vm->ValueError("no exception");
|
||||
Exception& e = vm->__last_exception->as<Exception>();
|
||||
return VAR(e.summary());
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_dis(VM* vm) {
|
||||
PyObject* mod = vm->new_module("dis");
|
||||
|
||||
vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) {
|
||||
CodeObject* code;
|
||||
bool need_delete = false;
|
||||
PyVar obj = args[0];
|
||||
if(is_type(obj, vm->tp_str)) {
|
||||
const Str& source = CAST(Str, obj);
|
||||
code = vm->compile(source, "<dis>", EXEC_MODE);
|
||||
need_delete = true;
|
||||
}
|
||||
PyVar f = obj;
|
||||
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func;
|
||||
code = CAST(Function&, f).decl->code;
|
||||
vm->stdout_write(vm->disassemble(code));
|
||||
if(need_delete) CodeObject__delete(code);
|
||||
return vm->None;
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_gc(VM* vm) {
|
||||
PyObject* mod = vm->new_module("gc");
|
||||
vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(pk_ManagedHeap__collect(&vm->heap))));
|
||||
}
|
||||
|
||||
void add_module_enum(VM* vm) {
|
||||
PyObject* mod = vm->new_module("enum");
|
||||
CodeObject* code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
|
||||
vm->_exec(code, mod);
|
||||
CodeObject__delete(code);
|
||||
PyVar Enum = mod->attr("Enum");
|
||||
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) {
|
||||
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
|
||||
NameDict& attr = new_ti->obj->attr();
|
||||
for(auto [k, v]: attr.items()) {
|
||||
// wrap every attribute
|
||||
std::string_view k_sv = k.sv();
|
||||
if(k_sv.empty() || k_sv[0] == '_') continue;
|
||||
attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void add_module___builtins(VM* vm) {
|
||||
PyObject* mod = vm->new_module("__builtins");
|
||||
|
||||
vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args) {
|
||||
return vm->py_next(args[0]);
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) {
|
||||
PyVar self = args[0];
|
||||
if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
|
||||
if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
|
||||
self->_attr = new NameDict();
|
||||
return vm->None;
|
||||
});
|
||||
}
|
||||
|
||||
/************************************************/
|
||||
#if PK_ENABLE_PROFILER
|
||||
struct LineProfilerW;
|
||||
|
||||
struct _LpGuard {
|
||||
PK_ALWAYS_PASS_BY_POINTER(_LpGuard)
|
||||
LineProfilerW* lp;
|
||||
VM* vm;
|
||||
_LpGuard(LineProfilerW* lp, VM* vm);
|
||||
~_LpGuard();
|
||||
};
|
||||
|
||||
// line_profiler wrapper
|
||||
struct LineProfilerW {
|
||||
LineProfiler profiler;
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
return vm->new_object<LineProfilerW>(cls);
|
||||
});
|
||||
|
||||
vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args) {
|
||||
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]);
|
||||
vm->check_type(args[1], VM::tp_function);
|
||||
auto decl = PK_OBJ_GET(Function, args[1]).decl.get();
|
||||
self.profiler.functions.push_back(decl);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(type, "runcall(self, func, *args)", [](VM* vm, ArgsView view) {
|
||||
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, view[0]);
|
||||
PyVar func = view[1];
|
||||
const Tuple& args = CAST(Tuple&, view[2]);
|
||||
vm->s_data.push(func);
|
||||
vm->s_data.push(PY_NULL);
|
||||
for(PyVar arg: args)
|
||||
vm->s_data.push(arg);
|
||||
_LpGuard guard(&self, vm);
|
||||
PyVar ret = vm->vectorcall(args.size());
|
||||
return ret;
|
||||
});
|
||||
|
||||
vm->bind(type, "print_stats(self)", [](VM* vm, ArgsView args) {
|
||||
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]);
|
||||
vm->stdout_write(self.profiler.stats());
|
||||
return vm->None;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) {
|
||||
if(vm->_profiler) { vm->ValueError("only one profiler can be enabled at a time"); }
|
||||
vm->_profiler = &lp->profiler;
|
||||
lp->profiler.begin();
|
||||
}
|
||||
|
||||
_LpGuard::~_LpGuard() {
|
||||
vm->_profiler = nullptr;
|
||||
lp->profiler.end();
|
||||
}
|
||||
|
||||
void add_module_line_profiler(VM* vm) {
|
||||
PyObject* mod = vm->new_module("line_profiler");
|
||||
vm->register_user_class<LineProfilerW>(mod, "LineProfiler");
|
||||
}
|
||||
#else
|
||||
void add_module_line_profiler(VM* vm) { (void)vm; }
|
||||
#endif
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,225 +0,0 @@
|
||||
#include "pocketpy/modules/random.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
/* https://github.com/clibs/mt19937ar
|
||||
|
||||
Copyright (c) 2011 Mutsuo Saito, Makoto Matsumoto, Hiroshima
|
||||
University and The University of Tokyo. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of the Hiroshima University nor the names of
|
||||
its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
struct mt19937 {
|
||||
const static int N = 624;
|
||||
const static int M = 397;
|
||||
const uint32_t MATRIX_A = 0x9908b0dfUL; /* constant vector a */
|
||||
const uint32_t UPPER_MASK = 0x80000000UL; /* most significant w-r bits */
|
||||
const uint32_t LOWER_MASK = 0x7fffffffUL; /* least significant r bits */
|
||||
|
||||
uint32_t mt[N]; /* the array for the state vector */
|
||||
int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
|
||||
|
||||
/* initializes mt[N] with a seed */
|
||||
void seed(uint32_t s) {
|
||||
mt[0] = s & 0xffffffffUL;
|
||||
for(mti = 1; mti < N; mti++) {
|
||||
mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
/* only MSBs of the array mt[]. */
|
||||
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||
mt[mti] &= 0xffffffffUL;
|
||||
/* for >32 bit machines */
|
||||
}
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0xffffffff]-interval */
|
||||
uint32_t next_uint32(void) {
|
||||
uint32_t y;
|
||||
static uint32_t mag01[2] = {0x0UL, MATRIX_A};
|
||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||
|
||||
if(mti >= N) { /* generate N words at one time */
|
||||
int kk;
|
||||
|
||||
if(mti == N + 1) /* if init_genrand() has not been called, */
|
||||
seed(5489UL); /* a default initial seed is used */
|
||||
|
||||
for(kk = 0; kk < N - M; kk++) {
|
||||
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
|
||||
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
for(; kk < N - 1; kk++) {
|
||||
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
|
||||
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
|
||||
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
|
||||
y = mt[mti++];
|
||||
|
||||
/* Tempering */
|
||||
y ^= (y >> 11);
|
||||
y ^= (y << 7) & 0x9d2c5680UL;
|
||||
y ^= (y << 15) & 0xefc60000UL;
|
||||
y ^= (y >> 18);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
uint64_t next_uint64(void) { return (uint64_t(next_uint32()) << 32) | next_uint32(); }
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
float random(void) { return next_uint32() * (1.0 / 4294967296.0); /* divided by 2^32 */ }
|
||||
|
||||
/* generates a random number on [a, b]-interval */
|
||||
int64_t randint(int64_t a, int64_t b) {
|
||||
uint64_t delta = b - a + 1;
|
||||
if(delta < 0x80000000UL) {
|
||||
return a + next_uint32() % (uint32_t)delta;
|
||||
} else {
|
||||
return a + next_uint64() % delta;
|
||||
}
|
||||
}
|
||||
|
||||
float uniform(float a, float b) { return a + random() * (b - a); }
|
||||
};
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct Random {
|
||||
mt19937 gen;
|
||||
|
||||
Random() {
|
||||
auto count = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
gen.seed((uint32_t)count);
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
return vm->new_object<Random>(cls);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "seed", 2, [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
self.gen.seed(CAST(i64, args[1]));
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "randint", 3, [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
i64 a = CAST(i64, args[1]);
|
||||
i64 b = CAST(i64, args[2]);
|
||||
if(a > b) vm->ValueError("randint(a, b): a must be less than or equal to b");
|
||||
return VAR(self.gen.randint(a, b));
|
||||
});
|
||||
|
||||
vm->bind_func(type, "random", 1, [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
return VAR(self.gen.random());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "uniform", 3, [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
f64 a = CAST(f64, args[1]);
|
||||
f64 b = CAST(f64, args[2]);
|
||||
if(a > b) std::swap(a, b);
|
||||
return VAR(self.gen.uniform(a, b));
|
||||
});
|
||||
|
||||
vm->bind_func(type, "shuffle", 2, [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
List& L = CAST(List&, args[1]);
|
||||
for(int i = L.size() - 1; i > 0; i--) {
|
||||
int j = self.gen.randint(0, i);
|
||||
std::swap(L[i], L[j]);
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
ArgsView view = vm->cast_array_view(args[1]);
|
||||
if(view.empty()) vm->IndexError("cannot choose from an empty sequence");
|
||||
int index = self.gen.randint(0, view.size() - 1);
|
||||
return view[index];
|
||||
});
|
||||
|
||||
vm->bind(type, "choices(self, population, weights=None, k=1)", [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
ArgsView view = vm->cast_array_view(args[1]);
|
||||
PyVar* data = view.begin();
|
||||
int size = view.size();
|
||||
if(size == 0) vm->IndexError("cannot choose from an empty sequence");
|
||||
array<f64> cum_weights(size);
|
||||
if(is_none(args[2])) {
|
||||
for(int i = 0; i < size; i++)
|
||||
cum_weights[i] = i + 1;
|
||||
} else {
|
||||
ArgsView weights = vm->cast_array_view(args[2]);
|
||||
if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size));
|
||||
cum_weights[0] = CAST(f64, weights[0]);
|
||||
for(int i = 1; i < size; i++) {
|
||||
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
|
||||
}
|
||||
}
|
||||
if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero");
|
||||
int k = CAST(int, args[3]);
|
||||
List result(k);
|
||||
for(int i = 0; i < k; i++) {
|
||||
f64 key = self.gen.uniform(0.0, cum_weights[size - 1]);
|
||||
int index;
|
||||
c11__lower_bound(f64, cum_weights.begin(), cum_weights.size(), key, c11__less, &index);
|
||||
assert(index != cum_weights.size());
|
||||
result[i] = data[index];
|
||||
}
|
||||
return VAR(std::move(result));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void add_module_random(VM* vm) {
|
||||
PyObject* mod = vm->new_module("random");
|
||||
vm->register_user_class<Random>(mod, "Random");
|
||||
PyVar instance = vm->new_user_object<Random>();
|
||||
mod->attr().set("seed", vm->getattr(instance, "seed"));
|
||||
mod->attr().set("random", vm->getattr(instance, "random"));
|
||||
mod->attr().set("uniform", vm->getattr(instance, "uniform"));
|
||||
mod->attr().set("randint", vm->getattr(instance, "randint"));
|
||||
mod->attr().set("shuffle", vm->getattr(instance, "shuffle"));
|
||||
mod->attr().set("choice", vm->getattr(instance, "choice"));
|
||||
mod->attr().set("choices", vm->getattr(instance, "choices"));
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,8 +1,6 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
struct pkpy_G pkpy_g;
|
||||
|
||||
PyVar pkpy_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0};
|
||||
PyVar pkpy_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0};
|
||||
PyVar pkpy_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0};
|
||||
PyVar PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0};
|
||||
PyVar PY_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0};
|
||||
PyVar PY_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0};
|
||||
|
||||
|
||||
@ -3,6 +3,6 @@
|
||||
#define SMALLMAP_T__SOURCE
|
||||
#define K uint16_t
|
||||
#define V PyVar
|
||||
#define NAME pkpy_NameDict
|
||||
#define NAME pk_NameDict
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__SOURCE
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/interpreter/vm.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
bool py_eq(const PyVar* a, const PyVar* b){
|
||||
auto vm = (pkpy::VM*)pkpy_g.vm;
|
||||
return vm->py_eq(*a, *b);
|
||||
}
|
||||
|
||||
bool py_le(const PyVar* a, const PyVar* b){
|
||||
auto vm = (pkpy::VM*)pkpy_g.vm;
|
||||
return vm->py_le(*a, *b);
|
||||
}
|
||||
|
||||
int64_t py_hash(const PyVar* a){
|
||||
auto vm = (pkpy::VM*)pkpy_g.vm;
|
||||
return vm->py_hash(*a);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
#include "pocketpy/objects/tuplelist.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
Tuple::Tuple(int n) {
|
||||
if(n <= INLINED_SIZE) {
|
||||
this->_args = _inlined;
|
||||
} else {
|
||||
this->_args = (PyVar*)std::malloc(n * sizeof(PyVar));
|
||||
}
|
||||
this->_size = n;
|
||||
}
|
||||
|
||||
Tuple::Tuple(Tuple&& other) noexcept {
|
||||
_size = other._size;
|
||||
if(other.is_inlined()) {
|
||||
_args = _inlined;
|
||||
for(int i = 0; i < _size; i++)
|
||||
_args[i] = other._args[i];
|
||||
} else {
|
||||
_args = other._args;
|
||||
other._args = other._inlined;
|
||||
other._size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Tuple::Tuple(PyVar _0, PyVar _1) : Tuple(2) {
|
||||
_args[0] = _0;
|
||||
_args[1] = _1;
|
||||
}
|
||||
|
||||
Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2) : Tuple(3) {
|
||||
_args[0] = _0;
|
||||
_args[1] = _1;
|
||||
_args[2] = _2;
|
||||
}
|
||||
|
||||
Tuple::~Tuple() {
|
||||
if(!is_inlined()) std::free(_args);
|
||||
}
|
||||
|
||||
List ArgsView::to_list() const {
|
||||
List ret(size());
|
||||
for(int i = 0; i < size(); i++)
|
||||
ret[i] = _begin[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
Tuple ArgsView::to_tuple() const {
|
||||
Tuple ret(size());
|
||||
for(int i = 0; i < size(); i++)
|
||||
ret[i] = _begin[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,9 +1,22 @@
|
||||
#include "pocketpy/objects/public.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
pk_VM* pk_vm;
|
||||
static pk_VM pk_default_vm;
|
||||
|
||||
void py_initialize(){
|
||||
// initialize the global VM
|
||||
Pools_initialize();
|
||||
pk_StrName__initialize();
|
||||
pk_vm = &pk_default_vm;
|
||||
pk_VM__ctor(&pk_default_vm);
|
||||
}
|
||||
|
||||
void py_finalize(){
|
||||
pk_VM__dtor(&pk_default_vm);
|
||||
pk_vm = NULL;
|
||||
pk_StrName__finalize();
|
||||
Pools_finalize();
|
||||
}
|
||||
|
||||
void py_newint(PyVar* self, int64_t val){
|
||||
1767
src/pocketpy.cpp
1767
src/pocketpy.cpp
File diff suppressed because it is too large
Load Diff
@ -1,575 +0,0 @@
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#ifndef PK_NO_EXPORT_C_API
|
||||
|
||||
#include "pocketpy/pocketpy.hpp"
|
||||
#include "pocketpy/pocketpy_c.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
#define PK_ASSERT_N_EXTRA_ELEMENTS(n) \
|
||||
int __ex_count = count_extra_elements(vm, n); \
|
||||
if(__ex_count < n) { \
|
||||
Str msg = _S("expected at least ", n, " elements, got ", __ex_count); \
|
||||
pkpy_error(vm_handle, "StackError", pkpy_string(msg.c_str())); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define PK_ASSERT_NO_ERROR() \
|
||||
if(vm->__c.error != nullptr) return false;
|
||||
|
||||
static int count_extra_elements(VM* vm, int n) {
|
||||
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||
assert(!vm->__c.s_view.empty());
|
||||
return vm->s_data._sp - vm->__c.s_view.back().end();
|
||||
}
|
||||
|
||||
static PyVar stack_item(VM* vm, int index) {
|
||||
PyVar* begin;
|
||||
PyVar* end = vm->s_data.end();
|
||||
if(vm->callstack.empty()) {
|
||||
begin = vm->s_data.begin();
|
||||
} else {
|
||||
assert(!vm->__c.s_view.empty());
|
||||
begin = vm->__c.s_view.back().begin();
|
||||
}
|
||||
int size = end - begin;
|
||||
if(index < 0) index += size;
|
||||
assert(index >= 0 && index < size);
|
||||
return begin[index];
|
||||
}
|
||||
|
||||
#define PK_PROTECTED(__B) \
|
||||
try { \
|
||||
__B \
|
||||
} catch(TopLevelException e) { \
|
||||
vm->__c.error = (PyObject*)e.ptr->self; \
|
||||
return false; \
|
||||
} catch(const std::exception& re) { \
|
||||
PyObject* e_t = vm->_t(vm->tp_exception); \
|
||||
vm->__c.error = vm->call(e_t, VAR(re.what())).get(); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
pkpy_vm* pkpy_new_vm(bool enable_os) { return (pkpy_vm*)new VM(enable_os); }
|
||||
|
||||
void pkpy_delete_vm(pkpy_vm* vm) { return delete (VM*)vm; }
|
||||
|
||||
bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res;
|
||||
PK_PROTECTED(
|
||||
CodeObject* code = vm->compile(source, "main.py", EXEC_MODE);
|
||||
res = vm->_exec(code, vm->_main);
|
||||
CodeObject__delete(code);
|
||||
)
|
||||
return res != nullptr;
|
||||
}
|
||||
|
||||
bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res;
|
||||
PyObject* mod;
|
||||
PK_PROTECTED(
|
||||
if(module == nullptr){ mod = vm->_main;
|
||||
}else{
|
||||
mod = vm->_modules[module].get(); // may raise
|
||||
}
|
||||
CodeObject* code = vm->compile(source, filename, (CompileMode)mode);
|
||||
res = vm->_exec(code, mod);
|
||||
CodeObject__delete(code); // TODO: _exec may raise, so code may leak
|
||||
)
|
||||
return res != nullptr;
|
||||
}
|
||||
|
||||
void pkpy_set_main_argv(pkpy_vm* vm_handle, int argc, char** argv) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
vm->set_main_argv(argc, argv);
|
||||
}
|
||||
|
||||
bool pkpy_dup(pkpy_vm* vm_handle, int n) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, n);
|
||||
vm->s_data.push(item);
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_pop(pkpy_vm* vm_handle, int n) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(n)
|
||||
vm->s_data.shrink(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_pop_top(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
vm->s_data.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_dup_top(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
vm->s_data.push(vm->s_data.top());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_rot_two(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
||||
std::swap(vm->s_data.top(), vm->s_data.second());
|
||||
return true;
|
||||
}
|
||||
|
||||
int pkpy_stack_size(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||
if(vm->__c.s_view.empty()) exit(127);
|
||||
return vm->s_data._sp - vm->__c.s_view.back().begin();
|
||||
}
|
||||
|
||||
// int
|
||||
bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res;
|
||||
PK_PROTECTED(
|
||||
// int may overflow so we should protect it
|
||||
res = py_var(vm, value);
|
||||
)
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_int(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
return is_int(stack_item(vm, i));
|
||||
)
|
||||
}
|
||||
|
||||
bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
*out = py_cast<int>(vm, item);
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
// float
|
||||
bool pkpy_push_float(pkpy_vm* vm_handle, double value) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res = py_var(vm, value);
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_float(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
return is_float(item);
|
||||
)
|
||||
}
|
||||
|
||||
bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
*out = py_cast<double>(vm, item);
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
// bool
|
||||
bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
vm->s_data.push(value ? vm->True : vm->False);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_bool(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
return is_type(item, vm->tp_bool);
|
||||
)
|
||||
}
|
||||
|
||||
bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
*out = py_cast<bool>(vm, item);
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
// string
|
||||
bool pkpy_push_string(pkpy_vm* vm_handle, pkpy_CString value) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res = py_var(vm, value);
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_string(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
return is_type(item, vm->tp_str);
|
||||
)
|
||||
}
|
||||
|
||||
bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
const Str& s = py_cast<Str&>(vm, item);
|
||||
*out = s.c_str();
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
// void_p
|
||||
bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res = py_var(vm, value);
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_voidp(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
return vm->is_user_type<VoidP>(item);
|
||||
)
|
||||
}
|
||||
|
||||
bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
VoidP& vp = py_cast<VoidP&>(vm, item);
|
||||
*out = vp.ptr;
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
// none
|
||||
bool pkpy_push_none(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
vm->s_data.push(vm->None);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_none(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
return is_none(item);
|
||||
)
|
||||
}
|
||||
|
||||
// null
|
||||
bool pkpy_push_null(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
vm->s_data.push(PY_NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct TempViewPopper {
|
||||
VM* vm;
|
||||
bool used;
|
||||
|
||||
TempViewPopper(VM* vm) : vm(vm), used(false) {}
|
||||
|
||||
void restore() noexcept {
|
||||
if(used) return;
|
||||
vm->__c.s_view.pop_back();
|
||||
used = true;
|
||||
}
|
||||
|
||||
~TempViewPopper() { restore(); }
|
||||
};
|
||||
|
||||
// function
|
||||
static PyVar c_function_wrapper(VM* vm, ArgsView args) {
|
||||
pkpy_CFunction f = lambda_get_userdata<pkpy_CFunction>(args.begin());
|
||||
PyVar* curr_sp = vm->s_data._sp;
|
||||
|
||||
vm->__c.s_view.push_back(args);
|
||||
TempViewPopper _tvp(vm);
|
||||
int retc = f((pkpy_vm*)vm); // may raise, _tvp will handle this via RAII
|
||||
_tvp.restore();
|
||||
|
||||
// propagate_if_errored
|
||||
if(vm->__c.error != nullptr) {
|
||||
PyObject* e_obj = vm->__c.error;
|
||||
vm->__c.error = nullptr;
|
||||
vm->_error(e_obj);
|
||||
return nullptr;
|
||||
}
|
||||
assert(retc == vm->s_data._sp - curr_sp);
|
||||
if(retc == 0) return vm->None;
|
||||
if(retc == 1) return vm->s_data.popx();
|
||||
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
||||
return py_var(vm, ret_view.to_tuple());
|
||||
}
|
||||
|
||||
bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar f_obj;
|
||||
PK_PROTECTED(
|
||||
f_obj = vm->bind(nullptr, sig, c_function_wrapper, f);
|
||||
)
|
||||
vm->s_data.push(f_obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
// special push
|
||||
bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyObject* module = vm->new_module(name);
|
||||
vm->s_data.emplace(module);
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
// some opt
|
||||
bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
PyVar o = vm->s_data.top();
|
||||
o = vm->getattr(o, StrName(name), false);
|
||||
if(o == nullptr) return false;
|
||||
vm->s_data.top() = o;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
||||
PyVar a = vm->s_data.top();
|
||||
PyVar val = vm->s_data.second();
|
||||
PK_PROTECTED(
|
||||
vm->setattr(a, StrName(name), val);
|
||||
)
|
||||
vm->s_data.shrink(2);
|
||||
return true;
|
||||
}
|
||||
|
||||
// get global will also get bulitins
|
||||
bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar o = vm->_main->attr().try_get(StrName(name));
|
||||
if(o == nullptr) {
|
||||
o = vm->builtins->attr().try_get(StrName(name));
|
||||
if(o == nullptr) return false;
|
||||
}
|
||||
vm->s_data.push(o);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
vm->_main->attr().set(StrName(name), vm->s_data.popx());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_eval(pkpy_vm* vm_handle, const char* source) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
CodeObject* code = vm->compile(source, "<eval>", EVAL_MODE);
|
||||
PyVar ret = vm->_exec(code, vm->_main);
|
||||
vm->s_data.push(ret);
|
||||
CodeObject__delete(code);
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
auto _lock = vm->gc_scope_lock();
|
||||
PK_PROTECTED(
|
||||
PyVar _0 = vm->py_iter(vm->s_data.popx());
|
||||
for(int i=0; i<n; i++){
|
||||
PyVar _1 = vm->py_next(_0);
|
||||
if(_1 == vm->StopIteration) vm->ValueError("not enough values to unpack");
|
||||
vm->s_data.push(_1);
|
||||
}
|
||||
if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack");
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
PyVar o = vm->s_data.top();
|
||||
PyVar self;
|
||||
PK_PROTECTED(
|
||||
o = vm->get_unbound_method(o, StrName(name), &self);
|
||||
)
|
||||
vm->s_data.pop();
|
||||
vm->s_data.push(o);
|
||||
vm->s_data.push(self);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_py_repr(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
PyVar item = vm->s_data.top();
|
||||
PK_PROTECTED(
|
||||
item = VAR(vm->py_repr(item));
|
||||
)
|
||||
vm->s_data.top() = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_py_str(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
PyVar item = vm->s_data.top();
|
||||
PK_PROTECTED(
|
||||
item = VAR(vm->py_str(item));
|
||||
)
|
||||
vm->s_data.top() = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar module = vm->py_import(name);
|
||||
vm->s_data.push(module);
|
||||
)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Error Handling */
|
||||
bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar e_t = vm->_main->attr().try_get_likely_found(name);
|
||||
if(e_t == nullptr) {
|
||||
e_t = vm->builtins->attr().try_get_likely_found(name);
|
||||
if(e_t == nullptr) {
|
||||
e_t = vm->_t(vm->tp_exception);
|
||||
std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
vm->__c.error = vm->call(e_t, VAR(message)).get();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pkpy_check_error(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
return vm->__c.error != nullptr;
|
||||
}
|
||||
|
||||
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
// no error
|
||||
if(vm->__c.error == nullptr) return false;
|
||||
Exception& e = vm->__c.error->as<Exception>();
|
||||
if(message != nullptr)
|
||||
*message = strdup(e.summary().c_str());
|
||||
else
|
||||
std::cout << e.summary() << std::endl;
|
||||
vm->__c.error = nullptr;
|
||||
if(vm->callstack.empty()) {
|
||||
vm->s_data.clear();
|
||||
} else {
|
||||
if(vm->__c.s_view.empty()) exit(127);
|
||||
vm->s_data.reset(vm->__c.s_view.back().end());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(argc + 2)
|
||||
PyVar res;
|
||||
PK_PROTECTED(
|
||||
res = vm->vectorcall(argc);
|
||||
)
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
void pkpy_free(void* p) { std::free(p); }
|
||||
|
||||
pkpy_CName pkpy_name(const char* name) { return StrName(name).index; }
|
||||
|
||||
pkpy_CString pkpy_name_to_string(pkpy_CName name) { return StrName(name).c_str(); }
|
||||
|
||||
void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
vm->_stdout = handler;
|
||||
}
|
||||
|
||||
void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
vm->_import_handler = handler;
|
||||
}
|
||||
|
||||
void* pkpy_new_repl(pkpy_vm* vm_handle) { return new REPL((VM*)vm_handle); }
|
||||
|
||||
bool pkpy_repl_input(void* r, const char* line) { return ((REPL*)r)->input(line); }
|
||||
|
||||
void pkpy_delete_repl(void* repl) { delete (REPL*)repl; }
|
||||
|
||||
#endif // PK_NO_EXPORT_C_API
|
||||
|
||||
} // namespace pkpy
|
||||
42
src2/main.c
Normal file
42
src2/main.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "pocketpy.h"
|
||||
|
||||
char* read_file(const char* path) {
|
||||
FILE* file = fopen(path, "r");
|
||||
if(file == NULL) {
|
||||
printf("Error: file not found\n");
|
||||
return NULL;
|
||||
}
|
||||
fseek(file, 0, SEEK_END);
|
||||
long size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
char* buffer = malloc(size + 1);
|
||||
fread(buffer, 1, size, file);
|
||||
buffer[size] = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#if _WIN32
|
||||
SetConsoleCP(CP_UTF8);
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
if(argc != 2) goto __HELP;
|
||||
char* source = read_file(argv[1]);
|
||||
py_initialize();
|
||||
|
||||
py_Error* err = py_exec_simple(source);
|
||||
if(err){
|
||||
py_Error__print(err);
|
||||
py_Error__delete(err);
|
||||
}
|
||||
|
||||
py_finalize();
|
||||
free(source);
|
||||
|
||||
__HELP:
|
||||
printf("Usage: pocketpy [filename]\n");
|
||||
return 0;
|
||||
}
|
||||
@ -1,265 +0,0 @@
|
||||
|
||||
#include "pocketpy/pocketpy_c.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable: 4700)
|
||||
#endif
|
||||
|
||||
pkpy_vm* pkpy_new_vm(bool enable_os) {
|
||||
pkpy_vm* returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void pkpy_delete_vm(pkpy_vm* vm) {
|
||||
|
||||
}
|
||||
|
||||
bool pkpy_exec(pkpy_vm* vm, const char* source) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_exec_2(pkpy_vm* vm, const char* source, const char* filename, int mode, const char* module) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void pkpy_set_main_argv(pkpy_vm* vm, int argc, char** argv){
|
||||
|
||||
}
|
||||
|
||||
bool pkpy_dup(pkpy_vm* vm, int i) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_pop(pkpy_vm* vm, int n) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_pop_top(pkpy_vm* vm) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_dup_top(pkpy_vm* vm) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_rot_two(pkpy_vm* vm) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int pkpy_stack_size(pkpy_vm* vm) {
|
||||
int returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_int(pkpy_vm* vm, int val) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_is_int(pkpy_vm* vm, int i) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_to_int(pkpy_vm* vm, int i, int* out) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_float(pkpy_vm* vm, double val) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_is_float(pkpy_vm* vm, int i) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_to_float(pkpy_vm* vm, int i, double* out) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_bool(pkpy_vm* vm, bool val) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_is_bool(pkpy_vm* vm, int i) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_to_bool(pkpy_vm* vm, int i, bool* out) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_string(pkpy_vm* vm, pkpy_CString val) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_is_string(pkpy_vm* vm, int i) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_to_string(pkpy_vm* vm, int i, pkpy_CString* out) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_voidp(pkpy_vm* vm, void* val) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_is_voidp(pkpy_vm* vm, int i) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_to_voidp(pkpy_vm* vm, int i, void** out) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_none(pkpy_vm* vm) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_is_none(pkpy_vm* vm, int i) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_null(pkpy_vm* vm) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_function(pkpy_vm* vm, const char* sig, pkpy_CFunction val) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_push_module(pkpy_vm* vm, const char* name) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_getattr(pkpy_vm* vm, pkpy_CName name) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_setattr(pkpy_vm* vm, pkpy_CName name) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_getglobal(pkpy_vm* vm, pkpy_CName name) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_setglobal(pkpy_vm* vm, pkpy_CName name) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_eval(pkpy_vm* vm, const char* source) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_unpack_sequence(pkpy_vm* vm, int size) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_get_unbound_method(pkpy_vm* vm, pkpy_CName name) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_py_repr(pkpy_vm* vm) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_py_str(pkpy_vm* vm) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_py_import(pkpy_vm* vm, pkpy_CString name) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_error(pkpy_vm* vm, const char* name, pkpy_CString msg) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_check_error(pkpy_vm* vm) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_clear_error(pkpy_vm* vm, char** message) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_vectorcall(pkpy_vm* vm, int argc) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void pkpy_free(void* p) {
|
||||
|
||||
}
|
||||
|
||||
pkpy_CName pkpy_name(const char* s) {
|
||||
pkpy_CName returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
pkpy_CString pkpy_name_to_string(pkpy_CName name) {
|
||||
pkpy_CString returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void pkpy_set_output_handler(pkpy_vm* vm, pkpy_COutputHandler handler) {
|
||||
|
||||
}
|
||||
|
||||
void pkpy_set_import_handler(pkpy_vm* vm, pkpy_CImportHandler handler) {
|
||||
|
||||
}
|
||||
|
||||
void* pkpy_new_repl(pkpy_vm* vm) {
|
||||
void* returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool pkpy_repl_input(void* r, const char* line) {
|
||||
bool returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void pkpy_delete_repl(void* repl) {
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user