summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ast.c48
-rw-r--r--ast.h5
-rw-r--r--eval.c32
-rw-r--r--eval.h3
-rw-r--r--lib.c100
5 files changed, 125 insertions, 63 deletions
diff --git a/ast.c b/ast.c
index 390c4d2..818f6af 100644
--- a/ast.c
+++ b/ast.c
@@ -370,6 +370,54 @@ ut_new_func(struct ut_state *s, struct ut_op *decl, struct ut_scope *scope)
}
static void
+exception_free(struct json_object *v, void *ud)
+{
+ free(ud);
+}
+
+__attribute__((format(printf, 3, 0))) struct json_object *
+ut_new_exception(struct ut_state *s, uint32_t off, const char *fmt, ...)
+{
+ struct ut_op *op, *failing_op;
+ va_list ap;
+ ssize_t sz;
+ char *p;
+
+ sz = ALIGN(sizeof(*op));
+
+ if (s->filename)
+ sz += ALIGN(strlen(s->filename) + 1);
+
+ failing_op = ut_get_op(s, off);
+
+ op = xalloc(sz);
+ op->type = T_EXCEPTION;
+ op->off = failing_op ? failing_op->off : 0;
+
+ if (s->filename) {
+ p = (char *)op + ALIGN(sizeof(*op));
+ op->tag.data = strcpy(p, s->filename);
+ }
+
+ va_start(ap, fmt);
+ sz = xvasprintf(&p, fmt, ap);
+ va_end(ap);
+
+ op->val = xjs_new_string_len(p, sz);
+ free(p);
+
+ json_object_set_userdata(op->val, op, exception_free);
+
+ if (s->error.code == UT_ERROR_EXCEPTION)
+ json_object_put(s->error.info.exception);
+
+ s->error.code = UT_ERROR_EXCEPTION;
+ s->error.info.exception = op->val;
+
+ return json_object_get(op->val);
+}
+
+static void
scope_free(struct json_object *v, void *ud)
{
struct ut_scope *sc = ud;
diff --git a/ast.h b/ast.h
index 8d9a8eb..339c178 100644
--- a/ast.h
+++ b/ast.h
@@ -165,6 +165,11 @@ struct json_object *ut_new_double(double v);
struct json_object *ut_new_null(void);
struct json_object *ut_new_regexp(const char *source, bool icase, bool newline, bool global, char **err);
+__attribute__((format(printf, 3, 0)))
+struct json_object *ut_new_exception(struct ut_state *s, uint32_t off, const char *fmt, ...);
+
+#define ut_exception ut_new_exception
+
struct ut_scope *ut_new_scope(struct ut_state *s, struct ut_scope *parent);
struct ut_scope *ut_parent_scope(struct ut_scope *scope);
struct ut_scope *ut_acquire_scope(struct ut_scope *scope);
diff --git a/eval.c b/eval.c
index 881766b..1803355 100644
--- a/eval.c
+++ b/eval.c
@@ -26,38 +26,6 @@
#include <stdarg.h>
#include <regex.h>
-char exception_tag_space[sizeof(struct ut_op) + sizeof(struct ut_op *)];
-static struct ut_op *exception_tag = (struct ut_op *)exception_tag_space;
-
-__attribute__((format(printf, 3, 0))) struct json_object *
-ut_exception(struct ut_state *state, uint32_t off, const char *fmt, ...)
-{
- struct json_object *msg;
- va_list ap;
- char *s;
- int len;
-
- va_start(ap, fmt);
- len = xvasprintf(&s, fmt, ap);
- va_end(ap);
-
- msg = xjs_new_string_len(s, len);
- free(s);
-
- exception_tag->type = T_EXCEPTION;
- exception_tag->tree.operand[0] = off;
-
- json_object_set_userdata(msg, exception_tag, NULL);
-
- if (state->error.code == UT_ERROR_EXCEPTION)
- json_object_put(state->error.info.exception);
-
- state->error.code = UT_ERROR_EXCEPTION;
- state->error.info.exception = msg;
-
- return json_object_get(msg);
-}
-
bool
ut_val_is_truish(struct json_object *val)
{
diff --git a/eval.h b/eval.h
index 869839e..bc59cea 100644
--- a/eval.h
+++ b/eval.h
@@ -24,9 +24,6 @@
#include "ast.h"
-__attribute__((format(printf, 3, 0))) struct json_object *
-ut_exception(struct ut_state *state, uint32_t op, const char *fmt, ...);
-
bool
ut_cmp(int how, struct json_object *v1, struct json_object *v2);
diff --git a/lib.c b/lib.c
index c46745e..e5fcf8c 100644
--- a/lib.c
+++ b/lib.c
@@ -64,47 +64,29 @@ snprintf_append(char **dptr, size_t *dlen, const char *fmt, ssize_t sz, ...)
snprintf_append(dptr, dlen, fmt, -1, ##__VA_ARGS__)
static void
-format_error_context(char **msg, size_t *msglen, const char *path, const char *expr, size_t off)
+format_context_line(char **msg, size_t *msglen, const char *line, size_t off)
{
- int eoff, eline, padlen;
- const char *p, *nl;
- int i;
-
- /* skip lines until error line */
- for (p = nl = expr, eline = 0; *p && p < expr + off; p++) {
- if (*p == '\n') {
- nl = p + 1;
- eline++;
- }
- }
-
- eoff = p - nl;
-
- if (path)
- sprintf_append(msg, msglen, "In %s, ", path);
- else
- sprintf_append(msg, msglen, "In ");
-
- sprintf_append(msg, msglen, "line %u, byte %d:\n\n `", eline + 1, eoff);
+ const char *p;
+ int padlen, i;
- for (p = nl, padlen = 0; *p != '\n' && *p != '\0'; p++) {
+ for (p = line, padlen = 0; *p != '\n' && *p != '\0'; p++) {
switch (*p) {
case '\t':
sprintf_append(msg, msglen, " ");
- if (p < nl + eoff)
+ if (p < line + off)
padlen += 4;
break;
case '\r':
case '\v':
sprintf_append(msg, msglen, " ");
- if (p < nl + eoff)
+ if (p < line + off)
padlen++;
break;
default:
sprintf_append(msg, msglen, "%c", *p);
- if (p < nl + eoff)
+ if (p < line + off)
padlen++;
}
}
@@ -127,14 +109,72 @@ format_error_context(char **msg, size_t *msglen, const char *path, const char *e
}
}
+static void
+format_error_context(char **msg, size_t *msglen, const char *path, const char *expr, size_t off)
+{
+ const char *p, *nl;
+ size_t len, rlen;
+ bool truncated;
+ char buf[256];
+ int eline;
+ FILE *f;
+
+ if (path) {
+ f = fopen(path, "rb");
+
+ if (f) {
+ truncated = false;
+ eline = 1;
+ rlen = 0;
+
+ while (fgets(buf, sizeof(buf), f)) {
+ len = strlen(buf);
+ rlen += len;
+
+ if (rlen > off) {
+ sprintf_append(msg, msglen, "In %s, line %u, byte %d:\n\n `%s",
+ path, eline, len - (rlen - off) + (truncated ? sizeof(buf) : 1),
+ truncated ? "..." : "");
+
+ format_context_line(msg, msglen, buf,
+ len - (rlen - off) + (truncated ? 3 : 0));
+
+ break;
+ }
+
+ truncated = (len > 0 && buf[len-1] != '\n');
+ eline += !truncated;
+ }
+ }
+ else {
+ sprintf_append(msg, msglen, "In %s, byte offset %zu [Unable to read source context]\n",
+ path, off);
+ }
+
+ fclose(f);
+ }
+ else if (expr) {
+ /* skip lines until error line */
+ for (p = nl = expr, eline = 1; *p && p < expr + off; p++) {
+ if (*p == '\n') {
+ nl = p + 1;
+ eline++;
+ }
+ }
+
+ sprintf_append(msg, msglen, "In line %u, byte %d:\n\n `", eline, p - nl);
+ format_context_line(msg, msglen, nl, p - nl);
+ }
+}
+
char *
ut_format_error(struct ut_state *state, const char *expr)
{
+ char *msg = NULL, *filename = state->filename;
size_t off = state ? state->off : 0;
struct ut_op *tag;
bool first = true;
size_t msglen = 0;
- char *msg = NULL;
int i, max_i;
switch (state ? state->error.code : UT_ERROR_OUT_OF_MEMORY) {
@@ -207,14 +247,18 @@ ut_format_error(struct ut_state *state, const char *expr)
case UT_ERROR_EXCEPTION:
tag = json_object_get_userdata(state->error.info.exception);
- off = (tag && tag->tree.operand[0]) ? ut_get_op(state, tag->tree.operand[0])->off : 0;
+
+ if (tag && tag->type == T_EXCEPTION) {
+ off = tag->off;
+ filename = tag->tag.data;
+ }
sprintf_append(&msg, &msglen, "%s\n", json_object_get_string(state->error.info.exception));
break;
}
if (off)
- format_error_context(&msg, &msglen, state->filename, expr, off);
+ format_error_context(&msg, &msglen, filename, expr, off);
return msg;
}