aboutsummaryrefslogtreecommitdiff
path: root/src/parse/errors.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse/errors.h')
-rw-r--r--src/parse/errors.h86
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; \
+ })