Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modular error printing #50

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion src/bar_token.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ void BarToken_destroy_at(BarToken* token) {
return;
}

int BarToken_print(BarToken* token, FILE* stream) {
int BarToken_print(const BarToken* token, FILE* stream) {

if(token == NULL || token->content == NULL || stream == NULL) {
return ERROR_CODE_INVALID_ARGUMENT;
Expand Down
2 changes: 1 addition & 1 deletion src/bar_token.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ void BarToken_set_content(BarToken* token, char* content, size_t content_length)

void BarToken_destroy_at(BarToken* token);

int BarToken_print(BarToken* token, FILE* stream);
int BarToken_print(const BarToken* token, FILE* stream);

// --------
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/error_codes.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ enum ErrorCodes {

ERROR_CODE_CONFIG_WRITE_AFTER_READ,

ERROR_CODE_NOTE_COMPILER_ERROR,

};

// --------
Expand Down
2 changes: 1 addition & 1 deletion src/instrument.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ int Instrument_add_notes_for_bar(Instrument* instrument, NoteProvider note_provi
}

if(status != 0) {
return status;
return ERROR_CODE_NOTE_COMPILER_ERROR;
}

if(!instrument_done) {
Expand Down
79 changes: 71 additions & 8 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
static bool destroy_token(Token* token);
static bool destroy_bar_token(BarToken* bar);

static int play_track_token(Token* track);
static int play_track_token(Interpreter* interpreter, Token* track);

static int play_bar_token(Player* player, Instrument* instrument, BarToken* bar);
static int play_bar_token(Interpreter* interpreter, Player* player, Instrument* instrument, BarToken* bar);

static int print_bar_length_error(const Interpreter* interpreter, FILE* stream, const BarToken* bar, int error_code);

// --------

Expand All @@ -32,7 +34,7 @@ static bool destroy_bar_token(BarToken* bar) {
BarToken_destroy_at(bar);
return true;
}
static int play_track_token(Token* track) {
static int play_track_token(Interpreter* interpreter, Token* track) {

if(track == NULL || track->type != TOKEN_TRACK) {
return ERROR_CODE_INVALID_ARGUMENT;
Expand Down Expand Up @@ -69,7 +71,7 @@ static int play_track_token(Token* track) {
}

while(status == 0 && destroy_bar_token(&bar) && !lexer.super.finished && (status = TrackLexer_get_next_bar(&lexer, &bar)) == 0) {
status = play_bar_token(&player, &instrument, &bar);
status = play_bar_token(interpreter, &player, &instrument, &bar);
}

if(status == 0) {
Expand All @@ -84,7 +86,7 @@ static int play_track_token(Token* track) {
return status;
}

static int play_bar_token(Player* player, Instrument* instrument, BarToken* bar) {
static int play_bar_token(Interpreter* interpreter, Player* player, Instrument* instrument, BarToken* bar) {

NoteCompiler compiler;
int status;
Expand All @@ -95,10 +97,35 @@ static int play_bar_token(Player* player, Instrument* instrument, BarToken* bar)
return ERROR_CODE_INVALID_ARGUMENT;
}

NoteCompiler_init_at(&compiler, (char*) (bar->content), bar->content_length);
status = NoteCompiler_init_at(&compiler, bar, interpreter->filename);
if(status != 0) {
return status;
}

status = Instrument_add_notes_for_bar(instrument, &NoteCompiler_get_next_note, &compiler);

if(status != 0) {

switch(status) {

case ERROR_CODE_NOTE_COMPILER_ERROR:

if(NoteCompiler_print_error(&compiler, stderr) == 0) {
interpreter->printed_err_msg = true;
}
break;

case ERROR_CODE_BAR_TOO_SHORT:
case ERROR_CODE_BAR_TOO_LONG:

if(print_bar_length_error(interpreter, stderr, bar, status) == 0) {
interpreter->printed_err_msg = true;
}
break;

default:
break;
}
return status;
}

Expand All @@ -110,6 +137,41 @@ static int play_bar_token(Player* player, Instrument* instrument, BarToken* bar)
return Player_play_bar(player);
}

static int print_bar_length_error(const Interpreter* interpreter, FILE* stream, const BarToken* bar, int error_code) {

int status = 0;

if(interpreter == NULL || stream == NULL || bar == NULL) {
return ERROR_CODE_INVALID_ARGUMENT;
}

if(bar->content == NULL) {
return ERROR_CODE_INVALID_STATE;
}

fprintf(stream, "%s:%u:%u: ", interpreter->filename, bar->line, bar->col);

switch(error_code) {

case ERROR_CODE_BAR_TOO_SHORT:
fputs("Bar too short:\n", stream);
break;

case ERROR_CODE_BAR_TOO_LONG:
fputs("Bar too long:\n", stream);
break;

default:
fputs("Bar length mismatch:\n", stream);
break;
}

status = BarToken_print(bar, stream);
fputs("\n", stream);

return status;
}

// --------

void Interpreter_init_at(Interpreter* interpreter) {
Expand All @@ -119,6 +181,7 @@ void Interpreter_init_at(Interpreter* interpreter) {
interpreter->error_state = INTERPRETER_ERROR_STATE_UNKNOWN_ERROR;
interpreter->finished = false;
interpreter->error = false;
interpreter->printed_err_msg = false;

return;
}
Expand Down Expand Up @@ -194,7 +257,7 @@ int Interpreter_interpret(Interpreter* interpreter, FILE* stream) {

case TOKEN_TRACK:

if((status = play_track_token(&token)) != 0) {
if((status = play_track_token(interpreter, &token)) != 0) {
interpreter->finished = true;
interpreter->error = true;
interpreter->error_state = INTERPRETER_ERROR_STATE_INTERNAL_ERROR;
Expand Down Expand Up @@ -223,7 +286,7 @@ int Interpreter_interpret(Interpreter* interpreter, FILE* stream) {
status = status != 0? status: ERROR_CODE_UNKNOWN_ERROR;
}

if(interpreter->error) {
if(interpreter->error && !interpreter->printed_err_msg) {

switch(interpreter->error_state) {

Expand Down
3 changes: 2 additions & 1 deletion src/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ typedef enum InterpreterState {

typedef enum InterpreterErrorState {
INTERPRETER_ERROR_STATE_UNKNOWN_ERROR = 0,
INTERPRETER_ERROR_STATE_UNEXPECTED_TOKEN,
INTERPRETER_ERROR_STATE_INTERNAL_ERROR,
INTERPRETER_ERROR_STATE_UNEXPECTED_TOKEN,
NUM_INTERPRETER_ERROR_STATES,
} InterpreterErrorState;

Expand All @@ -35,6 +35,7 @@ struct Interpreter {
InterpreterErrorState error_state;
bool finished;
bool error;
bool printed_err_msg;
};

// --------
Expand Down
63 changes: 53 additions & 10 deletions src/note_compiler.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include <stdio.h>
#include <stdlib.h>

#include <string.h>
Expand All @@ -23,24 +22,24 @@ static int finish_note(NoteCompiler* compiler, Note* note);

static int advance(NoteCompiler* compiler) {

if(compiler->position >= compiler->bar_length) {
if(compiler->position >= compiler->bar->content_length) {
compiler->finished = true;
return END_OF_BAR;
}

compiler->symbol = (compiler->bar)[compiler->position];
compiler->symbol = (compiler->bar->content)[compiler->position];
(compiler->position)++;

return (char) (compiler->symbol);
}

static int peek(NoteCompiler* compiler) {

if(compiler->position >= compiler->bar_length) {
if(compiler->position >= compiler->bar->content_length) {
return END_OF_BAR;
}

return (char) ((compiler->bar)[compiler->position]);
return (char) ((compiler->bar->content)[compiler->position]);
}

static int finish_note(NoteCompiler* compiler, Note* note) {
Expand Down Expand Up @@ -145,18 +144,21 @@ static int finish_note(NoteCompiler* compiler, Note* note) {

// --------

int NoteCompiler_init_at(NoteCompiler* compiler, char* bar, size_t length) {
int NoteCompiler_init_at(NoteCompiler* compiler, BarToken* bar, char* filename) {

if(compiler == NULL || bar == NULL || bar->content == NULL || bar->content_length == 0) {
return ERROR_CODE_INVALID_ARGUMENT;
}

compiler->bar = bar;
compiler->state = NOTE_COMPILER_STATE_EXPECTING_NOTE;
compiler->bar_length = 0;
compiler->position = 0;
compiler->state = NOTE_COMPILER_STATE_EXPECTING_NOTE;
compiler->error_state = NOTE_COMPILER_ERROR_STATE_UNKNOWN_ERROR;
compiler->symbol = '\0';
compiler->finished = false;
compiler->error = false;

compiler->bar = bar;
compiler->bar_length = length;
compiler->filename = filename == NULL? "": filename;

return 0;
}
Expand Down Expand Up @@ -210,6 +212,7 @@ int NoteCompiler_get_next_note(void* compiler, Note* note, bool* finished) {
default:
comp->error = true;
comp->finished = true;
comp->error_state = NOTE_COMPILER_ERROR_STATE_UNEXPECTED_CHARACTER;
return ERROR_CODE_UNEXPECTED_CHARACTER;
}
default:
Expand All @@ -226,3 +229,43 @@ int NoteCompiler_get_next_note(void* compiler, Note* note, bool* finished) {
return 0;
}

int NoteCompiler_print_error(const NoteCompiler* compiler, FILE* stream) {

int status = 0;

if(compiler == NULL || !(compiler->error)) {
return ERROR_CODE_INVALID_ARGUMENT;
}

if(compiler->bar == NULL || compiler->bar->content == NULL) {
return ERROR_CODE_INVALID_STATE;
}

fprintf(stream, "%s:%u:%u: ", compiler->filename, compiler->bar->line, compiler->bar->col);

switch(compiler->error_state) {

case NOTE_COMPILER_ERROR_STATE_UNEXPECTED_CHARACTER:

fputs("Unexpected character:\n", stream);
BarToken_print(compiler->bar, stream);

if(fprintf(stream, "\n%*s^", (int) (compiler->position - 1), " ") < 0) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're likely gonna use the exact same trick inside the token module; might be worth extracting the string formatting into a helper method.

return ERROR_CODE_UNKNOWN_SYSTEM_ERROR;
}

break;

default:

fputs("Unknown error when reading bar:\n", stream);
BarToken_print(compiler->bar, stream);

break;
}

fputs("\n", stream);

return status;
}

18 changes: 13 additions & 5 deletions src/note_compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// --------

#include <stdbool.h>
#include <stddef.h>

#include "bar_token.h"
#include "note.h"

// --------
Expand All @@ -22,22 +22,30 @@ typedef enum NoteCompilerState {
NUM_NOTE_COMPILER_STATES,
} NoteCompilerState;

typedef enum NoteCompilerErrorState {
NOTE_COMPILER_ERROR_STATE_UNKNOWN_ERROR = 0,
NOTE_COMPILER_ERROR_STATE_UNEXPECTED_CHARACTER,
} NoteCompilerErrorState;

struct NoteCompiler {
char* bar;
NoteCompilerState state;
size_t bar_length;
char* filename;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we pass the filename in the constructor here, we should probably do that for all the other modules as well.
(Maybe not for the interpreter, if the idea is to be able to potentially load modules from different files?)

Also need to think about scope. (Caller needs to guarantee the string stays around for as long as the compiler/lexer whatever is used. This is fine, but should really be documented.)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Thinking more about this, we might want to store the (pointer-to) filename in the tokens instead. There's little sense in having the line information in one place, and the file name in another.)

BarToken* bar;
size_t position;
NoteCompilerState state;
NoteCompilerErrorState error_state;
char symbol;
bool finished;
bool error;
};

// --------

int NoteCompiler_init_at(NoteCompiler* compiler, char* bar, size_t length);
int NoteCompiler_init_at(NoteCompiler* compiler, BarToken* bar, char* filename);

int NoteCompiler_get_next_note(void* compiler, Note* note, bool* finished);

int NoteCompiler_print_error(const NoteCompiler* compiler, FILE* stream);

// --------
#endif

13 changes: 10 additions & 3 deletions src/track_lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,21 +164,28 @@ static int TrackLexer_get_next_bar_internal(AbstractLexer* lexer, BarToken* toke

int TrackLexer_init_at(TrackLexer* lexer, Token* track) {

int status = AbstractLexer_init_at((AbstractLexer*) lexer, 16);
AbstractLexer* super = (AbstractLexer*) lexer;

int status = AbstractLexer_init_at((AbstractLexer*) super, 16);
if(status != 0) {
return status;
}

if(track == NULL || track->type != TOKEN_TRACK || track->content.buffer == NULL) {
((AbstractLexer*) lexer)->error = true;
((AbstractLexer*) lexer)->finished = true;
super->error = true;
super->finished = true;
return ERROR_CODE_INVALID_ARGUMENT;
}

lexer->state = TRACK_LEXER_STATE_START;
lexer->track = track;
lexer->track_position = 0;

super->line = track->line;
super->col = track->col;

update_lineinfo(super);

return 0;
}

Expand Down