[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.
This commit is contained in:
M Joonas Pihlaja 2008-12-08 10:14:33 +02:00 committed by Chris Wilson
parent 05afec7a8a
commit 265ebd372a
3 changed files with 132 additions and 120 deletions

View file

@ -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);
}

View file

@ -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

View file

@ -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 *