#include #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"; case APFL_ERR_NOT_IMPLEMENTED: return "APFL_ERR_NOT_IMPLEMENTED"; } return ""; } 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; case APFL_ERR_NOT_IMPLEMENTED: return apfl_messages.feature_not_implemented; 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; case APFL_ERR_NOT_IMPLEMENTED: TRY(apfl_format_put_string(w, apfl_messages.feature_not_implemented)); 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, &builder); 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: case APFL_ERR_INPUT_ERROR: return true; default: return false; } }