better error messages are awesome!
[pspp] / src / libpspp / message.c
index 9ead3efb3f953773441a4fd8baf48973d1a436a9..ab50f2b0225fa570c7b7b08aad6690bfc0896398 100644 (file)
@@ -28,6 +28,7 @@
 
 #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"
@@ -121,6 +122,7 @@ msg_set_handler (void (*handler) (const struct msg *, void *aux), void *aux)
 void
 msg_location_uninit (struct msg_location *loc)
 {
+  lex_source_unref (loc->src);
   intern_unref (loc->file_name);
 }
 
@@ -176,11 +178,11 @@ 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),
-    .p[0] = src->p[0],
-    .p[1] = src->p[1],
-  };
+  *dst = *src;
+  if (src->file_name)
+    dst->file_name = intern_ref (src->file_name);
+  if (src->src)
+    lex_source_ref (dst->src);
   return dst;
 }
 
@@ -361,6 +363,22 @@ msg_to_string (const struct msg *m)
 
   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