summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-01-09 19:01:06 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-01-09 19:01:06 -0500
commitc156e952d94049e8dbd8bc9a0f294712c6f253e8 (patch)
tree107b465473a8c32018c5a2685979fa13c14731fe
parent6f4074136719bd7ec612e8357596fe3e884c3bf7 (diff)
better error system
-rw-r--r--.gitignore1
-rwxr-xr-xbuild.sh5
-rw-r--r--compatibility.c67
-rw-r--r--err.c125
-rw-r--r--main.c21
-rwxr-xr-xtest-all.sh1
-rw-r--r--test.toc5
-rw-r--r--tokenizer.c5
-rw-r--r--types.c2
-rw-r--r--types.h1
10 files changed, 186 insertions, 47 deletions
diff --git a/.gitignore b/.gitignore
index a7b3e40..d40b8cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ vgcore*
TAGS
tags
*.o
+compatibility \ No newline at end of file
diff --git a/build.sh b/build.sh
index 52831a1..c22169d 100755
--- a/build.sh
+++ b/build.sh
@@ -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;
}
diff --git a/err.c b/err.c
index 448dc47..823c039 100644
--- a/err.c
+++ b/err.c
@@ -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>");
}
diff --git a/main.c b/main.c
index e945b3c..849aabf 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/test.toc b/test.toc
index d48623a..2c58e20 100644
--- a/test.toc
+++ b/test.toc
@@ -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);
diff --git a/types.c b/types.c
index 10125f6..00ddd8c 100644
--- a/types.c
+++ b/types.c
@@ -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 {
diff --git a/types.h b/types.h
index e74ad70..606c748 100644
--- a/types.h
+++ b/types.h
@@ -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;