mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-03 20:40:26 +01:00
[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:
parent
05afec7a8a
commit
265ebd372a
3 changed files with 132 additions and 120 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue