More error reporting improvemnts.
[pspp] / src / language / lexer / lexer.c
index 6e9bba43a789042259132b1ba7a3bde63407c6e8..562fcc5827d3a4662d237633cb3785dee6e0cf33 100644 (file)
@@ -1242,6 +1242,34 @@ lex_get_file_name (const struct lexer *lexer)
   return src == NULL ? NULL : src->reader->file_name;
 }
 
+/* Returns a newly allocated msg_location for the syntax that represents tokens
+   with 0-based offsets N0...N1, inclusive, from the current token.  The caller
+   must eventually free the location (with msg_location_destroy()). */
+struct msg_location *
+lex_get_location (const struct lexer *lexer, int n0, int n1)
+{
+  struct msg_location *loc = lex_get_lines (lexer, n0, n1);
+  loc->first_column = lex_get_first_column (lexer, n0);
+  loc->last_column = lex_get_last_column (lexer, n1);
+  return loc;
+}
+
+/* Returns a newly allocated msg_location for the syntax that represents tokens
+   with 0-based offsets N0...N1, inclusive, from the current token.  The
+   location only covers the tokens' lines, not the columns.  The caller must
+   eventually free the location (with msg_location_destroy()). */
+struct msg_location *
+lex_get_lines (const struct lexer *lexer, int n0, int n1)
+{
+  struct msg_location *loc = xmalloc (sizeof *loc);
+  *loc = (struct msg_location) {
+    .file_name = xstrdup_if_nonnull (lex_get_file_name (lexer)),
+    .first_line = lex_get_first_line_number (lexer, n0),
+    .last_line = lex_get_last_line_number (lexer, n1),
+  };
+  return loc;
+}
+
 const char *
 lex_get_encoding (const struct lexer *lexer)
 {
@@ -1452,8 +1480,8 @@ lex_source_get_syntax__ (const struct lex_source *src, int n0, int n1)
   return ds_steal_cstr (&s);
 }
 
-static void
-lex_ellipsize__ (struct substring in, char *out, size_t out_size)
+void
+lex_ellipsize (struct substring in, char *out, size_t out_size)
 {
   size_t out_maxlen;
   size_t out_len;
@@ -1527,14 +1555,14 @@ lex_source_error_valist (struct lex_source *src, int n0, int n1,
       /* Get the syntax that caused the error. */
       char *syntax = lex_source_get_syntax__ (src, n0, n1);
       char syntax_cstr[64];
-      lex_ellipsize__ (ss_cstr (syntax), syntax_cstr, sizeof syntax_cstr);
+      lex_ellipsize (ss_cstr (syntax), syntax_cstr, sizeof syntax_cstr);
       free (syntax);
 
       /* Get the macro call(s) that expanded to the syntax that caused the
          error. */
       char call_cstr[64];
       struct substring call = lex_source_get_macro_call (src, n0, n1);
-      lex_ellipsize__ (call, call_cstr, sizeof call_cstr);
+      lex_ellipsize (call, call_cstr, sizeof call_cstr);
 
       if (syntax_cstr[0])
         {
@@ -1560,34 +1588,44 @@ lex_source_error_valist (struct lex_source *src, int n0, int n1,
   if (ds_last (&s) != '.')
     ds_put_byte (&s, '.');
 
-  struct msg m = {
-    .category = MSG_C_SYNTAX,
-    .severity = MSG_S_ERROR,
-    .file_name = src->reader->file_name,
+  struct msg_location *location = xmalloc (sizeof *location);
+  *location = (struct msg_location) {
+    .file_name = xstrdup_if_nonnull (src->reader->file_name),
     .first_line = lex_source_get_first_line_number (src, n0),
     .last_line = lex_source_get_last_line_number (src, n1),
     .first_column = lex_source_get_first_column (src, n0),
     .last_column = lex_source_get_last_column (src, n1),
+  };
+  struct msg *m = xmalloc (sizeof *m);
+  *m = (struct msg) {
+    .category = MSG_C_SYNTAX,
+    .severity = MSG_S_ERROR,
+    .location = location,
     .text = ds_steal_cstr (&s),
   };
-  msg_emit (&m);
+  msg_emit (m);
 }
 
-static void PRINTF_FORMAT (2, 3)
-lex_get_error (struct lex_source *src, const char *format, ...)
+static void PRINTF_FORMAT (4, 5)
+lex_source_error (struct lex_source *src, int n0, int n1,
+                  const char *format, ...)
 {
   va_list args;
   va_start (args, format);
+  lex_source_error_valist (src, n0, n1, format, args);
+  va_end (args);
+}
 
+static void
+lex_get_error (struct lex_source *src, const char *s)
+{
   size_t old_middle = src->middle;
   src->middle = src->front;
   size_t n = src->front - src->back - 1;
-  lex_source_error_valist (src, n, n, format, args);
+  lex_source_error (src, n, n, "%s", s);
   src->middle = old_middle;
 
   lex_source_pop_front (src);
-
-  va_end (args);
 }
 
 /* Attempts to append an additional token at the front of SRC, reading more
@@ -1739,44 +1777,17 @@ lex_source_try_get__ (struct lex_source *src)
       return true;
 
     case SCAN_BAD_HEX_LENGTH:
-      lex_get_error (src, _("String of hex digits has %d characters, which "
-                            "is not a multiple of 2"),
-                     (int) token->token.number);
-      return false;
-
     case SCAN_BAD_HEX_DIGIT:
     case SCAN_BAD_UNICODE_DIGIT:
-      lex_get_error (src, _("`%c' is not a valid hex digit"),
-                     (int) token->token.number);
-      return false;
-
     case SCAN_BAD_UNICODE_LENGTH:
-      lex_get_error (src, _("Unicode string contains %d bytes, which is "
-                            "not in the valid range of 1 to 8 bytes"),
-                     (int) token->token.number);
-      return false;
-
     case SCAN_BAD_UNICODE_CODE_POINT:
-      lex_get_error (src, _("U+%04X is not a valid Unicode code point"),
-                     (int) token->token.number);
-      return false;
-
     case SCAN_EXPECTED_QUOTE:
-      lex_get_error (src, _("Unterminated string constant"));
-      return false;
-
     case SCAN_EXPECTED_EXPONENT:
-      lex_get_error (src, _("Missing exponent following `%s'"),
-                     token->token.string.string);
-      return false;
-
     case SCAN_UNEXPECTED_CHAR:
-      {
-        char c_name[16];
-        lex_get_error (src, _("Bad character %s in input"),
-                       uc_name (token->token.number, c_name));
-        return false;
-      }
+      char *msg = scan_token_to_error (&token->token);
+      lex_get_error (src, msg);
+      free (msg);
+      return false;
 
     case SCAN_SKIP:
       lex_source_pop_front (src);
@@ -1884,7 +1895,7 @@ lex_source_get (const struct lex_source *src_)
 
   /* Now expand the macro. */
   struct macro_tokens expansion = { .n = 0 };
-  macro_expander_get_expansion (me, &expansion);
+  macro_expander_get_expansion (me, src->reader->syntax, &expansion);
   macro_expander_destroy (me);
 
   /* Convert the macro expansion into syntax for possible error messages later. */