aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-02-19 01:36:55 +0100
committerThomas Voss <mail@thomasvoss.com> 2024-02-19 01:36:55 +0100
commit6eec862df222c8d060e8482dd09d0f91197ee9fc (patch)
tree233c425622b379c3a719051351a1d5137df73e11 /src/common
parent623c781706175767a81287f48fc399bf6aee5a43 (diff)
Better error messages in the lexer
Diffstat (limited to 'src/common')
-rw-r--r--src/common/cerr.c103
-rw-r--r--src/common/cerr.h7
2 files changed, 102 insertions, 8 deletions
diff --git a/src/common/cerr.c b/src/common/cerr.c
index 8570247..819df4a 100644
--- a/src/common/cerr.c
+++ b/src/common/cerr.c
@@ -1,19 +1,33 @@
#include <errno.h>
#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <mbstring.h>
+
#include "cerr.h"
+#include "macros.h"
+#include "mbstring.h"
+
+#define TAB_AS_SPC " "
+
+#define EOLS8 u8"\n\v\f\r\x85\u2028\u2029"
+#define EOLS32 U"\n\v\f\r\x85\u2028\u2029"
#define SGR_BOLD "\33[1m"
#define SGR_DONE "\33[0m"
+#define SGR_WARN "\33[1;35m"
+#define SGR_ERR "\33[1;31m"
+
+int sizelen(size_t);
static bool color;
static const char *progname;
-static const char *_bold, *_done;
+static const char *_bold, *_done, *_warn, *_err;
void
cerrinit(const char *s)
@@ -23,17 +37,16 @@ cerrinit(const char *s)
if (isatty(STDOUT_FILENO)) {
const char *ev = getenv("NO_COLOR");
- if (!ev || !*ev)
- color = true;
+ color = !ev || !*ev;
}
if (color) {
_bold = SGR_BOLD;
_done = SGR_DONE;
- } else {
- _bold = "";
- _done = "";
- }
+ _warn = SGR_WARN;
+ _err = SGR_ERR;
+ } else
+ _bold = _done = _warn = _err = "";
}
void
@@ -71,10 +84,84 @@ die_with_off(const char *file, size_t off, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "%s%s:%s:%zu:%s ", _bold, progname, file, off, _done);
+ fprintf(stderr, "%s%s: %s:%zu:%s %serror:%s ", _bold, progname, file, off,
+ _done, _err, _done);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+
+ exit(EXIT_FAILURE);
+}
+
+void
+die_at_pos_with_code(const char *file, struct u8view sv, struct u8view hl,
+ size_t off, const char *fmt, ...)
+{
+ int w;
+ rune _;
+ size_t lb;
+ va_list ap;
+ const char8_t *prv, *end;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "%s%s: %s:%zu:%s %serror:%s ", _bold, progname, file, off,
+ _done, _err, _done);
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
va_end(ap);
+ for (lb = 0, prv = end = sv.p; end <= sv.p + off; lb++) {
+ prv = end;
+ end += u8cbspn(end, sv.p + sv.len - end, EOLS32, lengthof(EOLS32) - 1);
+ end += u8tor_uc(&_, end);
+ }
+
+ u8prev(&_, &end, prv);
+ w = sizelen(lb);
+ w = MAX(w, 4);
+
+ fprintf(stderr, " %*zu │ ", w, lb);
+
+ /* The following is really ugly, but it works! */
+ if (hl.p) {
+ ptrdiff_t w2 = hl.p - prv;
+ struct u8view pfx = {prv, w2};
+
+ for (ptrdiff_t i = 0; i < w2; i++) {
+ if (prv[i] == '\t')
+ fputs(TAB_AS_SPC, stderr);
+ else
+ fputc(prv[i], stderr);
+ }
+ fprintf(stderr, "%s%.*s%s%.*s\n", _err, U8_PRI_ARGS(hl), _done,
+ (int)(end - (prv + w2 + hl.len)), prv + w2 + hl.len);
+ fprintf(stderr, " %*c │ ", w, ' ');
+
+ while (u8next(&_, &pfx.p, &pfx.len)) {
+ if (_ == '\t')
+ fputs(TAB_AS_SPC, stderr);
+ else
+ fputc(' ', stderr);
+ }
+
+ fprintf(stderr, "%s^", _err);
+ for (u8next(&_, &hl.p, &hl.len); u8next(&_, &hl.p, &hl.len);
+ fputc('~', stderr))
+ ;
+ fprintf(stderr, "%s\n", _done);
+ } else {
+ fprintf(stderr, "%.*s\n", (int)(end - prv), prv);
+ fprintf(stderr, " %*c │\n", w, ' ');
+ }
+
exit(EXIT_FAILURE);
}
+
+int
+sizelen(size_t x)
+{
+ int n;
+ for (n = 0; x; x /= 10, n++)
+ ;
+ return n;
+}
diff --git a/src/common/cerr.h b/src/common/cerr.h
index 869c9e2..5476f96 100644
--- a/src/common/cerr.h
+++ b/src/common/cerr.h
@@ -3,6 +3,8 @@
#include <stddef.h>
+#include <mbstring.h>
+
void cerrinit(const char *);
[[noreturn, gnu::nonnull, gnu::format(printf, 1, 2)]]
@@ -14,4 +16,9 @@ void diex(const char *, ...);
[[noreturn, gnu::nonnull, gnu::format(printf, 3, 4)]]
void die_with_off(const char *, size_t, const char *, ...);
+[[noreturn, gnu::nonnull, gnu::format(printf, 5, 6)]]
+void
+die_at_pos_with_code(const char *, struct u8view, struct u8view, size_t,
+ const char *, ...);
+
#endif /* !AHOY_COMMON_CERR_H */