summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--lib.c180
-rw-r--r--lib.h2
-rw-r--r--main.c158
3 files changed, 195 insertions, 145 deletions
diff --git a/lib.c b/lib.c
index 30b7574..39238ed 100644
--- a/lib.c
+++ b/lib.c
@@ -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)
{
diff --git a/lib.h b/lib.h
index 038350e..9a23d56 100644
--- a/lib.h
+++ b/lib.h
@@ -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_ */
diff --git a/main.c b/main.c
index ae10265..d1bb463 100644
--- a/main.c
+++ b/main.c
@@ -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;
}