parsing postcomputes into categories
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 12 Feb 2022 19:01:39 +0000 (11:01 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 13 Mar 2022 23:56:02 +0000 (16:56 -0700)
src/language/stats/ctables.c

index 9dd1fd55a6b43346250bb43b8ed13f7ada6002dc..7f324349bfd233d46ce5f65826baadfd948b1e13 100644 (file)
@@ -242,6 +242,9 @@ struct ctables
     size_t n_tables;
   };
 
+static struct ctables_postcompute *ctables_find_postcompute (struct ctables *,
+                                                             const char *name);
+
 struct ctables_postcompute
   {
     struct hmap_node hmap_node; /* In struct ctables's 'pcompute' hmap. */
@@ -455,6 +458,7 @@ struct ctables_category
         CCT_RANGE,
         CCT_MISSING,
         CCT_OTHERNM,
+        CCT_POSTCOMPUTE,
 
         /* Totals and subtotals. */
         CCT_SUBTOTAL,
@@ -475,7 +479,8 @@ struct ctables_category
         double number;          /* CCT_NUMBER. */
         char *string;           /* CCT_STRING. */
         double range[2];        /* CCT_RANGE. */
-        char *total_label;   /* CCT_SUBTOTAL, CCT_HSUBTOTAL, CCT_TOTAL. */
+        char *total_label;      /* CCT_SUBTOTAL, CCT_HSUBTOTAL, CCT_TOTAL. */
+        const struct ctables_postcompute *pc; /* CCT_POSTCOMPUTE. */
 
         /* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */
         struct
@@ -503,6 +508,7 @@ ctables_category_uninit (struct ctables_category *cat)
     case CCT_RANGE:
     case CCT_MISSING:
     case CCT_OTHERNM:
+    case CCT_POSTCOMPUTE:
       break;
 
     case CCT_STRING:
@@ -544,6 +550,9 @@ ctables_category_equal (const struct ctables_category *a,
     case CCT_OTHERNM:
       return true;
 
+    case CCT_POSTCOMPUTE:
+      return a->pc == b->pc;
+
     case CCT_SUBTOTAL:
     case CCT_HSUBTOTAL:
     case CCT_TOTAL:
@@ -1302,7 +1311,7 @@ cct_range (double low, double high)
 
 static bool
 ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
-                                struct ctables_table *t)
+                                struct ctables *ct, struct ctables_table *t)
 {
   if (!lex_match_id (lexer, "VARIABLES"))
     return false;
@@ -1380,6 +1389,27 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
               };
               lex_get (lexer);
             }
+          else if (lex_match (lexer, T_AND))
+            {
+              if (!lex_force_id (lexer))
+                return false;
+              struct ctables_postcompute *pc = ctables_find_postcompute (
+                ct, lex_tokcstr (lexer));
+              if (!pc)
+                {
+                  struct msg_location *loc = lex_get_location (lexer, -1, 0);
+                  msg_at (SE, loc, _("Unknown postcompute &%s."),
+                          lex_tokcstr (lexer));
+                  msg_location_destroy (loc);
+                  return false;
+                }
+              lex_get (lexer);
+
+              *cat = (struct ctables_category) {
+                .type = CCT_POSTCOMPUTE,
+                .pc = pc,
+              };
+            }
           else
             {
               lex_error (lexer, NULL);
@@ -1578,6 +1608,9 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
           cat->subtotal = subtotal;
           break;
 
+        case CCT_POSTCOMPUTE:
+          break;
+
         case CCT_SUBTOTAL:
         case CCT_HSUBTOTAL:
           subtotal = cat;
@@ -2343,6 +2376,7 @@ ctables_cell_compare_3way (const void *a_, const void *b_, const void *aux_)
           case CCT_SUBTOTAL:
           case CCT_HSUBTOTAL:
           case CCT_TOTAL:
+          case CCT_POSTCOMPUTE:
             /* Must be equal. */
             continue;
 
@@ -2474,6 +2508,9 @@ ctables_categories_match (const struct ctables_categories *c,
             return cat;
           break;
 
+        case CCT_POSTCOMPUTE:
+          break;
+
         case CCT_OTHERNM:
           if (!othernm)
             othernm = cat;
@@ -3462,6 +3499,9 @@ ctables_add_category_occurrences (const struct variable *var,
             ctables_add_occurrence (var, &vl->value, occurrences);
           break;
 
+        case CCT_POSTCOMPUTE:
+          break;
+
         case CCT_SUBTOTAL:
         case CCT_HSUBTOTAL:
         case CCT_TOTAL:
@@ -4564,7 +4604,8 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds)
             }
           else if (lex_match_id (lexer, "CATEGORIES"))
             {
-              if (!ctables_table_parse_categories (lexer, dataset_dict (ds), t))
+              if (!ctables_table_parse_categories (lexer, dataset_dict (ds),
+                                                   ct, t))
                 goto error;
             }
           else if (lex_match_id (lexer, "TITLES"))