PCOMPUTE works
[pspp] / src / language / stats / ctables.c
index 05fb957439772a87d4ee66f02d7ba86592f49bc9..d605b63ed596702e24057d755753f0bc63ca9e9a 100644 (file)
@@ -1535,7 +1535,7 @@ ctables_recursive_check_postcompute (const struct ctables_pcexpr *e,
             msg_at (SE, pc_cat->location,
                     _("Computed category &%s references a category not included "
                       "in the category list."),
-                    cat->pc->name);
+                    pc_cat->pc->name);
             msg_at (SN, e->location, _("This is the missing category."));
             msg_at (SN, cats_location,
                     _("To fix the problem, add the missing category to the "
@@ -3113,7 +3113,7 @@ ctables_pcexpr_evaluate_nonterminal (
 
 static double
 ctables_pcexpr_evaluate_category (const struct ctables_pcexpr_evaluate_ctx *ctx,
-                                  const struct ctables_category *cat)
+                                  const struct ctables_cell_value *pc_cv)
 {
   const struct ctables_section *s = ctx->section;
 
@@ -3122,16 +3122,11 @@ ctables_pcexpr_evaluate_category (const struct ctables_pcexpr_evaluate_ctx *ctx,
     {
       const struct ctables_nest *nest = s->nests[a];
       for (size_t i = 0; i < nest->n; i++)
-        if (a == ctx->pc_a && i == ctx->pc_a_idx)
-          {
-            /* XXX anything other than just a constant.... need a higher level
-               loop to go through occurrences */
-            hash = hash_pointer (cat, hash);
-            hash = hash_double (cat->number, hash);
-          }
-        else if (i != nest->scale_idx)
+        if (i != nest->scale_idx)
           {
-            const struct ctables_cell_value *cv = &ctx->cell->axes[a].cvs[i];
+            const struct ctables_cell_value *cv
+              = (a == ctx->pc_a && i == ctx->pc_a_idx ? pc_cv
+                 : &ctx->cell->axes[a].cvs[i]);
             hash = hash_pointer (cv->category, hash);
             if (cv->category->type != CCT_TOTAL
                 && cv->category->type != CCT_SUBTOTAL
@@ -3148,29 +3143,21 @@ ctables_pcexpr_evaluate_category (const struct ctables_pcexpr_evaluate_ctx *ctx,
         {
           const struct ctables_nest *nest = s->nests[a];
           for (size_t i = 0; i < nest->n; i++)
-            {
-              const struct ctables_cell_value *p_cv = &ctx->cell->axes[a].cvs[i];
-              const struct ctables_cell_value *t_cv = &tc->axes[a].cvs[i];
-
-              if (i == nest->scale_idx)
-                {
-                  /* Nothing to do. */
-                }
-              else if (a == ctx->pc_a && i == ctx->pc_a_idx)
-                {
-                  /* XXX anything other than a constant.... */
-                  if (t_cv->category != cat || t_cv->value.f != cat->number)
-                    goto not_equal;
-                }
-              else if (p_cv->category != t_cv->category
-                       || (p_cv->category->type != CCT_TOTAL
-                           && p_cv->category->type != CCT_SUBTOTAL
-                           && p_cv->category->type != CCT_POSTCOMPUTE
-                           && !value_equal (&p_cv->value,
-                                            &t_cv->value,
-                                            var_get_width (nest->vars[i]))))
-                goto not_equal;
-            }
+            if (i != nest->scale_idx)
+              {
+                const struct ctables_cell_value *p_cv
+                  = (a == ctx->pc_a && i == ctx->pc_a_idx ? pc_cv
+                     : &ctx->cell->axes[a].cvs[i]);
+                const struct ctables_cell_value *t_cv = &tc->axes[a].cvs[i];
+                if (p_cv->category != t_cv->category
+                    || (p_cv->category->type != CCT_TOTAL
+                        && p_cv->category->type != CCT_SUBTOTAL
+                        && p_cv->category->type != CCT_POSTCOMPUTE
+                        && !value_equal (&p_cv->value,
+                                         &t_cv->value,
+                                         var_get_width (nest->vars[i]))))
+                  goto not_equal;
+              }
         }
 
       goto found;
@@ -3196,19 +3183,40 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
     case CTPO_CONSTANT:
       return e->number;
 
+    case CTPO_CAT_RANGE:
+      {
+        struct ctables_cell_value cv = {
+          .category = ctables_find_category_for_postcompute (ctx->cats, e)
+        };
+        assert (cv.category != NULL);
+
+        struct hmap *occurrences = &ctx->section->occurrences[ctx->pc_a][ctx->pc_a_idx];
+        const struct ctables_occurrence *o;
+
+        double sum = 0.0;
+        const struct variable *var = ctx->section->nests[ctx->pc_a]->vars[ctx->pc_a_idx];
+        HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
+          if (ctables_categories_match (ctx->cats, &o->value, var) == cv.category)
+            {
+              cv.value = o->value;
+              sum += ctables_pcexpr_evaluate_category (ctx, &cv);
+            }
+        return sum;
+      }
+
     case CTPO_CAT_NUMBER:
     case CTPO_CAT_STRING:
-    case CTPO_CAT_RANGE:
     case CTPO_CAT_MISSING:
     case CTPO_CAT_OTHERNM:
     case CTPO_CAT_SUBTOTAL:
     case CTPO_CAT_TOTAL:
       {
-        struct ctables_category *cat = ctables_find_category_for_postcompute (
-          ctx->cats, e);
-        assert (cat != NULL);
-
-        return ctables_pcexpr_evaluate_category (ctx, cat);
+        struct ctables_cell_value cv = {
+          .category = ctables_find_category_for_postcompute (ctx->cats, e),
+          .value = { .f = e->number },
+        };
+        assert (cv.category != NULL);
+        return ctables_pcexpr_evaluate_category (ctx, &cv);
       }
 
     case CTPO_ADD:
@@ -3968,8 +3976,7 @@ ctables_section_recurse_add_empty_categories (
           const struct ctables_category *cat = &categories->cats[i];
           if (cat->type == CCT_POSTCOMPUTE)
             {
-              printf ("%s:%d\n", __FILE__, __LINE__);
-              cats[a][a_idx] = cat;
+q              cats[a][a_idx] = cat;
               ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
             }
         }