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);