harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

commit d82683473da59e1cbf6a095ec68db6cfca92f4b1
parent 07e888e539e618dd5ccc16c0f0325d74d373a2b5
Author: Autumn! <autumnull@posteo.net>
Date:   Wed, 15 Feb 2023 13:51:07 +0000

Add visual marker for errors

Signed-off-by: Autumn! <autumnull@posteo.net>

Diffstat:
Minclude/util.h | 2++
Msrc/check.c | 5+++++
Msrc/lex.c | 1+
Msrc/parse.c | 2++
Msrc/util.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 79 insertions(+), 0 deletions(-)

diff --git a/include/util.h b/include/util.h @@ -30,4 +30,6 @@ struct pathspec { char *getpath(const struct pathspec *paths, size_t npaths); +int errline(const char* path, int lineno, int colno); + #endif diff --git a/src/check.c b/src/check.c @@ -51,9 +51,14 @@ static void handle_errors(struct errors *errors) { struct errors *error = errors; + bool first = true; while (error) { fprintf(stderr, "Error %s:%d:%d: %s\n", sources[error->loc.file], error->loc.lineno, error->loc.colno, error->msg); + if (first) { + errline(sources[error->loc.file], error->loc.lineno, error->loc.colno); + first = false; + } struct errors *next = error->next; free(error); error = next; diff --git a/src/lex.c b/src/lex.c @@ -151,6 +151,7 @@ error(struct location *loc, char *fmt, ...) va_end(ap); fputc('\n', stderr); + errline(sources[loc->file], loc->lineno, loc->colno); exit(EXIT_FAILURE); } diff --git a/src/parse.c b/src/parse.c @@ -22,6 +22,7 @@ synassert_msg(bool cond, const char *msg, struct token *tok) fprintf(stderr, "Syntax error: %s at %s:%d:%d (found '%s')\n", msg, sources[tok->loc.file], tok->loc.lineno, tok->loc.colno, token_str(tok)); + errline(sources[tok->loc.file], tok->loc.lineno, tok->loc.colno); exit(EXIT_FAILURE); } } @@ -43,6 +44,7 @@ vsynerr(struct token *tok, va_list ap) t = va_arg(ap, enum lexical_token); fprintf(stderr, "%s", t == T_EOF ? "\n" : ", "); } + errline(sources[tok->loc.file], tok->loc.lineno, tok->loc.colno); exit(EXIT_FAILURE); } diff --git a/src/util.c b/src/util.c @@ -1,7 +1,10 @@ +#include <sys/stat.h> +#include <stdbool.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <stdio.h> +#include <unistd.h> #include "util.h" // Remove safety macros: #undef malloc @@ -117,3 +120,69 @@ getpath(const struct pathspec *paths, size_t npaths) { } return NULL; } + +int +errline(const char* path, int lineno, int colno) +{ + char* real = realpath(path, NULL); + struct stat filestat; + if (stat(real, &filestat) != 0 || !S_ISREG(filestat.st_mode)) { + free(real); + return -1; + } + free(real); + + FILE* src = fopen(path, "r"); + if (!src) { + return -1; + } + char* line = NULL; + size_t len = 0; + int n = 0; + while (n < lineno) { + if (getline(&line, &len, src) == -1) { + fclose(src); + if (line) { + free(line); + } + return -1; + } + n += 1; + } + if (line) { + bool color = true; + const char* no_color = getenv("NO_COLOR"); + const char* harec_color = getenv("HAREC_COLOR"); + if (!isatty(fileno(stderr))) { + color = false; + } + if (no_color != NULL) { + if (0 < strlen(no_color)) { + color = false; + } + } + if (harec_color != NULL) { + if (strcmp(harec_color, "0") == 0) { + color = false; + } else { + color = true; + } + } + fprintf(stderr, "\n%d |\t%s", lineno, line); + for (int i = lineno; 1 <= i; i /= 10) { + fputc(' ', stderr); + } + fputs(" |\t", stderr); + for (int i = 1; i < colno; i++) { + fputc(' ', stderr); + } + if (color) { + fputs("\x1b[31m^\x1b[0m\n\n", stderr); + } else { + fputs("^\n\n", stderr); + } + free(line); + } + fclose(src); + return 0; +}