diff options
Diffstat (limited to 'src/source.c')
| -rw-r--r-- | src/source.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/source.c b/src/source.c new file mode 100644 index 0000000..cc544e4 --- /dev/null +++ b/src/source.c @@ -0,0 +1,59 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include "source.h" + +void source_init(struct source *src, str name, str contents) +{ + src->name = name; + src->offset = 0; + src->contents = contents; + src->strings.len = src->strings.cap = 0; + src->strings.ptr = nullptr; +} + +void source_error(struct source *src, struct range loc, const char *fmt, ...) +{ + char *p_start = src->contents.ptr + loc.start; + char *p_end = src->contents.ptr + loc.end; + + unsigned int lineno = 0; + str iter = src->contents; + str line; + do { + line = str_walk(&iter, S("\n")); + lineno++; + } while (line.ptr + line.len <= p_start); + + fprintf(stderr, "parse error in %.*s:%u: ", PSTR(src->name), lineno); + + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + fprintf(stderr, "\n"); + + while (line.ptr && line.ptr < p_end) { + fprintf(stderr, " %4u: %.*s\n", lineno, PSTR(line)); + fprintf(stderr, " "); + for (size_t i = 0; i < line.len+1; i++) { + char *p = line.ptr + i; + fprintf(stderr, "%c", p >= p_start && p < p_end ? '^' : ' '); + } + fprintf(stderr, "\n"); + + line = str_walk(&iter, S("\n")); + lineno++; + } + + exit(EXIT_FAILURE); +} + +void source_free(struct source *src) +{ + free(src->contents.ptr); + for (size_t i = 0; i < src->strings.len; i++) + free(src->strings.ptr[i].ptr); + free(src->strings.ptr); +} |
