apfl/src/error.c
Laria Carolin Chabowski 5b4ac67de9 Make APFL_ERR_INPUT_ERROR non fatal
For two reasons:

- We'll later want apfl code to load other apfl code. If an IO error
  happens in that case, we don't want that to be a fatal error, only a
  regular error that can be catched in apfl (once we have something like
  `try`).
- I want to get rid of fatal errors as a generic category completely.
  Instead the error reporting functions themselves should tell you the type
  of error directly, if it was something fatal.
2022-12-08 22:10:18 +01:00

225 lines
8.9 KiB
C

#include <stdio.h>
#include "apfl.h"
#include "format.h"
#define POSFMT "%d:%d"
#define POSARGS error.position.line, error.position.col
#define POS2ARGS error.position2.line, error.position2.col
#define TRY(x) do { if (!(x)) return false; } while (0)
const char *
apfl_error_type_name(enum apfl_error_type type)
{
switch (type) {
case APFL_ERR_MALLOC_FAILED:
return "APFL_ERR_MALLOC_FAILED";
case APFL_ERR_INPUT_ERROR:
return "APFL_ERR_INPUT_ERROR";
case APFL_ERR_UNEXPECTED_EOF:
return "APFL_ERR_UNEXPECTED_EOF";
case APFL_ERR_EXPECTED_EQ_AFTER_COLON:
return "APFL_ERR_EXPECTED_EQ_AFTER_COLON";
case APFL_ERR_UNEXPECTED_BYTE:
return "APFL_ERR_UNEXPECTED_BYTE";
case APFL_ERR_UNEXPECTED_BYTE_IN_NUMBER:
return "APFL_ERR_UNEXPECTED_BYTE_IN_NUMBER";
case APFL_ERR_EXPECTED_DIGIT:
return "APFL_ERR_EXPECTED_DIGIT";
case APFL_ERR_EXPECTED_HEX_IN_HEX_ESCAPE:
return "APFL_ERR_EXPECTED_HEX_IN_HEX_ESCAPE";
case APFL_ERR_INVALID_ESCAPE_SEQUENCE:
return "APFL_ERR_INVALID_ESCAPE_SEQUENCE";
case APFL_ERR_NO_LINEBREAK_AFTER_CONTINUE_LINE:
return "APFL_ERR_NO_LINEBREAK_AFTER_CONTINUE_LINE";
case APFL_ERR_UNEXPECTED_TOKEN:
return "APFL_ERR_UNEXPECTED_TOKEN";
case APFL_ERR_MISMATCHING_CLOSING_BRACKET:
return "APFL_ERR_MISMATCHING_CLOSING_BRACKET";
case APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN:
return "APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN";
case APFL_ERR_STATEMENTS_BEFORE_PARAMETERS:
return "APFL_ERR_STATEMENTS_BEFORE_PARAMETERS";
case APFL_ERR_EMPTY_ASSIGNMENT_BEFORE_PARAMETERS:
return "APFL_ERR_EMPTY_ASSIGNMENT_BEFORE_PARAMETERS";
case APFL_ERR_UNEXPECTED_EXPRESSION:
return "APFL_ERR_UNEXPECTED_EXPRESSION";
case APFL_ERR_INVALID_ASSIGNMENT_LHS:
return "APFL_ERR_INVALID_ASSIGNMENT_LHS";
case APFL_ERR_EMPTY_ASSIGNMENT:
return "APFL_ERR_EMPTY_ASSIGNMENT";
case APFL_ERR_ONLY_ONE_EXPAND_ALLOWED:
return "APFL_ERR_ONLY_ONE_EXPAND_ALLOWED";
case APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS:
return "APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS";
case APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS:
return "APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS";
case APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS:
return "APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS";
}
return "<unknown error>";
}
const char *
apfl_error_as_const_string(struct apfl_error error)
{
switch (error.type) {
case APFL_ERR_MALLOC_FAILED:
return apfl_messages.could_not_alloc_mem;
case APFL_ERR_INPUT_ERROR:
return apfl_messages.input_error_while_parsing;
case APFL_ERR_UNEXPECTED_EOF:
return apfl_messages.unexpected_end_of_file;
default:
return NULL;
}
}
static bool
format_error(struct apfl_format_writer w, struct apfl_error error)
{
switch (error.type) {
case APFL_ERR_MALLOC_FAILED:
return apfl_format_put_string(w, apfl_messages.could_not_alloc_mem);
case APFL_ERR_INPUT_ERROR:
return apfl_format_put_string(w, apfl_messages.input_error_while_parsing);
case APFL_ERR_UNEXPECTED_EOF:
return apfl_format_put_string(w, apfl_messages.unexpected_end_of_file);
case APFL_ERR_EXPECTED_EQ_AFTER_COLON:
TRY(apfl_format_put_string(w, "Expected '=' after ':' at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_UNEXPECTED_BYTE:
TRY(apfl_format_put_string(w, "Unexpected byte '"));
TRY(apfl_format_put_char(w, error.byte));
TRY(apfl_format_put_string(w, "' (0x"));
TRY(apfl_format_put_hexbyte(w, (unsigned char)error.byte));
TRY(apfl_format_put_string(w, ") at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_UNEXPECTED_BYTE_IN_NUMBER:
TRY(apfl_format_put_string(w, "Unexpected byte '"));
TRY(apfl_format_put_char(w, error.byte));
TRY(apfl_format_put_string(w, "' while parsing number at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_EXPECTED_DIGIT:
TRY(apfl_format_put_string(w, "Expected a digit at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_EXPECTED_HEX_IN_HEX_ESCAPE:
TRY(apfl_format_put_string(w, "Expected a hex-digit in hex escape at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_INVALID_ESCAPE_SEQUENCE:
TRY(apfl_format_put_string(w, "Invalid escape sequence \\"));
TRY(apfl_format_put_char(w, error.byte));
TRY(apfl_format_put_string(w, " at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_NO_LINEBREAK_AFTER_CONTINUE_LINE:
TRY(apfl_format_put_string(w, "No line break (after optional comments) after \\ at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_UNEXPECTED_TOKEN:
TRY(apfl_format_put_string(w, "Unexpected `"));
TRY(apfl_format_put_string(w, apfl_token_type_name(error.token_type)));
TRY(apfl_format_put_string(w, "` token at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_MISMATCHING_CLOSING_BRACKET:
TRY(apfl_format_put_string(w, "Closing `"));
TRY(apfl_format_put_string(w, apfl_token_type_name(error.token_type)));
TRY(apfl_format_put_string(w, "` token at "));
TRY(apfl_format_put_pos(w, error.position));
TRY(apfl_format_put_string(w, "Does not match opening `"));
TRY(apfl_format_put_string(w, apfl_token_type_name(error.token_type2)));
TRY(apfl_format_put_string(w, "` at "));
TRY(apfl_format_put_pos(w, error.position2));
return true;
case APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN:
TRY(apfl_format_put_string(w, "Unexpected end of file after `"));
TRY(apfl_format_put_string(w, apfl_token_type_name(error.token_type)));
TRY(apfl_format_put_string(w, "` token at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_STATEMENTS_BEFORE_PARAMETERS:
TRY(apfl_format_put_string(w, "Unexpected statements before parameters near "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_EMPTY_ASSIGNMENT_BEFORE_PARAMETERS:
TRY(apfl_format_put_string(w, "Unexpected empty assignment before parameters near "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_UNEXPECTED_EXPRESSION:
TRY(apfl_format_put_string(w, "Unexpected expression near "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_INVALID_ASSIGNMENT_LHS:
TRY(apfl_format_put_string(w, "Invalid left hand side of assignment near "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_EMPTY_ASSIGNMENT:
TRY(apfl_format_put_string(w, "Empty assignment at "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_ONLY_ONE_EXPAND_ALLOWED:
TRY(apfl_format_put_string(w, "Only one expansion (~) is allowed per level, near "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS:
TRY(apfl_format_put_string(w, "Unexpected constant in member access near "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS:
TRY(apfl_format_put_string(w, "Unexpected expression in member access near "));
TRY(apfl_format_put_pos(w, error.position));
return true;
case APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS:
TRY(apfl_format_put_string(w, "Unexpected blank (\"_\") in member access near "));
TRY(apfl_format_put_pos(w, error.position));
return true;
}
TRY(apfl_format_put_string(w, "Unknown error "));
TRY(apfl_format_put_int(w, (int)error.type));
return true;
}
bool
apfl_error_print(struct apfl_error error, FILE *file)
{
struct apfl_format_writer w = apfl_format_file_writer(file);
TRY(format_error(w, error));
TRY(apfl_format_put_char(w, '\n'));
return true;
}
bool
apfl_error_as_string(struct apfl_error error, struct apfl_allocator allocator, struct apfl_string *out)
{
struct apfl_string_builder builder = apfl_string_builder_init(allocator);
TRY(format_error(apfl_format_string_writer(&builder), error));
*out = apfl_string_builder_move_string(&builder);
return true;
}
struct apfl_error
apfl_error_simple(enum apfl_error_type type)
{
return (struct apfl_error) { .type = type };
}
bool
apfl_error_is_fatal_type(enum apfl_error_type type)
{
switch (type) {
case APFL_ERR_MALLOC_FAILED:
return true;
default:
return false;
}
}