From 265ebd372a4fd510bc29c749a46393ee7caace41 Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Mon, 8 Dec 2008 10:14:33 +0200 Subject: [PATCH] [script] Flesh out the relational comparison operators to be more PostScript-like. The relational comparison operators can now compare strings vs names by content as well as performing automatic type promotions on the numeric types. For other types relational comparisons succeeed only if the values compare equal according to the eq operator, and put the interpreter into a type-error state otherwise. --- util/cairo-script/cairo-script-objects.c | 103 +++++++++++++++ util/cairo-script/cairo-script-operators.c | 144 ++++----------------- util/cairo-script/cairo-script-private.h | 5 + 3 files changed, 132 insertions(+), 120 deletions(-) diff --git a/util/cairo-script/cairo-script-objects.c b/util/cairo-script/cairo-script-objects.c index bf00b15df..7fe196d69 100644 --- a/util/cairo-script/cairo-script-objects.c +++ b/util/cairo-script/cairo-script-objects.c @@ -756,3 +756,106 @@ csi_object_eq (csi_object_t *a, return FALSE; } + +csi_status_t +csi_object_compare (csi_object_t *a, + csi_object_t *b, + int *out) +{ + csi_object_type_t atype = csi_object_get_type (a); + csi_object_type_t btype = csi_object_get_type (b); + int sign; + + if (csi_object_eq (a, b)){ + *out = 0; + return CSI_STATUS_SUCCESS; + } + +#define CMP(x,y) ((x) < (y) ? -1 : +1) + + if (atype == btype) { + switch (atype) { + case CSI_OBJECT_TYPE_BOOLEAN: + *out = CMP (a->datum.boolean, b->datum.boolean); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_INTEGER: + *out = CMP (a->datum.integer, b->datum.integer); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_REAL: + *out = CMP (a->datum.real, b->datum.real); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_NAME: { + const char *x = (char const *) a->datum.name; + const char *y = (char const *) b->datum.name; + *out = lexcmp (x, strlen(x), y, strlen (y)); + return CSI_STATUS_SUCCESS; + } + case CSI_OBJECT_TYPE_STRING: + *out = lexcmp (a->datum.string->string, + a->datum.string->len, + b->datum.string->string, + b->datum.string->len); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_NULL: + case CSI_OBJECT_TYPE_MARK: + case CSI_OBJECT_TYPE_OPERATOR: + case CSI_OBJECT_TYPE_ARRAY: + case CSI_OBJECT_TYPE_DICTIONARY: + case CSI_OBJECT_TYPE_FILE: + case CSI_OBJECT_TYPE_MATRIX: + case CSI_OBJECT_TYPE_CONTEXT: + case CSI_OBJECT_TYPE_FONT: + case CSI_OBJECT_TYPE_PATTERN: + case CSI_OBJECT_TYPE_SCALED_FONT: + case CSI_OBJECT_TYPE_SURFACE: + goto TYPE_CHECK_ERROR; + } + } + + sign = +1; + if (atype < btype) { + csi_object_t *c; + csi_object_type_t ctype; + c = a; a = b; b = c; + ctype = atype; atype = btype; btype = ctype; + sign = -1; + } + + switch ((int) atype) { + case CSI_OBJECT_TYPE_INTEGER: + if (btype == CSI_OBJECT_TYPE_BOOLEAN) { + *out = sign * CMP (a->datum.integer, !!b->datum.boolean); + return CSI_STATUS_SUCCESS; + } + break; + case CSI_OBJECT_TYPE_REAL: + if (btype == CSI_OBJECT_TYPE_INTEGER) { + *out = sign * CMP (a->datum.real, b->datum.integer); + return CSI_STATUS_SUCCESS; + } + else if (btype == CSI_OBJECT_TYPE_BOOLEAN) { + *out = sign * CMP (a->datum.real, !!b->datum.boolean); + return CSI_STATUS_SUCCESS; + } + break; + + case CSI_OBJECT_TYPE_STRING: + if (btype == CSI_OBJECT_TYPE_NAME) { + const char *bstr = (const char *) b->datum.name; + *out = sign * lexcmp (a->datum.string->string, + a->datum.string->len, + bstr, + strlen (bstr)); + return CSI_STATUS_SUCCESS; + } + break; + + default: + break; + } + +#undef CMP + + TYPE_CHECK_ERROR: + return _csi_error (CSI_STATUS_SCRIPT_INVALID_TYPE); +} diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c index 63b3aebd6..e5b6b2d3d 100644 --- a/util/cairo-script/cairo-script-operators.c +++ b/util/cairo-script/cairo-script-operators.c @@ -1885,45 +1885,21 @@ _for (csi_t *ctx) static csi_status_t _ge (csi_t *ctx) { + csi_status_t status; csi_object_t *a, *b; - csi_boolean_t v; + int cmp; check (2); b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (csi_object_get_type (a) != csi_object_get_type (b)) { - if (csi_object_is_number (a) && csi_object_is_number (b)) { - double ia, ib; - ia = csi_number_get_value (a); - ib = csi_number_get_value (b); - v = ia >= ib; - } else { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.boolean >= b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.integer >= b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.real >= b->datum.real; - break; - case CSI_OBJECT_TYPE_STRING: - v = strcmp (a->datum.string->string, b->datum.string->string) >= 0; - break; - case CSI_OBJECT_TYPE_NAME: - v = strcmp ((char *) a->datum.name, (char *) b->datum.name) >= 0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; pop (2); - return _csi_push_ostack_boolean (ctx, v); + return _csi_push_ostack_boolean (ctx, cmp >= 0); } static csi_status_t @@ -2335,45 +2311,21 @@ _gray (csi_t *ctx) static csi_status_t _gt (csi_t *ctx) { + csi_status_t status; csi_object_t *a, *b; - csi_boolean_t v; + int cmp; check (2); b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { - if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))){ - double ia, ib; - ia = csi_number_get_value (a); - ib = csi_number_get_value (b); - v = ia > ib; - } else { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.boolean > b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.integer > b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.real > b->datum.real; - break; - case CSI_OBJECT_TYPE_STRING: - v = strcmp (a->datum.string->string, b->datum.string->string) > 0; - break; - case CSI_OBJECT_TYPE_NAME: - v = strcmp ((char *) a->datum.name, (char *) b->datum.name) > 0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; pop (2); - return _csi_push_ostack_boolean (ctx, v); + return _csi_push_ostack_boolean (ctx, cmp > 0); } static csi_status_t @@ -2863,45 +2815,21 @@ _index (csi_t *ctx) static csi_status_t _le (csi_t *ctx) { + csi_status_t status; csi_object_t *a, *b; - csi_boolean_t v; + int cmp; check (2); b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { - if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))) { - double ia, ib; - ia = csi_number_get_value (a); - ib = csi_number_get_value (b); - v = ia <= ib; - } else { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.boolean <= b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.integer <= b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.real <= b->datum.real; - break; - case CSI_OBJECT_TYPE_STRING: - v = strcmp (a->datum.string->string, b->datum.string->string) <= 0; - break; - case CSI_OBJECT_TYPE_NAME: - v = strcmp ((char *) a->datum.name, (char *) b->datum.name) <= 0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; pop (2); - return _csi_push_ostack_boolean (ctx, v); + return _csi_push_ostack_boolean (ctx, cmp <= 0); } static csi_status_t @@ -2962,45 +2890,21 @@ _line_to (csi_t *ctx) static csi_status_t _lt (csi_t *ctx) { + csi_status_t status; csi_object_t *a, *b; - csi_boolean_t v; + int cmp; check (2); b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { - if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))) { - double ia, ib; - ia = csi_number_get_value (a); - ib = csi_number_get_value (b); - v = ia < ib; - } else { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.boolean < b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.integer < b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.real < b->datum.real; - break; - case CSI_OBJECT_TYPE_STRING: - v = strcmp (a->datum.string->string, b->datum.string->string) < 0; - break; - case CSI_OBJECT_TYPE_NAME: - v = strcmp ((char *) a->datum.name, (char *) b->datum.name) < 0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; pop (2); - return _csi_push_ostack_boolean (ctx, v); + return _csi_push_ostack_boolean (ctx, cmp < 0); } static csi_status_t diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h index 819f25c3f..1952cbec4 100644 --- a/util/cairo-script/cairo-script-private.h +++ b/util/cairo-script/cairo-script-private.h @@ -720,6 +720,11 @@ csi_private csi_boolean_t csi_object_eq (csi_object_t *a, csi_object_t *b); +csi_private csi_status_t +csi_object_compare (csi_object_t *a, + csi_object_t *b, + int *out_cmp); + /* cairo-script-operators.c */ csi_private const csi_operator_def_t *