a76c6133077702d8bddf356ed39c20d697db0294 kent Tue Aug 13 11:51:58 2019 -0700 Adding and logical operation. Making type coercion for it and logical or follow a different and simpler path than for the math ops. diff --git src/lib/strex.c src/lib/strex.c index ef4cfb5..aab95e1 100644 --- src/lib/strex.c +++ src/lib/strex.c @@ -96,30 +96,31 @@ strexOpBuiltInCall, /* Call a built in function */ strexOpArrayIx, /* An array with an index. */ strexOpArrayRange, /* An array with a range. */ strexOpStrlen, /* Length of a string */ /* Unary minus for numbers */ strexOpUnaryMinusInt, strexOpUnaryMinusDouble, /* Binary operations. */ strexOpAdd, strexOpOr, + strexOpAnd, /* Type conversions - possibly a few more than we actually need at the moment. */ strexOpStringToBoolean, strexOpIntToBoolean, strexOpDoubleToBoolean, strexOpStringToInt, strexOpDoubleToInt, strexOpBooleanToInt, strexOpStringToDouble, strexOpBooleanToDouble, strexOpIntToDouble, strexOpBooleanToString, strexOpIntToString, strexOpDoubleToString, }; @@ -286,30 +287,32 @@ case strexOpIntToString: return "strexOpIntToString"; case strexOpDoubleToString: return "strexOpDoubleToString"; case strexOpUnaryMinusInt: return "strexOpUnaryMinusInt"; case strexOpUnaryMinusDouble: return "strexOpUnaryMinusDouble"; case strexOpAdd: return "strexOpAdd"; case strexOpOr: return "strexOpOr"; + case strexOpAnd: + return "strexOpAnd"; case strexOpBuiltInCall: return "strexOpBuiltInCall"; case strexOpArrayIx: return "strexOpArrayIx"; case strexOpArrayRange: return "strexOpArrayRange"; case strexOpStrlen: return "strexOpStrlen"; default: return "strexOpUnknown"; } } @@ -400,50 +403,58 @@ tokenizerReuse(tkz); } } else if (c == '(') { p = strexParseExpression(in); skipOverRequired(in, ")"); } else { errAbort("Unexpected %s line %d of %s", tok, tkz->lf->lineIx, tkz->lf->fileName); } return p; } -static enum strexType commonTypeForBop(enum strexType left, enum strexType right) -/* Return type that will work for a binary operation. */ +static enum strexType commonTypeForMathBop(enum strexType left, enum strexType right) +/* Return type that will work for a math binary operation. */ { if (left == right) return left; else if (left == strexTypeString || right == strexTypeString) return strexTypeString; else if (left == strexTypeDouble || right == strexTypeDouble) return strexTypeDouble; else if (left == strexTypeInt || right == strexTypeInt) return strexTypeInt; else if (left == strexTypeBoolean || right == strexTypeBoolean) return strexTypeBoolean; else { errAbort("Can't find commonTypeForBop"); return strexTypeString; } } +static enum strexType commonTypeForLogicBop(enum strexType left, enum strexType right) +/* Return type that will work for a boolean binary operation. */ +{ +if (left == right) + return left; +else + return strexTypeBoolean; +} static enum strexOp booleanCastOp(enum strexType oldType) /* Return op to convert oldType to boolean. */ { switch (oldType) { case strexTypeString: return strexOpStringToBoolean; case strexTypeInt: return strexOpIntToBoolean; case strexTypeDouble: return strexOpDoubleToBoolean; default: internalErr(); return strexOpUnknown; @@ -729,66 +740,99 @@ struct strexParse *p = strexParseUnaryMinus(in); for (;;) { char *tok = tokenizerNext(tkz); if (tok == NULL || differentString(tok, "+")) { tokenizerReuse(tkz); return p; } /* What we've parsed so far becomes left side of binary op, next term ends up on right. */ struct strexParse *l = p; struct strexParse *r = strexParseUnaryMinus(in); /* Make left and right side into a common type */ - enum strexType childType = commonTypeForBop(l->type, r->type); + enum strexType childType = commonTypeForMathBop(l->type, r->type); l = strexParseCoerce(l, childType); r = strexParseCoerce(r, childType); /* Create the binary operation */ AllocVar(p); p->op = strexOpAdd; p->type = childType; /* Now hang children onto node. */ p->children = l; l->next = r; } } +static struct strexParse *strexParseAnd(struct strexIn *in) +/* Parse out plus or minus. */ +{ +struct tokenizer *tkz = in->tkz; +struct strexParse *p = strexParseSum(in); +for (;;) + { + char *tok = tokenizerNext(tkz); + if (tok == NULL || differentString(tok, "and")) + { + tokenizerReuse(tkz); + return p; + } + + /* What we've parsed so far becomes left side of binary op, next term ends up on right. */ + struct strexParse *l = p; + struct strexParse *r = strexParseSum(in); + + /* Make left and right side into a common type */ + enum strexType childType = commonTypeForLogicBop(l->type, r->type); + l = strexParseCoerce(l, childType); + r = strexParseCoerce(r, childType); + + /* Create the binary operation */ + AllocVar(p); + p->op = strexOpAnd; + p->type = childType; + + /* Now hang children onto node. */ + p->children = l; + l->next = r; + } +} static struct strexParse *strexParseOr(struct strexIn *in) /* Parse out plus or minus. */ { struct tokenizer *tkz = in->tkz; -struct strexParse *p = strexParseSum(in); +struct strexParse *p = strexParseAnd(in); for (;;) { char *tok = tokenizerNext(tkz); if (tok == NULL || differentString(tok, "or")) { tokenizerReuse(tkz); return p; } /* What we've parsed so far becomes left side of binary op, next term ends up on right. */ struct strexParse *l = p; - struct strexParse *r = strexParseSum(in); + struct strexParse *r = strexParseAnd(in); /* Make left and right side into a common type */ - enum strexType childType = commonTypeForBop(l->type, r->type); + enum strexType childType = commonTypeForLogicBop(l->type, r->type); l = strexParseCoerce(l, childType); r = strexParseCoerce(r, childType); /* Create the binary operation */ AllocVar(p); p->op = strexOpOr; p->type = childType; /* Now hang children onto node. */ p->children = l; l->next = r; } } @@ -916,30 +960,63 @@ case strexTypeDouble: res.val.x = (lv.val.x != 0.0 ? lv.val.x : rv.val.x); break; case strexTypeString: res.val.s = (lv.val.s[0] ? lv.val.s : rv.val.s); break; default: internalErr(); res.val.b = FALSE; break; } res.type = lv.type; return res; } +static struct strexEval strexEvalAnd(struct strexParse *p, void *record, StrexEvalLookup lookup, + struct lm *lm) +/* Return a and b. */ +{ +struct strexParse *lp = p->children; +struct strexParse *rp = lp->next; +struct strexEval lv = strexLocalEval(lp, record, lookup, lm); +struct strexEval rv = strexLocalEval(rp, record, lookup, lm); +struct strexEval res; +assert(lv.type == rv.type); // Is our type automatic casting working? +switch (lv.type) + { + case strexTypeBoolean: + res.val.b = (lv.val.b && rv.val.b); + break; + case strexTypeInt: + res.val.i = (lv.val.i ? rv.val.i : lv.val.i); + break; + case strexTypeDouble: + res.val.x = (lv.val.x != 0.0 ? rv.val.x : lv.val.x); + break; + case strexTypeString: + res.val.s = (lv.val.s[0] ? rv.val.s : lv.val.s); + break; + default: + internalErr(); + res.val.b = FALSE; + break; + } +res.type = lv.type; +return res; +} + static char *csvParseOneOut(char *csvIn, int ix, struct dyString *scratch) /* Return csv value of given index or NULL if at end */ { char *pos = csvIn; int i; for (i=0; iop)); res.type = strexTypeInt; // Keep compiler from complaining. res.val.i = 0; // Keep compiler from complaining. break; } return res; } char *strexEvalAsString(struct strexParse *p, void *record, StrexEvalLookup lookup) /* Evaluating a strex expression on a symbol table with a lookup function for variables and * return result as a string value. */ { struct lm *lm = lmInit(0);