Skip to content

Commit

Permalink
W-I-P: improving error handlings.
Browse files Browse the repository at this point in the history
  • Loading branch information
tadd committed Jul 21, 2024
1 parent 988e0cc commit 127b31c
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 17 deletions.
44 changes: 34 additions & 10 deletions lisp.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <ctype.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
Expand All @@ -14,6 +15,25 @@
#define unexpected(exp, act, ...) \
error("expected %s but got " act, exp __VA_OPT__(,) __VA_ARGS__)

static jmp_buf jmp_runtime_error;
static char errmsg[BUFSIZ];

ATTR_NORETURN
static void runtime_error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
snprintf(errmsg, sizeof(errmsg), "error: ");
vsnprintf(errmsg, sizeof(errmsg), fmt, ap);

longjmp(jmp_runtime_error, Qundef);
}

const char *error_message(void)
{
return errmsg;
}

typedef enum {
// immediate
TYPE_BOOL,
Expand Down Expand Up @@ -338,7 +358,7 @@ static const char *unintern(Symbol sym)
{
const char *name = name_nth(symbol_names, (long) sym);
if (name == NULL)
error("symbol %lu not found", sym);
runtime_error("symbol %lu not found", sym);
return name;
}

Expand Down Expand Up @@ -428,7 +448,7 @@ static Token get_token(Parser *p)
ungetc(c, p->in);
return get_token_ident(p);
}
error("got unexpected char '%c'", c);
runtime_error("got unexpected char '%c'", c);
}

static void unget_token(Parser *p, Token t)
Expand Down Expand Up @@ -556,16 +576,16 @@ static void expect_arity(long expected, long actual)
{
if (expected < 0 || expected == actual)
return;
error("wrong number of arguments: expected %ld but got %ld",
expected, actual);
runtime_error("wrong number of arguments: expected %ld but got %ld",
expected, actual);
}

Value apply(Value *env, Value func, Value vargs)
{
static const long FUNCARG_MAX = 7;

long n = FUNCTION(func)->arity;
if (n > FUNCARG_MAX)
if (n > FUNCARG_MAX) // fatal; wrong at define_function()
error("arguments too long: max is %ld but got %ld", FUNCARG_MAX, n);
expect_arity(n, length(vargs));

Expand Down Expand Up @@ -637,7 +657,9 @@ static Value define_function(Value *env, const char *name, CFunc cfunc, long ari
static Value lookup(Value env, Value name)
{
Value found = alist_find(env, name);
return found == Qnil ? Qundef : cdr(found);
if (found == Qnil)
runtime_error("variable %s not found", value_to_string(name));
return cdr(found);
}

Value eval_string(const char *in)
Expand Down Expand Up @@ -703,6 +725,8 @@ Value load(FILE *in)
{
Value env = toplevel_environment;
Value last = Qnil;
if (setjmp(jmp_runtime_error) != 0)
return Qundef;
for (Value v = parse(in); v != Qnil; v = cdr(v))
last = ieval(&env, car(v));
return last;
Expand Down Expand Up @@ -821,8 +845,8 @@ static void expect_type(Type expected, Value v, const char *header)
Type t = value_typeof(v);
if (t == expected)
return;
error("%s: type error: expected %s but got %s",
header, TYPE_NAMES[expected], TYPE_NAMES[t]);
runtime_error("%s: type error: expected %s but got %s",
header, TYPE_NAMES[expected], TYPE_NAMES[t]);
}

static Value builtin_add(Value args)
Expand All @@ -839,7 +863,7 @@ static Value builtin_add(Value args)
static Value builtin_sub(Value args)
{
if (args == Qnil)
error("wrong number of arguments: expected 1 or more but got 0");
runtime_error("wrong number of arguments: expected 1 or more but got 0");
Value rest = cdr(args);
int64_t y = 0;
if (rest == Qnil)
Expand Down Expand Up @@ -871,7 +895,7 @@ static Value builtin_mul(Value args)
static Value builtin_div(Value args)
{
if (args == Qnil)
error("wrong number of arguments: expected 1 or more but got 0");
runtime_error("wrong number of arguments: expected 1 or more but got 0");
Value rest = cdr(args);
int64_t y = 1;
if (rest == Qnil)
Expand Down
2 changes: 2 additions & 0 deletions lisp.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ ATTR_MALLOC char *stringify(Value v);
Value parse_string(const char *in);
Value parse_expr_string(const char *in);

const char *error_message(void);

#endif
19 changes: 12 additions & 7 deletions test_lisp.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@

#include "lisp.h"

Test(lisp, nil) {
Value a = Qnil;
cr_assert(value_is_nil(a));
}

#define assert_stringify(expected, v) do { \
char *s = stringify(v); \
cr_assert_str_eq(expected, s); \
Expand All @@ -27,6 +22,16 @@ Test(lisp, nil) {
#define V(x) \
_Generic(x, int: value_of_int(x), const char *: value_of_symbol, Value: x)

#define assert_runtime_error(v, pattern) do { \
cr_assert_eq(Qundef, v); \
cr_assert_not_null(strstr(error_message(), pattern)); \
} while (0)

Test(lisp, nil) {
Value a = Qnil;
cr_assert(value_is_nil(a));
}

Test(lisp, printing) {
assert_stringify("#t", Qtrue);
assert_stringify("#f", Qfalse);
Expand Down Expand Up @@ -125,10 +130,10 @@ Test(lisp, eval_arithmetic_expr) {

Test(lisp, unbound_variable) {
Value v = eval_string("x");
cr_assert_eq(v, Qundef);
assert_runtime_error(v, "x not found");

v = eval_string("(+ x 2)");
cr_assert_eq(v, Qundef);
assert_runtime_error(v, "x not found");
}

Test(lisp, true_false) {
Expand Down

0 comments on commit 127b31c

Please sign in to comment.