diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-08-25 00:30:08 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-08-25 00:30:08 -0400 |
| commit | b378f7359a6b8bd2e47bafdba496d115825adcd7 (patch) | |
| tree | 52deff3a66e2265b84bd20a7e81b20111d29f7dd /src/parse/errors.h | |
| parent | 80755477735baaea66f865c316aff036bebd8e2f (diff) | |
Split out some parser functionality.
Diffstat (limited to 'src/parse/errors.h')
| -rw-r--r-- | src/parse/errors.h | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/src/parse/errors.h b/src/parse/errors.h new file mode 100644 index 00000000..479a785f --- /dev/null +++ b/src/parse/errors.h @@ -0,0 +1,86 @@ + +#include <ctype.h> // IWYU pragma: export +#include <stdio.h> // IWYU pragma: export +#include <stdlib.h> // IWYU pragma: export +#include <string.h> // IWYU pragma: export + +#include "../stdlib/files.h" // IWYU pragma: export +#include "../stdlib/print.h" // IWYU pragma: export +#include "../stdlib/stacktrace.h" // IWYU pragma: export +#include "../stdlib/stdlib.h" // IWYU pragma: export +#include "utils.h" // IWYU pragma: export + +// +// Print a parse error and exit (or use the on_err longjmp) +// +#define parser_err(ctx, start, end, ...) \ + ({ \ + if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \ + fprint_inline(stderr, (ctx)->file->relative_filename, ":", get_line_number((ctx)->file, (start)), ".", \ + get_line_column((ctx)->file, (start)), ": ", __VA_ARGS__); \ + if (USE_COLOR) fputs(" \x1b[m", stderr); \ + fputs("\n\n", stderr); \ + highlight_error((ctx)->file, (start), (end), "\x1b[31;1;7m", 2, USE_COLOR); \ + fputs("\n", stderr); \ + if (getenv("TOMO_STACKTRACE")) print_stacktrace(stderr, 1); \ + if ((ctx)->on_err) longjmp(*((ctx)->on_err), 1); \ + raise(SIGABRT); \ + exit(1); \ + }) + +// +// Expect a string (potentially after whitespace) and emit a parser error if it's not there +// +#define expect_str(ctx, start, pos, target, ...) \ + ({ \ + spaces(pos); \ + if (!match(pos, target)) { \ + if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \ + parser_err(ctx, start, *pos, __VA_ARGS__); \ + } \ + char _lastchar = target[strlen(target) - 1]; \ + if (isalpha(_lastchar) || isdigit(_lastchar) || _lastchar == '_') { \ + if (is_xid_continue_next(*pos)) { \ + if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \ + parser_err(ctx, start, *pos, __VA_ARGS__); \ + } \ + } \ + }) + +// +// Helper for matching closing parens with good error messages +// +#define expect_closing(ctx, pos, close_str, ...) \ + ({ \ + const char *_start = *pos; \ + spaces(pos); \ + if (!match(pos, (close_str))) { \ + const char *_eol = strchr(*pos, '\n'); \ + const char *_next = strstr(*pos, (close_str)); \ + const char *_end = _eol < _next ? _eol : _next; \ + if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \ + parser_err(ctx, _start, _end, __VA_ARGS__); \ + } \ + }) + +#define expect(ctx, start, pos, parser, ...) \ + ({ \ + const char **_pos = pos; \ + spaces(_pos); \ + __typeof(parser(ctx, *_pos)) _result = parser(ctx, *_pos); \ + if (!_result) { \ + if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \ + parser_err(ctx, start, *_pos, __VA_ARGS__); \ + } \ + *_pos = _result->end; \ + _result; \ + }) + +#define optional(ctx, pos, parser) \ + ({ \ + const char **_pos = pos; \ + spaces(_pos); \ + __typeof(parser(ctx, *_pos)) _result = parser(ctx, *_pos); \ + if (_result) *_pos = _result->end; \ + _result; \ + }) |
