Skip to content

Commit 831e7e0

Browse files
committed
refactor parse errors
1 parent 1526d0f commit 831e7e0

File tree

5 files changed

+81
-38
lines changed

5 files changed

+81
-38
lines changed

include/interpreter/error.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ extern jmp_buf runtime_error_jmp;
3232

3333

3434
void report_lex_err(Lexer *lexer, bool print_offending, char *msg);
35-
void report_parse_err(Parser *parser, char *msg);
35+
void report_all_parse_errors(ParseError *head, char *full_input);
36+
void report_parse_err(ParseError *error, char *full_input);
3637

3738
#ifdef DEBUG
3839
#define REPORT_RUNTIME_ERROR(...) \

include/interpreter/parser.h

+15-5
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,41 @@
1919

2020
#include <stdbool.h>
2121

22+
#include "interpreter/lexer.h"
2223
#include "nicc/nicc.h"
2324
#include "sac/sac.h"
2425

2526

2627
/* types */
28+
typedef struct parse_error_t ParseError;
29+
struct parse_error_t {
30+
char *msg;
31+
Token *failed; // the token that caused the error
32+
ParseError *next;
33+
};
34+
2735
typedef struct {
2836
Arena *ast_arena; // memory arena to put where all AST nodes live on
2937
ArrayList *tokens; // stream of tokens from the lexer
3038
size_t token_pos; // index of current token being processed
3139
char *input; // handle to the source code
32-
bool had_error;
33-
size_t n_errors;
3440
int source_line;
41+
size_t n_errors;
42+
ParseError *perr_head; // linked list of parse errors
43+
ParseError *perr_tail; // final parse error node
3544
} Parser;
3645

3746
typedef struct {
38-
bool had_error;
47+
size_t n_errors;
48+
ParseError *perr_head;
3949
ArrayList stmts;
40-
} StmtsOrErr;
50+
} ParseResult;
4151

4252
/*
4353
* Parses a list of tokens into a list of statements: Arraylist<Stmt>
4454
* The Stmt objects in the list are the first nodes in an AST.
4555
*/
46-
StmtsOrErr parse(Arena *ast_arena, ArrayList *tokens, char *input);
56+
ParseResult parse(Arena *ast_arena, ArrayList *tokens, char *input);
4757

4858

4959
#endif /* PARSER_H */

src/interpreter/error.c

+12-8
Original file line numberDiff line numberDiff line change
@@ -119,20 +119,24 @@ void report_lex_err(Lexer *lexer, bool print_offending, char *msg)
119119
free(bf.alloced_buffer);
120120
}
121121

122-
void report_parse_err(Parser *parser, char *msg)
122+
void report_all_parse_errors(ParseError *head, char *full_input)
123123
{
124-
parser->had_error = true;
125-
Token *failed = arraylist_get(parser->tokens, parser->token_pos);
126-
REPORT_IMPL("%s[line %zu]%s: Error during parsing: %s\n", ANSI_BOLD_START, failed->line + 1,
127-
ANSI_BOLD_END, msg);
124+
for (ParseError *error = head; error != NULL; error = error->next)
125+
report_parse_err(error, full_input);
126+
}
127+
128+
void report_parse_err(ParseError *error, char *full_input)
129+
{
130+
REPORT_IMPL("%s[line %zu]%s: Error during parsing: %s\n", ANSI_BOLD_START,
131+
error->failed->line + 1, ANSI_BOLD_END, error->msg);
128132

129-
char *line = offending_line(parser->input, failed->line);
133+
char *line = offending_line(full_input, error->failed->line);
130134
if (line == NULL) {
131135
REPORT_IMPL("Internal error: could not find line where parse error occured");
132136
return;
133137
}
134138

135-
ErrBuf bf = offending_line_from_offset(line, failed->start);
136-
err_buf_print(bf, failed->end - failed->start);
139+
ErrBuf bf = offending_line_from_offset(line, error->failed->start);
140+
err_buf_print(bf, error->failed->end - error->failed->start);
137141
free(bf.alloced_buffer);
138142
}

src/interpreter/parser.c

+37-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <stdarg.h>
1818
#include <stdbool.h>
1919
#include <stdlib.h>
20+
#include <string.h>
2021

2122
#include "interpreter/ast.h"
2223
#include "interpreter/error.h"
@@ -77,6 +78,19 @@ static ArenaLL arguments(Parser *parser);
7778

7879
static void handle_parse_err(Parser *parser, char *msg);
7980

81+
static ParseError *new_parse_error(Arena *arena, char *msg, Token *failed)
82+
{
83+
ParseError *error = m_arena_alloc_struct(arena, ParseError);
84+
size_t msg_len = strlen(msg); // TODO: could we avoid strlen somehow?
85+
char *msg_arena = m_arena_alloc(arena, msg_len + 1);
86+
memcpy(msg_arena, msg, msg_len + 1);
87+
error->msg = msg_arena;
88+
error->failed = failed;
89+
error->next = NULL;
90+
91+
return error;
92+
}
93+
8094
/* util/helper functions */
8195
static Token *peek(Parser *parser)
8296
{
@@ -196,13 +210,24 @@ static bool match_either(Parser *parser, unsigned int n, ...)
196210
static void handle_parse_err(Parser *parser, char *msg)
197211
{
198212
parser->n_errors++;
213+
Token *failed = arraylist_get(parser->tokens, parser->token_pos);
214+
ParseError *error = new_parse_error(parser->ast_arena, msg, failed);
215+
if (parser->perr_head == NULL) {
216+
parser->perr_head = error;
217+
parser->perr_tail = error;
218+
} else {
219+
parser->perr_tail->next = error;
220+
parser->perr_tail = error;
221+
}
222+
223+
// report_parse_err(parser, msg);
224+
199225
if (parser->n_errors >= MAX_PARSE_ERRORS) {
200-
report_parse_err(parser, msg);
201226
REPORT_IMPL("TOO MANY PARSE ERRORS. Quitting now ...\n");
202227
TODO_LOG("Gracfully quit after deciding to stop parsing.");
203228
exit(1);
204229
}
205-
report_parse_err(parser, msg);
230+
206231
advance(parser);
207232
}
208233

@@ -884,26 +909,31 @@ static ArenaLL arguments(Parser *parser)
884909
}
885910

886911

887-
StmtsOrErr parse(Arena *ast_arena, ArrayList *tokens, char *input)
912+
ParseResult parse(Arena *ast_arena, ArrayList *tokens, char *input)
888913
{
889914
Parser parser = { .ast_arena = ast_arena,
890915
.tokens = tokens,
891916
.token_pos = 0,
892917
.input = input,
893-
.had_error = false,
894-
.n_errors = 0 };
918+
.n_errors = 0,
919+
.perr_head = NULL,
920+
.perr_tail = NULL };
895921
ArrayList statements;
896922
arraylist_init(&statements, sizeof(Stmt *));
897923

898924
/* edge case: empty source file */
899925
ignore(&parser, t_newline);
900926
if (check(&parser, t_eof))
901-
return (StmtsOrErr){ .had_error = parser.had_error, .stmts = statements };
927+
return (ParseResult){ .n_errors = parser.n_errors,
928+
.perr_head = parser.perr_head,
929+
.stmts = statements };
902930

903931
while (!check(&parser, t_eof)) {
904932
Stmt *stmt = declaration(&parser);
905933
arraylist_append(&statements, &stmt);
906934
}
907935

908-
return (StmtsOrErr){ .had_error = parser.had_error, .stmts = statements };
936+
return (ParseResult){ .n_errors = parser.n_errors,
937+
.perr_head = parser.perr_head,
938+
.stmts = statements };
909939
}

src/main.c

+15-17
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,23 @@ void interactive(int argc, char **argv)
4444
prompt_init(&prompt, "-> ");
4545

4646
while (prompt_run(&prompt)) {
47+
m_arena_clear(&ast_arena);
48+
4749
Lexer lex_result = lex(&ast_arena, prompt.buf, prompt.buf_len);
4850
if (lex_result.had_error) {
49-
m_arena_clear(&ast_arena);
5051
arraylist_free(&lex_result.tokens);
5152
continue;
5253
}
5354

54-
StmtsOrErr stmts = parse(&ast_arena, &lex_result.tokens, prompt.buf);
55-
if (stmts.had_error) {
56-
m_arena_clear(&ast_arena);
57-
arraylist_free(&lex_result.tokens);
58-
arraylist_free(&stmts.stmts);
59-
continue;
60-
}
61-
62-
interpreter_run(&interpreter, &stmts.stmts);
55+
ParseResult parse_result = parse(&ast_arena, &lex_result.tokens, prompt.buf);
56+
if (parse_result.n_errors == 0)
57+
interpreter_run(&interpreter, &parse_result.stmts);
58+
else
59+
report_all_parse_errors(parse_result.perr_head, prompt.buf);
6360

64-
m_arena_clear(&ast_arena);
61+
// TODO: these should maybe be reset (e.i. set size to 0), not freed
6562
arraylist_free(&lex_result.tokens);
66-
arraylist_free(&stmts.stmts);
63+
arraylist_free(&parse_result.stmts);
6764
}
6865

6966
ast_arena_release(&ast_arena);
@@ -150,8 +147,9 @@ int main(int argc, char **argv)
150147
#endif /* DEBUG_PERF */
151148

152149
/* parse */
153-
StmtsOrErr stmts = parse(&ast_arena, &lex_result.tokens, input);
154-
if (stmts.had_error) {
150+
ParseResult parse_result = parse(&ast_arena, &lex_result.tokens, input);
151+
if (parse_result.n_errors != 0) {
152+
report_all_parse_errors(parse_result.perr_head, input);
155153
exit_code = 1;
156154
goto defer_stms;
157155
}
@@ -161,7 +159,7 @@ int main(int argc, char **argv)
161159
parse_elapsed = (double)(end_time - start_time) / CLOCKS_PER_SEC;
162160
#endif /* DEBUG_PERF */
163161
#ifdef DEBUG
164-
ast_print(&stmts.stmts);
162+
ast_print(&parse_result.stmts);
165163
#endif /* DEBUG */
166164

167165
#ifdef DEBUG
@@ -172,7 +170,7 @@ int main(int argc, char **argv)
172170
#endif /* DEBUG_PERF */
173171

174172
/* interpret */
175-
exit_code = interpret(&stmts.stmts, argc - 1, argv + 1);
173+
exit_code = interpret(&parse_result.stmts, argc - 1, argv + 1);
176174

177175
#ifdef DEBUG_PERF
178176
end_time = clock();
@@ -187,7 +185,7 @@ int main(int argc, char **argv)
187185

188186
/* clean up */
189187
defer_stms:
190-
arraylist_free(&stmts.stmts);
188+
arraylist_free(&parse_result.stmts);
191189
defer_tokens:
192190
ast_arena_release(&ast_arena);
193191
arraylist_free(&lex_result.tokens);

0 commit comments

Comments
 (0)