check number of args to matrix functions
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 21 Nov 2021 21:32:36 +0000 (13:32 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 21 Nov 2021 21:32:36 +0000 (13:32 -0800)
src/language/stats/matrix.c
tests/language/stats/matrix.at

index b507f022fa886bba070c7a67bacd393b3183c107..c166473e87d9f7f01aa90a04aa008e1ed35b4924 100644 (file)
@@ -2640,21 +2640,47 @@ matrix_parse_function (struct matrix_state *s, const char *token,
   struct matrix_expr *e = xmalloc (sizeof *e);
   *e = (struct matrix_expr) { .op = f->op, .subs = NULL };
 
-  size_t allocated_subs = 0;
-  do
+  if (lex_token (s->lexer) != T_RPAREN)
     {
-      struct matrix_expr *sub = matrix_parse_expr (s);
-      if (!sub)
-        goto error;
+      size_t allocated_subs = 0;
+      do
+        {
+          struct matrix_expr *sub = matrix_parse_expr (s);
+          if (!sub)
+            goto error;
 
-      if (e->n_subs >= allocated_subs)
-        e->subs = x2nrealloc (e->subs, &allocated_subs, sizeof *e->subs);
-      e->subs[e->n_subs++] = sub;
+          if (e->n_subs >= allocated_subs)
+            e->subs = x2nrealloc (e->subs, &allocated_subs, sizeof *e->subs);
+          e->subs[e->n_subs++] = sub;
+        }
+      while (lex_match (s->lexer, T_COMMA));
     }
-  while (lex_match (s->lexer, T_COMMA));
   if (!lex_force_match (s->lexer, T_RPAREN))
     goto error;
 
+  if (e->n_subs < f->min_args || e->n_subs > f->max_args)
+    {
+      if (f->min_args == f->max_args)
+        msg (SE, ngettext ("Matrix function %s requires %zu argument.",
+                           "Matrix function %s requires %zu arguments.",
+                           f->min_args),
+             f->name, f->min_args);
+      else if (f->min_args == 1 && f->max_args == 2)
+        msg (SE, ngettext ("Matrix function %s requires 1 or 2 arguments, "
+                           "but %zu was provided.",
+                           "Matrix function %s requires 1 or 2 arguments, "
+                           "but %zu were provided.",
+                           e->n_subs),
+             f->name, e->n_subs);
+      else if (f->min_args == 1 && f->max_args == INT_MAX)
+        msg (SE, _("Matrix function %s requires at least one argument."),
+             f->name);
+      else
+        NOT_REACHED ();
+
+      goto error;
+    }
+
   *exprp = e;
   return true;
 
index d8998f6e87dfd8dddcd5048c7ad07609c9186092..bd81cd7ec99cc5dae31ce8614f7fe1eb4e716e22 100644 (file)
@@ -1434,7 +1434,7 @@ PRINT LN({1, 2; 3, 4})/FORMAT F5.2.
 PRINT LN(0).
 END MATRIX.
 ])
-AT_CHECK([pspp matrix.sps], [0], [dnl
+AT_CHECK([pspp matrix.sps], [1], [dnl
 IDENT(1)
   1
 
@@ -1480,8 +1480,8 @@ LN({1, 2; 3, 4})
    .00   .69
   1.10  1.39
 
-LN(0)
- -In
+error: Argument 1 to matrix function LN has invalid value 0.  This argument
+must be greater than 0.
 ])
 AT_CLEANUP
 
@@ -1996,6 +1996,35 @@ AT_CHECK([pspp matrix.sps], [0], [dnl
 ])
 AT_CLEANUP
 
+AT_SETUP([MATRIX - invalid number function arguments])
+AT_DATA([matrix.sps], [dnl
+MATRIX.
+COMPUTE x=ABS().
+COMPUTE x=ABS(1,2).
+COMPUTE x=KRONEKER(1,2,3).
+COMPUTE x=IDENT().
+COMPUTE x=IDENT(1,2,3).
+COMPUTE x=BLOCK().
+END MATRIX.
+])
+AT_CHECK([pspp matrix.sps], [1], [dnl
+matrix.sps:2: error: COMPUTE: Matrix function ABS requires 1 argument.
+
+matrix.sps:3: error: COMPUTE: Matrix function ABS requires 1 argument.
+
+matrix.sps:4: error: COMPUTE: Matrix function KRONEKER requires 2 arguments.
+
+matrix.sps:5: error: COMPUTE: Matrix function IDENT requires 1 or 2 arguments,
+but 0 were provided.
+
+matrix.sps:6: error: COMPUTE: Matrix function IDENT requires 1 or 2 arguments,
+but 3 were provided.
+
+matrix.sps:7: error: COMPUTE: Matrix function BLOCK requires at least one
+argument.
+])
+AT_CLEANUP
+
 AT_SETUP([MATRIX - CALL SETDIAG])
 AT_DATA([matrix.sps], [dnl
 MATRIX.