mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 20:10:17 +00:00
Merge branch 'main' into c_binding_api
This commit is contained in:
commit
6bc1749b5c
1
.gitignore
vendored
1
.gitignore
vendored
@ -24,3 +24,4 @@ src/_generated.h
|
|||||||
profile.sh
|
profile.sh
|
||||||
test
|
test
|
||||||
tmp.rar
|
tmp.rar
|
||||||
|
src/httplib.h
|
||||||
|
@ -9,7 +9,7 @@ pipeline = [
|
|||||||
["common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
|
["common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
|
||||||
["obj.h", "codeobject.h", "frame.h"],
|
["obj.h", "codeobject.h", "frame.h"],
|
||||||
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
|
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
|
||||||
["iter.h", "cffi.h", "io.h", "_generated.h", "pocketpy.h"]
|
["_generated.h", "iter.h", "cffi.h", "requests.h", "io.h", "pocketpy.h"]
|
||||||
]
|
]
|
||||||
|
|
||||||
copied = set()
|
copied = set()
|
||||||
|
@ -74,7 +74,7 @@ class dict:
|
|||||||
def items(self):
|
def items(self):
|
||||||
for kv in self._a:
|
for kv in self._a:
|
||||||
if kv is not None:
|
if kv is not None:
|
||||||
yield kv
|
yield kv[0], kv[1]
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self._a = [None] * self._capacity
|
self._a = [None] * self._capacity
|
||||||
|
40
python/requests.py
Normal file
40
python/requests.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
class Response:
|
||||||
|
def __init__(self, status_code, reason, content):
|
||||||
|
self.status_code = status_code
|
||||||
|
self.reason = reason
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
assert type(self.status_code) is int
|
||||||
|
assert type(self.reason) is str
|
||||||
|
assert type(self.content) is bytes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
return self.content.decode()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
code = self.status_code
|
||||||
|
return f'<Response [{code}]>'
|
||||||
|
|
||||||
|
def _parse_h(headers):
|
||||||
|
if headers is None:
|
||||||
|
return []
|
||||||
|
if type(headers) is dict:
|
||||||
|
return list(headers.items())
|
||||||
|
raise ValueError('headers must be dict or None')
|
||||||
|
|
||||||
|
def get(url, headers=None):
|
||||||
|
headers = _parse_h(headers)
|
||||||
|
return _request('GET', url, headers, None)
|
||||||
|
|
||||||
|
def post(url, data: bytes, headers=None):
|
||||||
|
headers = _parse_h(headers)
|
||||||
|
return _request('POST', url, headers, data)
|
||||||
|
|
||||||
|
def put(url, data: bytes, headers=None):
|
||||||
|
headers = _parse_h(headers)
|
||||||
|
return _request('PUT', url, headers, data)
|
||||||
|
|
||||||
|
def delete(url, headers=None):
|
||||||
|
headers = _parse_h(headers)
|
||||||
|
return _request('DELETE', url, headers, None)
|
13
src/io.h
13
src/io.h
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
inline Bytes _read_file_cwd(const Str& name){
|
inline int _ = set_read_file_cwd([](const Str& name){
|
||||||
std::filesystem::path path(name.sv());
|
std::filesystem::path path(name.sv());
|
||||||
bool exists = std::filesystem::exists(path);
|
bool exists = std::filesystem::exists(path);
|
||||||
if(!exists) return Bytes();
|
if(!exists) return Bytes();
|
||||||
@ -19,7 +19,7 @@ inline Bytes _read_file_cwd(const Str& name){
|
|||||||
std::vector<char> buffer(std::istreambuf_iterator<char>(ifs), {});
|
std::vector<char> buffer(std::istreambuf_iterator<char>(ifs), {});
|
||||||
ifs.close();
|
ifs.close();
|
||||||
return Bytes(std::move(buffer));
|
return Bytes(std::move(buffer));
|
||||||
}
|
});
|
||||||
|
|
||||||
struct FileIO {
|
struct FileIO {
|
||||||
PY_CLASS(FileIO, io, FileIO)
|
PY_CLASS(FileIO, io, FileIO)
|
||||||
@ -182,13 +182,8 @@ inline void add_module_os(VM* vm){
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
inline void add_module_io(VM* vm){}
|
inline void add_module_io(void* vm){}
|
||||||
inline void add_module_os(VM* vm){}
|
inline void add_module_os(void* vm){}
|
||||||
|
|
||||||
inline Bytes _read_file_cwd(const Str& name){
|
|
||||||
return Bytes();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|
||||||
#endif
|
#endif
|
12
src/obj.h
12
src/obj.h
@ -12,19 +12,22 @@ struct Function;
|
|||||||
class VM;
|
class VM;
|
||||||
|
|
||||||
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
||||||
typedef shared_ptr<CodeObject> CodeObject_;
|
typedef int (*LuaStyleFuncC)(VM*);
|
||||||
|
|
||||||
struct NativeFunc {
|
struct NativeFunc {
|
||||||
NativeFuncC f;
|
NativeFuncC f;
|
||||||
int argc; // DONOT include self
|
int argc; // DONOT include self
|
||||||
bool method;
|
bool method;
|
||||||
|
|
||||||
|
// this is designed for lua style C bindings
|
||||||
|
// access it via `CAST(NativeFunc&, args[-2])._lua_f`
|
||||||
|
LuaStyleFuncC _lua_f;
|
||||||
|
|
||||||
NativeFunc(NativeFuncC f, int argc, bool method) : f(f), argc(argc), method(method) {}
|
NativeFunc(NativeFuncC f, int argc, bool method) : f(f), argc(argc), method(method), _lua_f(nullptr) {}
|
||||||
PyObject* operator()(VM* vm, ArgsView args) const;
|
PyObject* operator()(VM* vm, ArgsView args) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef shared_ptr<CodeObject> CodeObject_;
|
||||||
typedef void (*StackFunc)(VM*);
|
|
||||||
|
|
||||||
struct FuncDecl {
|
struct FuncDecl {
|
||||||
struct KwArg {
|
struct KwArg {
|
||||||
@ -79,6 +82,7 @@ struct Bytes{
|
|||||||
|
|
||||||
Bytes() : _data(), _ok(false) {}
|
Bytes() : _data(), _ok(false) {}
|
||||||
Bytes(std::vector<char>&& data) : _data(std::move(data)), _ok(true) {}
|
Bytes(std::vector<char>&& data) : _data(std::move(data)), _ok(true) {}
|
||||||
|
Bytes(const std::string& data) : _data(data.begin(), data.end()), _ok(true) {}
|
||||||
operator bool() const noexcept { return _ok; }
|
operator bool() const noexcept { return _ok; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "repl.h"
|
#include "repl.h"
|
||||||
#include "iter.h"
|
#include "iter.h"
|
||||||
#include "cffi.h"
|
#include "cffi.h"
|
||||||
|
#include "requests.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "_generated.h"
|
#include "_generated.h"
|
||||||
|
|
||||||
@ -920,11 +921,6 @@ inline void VM::post_init(){
|
|||||||
add_module_gc(this);
|
add_module_gc(this);
|
||||||
add_module_random(this);
|
add_module_random(this);
|
||||||
|
|
||||||
if(enable_os){
|
|
||||||
add_module_io(this);
|
|
||||||
add_module_os(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(const char* name: {"this", "functools", "collections", "heapq", "bisect"}){
|
for(const char* name: {"this", "functools", "collections", "heapq", "bisect"}){
|
||||||
_lazy_modules[name] = kPythonLibs[name];
|
_lazy_modules[name] = kPythonLibs[name];
|
||||||
}
|
}
|
||||||
@ -969,6 +965,12 @@ inline void VM::post_init(){
|
|||||||
}
|
}
|
||||||
return VAR(MappingProxy(args[0]));
|
return VAR(MappingProxy(args[0]));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if(enable_os){
|
||||||
|
add_module_io(this);
|
||||||
|
add_module_os(this);
|
||||||
|
add_module_requests(this);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
src/requests.h
Normal file
103
src/requests.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "obj.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "_generated.h"
|
||||||
|
|
||||||
|
#if __has_include("httplib.h")
|
||||||
|
#include "httplib.h"
|
||||||
|
|
||||||
|
namespace pkpy {
|
||||||
|
|
||||||
|
inline void add_module_requests(VM* vm){
|
||||||
|
static StrName m_requests("requests");
|
||||||
|
static StrName m_Response("Response");
|
||||||
|
PyObject* mod = vm->new_module(m_requests);
|
||||||
|
CodeObject_ code = vm->compile(kPythonLibs["requests"], "requests.py", EXEC_MODE);
|
||||||
|
vm->_exec(code, mod);
|
||||||
|
|
||||||
|
vm->bind_func<4>(mod, "_request", [](VM* vm, ArgsView args){
|
||||||
|
Str method = CAST(Str&, args[0]);
|
||||||
|
Str url = CAST(Str&, args[1]);
|
||||||
|
PyObject* headers = args[2]; // a dict object
|
||||||
|
PyObject* body = args[3]; // a bytes object
|
||||||
|
|
||||||
|
if(url.index("http://") != 0){
|
||||||
|
vm->ValueError("url must start with http://");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(char c: url){
|
||||||
|
switch(c){
|
||||||
|
case '.':
|
||||||
|
case '-':
|
||||||
|
case '_':
|
||||||
|
case '~':
|
||||||
|
case ':':
|
||||||
|
case '/':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(!isalnum(c)){
|
||||||
|
vm->ValueError(fmt("invalid character in url: '", c, "'"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int slash = url.index("/", 7);
|
||||||
|
Str path = "/";
|
||||||
|
if(slash != -1){
|
||||||
|
path = url.substr(slash);
|
||||||
|
url = url.substr(0, slash);
|
||||||
|
if(path.empty()) path = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
httplib::Client client(url.str());
|
||||||
|
|
||||||
|
httplib::Headers h;
|
||||||
|
if(headers != vm->None){
|
||||||
|
List list = CAST(List&, headers);
|
||||||
|
for(auto& item : list){
|
||||||
|
Tuple t = CAST(Tuple&, item);
|
||||||
|
Str key = CAST(Str&, t[0]);
|
||||||
|
Str value = CAST(Str&, t[1]);
|
||||||
|
h.emplace(key.str(), value.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto _to_resp = [=](const httplib::Result& res){
|
||||||
|
return vm->call(
|
||||||
|
vm->_modules[m_requests]->attr(m_Response),
|
||||||
|
VAR(res->status),
|
||||||
|
VAR(res->reason),
|
||||||
|
VAR(Bytes(res->body))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if(method == "GET"){
|
||||||
|
httplib::Result res = client.Get(path.str(), h);
|
||||||
|
return _to_resp(res);
|
||||||
|
}else if(method == "POST"){
|
||||||
|
Bytes b = CAST(Bytes&, body);
|
||||||
|
httplib::Result res = client.Post(path.str(), h, b.data(), b.size(), "application/octet-stream");
|
||||||
|
return _to_resp(res);
|
||||||
|
}else if(method == "PUT"){
|
||||||
|
Bytes b = CAST(Bytes&, body);
|
||||||
|
httplib::Result res = client.Put(path.str(), h, b.data(), b.size(), "application/octet-stream");
|
||||||
|
return _to_resp(res);
|
||||||
|
}else if(method == "DELETE"){
|
||||||
|
httplib::Result res = client.Delete(path.str(), h);
|
||||||
|
return _to_resp(res);
|
||||||
|
}else{
|
||||||
|
vm->ValueError("invalid method");
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pkpy
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
inline void add_module_requests(void* vm){ }
|
||||||
|
|
||||||
|
#endif
|
4
src/vm.h
4
src/vm.h
@ -24,7 +24,9 @@ namespace pkpy{
|
|||||||
#define POPX() (s_data.popx())
|
#define POPX() (s_data.popx())
|
||||||
#define STACK_VIEW(n) (s_data.view(n))
|
#define STACK_VIEW(n) (s_data.view(n))
|
||||||
|
|
||||||
Bytes _read_file_cwd(const Str& name);
|
typedef Bytes (*ReadFileCwdFunc)(const Str& name);
|
||||||
|
inline ReadFileCwdFunc _read_file_cwd = [](const Str& name) { return Bytes(); };
|
||||||
|
inline int set_read_file_cwd(ReadFileCwdFunc func) { _read_file_cwd = func; return 0; }
|
||||||
|
|
||||||
#define DEF_NATIVE_2(ctype, ptype) \
|
#define DEF_NATIVE_2(ctype, ptype) \
|
||||||
template<> inline ctype py_cast<ctype>(VM* vm, PyObject* obj) { \
|
template<> inline ctype py_cast<ctype>(VM* vm, PyObject* obj) { \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user