Add formatter abstraction for errors
This will allow us to format errors as strings later by implementing a different format writer.
This commit is contained in:
parent
9ce5c20736
commit
f8bab311d7
5 changed files with 203 additions and 101 deletions
|
|
@ -10,6 +10,7 @@ libapfl_a_SOURCES += context.c
|
|||
libapfl_a_SOURCES += error.c
|
||||
libapfl_a_SOURCES += eval.c
|
||||
libapfl_a_SOURCES += expr.c
|
||||
libapfl_a_SOURCES += format.c
|
||||
libapfl_a_SOURCES += gc.c
|
||||
libapfl_a_SOURCES += hashmap.c
|
||||
libapfl_a_SOURCES += internal.c
|
||||
|
|
@ -28,6 +29,7 @@ apfl_internal_headers += alloc.h
|
|||
apfl_internal_headers += bytecode.h
|
||||
apfl_internal_headers += compile.h
|
||||
apfl_internal_headers += context.h
|
||||
apfl_internal_headers += format.h
|
||||
apfl_internal_headers += gc.h
|
||||
apfl_internal_headers += hashmap.h
|
||||
apfl_internal_headers += internal.h
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ struct apfl_error {
|
|||
char byte;
|
||||
};
|
||||
|
||||
void apfl_error_print(struct apfl_error, FILE *);
|
||||
bool apfl_error_print(struct apfl_error, FILE *);
|
||||
|
||||
struct apfl_error apfl_error_simple(enum apfl_error_type);
|
||||
bool apfl_error_is_fatal_type(enum apfl_error_type);
|
||||
|
|
|
|||
208
src/error.c
208
src/error.c
|
|
@ -1,11 +1,15 @@
|
|||
#include <stdio.h>
|
||||
#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)
|
||||
{
|
||||
|
|
@ -61,132 +65,136 @@ apfl_error_type_name(enum apfl_error_type type)
|
|||
return "<unknown error>";
|
||||
}
|
||||
|
||||
void
|
||||
apfl_error_print(struct apfl_error error, FILE *file)
|
||||
static bool
|
||||
format_pos(struct apfl_format_writer w, struct apfl_position pos)
|
||||
{
|
||||
TRY(apfl_format_put_int(w, pos.line));
|
||||
TRY(apfl_format_put_string(w, ":"));
|
||||
TRY(apfl_format_put_int(w, pos.col));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
format_error(struct apfl_format_writer w, struct apfl_error error)
|
||||
{
|
||||
switch (error.type) {
|
||||
case APFL_ERR_MALLOC_FAILED:
|
||||
fprintf(file, "Could not allocate memory\n");
|
||||
return;
|
||||
return apfl_format_put_string(w, "Could not allocate memory");
|
||||
case APFL_ERR_INPUT_ERROR:
|
||||
fprintf(file, "Input error while parsing\n");
|
||||
return;
|
||||
return apfl_format_put_string(w, "Input error while parsing");
|
||||
case APFL_ERR_UNEXPECTED_EOF:
|
||||
fprintf(file, "Unexpected end of file\n");
|
||||
return;
|
||||
return apfl_format_put_string(w, "Unexpected end of file");
|
||||
case APFL_ERR_EXPECTED_EQ_AFTER_COLON:
|
||||
fprintf(file, "Expected '=' after ':' at " POSFMT "\n", POSARGS);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "Expected '=' after ':' at "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_UNEXPECTED_BYTE:
|
||||
fprintf(file, "Unexpected byte '%c' (0x%X) at " POSFMT "\n", error.byte, (unsigned)error.byte, POSARGS);
|
||||
return;
|
||||
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(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_UNEXPECTED_BYTE_IN_NUMBER:
|
||||
fprintf(file, "Unexpected byte '%c' while parsing number at " POSFMT "\n", error.byte, POSARGS);
|
||||
return;
|
||||
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(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_EXPECTED_DIGIT:
|
||||
fprintf(file, "Expected a digit at " POSFMT "\n", POSARGS);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "Expected a digit at "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_EXPECTED_HEX_IN_HEX_ESCAPE:
|
||||
fprintf(file, "Expected a hex-digit in hex escape at " POSFMT "\n", POSARGS);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "Expected a hex-digit in hex escape at "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_INVALID_ESCAPE_SEQUENCE:
|
||||
fprintf(file, "Invalid escape sequence \\%c at " POSFMT "\n", error.byte, POSARGS);
|
||||
return;
|
||||
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(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_NO_LINEBREAK_AFTER_CONTINUE_LINE:
|
||||
fprintf(file, "No line break (after optional comments) after \\ at " POSFMT "\n", POSARGS);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "No line break (after optional comments) after \\ at "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_UNEXPECTED_TOKEN:
|
||||
fprintf(file, "Unexpected `%s` token at " POSFMT "\n", apfl_token_type_name(error.token_type), POSARGS);
|
||||
return;
|
||||
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(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_MISMATCHING_CLOSING_BRACKET:
|
||||
fprintf(
|
||||
file,
|
||||
"Closing `%s` token at " POSFMT " does not match opening `%s` at " POSFMT "\n",
|
||||
apfl_token_type_name(error.token_type),
|
||||
POSARGS,
|
||||
apfl_token_type_name(error.token_type2),
|
||||
POS2ARGS
|
||||
);
|
||||
return;
|
||||
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(format_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(format_pos(w, error.position2));
|
||||
return true;
|
||||
case APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected end of file after `%s` token at " POSFMT "\n",
|
||||
apfl_token_type_name(error.token_type),
|
||||
POSARGS
|
||||
);
|
||||
return;
|
||||
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(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_STATEMENTS_BEFORE_PARAMETERS:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected statements before parameters near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "Unexpected statements before parameters near "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_EMPTY_ASSIGNMENT_BEFORE_PARAMETERS:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected empty assignment before parameters near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "Unexpected empty assignment before parameters near "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_UNEXPECTED_EXPRESSION:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected expression near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "Unexpected expression near "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_INVALID_ASSIGNMENT_LHS:
|
||||
fprintf(
|
||||
file,
|
||||
"Invalid left hand side of assignment near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "Invalid left hand side of assignment near "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_EMPTY_ASSIGNMENT:
|
||||
fprintf(
|
||||
file,
|
||||
"Empty assignment at " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
return;
|
||||
TRY(apfl_format_put_string(w, "Empty assignment at "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_ONLY_ONE_EXPAND_ALLOWED:
|
||||
fprintf(
|
||||
file,
|
||||
"Only one expansion (~) is allowed per level, near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
break;
|
||||
TRY(apfl_format_put_string(w, "Only one expansion (~) is allowed per level, near "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected constant in member access near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
break;
|
||||
TRY(apfl_format_put_string(w, "Unexpected constant in member access near "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected expression in member access near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
break;
|
||||
TRY(apfl_format_put_string(w, "Unexpected expression in member access near "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_UNEXPECTED_BLANK_IN_MEMBER_ACCESS:
|
||||
fprintf(
|
||||
file,
|
||||
"Unexpected blank (\"_\") in member access near " POSFMT "\n",
|
||||
POSARGS
|
||||
);
|
||||
break;
|
||||
TRY(apfl_format_put_string(w, "Unexpected blank (\"_\") in member access near "));
|
||||
TRY(format_pos(w, error.position));
|
||||
return true;
|
||||
case APFL_ERR_NOT_IMPLEMENTED:
|
||||
fprintf(
|
||||
file,
|
||||
"Feature not implemented\n"
|
||||
);
|
||||
TRY(apfl_format_put_string(w, "Feature not implemented"));
|
||||
return true;
|
||||
}
|
||||
|
||||
fprintf(file, "Unknown error %d\n", (int)error.type);
|
||||
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;
|
||||
}
|
||||
|
||||
struct apfl_error
|
||||
|
|
|
|||
61
src/format.c
Normal file
61
src/format.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "apfl.h"
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#define WRITE(w, buf, len) w.write(w.opaque, buf, len)
|
||||
#define TRY(x) if (!(x)) return false;
|
||||
|
||||
static bool
|
||||
write_file(void *opaque, const char *buf, size_t len)
|
||||
{
|
||||
FILE *f = opaque;
|
||||
return fwrite(buf, len, 1, f) == 1;
|
||||
}
|
||||
|
||||
struct apfl_format_writer
|
||||
apfl_format_file_writer(FILE *f)
|
||||
{
|
||||
return (struct apfl_format_writer) {
|
||||
.write = write_file,
|
||||
.opaque = f,
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
apfl_format_put_string_view(struct apfl_format_writer w, struct apfl_string_view sv)
|
||||
{
|
||||
return WRITE(w, sv.bytes, sv.len);
|
||||
}
|
||||
|
||||
#define PUT_INT_BUFSIZE 21 // ceil(log10(2**64)) + 1
|
||||
|
||||
bool
|
||||
apfl_format_put_int(struct apfl_format_writer w, int i)
|
||||
{
|
||||
char buf[PUT_INT_BUFSIZE];
|
||||
size_t len = snprintf(buf, PUT_INT_BUFSIZE, "%d", i);
|
||||
assert(len < PUT_INT_BUFSIZE);
|
||||
return WRITE(w, buf, len);
|
||||
}
|
||||
|
||||
bool
|
||||
apfl_format_put_char(struct apfl_format_writer w, char c)
|
||||
{
|
||||
return WRITE(w, &c, 1);
|
||||
}
|
||||
|
||||
#define PUT_HEXBYTE_BUFSIZE 3
|
||||
|
||||
bool
|
||||
apfl_format_put_hexbyte(struct apfl_format_writer w, unsigned char c)
|
||||
{
|
||||
char buf[PUT_HEXBYTE_BUFSIZE];
|
||||
size_t len = snprintf(buf, PUT_HEXBYTE_BUFSIZE, "%x", (unsigned) c);
|
||||
assert(len < PUT_HEXBYTE_BUFSIZE);
|
||||
return WRITE(w, buf, len);
|
||||
}
|
||||
31
src/format.h
Normal file
31
src/format.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef APFL_FORMAT_H
|
||||
#define APFL_FORMAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "apfl.h"
|
||||
|
||||
struct apfl_format_writer {
|
||||
bool (*write)(void *, const char *buf, size_t len);
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
struct apfl_format_writer apfl_format_file_writer(FILE *f);
|
||||
|
||||
bool apfl_format_put_string_view(struct apfl_format_writer, struct apfl_string_view);
|
||||
#define apfl_format_put_string(w, s) apfl_format_put_string_view((w), apfl_string_view_from(s))
|
||||
bool apfl_format_put_int(struct apfl_format_writer, int);
|
||||
bool apfl_format_put_char(struct apfl_format_writer, char);
|
||||
bool apfl_format_put_hexbyte(struct apfl_format_writer, unsigned char);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue