pcompute string ranges
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 4 Jul 2022 20:19:11 +0000 (13:19 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 4 Jul 2022 20:19:11 +0000 (13:19 -0700)
src/language/stats/ctables.c
tests/language/stats/ctables.at

index 5df2435b7b17f7eb785a4800a68738e525905613..e745794781460af6a891a2956b3e125cc0c6e8e4 100644 (file)
@@ -294,7 +294,8 @@ struct ctables_pcexpr
         CTPO_CONSTANT,          /* 5 */
         CTPO_CAT_NUMBER,        /* [5] */
         CTPO_CAT_STRING,        /* ["STRING"] */
-        CTPO_CAT_RANGE,         /* [LO THRU 5] */
+        CTPO_CAT_NRANGE,        /* [LO THRU 5] */
+        CTPO_CAT_SRANGE,        /* ["A" THRU "B"] */
         CTPO_CAT_MISSING,       /* MISSING */
         CTPO_CAT_OTHERNM,       /* OTHERNM */
         CTPO_CAT_SUBTOTAL,      /* SUBTOTAL */
@@ -318,8 +319,11 @@ struct ctables_pcexpr
         /* CTPO_CAT_STRING, in dictionary encoding. */
         struct substring string;
 
-        /* CTPO_CAT_RANGE. */
-        double range[2];
+        /* CTPO_CAT_NRANGE. */
+        double nrange[2];
+
+        /* CTPO_CAT_SRANGE. */
+        struct substring srange[2];
 
         /* CTPO_CAT_SUBTOTAL. */
         size_t subtotal_index;
@@ -1599,10 +1603,17 @@ ctables_find_category_for_postcompute (const struct ctables_categories *cats,
             best = cat;
           break;
 
-        case CTPO_CAT_RANGE:
+        case CTPO_CAT_NRANGE:
           if (cat->type == CCT_NRANGE
-              && cat->nrange[0] == e->range[0]
-              && cat->nrange[1] == e->range[1])
+              && cat->nrange[0] == e->nrange[0]
+              && cat->nrange[1] == e->nrange[1])
+            best = cat;
+          break;
+
+        case CTPO_CAT_SRANGE:
+          if (cat->type == CCT_SRANGE
+              && nullable_substring_equal (&cat->srange[0], &e->srange[0])
+              && nullable_substring_equal (&cat->srange[1], &e->srange[1]))
             best = cat;
           break;
 
@@ -1657,7 +1668,7 @@ ctables_recursive_check_postcompute (const struct ctables_pcexpr *e,
     {
     case CTPO_CAT_NUMBER:
     case CTPO_CAT_STRING:
-    case CTPO_CAT_RANGE:
+    case CTPO_CAT_NRANGE:
     case CTPO_CAT_MISSING:
     case CTPO_CAT_OTHERNM:
     case CTPO_CAT_SUBTOTAL:
@@ -3640,7 +3651,8 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
     case CTPO_CONSTANT:
       return e->number;
 
-    case CTPO_CAT_RANGE:
+    case CTPO_CAT_NRANGE:
+    case CTPO_CAT_SRANGE:
       {
         struct ctables_cell_value cv = {
           .category = ctables_find_category_for_postcompute (ctx->cats, e)
@@ -4666,6 +4678,11 @@ ctables_pcexpr_destroy (struct ctables_pcexpr *e)
           ss_dealloc (&e->string);
           break;
 
+        case CTPO_CAT_SRANGE:
+          for (size_t i = 0; i < 2; i++)
+            ss_dealloc (&e->srange[i]);
+          break;
+
         case CTPO_ADD:
         case CTPO_SUB:
         case CTPO_MUL:
@@ -4678,7 +4695,7 @@ ctables_pcexpr_destroy (struct ctables_pcexpr *e)
 
         case CTPO_CONSTANT:
         case CTPO_CAT_NUMBER:
-        case CTPO_CAT_RANGE:
+        case CTPO_CAT_NRANGE:
         case CTPO_CAT_MISSING:
         case CTPO_CAT_OTHERNM:
         case CTPO_CAT_SUBTOTAL:
@@ -4778,11 +4795,11 @@ static struct ctables_pcexpr *ctable_pcexpr_parse_add (struct lexer *,
                                                        struct dictionary *);
 
 static struct ctables_pcexpr
-ctpo_cat_range (double low, double high)
+ctpo_cat_nrange (double low, double high)
 {
   return (struct ctables_pcexpr) {
-    .op = CTPO_CAT_RANGE,
-    .range = { low, high },
+    .op = CTPO_CAT_NRANGE,
+    .nrange = { low, high },
   };
 }
 
@@ -4824,7 +4841,7 @@ ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
         {
           if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
             return false;
-          e = ctpo_cat_range (-DBL_MAX, lex_number (lexer));
+          e = ctpo_cat_nrange (-DBL_MAX, lex_number (lexer));
           lex_get (lexer);
         }
       else if (lex_is_number (lexer))
@@ -4834,12 +4851,12 @@ ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
           if (lex_match_id (lexer, "THRU"))
             {
               if (lex_match_id (lexer, "HI"))
-                e = ctpo_cat_range (number, DBL_MAX);
+                e = ctpo_cat_nrange (number, DBL_MAX);
               else
                 {
                   if (!lex_force_num (lexer))
                     return false;
-                  e = ctpo_cat_range (number, lex_number (lexer));
+                  e = ctpo_cat_nrange (number, lex_number (lexer));
                   lex_get (lexer);
                 }
             }
index 124b73938f1c0cbd5e35cbb918de3b810a9e353e..3b20068144881efbb512e33b99506a0baf29ca20 100644 (file)
@@ -15,8 +15,7 @@ dnl - CATEGORIES:
 dnl   * Data-dependent sorting.
 dnl - PCOMPUTE:
 dnl   * multi-dimensional (multiple CCT_POSTCOMPUTE in one cell
-dnl   * MISSING, OTHERNM
-dnl   * strings
+dnl   * dates
 dnl
 dnl Features not yet tested:
 dnl - Parsing (positive and negative)
@@ -25,8 +24,6 @@ dnl - Testing details of missing value handling in summaries.
 dnl - test CLABELS ROWLABELS=LAYER.
 dnl - Test VLABELS.
 dnl - Test WEIGHT and adjustment weights.
-dnl - Test PCOMPUTE and PPROPERTIES.
-dnl   * PCOMPUTE for more than one kind of summary (e.g. [COUNT, ROWPCT]).
 dnl - EMPTY=INCLUDE For string ranges.
 dnl - Summary functions:
 dnl   * Separate summary functions for totals and subtotals.
@@ -44,6 +41,10 @@ dnl - HIDESMALLCOUNTS.
 dnl - Date/time variables and values
 dnl - Special formats for summary functions: NEGPAREN, NEQUAL, PAREN, PCTPAREN.
 dnl - TITLES: )DATE, )TIME, )TABLE.
+dnl - Test PCOMPUTE:
+dnl   * PCOMPUTE for more than one kind of summary (e.g. [COUNT, ROWPCT]).
+dnl   * MISSING, OTHERNM
+dnl   * strings and string ranges
 dnl - PPROPERTIES:
 dnl   * )LABEL[N].
 dnl