f84f4ea07153528a12d96ce39cccef38031e1065
kent
  Fri Aug 23 21:08:18 2019 -0700
Adding 'not' operation and renaming split to word and separate to chop to help distinguish it a bit from python since the split doesn't quite work like python's

diff --git src/lib/strex.c src/lib/strex.c
index f8b2df3..2e4d952 100644
--- src/lib/strex.c
+++ src/lib/strex.c
@@ -39,57 +39,57 @@
 /* A type within parse tree or built in function specification. */
     {
     strexTypeBoolean = 1,
     strexTypeString = 2,
     strexTypeInt = 3,
     strexTypeDouble = 4,
     };
 
 enum strexBuiltInFunc
 /* One of these for each builtIn.  We'll just do a switch to implement 
  * Each built in function needs a value here, to keep it simple there's
  * aa correspondence between these names and the built in function name */
     {
     strexBuiltInTrim,
     strexBuiltInBetween,
-    strexBuiltInSplit,
+    strexBuiltInWord,
     strexBuiltInNow,
     strexBuiltInMd5,
-    strexBuiltInSeparate,
+    strexBuiltInChop,
     strexBuiltInUncsv,
     strexBuiltInUntsv,
     strexBuiltInReplace,
     strexBuiltInFix,
     strexBuiltInStrip,
     strexBuiltInLen,
     strexBuiltInSymbol,
     strexBuiltInLower,
     strexBuiltInUpper,
     strexBuiltInIn, 
     strexBuiltInStarts,
     strexBuiltInEnds,
     strexBuiltInSame,
     strexBuiltInTidy,
     strexBuiltInWarn,
     strexBuiltInError,
     };
 
 struct strexBuiltIn
 /* Information to describe a built in function */
     {
     char *name;		/* Name in strex language:  trim, split, etc */
-    enum strexBuiltInFunc func;  /* enum version: strexBuiltInTrim strexBuiltInSplit etc. */
+    enum strexBuiltInFunc func;  /* enum version: strexBuiltInTrim strexBuiltInChop etc. */
     enum strexType returnType;	 /* Type of return value */
     int paramCount;	/* Number of parameters, not flexible in this language! */
     enum strexType *paramTypes;  /* Array of types, one for each parameter */
     };
 
 union strexVal
 /* Some value of arbirary type that can be of any type corresponding to strexType */
     {
     boolean b;
     char *s;
     long long i;
     double x;
     struct strexBuiltIn *builtIn;
     };
 
@@ -104,33 +104,34 @@
 /* An operation in the parse tree. */
     {
     strexOpUnknown,	/* Should not occur */
     strexOpLiteral,        /* Literal string or number. */
     strexOpSymbol,	/* A symbol name. */
 
     strexOpBuiltInCall,	/* Call a built in function */
     strexOpPick,	/* Similar to built in but pick deserves it's own op. */
     strexOpConditional,	/* Conditional trinary operation */
 
     strexOpArrayIx,	/* An array with an index. */
     strexOpArrayRange,	/* An array with a range. */
 
     strexOpStrlen,	/* Length of a string */
 
-    /* Unary minus for numbers */
+    /* Unary minus for numbers, logical not */
     strexOpUnaryMinusInt,
     strexOpUnaryMinusDouble,
+    strexOpNot,
 
     /* 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,
@@ -160,46 +161,46 @@
     struct hash *importHash;   /* Hash of importex expressions keyed by file name */
     };
 
 /* Some predefined lists of parameter types */
 static enum strexType oneString[] = {strexTypeString};
 static enum strexType twoStrings[] = {strexTypeString, strexTypeString};
 static enum strexType threeStrings[] = {strexTypeString, strexTypeString, strexTypeString};
 static enum strexType stringInt[] = {strexTypeString, strexTypeInt};
 static enum strexType stringStringInt[] = {strexTypeString, strexTypeString, strexTypeInt};
 
 /* There's one element here for each built in function.  There's also a few switches you'll need to
  * fill in if you add a new built in function. */
 static struct strexBuiltIn builtins[] = {
     { "trim", strexBuiltInTrim, strexTypeString, 1, oneString, },
     { "between", strexBuiltInBetween, strexTypeString, 3, threeStrings },
-    { "split", strexBuiltInSplit, strexTypeString, 2, stringInt },
+    { "word", strexBuiltInWord, strexTypeString, 2, stringInt },
     { "now", strexBuiltInNow, strexTypeString, 0, NULL },
     { "md5", strexBuiltInMd5, strexTypeString, 1, oneString },
-    { "separate", strexBuiltInSeparate, strexTypeString, 3, stringStringInt },
+    { "chop", strexBuiltInChop, strexTypeString, 3, stringStringInt },
     { "uncsv", strexBuiltInUncsv, strexTypeString, 2, stringInt },
     { "untsv", strexBuiltInUntsv, strexTypeString, 2, stringInt },
     { "replace", strexBuiltInReplace, strexTypeString, 3, threeStrings },
     { "fix", strexBuiltInFix, strexTypeString, 3, threeStrings },
     { "strip", strexBuiltInStrip, strexTypeString, 2, twoStrings },
     { "len", strexBuiltInLen, strexTypeInt, 1, oneString},
     { "symbol", strexBuiltInSymbol, strexTypeString, 2, twoStrings },
     { "upper", strexBuiltInUpper, strexTypeString, 1, oneString },
     { "lower", strexBuiltInLower, strexTypeString, 1, oneString },
     { "in", strexBuiltInIn, strexTypeBoolean, 2, twoStrings },
-    { "starts", strexBuiltInStarts, strexTypeBoolean, 2, twoStrings}, 
-    { "ends", strexBuiltInEnds, strexTypeBoolean, 2, twoStrings}, 
+    { "starts_with", strexBuiltInStarts, strexTypeBoolean, 2, twoStrings}, 
+    { "ends_with", strexBuiltInEnds, strexTypeBoolean, 2, twoStrings}, 
     { "same", strexBuiltInSame, strexTypeBoolean, 2, twoStrings}, 
     { "tidy", strexBuiltInTidy, strexTypeString, 3, threeStrings },
     { "warn", strexBuiltInWarn, strexTypeString, 1, oneString},
     { "error", strexBuiltInError, strexTypeString, 1, oneString},
 };
 
 static struct hash *hashBuiltIns()
 /* Build a hash of builtins keyed by name */
 {
 struct hash *hash = hashNew(0);
 int i;
 for (i=0; i<ArraySize(builtins); ++i)
     hashAdd(hash, builtins[i].name, &builtins[i]);
 return hash;
 }
@@ -907,78 +908,96 @@
 	    // Simple no range case
 	    tokenizerReuse(tkz);
 	    p = strexParseNew(strexOpArrayIx, strexTypeString);
 	    p->children = array;
 	    array->next = firstIndex;
 	    }
 	}
     skipOverRequired(in, "]");
     }
 else
     tokenizerReuse(tkz);
 return p;
 }
 
 
-static struct strexParse *strexParseUnaryMinus(struct strexIn *in)
-/* Return unary minus sort of parse tree if there's a leading '-' */
+static struct strexParse *strexParseUnaryNeg(struct strexIn *in)
+/* Return parse tree for unary minus or logical not */
 {
 struct tokenizer *tkz = in->tkz;
 char *tok = tokenizerMustHaveNext(tkz);
 if (tok[0] == '-')
     {
     struct strexParse *c = strexParseIndex(in);
     struct strexParse *p;
     AllocVar(p);
     if (c->type == strexTypeInt)
         {
 	p->op = strexOpUnaryMinusInt;
 	p->type = strexTypeInt;
 	}
     else
 	{
 	c = strexParseCoerce(c, strexTypeDouble);
 	p->op = strexOpUnaryMinusDouble;
 	p->type = strexTypeDouble;
 	}
     p->children = c;
     return p;
     }
+else if (sameString(tok, "not"))
+    {
+    struct strexParse *c = strexParseIndex(in);
+    struct strexParse *p;
+    AllocVar(p);
+    if (c->type == strexTypeBoolean)
+        {
+	p->op = strexOpNot;
+	}
+    else
+	{
+	c = strexParseCoerce(c, strexTypeBoolean);
+	p->op = strexOpNot;
+	}
+    p->type = strexTypeBoolean;
+    p->children = c;
+    return p;
+    }
 else
     {
     tokenizerReuse(tkz);
     return strexParseIndex(in);
     }
 }
 
 static struct strexParse *strexParseSum(struct strexIn *in)
 /* Parse out plus or minus. */
 {
 struct tokenizer *tkz = in->tkz;
-struct strexParse *p = strexParseUnaryMinus(in);
+struct strexParse *p = strexParseUnaryNeg(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);
+    struct strexParse *r = strexParseUnaryNeg(in);
 
     /* Make left and right side into a common 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;
     }
@@ -1519,57 +1538,57 @@
 	{
         struct strexEval a = strexLocalEval(p->children, run);
 	res.val.s = trimSpaces(a.val.s);
 	break;
 	}
     case strexBuiltInBetween:
 	{
         struct strexEval a = strexLocalEval(p->children, run);
         struct strexEval b = strexLocalEval(p->children->next, run);
         struct strexEval c = strexLocalEval(p->children->next->next, run);
 	char *between = stringBetween(a.val.s, c.val.s, b.val.s);
 	res.val.s = emptyForNull(lmCloneString(lm, between));
 	freeMem(between);
         break;
 	}
-    case strexBuiltInSplit:
+    case strexBuiltInWord:
         {
         struct strexEval a = strexLocalEval(p->children, run);
         struct strexEval b = strexLocalEval(p->children->next, run);
 	res.val.s = splitString(a.val.s, b.val.i, lm);
 	break;
 	}
     case strexBuiltInNow:
         {
 	time_t now;
 	time(&now);
 	char buf[64];
 	// strftime(buf, sizeof buf, "%FT%TZ", gmtime(&now));
 	strftime(buf, sizeof buf, "%FT%T%z", localtime(&now));
 	res.val.s = lmCloneString(lm, buf);
 	eraseTrailingSpaces(res.val.s);
 	break;
 	}
     case strexBuiltInMd5:
         {
         struct strexEval a = strexLocalEval(p->children, run);
 	char *md5 = hmacMd5("", a.val.s);
 	res.val.s = lmCloneString(lm, md5);
 	freez(&md5);
 	break;
 	}
-    case strexBuiltInSeparate:
+    case strexBuiltInChop:
         {
         struct strexEval a = strexLocalEval(p->children, run);
         struct strexEval b = strexLocalEval(p->children->next, run);
         struct strexEval c = strexLocalEval(p->children->next->next, run);
 	res.val.s = separateString(a.val.s, b.val.s, c.val.i, lm);
 	break;
 	}
     case strexBuiltInUncsv:
         {
         struct strexEval a = strexLocalEval(p->children, run);
         struct strexEval b = strexLocalEval(p->children->next, run);
 	res.val.s = uncsvString(a.val.s, b.val.i, lm);
 	break;
 	}
     case strexBuiltInUntsv:
@@ -1904,37 +1923,41 @@
        res = strexEvalCallBuiltIn(p, run);
        break;
     case strexOpPick:
        res = strexEvalPick(p, run);
        break;
     case strexOpConditional:
        res = strexEvalConditional(p, run);
        break;
 
 
     /* Mathematical ops, simple binary type */
     case strexOpAdd:
        res = strexEvalAdd(p, run);
        break;
 
-    /* Logical ops, simple binary type */
+    /* Logical ops, simple binary type and not*/
     case strexOpOr:
         res = strexEvalOr(p, run);
         break;
     case strexOpAnd:
         res = strexEvalAnd(p, run);
         break;
+    case strexOpNot:
+        res = strexLocalEval(p->children, run);
+	res.val.b = !res.val.b;
+	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;
 }
 
 /* ---- And the one public evaluation function ---- */
 
 char *strexEvalAsString(struct strexParse *p, void *symbols, StrexLookup lookup,
     void (*warnHandler)(void *symbols, char *warning), void (*abortHandler)(void *symbols) )
 /* Return result as a string value.  The warnHandler and abortHandler are optional,