From c3065702e32aa632257f7033fafa78206c9addd9 Mon Sep 17 00:00:00 2001 From: Brandon Rozek Date: Sat, 9 Jun 2018 21:22:14 -0400 Subject: [PATCH] Better error reporting --- lval/environment.c | 8 +++++--- lval/error.c | 38 ++++++++++++++++++++++++++++++++++---- lval/error.h | 11 ++++++++--- lval/expressions.c | 31 ++++++++++++++++++++----------- lval/io.c | 1 + prompt.c | 6 ++++-- 6 files changed, 72 insertions(+), 23 deletions(-) diff --git a/lval/environment.c b/lval/environment.c index 975387a..5a3dece 100644 --- a/lval/environment.c +++ b/lval/environment.c @@ -33,7 +33,7 @@ lval* lenv_get(lenv* e, lval* k) { } // If no symbol found return error - return lval_err("unbounded symbol!"); + return lval_err("Unbounded symbol %s", k->sym); } void lenv_put(lenv* e, lval* k, lval* v) { @@ -95,11 +95,13 @@ void lenv_add_builtins(lenv* e) { lenv_add_builtin(e, "max", builtin_max); lenv_add_builtin(e, "def", builtin_def); + lenv_add_builtin(e, "ls", builtin_ls); } lval* builtin_def(lenv* e, lval* a) { LASSERT(a, a->cell[0]->type == LVAL_QEXPR, - "Function 'def' passed incorrect type") + "Function 'def' passed incorrect type. Got %s, expected %s", + ltype_name(a->cell[0]->type), ltype_name(LVAL_QEXPR)) // First argument is the symbol list lval* syms = a->cell[0]; @@ -112,7 +114,7 @@ lval* builtin_def(lenv* e, lval* a) { // Check correct number of symbols and values LASSERT(a, syms->count == a->count - 1, - "Function 'def' cannot define incorrect number of values to symbols") + "Function 'def' cannot define incorrect number of values to symbols. Left side %i, right side %i", syms->count, a->count - 1) // Assign copies of values to symbols for (int i = 0; i < syms->count; i++) { diff --git a/lval/error.c b/lval/error.c index 22f3936..f6af656 100644 --- a/lval/error.c +++ b/lval/error.c @@ -1,11 +1,41 @@ +#include +#include #include #include #include "error.h" -lval* lval_err(char* m) { +lval* lval_err(char* fmt, ...) { lval* v = (lval *) malloc(sizeof(lval)); v->type = LVAL_ERR; - v->err = (char *) malloc(strlen(m) + 1); - strcpy(v->err, m); + + // Create a va list and initialize it + va_list va; + va_start(va, fmt); + + // Allocate 512 bytes of space + v->err = (char *) malloc(512); + + //printf the error string with a maximum of 511 characters + vsnprintf(v->err, 511, fmt, va); + + // Reallocate to the number of actual bytes + v->err = realloc(v->err, strlen(v->err) + 1); + + // Cleanup our va list + va_end(va); + return v; -} \ No newline at end of file +} + +char* ltype_name(int t) { + switch(t) { + case LVAL_FUN: return "Function"; + case LVAL_LONG: return "Long"; + case LVAL_DOUBLE: return "Double"; + case LVAL_ERR: return "Error"; + case LVAL_SYM: return "Symbol"; + case LVAL_SEXPR: return "S-Expression"; + case LVAL_QEXPR: return "Q-Expression"; + default: return "Unknown"; + } +} diff --git a/lval/error.h b/lval/error.h index 19b9a45..0d95fb5 100644 --- a/lval/error.h +++ b/lval/error.h @@ -3,9 +3,14 @@ #include #include "base.h" -lval* lval_err(char* m); +lval* lval_err(char* fmt, ...); +char* ltype_name(int t); -#define LASSERT(args, cond, err) \ - if (!(cond)) { lval_del(args); return lval_err(err); } +#define LASSERT(args, cond, fmt, ...) \ + if (!(cond)) { \ + lval* err = lval_err(fmt, ##__VA_ARGS__); \ + lval_del(args); \ + return err; \ + } #endif diff --git a/lval/expressions.c b/lval/expressions.c index 44d5644..8d6e04f 100644 --- a/lval/expressions.c +++ b/lval/expressions.c @@ -86,8 +86,9 @@ lval* lval_eval_sexpr(lenv* e, lval* v) { lval* builtin_headn(lenv* e, lval* a, int n) { - LASSERT(a, a->count == 1, "Function 'head' passed too many arguments") - LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'head' passed incorrect type") + LASSERT(a, a->count == 1, "Function 'head' passed too many arguments. Got %i, Expected %i.", a->count, 1) + LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'head' passed incorrect type. Got %s, expected %s.", + ltype_name(a->cell[0]->type), ltype_name(LVAL_QEXPR)) LASSERT(a, a->cell[0]->count != 0, "Function 'head' passed {}") lval* v = lval_take(a, 0); @@ -101,7 +102,8 @@ lval* builtin_head(lenv* e, lval* a) { lval* builtin_init(lenv* e, lval* a) { LASSERT(a, a->count == 1, "Function 'init' passed too many arguments") - LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'init' passed incorrect type") + LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'init' passed incorrect type. Got %s, expeced %s.", + ltype_name(a->cell[0]->type), ltype_name(LVAL_QEXPR)) LASSERT(a, a->cell[0]->count != 0, "Function 'init' passed {}") return builtin_headn(e, a, a->cell[0]->count - 1); @@ -109,8 +111,9 @@ lval* builtin_init(lenv* e, lval* a) { lval* builtin_tail(lenv* e, lval* a) { - LASSERT(a, a->count == 1, "Function 'tail' passed too many arguments") - LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'tail' passed incorrect type") + LASSERT(a, a->count == 1, "Function 'tail' passed too many arguments. Got %i, expected %i.", a->count, 1) + LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'tail' passed incorrect type. Got %s, expected %s.", + ltype_name(a->cell[0]->type), ltype_name(LVAL_QEXPR)) LASSERT(a, a->cell[0]->count != 0, "Function 'tail' passed {}") lval* v = lval_take(a, 0); @@ -125,7 +128,8 @@ lval* builtin_list(lenv* e, lval* a) { lval* builtin_eval(lenv* e, lval* a) { LASSERT(a, a->count == 1, "Function 'eval' passed too many arguments") - LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'eval' passed incorrect type") + LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'eval' passed incorrect type. Got %s, expected %s.", + ltype_name(a->cell[0]->type), ltype_name(LVAL_QEXPR)) lval* x = lval_take(a, 0); x->type = LVAL_SEXPR; @@ -145,7 +149,8 @@ lval* lval_join(lenv* e, lval* x, lval* y) { lval* builtin_join(lenv* e, lval* a) { for (int i = 0 ; i < a->count; i++) { - LASSERT(a, a->cell[i]->type == LVAL_QEXPR, "Function 'join' passed incorrect type") + LASSERT(a, a->cell[i]->type == LVAL_QEXPR, "Function 'join' passed incorrect type. Got %s, expected %s", + ltype_name(a->cell[i]->type), ltype_name(LVAL_QEXPR)) } lval* x = lval_pop(a, 0); @@ -159,7 +164,8 @@ lval* builtin_join(lenv* e, lval* a) { } lval* builtin_len(lenv* e, lval* a) { - LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'len' passed incorrect type") + LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'len' passed incorrect type. Got %s, expected %s.", + ltype_name(a->cell[0]->type), ltype_name(LVAL_QEXPR)) lval* x = lval_long(a->cell[0]->count); lval_del(a); @@ -167,9 +173,12 @@ lval* builtin_len(lenv* e, lval* a) { } lval* builtin_cons(lenv* e, lval* a) { - LASSERT(a, a->cell[0]->type != LVAL_QEXPR, "Function 'cons' passed incorrect type on first argument") - LASSERT(a, a->cell[1]->type == LVAL_QEXPR, "Function 'cons' passed incorrect type on second argument") - LASSERT(a, a->count == 2, "Function 'cons' passed an incorrect number of arguments") + LASSERT(a, a->cell[0]->type != LVAL_QEXPR, "Function 'cons' passed incorrect type on first argument. Got %s, expected not %s", + ltype_name(a->cell[0]->type), ltype_name(LVAL_QEXPR)) + LASSERT(a, a->cell[1]->type == LVAL_QEXPR, "Function 'cons' passed incorrect type on second argument. Got %s, expected %s.", + ltype_name(a->cell[1]->type), ltype_name(LVAL_QEXPR)) + LASSERT(a, a->count == 2, "Function 'cons' passed an incorrect number of arguments. Got %i, expected %i.", + a->count, 2) lval* x = lval_qexpr(); x = lval_add(x, lval_pop(a, 0)); diff --git a/lval/io.c b/lval/io.c index 1a05b3e..6780593 100644 --- a/lval/io.c +++ b/lval/io.c @@ -1,4 +1,5 @@ #include +#include "environment.h" #include "io.h" void flval_expr_print(FILE* stream, lval* v, char open, char close) { diff --git a/prompt.c b/prompt.c index 9aa616e..ab87c18 100644 --- a/prompt.c +++ b/prompt.c @@ -121,8 +121,10 @@ lval* builtin_op(lenv* e, lval* a, char* op) { // Ensure all arguments are numbers for (int i = 0; i < a->count; i++) { if (a->cell[i]->type != LVAL_LONG && a->cell[i]->type != LVAL_DOUBLE) { + lval* x = lval_err("Function '%s' passed incorrect type for argument %i. Got %s, expected %s or %s.", + op, i, ltype_name(a->cell[i]->type), ltype_name(LVAL_LONG), ltype_name(LVAL_DOUBLE)); lval_del(a); - return lval_err("Cannot run operation on non-number"); + return x; } } @@ -171,5 +173,5 @@ lval* builtin(lenv* e, lval* a, char* func) { if (strcmp("max", func) == 0) { return builtin_op(e, a, func); } lval_del(a); - return lval_err("Unknown Function!"); + return lval_err("Unknown Function %s", func); } \ No newline at end of file