mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
function calls are working
This commit is contained in:
parent
7882d18df6
commit
aea01c5aca
@ -1,6 +1,8 @@
|
|||||||
#include "pocketpy_c.h"
|
#include "pocketpy_c.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
//tests the c bindings for pocketpy
|
||||||
|
|
||||||
|
|
||||||
void test_binding(pkpy_vm vm) {
|
void test_binding(pkpy_vm vm) {
|
||||||
pkpy_push_int(vm, 12);
|
pkpy_push_int(vm, 12);
|
||||||
@ -15,22 +17,24 @@ int main(int argc, char** argv) {
|
|||||||
pkpy_push_int(vm, 11);
|
pkpy_push_int(vm, 11);
|
||||||
pkpy_set_global(vm, "eleven");
|
pkpy_set_global(vm, "eleven");
|
||||||
|
|
||||||
pkpy_push_cfunction(vm, test_binding);
|
//pkpy_push_cfunction(vm, test_binding);
|
||||||
pkpy_set_global(vm, "binding");
|
//pkpy_set_global(vm, "binding");
|
||||||
|
|
||||||
pkpy_vm_exec(vm, "print(eleven)");
|
pkpy_vm_exec(vm, "print(eleven)");
|
||||||
pkpy_vm_exec(vm, "print(binding())");
|
//pkpy_vm_exec(vm, "print(binding())");
|
||||||
|
|
||||||
pkpy_vm_exec(vm, "x = lambda x : x + 1");
|
pkpy_vm_exec(vm, "def x(x) : return x + 1");
|
||||||
|
|
||||||
pkpy_get_global(vm, "x");
|
pkpy_get_global(vm, "x");
|
||||||
pkpy_push_null(vm);
|
|
||||||
pkpy_push_int(vm, 1);
|
pkpy_push_int(vm, 1);
|
||||||
pkpy_call(vm, 1);
|
pkpy_call(vm, 1);
|
||||||
|
|
||||||
int64_t r = pkpy_toint(vm, 1);
|
int r;
|
||||||
|
pkpy_to_int(vm, -1, &r);
|
||||||
printf("%li\n", r);
|
printf("%li\n", r);
|
||||||
|
|
||||||
|
pkpy_clear_error(vm, NULL);
|
||||||
|
|
||||||
pkpy_vm_destroy(vm);
|
pkpy_vm_destroy(vm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,71 +1,180 @@
|
|||||||
#include "pocketpy.h"
|
#include "pocketpy.h"
|
||||||
#include "pocketpy_c.h"
|
#include "pocketpy_c.h"
|
||||||
|
|
||||||
pkpy_vm pkpy_vm_create(bool use_stdio, bool enable_os) {
|
using namespace pkpy;
|
||||||
pkpy::VM* p = new pkpy::VM(use_stdio, enable_os);
|
|
||||||
|
|
||||||
return (pkpy_vm) p;
|
|
||||||
|
#define ERRHANDLER_OPEN try { \
|
||||||
|
try { \
|
||||||
|
if (vm->c_data.top() == nullptr) \
|
||||||
|
return false; \
|
||||||
|
|
||||||
|
#define ERRHANDLER_CLOSE \
|
||||||
|
} catch( Exception e ) { \
|
||||||
|
vm->c_data.clear(); \
|
||||||
|
vm->c_data.push(VAR(e.summary())); \
|
||||||
|
vm->c_data.push(NULL); \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
} catch(...) { \
|
||||||
|
std::cerr << "ERROR: a non pocketpy exeception was thrown " \
|
||||||
|
<< "this probably means pocketpy itself has a bug!\n"; \
|
||||||
|
exit(2); \
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_vm_exec(pkpy_vm vm_handle, const char* source) {
|
bool pkpy_clear_error(pkpy_vm vm_handle, const char** message) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
|
|
||||||
vm->exec(source, "main.py", pkpy::EXEC_MODE);
|
try {
|
||||||
|
if (vm->c_data.top() != nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vm->c_data.pop();
|
||||||
|
Str wrapped_message = CAST(Str&, vm->c_data.top());
|
||||||
|
if (message != nullptr)
|
||||||
|
*message = wrapped_message.c_str_dup();
|
||||||
|
else
|
||||||
|
std::cerr << "ERROR: " << wrapped_message << "\n";
|
||||||
|
|
||||||
|
vm->c_data.pop();
|
||||||
|
//at this point the stack is clear
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch(...) {
|
||||||
|
std::cerr << "ERROR: a non pocketpy exeception was thrown "
|
||||||
|
<< "this probably means pocketpy itself has a bug!\n";
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pkpy_vm pkpy_vm_create(bool use_stdio, bool enable_os) {
|
||||||
|
VM* vm = new VM(use_stdio, enable_os);
|
||||||
|
|
||||||
|
return (pkpy_vm) vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_vm_exec(pkpy_vm vm_handle, const char* source) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
ERRHANDLER_OPEN
|
||||||
|
|
||||||
|
vm->exec(source, "main.py", EXEC_MODE);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
ERRHANDLER_CLOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_vm_destroy(pkpy_vm vm_handle) {
|
void pkpy_vm_destroy(pkpy_vm vm_handle) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
|
|
||||||
delete vm;
|
delete vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_push_cfunction(pkpy_vm vm_handle, pkpy_cfunction f) {
|
bool pkpy_push_function(pkpy_vm vm_handle, pkpy_function f) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
return true;
|
||||||
vm->s_data.push(VAR((pkpy::StackFunc) f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_push_int(pkpy_vm vm_handle, int64_t value) {
|
bool pkpy_push_int(pkpy_vm vm_handle, int value) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
vm->s_data.push(VAR(value));
|
ERRHANDLER_OPEN
|
||||||
|
|
||||||
|
vm->c_data.push(VAR(value));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
ERRHANDLER_CLOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_push_null(pkpy_vm vm_handle) {
|
bool pkpy_push_float(pkpy_vm vm_handle, double value) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
vm->s_data.push(pkpy::PY_NULL);
|
|
||||||
|
ERRHANDLER_OPEN
|
||||||
|
vm->c_data.push(VAR(value));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
ERRHANDLER_CLOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pkpy_set_global(pkpy_vm vm_handle, const char* name) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
|
||||||
void pkpy_push_float(pkpy_vm vm_handle, double value) {
|
ERRHANDLER_OPEN
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
|
||||||
vm->s_data.push(VAR(value));
|
vm->_main->attr().set(name, vm->c_data.top());
|
||||||
|
|
||||||
|
vm->c_data.pop();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
ERRHANDLER_CLOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_set_global(pkpy_vm vm_handle, const char* name) {
|
bool pkpy_get_global(pkpy_vm vm_handle, const char* name) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
|
|
||||||
vm->_main->attr().set(name, vm->s_data.top());
|
ERRHANDLER_OPEN
|
||||||
|
|
||||||
vm->s_data.pop();
|
PyObject* o = vm->_main->attr().try_get(name);
|
||||||
|
|
||||||
|
vm->c_data.push(o);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
ERRHANDLER_CLOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_get_global(pkpy_vm vm_handle, const char* name) {
|
static void call_wrapper(VM* vm, int argc, bool method_call) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
int callable_index = vm->c_data.size() - argc - 1;
|
||||||
|
|
||||||
pkpy::PyObject* o = vm->_main->attr().try_get(name);
|
PyObject* callable = vm->c_data.get(callable_index);
|
||||||
|
|
||||||
vm->s_data.push(o);
|
vm->s_data.push(callable);
|
||||||
|
if (method_call)
|
||||||
|
vm->s_data.push(vm->c_data.get(callable_index - 1));
|
||||||
|
else
|
||||||
|
vm->s_data.push(PY_NULL);
|
||||||
|
|
||||||
|
for (int i = 0; i < argc; i++)
|
||||||
|
vm->s_data.push(vm->c_data.get(callable_index + i + 1));
|
||||||
|
|
||||||
|
PyObject* o = vm->vectorcall(argc);
|
||||||
|
|
||||||
|
vm->c_data.shrink(argc + 1 + (int) method_call);
|
||||||
|
|
||||||
|
//TODO unpack tuple?
|
||||||
|
vm->c_data.push(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_call(pkpy_vm vm_handle, int argc) {
|
bool pkpy_call(pkpy_vm vm_handle, int argc) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
pkpy::PyObject* o = vm->vectorcall(argc, 0, 0);
|
ERRHANDLER_OPEN
|
||||||
vm->s_data.push(o);
|
call_wrapper(vm, argc, false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
ERRHANDLER_CLOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
int pkpy_toint(pkpy_vm vm_handle, int index) {
|
bool pkpy_call_method(pkpy_vm vm_handle, int argc) {
|
||||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
|
ERRHANDLER_OPEN
|
||||||
|
call_wrapper(vm, argc, true);
|
||||||
|
|
||||||
pkpy::PyObject* o = vm->s_data.peek(index);
|
return true;
|
||||||
return pkpy::py_cast<int>(vm, o);
|
ERRHANDLER_CLOSE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lua_to_cstack_index(int index, int size) {
|
||||||
|
if (index < 0)
|
||||||
|
index = size + index;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pkpy_to_int(pkpy_vm vm_handle, int index, int* ret) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
ERRHANDLER_OPEN
|
||||||
|
|
||||||
|
index = lua_to_cstack_index(index, vm->c_data.size());
|
||||||
|
|
||||||
|
PyObject* o = vm->c_data.get(index);
|
||||||
|
if (ret != nullptr)
|
||||||
|
*ret = py_cast<int>(vm, o);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
ERRHANDLER_CLOSE
|
||||||
|
}
|
||||||
|
@ -10,23 +10,52 @@ extern "C" {
|
|||||||
|
|
||||||
typedef struct pkpy_vm_handle* pkpy_vm;
|
typedef struct pkpy_vm_handle* pkpy_vm;
|
||||||
|
|
||||||
|
//we mostly follow the lua api for these bindings
|
||||||
|
//the key difference being each method returns a bool, true if it succeeded
|
||||||
|
//false if it did not
|
||||||
|
|
||||||
|
//if a method returns false call this next method to check the error and clear it
|
||||||
|
//if this method returns false it means that no error was set, and no action is taken
|
||||||
|
//if it returns true it means there was an error and it was cleared, it will provide a string summary of the error in the message parameter (if it is not NULL)
|
||||||
|
//NOTE : you need to free the message that is passed back after you are done using it
|
||||||
|
//or else pass in null
|
||||||
|
bool pkpy_clear_error(pkpy_vm, const char** message);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pkpy_vm pkpy_vm_create(bool use_stdio, bool enable_os);
|
pkpy_vm pkpy_vm_create(bool use_stdio, bool enable_os);
|
||||||
void pkpy_vm_exec(pkpy_vm vm_handle, const char* source);
|
bool pkpy_vm_exec(pkpy_vm vm_handle, const char* source);
|
||||||
void pkpy_vm_destroy(pkpy_vm vm);
|
void pkpy_vm_destroy(pkpy_vm vm);
|
||||||
|
|
||||||
////////binding a c function to pocketpy
|
|
||||||
typedef int (*pkpy_cfunction)(pkpy_vm);
|
|
||||||
|
|
||||||
void pkpy_push_cfunction(pkpy_vm, pkpy_cfunction);
|
typedef int (*pkpy_function)(pkpy_vm);
|
||||||
void pkpy_push_int(pkpy_vm, int64_t);
|
|
||||||
void pkpy_push_float(pkpy_vm, double);
|
|
||||||
void pkpy_push_null(pkpy_vm);
|
|
||||||
|
|
||||||
void pkpy_set_global(pkpy_vm, const char* name);
|
bool pkpy_push_function(pkpy_vm, pkpy_function);
|
||||||
void pkpy_get_global(pkpy_vm vm_handle, const char* name);
|
bool pkpy_push_int(pkpy_vm, int);
|
||||||
|
bool pkpy_push_float(pkpy_vm, double);
|
||||||
|
|
||||||
void pkpy_call(pkpy_vm vm_handle, int argc);
|
bool pkpy_set_global(pkpy_vm, const char* name);
|
||||||
int pkpy_toint(pkpy_vm vm_handle, int index);
|
bool pkpy_get_global(pkpy_vm vm_handle, const char* name);
|
||||||
|
|
||||||
|
//first push callable you want to call
|
||||||
|
//then push the arguments to send
|
||||||
|
//argc is the number of arguments
|
||||||
|
bool pkpy_call(pkpy_vm vm_handle, int argc);
|
||||||
|
|
||||||
|
//first push the object the method belongs to (self)
|
||||||
|
//then push the callable you want to call
|
||||||
|
//then push the the argments
|
||||||
|
//argc is the number of arguments that was pushed
|
||||||
|
bool pkpy_call_method(pkpy_vm vm_handle, int argc);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//we will break with the lua api here
|
||||||
|
//lua uses 1 as the index to the first pushed element for all of these functions
|
||||||
|
//but we will start counting at zero to match python
|
||||||
|
//we will allow negative numbers to count backwards from the top
|
||||||
|
|
||||||
|
bool pkpy_to_int(pkpy_vm vm_handle, int index, int* ret);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
17
src/frame.h
17
src/frame.h
@ -101,14 +101,13 @@ struct ValueStack {
|
|||||||
//stack for working with c bindings
|
//stack for working with c bindings
|
||||||
struct CVirtualStack {
|
struct CVirtualStack {
|
||||||
static const size_t MAX_SIZE = 256;
|
static const size_t MAX_SIZE = 256;
|
||||||
// We allocate 512 more bytes to keep `_sp` valid when `is_overflow() == true`.
|
|
||||||
PyObject* _begin[MAX_SIZE];
|
PyObject* _begin[MAX_SIZE];
|
||||||
PyObject** _sp;
|
PyObject** _sp;
|
||||||
|
|
||||||
CVirtualStack(): _sp(_begin) {}
|
CVirtualStack(): _sp(_begin) {}
|
||||||
|
|
||||||
PyObject* top() const { return _sp[-1]; }
|
PyObject* top() const { return _sp[-1]; }
|
||||||
PyObject* peek(int n) const { return _sp[-n]; }
|
PyObject* get(int index) const { return _begin[index]; }
|
||||||
void push(PyObject* v){ *_sp++ = v; }
|
void push(PyObject* v){ *_sp++ = v; }
|
||||||
void pop(){ --_sp; }
|
void pop(){ --_sp; }
|
||||||
void shrink(int n){ _sp -= n; }
|
void shrink(int n){ _sp -= n; }
|
||||||
@ -116,18 +115,12 @@ struct CVirtualStack {
|
|||||||
bool empty() const { return _sp == _begin; }
|
bool empty() const { return _sp == _begin; }
|
||||||
PyObject** begin() { return _begin; }
|
PyObject** begin() { return _begin; }
|
||||||
PyObject** end() { return _sp; }
|
PyObject** end() { return _sp; }
|
||||||
void reset(PyObject** sp) {
|
|
||||||
#if DEBUG_EXTRA_CHECK
|
|
||||||
if(sp < _begin || sp > _begin + MAX_SIZE) FATAL_ERROR();
|
|
||||||
#endif
|
|
||||||
_sp = sp;
|
|
||||||
}
|
|
||||||
void clear() { _sp = _begin; }
|
void clear() { _sp = _begin; }
|
||||||
|
|
||||||
ValueStack(const ValueStack&) = delete;
|
CVirtualStack(const CVirtualStack&) = delete;
|
||||||
ValueStack(ValueStack&&) = delete;
|
CVirtualStack(CVirtualStack&&) = delete;
|
||||||
ValueStack& operator=(const ValueStack&) = delete;
|
CVirtualStack& operator=(const CVirtualStack&) = delete;
|
||||||
ValueStack& operator=(ValueStack&&) = delete;
|
CVirtualStack& operator=(CVirtualStack&&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
|
10
src/main.cpp
10
src/main.cpp
@ -6,21 +6,21 @@
|
|||||||
#ifndef __EMSCRIPTEN__
|
#ifndef __EMSCRIPTEN__
|
||||||
|
|
||||||
int main(int argc, char** argv){
|
int main(int argc, char** argv){
|
||||||
pkpy::VM* vm = pkpy_new_vm();
|
pkpy::VM* vm = new pkpy::VM();
|
||||||
vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){
|
vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){
|
||||||
return VAR(pkpy::getline());
|
return VAR(pkpy::getline());
|
||||||
});
|
});
|
||||||
if(argc == 1){
|
if(argc == 1){
|
||||||
pkpy::REPL* repl = pkpy_new_repl(vm);
|
pkpy::REPL* repl = new pkpy::REPL(vm);
|
||||||
bool need_more_lines = false;
|
bool need_more_lines = false;
|
||||||
while(true){
|
while(true){
|
||||||
(*vm->_stdout) << (need_more_lines ? "... " : ">>> ");
|
(*vm->_stdout) << (need_more_lines ? "... " : ">>> ");
|
||||||
bool eof = false;
|
bool eof = false;
|
||||||
std::string line = pkpy::getline(&eof);
|
std::string line = pkpy::getline(&eof);
|
||||||
if(eof) break;
|
if(eof) break;
|
||||||
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
need_more_lines = repl->input(line.c_str());
|
||||||
}
|
}
|
||||||
pkpy_delete(vm);
|
delete vm;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ int main(int argc, char** argv){
|
|||||||
|
|
||||||
pkpy::PyObject* ret = nullptr;
|
pkpy::PyObject* ret = nullptr;
|
||||||
ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE);
|
ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE);
|
||||||
pkpy_delete(vm);
|
delete vm;
|
||||||
return ret != nullptr ? 0 : 1;
|
return ret != nullptr ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user