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; ichildren = 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,