From a09112404d40c1b3d5261a314b36e2f71b931f25 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 13 Apr 2020 23:18:27 -0500 Subject: [PATCH] Add better error message on unexpected eos. Show innermost open delimiter --- src/core/parse.c | 59 +++++++++++++++++++++++++++++++++------------ src/core/pp.c | 8 ++++++ src/include/janet.h | 1 + 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/core/parse.c b/src/core/parse.c index 6e479478..4e8bba04 100644 --- a/src/core/parse.c +++ b/src/core/parse.c @@ -26,6 +26,9 @@ #include "util.h" #endif +#define JANET_PARSER_DEAD 0x1 +#define JANET_PARSER_GENERATED_ERROR 0x2 + /* Check if a character is whitespace */ static int is_whitespace(uint8_t c) { return c == ' ' @@ -637,11 +640,30 @@ void janet_parser_eof(JanetParser *parser) { size_t oldline = parser->line; janet_parser_consume(parser, '\n'); if (parser->statecount > 1) { - parser->error = "unexpected end of source"; + JanetParseState *s = parser->states + (parser->statecount - 1); + JanetBuffer *buffer = janet_buffer(40); + janet_buffer_push_cstring(buffer, "unexpected end of source: "); + if (s->flags & PFLAG_PARENS) { + janet_buffer_push_u8(buffer, '('); + } else if (s->flags & PFLAG_SQRBRACKETS) { + janet_buffer_push_u8(buffer, '['); + } else if (s->flags & PFLAG_CURLYBRACKETS) { + janet_buffer_push_u8(buffer, '{'); + } else if (s->flags & PFLAG_STRING) { + janet_buffer_push_u8(buffer, '"'); + } else if (s->flags & PFLAG_LONGSTRING) { + int32_t i; + for (i = 0; i < s->argn; i++) { + janet_buffer_push_u8(buffer, '`'); + } + } + janet_formatbb(buffer, " opened at line %d, column %d", s->line, s->column); + parser->error = (const char *) janet_string(buffer->data, buffer->count); + parser->flag |= JANET_PARSER_GENERATED_ERROR; } parser->line = oldline; parser->column = oldcolumn; - parser->flag = 1; + parser->flag |= JANET_PARSER_DEAD; } enum JanetParserStatus janet_parser_status(JanetParser *parser) { @@ -663,6 +685,7 @@ const char *janet_parser_error(JanetParser *parser) { if (status == JANET_PARSE_ERROR) { const char *e = parser->error; parser->error = NULL; + parser->flag &= ~JANET_PARSER_GENERATED_ERROR; janet_parser_flush(parser); return e; } @@ -766,6 +789,9 @@ static int parsermark(void *p, size_t size) { for (i = 0; i < parser->argcount; i++) { janet_mark(parser->args[i]); } + if (parser->flag & JANET_PARSER_GENERATED_ERROR) { + janet_mark(janet_wrap_string(parser->error)); + } return 0; } @@ -900,7 +926,11 @@ static Janet cfun_parse_error(int32_t argc, Janet *argv) { janet_fixarity(argc, 1); JanetParser *p = janet_getabstract(argv, 0, &janet_parser_type); const char *err = janet_parser_error(p); - if (err) return janet_cstringv(err); + if (err) { + return (p->flag & JANET_PARSER_GENERATED_ERROR) + ? janet_wrap_string(err) + : janet_cstringv(err); + } return janet_wrap_nil(); } @@ -999,31 +1029,30 @@ struct ParserStateGetter { }; static Janet parser_state_delimiters(const JanetParser *_p) { - JanetParser *clone = janet_abstract(&janet_parser_type, sizeof(JanetParser)); - janet_parser_clone(_p, clone); + JanetParser *p = (JanetParser *)_p; size_t i; const uint8_t *str; size_t oldcount; - oldcount = clone->bufcount; - for (i = 0; i < clone->statecount; i++) { - JanetParseState *s = clone->states + i; + oldcount = p->bufcount; + for (i = 0; i < p->statecount; i++) { + JanetParseState *s = p->states + i; if (s->flags & PFLAG_PARENS) { - push_buf(clone, '('); + push_buf(p, '('); } else if (s->flags & PFLAG_SQRBRACKETS) { - push_buf(clone, '['); + push_buf(p, '['); } else if (s->flags & PFLAG_CURLYBRACKETS) { - push_buf(clone, '{'); + push_buf(p, '{'); } else if (s->flags & PFLAG_STRING) { - push_buf(clone, '"'); + push_buf(p, '"'); } else if (s->flags & PFLAG_LONGSTRING) { int32_t i; for (i = 0; i < s->argn; i++) { - push_buf(clone, '`'); + push_buf(p, '`'); } } } - str = janet_string(clone->buf + oldcount, (int32_t)(clone->bufcount - oldcount)); - clone->bufcount = oldcount; + str = janet_string(p->buf + oldcount, (int32_t)(p->bufcount - oldcount)); + p->bufcount = oldcount; return janet_wrap_string(str); } diff --git a/src/core/pp.c b/src/core/pp.c index b0c914fb..828e4c11 100644 --- a/src/core/pp.c +++ b/src/core/pp.c @@ -863,6 +863,14 @@ const uint8_t *janet_formatc(const char *format, ...) { return ret; } +JanetBuffer *janet_formatbb(JanetBuffer *buffer, const char *format, ...) { + va_list args; + va_start(args, format); + janet_formatb(buffer, format, args); + va_end(args); + return buffer; +} + /* Shared implementation between string/format and * buffer/format */ void janet_buffer_format( diff --git a/src/include/janet.h b/src/include/janet.h index 00975136..66cd1813 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -1239,6 +1239,7 @@ JANET_API void janet_description_b(JanetBuffer *buffer, Janet x); #define janet_stringv(str, len) janet_wrap_string(janet_string((str), (len))) JANET_API JanetString janet_formatc(const char *format, ...); JANET_API void janet_formatb(JanetBuffer *bufp, const char *format, va_list args); +JANET_API JanetBuffer *janet_formatbb(JanetBuffer *bufp, const char *format, ...); /* Symbol functions */ JANET_API JanetSymbol janet_symbol(const uint8_t *str, int32_t len);