Simplify type coercion in condition evaluation

Change nstr_mkselval() to generate values with promoted types only,
and replace nstr_coerce_val() by new and simpler nstr_optype() in
nstr_comp().

Replace the only remaining use of nstr_coerce_val() in surv() by
nstr_promote(), and remove nstr_coerce_val().

This loses one half of the unimplemented sketch of coercions to
NSC_STRING.  Drop the other half from nstr_exec_val().
This commit is contained in:
Markus Armbruster 2008-12-27 16:59:53 +01:00
parent d2fba584e8
commit 9115c03949
4 changed files with 36 additions and 90 deletions

View file

@ -48,7 +48,7 @@ enum nsc_type {
/* promoted types */ /* promoted types */
NSC_LONG, /* long */ NSC_LONG, /* long */
NSC_DOUBLE, /* double */ NSC_DOUBLE, /* double */
NSC_STRING, /* char *, zero-terminated string */ NSC_STRING, /* character string */
/* unpromoted types */ /* unpromoted types */
NSC_CHAR, /* signed char */ NSC_CHAR, /* signed char */
NSC_UCHAR, /* unsigned char */ NSC_UCHAR, /* unsigned char */
@ -61,7 +61,7 @@ enum nsc_type {
may need hiding */ may need hiding */
NSC_TIME, /* time_t */ NSC_TIME, /* time_t */
NSC_FLOAT, /* float */ NSC_FLOAT, /* float */
NSC_STRINGY, /* char[], may be zero-terminated */ NSC_STRINGY, /* char[] */
/* aliases, must match typedefs */ /* aliases, must match typedefs */
NSC_NATID = NSC_UCHAR /* nation id */ NSC_NATID = NSC_UCHAR /* nation id */
}; };
@ -287,7 +287,6 @@ extern struct symbol sector_navigation[];
/* src/lib/subs/nstr.c */ /* src/lib/subs/nstr.c */
extern int nstr_comp(struct nscstr *np, int len, int type, char *str); extern int nstr_comp(struct nscstr *np, int len, int type, char *str);
extern char *nstr_comp_val(char *, struct valstr*, int); extern char *nstr_comp_val(char *, struct valstr*, int);
extern int nstr_coerce_val(struct valstr *, enum nsc_type, char *);
extern int nstr_exec(struct nscstr *, int, void *); extern int nstr_exec(struct nscstr *, int, void *);
/* src/lib/common/nstreval.c */ /* src/lib/common/nstreval.c */
extern struct valstr *nstr_mksymval(struct valstr *, struct castr *, int); extern struct valstr *nstr_mksymval(struct valstr *, struct castr *, int);

View file

@ -71,7 +71,7 @@ surv(void)
ptr = nstr_comp_val(ptr, &val, EF_SECTOR); ptr = nstr_comp_val(ptr, &val, EF_SECTOR);
if (!ptr) if (!ptr)
return RET_SYN; return RET_SYN;
if (val.val_cat != NSC_OFF || nstr_coerce_val(&val, NSC_LONG, NULL) < 0) { if (val.val_cat != NSC_OFF || nstr_promote(val.val_type) != NSC_LONG) {
pr("Can't survey this\n"); pr("Can't survey this\n");
return RET_SYN; return RET_SYN;
} }

View file

@ -66,8 +66,7 @@ nstr_mksymval(struct valstr *val, struct castr *ca, int idx)
* PTR points to a context object of the type that was used to compile * PTR points to a context object of the type that was used to compile
* the value. * the value.
* Unless WANT is NSC_NOTYPE, coerce the value to promoted value type * Unless WANT is NSC_NOTYPE, coerce the value to promoted value type
* WANT. VAL must be coercible. That's the case if a previous * WANT. VAL must be coercible.
* nstr_coerce_val(VAL, WANT, STR) succeeded.
*/ */
struct valstr * struct valstr *
nstr_exec_val(struct valstr *val, natid cnum, void *ptr, enum nsc_type want) nstr_exec_val(struct valstr *val, natid cnum, void *ptr, enum nsc_type want)
@ -186,6 +185,7 @@ nstr_exec_val(struct valstr *val, natid cnum, void *ptr, enum nsc_type want)
valtype = NSC_NOTYPE; valtype = NSC_NOTYPE;
} }
/* coerce */
if (valtype == want) if (valtype == want)
; ;
else if (want == NSC_DOUBLE) { else if (want == NSC_DOUBLE) {
@ -193,8 +193,7 @@ nstr_exec_val(struct valstr *val, natid cnum, void *ptr, enum nsc_type want)
valtype = want; valtype = want;
val->val_as.dbl = val->val_as.lng; val->val_as.dbl = val->val_as.lng;
} }
} else if (want == NSC_STRING) }
CANT_REACH(); /* FIXME implement */
if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE)) { if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE)) {
/* make up an error value */ /* make up an error value */

View file

@ -46,9 +46,10 @@ static char *nstr_parse_val(char *, struct valstr *);
static int nstr_match_ca(struct valstr *, struct castr *); static int nstr_match_ca(struct valstr *, struct castr *);
static int nstr_match_val(struct valstr *, struct castr *, int); static int nstr_match_val(struct valstr *, struct castr *, int);
static int nstr_string_ok(struct castr *ca, int idx); static int nstr_string_ok(struct castr *ca, int idx);
static struct valstr *nstr_resolve_id(struct valstr *, struct castr *, int, int);
static struct valstr *nstr_resolve_sel(struct valstr *, struct castr *); static struct valstr *nstr_resolve_sel(struct valstr *, struct castr *);
static struct valstr *nstr_mkselval(struct valstr *, int, struct castr *); static struct valstr *nstr_mkselval(struct valstr *, int, struct castr *);
static struct valstr *nstr_resolve_id(struct valstr *, struct castr *, int, int); static int nstr_optype(enum nsc_type, enum nsc_type);
/* /*
* Compile conditions into array NP[LEN]. * Compile conditions into array NP[LEN].
@ -68,7 +69,6 @@ nstr_comp(struct nscstr *np, int len, int type, char *str)
struct nscstr dummy; struct nscstr dummy;
int lft_caidx, rgt_caidx; int lft_caidx, rgt_caidx;
int lft_val, rgt_val; int lft_val, rgt_val;
int lft_type, rgt_type;
cond = str; cond = str;
for (i = 0; ; ++i, ++np) { for (i = 0; ; ++i, ++np) {
@ -125,7 +125,7 @@ nstr_comp(struct nscstr *np, int len, int type, char *str)
} else { } else {
/* /*
* Neither side works as selector value; any identifiers * Neither side works as selector value; any identifiers
* must name selectors. * must name selectors or strings.
*/ */
if (!nstr_resolve_id(&np->lft, ca, lft_caidx, if (!nstr_resolve_id(&np->lft, ca, lft_caidx,
nstr_string_ok(ca, rgt_caidx))) nstr_string_ok(ca, rgt_caidx)))
@ -135,29 +135,13 @@ nstr_comp(struct nscstr *np, int len, int type, char *str)
return -1; return -1;
} }
/* find operator type, coerce operands */ /* find operator type */
lft_type = nstr_promote(np->lft.val_type); np->optype = nstr_optype(np->lft.val_type, np->rgt.val_type);
rgt_type = nstr_promote(np->rgt.val_type); if (np->optype == NSC_NOTYPE) {
np->optype = NSC_NOTYPE; pr("%.*s -- condition operand type mismatch\n",
if (lft_type == NSC_STRING) { (int)(tail-cond), cond);
if (!nstr_coerce_val(&np->rgt, NSC_STRING, str))
np->optype = NSC_STRING;
} else if (rgt_type == NSC_STRING) {
if (!nstr_coerce_val(&np->lft, NSC_STRING, str))
np->optype = NSC_STRING;
} else if (lft_type == NSC_DOUBLE) {
if (!nstr_coerce_val(&np->rgt, NSC_DOUBLE, str))
np->optype = NSC_DOUBLE;
} else if (rgt_type == NSC_DOUBLE) {
if (!nstr_coerce_val(&np->lft, NSC_DOUBLE, str))
np->optype = NSC_DOUBLE;
} else {
if (!nstr_coerce_val(&np->lft, NSC_LONG, str)
&& !nstr_coerce_val(&np->rgt, NSC_LONG, str))
np->optype = NSC_LONG;
}
if (np->optype == NSC_NOTYPE)
return -1; return -1;
}
/* another condition? */ /* another condition? */
if (*tail == 0) if (*tail == 0)
@ -436,19 +420,37 @@ nstr_resolve_sel(struct valstr *val, struct castr *ca)
static struct valstr * static struct valstr *
nstr_mkselval(struct valstr *val, int selval, struct castr *ca) nstr_mkselval(struct valstr *val, int selval, struct castr *ca)
{ {
if (CANT_HAPPEN(nstr_promote(ca->ca_type) != NSC_LONG enum nsc_type type = nstr_promote(ca->ca_type);
|| ca->ca_table == EF_BAD)) {
if (CANT_HAPPEN(type != NSC_LONG || ca->ca_table == EF_BAD)) {
val->val_type = NSC_NOTYPE; val->val_type = NSC_NOTYPE;
val->val_cat = NSC_NOCAT; val->val_cat = NSC_NOCAT;
return val; return val;
} }
val->val_type = ca->ca_type; val->val_type = type;
val->val_cat = NSC_VAL; val->val_cat = NSC_VAL;
val->val_as.lng = selval; val->val_as.lng = selval;
return val; return val;
} }
/*
* Return operator type for operand types LFT, RGT.
*/
static int
nstr_optype(enum nsc_type lft, enum nsc_type rgt)
{
lft = nstr_promote(lft);
rgt = nstr_promote(rgt);
if (lft == rgt)
return lft;
if (lft == NSC_DOUBLE && rgt == NSC_LONG)
return NSC_DOUBLE;
if (rgt == NSC_DOUBLE && lft == NSC_LONG)
return NSC_DOUBLE;
return NSC_NOTYPE;
}
/* /*
* Compile a value in STR into VAL. * Compile a value in STR into VAL.
* Return a pointer to the first character after the value on success, * Return a pointer to the first character after the value on success,
@ -466,57 +468,3 @@ nstr_comp_val(char *str, struct valstr *val, int type)
return NULL; return NULL;
return tail; return tail;
} }
static int
cond_type_mismatch(char *str)
{
if (str)
pr("%s -- condition operand type mismatch\n", str);
return -1;
}
/*
* Coerce VAL to promoted value type TO.
* Return 0 on success, -1 on error.
* If VAL is evaluated, convert it, else only check.
* STR is the condition text to be used for error messages. Suppress
* messages if it is a null pointer.
*/
int
nstr_coerce_val(struct valstr *val, enum nsc_type to, char *str)
{
/* FIXME get rid of promotion? */
enum nsc_type from = nstr_promote(val->val_type);
if (from == NSC_NOTYPE)
return 0;
if (from != to) {
switch (to) {
case NSC_STRING:
return cond_type_mismatch(str); /* FIXME implement */
case NSC_DOUBLE:
if (from == NSC_LONG) {
if (val->val_cat == NSC_VAL)
val->val_as.dbl = val->val_as.lng;
} else
return cond_type_mismatch(str);
break;
case NSC_LONG:
return cond_type_mismatch(str);
default:
CANT_REACH();
to = from;
}
}
if (val->val_cat == NSC_VAL) {
/* unimplemented conversions; don't currently occur here */
CANT_HAPPEN(val->val_type == NSC_XCOORD
|| val->val_type == NSC_YCOORD
|| val->val_type == NSC_HIDDEN);
val->val_type = to;
}
return 0;
}