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; i<ix; ++i)
     {
     if (csvParseNext(&pos,scratch) == NULL)
         return NULL;
     }
 return csvParseNext(&pos, scratch);
 }
 
 static struct strexEval strexEvalArrayIx(struct strexParse *p, 
@@ -1303,30 +1380,34 @@
        break;
 
     case strexOpBuiltInCall:
        res = strexEvalCallBuiltIn(p, record, lookup, lm);
        break;
 
     /* Mathematical ops, simple binary type */
     case strexOpAdd:
        res = strexEvalAdd(p, record, lookup, lm);
        break;
 
     /* Logical ops, simple binary type */
     case strexOpOr:
        res = strexEvalOr(p, record, lookup, lm);
        break;
+    case strexOpAnd:
+       res = strexEvalAnd(p, record, lookup, lm);
+       break;
+
 
     default:
         errAbort("Unknown op %s\n", strexOpToString(p->op));
 	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);