work on better matrix error reporting
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 30 Nov 2021 14:12:14 +0000 (06:12 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 30 Nov 2021 14:55:06 +0000 (06:55 -0800)
src/language/control/define.c
src/language/data-io/data-parser.c
src/language/data-io/matrix-data.c
src/language/lexer/lexer.c
src/language/lexer/lexer.h
src/language/stats/matrix.c
src/libpspp/message.c
src/libpspp/message.h

index f33e885925a807b67071d1832b2de8442f3c7845..0f1049678c30c6b0c27f149edd2d668d8d82aaef 100644 (file)
@@ -109,14 +109,8 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED)
     }
 
   struct macro *m = xmalloc (sizeof *m);
-  *m = (struct macro) {
-    .name = xstrdup (name),
-    .location = xmalloc (sizeof *m->location),
-  };
-  *m->location = (struct msg_location) {
-    .file_name = intern_new_if_nonnull (lex_get_file_name (lexer)),
-    .first_line = lex_get_first_line_number (lexer, 0),
-  };
+  *m = (struct macro) { .name = xstrdup (name) };
+  int first_line = lex_get_first_line_number (lexer, 0);
   lex_get (lexer);
 
   if (!lex_force_match (lexer, T_LPAREN))
@@ -282,7 +276,14 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED)
       ds_put_byte (&body, '\n');
       lex_get (lexer);
     }
-  m->location->last_line = lex_get_last_line_number (lexer, 0);
+
+  int last_line = lex_get_last_line_number (lexer, 0) - 1;
+  m->location = xmalloc (sizeof *m->location);
+  *m->location = (struct msg_location) {
+    .file_name = intern_new_if_nonnull (lex_get_file_name (lexer)),
+    .p[0] = { .line = first_line },
+    .p[1] = { .line = last_line },
+  };
 
   macro_tokens_from_string (&m->body, body.ss, lex_get_syntax_mode (lexer));
   ds_destroy (&body);
index 09af7542bb5750510f402b6ce3ee90bb6e833c01..f40fc99dd46e400602e3e73e6119cce17784c852 100644 (file)
@@ -500,10 +500,8 @@ parse_error (const struct dfm_reader *reader, const struct field *field,
   struct msg_location *location = xmalloc (sizeof *location);
   *location = (struct msg_location) {
     .file_name = intern_new (dfm_get_file_name (reader)),
-    .first_line = line_number,
-    .last_line = line_number + 1,
-    .first_column = first_column,
-    .last_column = last_column,
+    .p[0] = { .line = line_number, .column = first_column },
+    .p[1] = { .line = line_number, .column = last_column - 1 },
   };
   struct msg *m = xmalloc (sizeof *m);
   *m = (struct msg) {
index 31d6b710b0ba68a54402d33e50e559b9f581bf2e..fb54d30937883873ba22968e8ef210cf93ffff7d 100644 (file)
@@ -253,12 +253,13 @@ parse_msg (struct dfm_reader *reader, const struct substring *token,
 
   int line_number = dfm_get_line_number (reader);
   struct msg_location *location = xmalloc (sizeof *location);
+  int last_column = (first_column && token->length
+                     ? first_column + token->length - 1
+                     : 0);
   *location = (struct msg_location) {
     .file_name = intern_new (dfm_get_file_name (reader)),
-    .first_line = line_number,
-    .last_line = line_number + 1,
-    .first_column = first_column,
-    .last_column = first_column ? first_column + token->length : 0,
+    .p[0] = { .line = line_number, .column = first_column },
+    .p[1] = { .line = line_number, .column = last_column },
   };
   struct msg *m = xmalloc (sizeof *m);
   *m = (struct msg) {
index df3a77de94fb11ac90d196c560f32de27922848d..cf40dcbe6d0ee76f53a16dbf110c8b34d201d5c1 100644 (file)
@@ -1248,12 +1248,13 @@ lex_token_location (const struct lex_source *src,
                     const struct lex_token *t0,
                     const struct lex_token *t1)
 {
+  int first_column = lex_token_get_first_column (src, t0);
+  int last_line = lex_token_get_last_line_number (src, t1) - 1;
+  int last_column = lex_token_get_last_column (src, t1) - 1;
   return (struct msg_location) {
     .file_name = intern_new_if_nonnull (src->reader->file_name),
-    .first_line = t0->first_line,
-    .last_line = lex_token_get_last_line_number (src, t1),
-    .first_column = lex_token_get_first_column (src, t0),
-    .last_column = lex_token_get_last_column (src, t1),
+    .p[0] = { .line = t0->first_line, .column = first_column },
+    .p[1] = { .line = last_line, .column = last_column },
   };
 }
 
@@ -1351,8 +1352,8 @@ 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);
+  loc->p[0].column = lex_get_first_column (lexer, n0);
+  loc->p[1].column = lex_get_last_column (lexer, n1) - 1;
   return loc;
 }
 
@@ -1364,14 +1365,24 @@ struct msg_location *
 lex_get_lines (const struct lexer *lexer, int n0, int n1)
 {
   struct msg_location *loc = xmalloc (sizeof *loc);
+  int first_line = lex_get_first_line_number (lexer, n0);
+  int last_line = lex_get_last_line_number (lexer, n1) - 1;
   *loc = (struct msg_location) {
     .file_name = intern_new_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),
+    .p[0] = { .line = first_line },
+    .p[1] = { .line = last_line },
   };
   return loc;
 }
 
+void
+lex_extend_location (const struct lexer *lexer, int n, struct msg_location *loc)
+{
+  struct msg_location *new = lex_get_location (lexer, n, n);
+  msg_location_merge (loc, new);
+  msg_location_destroy (new);
+}
+
 const char *
 lex_get_encoding (const struct lexer *lexer)
 {
index d82470ffdd456d52a2efe37f9037f7441a4c2686..23dd305179be5b3fa41574a62d7946c137689612 100644 (file)
@@ -160,7 +160,7 @@ int lex_get_last_column (const struct lexer *, int n);
 const char *lex_get_file_name (const struct lexer *);
 struct msg_location *lex_get_location (const struct lexer *, int n0, int n1);
 struct msg_location *lex_get_lines (const struct lexer *, int n0, int n1);
-void lex_extend_location (const struct lexer *, int n, struct msg_location *);
+void lex_extend_location (const struct lexer *, int n, struct msg_location **);
 const char *lex_get_encoding (const struct lexer *);
 
 /* Issuing errors. */
index 0db2f532e74c4efad7f6ef19b58d1577fea15e47..bcefb94a9c615df4161af52f0dcc2052b3e6db66 100644 (file)
@@ -206,9 +206,9 @@ matrix_var_set (struct matrix_var *var, gsl_matrix *value)
 
      - "ai": Restrict a to integer values.
 
-     - "a>0", "a<0", "a>=0", "a<=0".
+     - "a>0", "a<0", "a>=0", "a<=0", "a!=0".
 
-     - "a<b", "a>b", "a<=b", "a>=b".
+     - "a<b", "a>b", "a<=b", "a>=b", "b!=0".
 */
 #define MATRIX_FUNCTIONS                                                \
     F(ABS,      "ABS",      m_e, NULL)                                  \
@@ -217,7 +217,7 @@ matrix_var_set (struct matrix_var *var, gsl_matrix *value)
     F(ARSIN,    "ARSIN",    m_e, "a[-1,1]")                             \
     F(ARTAN,    "ARTAN",    m_e, NULL)                                  \
     F(BLOCK,    "BLOCK",    m_any, NULL)                                \
-    F(CHOL,     "CHOL",     m_m, NULL)                                  \
+    F(CHOL,     "CHOL",     m_me, NULL)                                 \
     F(CMIN,     "CMIN",     m_m, NULL)                                  \
     F(CMAX,     "CMAX",     m_m, NULL)                                  \
     F(COS,      "COS",      m_e, NULL)                                  \
@@ -231,17 +231,17 @@ matrix_var_set (struct matrix_var *var, gsl_matrix *value)
     F(GINV,     "GINV",     m_m, NULL)                                  \
     F(GRADE,    "GRADE",    m_m, NULL)                                  \
     F(GSCH,     "GSCH",     m_m, NULL)                                  \
-    F(IDENT,    "IDENT",    IDENT, NULL)                                \
+    F(IDENT,    "IDENT",    IDENT, "ai>=0 bi>=0")                       \
     F(INV,      "INV",      m_m, NULL)                                  \
     F(KRONEKER, "KRONEKER", m_mm, NULL)                                 \
     F(LG10,     "LG10",     m_e, "a>0")                                 \
     F(LN,       "LN",       m_e, "a>0")                                 \
     F(MAGIC,    "MAGIC",    m_d, "ai>=3")                               \
-    F(MAKE,     "MAKE",     m_ddd, NULL)                                \
+    F(MAKE,     "MAKE",     m_ddd, "ai>=0 bi>=0")                       \
     F(MDIAG,    "MDIAG",    m_v, NULL)                                  \
     F(MMAX,     "MMAX",     d_m, NULL)                                  \
     F(MMIN,     "MMIN",     d_m, NULL)                                  \
-    F(MOD,      "MOD",      m_md, NULL)                                 \
+    F(MOD,      "MOD",      m_md, "b!=0")                               \
     F(MSSQ,     "MSSQ",     d_m, NULL)                                  \
     F(MSUM,     "MSUM",     d_m, NULL)                                  \
     F(NCOL,     "NCOL",     d_m, NULL)                                  \
@@ -390,6 +390,7 @@ enum { m_d_MIN_ARGS = 1, m_d_MAX_ARGS = 1 };
 enum { m_dd_MIN_ARGS = 2, m_dd_MAX_ARGS = 2 };
 enum { m_ddd_MIN_ARGS = 3, m_ddd_MAX_ARGS = 3 };
 enum { m_m_MIN_ARGS = 1, m_m_MAX_ARGS = 1 };
+enum { m_me_MIN_ARGS = 1, m_me_MAX_ARGS = 1 };
 enum { m_e_MIN_ARGS = 1, m_e_MAX_ARGS = 1 };
 enum { m_md_MIN_ARGS = 2, m_md_MAX_ARGS = 2 };
 enum { m_ed_MIN_ARGS = 2, m_ed_MAX_ARGS = 2 };
@@ -412,6 +413,7 @@ typedef gsl_matrix *matrix_proto_m_d (double);
 typedef gsl_matrix *matrix_proto_m_dd (double, double);
 typedef gsl_matrix *matrix_proto_m_ddd (double, double, double);
 typedef gsl_matrix *matrix_proto_m_m (gsl_matrix *);
+typedef gsl_matrix *matrix_proto_m_me (gsl_matrix *, const struct matrix_expr *);
 typedef double matrix_proto_m_e (double);
 typedef gsl_matrix *matrix_proto_m_md (gsl_matrix *, double);
 typedef double matrix_proto_m_ed (double, double);
@@ -570,8 +572,6 @@ matrix_expr_create_subs (enum matrix_op op, struct matrix_expr **subs,
     .n_subs = n_subs
   };
 
-  for (size_t i = 0; i < n_subs; i++)
-    msg_location_merge (&e->location, subs[i]->location);
   return e;
 }
 
@@ -605,10 +605,15 @@ matrix_expr_create_3 (enum matrix_op op, struct matrix_expr *sub0,
 }
 
 static struct matrix_expr *
-matrix_expr_create_number (double number)
+matrix_expr_create_number (struct lexer *lexer, double number)
 {
   struct matrix_expr *e = xmalloc (sizeof *e);
-  *e = (struct matrix_expr) { .op = MOP_NUMBER, .number = number };
+  *e = (struct matrix_expr) {
+    .op = MOP_NUMBER,
+    .number = number,
+    .location = lex_get_location (lexer, 0, 0),
+  };
+  lex_get (lexer);
   return e;
 }
 
@@ -638,7 +643,11 @@ static struct matrix_expr *
 matrix_parse_curly_semi (struct matrix_state *s)
 {
   if (lex_token (s->lexer) == T_RCURLY)
-    return matrix_expr_create_0 (MOP_EMPTY);
+    {
+      struct matrix_expr *e = matrix_expr_create_0 (MOP_EMPTY);
+      e->location = lex_get_location (s->lexer, -1, 0);
+      return e;
+    }
 
   struct matrix_expr *lhs = matrix_parse_curly_comma (s);
   if (!lhs)
@@ -737,7 +746,7 @@ matrix_eval_BLOCK (gsl_matrix *m[], size_t n)
 }
 
 static gsl_matrix *
-matrix_eval_CHOL (gsl_matrix *m)
+matrix_eval_CHOL (gsl_matrix *m, const struct matrix_expr *e)
 {
   if (!gsl_linalg_cholesky_decomp1 (m))
     {
@@ -752,7 +761,8 @@ matrix_eval_CHOL (gsl_matrix *m)
     }
   else
     {
-      msg (SE, _("Input to CHOL function is not positive-definite."));
+      msg_at (SE, e->location,
+              _("Input to CHOL function is not positive-definite."));
       return NULL;
     }
 }
@@ -1154,12 +1164,6 @@ matrix_eval_GSCH (gsl_matrix *v)
 static gsl_matrix *
 matrix_eval_IDENT (double s1, double s2)
 {
-  if (s1 < 0 || s1 > SIZE_MAX || s2 < 0 || s2 > SIZE_MAX)
-    {
-      msg (SE, _("Arguments to IDENT must be non-negative integers."));
-      return NULL;
-    }
-
   gsl_matrix *m = gsl_matrix_alloc (s1, s2);
   MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
     *d = x == y;
@@ -1380,12 +1384,6 @@ matrix_eval_MAGIC (double n_)
 static gsl_matrix *
 matrix_eval_MAKE (double r, double c, double value)
 {
-  if (r < 0 || r >= SIZE_MAX || c < 0 || c >= SIZE_MAX)
-    {
-      msg (SE, _("Size arguments to MAKE must be integers."));
-      return NULL;
-    }
-
   gsl_matrix *m = gsl_matrix_alloc (r, c);
   MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
     *d = value;
@@ -1416,12 +1414,6 @@ matrix_eval_MMIN (gsl_matrix *m)
 static gsl_matrix *
 matrix_eval_MOD (gsl_matrix *m, double divisor)
 {
-  if (divisor == 0.0)
-    {
-      msg (SE, _("Divisor argument to MOD function must be nonzero."));
-      return NULL;
-    }
-
   MATRIX_FOR_ALL_ELEMENTS (d, y, x, m)
     *d = fmod (*d, divisor);
   return m;
@@ -2673,7 +2665,7 @@ matrix_parse_function (struct matrix_state *s, const char *token,
             }
           if (!sub->location)
             {
-              lex_extend_location (s->lexer, 0, arg_location);
+              //lex_extend_location (s->lexer, 0, arg_location);
               sub->location = arg_location;
             }
           else
@@ -2725,18 +2717,16 @@ matrix_parse_primary (struct matrix_state *s)
   if (lex_is_number (s->lexer))
     {
       double number = lex_number (s->lexer);
-      lex_get (s->lexer);
-      return matrix_expr_create_number (number);
+      return matrix_expr_create_number (s->lexer, number);
     }
   else if (lex_is_string (s->lexer))
     {
       char string[sizeof (double)];
       buf_copy_str_rpad (string, sizeof string, lex_tokcstr (s->lexer), ' ');
-      lex_get (s->lexer);
 
       double number;
       memcpy (&number, string, sizeof number);
-      return matrix_expr_create_number (number);
+      return matrix_expr_create_number (s->lexer, number);
     }
   else if (lex_match (s->lexer, T_LPAREN))
     {
@@ -3600,10 +3590,10 @@ matrix_expr_evaluate_mat_index (gsl_matrix *sm, gsl_matrix *im0,
   return dm;
 }
 
-#define F(ENUM, STRING, PROTO, CONSTRAINTS)                             \
-  static gsl_matrix *matrix_expr_evaluate_##PROTO (                     \
-    const struct matrix_function_properties *, gsl_matrix *[], size_t,  \
-    matrix_proto_##PROTO *);
+#define F(ENUM, STRING, PROTO, CONSTRAINTS)                     \
+  static gsl_matrix *matrix_expr_evaluate_##PROTO (             \
+    const struct matrix_function_properties *, gsl_matrix *[],  \
+    const struct matrix_expr *, matrix_proto_##PROTO *);
 MATRIX_FUNCTIONS
 #undef F
 
@@ -3672,32 +3662,58 @@ argument_invalid (const struct matrix_function_properties *props,
                    gsl_matrix_get (a, y, x));
 }
 
+enum matrix_argument_relop
+  {
+    MRR_GT,                 /* > */
+    MRR_GE,                 /* >= */
+    MRR_LT,                 /* < */
+    MRR_LE,                 /* <= */
+    MRR_NE,                 /* <> */
+  };
+
 static void
 argument_inequality_error (const struct matrix_function_properties *props,
                            size_t a_index, gsl_matrix *a, size_t y, size_t x,
                            size_t b_index, double b,
-                           bool greater, bool equal)
+                           enum matrix_argument_relop relop)
 {
   struct string s = DS_EMPTY_INITIALIZER;
 
   argument_invalid (props, a_index, a, y, x, &s);
   ds_put_cstr (&s, "  ");
-  if (greater && equal)
-    ds_put_format (&s, _("This argument must be greater than or "
-                         "equal to argument %zu, but that has value %g."),
-                   b_index, b);
-  else if (greater && !equal)
-    ds_put_format (&s, _("This argument must be greater than argument %zu, "
-                         "but that has value %g."),
-                   b_index, b);
-  else if (equal)
-    ds_put_format (&s, _("This argument must be less than or "
-                         "equal to argument %zu, but that has value %g."),
-                   b_index, b);
-  else
-    ds_put_format (&s, _("This argument must be less than argument %zu, "
-                         "but that has value %g."),
-                   b_index, b);
+  switch (relop)
+    {
+    case MRR_GE:
+      ds_put_format (&s, _("This argument must be greater than or "
+                           "equal to argument %zu, but that has value %g."),
+                     b_index, b);
+      break;
+
+    case MRR_GT:
+      ds_put_format (&s, _("This argument must be greater than argument %zu, "
+                           "but that has value %g."),
+                     b_index, b);
+      break;
+
+    case MRR_LE:
+      ds_put_format (&s, _("This argument must be less than or "
+                           "equal to argument %zu, but that has value %g."),
+                     b_index, b);
+      break;
+
+    case MRR_LT:
+      ds_put_format (&s, _("This argument must be less than argument %zu, "
+                           "but that has value %g."),
+                     b_index, b);
+      break;
+
+    case MRR_NE:
+      ds_put_format (&s,
+                     _("This argument must not be the same as argument %zu."),
+                     b_index);
+      break;
+    }
+
   msg (ME, ds_cstr (&s));
   ds_destroy (&s);
 }
@@ -3706,24 +3722,72 @@ static void
 argument_value_error (const struct matrix_function_properties *props,
                       size_t a_index, gsl_matrix *a, size_t y, size_t x,
                       double b,
-                      bool greater, bool equal)
+                      enum matrix_argument_relop relop)
 {
   struct string s = DS_EMPTY_INITIALIZER;
   argument_invalid (props, a_index, a, y, x, &s);
   ds_put_cstr (&s, "  ");
-  if (greater && equal)
-    ds_put_format (&s, _("This argument must be greater than or equal to %g."),
-                   b);
-  else if (greater && !equal)
-    ds_put_format (&s, _("This argument must be greater than %g."), b);
-  else if (equal)
-    ds_put_format (&s, _("This argument must be less than or equal to %g."), b);
-  else
-    ds_put_format (&s, _("This argument must be less than %g."), b);
+  switch (relop)
+    {
+    case MRR_GE:
+      ds_put_format (&s,
+                     _("This argument must be greater than or equal to %g."),
+                     b);
+      break;
+
+    case MRR_GT:
+      ds_put_format (&s, _("This argument must be greater than %g."), b);
+      break;
+
+    case MRR_LE:
+      ds_put_format (&s, _("This argument must be less than or equal to %g."),
+                     b);
+      break;
+
+    case MRR_LT:
+      ds_put_format (&s, _("This argument must be less than %g."), b);
+      break;
+
+    case MRR_NE:
+      ds_put_format (&s, _("This argument may not be %g."), b);
+      break;
+    }
+
   msg (ME, ds_cstr (&s));
   ds_destroy (&s);
 }
 
+static bool
+matrix_argument_relop_is_satisfied (double a, double b,
+                                    enum matrix_argument_relop relop)
+{
+  switch (relop)
+    {
+    case MRR_GE: return a >= b;
+    case MRR_GT: return a > b;
+    case MRR_LE: return a <= b;
+    case MRR_LT: return a < b;
+    case MRR_NE: return a != b;
+    }
+
+  NOT_REACHED ();
+}
+
+static enum matrix_argument_relop
+matrix_argument_relop_flip (enum matrix_argument_relop relop)
+{
+  switch (relop)
+    {
+    case MRR_GE: return MRR_LE;
+    case MRR_GT: return MRR_LT;
+    case MRR_LE: return MRR_GE;
+    case MRR_LT: return MRR_GT;
+    case MRR_NE: return MRR_NE;
+    }
+
+  NOT_REACHED ();
+}
+
 static bool
 check_constraints (const struct matrix_function_properties *props,
                    gsl_matrix *args[], size_t n_args)
@@ -3773,17 +3837,38 @@ check_constraints (const struct matrix_function_properties *props,
                 return false;
               }
         }
-      else if (*constraints == '>' || *constraints == '<')
+      else if (*constraints == '>'
+               || *constraints == '<'
+               || *constraints == '!')
         {
-          bool greater = *constraints++ == '>';
-          bool equal;
-          if (*constraints == '=')
+          enum matrix_argument_relop relop;
+          switch (*constraints++)
             {
-              equal = true;
+            case '>':
+              if (*constraints == '=')
+                {
+                  constraints++;
+                  relop = MRR_GE;
+                }
+              else
+                relop = MRR_GT;
+              break;
+
+            case '<':
+              if (*constraints == '=')
+                {
+                  constraints++;
+                  relop = MRR_LE;
+                }
+              else
+                relop = MRR_LT;
+              break;
+
+            case '!':
+              assert (*constraints == '=');
               constraints++;
+              relop = MRR_NE;
             }
-          else
-            equal = false;
 
           if (*constraints >= 'a' && *constraints <= 'd')
             {
@@ -3801,20 +3886,17 @@ check_constraints (const struct matrix_function_properties *props,
                   size_t tmp_index = a_index;
                   a_index = b_index;
                   b_index = tmp_index;
-
-                  greater = !greater;
+                  relop = matrix_argument_relop_flip (relop);
                 }
 
               double b = to_scalar (args[b_index]);
               MATRIX_FOR_ALL_ELEMENTS (a, y, x, args[a_index])
-                if (greater
-                    ? (equal ? !(*a >= b) : !(*a > b))
-                    : (equal ? !(*a <= b) : !(*a < b)))
+                if (!matrix_argument_relop_is_satisfied (*a, b, relop))
                   {
                     argument_inequality_error (props,
                                                a_index + 1, args[a_index], y, x,
                                                b_index + 1, b,
-                                               greater, equal);
+                                               relop);
                     return false;
                   }
             }
@@ -3823,14 +3905,12 @@ check_constraints (const struct matrix_function_properties *props,
               int comparand = parse_constraint_value (&constraints);
 
               MATRIX_FOR_ALL_ELEMENTS (d, y, x, args[arg_index])
-                if (greater
-                    ? (equal ? !(*d >= comparand) : !(*d > comparand))
-                    : (equal ? !(*d <= comparand) : !(*d < comparand)))
+                if (!matrix_argument_relop_is_satisfied (*d, comparand, relop))
                   {
                     argument_value_error (props,
                                           arg_index + 1, args[arg_index], y, x,
                                           comparand,
-                                          greater, equal);
+                                          relop);
                     return false;
                   }
             }
@@ -3848,10 +3928,10 @@ check_constraints (const struct matrix_function_properties *props,
 static gsl_matrix *
 matrix_expr_evaluate_d_none (
   const struct matrix_function_properties *props UNUSED,
-  gsl_matrix *subs[] UNUSED, size_t n_subs,
+  gsl_matrix *subs[] UNUSED, const struct matrix_expr *e,
   matrix_proto_d_none *f)
 {
-  assert (n_subs == 0);
+  assert (e->n_subs == 0);
 
   gsl_matrix *m = gsl_matrix_alloc (1, 1);
   gsl_matrix_set (m, 0, 0, f ());
@@ -3860,16 +3940,16 @@ matrix_expr_evaluate_d_none (
 
 static gsl_matrix *
 matrix_expr_evaluate_d_d (const struct matrix_function_properties *props,
-                          gsl_matrix *subs[], size_t n_subs,
+                          gsl_matrix *subs[], const struct matrix_expr *e,
                           matrix_proto_d_d *f)
 {
-  assert (n_subs == 1);
+  assert (e->n_subs == 1);
 
   double d;
-  if (!to_scalar_args (props->name, subs, n_subs, &d))
+  if (!to_scalar_args (props->name, subs, e->n_subs, &d))
     return NULL;
 
-  if (!check_constraints (props, subs, n_subs))
+  if (!check_constraints (props, subs, e->n_subs))
     return NULL;
 
   gsl_matrix *m = gsl_matrix_alloc (1, 1);
@@ -3879,16 +3959,16 @@ matrix_expr_evaluate_d_d (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_d_dd (const struct matrix_function_properties *props,
-                           gsl_matrix *subs[], size_t n_subs,
+                           gsl_matrix *subs[], const struct matrix_expr *e,
                            matrix_proto_d_dd *f)
 {
-  assert (n_subs == 2);
+  assert (e->n_subs == 2);
 
   double d[2];
-  if (!to_scalar_args (props->name, subs, n_subs, d))
+  if (!to_scalar_args (props->name, subs, e->n_subs, d))
     return NULL;
 
-  if (!check_constraints (props, subs, n_subs))
+  if (!check_constraints (props, subs, e->n_subs))
     return NULL;
 
   gsl_matrix *m = gsl_matrix_alloc (1, 1);
@@ -3898,16 +3978,16 @@ matrix_expr_evaluate_d_dd (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_d_ddd (const struct matrix_function_properties *props,
-                            gsl_matrix *subs[], size_t n_subs,
+                            gsl_matrix *subs[], const struct matrix_expr *e,
                             matrix_proto_d_ddd *f)
 {
-  assert (n_subs == 3);
+  assert (e->n_subs == 3);
 
   double d[3];
-  if (!to_scalar_args (props->name, subs, n_subs, d))
+  if (!to_scalar_args (props->name, subs, e->n_subs, d))
     return NULL;
 
-  if (!check_constraints (props, subs, n_subs))
+  if (!check_constraints (props, subs, e->n_subs))
     return NULL;
 
   gsl_matrix *m = gsl_matrix_alloc (1, 1);
@@ -3917,54 +3997,63 @@ matrix_expr_evaluate_d_ddd (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_m_d (const struct matrix_function_properties *props,
-                          gsl_matrix *subs[], size_t n_subs,
+                          gsl_matrix *subs[], const struct matrix_expr *e,
                           matrix_proto_m_d *f)
 {
-  assert (n_subs == 1);
+  assert (e->n_subs == 1);
 
   double d;
-  return to_scalar_args (props->name, subs, n_subs, &d) ? f (d) : NULL;
+  return to_scalar_args (props->name, subs, e->n_subs, &d) ? f (d) : NULL;
 }
 
 static gsl_matrix *
 matrix_expr_evaluate_m_dd (const struct matrix_function_properties *props,
-                           gsl_matrix *subs[], size_t n_subs,
+                           gsl_matrix *subs[], const struct matrix_expr *e,
                            matrix_proto_m_dd *f)
 {
-  assert (n_subs == 2);
+  assert (e->n_subs == 2);
 
   double d[2];
-  return to_scalar_args (props->name, subs, n_subs, d) ? f(d[0], d[1]) : NULL;
+  return to_scalar_args (props->name, subs, e->n_subs, d) ? f(d[0], d[1]) : NULL;
 }
 
 static gsl_matrix *
 matrix_expr_evaluate_m_ddd (const struct matrix_function_properties *props,
-                           gsl_matrix *subs[], size_t n_subs,
+                            gsl_matrix *subs[], const struct matrix_expr *e,
                            matrix_proto_m_ddd *f)
 {
-  assert (n_subs == 3);
+  assert (e->n_subs == 3);
 
   double d[3];
-  return to_scalar_args (props->name, subs, n_subs, d) ? f(d[0], d[1], d[2]) : NULL;
+  return to_scalar_args (props->name, subs, e->n_subs, d) ? f(d[0], d[1], d[2]) : NULL;
 }
 
 static gsl_matrix *
 matrix_expr_evaluate_m_m (const struct matrix_function_properties *props UNUSED,
-                          gsl_matrix *subs[], size_t n_subs,
+                          gsl_matrix *subs[], const struct matrix_expr *e,
                           matrix_proto_m_m *f)
 {
-  assert (n_subs == 1);
+  assert (e->n_subs == 1);
   return f (subs[0]);
 }
 
+static gsl_matrix *
+matrix_expr_evaluate_m_me (const struct matrix_function_properties *props UNUSED,
+                           gsl_matrix *subs[], const struct matrix_expr *e,
+                           matrix_proto_m_me *f)
+{
+  assert (e->n_subs == 1);
+  return f (subs[0], e);
+}
+
 static gsl_matrix *
 matrix_expr_evaluate_m_e (const struct matrix_function_properties *props,
-                            gsl_matrix *subs[], size_t n_subs,
-                            matrix_proto_m_e *f)
+                          gsl_matrix *subs[], const struct matrix_expr *e,
+                          matrix_proto_m_e *f)
 {
-  assert (n_subs == 1);
+  assert (e->n_subs == 1);
 
-  if (!check_constraints (props, subs, n_subs))
+  if (!check_constraints (props, subs, e->n_subs))
     return NULL;
 
   MATRIX_FOR_ALL_ELEMENTS (a, y, x, subs[0])
@@ -3974,10 +4063,10 @@ matrix_expr_evaluate_m_e (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_m_md (const struct matrix_function_properties *props UNUSED,
-                           gsl_matrix *subs[], size_t n_subs,
+                           gsl_matrix *subs[], const struct matrix_expr *e,
                            matrix_proto_m_md *f)
 {
-  assert (n_subs == 2);
+  assert (e->n_subs == 2);
   if (!check_scalar_arg (props->name, subs, 1))
     return NULL;
   return f (subs[0], to_scalar (subs[1]));
@@ -3985,14 +4074,14 @@ matrix_expr_evaluate_m_md (const struct matrix_function_properties *props UNUSED
 
 static gsl_matrix *
 matrix_expr_evaluate_m_ed (const struct matrix_function_properties *props,
-                           gsl_matrix *subs[], size_t n_subs,
+                           gsl_matrix *subs[], const struct matrix_expr *e,
                            matrix_proto_m_ed *f)
 {
-  assert (n_subs == 2);
+  assert (e->n_subs == 2);
   if (!check_scalar_arg (props->name, subs, 1))
     return NULL;
 
-  if (!check_constraints (props, subs, n_subs))
+  if (!check_constraints (props, subs, e->n_subs))
     return NULL;
 
   double b = to_scalar (subs[1]);
@@ -4003,10 +4092,10 @@ matrix_expr_evaluate_m_ed (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_m_mdd (const struct matrix_function_properties *props UNUSED,
-                            gsl_matrix *subs[], size_t n_subs,
+                            gsl_matrix *subs[], const struct matrix_expr *e,
                             matrix_proto_m_mdd *f)
 {
-  assert (n_subs == 3);
+  assert (e->n_subs == 3);
   if (!check_scalar_arg (props->name, subs, 1) || !check_scalar_arg (props->name, subs, 2))
     return NULL;
   return f (subs[0], to_scalar (subs[1]), to_scalar (subs[2]));
@@ -4014,14 +4103,14 @@ matrix_expr_evaluate_m_mdd (const struct matrix_function_properties *props UNUSE
 
 static gsl_matrix *
 matrix_expr_evaluate_m_edd (const struct matrix_function_properties *props,
-                            gsl_matrix *subs[], size_t n_subs,
+                            gsl_matrix *subs[], const struct matrix_expr *e,
                             matrix_proto_m_edd *f)
 {
-  assert (n_subs == 3);
+  assert (e->n_subs == 3);
   if (!check_scalar_arg (props->name, subs, 1) || !check_scalar_arg (props->name, subs, 2))
     return NULL;
 
-  if (!check_constraints (props, subs, n_subs))
+  if (!check_constraints (props, subs, e->n_subs))
     return NULL;
 
   double b = to_scalar (subs[1]);
@@ -4033,15 +4122,15 @@ matrix_expr_evaluate_m_edd (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_m_eddd (const struct matrix_function_properties *props,
-                             gsl_matrix *subs[], size_t n_subs,
+                             gsl_matrix *subs[], const struct matrix_expr *e,
                              matrix_proto_m_eddd *f)
 {
-  assert (n_subs == 4);
+  assert (e->n_subs == 4);
   for (size_t i = 1; i < 4; i++)
     if (!check_scalar_arg (props->name, subs, i))
     return NULL;
 
-  if (!check_constraints (props, subs, n_subs))
+  if (!check_constraints (props, subs, e->n_subs))
     return NULL;
 
   double b = to_scalar (subs[1]);
@@ -4054,10 +4143,10 @@ matrix_expr_evaluate_m_eddd (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_m_eed (const struct matrix_function_properties *props,
-                            gsl_matrix *subs[], size_t n_subs,
+                            gsl_matrix *subs[], const struct matrix_expr *e,
                             matrix_proto_m_eed *f)
 {
-  assert (n_subs == 3);
+  assert (e->n_subs == 3);
   if (!check_scalar_arg (props->name, subs, 2))
     return NULL;
 
@@ -4074,7 +4163,7 @@ matrix_expr_evaluate_m_eed (const struct matrix_function_properties *props,
       return NULL;
     }
 
-  if (!check_constraints (props, subs, n_subs))
+  if (!check_constraints (props, subs, e->n_subs))
     return NULL;
 
   double c = to_scalar (subs[2]);
@@ -4097,19 +4186,19 @@ matrix_expr_evaluate_m_eed (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_m_mm (const struct matrix_function_properties *props UNUSED,
-                           gsl_matrix *subs[], size_t n_subs,
+                           gsl_matrix *subs[], const struct matrix_expr *e,
                            matrix_proto_m_mm *f)
 {
-  assert (n_subs == 2);
+  assert (e->n_subs == 2);
   return f (subs[0], subs[1]);
 }
 
 static gsl_matrix *
 matrix_expr_evaluate_m_v (const struct matrix_function_properties *props,
-                          gsl_matrix *subs[], size_t n_subs,
+                          gsl_matrix *subs[], const struct matrix_expr *e,
                           matrix_proto_m_v *f)
 {
-  assert (n_subs == 1);
+  assert (e->n_subs == 1);
   if (!check_vector_arg (props->name, subs, 0))
     return NULL;
   gsl_vector v = to_vector (subs[0]);
@@ -4118,10 +4207,10 @@ matrix_expr_evaluate_m_v (const struct matrix_function_properties *props,
 
 static gsl_matrix *
 matrix_expr_evaluate_d_m (const struct matrix_function_properties *props UNUSED,
-                          gsl_matrix *subs[], size_t n_subs,
+                          gsl_matrix *subs[], const struct matrix_expr *e,
                           matrix_proto_d_m *f)
 {
-  assert (n_subs == 1);
+  assert (e->n_subs == 1);
 
   gsl_matrix *m = gsl_matrix_alloc (1, 1);
   gsl_matrix_set (m, 0, 0, f (subs[0]));
@@ -4130,24 +4219,24 @@ matrix_expr_evaluate_d_m (const struct matrix_function_properties *props UNUSED,
 
 static gsl_matrix *
 matrix_expr_evaluate_m_any (const struct matrix_function_properties *props UNUSED,
-                          gsl_matrix *subs[], size_t n_subs,
-                          matrix_proto_m_any *f)
+                            gsl_matrix *subs[], const struct matrix_expr *e,
+                            matrix_proto_m_any *f)
 {
-  return f (subs, n_subs);
+  return f (subs, e->n_subs);
 }
 
 static gsl_matrix *
 matrix_expr_evaluate_IDENT (const struct matrix_function_properties *props,
-                            gsl_matrix *subs[], size_t n_subs,
+                            gsl_matrix *subs[], const struct matrix_expr *e,
                             matrix_proto_IDENT *f)
 {
-  assert (n_subs <= 2);
+  assert (e->n_subs <= 2);
 
   double d[2];
-  if (!to_scalar_args (props->name, subs, n_subs, d))
+  if (!to_scalar_args (props->name, subs, e->n_subs, d))
     return NULL;
 
-  return f (d[0], d[n_subs - 1]);
+  return f (d[0], d[e->n_subs - 1]);
 }
 
 static gsl_matrix *
@@ -4210,7 +4299,7 @@ matrix_expr_evaluate (const struct matrix_expr *e)
             .name = STRING,                                             \
             .constraints = CONSTRAINTS,                                 \
           };                                                            \
-          result = matrix_expr_evaluate_##PROTO (&props, subs, e->n_subs, \
+          result = matrix_expr_evaluate_##PROTO (&props, subs, e,       \
                                                  matrix_eval_##ENUM);   \
         }                                                               \
       break;
@@ -4348,9 +4437,11 @@ matrix_expr_evaluate_integer (const struct matrix_expr *e, const char *context,
 struct matrix_lvalue
   {
     struct matrix_var *var;
-    struct msg_location *var_location;
     struct matrix_expr *indexes[2];
     size_t n_indexes;
+
+    struct msg_location *var_location; /* Variable name. */
+    struct msg_location *index_location; /* Variable name plus indexing. */
   };
 
 static void
@@ -4358,6 +4449,8 @@ matrix_lvalue_destroy (struct matrix_lvalue *lvalue)
 {
   if (lvalue)
     {
+      msg_location_destroy (lvalue->var_location);
+      msg_location_destroy (lvalue->index_location);
       for (size_t i = 0; i < lvalue->n_indexes; i++)
         matrix_expr_destroy (lvalue->indexes[i]);
       free (lvalue);
@@ -4395,6 +4488,9 @@ matrix_lvalue_parse (struct matrix_state *s)
         }
       if (!lex_force_match (s->lexer, T_RPAREN))
         goto error;
+
+      lvalue->index_location = msg_location_dup (lvalue->var_location);
+      lex_extend_location (s->lexer, -1, lvalue->index_location);
     }
   else
     {
@@ -6181,10 +6277,8 @@ parse_error (const struct dfm_reader *reader, enum fmt_type format,
   struct msg_location *location = xmalloc (sizeof *location);
   *location = (struct msg_location) {
     .file_name = intern_new (dfm_get_file_name (reader)),
-    .first_line = line_number,
-    .last_line = line_number + 1,
-    .first_column = first_column,
-    .last_column = last_column,
+    .p[0] = { .line = line_number, .column = first_column },
+    .p[1] = { .line = line_number, .column = last_column },
   };
   struct msg *m = xmalloc (sizeof *m);
   *m = (struct msg) {
@@ -6230,7 +6324,7 @@ matrix_read_set_field (struct read_command *read, struct dfm_reader *reader,
   if (error)
     {
       int c1 = utf8_count_columns (line_start, p.string - line_start) + 1;
-      int c2 = c1 + ss_utf8_count_columns (p) - 1;
+      int c2 = c1 + ss_utf8_count_columns (p);
       parse_error (reader, read->format, p, y, x, c1, c2, error);
     }
   else
index d71df204ea46a5dd4774246e11b1f2ef25a6e361..526e19f3a016619dbd948c1f0c111db22bc3140e 100644 (file)
@@ -134,6 +134,35 @@ msg_location_destroy (struct msg_location *loc)
     }
 }
 
+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)
+{
+  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)
 {
@@ -143,10 +172,8 @@ msg_location_dup (const struct msg_location *src)
   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,
+    .p[0] = src->p[0],
+    .p[1] = src->p[1],
   };
   return dst;
 }
@@ -155,8 +182,8 @@ bool
 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
@@ -168,10 +195,10 @@ msg_location_format (const struct msg_location *loc, struct string *s)
   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)
     {
index f0066ee0a745adbd9a2150281a89255947e315ff..d54598b6960513d7f5b0b2797f8b3528da50879e 100644 (file)
@@ -72,20 +72,29 @@ msg_class_from_category_and_severity (enum msg_category category,
   return category * 3 + severity;
 }
 
+struct msg_point
+  {
+    int line;                   /* 1-based line number, or 0 if none. */
+    int column;                 /* 1-based column number, or 0 if none. */
+  };
+
 struct msg_location
   {
     const char *file_name;      /* Interned file name, or NULL. */
+    struct msg_point p[2];
+#if 0
     int first_line;             /* 1-based line number, or 0 if none. */
     int last_line;              /* 1-based exclusive last line (0=none). */
     int first_column;           /* 1-based first column, or 0 if none. */
     int last_column;            /* 1-based exclusive last column (0=none). */
+#endif
   };
 
 void msg_location_uninit (struct msg_location *);
 void msg_location_destroy (struct msg_location *);
 struct msg_location *msg_location_dup (const struct msg_location *);
 
-void msg_location_merge (struct msg_location **, const struct msg_location *);
+void msg_location_merge (struct msg_location *, const struct msg_location *);
 
 bool msg_location_is_empty (const struct msg_location *);
 void msg_location_format (const struct msg_location *, struct string *);