diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-01-09 19:01:06 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-01-09 19:01:06 -0500 |
commit | c156e952d94049e8dbd8bc9a0f294712c6f253e8 (patch) | |
tree | 107b465473a8c32018c5a2685979fa13c14731fe | |
parent | 6f4074136719bd7ec612e8357596fe3e884c3bf7 (diff) |
better error system
-rw-r--r-- | .gitignore | 1 | ||||
-rwxr-xr-x | build.sh | 5 | ||||
-rw-r--r-- | compatibility.c | 67 | ||||
-rw-r--r-- | err.c | 125 | ||||
-rw-r--r-- | main.c | 21 | ||||
-rwxr-xr-x | test-all.sh | 1 | ||||
-rw-r--r-- | test.toc | 5 | ||||
-rw-r--r-- | tokenizer.c | 5 | ||||
-rw-r--r-- | types.c | 2 | ||||
-rw-r--r-- | types.h | 1 |
10 files changed, 186 insertions, 47 deletions
@@ -9,3 +9,4 @@ vgcore* TAGS tags *.o +compatibility
\ No newline at end of file @@ -26,6 +26,11 @@ RELEASE_FLAGS="-O3 -s -DNDEBUG $WARNINGS -std=c11" if [ "$1" = "release" ]; then FLAGS="$RELEASE_FLAGS $ADDITIONAL_FLAGS" + + COMMAND="$CC compatibility.c -Wall -Wextra -std=c99 -Wpedantic -o compatibility" + echo $COMMAND + $COMMAND || exit 1 + FLAGS="$FLAGS $(./compatibility)" else FLAGS="$DEBUG_FLAGS $ADDITIONAL_FLAGS" fi diff --git a/compatibility.c b/compatibility.c index 705bd07..6a7c32c 100644 --- a/compatibility.c +++ b/compatibility.c @@ -1,5 +1,35 @@ +/* +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +For more information, please refer to <http://unlicense.org/> +*/ + #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <stdint.h> + +typedef float F32; +typedef double F64; +typedef uint32_t U32; +typedef uint64_t U64; int main(void) { int *p; @@ -8,5 +38,40 @@ int main(void) { fprintf(stderr, "You cannot run toc. Sorry.\n"); return EXIT_FAILURE; } - return EXIT_SUCCESS; + + + FILE *f; + f = tmpfile(); + /* endianness test */ + putc(0x12, f); + putc(0x34, f); + putc(0x56, f); + putc(0x78, f); + + if (sizeof(float) != 4 || sizeof(double) != 8) { + fprintf(stderr, "You may experience some problems with toc (sizeof(double) and sizeof(float) are strange)."); + goto unusual; + } else { + F32 flt = -12.3456f; + fwrite(&flt, sizeof flt, 1, f); + F64 dbl = -12.3456; + fwrite(&dbl, sizeof dbl, 1, f); + } + fseek(f, 0L, SEEK_SET); + U32 num; + fread(&num, sizeof num, 1, f); + if (num != 0x78563412) { + /* not little endian */ + goto unusual; + } + U32 flt_rep; + fread(&flt_rep, sizeof flt_rep, 1, f); + if (flt_rep != 0xc1458794) goto unusual; + U64 dbl_rep; + fread(&dbl_rep, sizeof dbl_rep, 1, f); + if (dbl_rep != 0xc028b0f27bb2fec5) goto unusual; + return 0; + unusual: + printf("-DBINFILE_PORTABLE"); + return 0; } @@ -13,17 +13,17 @@ #endif #endif -#if USE_COLORED_TEXT -#define TEXT_ERROR(x) "\x1b[91m" x "\x1b[0m" -#define TEXT_INFO(x) "\x1b[94m" x "\x1b[0m" -#define TEXT_WARN(x) "\x1b[93m" x "\x1b[0m" -#define TEXT_IMPORTANT(x) "\x1b[1m" x "\x1b[0m" -#else -#define TEXT_ERROR(x) x -#define TEXT_INFO(x) x -#define TEXT_WARN(x) x -#define TEXT_IMPORTANT(x) x -#endif +#define TEXT_ERR_START "\x1b[91m" +#define TEXT_ERR_END "\x1b[0m" + +#define TEXT_INDICATOR_START "\x1b[96m" +#define TEXT_INDICATOR_END "\x1b[0m" +#define TEXT_INFO_START "\x1b[94m" +#define TEXT_INFO_END "\x1b[0m" +#define TEXT_WARN_START "\x1b[93m" +#define TEXT_WARN_END "\x1b[0m" +#define TEXT_IMPORTANT_START "\x1b[1m" +#define TEXT_IMPORTANT_END "\x1b[0m" #if defined(TOC_DEBUG) && __STDC_VERSION__ >= 199901 #define ERR_SHOW_SOURCE_LOCATION 1 @@ -50,57 +50,120 @@ static void err_fprint(const char *fmt, ...) { va_end(args); } +static void err_text_err(ErrCtx *ctx, const char *s) { + if (ctx->color_enabled) + err_fprint(TEXT_ERR_START "%s" TEXT_ERR_END, s); + else + err_fprint("%s", s); +} +static void err_text_warn(ErrCtx *ctx, const char *s) { + if (ctx->color_enabled) + err_fprint(TEXT_WARN_START "%s" TEXT_WARN_END, s); + else + err_fprint("%s", s); +} +static void err_text_info(ErrCtx *ctx, const char *s) { + if (ctx->color_enabled) + err_fprint(TEXT_INFO_START "%s" TEXT_INFO_END, s); + else + err_fprint("%s", s); +} +static void err_text_important(ErrCtx *ctx, const char *s) { + if (ctx->color_enabled) + err_fprint(TEXT_IMPORTANT_START "%s" TEXT_IMPORTANT_END, s); + else + err_fprint("%s", s); +} + + + static void err_vfprint(const char *fmt, va_list args) { vfprintf(stderr, fmt, args); } static void err_print_header_(Location where) { + SourcePos start_pos = where.start->pos; + ErrCtx *ctx = start_pos.ctx; + err_text_err(ctx, "error"); if (!where.start) - err_fprint(TEXT_ERROR("error") ":\n"); + err_fprint(":\n"); else { - SourcePos start_pos = where.start->pos; - err_fprint(TEXT_ERROR("error") " at line %lu of %s:\n", (unsigned long)start_pos.line, start_pos.ctx->filename); + err_fprint(" at line %lu of %s:\n", (unsigned long)start_pos.line, ctx->filename); } } static void info_print_header_(Location where) { + SourcePos start_pos = where.start->pos; + ErrCtx *ctx = start_pos.ctx; + err_text_info(ctx, "info"); if (!where.start) - err_fprint(TEXT_INFO("info") ":\n"); + err_fprint(":\n"); else { - SourcePos start_pos = where.start->pos; - err_fprint(TEXT_INFO("info") " at line %lu of %s:\n", (unsigned long)start_pos.line, start_pos.ctx->filename); + err_fprint(" at line %lu of %s:\n", (unsigned long)start_pos.line, ctx->filename); } } static void warn_print_header_(Location where) { + SourcePos start_pos = where.start->pos; + ErrCtx *ctx = start_pos.ctx; + err_text_warn(ctx, "warning"); if (!where.start) - err_fprint(TEXT_WARN("warning") ":\n"); + err_fprint(":\n"); else { - SourcePos start_pos = where.start->pos; - err_fprint(TEXT_WARN("warning") " at line %lu of %s:\n", (unsigned long)start_pos.line, start_pos.ctx->filename); + err_fprint(" at line %lu of %s:\n", (unsigned long)start_pos.line, ctx->filename); } } -static void err_print_location_text_from_str(char *str, U32 start_pos, U32 end_pos) { + +/* + before_pos and after_pos could be things like TEXT_ERR_START or TEXT_ERR_END. + they will not be printed if color output is disabled. +*/ +static void err_print_pos_text(ErrCtx *ctx, U32 start_pos, U32 end_pos) { (void)end_pos; /* TODO */ - const char *text = str + start_pos; - const char *end = strchr(text, '\n'); - int has_newline = end != NULL; + char *str = ctx->str; + char *start = str + start_pos; + char *line_start = start; + char *end = str + end_pos; + + /* go back to last newline / 0 byte */ + while (*line_start != '\0' && *line_start != '\n') --line_start; + if (line_start < start) ++line_start; + + char *line_end = strchr(start, '\n'); + int has_newline = line_end != NULL; if (!has_newline) - end = strchr(text, '\0'); - assert(end); - err_fprint("\there: --> "); - if (!text[0]) + line_end = strchr(start, '\0'); + assert(line_end); + err_fprint("\t"); + if (!line_start[0]) err_fprint("<end of file>"); - else - err_fwrite(text, 1, (size_t)(end - text)); + else { + /* write up to start of error */ + err_fwrite(line_start, 1, (size_t)(start - line_start)); + if (ctx->color_enabled) + err_fprint(TEXT_INDICATOR_START); + if (line_end < end) { + /* write error part (only go to end of line) */ + err_fwrite(start, 1, (size_t)(line_end - start)); + if (ctx->color_enabled) + err_fprint(TEXT_INDICATOR_END); + } else { + /* write error part */ + err_fwrite(start, 1, (size_t)(end - start)); + if (ctx->color_enabled) + err_fprint(TEXT_INDICATOR_END); + /* write rest of line */ + err_fwrite(end, 1, (size_t)(line_end - end)); + } + } err_fprint("\n"); } static void err_print_location_text(Location where) { if (where.start) { ErrCtx *ctx = where.start->pos.ctx; - err_print_location_text_from_str(ctx->str, where.start->pos.start, where.end[-1].pos.end); + err_print_pos_text(ctx, where.start->pos.start, where.end[-1].pos.end); } else { err_fprint("\t<no location available>"); } @@ -61,17 +61,18 @@ int main(int argc, char **argv) { } char *contents = err_malloc(4096); + contents[0] = 0; /* put 0 byte at the start of the file. see err.c:err_print_location_text to find out why */ long contents_cap = 4095; - long contents_len = 0; + long contents_len = 1; while (fgets(contents + contents_len, (int)(contents_cap - contents_len), in)) { contents_len += (long)strlen(contents + contents_len); if (contents_len >= (long)contents_cap - 1024) { contents_cap *= 2; - /* allocate +1 so that pointers don't overflow */ contents = err_realloc(contents, (size_t)contents_cap + 1); } } + ++contents; if (ferror(in)) { fprintf(stderr, "Error reading input file: %s.\n", argv[1]); return EXIT_FAILURE; @@ -85,10 +86,10 @@ int main(int argc, char **argv) { ErrCtx err_ctx = {0}; err_ctx.filename = in_filename; err_ctx.enabled = true; + err_ctx.color_enabled = true; tokr_create(&t, &idents, &err_ctx, &main_allocr); if (!tokenize_string(&t, contents)) { - - err_fprint(TEXT_IMPORTANT("Errors occured while preprocessing.\n")); + err_text_important(&err_ctx, "Errors occured during preprocessing.\n"); return EXIT_FAILURE; } @@ -105,8 +106,7 @@ int main(int argc, char **argv) { parser_create(&p, &t, &main_allocr); ParsedFile f; if (!parse_file(&p, &f)) { - - err_fprint(TEXT_IMPORTANT("Errors occured while parsing.\n")); + err_text_important(&err_ctx, "Errors occured during parsing.\n"); return EXIT_FAILURE; } /* fprint_parsed_file(stdout, &f); */ @@ -125,7 +125,7 @@ int main(int argc, char **argv) { if (!types_file(&tr, &f)) { /* TODO(eventually): fix this if the error occured while exporting something */ - err_fprint(TEXT_IMPORTANT("Errors occured while determining types.\n")); + err_text_important(&err_ctx, "Errors occured while determining types.\n"); return EXIT_FAILURE; } #ifdef TOC_DEBUG @@ -134,21 +134,22 @@ int main(int argc, char **argv) { #endif FILE *out = fopen(out_filename, "w"); if (!out) { - err_fprint(TEXT_IMPORTANT("Could not open output file (out.c).\n")); + err_text_important(&err_ctx, "Could not open output file: "); + err_fprint("%s\n", out_filename); return EXIT_FAILURE; } CGenerator g; cgen_create(&g, out, &idents, &ev, &main_allocr); if (!cgen_file(&g, &f)) { fclose(out); - err_fprint(TEXT_IMPORTANT("Errors occured while generating C code.\n")); + err_text_important(&err_ctx, "Errors occured while generating C code.\n"); return EXIT_FAILURE; } block_exit(NULL, f.stmts); /* exit global scope */ tokr_free(&t); - free(contents); + free(contents - 1); /* -1 because we put a 0 byte at the beginning */ allocr_free_all(&main_allocr); evalr_free(&ev); diff --git a/test-all.sh b/test-all.sh index 11243db..03e26fb 100755 --- a/test-all.sh +++ b/test-all.sh @@ -1,4 +1,3 @@ #!/bin/sh ./test-build.sh || exit 1 -./build.sh || exit 1 tests/test.sh || exit 1 @@ -8,5 +8,8 @@ putf ::= fn(x: float) { }; point ::= pkg "point"; main ::= fn() { - x := y; + x := fahfsdkjahksjdfh; + +fahfsdkjahksjdfh := +5; };
\ No newline at end of file diff --git a/tokenizer.c b/tokenizer.c index 2340496..5c46ec8 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -156,12 +156,13 @@ static Location token_location(Token *t) { static void tokenization_err(Tokenizer *t, const char *fmt, ...) { va_list args; va_start(args, fmt); - err_fprint(TEXT_ERROR("error") " at line %lu of %s:\n", (unsigned long)t->line, t->err_ctx->filename); + err_text_err(t->err_ctx, "error"); + err_fprint(" at line %lu of %s:\n", (unsigned long)t->line, t->err_ctx->filename); err_vfprint(fmt, args); va_end(args); err_fprint("\n"); U32 pos = (U32)(t->s - t->err_ctx->str); - err_print_location_text_from_str(t->err_ctx->str, pos, pos + 1); + err_print_pos_text(t->err_ctx, pos, pos + 1); while (*t->s) { if (*t->s == '\n') { tokr_nextchar(t); @@ -410,7 +410,7 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) { } else { if (where.start <= d->where.end) { char *s = ident_to_str(i); - err_print(where, "Use of identifier %s before its declaration.\nNote that it is only possible to use a constant function before it is directly declared (e.g. x ::= fn() {}).", s); + err_print(where, "Use of identifier %s before its declaration.", s); info_print(d->where, "%s will be declared here.", s); free(s); } else { @@ -85,6 +85,7 @@ typedef struct ErrCtx { const char *filename; char *str; /* file contents */ bool enabled; + bool color_enabled; struct Location *instance_stack; /* stack of locations which generate the instances we're dealing with */ } ErrCtx; |