From bb72c27d2d612e68b288c265f411b7fb3d1dc4d3 Mon Sep 17 00:00:00 2001 From: q66 Date: Fri, 9 Sep 2016 00:41:42 +0200 Subject: [PATCH] simple error handling mechanism (will be used extensively later once it improves) --- include/cubescript/cubescript.hh | 17 +++++++++ src/cs_vm.hh | 8 +++++ src/cubescript.cc | 62 ++++++++++++++++++++++++++++++-- tools/repl.cc | 12 +++---- 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index 4da86bfa..b06a5493 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -316,6 +316,7 @@ enum { }; using CsHookCb = ostd::Function; +using CsPanicCb = ostd::Function; struct OSTD_EXPORT CsState { CsMap idents; @@ -326,6 +327,7 @@ struct OSTD_EXPORT CsState { int identflags = 0; int nodebug = 0; + int protect = 0; CsState(); virtual ~CsState(); @@ -346,6 +348,19 @@ struct OSTD_EXPORT CsState { void init_libs(int libs = CsLibAll); + CsPanicCb set_panic_func(CsPanicCb func); + CsPanicCb const &get_panic_func() const; + CsPanicCb &get_panic_func(); + + template + bool pcall(F func, ostd::String *error) { + return ipcall([](void *data) { + (*static_cast(data))(); + }, error, &func); + } + + void error(CsString msg); + void clear_override(CsIdent &id); void clear_overrides(); @@ -461,8 +476,10 @@ struct OSTD_EXPORT CsState { private: CsIdent *add_ident(CsIdent *id); + bool ipcall(void (*f)(void *data), ostd::String *error, void *data); CsHookCb p_callhook; + CsPanicCb p_panicfunc; CsStream *p_out, *p_err; }; diff --git a/src/cs_vm.hh b/src/cs_vm.hh index 9a1c54fb..aadc52a9 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -82,6 +82,14 @@ enum { CsRetFloat = CsValFloat << CsCodeRet, }; +struct CsErrorException { + CsString errmsg; + CsErrorException() = delete; + CsErrorException(CsErrorException const &) = delete; + CsErrorException(CsErrorException &&v): errmsg(ostd::move(v.errmsg)) {} + CsErrorException(CsString &&v): errmsg(ostd::move(v)) {} +}; + ostd::ConstCharRange cs_debug_line( ostd::ConstCharRange p, ostd::ConstCharRange fmt, ostd::CharRange buf ); diff --git a/src/cubescript.cc b/src/cubescript.cc index 7afd3bc3..9d075c34 100644 --- a/src/cubescript.cc +++ b/src/cubescript.cc @@ -252,11 +252,21 @@ int CsCommand::get_num_args() const { void cs_init_lib_base(CsState &cs); -CsState::CsState(): p_out(&ostd::out), p_err(&ostd::err) { +CsState::CsState(): + p_callhook(), p_panicfunc(), p_out(&ostd::out), p_err(&ostd::err) +{ noalias.id = nullptr; noalias.next = nullptr; noalias.usedargs = (1 << MaxArguments) - 1; noalias.argstack = nullptr; + + /* default panic func */ + p_panicfunc = [this](CsString v) { + get_err().writefln( + "PANIC: unprotected error in call to CubeScript (%s)", v + ); + }; + for (int i = 0; i < MaxArguments; ++i) { char buf[32]; snprintf(buf, sizeof(buf), "arg%d", i + 1); @@ -394,6 +404,49 @@ void *CsState::alloc(void *ptr, ostd::Size, ostd::Size ns) { return new ostd::byte[ns]; } +CsPanicCb CsState::set_panic_func(CsPanicCb func) { + auto hk = ostd::move(p_panicfunc); + p_panicfunc = ostd::move(func); + return hk; +} + +CsPanicCb const &CsState::get_panic_func() const { + return p_panicfunc; +} + +CsPanicCb &CsState::get_panic_func() { + return p_panicfunc; +} + +bool CsState::ipcall(void (*f)(void *data), ostd::String *error, void *data) { + ++protect; + try { + f(data); + } catch (CsErrorException const &v) { + --protect; + if (error) { + *error = ostd::move(v.errmsg); + } + return false; + } catch (...) { + --protect; + throw; + } + --protect; + return true; +} + +void CsState::error(CsString msg) { + if (protect) { + throw CsErrorException(ostd::move(msg)); + } else { + if (p_panicfunc) { + p_panicfunc(ostd::move(msg)); + } + exit(EXIT_FAILURE); + } +} + void CsState::clear_override(CsIdent &id) { if (!(id.get_flags() & CsIdfOverridden)) { return; @@ -1223,8 +1276,11 @@ void cs_init_lib_base(CsState &cs) { cs.new_command("nodebug", "e", [&cs](CsValueRange args, CsValue &res) { ++cs.nodebug; - cs.run(args[0].get_code(), res); - --cs.nodebug; + cs_do_and_cleanup([&]() { + cs.run(args[0].get_code(), res); + }, [&cs]() { + --cs.nodebug; + }); }); cs.new_command("push", "rTe", [&cs](CsValueRange args, CsValue &res) { diff --git a/tools/repl.cc b/tools/repl.cc index 175958ec..1a66dad4 100644 --- a/tools/repl.cc +++ b/tools/repl.cc @@ -182,16 +182,13 @@ void print_version() { ostd::writeln(version); } -struct InterruptedException { -}; - static void do_sigint(int n) { /* in case another SIGINT happens, terminate normally */ signal(n, SIG_DFL); if (gcs) { gcs->set_call_hook([]() { gcs->set_call_hook(nullptr); - throw InterruptedException{}; + gcs->error(""); }); } } @@ -199,7 +196,8 @@ static void do_sigint(int n) { static void do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) { CsValue ret; signal(SIGINT, do_sigint); - try { + ostd::String err; + if (!cs.pcall([&]() { if (file) { if (!cs.run_file(line, ret)) { ostd::err.writeln("cannot read file: ", line); @@ -207,9 +205,9 @@ static void do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) { } else { cs.run(line, ret); } - } catch (InterruptedException) { + }, &err)) { signal(SIGINT, SIG_DFL); - ostd::writeln(""); + ostd::writeln(err); return; } signal(SIGINT, SIG_DFL);