mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
fix error handler
This commit is contained in:
parent
7b326b326f
commit
ea9f7ee97e
@ -1,3 +1,4 @@
|
||||
#include "error.h"
|
||||
#include "pocketpy.h"
|
||||
#include "pocketpy_c.h"
|
||||
|
||||
@ -5,33 +6,17 @@ using namespace pkpy;
|
||||
|
||||
#define PKPY_STACK_SIZE 32
|
||||
|
||||
#define SAFEGUARD_OPEN try { \
|
||||
|
||||
#define SAFEGUARD_CLOSE \
|
||||
} catch(std::exception& e) { \
|
||||
std::cerr << "ERROR: a std::exception " \
|
||||
<< "this probably means pocketpy itself has a bug!\n" \
|
||||
<< e.what() << "\n"; \
|
||||
exit(2); \
|
||||
} catch(...) { \
|
||||
std::cerr << "ERROR: a unknown exception was thrown from " << __func__ \
|
||||
<< "\nthis probably means pocketpy itself has a bug!\n"; \
|
||||
exit(2); \
|
||||
}
|
||||
|
||||
|
||||
#define ERRHANDLER_OPEN SAFEGUARD_OPEN \
|
||||
try { \
|
||||
#define ERRHANDLER_OPEN \
|
||||
if (vm->c_data->size() > 0 && vm->c_data->top() == nullptr) \
|
||||
return false; \
|
||||
try {
|
||||
|
||||
#define ERRHANDLER_CLOSE \
|
||||
} catch( Exception e ) { \
|
||||
} catch(Exception& e ) { \
|
||||
vm->c_data->push(py_var(vm, e)); \
|
||||
vm->c_data->push(NULL); \
|
||||
return false; \
|
||||
} \
|
||||
SAFEGUARD_CLOSE \
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -47,6 +32,23 @@ class CVM : public VM {
|
||||
c_data->clear();
|
||||
delete c_data;
|
||||
}
|
||||
|
||||
struct TempStack{
|
||||
CVM* cvm;
|
||||
ValueStackImpl<PKPY_STACK_SIZE>* prev;
|
||||
TempStack(CVM* cvm, ValueStackImpl<PKPY_STACK_SIZE>* new_data) : cvm(cvm) {
|
||||
prev = cvm->c_data;
|
||||
cvm->c_data = new_data;
|
||||
}
|
||||
|
||||
~TempStack() { restore(); }
|
||||
|
||||
void restore(){
|
||||
if(prev == nullptr) return;
|
||||
cvm->c_data = prev;
|
||||
prev = nullptr;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -76,24 +78,20 @@ static void unpack_return(CVM* vm, PyObject* ret) {
|
||||
|
||||
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
SAFEGUARD_OPEN
|
||||
if (vm->c_data->size() == 0 || vm->c_data->top() != nullptr)
|
||||
return false;
|
||||
|
||||
if (vm->c_data->size() == 0 || vm->c_data->top() != nullptr)
|
||||
return false;
|
||||
vm->c_data->pop();
|
||||
Exception& e = py_cast<Exception&>(vm, vm->c_data->top());
|
||||
if (message != nullptr)
|
||||
*message = e.summary().c_str_dup();
|
||||
else
|
||||
std::cerr << "ERROR: " << e.summary() << "\n";
|
||||
|
||||
vm->c_data->pop();
|
||||
Exception& e = py_cast<Exception&>(vm, vm->c_data->top());
|
||||
if (message != nullptr)
|
||||
*message = e.summary().c_str_dup();
|
||||
else
|
||||
std::cerr << "ERROR: " << e.summary() << "\n";
|
||||
|
||||
vm->c_data->clear();
|
||||
vm->callstack.clear();
|
||||
vm->s_data.clear();
|
||||
return true;
|
||||
|
||||
SAFEGUARD_CLOSE
|
||||
vm->c_data->clear();
|
||||
vm->callstack.clear();
|
||||
vm->s_data.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void gc_marker_ex(CVM* vm) {
|
||||
@ -149,27 +147,6 @@ void pkpy_vm_destroy(pkpy_vm* vm_handle) {
|
||||
delete vm;
|
||||
}
|
||||
|
||||
static void propagate_if_errored(CVM* vm, ValueStackImpl<PKPY_STACK_SIZE>* stored_stack) {
|
||||
try {
|
||||
if (vm->c_data->size() == 0 || vm->c_data->top() != nullptr)
|
||||
return;
|
||||
|
||||
vm->c_data->pop();
|
||||
Exception& e = py_cast<Exception&>(vm, vm->c_data->top());
|
||||
vm->c_data->pop();
|
||||
|
||||
vm->c_data = stored_stack;
|
||||
|
||||
throw e;
|
||||
} catch(Exception& e) {
|
||||
throw;
|
||||
} catch(...) {
|
||||
std::cerr << "ERROR: a non pocketpy exeception was thrown "
|
||||
<< "this probably means pocketpy itself has a bug!\n";
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||
LuaStyleFuncC f;
|
||||
if(args[-1] != PY_NULL){
|
||||
@ -185,13 +162,19 @@ PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||
for (int i = 0; i < args.size(); i++)
|
||||
local_stack.push(args[i]);
|
||||
|
||||
ValueStackImpl<PKPY_STACK_SIZE>* stored_stack = cvm->c_data;
|
||||
cvm->c_data = &local_stack;
|
||||
|
||||
// tmp is controlled by RAII
|
||||
auto tmp = CVM::TempStack(cvm, &local_stack);
|
||||
int retc = f(cvm);
|
||||
|
||||
propagate_if_errored(cvm, stored_stack);
|
||||
cvm->c_data = stored_stack;
|
||||
// propagate_if_errored
|
||||
if (!cvm->c_data->empty() && cvm->c_data->top() == nullptr){
|
||||
cvm->c_data->pop(); // pop nullptr
|
||||
Exception& e = _py_cast<Exception&>(vm, cvm->c_data->popx());
|
||||
tmp.restore();
|
||||
// throw e;
|
||||
vm->_error(e);
|
||||
}
|
||||
tmp.restore();
|
||||
|
||||
PyObject* ret = cvm->None;
|
||||
|
||||
@ -315,7 +298,7 @@ bool pkpy_get_global(pkpy_vm* vm_handle, const char* name) {
|
||||
if (o == nullptr) {
|
||||
o = vm->builtins->attr().try_get(name);
|
||||
if (o == nullptr)
|
||||
throw Exception("NameError", "could not find requested global");
|
||||
throw Exception("NameError", name);
|
||||
}
|
||||
|
||||
vm->c_data->push(o);
|
||||
@ -535,7 +518,6 @@ bool pkpy_is_none(pkpy_vm* vm_handle, int index) {
|
||||
|
||||
bool pkpy_check_global(pkpy_vm* vm_handle, const char* name) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
SAFEGUARD_OPEN
|
||||
PyObject* o = vm->_main->attr().try_get(name);
|
||||
if (o == nullptr) {
|
||||
o = vm->builtins->attr().try_get(name);
|
||||
@ -543,17 +525,13 @@ bool pkpy_check_global(pkpy_vm* vm_handle, const char* name) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
SAFEGUARD_CLOSE
|
||||
}
|
||||
|
||||
bool pkpy_check_error(pkpy_vm* vm_handle) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
SAFEGUARD_OPEN
|
||||
if (vm->c_data->size() > 0 && vm->c_data->top() == nullptr)
|
||||
return true;
|
||||
return false;
|
||||
SAFEGUARD_CLOSE
|
||||
}
|
||||
|
||||
|
||||
@ -582,11 +560,15 @@ bool pkpy_push(pkpy_vm* vm_handle, int index) {
|
||||
}
|
||||
|
||||
|
||||
bool pkpy_error(pkpy_vm* vm_handle, const char* message) {
|
||||
bool pkpy_error(pkpy_vm* vm_handle, const char* name, const char* message) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
ERRHANDLER_OPEN
|
||||
throw Exception("CBindingError", message);
|
||||
ERRHANDLER_CLOSE
|
||||
// already in error state
|
||||
if (vm->c_data->size() > 0 && vm->c_data->top() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
vm->c_data->push(py_var(vm, Exception(name, message)));
|
||||
vm->c_data->push(nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pkpy_getattr(pkpy_vm* vm_handle, const char* name) {
|
||||
|
@ -27,7 +27,7 @@ PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
||||
//when queried
|
||||
//note that at the moment this is more like a panic than throwing an error
|
||||
//the user will not be able to catch it with python code
|
||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* message);
|
||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, const char* message);
|
||||
|
||||
PK_EXPORT pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os);
|
||||
PK_EXPORT bool pkpy_vm_run(pkpy_vm*, const char* source);
|
||||
|
@ -26,7 +26,7 @@ void fail_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
} else {
|
||||
char* message;
|
||||
if (pkpy_clear_error(vm, &message)) {
|
||||
printf("actually errored!\n");
|
||||
printf("actually errored! line %i\n", lineno);
|
||||
free(message);
|
||||
exit(1);
|
||||
}
|
||||
@ -83,14 +83,9 @@ int test_nested_error(pkpy_vm* vm) {
|
||||
|
||||
pkpy_vm* vm;
|
||||
|
||||
void cleanup(void) {
|
||||
pkpy_vm_destroy(vm);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
vm = pkpy_vm_create(true, true);
|
||||
atexit(cleanup);
|
||||
|
||||
//test run
|
||||
check(pkpy_vm_run(vm, "print('hello world!')"));
|
||||
@ -308,16 +303,16 @@ int main(int argc, char** argv) {
|
||||
|
||||
pkpy_vm_run(vm, "test_error_propagate()");
|
||||
check(pkpy_check_error(vm));
|
||||
fprintf(stderr, "testing code going to standard error, can ignore next error\n");
|
||||
// testing code going to standard error, can ignore next error
|
||||
pkpy_clear_error(vm, NULL);
|
||||
|
||||
//with the current way execptions are handled, this will fail and pass the
|
||||
//error clean through, ignoring the python handling
|
||||
//
|
||||
//maybe worth fixing someday, but for now it is functionating as implemented
|
||||
error(pkpy_vm_run(vm, "try : test_error_propagate(); except NameError : pass"));
|
||||
check(pkpy_vm_run(vm, "try : test_error_propagate(); except NameError : pass"));
|
||||
|
||||
error(pkpy_error(vm, "test direct error mechanism"));
|
||||
error(pkpy_error(vm, "_", "test direct error mechanism"));
|
||||
|
||||
|
||||
//more complicated error handling
|
||||
@ -334,10 +329,10 @@ int main(int argc, char** argv) {
|
||||
//at such a time this interferes with a real world use case of the bindings
|
||||
//we can revisit it
|
||||
//
|
||||
//check(pkpy_vm_run(vm, "def error_from_python() : raise NotImplementedError()"));
|
||||
//check(pkpy_push_function(vm, test_nested_error));
|
||||
//check(pkpy_set_global(vm, "test_nested_error"));
|
||||
//fail(pkpy_vm_run(vm, "test_nested_error()"));
|
||||
check(pkpy_vm_run(vm, "def error_from_python() : raise NotImplementedError()"));
|
||||
check(pkpy_push_function(vm, test_nested_error));
|
||||
check(pkpy_set_global(vm, "test_nested_error"));
|
||||
error(pkpy_vm_run(vm, "test_nested_error()"));
|
||||
|
||||
check(pkpy_vm_run(vm, "import math"));
|
||||
check(pkpy_get_global(vm, "math"));
|
||||
@ -356,5 +351,7 @@ int main(int argc, char** argv) {
|
||||
check(pkpy_eval(vm, "math"));
|
||||
check(pkpy_setattr(vm, "pi"));
|
||||
check(pkpy_vm_run(vm, "print(math.pi)"));
|
||||
|
||||
pkpy_vm_destroy(vm);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
hello world!
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
NameError: could not find requested global
|
||||
NameError: nonexistatn
|
||||
|
||||
testing int methods
|
||||
11
|
||||
@ -52,7 +52,9 @@ testing pushing functions
|
||||
12
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
NameError: could not find requested global
|
||||
File "<c-bound>", line 1
|
||||
test_error_propagate()
|
||||
NameError: does not exist
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
File "<c-bound>", line 1
|
||||
@ -60,10 +62,14 @@ Traceback (most recent call last):
|
||||
NameError: testing error throwing from python
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
NameError: could not find requested global
|
||||
_: test direct error mechanism
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
CBindingError: test direct error mechanism
|
||||
File "<c-bound>", line 1
|
||||
test_nested_error()
|
||||
File "<c-bound>", line 1
|
||||
def error_from_python() : raise NotImplementedError()
|
||||
NotImplementedError
|
||||
pi: 3.14
|
||||
pi: 3.14
|
||||
2
|
||||
|
@ -1,10 +1,10 @@
|
||||
python3 preprocess.py
|
||||
|
||||
echo "compiling c++ lib"
|
||||
clang++ -c -o pocketpy_c.o c_bindings/pocketpy_c.cpp -Wfatal-errors --std=c++17 -O2 -Wall -Wno-sign-compare -Wno-unused-variable -fno-rtti -stdlib=libc++ -I src/ -g
|
||||
clang++ -c -o pocketpy_c.o c_bindings/pocketpy_c.cpp -Wfatal-errors -O1 --std=c++17 -Wall -Wno-sign-compare -Wno-unused-variable -fno-rtti -stdlib=libc++ -I src/ -g
|
||||
|
||||
echo "compiling c executable"
|
||||
clang -c -o test.o c_bindings/test.c -Wfatal-errors -O2 -Wall -Wno-sign-compare -Wno-unused-variable -I src/ -g
|
||||
clang -c -o test.o c_bindings/test.c -Wfatal-errors -Wall -O1 -Wno-sign-compare -Wno-unused-variable -I src/ -g
|
||||
echo "linking"
|
||||
clang++ -o c_binding_test test.o pocketpy_c.o -stdlib=libc++ -g
|
||||
./c_binding_test > binding_test_scratch
|
||||
@ -13,6 +13,8 @@ diff -q -s binding_test_scratch c_bindings/test_answers.txt
|
||||
if [ $? -eq 1 ]
|
||||
then
|
||||
echo "ERROR: c binding test failed"
|
||||
rm pocketpy_c.o
|
||||
rm test.o
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user