function calls are working

This commit is contained in:
Kolten Pearson 2023-04-30 11:30:45 -06:00
parent 7882d18df6
commit aea01c5aca
7 changed files with 208 additions and 73 deletions

View File

@ -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;
}

View File

@ -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); \
}
void pkpy_vm_exec(pkpy_vm vm_handle, const char* source) {
pkpy::VM* vm = (pkpy::VM*) vm_handle;
bool pkpy_clear_error(pkpy_vm vm_handle, const char** message) {
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) {
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
}

View File

@ -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);

View File

@ -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 {

View File

@ -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;
}