From 0cf7dd978080c7c00f41312d1a053a2c6d21e4e0 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Thu, 8 May 2025 10:49:32 +0100 Subject: [PATCH] test: add diagnostic test program --- test/CMakeLists.txt | 2 +- test/diag.c | 163 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 test/diag.c diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e216421..e72b607 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,7 +4,7 @@ foreach (test_file ${test_sources}) get_filename_component(test_name ${test_file} NAME_WE) add_executable(${test_name} ${test_file}) - target_link_libraries(${test_name} ivy-common ivy-lang ivy-asm ivy-rt mie) + target_link_libraries(${test_name} ivy-common ivy-diag ivy-lang ivy-asm ivy-rt mie) set_target_properties(${test_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" diff --git a/test/diag.c b/test/diag.c new file mode 100644 index 0000000..0299b50 --- /dev/null +++ b/test/diag.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include + +#define NR_NAMES 6 + +#define ERROR_CLASS(id, title) \ + [id] = {.c_type = IVY_DIAG_ERROR, .c_title = (title)} + +#define MSG(id, content) [id] = {.msg_content = (content)} + +enum { + E_NONE = 0, + E_UNRECOGNISED_SYMBOL, +}; + +enum { + MSG_NONE, + MSG_SYMBOL_NOT_RECOGNISED, + MSG_CORRECTION_1, + MSG_EXAMPLE_2, +}; + +static const char *fake_file_content[] = { + "var x = 32.\n", + "var y = 64.\n", + "var z = x $ y.\n", +}; +static const size_t fake_file_lines + = sizeof fake_file_content / sizeof fake_file_content[0]; + +static enum ivy_status get_name( + struct ivy_line_source *src, char *buf, size_t count, size_t *nr_read) +{ + *nr_read = snprintf(buf, count, "SAMPLE"); + return IVY_OK; +} + +static enum ivy_status get_row( + struct ivy_line_source *src, size_t row, char *buf, size_t count, + size_t *nr_read) +{ + if (row > fake_file_lines) { + return IVY_ERR_EOF; + } + + const char *line = fake_file_content[row - 1]; + size_t len = strlen(line); + if (len > count) { + len = count; + } + + memcpy(buf, line, len); + buf[len - 1] = 0; + *nr_read = len - 1; + + return IVY_OK; +} + +static struct ivy_line_source source_file = { + .s_get_name = get_name, + .s_get_row = get_row, +}; + +static const struct ivy_diag_class diag_classes[] = { + ERROR_CLASS(E_UNRECOGNISED_SYMBOL, "Unrecognised symbol"), +}; +static const size_t nr_diag_classes = sizeof diag_classes / sizeof diag_classes[0]; + +static const struct ivy_diag_msg diag_msg[] = { + MSG(MSG_SYMBOL_NOT_RECOGNISED, + "encountered a symbol that is not part of the Ivy syntax."), + MSG(MSG_CORRECTION_1, + "perhaps you meant to use an arithmetic operator instead?"), + MSG(MSG_EXAMPLE_2, "an example diagnostic message."), +}; +static const size_t nr_diag_msg = sizeof diag_msg / sizeof diag_msg[0]; + +int main(void) +{ + struct ivy_diag_ctx *ctx; + if (ivy_diag_ctx_create(&ctx) != IVY_OK) { + return -1; + } + + ivy_diag_set_line_source(ctx, &source_file); + ivy_diag_ctx_set_class_definitions(ctx, diag_classes, nr_diag_classes); + ivy_diag_ctx_set_msg_definitions(ctx, diag_msg, nr_diag_msg); + + const struct ivy_diag_highlight hl[] = { + IVY_DIAG_HL(ERROR, 3, 11, 3, 11), + }; + + const struct ivy_diag_highlight hl2[] = { + IVY_DIAG_HL(HINT, 3, 11, 3, 11), + }; + + const struct ivy_diag_amendment amend[] = { + IVY_DIAG_REPLACE(3, 11, 1, "+"), + }; + + struct ivy_diag *diag + = ivy_diag_ctx_create_diag(ctx, E_UNRECOGNISED_SYMBOL); + ivy_diag_set_location(diag, 3, 11); + ivy_diag_push_msg(diag, MSG_SYMBOL_NOT_RECOGNISED); + ivy_diag_push_snippet( + diag, 1, 3, amend, sizeof amend / sizeof amend[0], hl, + sizeof hl / sizeof hl[0]); + ivy_diag_push_msg(diag, MSG_CORRECTION_1); + ivy_diag_push_snippet( + diag, 1, 3, amend, sizeof amend / sizeof amend[0], hl2, + sizeof hl2 / sizeof hl2[0]); + ivy_diag_push_msg(diag, MSG_EXAMPLE_2); + + struct ivy_diag_stream stream; + ivy_diag_stream_init_tty(&stream, b_stdtty); + ivy_diag_ctx_write(ctx, IVY_DIAG_FORMAT_PRETTY, &stream); + +#if 0 + b_printf( + "[cyan]--- UNRECOGNISED SYMBOL " + "-------------------------" + "--------------------------[reset]\n"); + b_printf(" [cyan]> src/std/io/StreamReader.im[reset]:8:11\n\n"); + + b_printf( + " encountered a symbol that is not part of the Ivy " + "syntax.\n\n"); + + b_printf(" [cyan]6 |[reset] var x = 32.\n"); + b_printf(" [cyan]7 |[reset] var y = 64.\n"); + b_printf(" [cyan]8 |[reset] var z = x [red]$[reset] y.\n"); + b_printf(" [red]^[reset]\n\n"); + + b_printf("\n\n"); + + b_printf( + "[red,bold]error[[E0102][reset]: [bold]encountered an " + "unrecognised symbol[reset]\n"); + b_printf(" [blue,bold]-->[reset] src/std/io/StreamReader.im\n"); + b_printf(" [blue,bold] |[reset]\n"); + b_printf(" [blue,bold]6 |[reset] var x = 32.\n"); + b_printf(" [blue,bold]7 |[reset] var y = 64.\n"); + b_printf(" [blue,bold]8 |[reset] var z = x [red,bold]$[reset] y.\n"); + b_printf(" [blue,bold] |[reset] [red,bold]^[reset]\n"); + + b_printf("\n\n"); + + b_printf(" [red,bold]\u2A2F[reset] unrecognised symbol\n"); + b_printf(" [cyan,bold]>[reset] src/std/io/StreamReader.im\n"); + b_printf(" \u256D\u2500\u2500\u2500\n"); + b_printf(" [dark_grey]0[reset] \u2502 var x = 2 $ 3.\n"); + b_printf(" \u00B7 [green]\u252C[reset]\n"); + b_printf( + " \u00B7 [green]\u2570\u2500\u2500 this symbol is " + "not " + "used in Ivy syntax.[reset]\n"); + b_printf(" \u2570\u2500\u2500\u2500\n"); +#endif + + return 0; +}