Skip to content

Commit

Permalink
[pjs] Enhanced exception handling
Browse files Browse the repository at this point in the history
  • Loading branch information
pajama-coder committed Jul 3, 2024
1 parent 7c468b5 commit d215d20
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 107 deletions.
8 changes: 6 additions & 2 deletions src/api/http.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ auto Match::exec(const std::string &path) -> pjs::Object* {
auto size = path.length();
if (size > 0 && path.back() == '/') size--;
while (i < m_sections.size() && p < size) {
if (path[p++] != '/') break;
if (path[p] == '/') p++; else break;
auto q = p;
while (q < size) {
auto c = path[q];
Expand All @@ -224,7 +224,11 @@ auto Match::exec(const std::string &path) -> pjs::Object* {
p += n;
i += 1;
}
if (i < m_sections.size() || p < size) {
if (i < m_sections.size() || (
p < size &&
path[p] != '#' &&
path[p] != '?'
)) {
args->retain();
args->release();
return nullptr;
Expand Down
2 changes: 1 addition & 1 deletion src/api/pipy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ template<> void ClassDef<Pipy>::init() {
auto worker = static_cast<Worker*>(ctx.instance());
pjs::Ref<pipy::Context> context = worker->new_context(root);
(*func)(*context, 0, nullptr, ret);
if (!context->ok()) ctx.error(*context);
if (!context->ok()) ctx.error(context->error());
});

method("mount", [](Context &ctx, Object*, Value &ret) {
Expand Down
12 changes: 6 additions & 6 deletions src/pjs/expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,12 +560,12 @@ void FunctionLiteral::resolve(Module *module, Context &ctx, int l, LegacyImports
if (!scope) return;
Stmt::Result res;
m_output->execute(ctx, res);
if (res.is_return()) {
result = res.value;
} else if (res.is_throw()) {
ctx.error(res.value);
} else {
result = Value::undefined;
if (ctx.ok()) {
if (res.is_return()) {
result = res.value;
} else {
result = Value::undefined;
}
}
scope->clear();
}
Expand Down
10 changes: 1 addition & 9 deletions src/pjs/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,7 @@ void Module::execute(Context &ctx, int l, Tree::LegacyImports *imports, Value &r

Stmt::Result res;
m_tree->execute(ctx, res);
if (res.is_throw()) {
auto s = res.value.to_string();
ctx.error(s->str());
ctx.backtrace("(root)");
s->release();
return;
}

result = res.value;
if (ctx.ok()) result = res.value;
}

void Module::check_cyclic_import(Tree::Import *root, Tree::Import *current) {
Expand Down
60 changes: 13 additions & 47 deletions src/pjs/stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ Stmt::~Stmt()
{
}

bool Stmt::execute(Context &ctx, Value &result) {
void Stmt::execute(Context &ctx, Value &result) {
Result res;
execute(ctx, res);
result = res.value;
return !res.is_throw();
}

namespace stmt {
Expand Down Expand Up @@ -142,9 +141,6 @@ void Evaluate::execute(Context &ctx, Result &result) {
auto obj = m_module->exports_object();
obj->type()->set(obj, m_export->id, result.value);
}
} else {
result.value = ctx.error().value;
result.set_throw();
}
}

Expand Down Expand Up @@ -189,9 +185,6 @@ void Var::execute(Context &ctx, Result &result) {
Value val;
if (m_expr->eval(ctx, val) && m_identifier->assign(ctx, val)) {
result.set_done();
} else {
result.value = ctx.error().value;
result.set_throw();
}
}
}
Expand Down Expand Up @@ -265,9 +258,6 @@ void Function::execute(Context &ctx, Result &result) {
Value val;
if (m_expr->eval(ctx, val) && m_identifier->assign(ctx, val)) {
result.set_done();
} else {
result.value = ctx.error().value;
result.set_throw();
}
}
}
Expand Down Expand Up @@ -312,11 +302,7 @@ void If::resolve(Module *module, Context &ctx, int l, Tree::LegacyImports *impor

void If::execute(Context &ctx, Result &result) {
Value val;
if (!m_cond->eval(ctx, val)) {
result.value = ctx.error().value;
result.set_throw();
return;
}
if (!m_cond->eval(ctx, val)) return;

if (val.to_boolean()) {
m_then->execute(ctx, result);
Expand Down Expand Up @@ -361,22 +347,14 @@ void Switch::resolve(Module *module, Context &ctx, int l, Tree::LegacyImports *i

void Switch::execute(Context &ctx, Result &result) {
Value cond_val;
if (!m_cond->eval(ctx, cond_val)) {
result.value = ctx.error().value;
result.set_throw();
return;
}
if (!m_cond->eval(ctx, cond_val)) return;

auto def = m_cases.end();
auto p = m_cases.begin();
while (p != m_cases.end()) {
if (auto e = p->first.get()) {
Value val;
if (!e->eval(ctx, val)) {
result.value = ctx.error().value;
result.set_throw();
return;
}
if (!e->eval(ctx, val)) return;
if (Value::is_equal(cond_val, val)) break;
} else {
def = p;
Expand Down Expand Up @@ -468,9 +446,6 @@ void Return::execute(Context &ctx, Result &result) {
if (m_expr) {
if (m_expr->eval(ctx, result.value)) {
result.set_return();
} else {
result.value = ctx.error().value;
result.set_throw();
}
} else {
result.value = Value::undefined;
Expand Down Expand Up @@ -499,15 +474,11 @@ void Throw::resolve(Module *module, Context &ctx, int l, Tree::LegacyImports *im
void Throw::execute(Context &ctx, Result &result) {
if (m_expr) {
if (m_expr->eval(ctx, result.value)) {
ctx.error(result.value);
ctx.backtrace(source(), line(), column());
result.set_throw();
} else {
result.value = ctx.error().value;
result.set_throw();
}
} else {
result.value = Value::undefined;
result.set_throw();
ctx.error(Value::undefined);
}
}

Expand Down Expand Up @@ -561,25 +532,20 @@ void Try::resolve(Module *module, Context &ctx, int l, Tree::LegacyImports *impo

void Try::execute(Context &ctx, Result &result) {
m_try->execute(ctx, result);
if (result.is_throw() && m_catch) {
if (result.value.is<pjs::Error>()) {
result.value.as<pjs::Error>()->backtrace(ctx.error().backtrace);
}
if (!ctx.ok() && m_catch) {
auto exception = ctx.error().to_exception();
ctx.reset();
Context cctx(ctx, 1, &result.value, ctx.scope());
Context cctx(ctx, 1, &exception, ctx.scope());
if (auto scope = m_catch_scope.instantiate(cctx)) {
m_catch->execute(cctx, result);
scope->clear();
} else {
result.value = ctx.error().value;
result.set_throw();
}
}
if (m_finally) {
if (result.is_throw()) {
Result res;
m_finally->execute(ctx, res);
if (res.is_throw()) result.value = res.value;
if (!ctx.ok()) {
ctx.reset();
m_finally->execute(ctx, result);
ctx.error(true);
} else {
m_finally->execute(ctx, result);
}
Expand Down
6 changes: 2 additions & 4 deletions src/pjs/stmt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Stmt : public Tree {
//

struct Result {
enum Type { DONE, RETURN, BREAK, CONTINUE, THROW };
enum Type { DONE, RETURN, BREAK, CONTINUE };
Type type = DONE;
Str* label = nullptr;
Value value;
Expand All @@ -54,13 +54,11 @@ class Stmt : public Tree {
bool is_return() const { return type == RETURN; }
bool is_break() const { return type == BREAK; }
bool is_continue() const { return type == CONTINUE; }
bool is_throw() const { return type == THROW; }

void set_done() { type = DONE; label = nullptr; }
void set_return() { type = RETURN; label = nullptr; }
void set_break(Str *l = nullptr) { type = BREAK; label = l; }
void set_continue(Str *l = nullptr) { type = CONTINUE; label = l; }
void set_throw() { type = THROW; label = nullptr; }
};

//
Expand All @@ -77,7 +75,7 @@ class Stmt : public Tree {
// Statement execution
//

bool execute(Context &ctx, Value &result);
void execute(Context &ctx, Value &result);
};

//
Expand Down
53 changes: 20 additions & 33 deletions src/pjs/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,34 +528,36 @@ auto Context::Error::where() const -> const Location* {
return nullptr;
}

void Context::reset() {
for (auto *c = this; c; c = c->m_caller) c->m_has_error = false;
m_error->value = Value::undefined;
m_error->message.clear();
m_error->backtrace.clear();
auto Context::Error::to_exception() -> Value {
if (thrown.is_empty()) return pjs::Error::make(*this);
return thrown;
}

void Context::error(bool flag) {
for (auto *c = this; c; c = c->m_caller) c->m_has_error = flag;
}

void Context::error(const Context &ctx) {
for (auto *c = this; c; c = c->m_caller) c->m_has_error = true;
*m_error = *ctx.m_error;
void Context::error(const Error &err) {
error(true);
*m_error = err;
}

void Context::error(const Value &value) {
for (auto *c = this; c; c = c->m_caller) c->m_has_error = true;
auto s = value.to_string();
m_error->message = s->str();
m_error->value = value;
s->release();
void Context::error(const Value &thrown) {
error(true);
m_error->thrown = thrown;
m_error->message.clear();
m_error->backtrace.clear();
}

void Context::error(const char *msg) {
error(std::string(msg));
}

void Context::error(const std::string &msg) {
for (auto *c = this; c; c = c->m_caller) c->m_has_error = true;
error(true);
m_error->thrown = Value::empty;
m_error->message = msg;
m_error->value = pjs::Error::make(*m_error);
m_error->backtrace.clear();
}

void Context::error(const std::runtime_error &err) {
Expand Down Expand Up @@ -2096,21 +2098,6 @@ auto Error::name() const -> Str* {
return s_error;
}

void Error::backtrace(const std::vector<Location> &bt) {
std::string s;
for (const auto &l : bt) {
s += "In ";
s += l.name;
if (l.line && l.column) {
char buf[100];
std::sprintf(buf, " at line %d column %d in %s", l.line, l.column, l.source->filename.c_str());
s += buf;
}
s += '\n';
}
m_stack = Str::make(std::move(s));
}

auto Error::to_string() const -> std::string {
return m_message->str();
}
Expand Down Expand Up @@ -2491,7 +2478,7 @@ void Promise::Then::execute(Context *ctx, State state, const Value &result) {
}

if (!ctx->ok()) {
m_promise->settle(REJECTED, ctx->error().value);
m_promise->settle(REJECTED, ctx->error().to_exception());
ctx->reset();
return;
}
Expand All @@ -2500,7 +2487,7 @@ void Promise::Then::execute(Context *ctx, State state, const Value &result) {
Value val;
(*m_on_finally)(*ctx, 0, nullptr, val);
if (!ctx->ok()) {
m_promise->settle(REJECTED, ctx->error().value);
m_promise->settle(REJECTED, ctx->error().to_exception());
ctx->reset();
return;
} else if (val.is_promise() && val.as<Promise>()->is_rejected()) {
Expand Down
11 changes: 6 additions & 5 deletions src/pjs/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2251,10 +2251,11 @@ class Scope : public Pooled<Scope, RefCount<Scope>> {
class Context : public RefCount<Context> {
public:
struct Error {
Value value;
Value thrown = Value::empty;
std::string message;
std::vector<Location> backtrace;
auto where() const -> const Location*;
auto to_exception() -> Value;
};

static auto current() -> Context* { return s_current; }
Expand Down Expand Up @@ -2301,11 +2302,12 @@ class Context : public RefCount<Context> {
auto arg(int i) const -> Value& { return m_argv[i]; }
auto call_site() const -> const Location& { return m_call_site; }

void reset();
void reset() { error(false); }
bool ok() const { return !m_has_error; }
auto error() const -> Error& { return *m_error; }
void error(const Context &ctx);
void error(const Value &value);
void error(bool flag);
void error(const Error &err);
void error(const Value &thrown);
void error(const char *msg);
void error(const std::string &msg);
void error(const std::runtime_error &err);
Expand Down Expand Up @@ -3625,7 +3627,6 @@ class Error : public ObjectTemplate<Error> {
auto message() const -> Str* { return m_message; }
auto cause() const -> Error* { return m_cause; }
auto stack() const -> Str* { return m_stack; }
void backtrace(const std::vector<Location> &bt);

private:
Error(Str *message = nullptr, Object *cause = nullptr)
Expand Down

0 comments on commit d215d20

Please sign in to comment.