diff options
-rw-r--r-- | lib.c | 180 | ||||
-rw-r--r-- | lib.h | 2 | ||||
-rw-r--r-- | main.c | 158 |
3 files changed, 195 insertions, 145 deletions
@@ -31,6 +31,186 @@ #include <sys/time.h> +static bool +snprintf_append(char **dptr, size_t *dlen, const char *fmt, ssize_t sz, ...) +{ + va_list ap; + char *tmp; + int n; + + va_start(ap, sz); + n = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + if (n < 0) + return false; + else if (sz >= 0 && n > sz) + n = sz; + + tmp = realloc(*dptr, *dlen + n + 1); + + if (!tmp) + return false; + + va_start(ap, sz); + vsnprintf(tmp + *dlen, n + 1, fmt, ap); + va_end(ap); + + *dptr = tmp; + *dlen += n; + + return true; +} + +#define sprintf_append(dptr, dlen, fmt, ...) \ + snprintf_append(dptr, dlen, fmt, -1, ##__VA_ARGS__) + +static void +format_error_context(char **msg, size_t *msglen, const char *expr, size_t off) +{ + int eoff, eline, padlen; + const char *p, *nl; + int i; + + /* skip lines until error line */ + for (p = nl = expr, eline = 0; *p && p < expr + off; p++) { + if (*p == '\n') { + nl = p + 1; + eline++; + } + } + + eoff = p - nl; + + sprintf_append(msg, msglen, "In line %u, byte %d:\n\n `", eline + 1, eoff); + + for (p = nl, padlen = 0; *p != '\n' && *p != '\0'; p++) { + switch (*p) { + case '\t': + sprintf_append(msg, msglen, " "); + if (p < nl + eoff) + padlen += 4; + break; + + case '\r': + case '\v': + sprintf_append(msg, msglen, " "); + if (p < nl + eoff) + padlen++; + break; + + default: + sprintf_append(msg, msglen, "%c", *p); + if (p < nl + eoff) + padlen++; + } + } + + sprintf_append(msg, msglen, "`\n "); + + if (padlen < strlen("Near here ^")) { + for (i = 0; i < padlen; i++) + sprintf_append(msg, msglen, " "); + + sprintf_append(msg, msglen, "^-- Near here\n"); + } + else { + sprintf_append(msg, msglen, "Near here "); + + for (i = strlen("Near here "); i < padlen; i++) + sprintf_append(msg, msglen, "-"); + + sprintf_append(msg, msglen, "^\n"); + } + + sprintf_append(msg, msglen, "\n"); +} + +char * +ut_format_error(struct ut_state *state, const char *expr) +{ + size_t off = state ? state->off : 0; + struct ut_opcode *tag; + bool first = true; + size_t msglen = 0; + char *msg = NULL; + int i, max_i; + + switch (state ? state->error.code : UT_ERROR_OUT_OF_MEMORY) { + case UT_ERROR_NO_ERROR: + return NULL; + + case UT_ERROR_OUT_OF_MEMORY: + sprintf_append(&msg, &msglen, "Runtime error: Out of memory\n"); + break; + + case UT_ERROR_UNTERMINATED_COMMENT: + sprintf_append(&msg, &msglen, "Syntax error: Unterminated comment\n"); + break; + + case UT_ERROR_UNTERMINATED_STRING: + sprintf_append(&msg, &msglen, "Syntax error: Unterminated string\n"); + break; + + case UT_ERROR_UNTERMINATED_BLOCK: + sprintf_append(&msg, &msglen, "Syntax error: Unterminated template block\n"); + break; + + case UT_ERROR_UNEXPECTED_CHAR: + sprintf_append(&msg, &msglen, "Syntax error: Unexpected character\n"); + break; + + case UT_ERROR_OVERLONG_STRING: + sprintf_append(&msg, &msglen, "Syntax error: String or label literal too long\n"); + break; + + case UT_ERROR_INVALID_ESCAPE: + sprintf_append(&msg, &msglen, "Syntax error: Invalid escape sequence\n"); + break; + + case UT_ERROR_NESTED_BLOCKS: + sprintf_append(&msg, &msglen, "Syntax error: Template blocks may not be nested\n"); + break; + + case UT_ERROR_UNEXPECTED_TOKEN: + sprintf_append(&msg, &msglen, "Syntax error: Unexpected token\n"); + + for (i = 0, max_i = 0; i < sizeof(state->error.info.tokens) * 8; i++) + if ((state->error.info.tokens[i / 64] & ((unsigned)1 << (i % 64))) && tokennames[i]) + max_i = i; + + for (i = 0; i < sizeof(state->error.info.tokens) * 8; i++) { + if ((state->error.info.tokens[i / 64] & ((unsigned)1 << (i % 64))) && tokennames[i]) { + if (first) { + sprintf_append(&msg, &msglen, "Expecting %s", tokennames[i]); + first = false; + } + else if (i < max_i) { + sprintf_append(&msg, &msglen, ", %s", tokennames[i]); + } + else { + sprintf_append(&msg, &msglen, " or %s", tokennames[i]); + } + } + } + + sprintf_append(&msg, &msglen, "\n"); + break; + + case UT_ERROR_EXCEPTION: + tag = json_object_get_userdata(state->error.info.exception); + off = (tag && tag->operand[0]) ? tag->operand[0]->off : 0; + + sprintf_append(&msg, &msglen, "%s\n", json_object_get_string(state->error.info.exception)); + break; + } + + if (off) + format_error_context(&msg, &msglen, expr, off); + + return msg; +} + static double ut_cast_double(struct json_object *v) { @@ -23,4 +23,6 @@ typedef struct json_object *(ut_c_fn)(struct ut_state *, struct ut_opcode *, str void ut_lib_init(struct ut_state *state, struct json_object *scope); +char *ut_format_error(struct ut_state *state, const char *expr); + #endif /* __LIB_H_ */ @@ -30,6 +30,7 @@ #include "lexer.h" #include "parser.h" #include "eval.h" +#include "lib.h" static void @@ -45,148 +46,6 @@ print_usage(char *app) app); } -static void -print_error_context(const char *expr, size_t off) -{ - int eoff, eline, padlen; - const char *p, *nl; - int i; - - /* skip lines until error line */ - for (p = nl = expr, eline = 0; *p && p < expr + off; p++) { - if (*p == '\n') { - nl = p + 1; - eline++; - } - } - - eoff = p - nl; - - fprintf(stderr, "In line %u, byte %d:\n\n `", eline + 1, eoff); - - for (p = nl, padlen = 0; *p != '\n' && *p != '\0'; p++) { - switch (*p) { - case '\t': - fprintf(stderr, " "); - if (p < nl + eoff) - padlen += 4; - break; - - case '\r': - case '\v': - fprintf(stderr, " "); - if (p < nl + eoff) - padlen++; - break; - - default: - fprintf(stderr, "%c", *p); - if (p < nl + eoff) - padlen++; - } - } - - fprintf(stderr, "`\n "); - - if (padlen < strlen("Near here ^")) { - for (i = 0; i < padlen; i++) - fprintf(stderr, " "); - - fprintf(stderr, "^-- Near here\n"); - } - else { - fprintf(stderr, "Near here "); - - for (i = strlen("Near here "); i < padlen; i++) - fprintf(stderr, "-"); - - fprintf(stderr, "^\n"); - } - - fprintf(stderr, "\n"); -} - -static void -print_error(struct ut_state *state, const char *expr) -{ - size_t off = state ? state->off : 0; - struct ut_opcode *tag; - bool first = true; - int i, max_i; - - switch (state ? state->error.code : UT_ERROR_OUT_OF_MEMORY) { - case UT_ERROR_NO_ERROR: - return; - - case UT_ERROR_OUT_OF_MEMORY: - fprintf(stderr, "Runtime error: Out of memory\n"); - break; - - case UT_ERROR_UNTERMINATED_COMMENT: - fprintf(stderr, "Syntax error: Unterminated comment\n"); - break; - - case UT_ERROR_UNTERMINATED_STRING: - fprintf(stderr, "Syntax error: Unterminated string\n"); - break; - - case UT_ERROR_UNTERMINATED_BLOCK: - fprintf(stderr, "Syntax error: Unterminated template block\n"); - break; - - case UT_ERROR_UNEXPECTED_CHAR: - fprintf(stderr, "Syntax error: Unexpected character\n"); - break; - - case UT_ERROR_OVERLONG_STRING: - fprintf(stderr, "Syntax error: String or label literal too long\n"); - break; - - case UT_ERROR_INVALID_ESCAPE: - fprintf(stderr, "Syntax error: Invalid escape sequence\n"); - break; - - case UT_ERROR_NESTED_BLOCKS: - fprintf(stderr, "Syntax error: Template blocks may not be nested\n"); - break; - - case UT_ERROR_UNEXPECTED_TOKEN: - fprintf(stderr, "Syntax error: Unexpected token\n"); - - for (i = 0, max_i = 0; i < sizeof(state->error.info.tokens) * 8; i++) - if ((state->error.info.tokens[i / 64] & ((unsigned)1 << (i % 64))) && tokennames[i]) - max_i = i; - - for (i = 0; i < sizeof(state->error.info.tokens) * 8; i++) { - if ((state->error.info.tokens[i / 64] & ((unsigned)1 << (i % 64))) && tokennames[i]) { - if (first) { - fprintf(stderr, "Expecting %s", tokennames[i]); - first = false; - } - else if (i < max_i) { - fprintf(stderr, ", %s", tokennames[i]); - } - else { - fprintf(stderr, " or %s", tokennames[i]); - } - } - } - - fprintf(stderr, "\n"); - break; - - case UT_ERROR_EXCEPTION: - tag = json_object_get_userdata(state->error.info.exception); - off = (tag && tag->operand[0]) ? tag->operand[0]->off : 0; - - fprintf(stderr, "%s\n", json_object_get_string(state->error.info.exception)); - break; - } - - if (off) - print_error_context(expr, off); -} - #ifndef NDEBUG static void dump(struct ut_opcode *op, int level); @@ -272,6 +131,7 @@ parse(const char *source, bool dumponly) { struct ut_state *state = calloc(1, sizeof(*state)); enum ut_error_type err; + char *msg; err = ut_parse(state, source); @@ -289,8 +149,12 @@ parse(const char *source, bool dumponly) } } - if (err) - print_error(state, source); + if (err) { + msg = ut_format_error(state, source); + + fprintf(stderr, "%s\n", msg); + free(msg); + } ut_free(state); @@ -351,7 +215,11 @@ main(int argc, char **argv) tmp = realloc(source, tlen + rlen + 1); if (!tmp) { - print_error(NULL, ""); + tmp = ut_format_error(NULL, ""); + + fprintf(stderr, "%s\n", tmp); + free(tmp); + rv = UT_ERROR_OUT_OF_MEMORY; goto out; } |