3b8231d6039e2a9ffc012414a7881ebf72eee458 kent Mon Jan 11 16:50:51 2021 -0800 Implementing subtraction, since it was in the docs, as Jonathon pointed out. #ref 26745 diff --git src/lib/strex.c src/lib/strex.c index 38c0933..7c4efa1 100644 --- src/lib/strex.c +++ src/lib/strex.c @@ -111,30 +111,31 @@ 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, logical not */ strexOpUnaryMinusInt, strexOpUnaryMinusDouble, strexOpNot, /* Binary operations. */ strexOpAdd, + strexOpSubtract, 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, @@ -971,42 +972,51 @@ 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 = strexParseUnaryNeg(in); for (;;) { char *tok = tokenizerNext(tkz); - if (tok == NULL || differentString(tok, "+")) + if (tok == NULL || (differentString(tok, "+") && differentString(tok, "-"))) { tokenizerReuse(tkz); return p; } + enum strexOp op = (tok[0] == '+' ? strexOpAdd : strexOpSubtract); /* 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 = strexParseUnaryNeg(in); /* Make left and right side into a common type */ enum strexType childType = commonTypeForMathBop(l->type, r->type); + if (op == strexOpSubtract) + { + if (childType == strexTypeString) + { + errAbort("Expecting numbers around '-' sign line %d of %s", + in->tkz->lf->lineIx, in->tkz->lf->fileName); + } + } 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) @@ -1222,30 +1232,56 @@ r.val.s = buf; break; case strexTypeDouble: safef(buf, bufSize, "%g", r.val.x); r.val.s = buf; break; default: internalErr(); r.val.s = NULL; break; } r.type = strexTypeString; return r; } +static struct strexEval strexEvalSubtract(struct strexParse *p, struct strexRun *run) +/* Return a - b. */ +{ +struct strexParse *lp = p->children; +struct strexParse *rp = lp->next; +struct strexEval lv = strexLocalEval(lp, run); +struct strexEval rv = strexLocalEval(rp, run); +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; + default: + internalErr(); + res.val.b = FALSE; + break; + } +res.type = lv.type; +return res; +} + static struct strexEval strexEvalAdd(struct strexParse *p, struct strexRun *run) /* Return a + b. */ { struct strexParse *lp = p->children; struct strexParse *rp = lp->next; struct strexEval lv = strexLocalEval(lp, run); struct strexEval rv = strexLocalEval(rp, run); 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: @@ -1263,30 +1299,31 @@ char *s = lmAlloc(run->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, struct strexRun *run) /* Return a or b. */ { struct strexParse *lp = p->children; struct strexParse *rp = lp->next; struct strexEval res = strexLocalEval(lp, run); boolean gotIt = TRUE; switch (res.type) { case strexTypeBoolean: gotIt = res.val.b != 0; break; case strexTypeInt: gotIt = (res.val.i != 0); break; @@ -2047,30 +2084,33 @@ case strexOpBuiltInCall: 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; + case strexOpSubtract: + res = strexEvalSubtract(p, run); + break; /* 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));