mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20: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 <stdio.h>
|
||||
|
||||
//tests the c bindings for pocketpy
|
||||
|
||||
|
||||
void test_binding(pkpy_vm vm) {
|
||||
pkpy_push_int(vm, 12);
|
||||
@ -15,22 +17,24 @@ int main(int argc, char** argv) {
|
||||
pkpy_push_int(vm, 11);
|
||||
pkpy_set_global(vm, "eleven");
|
||||
|
||||
pkpy_push_cfunction(vm, test_binding);
|
||||
pkpy_set_global(vm, "binding");
|
||||
//pkpy_push_cfunction(vm, test_binding);
|
||||
//pkpy_set_global(vm, "binding");
|
||||
|
||||
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_push_null(vm);
|
||||
pkpy_push_int(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);
|
||||
|
||||
pkpy_clear_error(vm, NULL);
|
||||
|
||||
pkpy_vm_destroy(vm);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,71 +1,180 @@
|
||||
#include "pocketpy.h"
|
||||
#include "pocketpy_c.h"
|
||||
|
||||
pkpy_vm pkpy_vm_create(bool use_stdio, bool enable_os) {
|
||||
pkpy::VM* p = new pkpy::VM(use_stdio, enable_os);
|
||||
using namespace pkpy;
|
||||
|
||||
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); \
|
||||
}
|
||||
|
||||
bool pkpy_clear_error(pkpy_vm vm_handle, const char** message) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void pkpy_vm_exec(pkpy_vm vm_handle, const char* source) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
pkpy_vm pkpy_vm_create(bool use_stdio, bool enable_os) {
|
||||
VM* vm = new VM(use_stdio, enable_os);
|
||||
|
||||
vm->exec(source, "main.py", pkpy::EXEC_MODE);
|
||||
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) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
|
||||
VM* vm = (VM*) vm_handle;
|
||||
delete vm;
|
||||
}
|
||||
|
||||
void pkpy_push_cfunction(pkpy_vm vm_handle, pkpy_cfunction f) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
vm->s_data.push(VAR((pkpy::StackFunc) f));
|
||||
bool pkpy_push_function(pkpy_vm vm_handle, pkpy_function f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void pkpy_push_int(pkpy_vm vm_handle, int64_t value) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
vm->s_data.push(VAR(value));
|
||||
bool pkpy_push_int(pkpy_vm vm_handle, int value) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
ERRHANDLER_OPEN
|
||||
|
||||
vm->c_data.push(VAR(value));
|
||||
|
||||
return true;
|
||||
ERRHANDLER_CLOSE
|
||||
}
|
||||
|
||||
void pkpy_push_null(pkpy_vm vm_handle) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
vm->s_data.push(pkpy::PY_NULL);
|
||||
bool pkpy_push_float(pkpy_vm vm_handle, double value) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
|
||||
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) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
vm->s_data.push(VAR(value));
|
||||
ERRHANDLER_OPEN
|
||||
|
||||
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) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
bool pkpy_get_global(pkpy_vm vm_handle, const char* name) {
|
||||
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) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
static void call_wrapper(VM* vm, int argc, bool method_call) {
|
||||
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) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
pkpy::PyObject* o = vm->vectorcall(argc, 0, 0);
|
||||
vm->s_data.push(o);
|
||||
bool pkpy_call(pkpy_vm vm_handle, int argc) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
ERRHANDLER_OPEN
|
||||
call_wrapper(vm, argc, false);
|
||||
|
||||
return true;
|
||||
ERRHANDLER_CLOSE
|
||||
}
|
||||
|
||||
int pkpy_toint(pkpy_vm vm_handle, int index) {
|
||||
pkpy::VM* vm = (pkpy::VM*) vm_handle;
|
||||
bool pkpy_call_method(pkpy_vm vm_handle, int argc) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
ERRHANDLER_OPEN
|
||||
call_wrapper(vm, argc, true);
|
||||
|
||||
pkpy::PyObject* o = vm->s_data.peek(index);
|
||||
return pkpy::py_cast<int>(vm, o);
|
||||
return true;
|
||||
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;
|
||||
|
||||
//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);
|
||||
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);
|
||||
|
||||
////////binding a c function to pocketpy
|
||||
typedef int (*pkpy_cfunction)(pkpy_vm);
|
||||
|
||||
void pkpy_push_cfunction(pkpy_vm, pkpy_cfunction);
|
||||
void pkpy_push_int(pkpy_vm, int64_t);
|
||||
void pkpy_push_float(pkpy_vm, double);
|
||||
void pkpy_push_null(pkpy_vm);
|
||||
typedef int (*pkpy_function)(pkpy_vm);
|
||||
|
||||
void pkpy_set_global(pkpy_vm, const char* name);
|
||||
void pkpy_get_global(pkpy_vm vm_handle, const char* name);
|
||||
bool pkpy_push_function(pkpy_vm, pkpy_function);
|
||||
bool pkpy_push_int(pkpy_vm, int);
|
||||
bool pkpy_push_float(pkpy_vm, double);
|
||||
|
||||
void pkpy_call(pkpy_vm vm_handle, int argc);
|
||||
int pkpy_toint(pkpy_vm vm_handle, int index);
|
||||
bool pkpy_set_global(pkpy_vm, const char* name);
|
||||
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
|
||||
struct CVirtualStack {
|
||||
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** _sp;
|
||||
|
||||
CVirtualStack(): _sp(_begin) {}
|
||||
|
||||
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 pop(){ --_sp; }
|
||||
void shrink(int n){ _sp -= n; }
|
||||
@ -116,18 +115,12 @@ struct CVirtualStack {
|
||||
bool empty() const { return _sp == _begin; }
|
||||
PyObject** begin() { return _begin; }
|
||||
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; }
|
||||
|
||||
ValueStack(const ValueStack&) = delete;
|
||||
ValueStack(ValueStack&&) = delete;
|
||||
ValueStack& operator=(const ValueStack&) = delete;
|
||||
ValueStack& operator=(ValueStack&&) = delete;
|
||||
CVirtualStack(const CVirtualStack&) = delete;
|
||||
CVirtualStack(CVirtualStack&&) = delete;
|
||||
CVirtualStack& operator=(const CVirtualStack&) = delete;
|
||||
CVirtualStack& operator=(CVirtualStack&&) = delete;
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
|
10
src/main.cpp
10
src/main.cpp
@ -6,21 +6,21 @@
|
||||
#ifndef __EMSCRIPTEN__
|
||||
|
||||
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){
|
||||
return VAR(pkpy::getline());
|
||||
});
|
||||
if(argc == 1){
|
||||
pkpy::REPL* repl = pkpy_new_repl(vm);
|
||||
pkpy::REPL* repl = new pkpy::REPL(vm);
|
||||
bool need_more_lines = false;
|
||||
while(true){
|
||||
(*vm->_stdout) << (need_more_lines ? "... " : ">>> ");
|
||||
bool eof = false;
|
||||
std::string line = pkpy::getline(&eof);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ int main(int argc, char** argv){
|
||||
|
||||
pkpy::PyObject* ret = nullptr;
|
||||
ret = vm->exec(src.c_str(), argv_1, pkpy::EXEC_MODE);
|
||||
pkpy_delete(vm);
|
||||
delete vm;
|
||||
return ret != nullptr ? 0 : 1;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user