FACTOR: Improve error messages and coding style.
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 20 Nov 2022 01:48:08 +0000 (17:48 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 20 Nov 2022 01:48:08 +0000 (17:48 -0800)
src/language/stats/factor.c
tests/language/stats/factor.at

index b93e5ea31eaba80a68a999de510710b67b27d4c2..f4e9a8a7bed85189b9d584b7d6fcf11ba8b111a4 100644 (file)
@@ -1022,10 +1022,8 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
   else if (lex_match_id (lexer, "MATRIX"))
     {
       lex_match (lexer, T_EQUALS);
-      if (!lex_force_match_id (lexer, "IN"))
+      if (!lex_force_match_phrase (lexer, "IN("))
        goto error;
-      if (!lex_force_match (lexer, T_LPAREN))
-        goto error;
       if (!lex_match_id (lexer, "CORR") && !lex_match_id (lexer, "COV"))
        {
          lex_error (lexer, _("Matrix input for %s must be either COV or CORR"),
@@ -1054,7 +1052,10 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
       vars_end = lex_ofs (lexer) - 1;
 
       if (!lex_force_match (lexer, T_RPAREN))
-       goto error;
+        {
+          casereader_destroy (matrix_reader);
+          goto error;
+        }
 
       mr = matrix_reader_create (dict, matrix_reader);
       factor.vars = xmemdup (mr->cvars, mr->n_cvars * sizeof *mr->cvars);
@@ -1112,7 +1113,11 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
 #endif
              else
                {
-                 lex_error (lexer, NULL);
+                 lex_error_expecting (lexer, "EIGEN"
+#if FACTOR_FULLY_IMPLEMENTED
+                                       , "ROTATION"
+#endif
+                                       );
                  goto error;
                }
            }
@@ -1148,9 +1153,10 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
              else if (lex_match_id (lexer, "PROMAX"))
                {
                  factor.promax_power = 5;
-                 if (lex_match (lexer, T_LPAREN)
-                      && lex_force_int (lexer))
-                   {
+                 if (lex_match (lexer, T_LPAREN))
+                    {
+                      if (!lex_force_int (lexer))
+                        goto error;
                      factor.promax_power = lex_integer (lexer);
                      lex_get (lexer);
                      if (!lex_force_match (lexer, T_RPAREN))
@@ -1176,58 +1182,53 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
            {
              if (lex_match_id (lexer, "FACTORS"))
                {
-                 if (lex_force_match (lexer, T_LPAREN)
-                      && lex_force_int (lexer))
-                   {
-                     factor.n_factors = lex_integer (lexer);
-                     lex_get (lexer);
-                     if (!lex_force_match (lexer, T_RPAREN))
-                       goto error;
-                   }
+                 if (!lex_force_match (lexer, T_LPAREN)
+                      || !lex_force_int (lexer))
+                    goto error;
+                  factor.n_factors = lex_integer (lexer);
+                  lex_get (lexer);
+                  if (!lex_force_match (lexer, T_RPAREN))
+                    goto error;
                }
              else if (lex_match_id (lexer, "MINEIGEN"))
                {
-                 if (lex_force_match (lexer, T_LPAREN)
-                      && lex_force_num (lexer))
-                   {
-                     factor.min_eigen = lex_number (lexer);
-                     lex_get (lexer);
-                     if (!lex_force_match (lexer, T_RPAREN))
-                       goto error;
-                   }
+                 if (!lex_force_match (lexer, T_LPAREN)
+                      || !lex_force_num (lexer))
+                    goto error;
+                  factor.min_eigen = lex_number (lexer);
+                  lex_get (lexer);
+                  if (!lex_force_match (lexer, T_RPAREN))
+                    goto error;
                }
              else if (lex_match_id (lexer, "ECONVERGE"))
                {
-                 if (lex_force_match (lexer, T_LPAREN)
-                      && lex_force_num (lexer))
-                   {
-                     factor.econverge = lex_number (lexer);
-                     lex_get (lexer);
-                     if (!lex_force_match (lexer, T_RPAREN))
-                       goto error;
-                   }
+                 if (!lex_force_match (lexer, T_LPAREN)
+                      || !lex_force_num (lexer))
+                    goto error;
+                  factor.econverge = lex_number (lexer);
+                  lex_get (lexer);
+                  if (!lex_force_match (lexer, T_RPAREN))
+                    goto error;
                }
              else if (lex_match_id (lexer, "RCONVERGE"))
                 {
-                  if (lex_force_match (lexer, T_LPAREN)
-                      && lex_force_num (lexer))
-                    {
-                      factor.rconverge = lex_number (lexer);
-                      lex_get (lexer);
-                      if (!lex_force_match (lexer, T_RPAREN))
-                       goto error;
-                    }
+                  if (!lex_force_match (lexer, T_LPAREN)
+                      || !lex_force_num (lexer))
+                    goto error;
+                  factor.rconverge = lex_number (lexer);
+                  lex_get (lexer);
+                  if (!lex_force_match (lexer, T_RPAREN))
+                    goto error;
                }
              else if (lex_match_id (lexer, "ITERATE"))
                {
-                 if (lex_force_match (lexer, T_LPAREN)
-                      && lex_force_int_range (lexer, "ITERATE", 0, INT_MAX))
-                   {
-                     n_iterations = lex_integer (lexer);
-                     lex_get (lexer);
-                     if (!lex_force_match (lexer, T_RPAREN))
-                       goto error;
-                   }
+                 if (!lex_force_match (lexer, T_LPAREN)
+                      || !lex_force_int_range (lexer, "ITERATE", 0, INT_MAX))
+                    goto error;
+                  n_iterations = lex_integer (lexer);
+                  lex_get (lexer);
+                  if (!lex_force_match (lexer, T_RPAREN))
+                    goto error;
                }
              else if (lex_match_id (lexer, "DEFAULT"))
                {
@@ -1274,14 +1275,13 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
                 factor.sort = true;
              else if (lex_match_id (lexer, "BLANK"))
                {
-                 if (lex_force_match (lexer, T_LPAREN)
-                      && lex_force_num (lexer))
-                   {
-                     factor.blank = lex_number (lexer);
-                     lex_get (lexer);
-                     if (!lex_force_match (lexer, T_RPAREN))
-                       goto error;
-                   }
+                 if (!lex_force_match (lexer, T_LPAREN)
+                      || !lex_force_num (lexer))
+                    goto error;
+                  factor.blank = lex_number (lexer);
+                  lex_get (lexer);
+                  if (!lex_force_match (lexer, T_RPAREN))
+                    goto error;
                }
              else if (lex_match_id (lexer, "DEFAULT"))
                {
@@ -1377,7 +1377,9 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
        }
       else
        {
-         lex_error (lexer, NULL);
+         lex_error_expecting (lexer, "ANALYSIS", "PLOT", "METHOD", "ROTATION",
+                               "CRITERIA", "EXTRACTION", "FORMAT", "PRINT",
+                               "MISSING");
          goto error;
        }
     }
@@ -1385,17 +1387,11 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
   if (factor.rotation == ROT_NONE)
     factor.print &= ~PRINT_ROTATION;
 
+  assert (factor.n_vars > 0);
   if (factor.n_vars < 2)
     lex_ofs_msg (lexer, SW, vars_start, vars_end,
                  _("Factor analysis on a single variable is not useful."));
 
-  if (factor.n_vars < 1)
-    {
-      lex_ofs_error (lexer, vars_start, vars_end,
-                     _("Factor analysis without variables is not possible."));
-      goto error;
-    }
-
   if (matrix_reader)
     {
       struct idata *id = idata_alloc (factor.n_vars);
index c066dae52b14ea580ad79b1174295679f112a45b..972bf633eb60eba61f463ffeb1daf62840b913d6 100644 (file)
@@ -2400,3 +2400,188 @@ piatc,.774,.122,-.368,.365,-.322
 ])
 
 AT_CLEANUP
+
+AT_SETUP([FACTOR syntax errors])
+AT_DATA([factor.sps], [dnl
+DATA LIST LIST NOTABLE /x y.
+FACTOR VARIABLES=**.
+FACTOR MATRIX=**.
+FACTOR MATRIX=IN **.
+FACTOR MATRIX=IN(**).
+FACTOR MATRIX=IN(CORR **).
+FACTOR MATRIX=IN(CORR=**).
+FACTOR MATRIX=IN(CORR=* **).
+FACTOR **.
+FACTOR VARIABLES=x/ANALYSIS=**.
+FACTOR VARIABLES=x/PLOT=**.
+FACTOR VARIABLES=x/METHOD=**.
+FACTOR VARIABLES=x/ROTATION=PROMAX(**).
+FACTOR VARIABLES=x/ROTATION=PROMAX(123 **).
+FACTOR VARIABLES=x/ROTATION=**.
+FACTOR VARIABLES=x/CRITERIA=FACTORS **.
+FACTOR VARIABLES=x/CRITERIA=FACTORS(**).
+FACTOR VARIABLES=x/CRITERIA=FACTORS(123 **).
+FACTOR VARIABLES=x/CRITERIA=MINEIGEN **.
+FACTOR VARIABLES=x/CRITERIA=MINEIGEN(**).
+FACTOR VARIABLES=x/CRITERIA=MINEIGEN(123 **).
+FACTOR VARIABLES=x/CRITERIA=ECONVERGE **.
+FACTOR VARIABLES=x/CRITERIA=ECONVERGE(**).
+FACTOR VARIABLES=x/CRITERIA=ECONVERGE(123 **).
+FACTOR VARIABLES=x/CRITERIA=RCONVERGE **.
+FACTOR VARIABLES=x/CRITERIA=RCONVERGE(**).
+FACTOR VARIABLES=x/CRITERIA=RCONVERGE(123 **).
+FACTOR VARIABLES=x/CRITERIA=**.
+FACTOR VARIABLES=x/EXTRACTION=**.
+FACTOR VARIABLES=x/FORMAT=BLANK **.
+FACTOR VARIABLES=x/FORMAT=BLANK(**).
+FACTOR VARIABLES=x/FORMAT=BLANK(123 **).
+FACTOR VARIABLES=x/FORMAT=**.
+FACTOR VARIABLES=x/PRINT=**.
+FACTOR VARIABLES=x/MISSING=**.
+FACTOR VARIABLES=x/ **.
+FACTOR VARIABLES=x.
+])
+AT_CHECK([pspp -O format=csv factor.sps], [1], [dnl
+"factor.sps:2.18-2.19: error: FACTOR: Syntax error expecting variable name.
+    2 | FACTOR VARIABLES=**.
+      |                  ^~"
+
+"factor.sps:3.15-3.16: error: FACTOR: Syntax error expecting `IN('.
+    3 | FACTOR MATRIX=**.
+      |               ^~"
+
+"factor.sps:4.15-4.19: error: FACTOR: Syntax error expecting `IN('.
+    4 | FACTOR MATRIX=IN **.
+      |               ^~~~~"
+
+"factor.sps:5.18-5.19: error: FACTOR: Matrix input for FACTOR must be either COV or CORR.
+    5 | FACTOR MATRIX=IN(**).
+      |                  ^~"
+
+"factor.sps:6.23-6.24: error: FACTOR: Syntax error expecting `='.
+    6 | FACTOR MATRIX=IN(CORR **).
+      |                       ^~"
+
+"factor.sps:7.23-7.24: error: FACTOR: Syntax error expecting a file name or handle name.
+    7 | FACTOR MATRIX=IN(CORR=**).
+      |                       ^~"
+
+"factor.sps:8.25-8.26: error: FACTOR: Syntax error expecting `)'.
+    8 | FACTOR MATRIX=IN(CORR=* **).
+      |                         ^~"
+
+"factor.sps:10.29-10.30: error: FACTOR: Syntax error expecting variable name.
+   10 | FACTOR VARIABLES=x/ANALYSIS=**.
+      |                             ^~"
+
+"factor.sps:11.25-11.26: error: FACTOR: Syntax error expecting EIGEN.
+   11 | FACTOR VARIABLES=x/PLOT=**.
+      |                         ^~"
+
+"factor.sps:12.27-12.28: error: FACTOR: Syntax error expecting COVARIANCE or CORRELATION.
+   12 | FACTOR VARIABLES=x/METHOD=**.
+      |                           ^~"
+
+"factor.sps:13.36-13.37: error: FACTOR: Syntax error expecting integer.
+   13 | FACTOR VARIABLES=x/ROTATION=PROMAX(**).
+      |                                    ^~"
+
+"factor.sps:14.40-14.41: error: FACTOR: Syntax error expecting `)'.
+   14 | FACTOR VARIABLES=x/ROTATION=PROMAX(123 **).
+      |                                        ^~"
+
+"factor.sps:15.29-15.30: error: FACTOR: Syntax error expecting DEFAULT, VARIMAX, EQUAMAX, QUARTIMAX, PROMAX, or NOROTATE.
+   15 | FACTOR VARIABLES=x/ROTATION=**.
+      |                             ^~"
+
+"factor.sps:16.37-16.38: error: FACTOR: Syntax error expecting `('.
+   16 | FACTOR VARIABLES=x/CRITERIA=FACTORS **.
+      |                                     ^~"
+
+"factor.sps:17.37-17.38: error: FACTOR: Syntax error expecting integer.
+   17 | FACTOR VARIABLES=x/CRITERIA=FACTORS(**).
+      |                                     ^~"
+
+"factor.sps:18.41-18.42: error: FACTOR: Syntax error expecting `)'.
+   18 | FACTOR VARIABLES=x/CRITERIA=FACTORS(123 **).
+      |                                         ^~"
+
+"factor.sps:19.38-19.39: error: FACTOR: Syntax error expecting `('.
+   19 | FACTOR VARIABLES=x/CRITERIA=MINEIGEN **.
+      |                                      ^~"
+
+"factor.sps:20.38-20.39: error: FACTOR: Syntax error expecting number.
+   20 | FACTOR VARIABLES=x/CRITERIA=MINEIGEN(**).
+      |                                      ^~"
+
+"factor.sps:21.42-21.43: error: FACTOR: Syntax error expecting `)'.
+   21 | FACTOR VARIABLES=x/CRITERIA=MINEIGEN(123 **).
+      |                                          ^~"
+
+"factor.sps:22.39-22.40: error: FACTOR: Syntax error expecting `('.
+   22 | FACTOR VARIABLES=x/CRITERIA=ECONVERGE **.
+      |                                       ^~"
+
+"factor.sps:23.39-23.40: error: FACTOR: Syntax error expecting number.
+   23 | FACTOR VARIABLES=x/CRITERIA=ECONVERGE(**).
+      |                                       ^~"
+
+"factor.sps:24.43-24.44: error: FACTOR: Syntax error expecting `)'.
+   24 | FACTOR VARIABLES=x/CRITERIA=ECONVERGE(123 **).
+      |                                           ^~"
+
+"factor.sps:25.39-25.40: error: FACTOR: Syntax error expecting `('.
+   25 | FACTOR VARIABLES=x/CRITERIA=RCONVERGE **.
+      |                                       ^~"
+
+"factor.sps:26.39-26.40: error: FACTOR: Syntax error expecting number.
+   26 | FACTOR VARIABLES=x/CRITERIA=RCONVERGE(**).
+      |                                       ^~"
+
+"factor.sps:27.43-27.44: error: FACTOR: Syntax error expecting `)'.
+   27 | FACTOR VARIABLES=x/CRITERIA=RCONVERGE(123 **).
+      |                                           ^~"
+
+"factor.sps:28.29-28.30: error: FACTOR: Syntax error expecting FACTORS, MINEIGEN, ECONVERGE, RCONVERGE, ITERATE, or DEFAULT.
+   28 | FACTOR VARIABLES=x/CRITERIA=**.
+      |                             ^~"
+
+"factor.sps:29.31-29.32: error: FACTOR: Syntax error expecting PAF, PC, PA1, or DEFAULT.
+   29 | FACTOR VARIABLES=x/EXTRACTION=**.
+      |                               ^~"
+
+"factor.sps:30.33-30.34: error: FACTOR: Syntax error expecting `('.
+   30 | FACTOR VARIABLES=x/FORMAT=BLANK **.
+      |                                 ^~"
+
+"factor.sps:31.33-31.34: error: FACTOR: Syntax error expecting number.
+   31 | FACTOR VARIABLES=x/FORMAT=BLANK(**).
+      |                                 ^~"
+
+"factor.sps:32.37-32.38: error: FACTOR: Syntax error expecting `)'.
+   32 | FACTOR VARIABLES=x/FORMAT=BLANK(123 **).
+      |                                     ^~"
+
+"factor.sps:33.27-33.28: error: FACTOR: Syntax error expecting SORT, BLANK, or DEFAULT.
+   33 | FACTOR VARIABLES=x/FORMAT=**.
+      |                           ^~"
+
+"factor.sps:34.26-34.27: error: FACTOR: Syntax error expecting one of the following: UNIVARIATE, DET, AIC, SIG, CORRELATION, COVARIANCE, ROTATION, EXTRACTION, INITIAL, KMO, ALL, DEFAULT.
+   34 | FACTOR VARIABLES=x/PRINT=**.
+      |                          ^~"
+
+"factor.sps:35.28-35.29: error: FACTOR: Syntax error expecting INCLUDE, EXCLUDE, LISTWISE, PAIRRWISE, or MEANSUB.
+   35 | FACTOR VARIABLES=x/MISSING=**.
+      |                            ^~"
+
+"factor.sps:36.21-36.22: error: FACTOR: Syntax error expecting one of the following: ANALYSIS, PLOT, METHOD, ROTATION, CRITERIA, EXTRACTION, FORMAT, PRINT, MISSING.
+   36 | FACTOR VARIABLES=x/ **.
+      |                     ^~"
+
+"factor.sps:37.18: warning: FACTOR: Factor analysis on a single variable is not useful.
+   37 | FACTOR VARIABLES=x.
+      |                  ^"
+
+error: FACTOR: At end of input: Syntax error expecting `BEGIN DATA'.
+])
+AT_CLEANUP
\ No newline at end of file