From: Ben Pfaff Date: Sat, 9 Jul 2022 16:04:51 +0000 (-0700) Subject: pcompute dates X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a58d7450e4c0fd39815fd0ea92a9f4c7ffd428b;p=pspp pcompute dates --- diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index a25205e48d..aa204b4ea5 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -580,7 +580,12 @@ struct ctables_category bool hide_subcategories; /* CCT_SUBTOTAL. */ }; - const struct ctables_postcompute *pc; /* CCT_POSTCOMPUTE. */ + /* CCT_POSTCOMPUTE. */ + struct + { + const struct ctables_postcompute *pc; + enum fmt_type parse_format; + }; /* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */ struct @@ -1715,9 +1720,30 @@ ctables_table_parse_explicit_category (struct lexer *lexer, return true; } +static bool +parse_category_string (struct msg_location *location, + struct substring s, const struct dictionary *dict, + enum fmt_type format, double *n) +{ + union value v; + char *error = data_in (s, dict_get_encoding (dict), format, + settings_get_fmt_settings (), &v, 0, NULL); + if (error) + { + msg_at (SE, location, + _("Failed to parse category specification as format %s: %s."), + fmt_name (format), error); + free (error); + return false; + } + + *n = v.f; + return true; +} + static struct ctables_category * -ctables_find_category_for_postcompute (const struct ctables_categories *cats, - const struct ctables_pcexpr *e) +ctables_find_category_for_postcompute__ (const struct ctables_categories *cats, + const struct ctables_pcexpr *e) { struct ctables_category *best = NULL; size_t n_subtotals = 0; @@ -1791,8 +1817,57 @@ ctables_find_category_for_postcompute (const struct ctables_categories *cats, return best; } +static struct ctables_category * +ctables_find_category_for_postcompute (const struct dictionary *dict, + const struct ctables_categories *cats, + enum fmt_type parse_format, + const struct ctables_pcexpr *e) +{ + if (parse_format != FMT_F) + { + if (e->op == CTPO_CAT_STRING) + { + double number; + if (!parse_category_string (e->location, e->string, dict, + parse_format, &number)) + return NULL; + + struct ctables_pcexpr e2 = { + .op = CTPO_CAT_NUMBER, + .number = number, + .location = e->location, + }; + return ctables_find_category_for_postcompute__ (cats, &e2); + } + else if (e->op == CTPO_CAT_SRANGE) + { + double nrange[2]; + if (!e->srange[0].string) + nrange[0] = -DBL_MAX; + else if (!parse_category_string (e->location, e->srange[0], dict, + parse_format, &nrange[0])) + return NULL; + + if (!e->srange[1].string) + nrange[1] = DBL_MAX; + else if (!parse_category_string (e->location, e->srange[1], dict, + parse_format, &nrange[1])) + return NULL; + + struct ctables_pcexpr e2 = { + .op = CTPO_CAT_NRANGE, + .nrange = { nrange[0], nrange[1] }, + .location = e->location, + }; + return ctables_find_category_for_postcompute__ (cats, &e2); + } + } + return ctables_find_category_for_postcompute__ (cats, e); +} + static bool -ctables_recursive_check_postcompute (const struct ctables_pcexpr *e, +ctables_recursive_check_postcompute (struct dictionary *dict, + const struct ctables_pcexpr *e, struct ctables_category *pc_cat, const struct ctables_categories *cats, const struct msg_location *cats_location) @@ -1808,7 +1883,7 @@ ctables_recursive_check_postcompute (const struct ctables_pcexpr *e, case CTPO_CAT_TOTAL: { struct ctables_category *cat = ctables_find_category_for_postcompute ( - cats, e); + dict, cats, pc_cat->parse_format, e); if (!cat) { if (e->op == CTPO_CAT_SUBTOTAL && e->subtotal_index == 0) @@ -1861,7 +1936,7 @@ ctables_recursive_check_postcompute (const struct ctables_pcexpr *e, case CTPO_NEG: for (size_t i = 0; i < 2; i++) if (e->subs[i] && !ctables_recursive_check_postcompute ( - e->subs[i], pc_cat, cats, cats_location)) + dict, e->subs[i], pc_cat, cats, cats_location)) return false; return true; @@ -1870,27 +1945,6 @@ ctables_recursive_check_postcompute (const struct ctables_pcexpr *e, } } -static bool -parse_category_string (const struct ctables_category *cat, - struct substring s, struct dictionary *dict, - enum fmt_type format, double *n) -{ - union value v; - char *error = data_in (s, dict_get_encoding (dict), format, - settings_get_fmt_settings (), &v, 0, NULL); - if (error) - { - msg_at (SE, cat->location, - _("Failed to parse category specification as format %s: %s."), - fmt_name (format), error); - free (error); - return false; - } - - *n = v.f; - return true; -} - static bool all_strings (struct variable **vars, size_t n_vars, const struct ctables_category *cat) @@ -1974,8 +2028,9 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, switch (cat->type) { case CCT_POSTCOMPUTE: - if (!ctables_recursive_check_postcompute (cat->pc->expr, cat, - c, cats_location)) + cat->parse_format = parse_strings ? common_format->type : FMT_F; + if (!ctables_recursive_check_postcompute (dict, cat->pc->expr, + cat, c, cats_location)) return false; break; @@ -1998,7 +2053,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, if (parse_strings) { double n; - if (!parse_category_string (cat, cat->string, dict, + if (!parse_category_string (cat->location, cat->string, dict, common_format->type, &n)) return false; @@ -2018,13 +2073,15 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, if (!cat->srange[0].string) n[0] = -DBL_MAX; - else if (!parse_category_string (cat, cat->srange[0], dict, + else if (!parse_category_string (cat->location, + cat->srange[0], dict, common_format->type, &n[0])) return false; if (!cat->srange[1].string) n[1] = DBL_MAX; - else if (!parse_category_string (cat, cat->srange[1], dict, + else if (!parse_category_string (cat->location, + cat->srange[1], dict, common_format->type, &n[1])) return false; @@ -4070,6 +4127,7 @@ struct ctables_pcexpr_evaluate_ctx enum pivot_axis_type pc_a; size_t pc_a_idx; size_t summary_idx; + enum fmt_type parse_format; }; static double ctables_pcexpr_evaluate ( @@ -4167,7 +4225,7 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx, case CTPO_CAT_SRANGE: { struct ctables_cell_value cv = { - .category = ctables_find_category_for_postcompute (ctx->cats, e) + .category = ctables_find_category_for_postcompute (ctx->section->table->ctables->dict, ctx->cats, ctx->parse_format, e) }; assert (cv.category != NULL); @@ -4193,7 +4251,7 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx, case CTPO_CAT_TOTAL: { struct ctables_cell_value cv = { - .category = ctables_find_category_for_postcompute (ctx->cats, e), + .category = ctables_find_category_for_postcompute (ctx->section->table->ctables->dict, ctx->cats, ctx->parse_format, e), .value = { .f = e->number }, }; assert (cv.category != NULL); @@ -4222,29 +4280,28 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx, NOT_REACHED (); } -/* XXX what if there is a postcompute in more than one dimension?? */ -static const struct ctables_postcompute * +static const struct ctables_category * ctables_cell_postcompute (const struct ctables_section *s, const struct ctables_cell *cell, enum pivot_axis_type *pc_a_p, size_t *pc_a_idx_p) { assert (cell->postcompute); - const struct ctables_postcompute *pc = NULL; + const struct ctables_category *pc_cat = NULL; for (enum pivot_axis_type pc_a = 0; pc_a < PIVOT_N_AXES; pc_a++) for (size_t pc_a_idx = 0; pc_a_idx < s->nests[pc_a]->n; pc_a_idx++) { const struct ctables_cell_value *cv = &cell->axes[pc_a].cvs[pc_a_idx]; if (cv->category->type == CCT_POSTCOMPUTE) { - if (pc) + if (pc_cat) { /* Multiple postcomputes cross each other. The value is undefined. */ return NULL; } - pc = cv->category->pc; + pc_cat = cv->category; if (pc_a_p) *pc_a_p = pc_a; if (pc_a_idx_p) @@ -4252,8 +4309,8 @@ ctables_cell_postcompute (const struct ctables_section *s, } } - assert (pc != NULL); - return pc; + assert (pc_cat != NULL); + return pc_cat; } static double @@ -4266,11 +4323,12 @@ ctables_cell_calculate_postcompute (const struct ctables_section *s, { enum pivot_axis_type pc_a = 0; size_t pc_a_idx = 0; - const struct ctables_postcompute *pc = ctables_cell_postcompute ( + const struct ctables_category *pc_cat = ctables_cell_postcompute ( s, cell, &pc_a, &pc_a_idx); - if (!pc) + if (!pc_cat) return SYSMIS; + const struct ctables_postcompute *pc = pc_cat->pc; if (pc->specs) { for (size_t i = 0; i < pc->specs->n; i++) @@ -4296,6 +4354,7 @@ ctables_cell_calculate_postcompute (const struct ctables_section *s, .pc_a = pc_a, .pc_a_idx = pc_a_idx, .summary_idx = summary_idx, + .parse_format = pc_cat->parse_format, }; return ctables_pcexpr_evaluate (&ctx, pc->expr); } diff --git a/tests/language/stats/ctables.at b/tests/language/stats/ctables.at index 65740d97b2..114d6dcc7c 100644 --- a/tests/language/stats/ctables.at +++ b/tests/language/stats/ctables.at @@ -4,8 +4,6 @@ dnl Features not yet implemented: dnl dnl - Definition of columns/rows when labels are rotated from one axis to another. dnl - Preprocessing to distinguish categorical from scale. -dnl - PCOMPUTE: -dnl * dates dnl dnl Features not yet tested: dnl - Parsing (positive and negative) @@ -41,6 +39,7 @@ dnl * PCOMPUTE for more than one kind of summary (e.g. [COUNT, ROWPCT]). dnl * MISSING, OTHERNM dnl * strings and string ranges dnl * multi-dimensional (multiple CCT_POSTCOMPUTE in one cell) +dnl * dates dnl - PPROPERTIES: dnl * )LABEL[N]. dnl - Summary functions: