#include "libpspp/cast.h"
#include "libpspp/intern.h"
+#include "language/lexer/lexer.h"
#include "libpspp/str.h"
#include "libpspp/version.h"
#include "data/settings.h"
void
-vmsg (enum msg_class class, const char *format, va_list args)
+vmsg (enum msg_class class, const struct msg_location *location,
+ const char *format, va_list args)
{
struct msg *m = xmalloc (sizeof *m);
*m = (struct msg) {
.category = msg_class_to_category (class),
.severity = msg_class_to_severity (class),
+ .location = msg_location_dup (location),
.text = xvasprintf (format, args),
};
msg_emit (m);
{
va_list args;
va_start (args, format);
- vmsg (class, format, args);
+ vmsg (class, NULL, format, args);
va_end (args);
}
-
+/* Outputs error message in CLASS, with text FORMAT, formatted with printf.
+ LOCATION is the reported location for the message. */
+void
+msg_at (enum msg_class class, const struct msg_location *location,
+ const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ vmsg (class, location, format, args);
+ va_end (args);
+}
void
msg_error (int errnum, const char *format, ...)
void
msg_location_uninit (struct msg_location *loc)
{
+ lex_source_unref (loc->src);
intern_unref (loc->file_name);
}
}
}
+static int
+msg_point_compare_3way (const struct msg_point *a, const struct msg_point *b)
+{
+ return (!a->line ? 1
+ : !b->line ? -1
+ : a->line > b->line ? 1
+ : a->line < b->line ? -1
+ : !a->column ? 1
+ : !b->column ? -1
+ : a->column > b->column ? 1
+ : a->column < b->column ? -1
+ : 0);
+}
+
+void
+msg_location_merge (struct msg_location **dstp, const struct msg_location *src)
+{
+ struct msg_location *dst = *dstp;
+ if (!dst)
+ {
+ *dstp = msg_location_dup (src);
+ return;
+ }
+
+ if (dst->file_name != src->file_name)
+ {
+ /* Failure. */
+ return;
+ }
+ if (msg_point_compare_3way (&dst->p[0], &src->p[0]) > 0)
+ dst->p[0] = src->p[0];
+ if (msg_point_compare_3way (&dst->p[1], &src->p[1]) < 0)
+ dst->p[1] = src->p[1];
+}
+
struct msg_location *
msg_location_dup (const struct msg_location *src)
{
return NULL;
struct msg_location *dst = xmalloc (sizeof *dst);
- *dst = (struct msg_location) {
- .file_name = intern_new_if_nonnull (src->file_name),
- .first_line = src->first_line,
- .last_line = src->last_line,
- .first_column = src->first_column,
- .last_column = src->last_column,
- };
+ *dst = *src;
+ if (src->file_name)
+ dst->file_name = intern_ref (src->file_name);
+ if (src->src)
+ lex_source_ref (dst->src);
return dst;
}
msg_location_is_empty (const struct msg_location *loc)
{
return !loc || (!loc->file_name
- && loc->first_line <= 0
- && loc->first_column <= 0);
+ && loc->p[0].line <= 0
+ && loc->p[0].column <= 0);
}
void
if (loc->file_name)
ds_put_cstr (s, loc->file_name);
- int l1 = loc->first_line;
- int l2 = MAX (loc->first_line, loc->last_line - 1);
- int c1 = loc->first_column;
- int c2 = MAX (loc->first_column, loc->last_column - 1);
+ int l1 = loc->p[0].line;
+ int l2 = MAX (l1, loc->p[1].line);
+ int c1 = loc->p[0].column;
+ int c2 = MAX (c1, loc->p[1].column);
if (l1 > 0)
{
ds_put_cstr (&s, m->text);
+ const struct msg_location *loc = m->location;
+ if (loc->src && loc->p[0].line)
+ {
+ struct substring line = lex_source_get_line (loc->src, m->location->p[0].line);
+ ds_put_format (&s, "\n%5d | %.*s", loc->p[0].line, (int) line.length, line.string);
+ if (loc->p[0].column && loc->p[1].column >= loc->p[0].column)
+ {
+ ds_put_cstr (&s, " | ");
+ ds_put_byte_multiple (&s, ' ', loc->p[0].column - 1);
+ int n = loc->p[1].column - loc->p[0].column + 1;
+ ds_put_byte (&s, '^');
+ if (n > 1)
+ ds_put_byte_multiple (&s, '~', n - 1);
+ }
+ }
+
return ds_cstr (&s);
}
\f