2acdc761f35359fc271e30c6d823357b03155ceb
kent
  Tue Aug 13 11:16:01 2019 -0700
Adding or operation.

diff --git src/lib/strex.c src/lib/strex.c
index 51d5e55..ef4cfb5 100644
--- src/lib/strex.c
+++ src/lib/strex.c
@@ -95,30 +95,31 @@
     strexOpSymbol,	/* A symbol name. */
 
     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,
 
     /* 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,
     };
@@ -283,30 +284,32 @@
     case strexOpBooleanToString:
         return "strexOpBooleanToString";
     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 strexOpBuiltInCall:
         return "strexOpBuiltInCall";
 
     case strexOpArrayIx:
         return "strexOpArrayIx";
     case strexOpArrayRange:
         return "strexOpArrayRange";
 
     case strexOpStrlen:
         return "strexOpStrlen";
     default:
 	return "strexOpUnknown";
     }
 }
@@ -742,34 +745,69 @@
     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 *strexParseOr(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, "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);
+
+    /* Make left and right side into a common type */
+    enum strexType childType = commonTypeForBop(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;
+    }
+}
+
+
 static struct strexParse *strexParseExpression(struct strexIn *in)
 /* Parse out an expression. Leaves input at next expression. */
 {
-return strexParseSum(in);
+return strexParseOr(in);
 }
 
 static void ensureAtEnd(struct strexIn *in)
 /* Make sure that we are at end of input. */
 {
 struct tokenizer *tkz = in->tkz;
 char *leftover = tokenizerNext(tkz);
 if (leftover != NULL)
     errAbort("Extra input starting with '%s' line %d of %s", leftover, tkz->lf->lineIx,
 	tkz->lf->fileName);
 }
 
 struct strexParse *strexParseString(char *s, char *fileName, int fileLineNumber)
 /* Parse out string expression in s and return root of tree. */
 {
@@ -812,30 +850,31 @@
 	break;
     }
 r.type = strexTypeString;
 return r;
 }
 
 static struct strexEval strexEvalAdd(struct strexParse *p, void *record, StrexEvalLookup lookup,
 	struct lm *lm)
 /* Return a + 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 strexTypeInt:
 	res.val.i = (lv.val.i + rv.val.i);
 	break;
     case strexTypeDouble:
 	res.val.x = (lv.val.x + rv.val.x);
 	break;
     case strexTypeString:
 	{
 	char numBuf[32];
 	if (rv.type != strexTypeString)  // Perhaps later could coerce to string
 	    {
 	    rv = strexEvalCoerceToString(rv, numBuf, sizeof(numBuf));
 	    }
@@ -844,30 +883,63 @@
 	char *s = lmAlloc(lm, lLen + rLen + 1);
 	memcpy(s, lv.val.s, lLen);
 	memcpy(s+lLen, rv.val.s, rLen);
 	res.val.s = s;
 	break;
 	}
     default:
 	internalErr();
 	res.val.b = FALSE;
 	break;
     }
 res.type = lv.type;
 return res;
 }
 
+static struct strexEval strexEvalOr(struct strexParse *p, void *record, StrexEvalLookup lookup,
+	struct lm *lm)
+/* Return a or 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 ? lv.val.i : rv.val.i);
+	break;
+    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 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, 
@@ -1227,30 +1299,35 @@
     case strexOpStrlen:
        res = strexLocalEval(p->children, record, lookup, lm);
        res.type = strexTypeInt;
        res.val.i = strlen(res.val.s);
        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;
+
     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);
 struct strexEval res = strexLocalEval(p, record, lookup, lm);